From 64168364695762aa1502c5369ad404286e8be6bb Mon Sep 17 00:00:00 2001 From: Andy Kolean Date: Sun, 15 Dec 2024 16:41:33 -0500 Subject: [PATCH 01/40] [XcodeProjToGraph] add XcodeProjToGraph and tests --- Package.resolved | 57 +- Package.swift | 48 +- .../App/Sources/ContentView.swift | 16 + .../App/Sources/MyApp.swift | 36 + .../Project.swift | 25 + .../README.md | 3 + .../App/Sources/App.swift | 10 + .../App/Sources/ContentView.swift | 13 + .../LocalSwiftPackage/Package.swift | 15 + .../LocalSwiftPackage/LocalSwiftPackage.swift | 3 + .../Project.swift | 29 + .../README.md | 7 + .../.package.resolved | 15 + .../App/Sources/App.swift | 10 + .../App/Sources/ContentView.swift | 13 + .../LocalSwiftPackage/Package.swift | 21 + .../LocalSwiftPackage/LocalSwiftPackage.swift | 6 + .../Project.swift | 29 + .../README.md | 8 + .../CommandLineTool/main.swift | 4 + .../DynamicFramework/DynamicFramework.swift | 5 + .../Project.swift | 26 + .../Tuist/Config.swift | 3 + .../Fixtures/ios_app_large/Info.plist | 43 + .../Fixtures/ios_app_large/Project.swift | 18 + .../ios_app_large/Sources/AppDelegate.swift | 21 + .../Fixtures/ios_app_large/Tests.plist | 24 + .../Fixtures/ios_app_large/Tuist/Config.swift | 3 + .../Sources/AppIntentExtension.swift | 9 + .../Sources/AppIntentExtensionExtension.swift | 6 + .../ios_app_with_extensions/Bundle/dummy.jpg | 0 .../ios_app_with_extensions/Info.plist | 43 + .../Resources/Assets.xcassets/Contents.json | 6 + .../Contents.json | 78 ++ .../Base.lproj/MainInterface.storyboard | 37 + .../Sources/MessagesViewController.swift | 57 + .../NotificationService.swift | 30 + .../ios_app_with_extensions/Project.swift | 128 ++ .../ios_app_with_extensions/README.md | 3 + .../Sources/AppDelegate.swift | 18 + .../Documentation.docc/Documentation.md | 13 + .../Sources/StaticFramework.swift | 5 + .../Stickers.xcassets/Contents.json | 6 + .../Sticker Pack.stickerpack/Contents.json | 9 + .../Contents.json | 78 ++ .../Tuist/Config.swift | 3 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 98 ++ .../Resources/Assets.xcassets/Contents.json | 6 + .../WidgetBackground.colorset/Contents.json | 11 + .../WidgetExtension/Sources/Widget.swift | 69 ++ .../App/Project.swift | 62 + .../App/Sources/AppDelegate.swift | 23 + .../App/Support/App-Info.plist | 43 + .../App/Support/AppTests-Info.plist | 22 + .../App/Tests/AppDelegateTests.swift | 11 + .../ConfigurationFiles/Beta.xcconfig | 2 + .../ConfigurationFiles/Debug.xcconfig | 2 + .../ConfigurationFiles/Release.xcconfig | 2 + .../ConfigurationFiles/Target.Beta.xcconfig | 2 + .../ConfigurationFiles/Target.Debug.xcconfig | 2 + .../Target.Release.xcconfig | 2 + .../Framework1/Project.swift | 43 + .../Framework1/Sources/Framework1File.swift | 16 + .../Framework1/Support/Framework1-Info.plist | 24 + .../Support/Framework1Tests-Info.plist | 22 + .../Tests/Framework1FileTests.swift | 17 + .../Framework2/Project.swift | 47 + .../Framework2/Sources/Framework2File.swift | 9 + .../Framework2/Support/Framework2-Info.plist | 24 + .../Support/Framework2Tests-Info.plist | 22 + .../Tests/Framework2FileTests.swift | 11 + .../ios_app_with_multi_configs/README.md | 3 + .../Tuist/Config.swift | 3 + .../Workspace.swift | 6 + .../.package.resolved | 16 + .../Package.resolved | 16 + .../Project.swift | 37 + .../README.md | 3 + .../Sources/AppDelegate.swift | 25 + .../Support/Info.plist | 43 + .../Support/Tests.plist | 24 + .../Tests/AppTests.swift | 6 + .../Tuist/Config.swift | 3 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 + .../Resources/Assets.xcassets/Contents.json | 6 + .../Preview Assets.xcassets/Contents.json | 6 + .../App/Sources/AppApp.swift | 10 + .../App/Sources/ContentView.swift | 30 + .../AppTests/AppTests.swift | 21 + .../Project.swift | 34 + .../ios_app_with_spm_dependencies/README.md | 3 + .../Tuist/Package.resolved | 69 ++ .../Tuist/Package.swift | 14 + .../ios_app_with_static_libraries/Info.plist | 43 + .../Modules/A/CustomHeaders/CustomHeader.h | 0 .../A/Playgrounds/A.playground/Contents.swift | 1 + .../A.playground/contents.xcplayground | 4 + .../Modules/A/Project.swift | 36 + .../Modules/A/Sources/A.swift | 12 + .../Modules/A/Tests/ATests.swift | 10 + .../Modules/B/Info.plist | 26 + .../B/Playgrounds/B.playground/Contents.swift | 1 + .../B.playground/contents.xcplayground | 4 + .../Modules/B/Project.swift | 30 + .../Modules/B/Sources/B.swift | 9 + .../Modules/B/Tests.plist | 24 + .../Modules/B/Tests/BTests.swift | 10 + .../Modules/C/Info.plist | 26 + .../Modules/C/Project.swift | 31 + .../Modules/C/Sources/C.swift | 9 + .../Modules/C/Tests.plist | 24 + .../Modules/C/Tests/CTests.swift | 10 + .../Modules/C/build.sh | 23 + .../arm64-apple-ios-simulator.swiftsourceinfo | Bin 0 -> 1084 bytes ...x86_64-apple-ios-simulator.swiftsourceinfo | Bin 0 -> 1084 bytes .../arm64-apple-ios-simulator.abi.json | 108 ++ ...apple-ios-simulator.private.swiftinterface | 12 + .../arm64-apple-ios-simulator.swiftdoc | Bin 0 -> 400 bytes .../arm64-apple-ios-simulator.swiftinterface | 12 + .../arm64-apple-ios-simulator.swiftmodule | Bin 0 -> 16304 bytes .../x86_64-apple-ios-simulator.abi.json | 108 ++ ...apple-ios-simulator.private.swiftinterface | 12 + .../x86_64-apple-ios-simulator.swiftdoc | Bin 0 -> 400 bytes .../x86_64-apple-ios-simulator.swiftinterface | 12 + .../x86_64-apple-ios-simulator.swiftmodule | Bin 0 -> 16308 bytes .../Modules/C/prebuilt/C/libC.a | Bin 0 -> 22696 bytes .../Contents.swift | 1 + .../contents.xcplayground | 4 + .../Project.swift | 29 + .../ios_app_with_static_libraries/README.md | 33 + .../Sources/AppDelegate.swift | 25 + .../ios_app_with_static_libraries/Tests.plist | 24 + .../Tests/AppTests.swift | 10 + .../Tuist/Config.swift | 3 + .../App/Config/App-Info.plist | 43 + .../App/Config/AppTests-Info.plist | 22 + .../App/Project.swift | 40 + .../App/Sources/AppDelegate.swift | 19 + .../App/Tests/AppDelegateTests.swift | 11 + .../App/UITests/AppUITest.swift | 26 + .../Framework1/Config/Framework1-Info.plist | 24 + .../Config/Framework1Tests-Info.plist | 22 + .../Framework1/Project.swift | 53 + .../Framework1/Sources/Framework1File.swift | 16 + .../Tests/Framework1FileTests.swift | 19 + .../Framework1/Tests/Info.plist | 22 + .../Framework2/Config/Framework2-Info.plist | 24 + .../Framework2/Project.swift | 29 + .../Framework2/Sources/Framework2File.swift | 9 + .../Framework2/build.sh | 62 + .../Mac/Framework2.framework/Framework2 | Bin 0 -> 54712 bytes .../Headers/Framework2-Swift.h | 311 +++++ .../Mac/Framework2.framework/Info.plist | 48 + .../Project/arm64-apple-macos.swiftsourceinfo | Bin 0 -> 1140 bytes .../x86_64-apple-macos.swiftsourceinfo | Bin 0 -> 1144 bytes .../Project/x86_64.swiftsourceinfo | Bin 0 -> 832 bytes .../arm64-apple-macos.abi.json | 76 ++ .../arm64-apple-macos.private.swiftinterface | 14 + .../arm64-apple-macos.swiftdoc | Bin 0 -> 400 bytes .../arm64-apple-macos.swiftinterface | 14 + .../arm64-apple-macos.swiftmodule | Bin 0 -> 20380 bytes .../x86_64-apple-macos.abi.json | 76 ++ .../x86_64-apple-macos.private.swiftinterface | 13 + .../x86_64-apple-macos.swiftdoc | Bin 0 -> 400 bytes .../x86_64-apple-macos.swiftinterface | 13 + .../x86_64-apple-macos.swiftmodule | Bin 0 -> 17056 bytes .../Framework2.swiftmodule/x86_64.swiftdoc | Bin 0 -> 384 bytes .../x86_64.swiftinterface | 10 + .../Framework2.swiftmodule/x86_64.swiftmodule | Bin 0 -> 15580 bytes .../Modules/module.modulemap | 4 + .../iOS/Framework2.framework/Framework2 | Bin 0 -> 170976 bytes .../Headers/Framework2-Swift.h | 618 ++++++++++ .../iOS/Framework2.framework/Info.plist | Bin 0 -> 837 bytes .../arm64-apple-ios-simulator.swiftsourceinfo | Bin 0 -> 1148 bytes .../Project/arm64-apple-ios.swiftsourceinfo | Bin 0 -> 828 bytes .../Project/arm64.swiftsourceinfo | Bin 0 -> 828 bytes ...x86_64-apple-ios-simulator.swiftsourceinfo | Bin 0 -> 1148 bytes .../Project/x86_64.swiftsourceinfo | Bin 0 -> 840 bytes .../arm64-apple-ios-simulator.abi.json | 76 ++ ...apple-ios-simulator.private.swiftinterface | 14 + .../arm64-apple-ios-simulator.swiftdoc | Bin 0 -> 408 bytes .../arm64-apple-ios-simulator.swiftinterface | 14 + .../arm64-apple-ios-simulator.swiftmodule | Bin 0 -> 20676 bytes .../arm64-apple-ios.swiftdoc | Bin 0 -> 380 bytes .../arm64-apple-ios.swiftinterface | 10 + .../arm64-apple-ios.swiftmodule | Bin 0 -> 15664 bytes .../Framework2.swiftmodule/arm64.swiftdoc | Bin 0 -> 380 bytes .../arm64.swiftinterface | 10 + .../Framework2.swiftmodule/arm64.swiftmodule | Bin 0 -> 15664 bytes .../x86_64-apple-ios-simulator.abi.json | 76 ++ ...apple-ios-simulator.private.swiftinterface | 14 + .../x86_64-apple-ios-simulator.swiftdoc | Bin 0 -> 408 bytes .../x86_64-apple-ios-simulator.swiftinterface | 14 + .../x86_64-apple-ios-simulator.swiftmodule | Bin 0 -> 20676 bytes .../Framework2.swiftmodule/x86_64.swiftdoc | Bin 0 -> 392 bytes .../x86_64.swiftinterface | 10 + .../Framework2.swiftmodule/x86_64.swiftmodule | Bin 0 -> 15784 bytes .../Modules/module.modulemap | 4 + .../README.md | 25 + .../StaticFramework1/Project.swift | 29 + .../Sources/Framework1File.swift | 16 + .../Tests/Framework1FileTests.swift | 19 + .../Tuist/Config.swift | 3 + .../Workspace.swift | 6 + .../Frameworks/CoreFramework/Info.plist | 26 + .../Frameworks/CoreFramework/Project.swift | 30 + .../CoreFramework/Sources/CoreClass.swift | 5 + .../Frameworks/CoreFramework/Tests.plist | 24 + .../CoreFramework/Tests/CoreClassTests.swift | 6 + .../Frameworks/DataFramework/Info.plist | 26 + .../Frameworks/DataFramework/Project.swift | 35 + .../DataFramework/Sources/DataClass.swift | 8 + .../Frameworks/DataFramework/Tests.plist | 24 + .../DataFramework/Tests/FrameworkATests.swift | 6 + .../Frameworks/FeatureAFramework/Info.plist | 26 + .../FeatureAFramework/Project.swift | 38 + .../Sources/FrameworkA.swift | 10 + .../Frameworks/FeatureAFramework/Tests.plist | 24 + .../Tests/FrameworkATests.swift | 6 + .../Frameworks/FeatureContracts/Info.plist | 26 + .../Frameworks/FeatureContracts/Project.swift | 36 + .../Sources/FeatureAContract.swift | 5 + .../Sources/FeatureBContract.swift | 7 + .../Frameworks/FeatureContracts/Tests.plist | 24 + .../Tests/FrameworkAContractTests.swift | 6 + .../UIComponentsFramework/Info.plist | 26 + .../UIComponentsFramework/Project.swift | 35 + .../Sources/UIComponentA.swift | 7 + .../UIComponentsFramework/Tests.plist | 24 + .../Tests/UIComponentATests.swift | 6 + .../StaticApp/Info.plist | 43 + .../StaticApp/Project.swift | 35 + .../StaticApp/Sources/AppDelegate.swift | 18 + .../StaticApp/Tests.plist | 24 + .../StaticApp/Tests/AppTests.swift | 6 + .../Tuist/Config.swift | 3 + .../Workspace.swift | 9 + .../MainApp/Info.plist | 28 + .../MainApp/Sources/main.swift | 3 + .../Project.swift | 25 + .../SystemExtension/Sources/main.swift | 3 + .../Tuist/Config.swift | 3 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 + .../Resources/Assets.xcassets/Contents.json | 6 + .../App/Sources/ContentView.swift | 20 + .../App/Sources/TestApp.swift | 15 + .../ModuleA/Macros/Sources/Macros.swift | 23 + .../Modules/ModuleA/Sources/Macros.swift | 3 + .../Modules/ModuleA/Sources/ModuleA.swift | 12 + .../Modules/ModuleA/Tests/ModuleATests.swift | 23 + .../Project.swift | 107 ++ .../Tuist/Package.resolved | 32 + .../Tuist/Package.swift | 23 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 + .../Resources/Assets.xcassets/Contents.json | 6 + .../WatchApp/Sources/ContentView.swift | 18 + .../WatchApp/Sources/WatchApp.swift | 21 + .../WatchApp/Sources/WatchConfig.swift | 5 + .../ProjectA/Project.swift | 28 + .../Targets/App/Sources/AppDelegate.swift | 19 + .../ProjectA/Targets/App/Tests/AppTests.swift | 8 + .../ProjectB/.gitignore | 67 + .../ProjectB/Project.swift | 28 + .../Targets/App/Sources/AppDelegate.swift | 19 + .../ProjectB/Targets/App/Tests/AppTests.swift | 8 + .../Workspace.swift | 9 + .../Mocks/MockBuildFilesAndPhases.swift | 139 +++ .../TestSupport/Mocks/MockBuildSettings.swift | 66 + Sources/TestSupport/Mocks/MockDefaults.swift | 31 + .../TestSupport/Mocks/MockFileCreator.swift | 18 + .../TestSupport/Mocks/MockFileStructure.swift | 143 +++ .../Mocks/MockProjectAndWorkspace.swift | 138 +++ .../Mocks/MockProjectProvider.swift | 50 + .../Mocks/MockSchemesAndUserData.swift | 79 ++ .../Mocks/MockTargetsAndDependencies.swift | 172 +++ Sources/TestSupport/WorkspaceFixture.swift | 30 + .../XcodeGraph/Graph/GraphDependency.swift | 6 +- Sources/XcodeGraph/Graph/GraphEdge.swift | 2 +- .../Models/BinaryArchitecture.swift | 4 +- .../Models/Metadata/TargetMetadata.swift | 2 +- Sources/XcodeGraph/Models/SDKSource.swift | 2 +- .../Models/XCFrameworkInfoPlist.swift | 6 +- .../Extensions/AbsolutePath+Extensions.swift | 88 ++ .../Extensions/Package+Extensions.swift | 13 + .../Extensions/Platform+Extensions.swift | 28 + .../PlatformFilter+Extensions.swift | 25 + .../Extensions/Sendable+Retroactive.swift | 16 + .../Extensions/Sequence+Async.swift | 24 + .../TargetDependency+Extensions.swift | 26 + .../XCWorkspaceDataFileRef+Extensions.swift | 36 + .../Mappers/Build/BuildPhaseConstants.swift | 48 + .../Mappers/Build/BuildPhaseMapper.swift | 421 +++++++ .../Mappers/Build/BuildRuleMapper.swift | 63 + .../Mappers/Dependency/DependencyMapper.swift | 165 +++ .../Dependency/FileDependencyMapper.swift | 22 + .../Dependency/PlatformConditionMapper.swift | 19 + .../TargetDependency+GraphMapping.swift | 272 +++++ .../Mappers/Graph/GraphMapper.swift | 132 ++ .../Mappers/Graph/MappingError.swift | 81 ++ .../Mappers/Graph/ProjectParser.swift | 111 ++ .../Mappers/Project/PackageMapper.swift | 92 ++ .../Mappers/Project/ProjectMapper.swift | 166 +++ .../Mappers/Project/ProjectProvider.swift | 67 + .../Mappers/Settings/BuildSettings.swift | 100 ++ .../Settings/ConfigurationMatcher.swift | 42 + .../Mappers/Settings/SettingsMapper.swift | 107 ++ .../XCConfigurationList+Helpers.swift | 36 + .../PBXTarget+BuildHeaders.swift | 8 + .../PBXTarget+BuildSettings.swift | 53 + .../PBXTarget+PlatformInference.swift | 83 ++ .../SchemeDiagnosticsOptions+XCScheme.swift | 25 + .../TargetAndSchemes/SchemeMapper.swift | 269 ++++ .../TargetAndSchemes/TargetMapper.swift | 280 +++++ .../Mappers/Workspace/WorkspaceMapper.swift | 128 ++ .../Mappers/Workspace/WorkspaceProvider.swift | 32 + .../ProcessRunner/Executable.swift | 59 + .../ProcessRunner/Lipo/LipoArchsResult.swift | 38 + .../ProcessRunner/Lipo/LipoArguments.swift | 29 + .../ProcessRunner/Lipo/LipoTool.swift | 36 + .../ProcessRunner/ProcessResult.swift | 33 + .../ProcessRunner/ProcessRunner.swift | 77 ++ .../ProcessRunner/ProcessRunnerError.swift | 21 + .../XcodeProjToGraph.docc/Documentation.md | 13 + .../Extensions/XCTestCase+Extras.swift | 4 +- .../XcodeGraphTests/Models/TargetTests.swift | 18 +- .../IntegrationTests/IntegrationTests.swift | 198 +++ ...+commandLineToolWithDynamicFramework.swift | 233 ++++ .../IntegrationTests+iosAppLarge.swift | 20 + ...ntegrationTests+iosAppWithExtensions.swift | 758 ++++++++++++ ...egrationTests+iosAppWithMultiConfigs.swift | 563 +++++++++ ...onTests+iosAppWithRemoteSwiftPackage.swift | 256 ++++ ...ationTests+iosAppWithSpmDependencies.swift | 275 +++++ ...ationTests+iosAppWithStaticLibraries.swift | 605 +++++++++ ...icrofeatureArchitectureStaticLinking.swift | 1084 +++++++++++++++++ ...ts+ios_app_with_transitive_framework.swift | 836 +++++++++++++ ...ionTests+macosAppWithSystemExtension.swift | 239 ++++ ...rmAppWithMacrosAndEmbeddedWatchosApp.swift | 598 +++++++++ .../Xcode/Build/BuildPhaseMapperTests.swift | 581 +++++++++ .../Xcode/Build/BuildRuleMapperTests.swift | 124 ++ .../Dependency/DependencyMapperTests.swift | 259 ++++ .../TargetDependencyExtensionsTests.swift | 224 ++++ .../Xcode/GraphMapper/GraphMapperTests.swift | 187 +++ .../Xcode/Project/PackageMapperTests.swift | 133 ++ .../Xcode/Project/ProjectMapperTests.swift | 158 +++ .../Xcode/Settings/BuildSettingsTests.swift | 63 + .../Settings/ConfigurationMatcherTests.swift | 35 + .../Xcode/Settings/SettingsMapperTests.swift | 162 +++ .../Xcode/Target/SchemeMapperTests.swift | 242 ++++ .../Xcode/Target/TargetMapperTests.swift | 153 +++ .../Workspace/WorkspaceMapperTests.swift | 0 .../ParserTests/ProjectParserTests.swift | 99 ++ .../ProcessTests/LipoToolTests.swift | 88 ++ .../ProcessTests/ProcessRunnerTests.swift | 187 +++ Tuist/ProjectDescriptionHelpers/Module.swift | 32 +- 358 files changed, 18640 insertions(+), 39 deletions(-) create mode 100644 Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/ContentView.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/MyApp.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_composable_architecture/Project.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_composable_architecture/README.md create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/App.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/ContentView.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Package.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/Project.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/README.md create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/.package.resolved create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/App.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/ContentView.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Package.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/Project.swift create mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/README.md create mode 100644 Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift create mode 100644 Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift create mode 100644 Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Project.swift create mode 100644 Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Tuist/Config.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_large/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_large/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_large/Sources/AppDelegate.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_large/Tests.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_large/Tuist/Config.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/Bundle/dummy.jpg create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/iMessage App Icon.stickersiconset/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/README.md create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/Documentation.docc/Documentation.md create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Sticker Pack.stickerpack/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/iMessage App Icon.stickersiconset/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/Tuist/Config.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/WidgetBackground.colorset/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Debug.xcconfig create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Release.xcconfig create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/README.md create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Tuist/Config.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Workspace.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/.package.resolved create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Package.resolved create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/README.md create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tuist/Config.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets/Contents.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/README.md create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.resolved create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/CustomHeaders/CustomHeader.h create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/Contents.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/contents.xcplayground create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Project.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/Contents.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/contents.xcplayground create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Project.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Info.plist create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Project.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Sources/C.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests.plist create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests/CTests.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/build.sh create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.abi.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.swiftdoc create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.swiftmodule create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.abi.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.swiftdoc create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.swiftmodule create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Playgrounds/application_with_transistive_static_dependency.playground/Contents.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Playgrounds/application_with_transistive_static_dependency.playground/contents.xcplayground create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/README.md create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests.plist create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tuist/Config.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1Tests-Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Config/Framework2-Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Sources/Framework2File.swift create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/build.sh create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Framework2 create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Headers/Framework2-Swift.h create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64-apple-macos.swiftsourceinfo create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64.swiftsourceinfo create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.abi.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.private.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftdoc create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftmodule create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.abi.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.private.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftdoc create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftmodule create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftdoc create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftmodule create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/module.modulemap create mode 100755 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Headers/Framework2-Swift.h create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64.swiftsourceinfo create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64.swiftsourceinfo create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.abi.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftdoc create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftmodule create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftdoc create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftmodule create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftdoc create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftmodule create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.abi.json create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftdoc create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftmodule create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftdoc create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftinterface create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftmodule create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/module.modulemap create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/README.md create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Tuist/Config.swift create mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Workspace.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Project.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Tuist/Config.swift create mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.swift create mode 100644 Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Info.plist create mode 100644 Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift create mode 100644 Sources/TestSupport/Fixtures/macos_app_with_system_extension/Project.swift create mode 100644 Sources/TestSupport/Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift create mode 100644 Sources/TestSupport/Fixtures/macos_app_with_system_extension/Tuist/Config.swift create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/Contents.json create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Project.swift create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.resolved create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.swift create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/Contents.json create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift create mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift create mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Project.swift create mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Sources/AppDelegate.swift create mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Tests/AppTests.swift create mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/.gitignore create mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Project.swift create mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Sources/AppDelegate.swift create mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Tests/AppTests.swift create mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/Workspace.swift create mode 100644 Sources/TestSupport/Mocks/MockBuildFilesAndPhases.swift create mode 100644 Sources/TestSupport/Mocks/MockBuildSettings.swift create mode 100644 Sources/TestSupport/Mocks/MockDefaults.swift create mode 100644 Sources/TestSupport/Mocks/MockFileCreator.swift create mode 100644 Sources/TestSupport/Mocks/MockFileStructure.swift create mode 100644 Sources/TestSupport/Mocks/MockProjectAndWorkspace.swift create mode 100644 Sources/TestSupport/Mocks/MockProjectProvider.swift create mode 100644 Sources/TestSupport/Mocks/MockSchemesAndUserData.swift create mode 100644 Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift create mode 100644 Sources/TestSupport/WorkspaceFixture.swift create mode 100644 Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift create mode 100644 Sources/XcodeProjToGraph/Extensions/Package+Extensions.swift create mode 100644 Sources/XcodeProjToGraph/Extensions/Platform+Extensions.swift create mode 100644 Sources/XcodeProjToGraph/Extensions/PlatformFilter+Extensions.swift create mode 100644 Sources/XcodeProjToGraph/Extensions/Sendable+Retroactive.swift create mode 100644 Sources/XcodeProjToGraph/Extensions/Sequence+Async.swift create mode 100644 Sources/XcodeProjToGraph/Extensions/TargetDependency+Extensions.swift create mode 100644 Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseConstants.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Build/BuildRuleMapper.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Dependency/FileDependencyMapper.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Settings/BuildSettings.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Settings/XCConfigurationList+Helpers.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildHeaders.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+PlatformInference.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeDiagnosticsOptions+XCScheme.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift create mode 100644 Sources/XcodeProjToGraph/ProcessRunner/Executable.swift create mode 100644 Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArchsResult.swift create mode 100644 Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArguments.swift create mode 100644 Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoTool.swift create mode 100644 Sources/XcodeProjToGraph/ProcessRunner/ProcessResult.swift create mode 100644 Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift create mode 100644 Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift create mode 100644 Sources/XcodeProjToGraph/XcodeProjToGraph.docc/Documentation.md create mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/IntegrationTests.swift create mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift create mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift create mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift create mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift create mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift create mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift create mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift create mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift create mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift create mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift create mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift create mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Workspace/WorkspaceMapperTests.swift create mode 100644 Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift create mode 100644 Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift create mode 100644 Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift diff --git a/Package.resolved b/Package.resolved index c1487b6c..5f910926 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,15 @@ { + "originHash" : "447185ac44bc164bd512707df26360069b79dc9ae8a26ab75a2aa5630c884a42", "pins" : [ + { + "identity" : "aexml", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tadija/AEXML.git", + "state" : { + "revision" : "38f7d00b23ecd891e1ee656fa6aeebd6ba04ecc3", + "version" : "4.6.1" + } + }, { "identity" : "anycodable", "kind" : "remoteSourceControl", @@ -17,7 +27,52 @@ "revision" : "7c74ac435e03a927c3a73134c48b61e60221abcb", "version" : "0.3.8" } + }, + { + "identity" : "pathkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kylef/PathKit.git", + "state" : { + "revision" : "3bfd2737b700b9a36565a8c94f4ad2b050a5e574", + "version" : "1.0.1" + } + }, + { + "identity" : "spectre", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kylef/Spectre.git", + "state" : { + "revision" : "26cc5e9ae0947092c7139ef7ba612e34646086c7", + "version" : "0.10.1" + } + }, + { + "identity" : "swift-snapshot-testing", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-snapshot-testing", + "state" : { + "revision" : "42a086182681cf661f5c47c9b7dc3931de18c6d7", + "version" : "1.17.6" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swiftlang/swift-syntax", + "state" : { + "revision" : "0687f71944021d616d34d922343dcef086855920", + "version" : "600.0.1" + } + }, + { + "identity" : "xcodeproj", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tuist/XcodeProj", + "state" : { + "revision" : "d3df4265b8383dd56dae4b01f817d30c22e7612c", + "version" : "8.25.0" + } } ], - "version" : 2 + "version" : 3 } diff --git a/Package.swift b/Package.swift index e63cef20..4aea2c18 100644 --- a/Package.swift +++ b/Package.swift @@ -1,8 +1,8 @@ -// swift-tools-version:5.9 +// swift-tools-version:6.0 -import PackageDescription +@preconcurrency import PackageDescription -var targets: [Target] = [ +let targets: [Target] = [ .target( name: "XcodeGraph", dependencies: [ @@ -13,6 +13,41 @@ var targets: [Target] = [ .enableExperimentalFeature("StrictConcurrency"), ] ), + .target( + name: "XcodeProjToGraph", + dependencies: [ + "XcodeGraph", + .product(name: "Path", package: "Path"), + .product(name: "XcodeProj", package: "XcodeProj") + ], + path: "Sources/XcodeProjToGraph" + ), + .target( + name: "TestSupport", + dependencies: [ + "XcodeProjToGraph" + ], + path: "Sources/TestSupport", + resources: [ + .copy("Fixtures") + ] + ), + .testTarget( + name: "XcodeGraphTests", + dependencies: [ + "XcodeGraph" + ], + path: "Tests/XcodeGraphTests" + ), + .testTarget( + name: "XcodeProjToGraphTests", + dependencies: [ + "XcodeProjToGraph", + "TestSupport", + .product(name: "InlineSnapshotTesting", package: "swift-snapshot-testing"), + ], + path: "Tests/XcodeProjToGraphTests" + ), ] let package = Package( @@ -23,10 +58,17 @@ let package = Package( name: "XcodeGraph", targets: ["XcodeGraph"] ), + .library(name: "XcodeProjToGraph", targets: ["XcodeProjToGraph"]) ], dependencies: [ .package(url: "https://github.com/Flight-School/AnyCodable", .upToNextMajor(from: "0.6.7")), .package(url: "https://github.com/tuist/Path.git", .upToNextMajor(from: "0.3.8")), + .package(url: "https://github.com/tuist/XcodeProj", from: "8.25.0"), + .package( + url: "https://github.com/pointfreeco/swift-snapshot-testing", + from: "1.17.0" + ), ], + targets: targets ) diff --git a/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/ContentView.swift new file mode 100644 index 00000000..9a777ffa --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/ContentView.swift @@ -0,0 +1,16 @@ +import SwiftUI + +public struct ContentView: View { + public init() {} + + public var body: some View { + Text("Hello, World!") + .padding() + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/MyApp.swift b/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/MyApp.swift new file mode 100644 index 00000000..062a6c94 --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/MyApp.swift @@ -0,0 +1,36 @@ +import ComposableArchitecture +import SwiftUI + +@main +struct MyApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} + +@Reducer +struct Counter { + struct State: Equatable { + var count = 0 + } + + enum Action { + case decrementButtonTapped + case incrementButtonTapped + } + + var body: some Reducer { + Reduce { state, action in + switch action { + case .decrementButtonTapped: + state.count -= 1 + return .none + case .incrementButtonTapped: + state.count += 1 + return .none + } + } + } +} diff --git a/Sources/TestSupport/Fixtures/app_with_composable_architecture/Project.swift b/Sources/TestSupport/Fixtures/app_with_composable_architecture/Project.swift new file mode 100644 index 00000000..35f89b58 --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_composable_architecture/Project.swift @@ -0,0 +1,25 @@ +import ProjectDescription + +let project = Project( + name: "App", + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: .extendingDefault( + with: [ + "UILaunchScreen": [ + "UIColorName": "", + "UIImageName": "", + ] + ] + ), + sources: ["App/Sources/**"], + dependencies: [ + .external(name: "ComposableArchitecture") + ] + ) + ] +) diff --git a/Sources/TestSupport/Fixtures/app_with_composable_architecture/README.md b/Sources/TestSupport/Fixtures/app_with_composable_architecture/README.md new file mode 100644 index 00000000..5f772ab8 --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_composable_architecture/README.md @@ -0,0 +1,3 @@ +# Application with the Composable Architecture (TCA) + +This example contains an example that uses the Composable Architecture. diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/App.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/App.swift new file mode 100644 index 00000000..6ca35d65 --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/App.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct MyApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/ContentView.swift new file mode 100644 index 00000000..fd34c2f1 --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/ContentView.swift @@ -0,0 +1,13 @@ +import LocalSwiftPackage +import SwiftUI + +public struct ContentView: View { + public init() { + _ = LocalSwiftPackage() + } + + public var body: some View { + Text("Hello, World!") + .padding() + } +} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Package.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Package.swift new file mode 100644 index 00000000..af29ec24 --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Package.swift @@ -0,0 +1,15 @@ +// swift-tools-version: 5.10 + +import PackageDescription + +let package = Package( + name: "LocalSwiftPackage", + products: [ + .library(name: "LocalSwiftPackage", targets: ["LocalSwiftPackage"]) + ], + targets: [ + .target( + name: "LocalSwiftPackage" + ) + ] +) diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift new file mode 100644 index 00000000..0e51666a --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift @@ -0,0 +1,3 @@ +public final class LocalSwiftPackage { + public init() {} +} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/Project.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/Project.swift new file mode 100644 index 00000000..d4685ec9 --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/Project.swift @@ -0,0 +1,29 @@ +import ProjectDescription + +let project = Project( + name: "App", + packages: [ + .package(path: "LocalSwiftPackage") + ], + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: .extendingDefault( + with: [ + "UILaunchScreen": [ + "UIColorName": "", + "UIImageName": "", + ] + ] + ), + sources: ["App/Sources/**"], + resources: [], + dependencies: [ + .package(product: "LocalSwiftPackage", type: .runtimeEmbedded) + ] + ) + ] +) diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/README.md b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/README.md new file mode 100644 index 00000000..dbac75e0 --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/README.md @@ -0,0 +1,7 @@ +# Application with Embedded Local SPM Module + +This example project demonstrates an application that includes a local Swift Package Manager (SPM) module (`LocalSwiftPackage`) configured as an embedded framework. + +The project leverages a local SPM module added to the Embed Frameworks section, showing that local SPM packages can now be embedded within the application. + +This demo project exists to validate and showcase the capability to embed local SPM modules as frameworks, allowing seamless integration into the main app. diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/.package.resolved b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/.package.resolved new file mode 100644 index 00000000..2d2b66fd --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/.package.resolved @@ -0,0 +1,15 @@ +{ + "originHash" : "ed38116a7ef6168e6f489a0ecc15390da3832a222e20155164ff72474d6b4615", + "pins" : [ + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections", + "state" : { + "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", + "version" : "1.1.4" + } + } + ], + "version" : 3 +} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/App.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/App.swift new file mode 100644 index 00000000..6ca35d65 --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/App.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct MyApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/ContentView.swift new file mode 100644 index 00000000..fd34c2f1 --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/ContentView.swift @@ -0,0 +1,13 @@ +import LocalSwiftPackage +import SwiftUI + +public struct ContentView: View { + public init() { + _ = LocalSwiftPackage() + } + + public var body: some View { + Text("Hello, World!") + .padding() + } +} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Package.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Package.swift new file mode 100644 index 00000000..62fc3932 --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Package.swift @@ -0,0 +1,21 @@ +// swift-tools-version: 5.10 + +import PackageDescription + +let package = Package( + name: "LocalSwiftPackage", + products: [ + .library(name: "LocalSwiftPackage", targets: ["LocalSwiftPackage"]) + ], + dependencies: [ + .package(url: "https://github.com/apple/swift-collections", from: "1.0.0") + ], + targets: [ + .target( + name: "LocalSwiftPackage", + dependencies: [ + .product(name: "Collections", package: "swift-collections") + ] + ) + ] +) diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift new file mode 100644 index 00000000..c40facea --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift @@ -0,0 +1,6 @@ +import Collections + +public final class LocalSwiftPackage { + public init() {} + public var deque: Deque = [] +} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/Project.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/Project.swift new file mode 100644 index 00000000..58474d5a --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/Project.swift @@ -0,0 +1,29 @@ +import ProjectDescription + +let project = Project( + name: "App", + packages: [ + .package(path: "LocalSwiftPackage") + ], + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: .extendingDefault( + with: [ + "UILaunchScreen": [ + "UIColorName": "", + "UIImageName": "", + ] + ] + ), + sources: ["App/Sources/**"], + resources: [], + dependencies: [ + .package(product: "LocalSwiftPackage") + ] + ) + ] +) diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/README.md b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/README.md new file mode 100644 index 00000000..a5b09eb1 --- /dev/null +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/README.md @@ -0,0 +1,8 @@ +# Application wih Local SPM Module with Remote Dependencies + +This example contains a project that depends upon a local SPM module (`LocalSwiftPackage`) colocated within this directory. + +This project does NOT contain any direct remote dependencies. +However, `LocalSwiftPackage` DOES have remote dependencies. + +This example application exists to ensure that package resolution occurs even in the case of solely transitive remote dependencies. \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift new file mode 100644 index 00000000..81c349d7 --- /dev/null +++ b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift @@ -0,0 +1,4 @@ +import DynamicFramework +import Foundation + +let dynamicClass = DynamicFramework() diff --git a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift new file mode 100644 index 00000000..521b6409 --- /dev/null +++ b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift @@ -0,0 +1,5 @@ +import Foundation + +public struct DynamicFramework { + public init() {} +} diff --git a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Project.swift b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Project.swift new file mode 100644 index 00000000..b2595958 --- /dev/null +++ b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Project.swift @@ -0,0 +1,26 @@ +import ProjectDescription + +let project = Project( + name: "CommandLineTool", + targets: [ + .target( + name: "CommandLineTool", + destinations: [.mac], + product: .commandLineTool, + bundleId: "com.example.commandlinetool", + infoPlist: .default, + sources: "CommandLineTool/**", + dependencies: [ + .target(name: "DynamicFramework") + ] + ), + .target( + name: "DynamicFramework", + destinations: [.mac], + product: .framework, + bundleId: "com.example.dynamicframework", + infoPlist: .default, + sources: "DynamicFramework/**" + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Tuist/Config.swift b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Tuist/Config.swift new file mode 100644 index 00000000..ff8e64fa --- /dev/null +++ b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Tuist/Config.swift @@ -0,0 +1,3 @@ +import ProjectDescription + +let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_large/Info.plist b/Sources/TestSupport/Fixtures/ios_app_large/Info.plist new file mode 100644 index 00000000..c407fafb --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_large/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSHumanReadableCopyright + Copyright ©. All rights reserved. + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Sources/TestSupport/Fixtures/ios_app_large/Project.swift b/Sources/TestSupport/Fixtures/ios_app_large/Project.swift new file mode 100644 index 00000000..c68b640a --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_large/Project.swift @@ -0,0 +1,18 @@ +import ProjectDescription + +func target(name: String) -> Target { + .target( + name: name, + destinations: .iOS, + product: .app, + bundleId: "io.tuist.\(name)", + infoPlist: .file(path: .relativeToManifest("Info.plist")), + sources: .paths([.relativeToManifest("Sources/**")]), + settings: .settings(base: ["CODE_SIGN_IDENTITY": "", "CODE_SIGNING_REQUIRED": "NO"]) + ) +} + +let project = Project( + name: "App", + targets: (1...300).map { target(name: "App\($0)") } +) diff --git a/Sources/TestSupport/Fixtures/ios_app_large/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_large/Sources/AppDelegate.swift new file mode 100644 index 00000000..14f15f2b --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_large/Sources/AppDelegate.swift @@ -0,0 +1,21 @@ +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func application( + _: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() + return true + } + + func hello() -> String { + "AppDelegate.hello()" + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_large/Tests.plist b/Sources/TestSupport/Fixtures/ios_app_large/Tests.plist new file mode 100644 index 00000000..f1d34193 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_large/Tests.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright ©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_app_large/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_app_large/Tuist/Config.swift new file mode 100644 index 00000000..ff8e64fa --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_large/Tuist/Config.swift @@ -0,0 +1,3 @@ +import ProjectDescription + +let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift new file mode 100644 index 00000000..dd03d4b0 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift @@ -0,0 +1,9 @@ +import AppIntents + +struct AppIntentExtension: AppIntent { + static var title: LocalizedStringResource = "AppIntentExtension" + + func perform() async throws -> some IntentResult { + .result() + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift new file mode 100644 index 00000000..5df8a56a --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift @@ -0,0 +1,6 @@ +import AppIntents + +@main +struct AppIntentExtensionExtension: AppIntentsExtension { + // No implementation +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Bundle/dummy.jpg b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Bundle/dummy.jpg new file mode 100644 index 00000000..e69de29b diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Info.plist new file mode 100644 index 00000000..c407fafb --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSHumanReadableCopyright + Copyright ©. All rights reserved. + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/iMessage App Icon.stickersiconset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/iMessage App Icon.stickersiconset/Contents.json new file mode 100644 index 00000000..bc3c4eea --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/iMessage App Icon.stickersiconset/Contents.json @@ -0,0 +1,78 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x45" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x45" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "67x50" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "74x55" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + }, + { + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "27x20" + }, + { + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "27x20" + }, + { + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "32x24" + }, + { + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "32x24" + }, + { + "idiom" : "ios-marketing", + "platform" : "ios", + "scale" : "1x", + "size" : "1024x768" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard new file mode 100644 index 00000000..36e2d491 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift new file mode 100644 index 00000000..fdd9284c --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift @@ -0,0 +1,57 @@ +import Messages +import UIKit + +class MessagesViewController: MSMessagesAppViewController { + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + } + + // MARK: - Conversation Handling + + override func willBecomeActive(with _: MSConversation) { + // Called when the extension is about to move from the inactive to active state. + // This will happen when the extension is about to present UI. + + // Use this method to configure the extension and restore previously stored state. + } + + override func didResignActive(with _: MSConversation) { + // Called when the extension is about to move from the active to inactive state. + // This will happen when the user dismisses the extension, changes to a different + // conversation or quits Messages. + + // Use this method to release shared resources, save user data, invalidate timers, + // and store enough state information to restore your extension to its current state + // in case it is terminated later. + } + + override func didReceive(_: MSMessage, conversation _: MSConversation) { + // Called when a message arrives that was generated by another instance of this + // extension on a remote device. + + // Use this method to trigger UI updates in response to the message. + } + + override func didStartSending(_: MSMessage, conversation _: MSConversation) { + // Called when the user taps the send button. + } + + override func didCancelSending(_: MSMessage, conversation _: MSConversation) { + // Called when the user deletes the message without sending it. + + // Use this to clean up state related to the deleted message. + } + + override func willTransition(to _: MSMessagesAppPresentationStyle) { + // Called before the extension transitions to a new presentation style. + + // Use this method to prepare for the change in presentation style. + } + + override func didTransition(to _: MSMessagesAppPresentationStyle) { + // Called after the extension transitions to a new presentation style. + + // Use this method to finalize any behaviors associated with the change in presentation style. + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift new file mode 100644 index 00000000..8b8ebc75 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift @@ -0,0 +1,30 @@ +import UserNotifications + +class NotificationService: UNNotificationServiceExtension { + var contentHandler: ((UNNotificationContent) -> Void)? + var bestAttemptContent: UNMutableNotificationContent? + + override func didReceive( + _ request: UNNotificationRequest, + withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void + ) { + self.contentHandler = contentHandler + bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) + + if let bestAttemptContent { + // Modify the notification content here... + bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" + + contentHandler(bestAttemptContent) + } + } + + override func serviceExtensionTimeWillExpire() { + // Called just before the extension will be terminated by the system. + // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will + // be used. + if let contentHandler, let bestAttemptContent { + contentHandler(bestAttemptContent) + } + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Project.swift new file mode 100644 index 00000000..7de95ae0 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Project.swift @@ -0,0 +1,128 @@ +import ProjectDescription + +let project = Project( + name: "App", + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: "Info.plist", + sources: ["Sources/**"], + dependencies: [ + .target(name: "StickersPackExtension"), + .target(name: "NotificationServiceExtension"), + .target(name: "WidgetExtension"), + .target(name: "AppIntentExtension"), + ] + ), + // We need a separate app to test out Message Extensions + // as having both stickers pack and message extensions in one app + // doesn't seem to be supported. + .target( + name: "AppWithMessagesExtension", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App2", + infoPlist: "Info.plist", + sources: ["Sources/**"], + dependencies: [ + .target(name: "MessageExtension"), + .target(name: "NotificationServiceExtension"), + ] + ), + .target( + name: "StickersPackExtension", + destinations: .iOS, + product: .stickerPackExtension, + bundleId: "io.tuist.App.StickersPackExtension", + infoPlist: .extendingDefault(with: [ + "CFBundleDisplayName": "$(PRODUCT_NAME)", + "NSExtension": [ + "NSExtensionPointIdentifier": "com.apple.message-payload-provider", + "NSExtensionPrincipalClass": "StickerBrowserViewController", + ], + ]), + sources: [], + resources: ["StickersPackExtension/**"], + dependencies: [] + ), + .target( + name: "NotificationServiceExtension", + destinations: .iOS, + product: .appExtension, + bundleId: "io.tuist.App.NotificationServiceExtension", + infoPlist: .extendingDefault(with: [ + "CFBundleDisplayName": "$(PRODUCT_NAME)", + "NSExtension": [ + "NSExtensionPointIdentifier": "com.apple.usernotifications.service", + "NSExtensionPrincipalClass": "$(PRODUCT_MODULE_NAME).NotificationService", + ], + ]), + sources: "NotificationServiceExtension/**", + dependencies: [] + ), + .target( + name: "MessageExtension", + destinations: .iOS, + product: .messagesExtension, + bundleId: "io.tuist.App2.MessageExtension", + infoPlist: .extendingDefault(with: [ + "CFBundleDisplayName": "$(PRODUCT_NAME)", + "NSExtension": [ + "NSExtensionMainStoryboard": "MainInterface", + "NSExtensionPointIdentifier": "com.apple.message-payload-provider", + ], + ]), + sources: "MessageExtension/Sources/**", + resources: "MessageExtension/Resources/**", + dependencies: [] + ), + .target( + name: "WidgetExtension", + destinations: .iOS, + product: .appExtension, + bundleId: "io.tuist.App.WidgetExtension", + infoPlist: .extendingDefault(with: [ + "CFBundleDisplayName": "$(PRODUCT_NAME)", + "NSExtension": [ + "NSExtensionPointIdentifier": "com.apple.widgetkit-extension" + ], + ]), + sources: "WidgetExtension/Sources/**", + resources: "WidgetExtension/Resources/**", + dependencies: [ + .target(name: "Bundle"), + .target(name: "StaticFramework"), + ] + ), + .target( + name: "StaticFramework", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.App.StaticFramework", + infoPlist: .default, + sources: "StaticFramework/Sources/**" + ), + .target( + name: "AppIntentExtension", + destinations: .iOS, + product: .extensionKitExtension, + bundleId: "io.tuist.App.AppIntentExtension", + infoPlist: .extendingDefault(with: [ + "EXAppExtensionAttributes": [ + "EXExtensionPointIdentifier": "com.apple.appintents-extension" + ] + ]), + sources: "AppIntentExtension/Sources/**" + ), + .target( + name: "Bundle", + destinations: .iOS, + product: .bundle, + bundleId: "io.tuist.App.Bundle", + resources: "Bundle/**" + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/README.md b/Sources/TestSupport/Fixtures/ios_app_with_extensions/README.md new file mode 100644 index 00000000..ec28324e --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/README.md @@ -0,0 +1,3 @@ +# iOS app with extensions + +Sample iOS application with extension targets. \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift new file mode 100644 index 00000000..9796fd0b --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift @@ -0,0 +1,18 @@ +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func application( + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() + return true + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/Documentation.docc/Documentation.md b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/Documentation.docc/Documentation.md new file mode 100644 index 00000000..e7a804b3 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/Documentation.docc/Documentation.md @@ -0,0 +1,13 @@ +# ``App`` + +Summary + +## Overview + +Text + +## Topics + +### Group + +- ``Symbol`` \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift new file mode 100644 index 00000000..cc50ecff --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift @@ -0,0 +1,5 @@ +import Foundation + +public struct StaticFramework { + public init() {} +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Sticker Pack.stickerpack/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Sticker Pack.stickerpack/Contents.json new file mode 100644 index 00000000..1b6728ea --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Sticker Pack.stickerpack/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "grid-size" : "regular" + } +} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/iMessage App Icon.stickersiconset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/iMessage App Icon.stickersiconset/Contents.json new file mode 100644 index 00000000..28c5ac36 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/iMessage App Icon.stickersiconset/Contents.json @@ -0,0 +1,78 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x45", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x45", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "67x50", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "74x55", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + }, + { + "size" : "27x20", + "idiom" : "universal", + "scale" : "2x", + "platform" : "ios" + }, + { + "size" : "27x20", + "idiom" : "universal", + "scale" : "3x", + "platform" : "ios" + }, + { + "size" : "32x24", + "idiom" : "universal", + "scale" : "2x", + "platform" : "ios" + }, + { + "size" : "32x24", + "idiom" : "universal", + "scale" : "3x", + "platform" : "ios" + }, + { + "size" : "1024x768", + "idiom" : "ios-marketing", + "scale" : "1x", + "platform" : "ios" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Tuist/Config.swift new file mode 100644 index 00000000..ff8e64fa --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Tuist/Config.swift @@ -0,0 +1,3 @@ +import ProjectDescription + +let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AccentColor.colorset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..9221b9bb --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/WidgetBackground.colorset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/WidgetBackground.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/WidgetBackground.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift new file mode 100644 index 00000000..21d02b91 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift @@ -0,0 +1,69 @@ +#if canImport(WidgetKit) + + import SwiftUI + import WidgetKit + + struct Provider: TimelineProvider { + public typealias Entry = SimpleEntry + + func placeholder(in _: Context) -> SimpleEntry { + SimpleEntry(date: Date()) + } + + func getSnapshot(in _: Context, completion _: @escaping (SimpleEntry) -> Void) {} + + func getTimeline(in _: Context, completion _: @escaping (Timeline) -> Void) {} + + public func snapshot(with _: Context, completion: @escaping (SimpleEntry) -> Void) { + let entry = SimpleEntry(date: Date()) + completion(entry) + } + + public func timeline(with _: Context, completion: @escaping (Timeline) -> Void) { + var entries: [SimpleEntry] = [] + + // Generate a timeline consisting of five entries an hour apart, starting from the current date. + let currentDate = Date() + for hourOffset in 0..<5 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! + let entry = SimpleEntry(date: entryDate) + entries.append(entry) + } + + let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) + } + } + + struct SimpleEntry: TimelineEntry { + public let date: Date + } + + struct PlaceholderView: View { + var body: some View { + Text("Placeholder View") + } + } + + struct MyWidgetEntryView: View { + var entry: Provider.Entry + + var body: some View { + Text(entry.date, style: .time) + } + } + + @main + struct MyWidget: Widget { + private let kind: String = "MyWidget" + + public var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: Provider()) { entry in + MyWidgetEntryView(entry: entry) + } + .configurationDisplayName("MyWidget") + .description("This is an example widget.") + } + } + +#endif diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Project.swift new file mode 100644 index 00000000..5281caf5 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Project.swift @@ -0,0 +1,62 @@ +import ProjectDescription + +let settings: Settings = .settings( + base: [ + "PROJECT_BASE": "PROJECT_BASE" + ], + configurations: [ + .debug(name: "Debug", xcconfig: "../ConfigurationFiles/Debug.xcconfig"), + .release(name: "Beta", xcconfig: "../ConfigurationFiles/Beta.xcconfig"), + .release(name: "Release", xcconfig: "../ConfigurationFiles/Release.xcconfig"), + ] +) + +let betaScheme: Scheme = .scheme( + name: "App-Beta", + shared: true, + buildAction: .buildAction(targets: ["App"]), + runAction: .runAction(configuration: "Beta", executable: "App"), + archiveAction: .archiveAction(configuration: "Beta"), + profileAction: .profileAction(configuration: "Release", executable: "App"), + analyzeAction: .analyzeAction(configuration: "Debug") +) + +let betaArchiveOnlyScheme: Scheme = .scheme( + name: "App-Beta-ArchiveOnly", + shared: true, + archiveAction: .archiveAction(configuration: "Beta") +) + +let project = Project( + name: "MainApp", + settings: settings, + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: "Support/App-Info.plist", + sources: "Sources/**", + dependencies: [ + .project(target: "Framework1", path: "../Framework1"), + .project(target: "Framework2", path: "../Framework2"), + ] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.AppTests", + infoPlist: "Support/AppTests-Info.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "App") + ] + ), + ], + schemes: [ + betaScheme, + betaArchiveOnlyScheme, + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift new file mode 100644 index 00000000..862a74f6 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift @@ -0,0 +1,23 @@ +import Framework1 +import Framework2 +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func applicationDidFinishLaunching(_: UIApplication) { + let framework1 = Framework1File() + let framework2 = Framework2File() + + print(hello()) + + print("AppDelegate -> \(framework1.hello())") + print("AppDelegate -> \(framework1.helloFromFramework2())") + print("AppDelegate -> \(framework2.hello())") + } + + func hello() -> String { + "AppDelegate.hello()" + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist new file mode 100644 index 00000000..314db985 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSHumanReadableCopyright + Copyright Tuist©. All rights reserved. + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift new file mode 100644 index 00000000..cf59e05b --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift @@ -0,0 +1,11 @@ +import XCTest + +@testable import App + +class AppDelegateTests: XCTestCase { + func testHello() { + let sut = AppDelegate() + + XCTAssertEqual("AppDelegate.hello()", sut.hello()) + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig new file mode 100644 index 00000000..1251f45d --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig @@ -0,0 +1,2 @@ + +CUSTOM_FLAG = "Beta" \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig new file mode 100644 index 00000000..12491216 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig @@ -0,0 +1,2 @@ + +CUSTOM_FLAG = "Debug" \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig new file mode 100644 index 00000000..5f758db5 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig @@ -0,0 +1,2 @@ + +CUSTOM_FLAG = "Release" \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig new file mode 100644 index 00000000..85a46af1 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig @@ -0,0 +1,2 @@ + +CUSTOM_FLAG = "Target.Beta" \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Debug.xcconfig b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Debug.xcconfig new file mode 100644 index 00000000..0171c5c6 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Debug.xcconfig @@ -0,0 +1,2 @@ + +CUSTOM_FLAG = "Target.Debug" \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Release.xcconfig b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Release.xcconfig new file mode 100644 index 00000000..fc53c985 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Release.xcconfig @@ -0,0 +1,2 @@ + +CUSTOM_FLAG = "Target.Release" \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Project.swift new file mode 100644 index 00000000..34fba0ea --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Project.swift @@ -0,0 +1,43 @@ +import ProjectDescription + +let settings: Settings = .settings( + base: [ + "PROJECT_BASE": "PROJECT_BASE" + ], + configurations: [ + .debug(name: "Debug", xcconfig: "../ConfigurationFiles/Debug.xcconfig"), + .release(name: "Beta", xcconfig: "../ConfigurationFiles/Beta.xcconfig"), + .release(name: "Release", xcconfig: "../ConfigurationFiles/Release.xcconfig"), + ] +) + +let project = Project( + name: "Framework1", + settings: settings, + targets: [ + .target( + name: "Framework1", + destinations: .iOS, + product: .framework, + productName: "Framework1", + bundleId: "io.tuist.Framework1", + infoPlist: "Support/Framework1-Info.plist", + sources: "Sources/**", + dependencies: [ + .project(target: "Framework2", path: "../Framework2") + ] + ), + .target( + name: "Framework1Tests", + destinations: .iOS, + product: .unitTests, + productName: "Framework1Tests", + bundleId: "io.tuist.Framework1Tests", + infoPlist: "Support/Framework1Tests-Info.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "Framework1") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift new file mode 100644 index 00000000..db42cbcb --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift @@ -0,0 +1,16 @@ +import Foundation +import Framework2 + +public class Framework1File { + private let framework2File = Framework2File() + + public init() {} + + public func hello() -> String { + "Framework1File.hello()" + } + + public func helloFromFramework2() -> String { + "Framework1File -> \(framework2File.hello())" + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist new file mode 100644 index 00000000..3c29058d --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright Tuist©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift new file mode 100644 index 00000000..9a1ef6da --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift @@ -0,0 +1,17 @@ +import XCTest + +@testable import Framework1 + +class Framework1Tests: XCTestCase { + func testHello() { + let sut = Framework1File() + + XCTAssertEqual("Framework1File.hello()", sut.hello()) + } + + func testHelloFromFramework2() { + let sut = Framework1File() + + XCTAssertEqual("Framework1File -> Framework2File.hello()", sut.helloFromFramework2()) + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Project.swift new file mode 100644 index 00000000..383a060f --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Project.swift @@ -0,0 +1,47 @@ +import ProjectDescription + +let settings: Settings = .settings( + configurations: [ + .debug(name: "Debug", xcconfig: "../ConfigurationFiles/Debug.xcconfig"), + .release(name: "Beta", xcconfig: "../ConfigurationFiles/Beta.xcconfig"), + .release(name: "Release", xcconfig: "../ConfigurationFiles/Release.xcconfig"), + ] +) + +// Targets can override select configurations if needed +let targetSettings: Settings = .settings( + base: [ + "TARGET_BASE": "TARGET_BASE" + ], + configurations: [ + .release(name: "Beta", xcconfig: "../ConfigurationFiles/Target.Beta.xcconfig") + ] +) + +let project = Project( + name: "Framework2", + settings: settings, + targets: [ + .target( + name: "Framework2", + destinations: .iOS, + product: .framework, + bundleId: "io.tuist.Framework2", + infoPlist: "Support/Framework2-Info.plist", + sources: "Sources/**", + dependencies: [], + settings: targetSettings + ), + .target( + name: "Framework2Tests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.Framework2Tests", + infoPlist: "Support/Framework2Tests-Info.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "Framework2") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift new file mode 100644 index 00000000..f3102dcd --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift @@ -0,0 +1,9 @@ +import Foundation + +public class Framework2File { + public init() {} + + public func hello() -> String { + "Framework2File.hello()" + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist new file mode 100644 index 00000000..3c29058d --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright Tuist©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift new file mode 100644 index 00000000..c96eef5f --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift @@ -0,0 +1,11 @@ +import XCTest + +@testable import Framework2 + +class Framework2Tests: XCTestCase { + func testHello() { + let sut = Framework2File() + + XCTAssertEqual("Framework2File.hello()", sut.hello()) + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/README.md b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/README.md new file mode 100644 index 00000000..f2f40c42 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/README.md @@ -0,0 +1,3 @@ +# iOS app with multiple configurations and an xcconfig + +A workspace that contains an application and frameworks that leverage multiple configurations (Debug, Beta and Release) each of which also has an associated xcconfig file within `ConfigurationFiles`. \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Tuist/Config.swift new file mode 100644 index 00000000..ff8e64fa --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Tuist/Config.swift @@ -0,0 +1,3 @@ +import ProjectDescription + +let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Workspace.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Workspace.swift new file mode 100644 index 00000000..f9fb261a --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Workspace.swift @@ -0,0 +1,6 @@ +import ProjectDescription + +let workspace = Workspace( + name: "Workspace", + projects: ["App", "Framework1", "Framework2"] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/.package.resolved b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/.package.resolved new file mode 100644 index 00000000..6e3d7b59 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/.package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "RxSwift", + "repositoryURL": "https://github.com/ReactiveX/RxSwift", + "state": { + "branch": null, + "revision": "b3e888b4972d9bc76495dd74d30a8c7fad4b9395", + "version": "5.0.1" + } + } + ] + }, + "version": 1 +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Package.resolved b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Package.resolved new file mode 100644 index 00000000..6e3d7b59 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "RxSwift", + "repositoryURL": "https://github.com/ReactiveX/RxSwift", + "state": { + "branch": null, + "revision": "b3e888b4972d9bc76495dd74d30a8c7fad4b9395", + "version": "5.0.1" + } + } + ] + }, + "version": 1 +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Project.swift new file mode 100644 index 00000000..113474ef --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Project.swift @@ -0,0 +1,37 @@ +import ProjectDescription + +let project = Project( + name: "App", + packages: [ + .package(url: "https://github.com/ReactiveX/RxSwift", .upToNextMajor(from: "5.0.0")) + ], + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: "Support/Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ], + dependencies: [ + .package(product: "RxSwift"), + .package(product: "RxBlocking"), + ] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.AppTests", + infoPlist: "Support/Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "App") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/README.md b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/README.md new file mode 100644 index 00000000..14993460 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/README.md @@ -0,0 +1,3 @@ +# iOS App with a remote Swift package + +An iOS application with a remote Swift package. \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift new file mode 100644 index 00000000..2049b986 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift @@ -0,0 +1,25 @@ +import RxBlocking +import RxSwift +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func application( + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + // To make sure RxSwift is available + let observable = RxSwift.Observable.just("Test") + + let result = RxBlocking.MaterializedSequenceResult.completed(elements: [1, 2]) + + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() + return true + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Info.plist new file mode 100644 index 00000000..c407fafb --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSHumanReadableCopyright + Copyright ©. All rights reserved. + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist new file mode 100644 index 00000000..f1d34193 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright ©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift new file mode 100644 index 00000000..12be2987 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift @@ -0,0 +1,6 @@ +import Foundation +import XCTest + +@testable import App + +final class AppTests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tuist/Config.swift new file mode 100644 index 00000000..ff8e64fa --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tuist/Config.swift @@ -0,0 +1,3 @@ +import ProjectDescription + +let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..13613e3e --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift new file mode 100644 index 00000000..9a54aeba --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct AppApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift new file mode 100644 index 00000000..ecd023f7 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift @@ -0,0 +1,30 @@ +import Buy +import JWTKit +import KSCrashInstallations +import Pay +import SwiftUI + +struct ContentView: View { + init() { + // Use Mobile Buy SDK + _ = Card.CreditCard(firstName: "", lastName: "", number: "", expiryMonth: "", expiryYear: "") + _ = PayAddress() + // Use KSCrash + _ = CrashInstallationStandard() + // Use JWTKit + _ = JWTKit.ES256PrivateKey() + } + + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + Text("Hello, world!") + } + .padding() + } +} + +#Preview { + ContentView() +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift new file mode 100644 index 00000000..2e6edc5b --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift @@ -0,0 +1,21 @@ +import XCTest + +@testable import App + +final class AppTests: XCTestCase { + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Project.swift new file mode 100644 index 00000000..bce1f982 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Project.swift @@ -0,0 +1,34 @@ +import ProjectDescription + +let project = Project( + name: "App", + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.app", + deploymentTargets: .iOS("16.0"), + infoPlist: .default, + sources: "App/Sources/**", + resources: "App/Resources/**", + dependencies: [ + .external(name: "Buy"), + .external(name: "Pay"), + .external(name: "Installations"), + .external(name: "JWTKit"), + .sdk(name: "c++", type: .library, status: .required), + ] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.app.tests", + deploymentTargets: .iOS("16.0"), + infoPlist: .default, + sources: "AppTests/**", + dependencies: [.target(name: "App")] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/README.md b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/README.md new file mode 100644 index 00000000..2b052bf2 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/README.md @@ -0,0 +1,3 @@ +# iOS app with SPM dependencies + +An iOS application project with various SPM dependencies. \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.resolved b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.resolved new file mode 100644 index 00000000..a875c203 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.resolved @@ -0,0 +1,69 @@ +{ + "originHash" : "57e8e560522d98da034eecf136da2a0571e102267ae8fa09d2264359afbe28cd", + "pins" : [ + { + "identity" : "bigint", + "kind" : "remoteSourceControl", + "location" : "https://github.com/attaswift/BigInt.git", + "state" : { + "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", + "version" : "5.3.0" + } + }, + { + "identity" : "jwt-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/jwt-kit.git", + "state" : { + "revision" : "6f512cb5a531e684f2e5238924be81db0b3303b4", + "version" : "5.0.0-beta.3" + } + }, + { + "identity" : "kscrash", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kstenerud/KSCrash", + "state" : { + "revision" : "353a7ea8f32e34b9008dd7aa6dc0b6466b7daf37", + "version" : "2.0.0-rc.3" + } + }, + { + "identity" : "mobile-buy-sdk-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Shopify/mobile-buy-sdk-ios", + "state" : { + "revision" : "6bd23c2f6243f73ef6ec135723d4909bc068409e", + "version" : "12.0.0" + } + }, + { + "identity" : "swift-asn1", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-asn1.git", + "state" : { + "revision" : "c7e239b5c1492ffc3ebd7fbcc7a92548ce4e78f0", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-certificates", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-certificates.git", + "state" : { + "revision" : "83640c8097acaec17c9835a083e89678cb0f2b66", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "bc1c29221f6dfeb0ebbfbc98eb95cd3d4967868e", + "version" : "3.4.0" + } + } + ], + "version" : 3 +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.swift new file mode 100644 index 00000000..b607e964 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.swift @@ -0,0 +1,14 @@ +// swift-tools-version: 5.10 +@preconcurrency import PackageDescription + +let package = Package( + name: "PackageName", + dependencies: [ + // Has space symbols in package name + .package(url: "https://github.com/Shopify/mobile-buy-sdk-ios", exact: "12.0.0"), + // Has targets with slash symbols in their names + .package(url: "https://github.com/kstenerud/KSCrash", exact: "2.0.0-rc.3"), + // Has custom `swiftSettings` and uses the package access level + .package(url: "https://github.com/vapor/jwt-kit.git", .upToNextMajor(from: "5.0.0-beta.2.1")), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Info.plist new file mode 100755 index 00000000..c407fafb --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSHumanReadableCopyright + Copyright ©. All rights reserved. + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/CustomHeaders/CustomHeader.h b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/CustomHeaders/CustomHeader.h new file mode 100644 index 00000000..e69de29b diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/Contents.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/Contents.swift new file mode 100755 index 00000000..fecc4ab4 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/Contents.swift @@ -0,0 +1 @@ +import Foundation diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/contents.xcplayground b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/contents.xcplayground new file mode 100755 index 00000000..4e6c0b72 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Project.swift new file mode 100755 index 00000000..625f477d --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Project.swift @@ -0,0 +1,36 @@ +import ProjectDescription + +let project = Project( + name: "A", + targets: [ + .target( + name: "A", + destinations: .iOS, + product: .staticLibrary, + bundleId: "io.tuist.A", + infoPlist: nil, + sources: "Sources/**", + dependencies: [ + .project(target: "B", path: "../B"), + .library( + path: "../C/prebuilt/C/libC.a", + publicHeaders: "../C/prebuilt/C", + swiftModuleMap: "../C/prebuilt/C/C.swiftmodule" + ), + ], + + settings: .settings(base: ["HEADER_SEARCH_PATHS": "$(SRCROOT)/CustomHeaders"]) + ), + .target( + name: "ATests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.ATests", + infoPlist: nil, + sources: "Tests/**", + dependencies: [ + .target(name: "A") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift new file mode 100755 index 00000000..55130f98 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift @@ -0,0 +1,12 @@ +import B +import C + +public enum A { + public static let value: String = "aValue" + + public static func printFromA() { + print("print from A") + B.printFromB() + C.printFromC() + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift new file mode 100755 index 00000000..c1848d89 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift @@ -0,0 +1,10 @@ +import Foundation +import XCTest + +@testable import A + +final class ATests: XCTestCase { + func test_value() { + XCTAssertEqual(A.value, "aValue") + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist new file mode 100755 index 00000000..a11b3ce7 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright ©. All rights reserved. + NSPrincipalClass + + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/Contents.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/Contents.swift new file mode 100755 index 00000000..fecc4ab4 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/Contents.swift @@ -0,0 +1 @@ +import Foundation diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/contents.xcplayground b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/contents.xcplayground new file mode 100755 index 00000000..4e6c0b72 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Project.swift new file mode 100755 index 00000000..5b80005d --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Project.swift @@ -0,0 +1,30 @@ +import ProjectDescription + +let project = Project( + name: "B", + targets: [ + .target( + name: "B", + destinations: .iOS, + product: .staticLibrary, + bundleId: "io.tuist.B", + infoPlist: "Info.plist", + sources: "Sources/**", + dependencies: [ + /* Target dependencies can be defined here */ + /* .framework(path: "framework") */ + ] + ), + .target( + name: "BTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.BTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "B") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift new file mode 100755 index 00000000..10a98b5a --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift @@ -0,0 +1,9 @@ +import Foundation + +public enum B { + public static let value: String = "bValue" + + public static func printFromB() { + print("print from B") + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist new file mode 100755 index 00000000..f1d34193 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright ©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift new file mode 100755 index 00000000..c262f528 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift @@ -0,0 +1,10 @@ +import Foundation +import XCTest + +@testable import B + +final class BTests: XCTestCase { + func test_value() { + XCTAssertEqual(B.value, "bValue") + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Info.plist new file mode 100755 index 00000000..a11b3ce7 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright ©. All rights reserved. + NSPrincipalClass + + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Project.swift new file mode 100755 index 00000000..11bb4d1c --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Project.swift @@ -0,0 +1,31 @@ +import ProjectDescription + +let project = Project( + name: "C", + targets: [ + .target( + name: "C", + destinations: .iOS, + product: .staticLibrary, + bundleId: "io.tuist.C", + infoPlist: "Info.plist", + sources: "Sources/**", + dependencies: [ + /* Target dependencies can be defined here */ + /* .framework(path: "framework") */ + ], + settings: .settings(base: ["BUILD_LIBRARY_FOR_DISTRIBUTION": "YES"]) + ), + .target( + name: "CTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.BTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "C") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Sources/C.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Sources/C.swift new file mode 100755 index 00000000..31ab0a24 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Sources/C.swift @@ -0,0 +1,9 @@ +import Foundation + +public enum C { + public static let value: String = "cValue" + + public static func printFromC() { + print("print from C") + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests.plist b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests.plist new file mode 100755 index 00000000..f1d34193 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright ©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests/CTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests/CTests.swift new file mode 100755 index 00000000..8ab03e78 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests/CTests.swift @@ -0,0 +1,10 @@ +import Foundation +import XCTest + +@testable import C + +final class BTests: XCTestCase { + func test_value() { + XCTAssertEqual(C.value, "cValue") + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/build.sh b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/build.sh new file mode 100755 index 00000000..e038b4bc --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/build.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +rm -rf prebuilt +tuist generate --no-open + +TEMP_DIR="/tmp/tuist-lib-c-fixture" +IPHONE_SIM_DIR="$TEMP_DIR/Build/Products/Debug-iphonesimulator" + +rm -rf $TEMP_DIR +mkdir -p $TEMP_DIR + +xcrun xcodebuild build -scheme C -workspace C.xcworkspace -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone 14 Pro,OS=latest" -derivedDataPath $TEMP_DIR ONLY_ACTIVE_ARCH=NO + +mkdir -p prebuilt/C +lipo -create \ + "$IPHONE_SIM_DIR/libC.a" \ + -output "$(pwd)/prebuilt/C/libC.a" + +mkdir -p prebuilt/C/C.swiftmodule +cp -r \ + "$IPHONE_SIM_DIR/C.swiftmodule/"* \ + "$(pwd)/prebuilt/C/C.swiftmodule/" + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo new file mode 100644 index 0000000000000000000000000000000000000000..a4b1292a8854a772a656dfb447ecf620369443bc GIT binary patch literal 1084 zcmbVK&rcIk5Z-RV;ucNQs2HNLsi?c`@9p-N>4CO{o3ROaA;h}0yRuE8&F;2HqKP&= zcp%zCZ%9xACqdBQjYP7>ghMru@JDzu{R4V%UQ3}~o#fm3-hA_B-g`UEwYP5^0~i*= zFwEtcV`jFS#74@!l_I_g?wyqTi$HAFh)++5ou+&JfY=d;k44Xj`zN_yp^qxeK2EnP zo+z?k1>Kg{~&(y8T@|N|1*(1z9)xK74N064Wvj z!0COPY}owkHrcY1Qw^IwsW8iEC$)jYPJTBr+Q8Y^*ekMXGaEM9!l}9qjrn$OCPsGG zCpL3v!`jK#aqh_GYY7sX#+W_|nzSlRwL-s3Pz@aJ>u?QVzrf!a#ISqdz5P?Umj^z< z;~y7OgIAnC-g{kpP7uy*i~t@l7W1laa#7bTUs*Lwy|Ca5a$!#LktPb}m4&BlJHUy7 zAQ$vy+7VF}1Ww?jC>IndXo)2Oe*lUxACg%GRb};pDTX+SHTC&YUa<-W=*aqA9&8=F z{~CFW&WjSy@&h89@@FvKEmu zK`j!<$Z~Z0?$Yqp6KQCzQx5ZAm^+41II~;8(Dg5!MLHx0ZWw^H-h8AYZ5414-~jX* z(z+G}(gzso22MT7`CqMD3e~s(xZVw%dK7;QKpJ}gUPIan0Ntm*R{)MQiSP{OX0Va& zogCQI>hlshy?I|u#^Vn~p=js})`U@*PcAJ@OrxKKV_$PGs^0UYU|GqR)XB+maT*o6 zxw*3CI#+?U`~N#~DB5`|szcjf|K;D?D35<+!UXbJjUQLbYQ9iZ4c;p0ro|VHLQc(C z=IK(?pIIeCHF=n@G|XChQMcyOrlnYVCY{%34aLwweNf1j^5B#FWT9ka5aZfI4ZZwc J59_y@ literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo new file mode 100644 index 0000000000000000000000000000000000000000..23022a2a99268f068c20a4ff4200b2c4dcbc0c03 GIT binary patch literal 1084 zcmbVK&rcIk5Z-Qq;ucNQs2HNLsi?bb_h+}iOb>KRxEY%iFN9c^b}QQy+U#x%B${Z` zg9oBL^o9f_a1sO!-bf^COgK~n34esgo;>y7yp}?}I?1>5z4_+Ny!UpR>u=xK1~Dv( zVVJ`<=bPDS5}OIXFJ{Dc0&Y$E#g+8wM4sg0v zA@?kL#Ttu_#^^fERB@^bU(0@H-=b?WvnNxn3SE`yy7gT+mdPWFf~=c;A3is0GPME) zaQeU^8y5GvO}4H0RKucAE4~%9liI{#C$}e$HEV`61hZ+yFNPu!kr%RjBopMb{*0=sd{7D~yf~W?LwrV(lyI6C`G}Ma zOX)y1>`zNlWcuFn$hA{(c)e2&^A60Nz$l#CZD8p7m(L>|k^?saKw57;QjxX>xCF2P zdJSn^ivZ~Z40i)(9_9S6)-8o<3;=F)17{w^p8$}C-oMw7whBP^>F*VQBTXb+L%A7j zw0kETHnsM=gidcf5aO}eBY`jK+JZT$7v|&3%ahaSC*j!F+>5IFA}LT-@+CEyEElIy zp<7$4+l~trSiAqfBZs1$x1u_<{qn73Do!eg=7U{(R literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.abi.json b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.abi.json new file mode 100644 index 00000000..318b6c33 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.abi.json @@ -0,0 +1,108 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "Foundation", + "printedName": "Foundation", + "declKind": "Import", + "moduleName": "C" + }, + { + "kind": "TypeDecl", + "name": "C", + "printedName": "C", + "children": [ + { + "kind": "Var", + "name": "value", + "printedName": "value", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + } + ], + "declKind": "Var", + "usr": "s:1CAAO5valueSSvpZ", + "mangledName": "$s1CAAO5valueSSvpZ", + "moduleName": "C", + "static": true, + "declAttributes": [ + "HasInitialValue", + "HasStorage", + "AccessControl" + ], + "isLet": true, + "hasStorage": true, + "accessors": [ + { + "kind": "Accessor", + "name": "Get", + "printedName": "Get()", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + } + ], + "declKind": "Accessor", + "usr": "s:1CAAO5valueSSvgZ", + "mangledName": "$s1CAAO5valueSSvgZ", + "moduleName": "C", + "static": true, + "implicit": true, + "accessorKind": "get" + } + ] + }, + { + "kind": "Function", + "name": "printFromC", + "printedName": "printFromC()", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + } + ], + "declKind": "Func", + "usr": "s:1CAAO10printFromCyyFZ", + "mangledName": "$s1CAAO10printFromCyyFZ", + "moduleName": "C", + "static": true, + "declAttributes": [ + "AccessControl" + ], + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Enum", + "usr": "s:1CAAO", + "mangledName": "$s1CAAO", + "moduleName": "C", + "declAttributes": [ + "AccessControl" + ] + } + ], + "json_format_version": 8 + }, + "ConstValues": [ + { + "filePath": "\/Users\/df\/Developer\/tuist\/projects\/tuist\/fixtures\/ios_app_with_static_libraries\/Modules\/C\/Sources\/C.swift", + "kind": "StringLiteral", + "offset": 73, + "length": 8, + "value": "\"cValue\"" + } + ] +} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface new file mode 100644 index 00000000..9ca576a8 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface @@ -0,0 +1,12 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51) +// swift-module-flags: -target arm64-apple-ios16.2-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name C +// swift-module-flags-ignorable: -enable-bare-slash-regex +import Foundation +import Swift +import _Concurrency +import _StringProcessing +public enum C { + public static let value: Swift.String + public static func printFromC() +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.swiftdoc new file mode 100644 index 0000000000000000000000000000000000000000..caeb1b3bbf84dd061b575686f70b5b8ecdfe7062 GIT binary patch literal 400 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 literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.abi.json b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.abi.json new file mode 100644 index 00000000..318b6c33 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.abi.json @@ -0,0 +1,108 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "Foundation", + "printedName": "Foundation", + "declKind": "Import", + "moduleName": "C" + }, + { + "kind": "TypeDecl", + "name": "C", + "printedName": "C", + "children": [ + { + "kind": "Var", + "name": "value", + "printedName": "value", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + } + ], + "declKind": "Var", + "usr": "s:1CAAO5valueSSvpZ", + "mangledName": "$s1CAAO5valueSSvpZ", + "moduleName": "C", + "static": true, + "declAttributes": [ + "HasInitialValue", + "HasStorage", + "AccessControl" + ], + "isLet": true, + "hasStorage": true, + "accessors": [ + { + "kind": "Accessor", + "name": "Get", + "printedName": "Get()", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + } + ], + "declKind": "Accessor", + "usr": "s:1CAAO5valueSSvgZ", + "mangledName": "$s1CAAO5valueSSvgZ", + "moduleName": "C", + "static": true, + "implicit": true, + "accessorKind": "get" + } + ] + }, + { + "kind": "Function", + "name": "printFromC", + "printedName": "printFromC()", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + } + ], + "declKind": "Func", + "usr": "s:1CAAO10printFromCyyFZ", + "mangledName": "$s1CAAO10printFromCyyFZ", + "moduleName": "C", + "static": true, + "declAttributes": [ + "AccessControl" + ], + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Enum", + "usr": "s:1CAAO", + "mangledName": "$s1CAAO", + "moduleName": "C", + "declAttributes": [ + "AccessControl" + ] + } + ], + "json_format_version": 8 + }, + "ConstValues": [ + { + "filePath": "\/Users\/df\/Developer\/tuist\/projects\/tuist\/fixtures\/ios_app_with_static_libraries\/Modules\/C\/Sources\/C.swift", + "kind": "StringLiteral", + "offset": 73, + "length": 8, + "value": "\"cValue\"" + } + ] +} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface new file mode 100644 index 00000000..498702a3 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface @@ -0,0 +1,12 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51) +// swift-module-flags: -target x86_64-apple-ios16.2-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name C +// swift-module-flags-ignorable: -enable-bare-slash-regex +import Foundation +import Swift +import _Concurrency +import _StringProcessing +public enum C { + public static let value: Swift.String + public static func printFromC() +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.swiftdoc new file mode 100644 index 0000000000000000000000000000000000000000..7d830f74f7ca665328c074fa5197598e03420cbc GIT binary patch literal 400 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 + + + \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Project.swift new file mode 100755 index 00000000..bc51dda9 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Project.swift @@ -0,0 +1,29 @@ +import ProjectDescription + +let project = Project( + name: "iOSAppWithTransistiveStaticLibraries", + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: "Info.plist", + sources: "Sources/**", + dependencies: [ + .project(target: "A", path: "Modules/A") + ] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.AppTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "App") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/README.md b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/README.md new file mode 100644 index 00000000..98320247 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/README.md @@ -0,0 +1,33 @@ +# iOS app with static libraries + + +This application provides a top level application with two static library dependencies. The first static library dependency has another static library dependency so that we are able to test how Tuist handles the transitiveness of the static libraries in the linked frameworks of the main app. + +``` +Workspace: + - App: + - MainApp (iOS app) + - MainAppTests (iOS unit tests) + - A: + - A (static library iOS) + - ATests (iOS unit tests) + - B: + - B (static library iOS) + - BTests (iOS unit tests) +``` + +A standalone C project is used to generate a prebuilt static library: + +``` + - C: + - C (static library iOS) + - CTests (iOS unit tests) +``` + +Dependencies: + +- App -> A +- A -> B +- A -> prebuild C (libC.a) + +Note: to re-create `libC.a` run `ios_app_with_static_libraries/Modules/C/build.sh` \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift new file mode 100755 index 00000000..9eaed6c1 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift @@ -0,0 +1,25 @@ +import A +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func application( + _: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() + + A.printFromA() + + return true + } +} + +public enum AClassInThisBundle { + public static let value: String = "aValue" +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests.plist b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests.plist new file mode 100755 index 00000000..f1d34193 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright ©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift new file mode 100755 index 00000000..18a4eda2 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift @@ -0,0 +1,10 @@ +import Foundation +import XCTest + +@testable import App + +final class AppTests: XCTestCase { + func test_application() { + XCTAssertEqual(App.AClassInThisBundle.value, "aValue") + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tuist/Config.swift new file mode 100644 index 00000000..ff8e64fa --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tuist/Config.swift @@ -0,0 +1,3 @@ +import ProjectDescription + +let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist new file mode 100644 index 00000000..314db985 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSHumanReadableCopyright + Copyright Tuist©. All rights reserved. + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Project.swift new file mode 100644 index 00000000..4fbc6fc6 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Project.swift @@ -0,0 +1,40 @@ +import ProjectDescription + +let project = Project( + name: "MainApp", + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: "Config/App-Info.plist", + sources: "Sources/**", + dependencies: [ + .project(target: "Framework1-iOS", path: "../Framework1") + ] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.AppTests", + infoPlist: "Config/AppTests-Info.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "App") + ] + ), + .target( + name: "AppUITests", + destinations: .iOS, + product: .uiTests, + bundleId: "io.tuist.AppUITests", + infoPlist: "Config/AppTests-Info.plist", + sources: "UITests/**", + dependencies: [ + .target(name: "App") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift new file mode 100644 index 00000000..2b97535e --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift @@ -0,0 +1,19 @@ +import Framework1 +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func applicationDidFinishLaunching(_: UIApplication) { + let framework1 = Framework1File() + + print(hello()) + print("AppDelegate -> \(framework1.hello())") + print("AppDelegate -> \(framework1.helloFromFramework2())") + } + + func hello() -> String { + "AppDelegate.hello()" + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift new file mode 100644 index 00000000..cf59e05b --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift @@ -0,0 +1,11 @@ +import XCTest + +@testable import App + +class AppDelegateTests: XCTestCase { + func testHello() { + let sut = AppDelegate() + + XCTAssertEqual("AppDelegate.hello()", sut.hello()) + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift new file mode 100644 index 00000000..90376ef8 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift @@ -0,0 +1,26 @@ +import XCTest + +class AppUITest: XCTestCase { + override func setUp() { + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + + // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test + // method. + XCUIApplication().launch() + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before + // they run. The setUp method is a good place to do this. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() { + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist new file mode 100644 index 00000000..3c29058d --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright Tuist©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1Tests-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1Tests-Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1Tests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Project.swift new file mode 100644 index 00000000..bf1a3b58 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Project.swift @@ -0,0 +1,53 @@ +import ProjectDescription + +let project = Project( + name: "Framework1", + targets: [ + .target( + name: "Framework1-iOS", + destinations: .iOS, + product: .framework, + productName: "Framework1", + bundleId: "io.tuist.Framework1", + infoPlist: "Config/Framework1-Info.plist", + sources: "Sources/**", + dependencies: [ + .framework(path: "../Framework2/prebuilt/iOS/Framework2.framework") + ] + ), + .target( + name: "Framework1-macOS", + destinations: [.mac], + product: .framework, + productName: "Framework1", + bundleId: "io.tuist.Framework1", + infoPlist: "Config/Framework1-Info.plist", + sources: "Sources/**", + dependencies: [ + .framework(path: "../Framework2/prebuilt/Mac/Framework2.framework") + ] + ), + .target( + name: "Framework1Tests-iOS", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.Framework1Tests", + infoPlist: "Tests/Info.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "Framework1-iOS") + ] + ), + .target( + name: "Framework1Tests-macOS", + destinations: [.mac], + product: .unitTests, + bundleId: "io.tuist.Framework1Tests", + infoPlist: "Tests/Info.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "Framework1-macOS") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift new file mode 100644 index 00000000..db42cbcb --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift @@ -0,0 +1,16 @@ +import Foundation +import Framework2 + +public class Framework1File { + private let framework2File = Framework2File() + + public init() {} + + public func hello() -> String { + "Framework1File.hello()" + } + + public func helloFromFramework2() -> String { + "Framework1File -> \(framework2File.hello())" + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift new file mode 100644 index 00000000..2aebdd35 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift @@ -0,0 +1,19 @@ +import XCTest + +@testable import Framework1 + +class Framework1Tests: XCTestCase { + func testHello() { + let sut = Framework1File() + + XCTAssertEqual("Framework1File.hello()", sut.hello()) + } + + #if canImport(Framework2) + func testHelloFromFramework2() { + let sut = Framework1File() + + XCTAssertEqual("Framework1File -> Framework2File.hello()", sut.helloFromFramework2()) + } + #endif +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Config/Framework2-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Config/Framework2-Info.plist new file mode 100644 index 00000000..3c29058d --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Config/Framework2-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright Tuist©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Project.swift new file mode 100644 index 00000000..b1878805 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Project.swift @@ -0,0 +1,29 @@ +import ProjectDescription + +let project = Project( + name: "Framework2", + targets: [ + .target( + name: "Framework2-iOS", + destinations: .iOS, + product: .framework, + productName: "Framework2", + bundleId: "io.tuist.Framework2", + infoPlist: "Config/Framework2-Info.plist", + sources: "Sources/**", + dependencies: [], + settings: .settings(base: ["BUILD_LIBRARY_FOR_DISTRIBUTION": "YES"]) + ), + .target( + name: "Framework2-macOS", + destinations: [.mac], + product: .framework, + productName: "Framework2", + bundleId: "io.tuist.Framework2", + infoPlist: "Config/Framework2-Info.plist", + sources: "Sources/**", + dependencies: [], + settings: .settings(base: ["BUILD_LIBRARY_FOR_DISTRIBUTION": "YES"]) + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Sources/Framework2File.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Sources/Framework2File.swift new file mode 100644 index 00000000..f3102dcd --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Sources/Framework2File.swift @@ -0,0 +1,9 @@ +import Foundation + +public class Framework2File { + public init() {} + + public func hello() -> String { + "Framework2File.hello()" + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/build.sh b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/build.sh new file mode 100755 index 00000000..a12e6fca --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/build.sh @@ -0,0 +1,62 @@ +#!/bin/sh + +rm -rf prebuild +tuist generate --no-open + +TEMP_DIR=/private$(mktemp -d) +IPHONE_SIM_DIR="$TEMP_DIR/Build/Products/Debug-iphonesimulator" +MAC_OS_DIR="$TEMP_DIR/Build/Products/Debug" + +echo $TEMP_DIR +trap "rm -rf $TEMP_DIR" EXIT # Ensures it gets deleted + +xcrun xcodebuild build -scheme Framework2-iOS -workspace Framework2.xcworkspace -destination generic/platform=iOS -destination generic/platform=iOS\ Simulator -derivedDataPath $TEMP_DIR ONLY_ACTIVE_ARCH=NO +xcrun xcodebuild build -scheme Framework2-macOS -workspace Framework2.xcworkspace -derivedDataPath $TEMP_DIR + +mkdir -p prebuilt/iOS/Framework2.framework +lipo -create \ + "$IPHONE_SIM_DIR/Framework2.framework/Framework2" \ + -output "$(pwd)/prebuilt/iOS/Framework2.framework/Framework2" + +cp \ + "$IPHONE_SIM_DIR/Framework2.framework/Info.plist" \ + "$(pwd)/prebuilt/iOS/Framework2.framework/Info.plist" + +mkdir -p prebuilt/iOS/Framework2.framework/Headers +cp -r \ + "$IPHONE_SIM_DIR/Framework2.framework/Headers/"* \ + "$(pwd)/prebuilt/iOS/Framework2.framework/Headers/" + +mkdir -p prebuilt/iOS/Framework2.framework/Modules +cp \ + "$IPHONE_SIM_DIR/Framework2.framework/Modules/module.modulemap" \ + "$(pwd)/prebuilt/iOS/Framework2.framework/Modules/module.modulemap" + +mkdir -p prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule +cp -r \ + "$IPHONE_SIM_DIR/Framework2.framework/Modules/Framework2.swiftmodule/"* \ + "$(pwd)/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/" + +mkdir -p prebuilt/Mac/Framework2.framework +cp \ + "$MAC_OS_DIR/Framework2.framework/Framework2" \ + "$(pwd)/prebuilt/Mac/Framework2.framework/Framework2" + +cp \ + "$MAC_OS_DIR/Framework2.framework/Resources/Info.plist" \ + "$(pwd)/prebuilt/Mac/Framework2.framework/Info.plist" + +mkdir -p prebuilt/Mac/Framework2.framework/Headers +cp -r \ + "$MAC_OS_DIR/Framework2.framework/Headers/"* \ + "$(pwd)/prebuilt/Mac/Framework2.framework/Headers/" + +mkdir -p prebuilt/Mac/Framework2.framework/Modules +cp \ + "$MAC_OS_DIR/Framework2.framework/Modules/module.modulemap" \ + "$(pwd)/prebuilt/Mac/Framework2.framework/Modules/module.modulemap" + +mkdir -p prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule +cp -r \ + "$MAC_OS_DIR/Framework2.framework/Modules/Framework2.swiftmodule/"* \ + "$(pwd)/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/" diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Framework2 b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Framework2 new file mode 100755 index 0000000000000000000000000000000000000000..0189f66a91a0260769f79ebd3cc85c2b1ec922e1 GIT binary patch literal 54712 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 +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="Framework2",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#else +#error unsupported Swift architecture +#endif diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Info.plist new file mode 100644 index 00000000..08d45571 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Info.plist @@ -0,0 +1,48 @@ + + + + + BuildMachineOSBuild + 23C71 + CFBundleDevelopmentRegion + en + CFBundleExecutable + Framework2 + CFBundleIdentifier + io.tuist.Framework2 + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Framework2 + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + + DTPlatformName + macosx + DTPlatformVersion + 14.2 + DTSDKBuild + 23C53 + DTSDKName + macosx14.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + LSMinimumSystemVersion + 14.2 + NSHumanReadableCopyright + Copyright Tuist©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo new file mode 100644 index 0000000000000000000000000000000000000000..9674059f0c081efcbbe707b98b7d826b82aa7e99 GIT binary patch literal 1140 zcmaJ=%}*0S6rXN^;+Bv~2quQZrefS>xBErgP}74ggo~HPqFzkucDqX#TH5TkAQyv8 z55^E_OuZ2lgC`NH!5fKWjR^-#AmQM_KY(NZfSUNGPzpwT$=iAJ`@N5OGjHo}mR~x$ z5eg%OT#hvN=wqE+kGVHuuw?y(o-ZSL>LGP5umr+OvI zEI|T--LdI?TX^0yHteyo(mWn5qqhg=TFo zOtP1q}DHt6>$IJ+;as5wjW^FTGF)8#=m zu)G8GAwD~nfUN4876?jyMNLUTzao!HNiCHem4do1$|F)pR#MW44rnlt45a*{qT&yZ zgfux6l2k<*c(8i+_{-~S)su9{+m$|qQ8*I{EZlzY8FFGgh2=UZ=FaSg6FLR6t4b)V4weSdArDeh$qH0At;j#P&;y5&wjd(Z+DR1HCxX6N8ufM8+0WUBww4Xqj4F zp)U0dq_s>Y7mqJY;J3$TY>g$p3mWuq!F_srkAGu7;l2e^D&)1ip_+O@uuN5$G79Np zl2>zCp-?oe!s%Bxo)n6vW(h{lO28y0=D{yfFqK)$C>V2ELT}Bi(C%4?=ZdBZL2U@% Q0pI)?@HzTueC22I2NOF1+yDRo literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64-apple-macos.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64-apple-macos.swiftsourceinfo new file mode 100644 index 0000000000000000000000000000000000000000..c71d696f0777a5a703e4b0cdef3097048eee1285 GIT binary patch literal 1144 zcmaJ=KTH#06u(}9;+2p}2!mm`RE&3Ad;i+2t?57yLL3{5aWSda>m5BPZPRP{vtiT0 z7?j3zBq|0cQNR!fLn1k2!cY@P7+BmK92`2E4!*CY6pZ+iU*G%Q@BR7ScdzxAtIuq` z7#7Ab%wbD;9=xj)8&T(Gl=#d$x1!DuJn^PNynje+)t#^Ri7lRZn{$mgzfpT7=CI`1 z!QfnLUfDS={5Mv1yG@)hyhn;=9;}d zVXA#Twmb(GobBE!&K_D^MW&!>*waNrlSau?E-`B|UBh8so1+)|4*EtPhTQ}`&^I#|@UcRx zdAGxb?SSbXqK?qrkw~JdYnl`g{EC_s0)9md3JEQl2nqpR=S80o5|yOj)4>~%5>nD1 z559j6-Az6(Iyzxr0dkLKwH zoEMZQ60W|PWh~X6$%d_;jLZ%JW8N0{&X?pP{z)UPjiY=U_T*TP4__J+8DCO$6;-rh ztK^F{^3q5trKQu^SZrw$hZuCn_FAI1pa6dhn$z9?^C{xFdnRltH>;SOsbrFg>>@X9 z6jH?mS11~0fy?EyGn!g3Pmj8>SSaQ-lQXhr9F{S@0KxG>Udfn7!I;5PvMC)TL>VG@g3cP)wFC`-LpA#tU1+nMl1D6U5C@)&fg*m(qHwltW{P zJKL^t-CCqgas3*5 zgt-P@xE)GxyA)ri!gV;Yd;S=6O_e`V!~GgpSGiq$DtA@(42L0VZes6Kuc?L`kbvUa znC)P3dvH0#?%8dX?WhY4EdCp@6&%_s->F49cq`gf!@nrLKP-8wHc2PqnaX~JDma3W z%R7Z$!fe;45t;`b@GR#xPZ-G`JP3G?DPR!V2PDeng3hF?M$Tc@bjvo(5~Bz)hP4S* z$d*=kIVvfFBt+xFBBNboQ&QPjUw~~?Dd=ROgzSCNqWAR)l6HK zg&W`i@p%2H1Ufj$K6MY6^Ml-H07S#npeq0uU?dZ8fpO49Jv(xOo&;PSY7$3scmPq_ zKYf1_%H*RPmM zBbB^fD46N=Mv`ou^fa28%)tWwm%Bg&XWqRae(|0SuOjMCtgLv))G9^2 Swift.String + @objc deinit +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftdoc new file mode 100644 index 0000000000000000000000000000000000000000..5618c6a78e561277e1a467c455aed399602cd7bd GIT binary patch literal 400 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mBGjnH89XK)H48yX)=TW&2cMA%uOxNFUmGzU|0v_Cl=+Jndl~hOxMj#OwKPh kG|>Y}fkCSv0|UrzBQ^mZFBS#?kRY Swift.String + @objc deinit +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftmodule new file mode 100644 index 0000000000000000000000000000000000000000..bd82756068676a1d4531918513882635dec4ab2e GIT binary patch literal 20380 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 Swift.String + @objc deinit +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftdoc new file mode 100644 index 0000000000000000000000000000000000000000..006c579058f72e867d04f51476f8de755de08ec5 GIT binary patch literal 400 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mBb;Y0c5ukn*fg&3xfbi6xm@)Tp5bUe2_c Swift.String + @objc deinit +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftmodule new file mode 100644 index 0000000000000000000000000000000000000000..846b58c90a976ce0069c5140ce9f2fd0c3a8cebe GIT binary patch literal 17056 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 F{{#M!iO2u| literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftdoc new file mode 100644 index 0000000000000000000000000000000000000000..a3de0be94c12e80046e03bb2f6f80ebbda56e65e GIT binary patch literal 384 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mBX(b9}sYS(^`FRSadL{}Q#UP=a#JqG}Ln8xIJp(->Gd)X%WMmOT zOFdIlV1R@G&2cMA%uOxNFUkg5x(&#$urP}^Gto^18Lyk0n4Dj1XsBlllmLQOK?Vjc bAZ^4Zz~jZjAOI2rxd#T6xH1%x`5^ literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftinterface b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftinterface new file mode 100644 index 00000000..13898be8 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftinterface @@ -0,0 +1,10 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55) +// swift-module-flags: -target x86_64-apple-macos11.3 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name Framework2 +import Foundation +import Swift +public class Framework2File { + public init() + public func hello() -> Swift.String + @objc deinit +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftmodule new file mode 100644 index 0000000000000000000000000000000000000000..1deeaaf48f09a81f66dd7eab993ad8e2e60a3354 GIT binary patch literal 15580 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 literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/module.modulemap b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/module.modulemap new file mode 100644 index 00000000..0e5447de --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/module.modulemap @@ -0,0 +1,4 @@ +framework module Framework2 { + header "Framework2-Swift.h" + requires objc +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 new file mode 100755 index 0000000000000000000000000000000000000000..9f4e3eb8933e94bbca01ccddef955ecd39eeec0e GIT binary patch literal 170976 zcmeI53v?XSdB^XrBx46+i-hnf1aGNu1;tv)7O_lu>}n+;JC@{n1yKrQyxN_WM%vw3 z@66hgWnd^a2M5z*pOVzL36UETFi8`il%9kTKp})zQZO_Lgr?L@$f-kKZcAF*jjev) z%$?oYu~t^|IES?V3wQ4Q?)R8GzqxmH$LGx4=TCh3aUn!7AjD}@)(8<1B5?j;sxPFr zGpHol;VRd zKi&=*&ly!husrAf(QWp}`Kmo)>o# z5Jl;T_D7XiUvJ!*9T6FzO3Cw#GxwWWD9Vst9(C2@HIl8JB96b5>^aMG%}pndhd~o#e9gj8Nf5*swbXW^M zc-1m$3sL5e*@)nocIGRz*#=J3TuODj|E#A(F{}Znl;dm<4ZX_(;rO^=s@d=wZLp9i zjF%Z0;V!+HqnoSgIWMD9qaD`%a86rA+&4%Hh;Y#;gfrS8XP#M2(WcZm)g3SAgF9Zo zz}0Ouy(|5kt~IrLJ^4dD5z2Hu_H_go@UMc$&;GgRv)YxIUQoU6HU}PGuD?i)oyy*g$JAueObljJrE+!{qQWktCsJzRBpbf+C6sx*?R?THFOf3O4^Ho;%=!Z_ z)3{y5El3~$0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd& z00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY0&^vBUHA4MMz34DX8X?{=ht+;%l4NrLUyY(LcfOy?06ySH~9x#?@^bkm~6TUoaC z-M9aw-ZfaWJ$t14?yFRa`1skR|1!UFMt6&v<%#cPU`n zPL=(+`>L2)-Cf75Y_ob*`O0zz8Dt^^q*P?}`j? z+w{eI$aVVSkJ-oj?Bk?;{A)VWJ8O-9aLL+reb=sw_FPeZ`7jisw$+`neox!dmhyXm zhp#EyigL9}%cvZb5?>1^e(#Up<#OMxtTb*KRx=sBkzdM^N$EFZEzM=Cmez9J6W+Go zLYV11)?q3qC_j8+diqKk$31UQ%G`I(Ec1mwczk-A2h?FI1CNq3)sHv@>AA;3+)pyw z(z|AM@|GNj-;s|{$=Q9so$KD@^dl(Fvd>KKV$$hrM1aHE{2kkR%Mt1=j!SQ(Sq`sy ztJap+TXr#r!vT+F>C_WlcrD_jCg!m zi!xZ$GNzV`n*}X5v_>=4LL$?$qG+buVtPuwE~l9>y_hpsXht+1TeT`4Z_g|3o7%M& z#Z0DSZsd%vk6xFLWfF$bqng8d%2lLP`=qvJRn9OIxuhzTzV_8IrKht$8e0>M$CU;} z={I9W%Q7X-{d9ZiT!fm{0$;hBPKTo`o+a$yP3>lVrf!bUL&k6qE_s@El9>wx6t9$o9QsQ zMTokDXwQmkbD~EV>x$w7wc>zdHNgfG6rw{IDKRGME+1Bjd^|qh)i2&1jg2SM;))(| zW3R}j#mzNhKS#7~CWqc)c2F&d`vcDH5c}xXHW)3^uaqNFenraNQa+77RIzZO zkl&>cVx^S3Eo!5bV0n=cU$SgbOpv_HsoF=r?v#7+ROcy`^5_rwCyT1)A_xkkgzgGG`DE(d8 z^$$@yC)eMrXMgwp&!-&p$zR_IG91KV+Z1e15N<{imdVLi)S1 z>mTv?d-d!u)BsUx01hC&;DzrKmCl`{;pij-_@T*1|jls6VKm}D^SVv*DD{RHm`iAPhR4a zdA@t?dA=|4&3CUpT3cz)^WCf8>yvrDd-Xium-yy8%kF$XC@SrF{x9*&|L#Dgp2Ujz z$$S@4qsx!4cTt@PZjrxVJpWi9lH-x@C(G{rVqR=-O8W<;-knc8{@7l~`+1OM>Ywx7 z93hxL`OEL%2*LMn5ixyL+Vfbj&o5=Z9`X+!u*i`T&kxqS%>OrZ3t-i(7l~9n%YH7p#&- zL}8OQtAS?Z6J~OFmKbw7k+aO!Hqv5p4v!1Y6U5BRc}F+HGr-K#qCENN5+sL$n$FN; z387Io%GIoIQuPe<&_l&|c2Lh~$q+dzN@%93U2Wv`bj=AE-LLZaoW-L|Z>}EBjh(A? z<#?H^SBD%Me*5yXR!6iyYCmpy*|oHmubCe&=(^`H05+Hmr}>V<<2(o<7+D1p$-;@mTLK7J*OI4wwOtndckA1RO^dNQ|G=J zOLKZ5o5+O6+TN$UuhnDPWDn-7o+=WCx9df8s0Et0skmM&Bvm6U%0TSd)07n9JXsL5 zx9b(0>NYsnp^NZ!1`nXTn%9zrv>7%E$?%Y74i^WTl6p357B$0^$Fw$P77K(!(+wq& z&nuhAPB9CKoS~V7OG&#=(Vp8Ko`E6H0B0Ed&SSJMrRraH&kr#zpgif=>t{^SKSw-8 zO| zZ(iJPeD`NJEx+hbfBe}$yYc5Q{Ka{x6K8(m=9U*v)O9`mslR=C{T<)^_PHJ5PyEfT zpZ&ss{`8O1Q?;+W^wMasZ=h~^%fnkXZ+q>rySleu_Q0w1?^(I|mOY6_4)6HK$i3~G zZrprk?=PorU;X@zr=9rhCr)e){OGJd8TsgoxBsE>@9~CDKd^Y-c>Lblv5`pq##^u4 zaoZ)@!SJc#|GN6C;s?Js@pte1R^N%`!E-+N__tp@EB->uiWT2@@4F{f|JUKSe*Wvm zKb8MK|Nbv(zu2)kzfO7V@6WyapFZ}~%F~v-?^FNq=%x28*nP&!Tfebu!LmKY|NP~* zKXlKl_k87yO&dFELlcomfic{#+Lmm{RmWxw^N4WUnAdjx*EGw6xuF1QEu|b+e!YM zCheoM|N3n4c)WE}R+KfXdf(sKvC0{3w9&c@V98R-2XAm>p0nP0`%aQ0l+P`-I~I`w z?aVyv*dXJV@|>1W-QBpa|Jon_;IU=Y7NTr#=pHX5Kuh9kziNbgpj1ewxQSD_^ z-XPnK%YRqeD&oFDQb2@@Mj@Qh208Q0YKk_c#;I;Q(ZTN*xVnv|ccq`xwWfBjC;LSx zGZVfC!3F%Q;PJCJ2j;Wd72c!S>uz)4@#Xr9)Yz%~JsirHK>k+58;9z%^uyU%+S3!i ze^6XBtH0bex)j0h@BETf<=|}Q%R7n72p3TQ8|jQTPjyU97R|(9MpY_jhaoELGJ1kG zi$2MQuY3t*9&bCJbjnMl%=3fOdnvPi>SZB9tGERT1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1pe<4c&qR6ea9yP`;N!Nu7fpaJv2XPt^1dn`41fu*1GRgdA$(#yj3F}qW3QEIX)5H z_g3GN4^Gu6-+61Z3?Ne9oqIU_YkCnPRFO3`(for~VQhP9RbpFyx9lfu#znhNZ zEz{G}bRO$4l@pY=o|v9?-!FI1ON{Nredo+FzhSxl`1CZf5)V@uc$A!}e#9wA&pj66 zev;Xi-Yv8J8n}@Xmv)?xUDWcs@%*kHXZJmKu6vWypE`OMk|T;>8y#+>uI#4rD^yY| zO$9gATeg*`x19dhTMoZ^%Q0GSxt6CY4|psir`azdp2`J!5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009vAe^1~xB0%4cDD4Mc0zx0M;7?r4HCbfH-#6e~ zk?c6@E1G5#c-LZzV!5TW|9r@@oB3eZLR_=c)~mRvclLWGKWAUe7W0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5CDPS0)Y_49Hz`~`!ApzpzNkvS+U=ZcN?i>Sw!gV`UqE? z#D1lAOEyvwpw?heh}sb4F3R7cJTD+>uMUXdhpF68c}kvD(FaG8ik>$WL(QaxVrZxuG?hsTLBMmK8-a-4@eR>UBBIjOoRk zxk59d@z|Ez`rP?R8HLG%lnaCwo zq4c${jwwBz{n6N(XgsboC`!K>Gg_7@aqg$vL+2vYY~CDKl8NLnIW`#W`UkF;0cLZS z+yaVtl9AMi-COAJlUsxcj)(;t#KIb3amyP{%lR8bs75?H9_SYrlV&rS#l+I2xV%P8 zO^8~t^R^%v@4tl(&)!UjHztIrONjQYxHczxbg`}|K2R$T*j8I7$lxG{=nzJVzKKwG z`LIglD&^7tt4}^ka@sRP8C=L?{}G?ep}p~^h=n))rSmK0Ye@FSXa6QTIN!k#Vl~MP z9+~wGl-nqCV!79+XMZ8TpYb47+2579%Kn@=vCRHnJ^Q=&zm9&O*x!}elzr{bbWq7M z`+N25zh0hyf^{C5sxzM7wP!v1Z)@%XFdDB zA^o||{;te=_Pu~ICzgACdiD`=zVPon`@1q%*-?Rma0@y&OyK3ZF8&-2}@-|LfkzI*jN z-V8{rJlr!`N@12QKQR`uXjYlJ*a}de8V{dv|;tWIgrI`EHI7%%A+_cW{K@`?rXgJ}d7(j|KL3#~)u0`3DbJ z=F=TK4^h)~xpObGFsvuf9N)EA6hnb+Jxm zO<%Nw7Pt1|JEj-ZE?P;a5+*Ozl&XduiNYprRs+q*C(PvVEHUPEB4?ScZKTEI93B^( zCy1Gs^NwzYXMmZfMS1ekB}fhhHJzcy5<;VFl&e|ar0N;yp@)j`?4X{}k|A>6#NTx?kn-Ig3Y`-dsJL8#`C)%JDK+uMRmj{PyK%t&V7a)PCIZvTJEAUo$^m z&~?wzZst4OlNRBPi9$H7XHs-G!)Ya)Y|9K~FK=GCta(Gr(3moq9c?z24;gLEl!kKQ z{;-+NH}$pVyN0^jve&N(x6^ZJD!eL352RT&r6o+&Xv*nYE~Soz%bjiF$JbQ2Lmey* zE!FbFdQLU8Y%!BC^@7K2sn!>lrp|pcmge+AHjxP@3fcFydMumlv7FUYMWXO_y@n38 zK+`rA*NcUuYJ^3Zhdp_kk|LZZ3u5+my@FHR1?Mt!5x&mg;geVMTC$Kf!$u()9@5O= z;$Tx!&xXySW|;Dr*2c_YfoN#Dp(OHoWfR#cW+9O?G?Qp4Y4;i0bGO4YAms7yjDp{F ziuRRM{j=`*6&A-{KVypi`Qa&AM$t;kP7QRVRa|gCFBGZ#3fZu{Lj>(*8r8)&DGyL) zA6mV?JQWIxGpIg?6e-zgdXs%0o64hDT+#R1iPL}jgFP>_ZM*g351!Y#cft0p10Pwi z`28DeA9-lS=;Gbup`E>-Q5P1+cGRt&+`q1O#CqbH-}~g!BQLM`^f|Gkcf9uI=by6D z$0tt=k8WNv73_TOzI~f-INJH}n-{km-~HK5%YQPk%lP>x4t%dMH@I!(&hLMC$HS9- zx79wk^Onn29$4_h(8vGg*3W)nK!5s2>8aXRUV3RX*f&r&z2)I8o4398*j?S*FMHrr z`upy$eKfo7n-@KC?*)^+yY5|)zbdf$o&ULeNpSwIzj%J?ypgm1WaOhS-u{QizsDOs z{lMaRb~p0esJ-3_bEHSwS4{a zzxbp5%l7Af{LTBm_~*ZF{8RZa-!gp1wtu+r*!bX!-}&h4>;GxxGv_`Z{+Rf;AHI3l z6O&gAf4KhI`H%dh^^UWjOa0{ot>5cA`}(>|6Cc0fuK)Pk^RB$@(nntT42?w|mG)RW z_WJ2uFFjk71{NwH00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY z0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4ea RAOHd&00JNY0>ASF{s+HZcbWhI literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Headers/Framework2-Swift.h b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Headers/Framework2-Swift.h new file mode 100644 index 00000000..d4d6c9db --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Headers/Framework2-Swift.h @@ -0,0 +1,618 @@ +#if 0 +#elif defined(__arm64__) && __arm64__ +// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +#ifndef FRAMEWORK2_SWIFT_H +#define FRAMEWORK2_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="Framework2",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#elif defined(__x86_64__) && __x86_64__ +// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +#ifndef FRAMEWORK2_SWIFT_H +#define FRAMEWORK2_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="Framework2",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#else +#error unsupported Swift architecture +#endif diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Info.plist new file mode 100644 index 0000000000000000000000000000000000000000..440a48af5e596156653fe4560822e450f2094153 GIT binary patch literal 837 zcmY*WOHb5L6h8O*!WVOSDWK>8iVu>e9WxRa#z^Z#g2Sr?ln`oZFEcmX_SQboN%Rl6 z^9Q)lolAGF+-hQoF5J2BH?Uyi!g!~&8EliD^L^+0?z!i5Gvq8zRP{F*K={bfW5-W) zoji5=%-QY|>FMq3A2@e@aA9y%J@HjQ-4&@^BX^UyzCL@J%CfE`Na}()z zqSgwHVwtTM)j7wPC-fC?!Ev{p2DMtDWQPmZY>Ft!on{iTpmDgEhM_D|Z-G0>mWce= zCZ)oeo7N0V7kDx}%O8y$Rbo1PBQ@tekMrhZ~rGHnZ24ePNhJi4C8e0`+O z0_LawyqTMAGB{^GOnoO8xfE4TD1ZHWeJwMaI2 zE~4#a3|L>bpyFD7MfP0X1c3xdss}YBm{jg|9ea$f+W; zZ2DN?e8*Q@?gR}*v(@E_rdMT;5)0e*xUgH=l#;dnpKi03R;{S3T2-&A>ZTwQpo4%A zS`Yz)1~egoGFXsG6wCYrC=%ZXF5mJYO`IVrHB_=Y^6P=}{>Dv$2!<}G!mK>(CA@); z@ELx>9_mJAG>Pt_N9ZZqMk#uQUZc0@6Z(R7(GTdvQO$gYV%*yn;D? XhFkb6{)TrUdoVhPFqy|Z;P3wc8> z6h;WS9BJ=^_jPh3=H85vUj+A7%>79q-Dauytui}1`-m@9-8tPd8ST9GJ zWk^7DKw{P?1C=Er!-VO$eG>YC*kzI{4H3Ir|xVq6#Sg-dW#K79$IW@Di zO9_3R2{G0);QaQw-?i-oLmL7KdL*CEs8oDG*DPvYHB3D>M+LYLCsDMC$&5TV?Q0U8 z#07$s(j>%yAaEilV2(jkkZ016v+6?5n3WLv1$)`Z2K_!6XZPtjQ@p`RK2y&YGP0F3 zPR`Kj>O)n~J%jWC?g1kpDVnMVf}&qmQex0AOJibEO(n;~pr#4Zs2GyulsKvZ8w?}^ zDgT%t`-7t)RSJbfMV1Het=&HQ{PIfWI34nIr4L{vPCebv&P5&9ZBh3@=>oajB2HGE`wj@U{i|*n zc-&7X$XVbxiR|l{SwiVnPY$&HV|aEDEapv7Xuqfs@lWa*bsWb#(6d7=F?69%WPDN4 z6r9n4R;aaA>O#*zTFqo~@%Z8-etUez)_CH(ph5ly?$gtI^c(x}cTJd9KCk9=#n3F? zG!%YXx6*|qr{uD{RnSfAjh{4 literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo new file mode 100644 index 0000000000000000000000000000000000000000..56650b2fc2b9781ead87aacbf2a33591fdd82c26 GIT binary patch literal 828 zcmZ`%&ui0g6#ph&*O`t{%kZ>Ah!v8h`O(r0CSICJ&&AG*2sMUejcc2dq^t8ZyB>xV z*TZ&`$;Jf1X{YSqq2S0aJ5=bwgGY}Z`v>gc`*y9J!oKkNzVG|Im-jRMx7)9YDTEY+ zP>3kRAAjsqhuQE^mii`#+u86JnR?fvK0Tq@{qVsl)t0Fbl}If7o$b{5UOnC+`HMPx z?DI{3{$4E2?~p=++yZ&afr*gkY;bNHbOl{#xq;r-13R(O( zLPTf^?Lu#NrV(O5MuW@d#wjgFn8Rr3gaihm13z(X5N9 zqE=oJ5=mJRWih!RF4Fo{Cb1|g3Wv}##K|~X$*9@RY7(J6&^4#DkPlr+8T+^s$+y@Kz|2zPKnR&m9?b1URHX<1>98J1!>(!D`_FQSj@(R_bl2^4{ zPpUZfGeZaVQZ=pTUez&N2}YiW;pc1MocA29>{_0+X5`J$nxt{-QqHbAI(#&y@F>K= OAAsv)qQCJd|DHd~oY-#w literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64.swiftsourceinfo new file mode 100644 index 0000000000000000000000000000000000000000..56650b2fc2b9781ead87aacbf2a33591fdd82c26 GIT binary patch literal 828 zcmZ`%&ui0g6#ph&*O`t{%kZ>Ah!v8h`O(r0CSICJ&&AG*2sMUejcc2dq^t8ZyB>xV z*TZ&`$;Jf1X{YSqq2S0aJ5=bwgGY}Z`v>gc`*y9J!oKkNzVG|Im-jRMx7)9YDTEY+ zP>3kRAAjsqhuQE^mii`#+u86JnR?fvK0Tq@{qVsl)t0Fbl}If7o$b{5UOnC+`HMPx z?DI{3{$4E2?~p=++yZ&afr*gkY;bNHbOl{#xq;r-13R(O( zLPTf^?Lu#NrV(O5MuW@d#wjgFn8Rr3gaihm13z(X5N9 zqE=oJ5=mJRWih!RF4Fo{Cb1|g3Wv}##K|~X$*9@RY7(J6&^4#DkPlr+8T+^s$+y@Kz|2zPKnR&m9?b1URHX<1>98J1!>(!D`_FQSj@(R_bl2^4{ zPpUZfGeZaVQZ=pTUez&N2}YiW;pc1MocA29>{_0+X5`J$nxt{-QqHbAI(#&y@F>K= OAAsv)qQCJd|DHd~oY-#w literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo new file mode 100644 index 0000000000000000000000000000000000000000..0f4eaa674e70ac5ca93c5f70b462ebc939fe0f4b GIT binary patch literal 1148 zcmaJ=PfXKL7=P>dXGh2+1QWxdK}=e@^&e|xW(QXY7cYxLy_n3dw5%}L(sum07+iKR zhR9;(ji4AjiGl`iB$65v512s0!INi>oIGLT_cq4Bh`;3P``+*S_rCYO9=%+8=4(SJ zh7fA?WkL_$9g%B^zv{dqbnU9(zy>E#gRKjetmgQ|;d+!m(SA>5>;(^XOxOsd!MBuhtI5 z==%P^3w`ro?+;f9ZqMV(Dh)+rp(X~392Y~SBD<_Iy9D&>Yi&b6VZGjt5Cdyx^XSCF z4kZM8hs8vDm;dXl&eknI7#a{r(Bt`h)}WHJmg!P6hV59nX-ejzoJ7$MCbQb~c(_V% z5+^H^UL{0X5IB(&Fvp-#$TMPVQ^su0o|F*!1^c-{C8b2d8crX!a*lX|lfsTQRmf^? z&aNGzxiyG3LGA6P_i+yxvZR}aAuD1;)5k<5qDg~d+89d@ii&9p(tsG1v@vnO1XhvL z@>pb0&?3q})R3Z4QP;HYdn>mOKfSn8sii}`Et!27iBnLZ;cMtPWopVJSgwL#+gX2X z#kS`lmq2_VXMt^X;JIr8fhRZz?DId{FxYWi*SV-#-8yw2lopW7b>d{jx$l5r+rR3T zfyezcgPaA9lgMEE!~)9Hd-9>xAAOVEU~z7WLgPh+cx1%N8bdhVhn^mosh$gc;zRSg zspE`3v_!2eQx|&586%s`C6n_b`0eo->*I;!{6ACzw5xX@_8d~>9*^Nqm#y0eu_Vn&;@k> literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64.swiftsourceinfo new file mode 100644 index 0000000000000000000000000000000000000000..281445fec92e279c91832b22179a72f82c13e738 GIT binary patch literal 840 zcmZ`%F>KR76g?+RQ=F;_QN`533PEz}*yluXL=j6|lsO`0K}aE3c4O+sk?k}sQ%N&a zD54pP#DGApiiAWV1$AJEMCC3Wf|P-Qk&!VIQwIK}2`NbZ(z}26{`0^4|GW2Q=Q%Zn zkc1HOQ^nYW4?X%I8#v6;U&TNx8~7~JZ=3YThjgnK*gv6LBK^J`j0C>1?Hbpu#o8XO zUt^D4uHnw#j-#(}s>&GtFl=&k$+OKhSncHJFk&!#5b_^;fI(;=EmC03g&0*G5%ht^jBMC`{ zwFzYuO3QpaAxeTMBvQfxqg-U-3xXs?5n6&g8LP0WR!wUqfzWR_uis4NQ%Sx+((}4$ z$CHA@+xlw7C^)7C0x+LHh)UqYlk8LPfH_~teg;51j0jx;P=Jw5zy``f7yaxg2!0Z9 zb?AwX|1ehT!ENQW^_YcgaF+8?7NnqyHt~2+)y-y zWTemz^ZFHYsZuJchGFJ%8yV7l@}^PEqz)GFzug5QJoD}aiQ{`VOb4q^tOCAcDwS2W zMKWh5AQ?XPVL-+GAhkO;pdB-Z0Y~9h<)Vwwt86KC8 ab7sX-;G;1`S|JSn2J*ge=oe|_U;6{75ZvDY literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.abi.json b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.abi.json new file mode 100644 index 00000000..5bbfed86 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.abi.json @@ -0,0 +1,76 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "Foundation", + "printedName": "Foundation", + "declKind": "Import", + "moduleName": "Framework2" + }, + { + "kind": "TypeDecl", + "name": "Framework2File", + "printedName": "Framework2File", + "children": [ + { + "kind": "Constructor", + "name": "init", + "printedName": "init()", + "children": [ + { + "kind": "TypeNominal", + "name": "Framework2File", + "printedName": "Framework2.Framework2File", + "usr": "s:10Framework20A4FileC" + } + ], + "declKind": "Constructor", + "usr": "s:10Framework20A4FileCACycfc", + "mangledName": "$s10Framework20A4FileCACycfc", + "moduleName": "Framework2", + "declAttributes": [ + "AccessControl" + ], + "init_kind": "Designated" + }, + { + "kind": "Function", + "name": "hello", + "printedName": "hello()", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + } + ], + "declKind": "Func", + "usr": "s:10Framework20A4FileC5helloSSyF", + "mangledName": "$s10Framework20A4FileC5helloSSyF", + "moduleName": "Framework2", + "isOpen": true, + "declAttributes": [ + "AccessControl" + ], + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "s:10Framework20A4FileC", + "mangledName": "$s10Framework20A4FileC", + "moduleName": "Framework2", + "isOpen": true, + "declAttributes": [ + "AccessControl" + ] + } + ], + "json_format_version": 8 + }, + "ConstValues": [] +} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface new file mode 100644 index 00000000..df83246e --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface @@ -0,0 +1,14 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-ios17.2-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name Framework2 +// swift-module-flags-ignorable: -enable-bare-slash-regex +import Foundation +import Swift +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +public class Framework2File { + public init() + public func hello() -> Swift.String + @objc deinit +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftdoc new file mode 100644 index 0000000000000000000000000000000000000000..1ed091506ac68c02e6ceacb3165882e68f3f8698 GIT binary patch literal 408 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mB_?V5L}*_R-#arT2!2wpQm7|XQ^kTpivAG%t_2k*98mc8R?mt zDI|jh3{4FT^bGY3Kw_E#F->_8>13`Jx Swift.String + @objc deinit +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftmodule new file mode 100644 index 0000000000000000000000000000000000000000..4b07dfa8e084e8bea3cecb4c1f097f3773c79078 GIT binary patch literal 20676 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 Y0Yw`6r)i>3|7B?|`;s(aPVx2s0KtU_!~g&Q literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftdoc new file mode 100644 index 0000000000000000000000000000000000000000..4a89e35cfb4572e553fbf382c9fe931f5a465e8a GIT binary patch literal 380 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mBX(b9}sYS(^`FRSadL{}Q#UP=a#JqG}Ln8xIJp(->Gd)X%WMmOT zOFdIlV1R@G&2cMA%uOxNFUmGzV3-HwCl=+Jndl~hOxMlKFE%vMGX;t=FtiFXFmM5B aBQ^mZFBS#?kQm4 Swift.String + @objc deinit +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftmodule new file mode 100644 index 0000000000000000000000000000000000000000..ec7884d89a4132a6bf07396b1de702eca9c7bb3e GIT binary patch literal 15664 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 literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftdoc new file mode 100644 index 0000000000000000000000000000000000000000..4a89e35cfb4572e553fbf382c9fe931f5a465e8a GIT binary patch literal 380 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mBX(b9}sYS(^`FRSadL{}Q#UP=a#JqG}Ln8xIJp(->Gd)X%WMmOT zOFdIlV1R@G&2cMA%uOxNFUmGzV3-HwCl=+Jndl~hOxMlKFE%vMGX;t=FtiFXFmM5B aBQ^mZFBS#?kQm4 Swift.String + @objc deinit +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftmodule new file mode 100644 index 0000000000000000000000000000000000000000..ec7884d89a4132a6bf07396b1de702eca9c7bb3e GIT binary patch literal 15664 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 literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.abi.json b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.abi.json new file mode 100644 index 00000000..5bbfed86 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.abi.json @@ -0,0 +1,76 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "Foundation", + "printedName": "Foundation", + "declKind": "Import", + "moduleName": "Framework2" + }, + { + "kind": "TypeDecl", + "name": "Framework2File", + "printedName": "Framework2File", + "children": [ + { + "kind": "Constructor", + "name": "init", + "printedName": "init()", + "children": [ + { + "kind": "TypeNominal", + "name": "Framework2File", + "printedName": "Framework2.Framework2File", + "usr": "s:10Framework20A4FileC" + } + ], + "declKind": "Constructor", + "usr": "s:10Framework20A4FileCACycfc", + "mangledName": "$s10Framework20A4FileCACycfc", + "moduleName": "Framework2", + "declAttributes": [ + "AccessControl" + ], + "init_kind": "Designated" + }, + { + "kind": "Function", + "name": "hello", + "printedName": "hello()", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + } + ], + "declKind": "Func", + "usr": "s:10Framework20A4FileC5helloSSyF", + "mangledName": "$s10Framework20A4FileC5helloSSyF", + "moduleName": "Framework2", + "isOpen": true, + "declAttributes": [ + "AccessControl" + ], + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "s:10Framework20A4FileC", + "mangledName": "$s10Framework20A4FileC", + "moduleName": "Framework2", + "isOpen": true, + "declAttributes": [ + "AccessControl" + ] + } + ], + "json_format_version": 8 + }, + "ConstValues": [] +} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface new file mode 100644 index 00000000..7c4d9572 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface @@ -0,0 +1,14 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target x86_64-apple-ios17.2-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name Framework2 +// swift-module-flags-ignorable: -enable-bare-slash-regex +import Foundation +import Swift +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +public class Framework2File { + public init() + public func hello() -> Swift.String + @objc deinit +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftdoc new file mode 100644 index 0000000000000000000000000000000000000000..8a6e1edfa88dde5bcd04b38c022383c9af2934a6 GIT binary patch literal 408 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mB_?V5L}*_R-#arT2!2wpQm7|XQ^kTpivAG%t_2k*98mc8R?mt zDI|jh3{4FT^bGY3Kw_Epcl literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftinterface b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftinterface new file mode 100644 index 00000000..7c4d9572 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftinterface @@ -0,0 +1,14 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target x86_64-apple-ios17.2-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name Framework2 +// swift-module-flags-ignorable: -enable-bare-slash-regex +import Foundation +import Swift +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +public class Framework2File { + public init() + public func hello() -> Swift.String + @objc deinit +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftmodule new file mode 100644 index 0000000000000000000000000000000000000000..642d1d19cc01fc05a61bfb2d7424a6f00a7ac295 GIT binary patch literal 20676 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 XDALeBP7{6lFH3XTm!t`Eim(3%Cfo@F literal 0 HcmV?d00001 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftdoc new file mode 100644 index 0000000000000000000000000000000000000000..dcf344bd4942babbb549fc122ed41ebd44e567c5 GIT binary patch literal 392 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mB63R);OV>3tGBDLM&@(dAvs6e%7BRHc zGc^SUNC?mzx1z+{)bjkIY$FDSZ$N&9g;~6riEbjuc-_qWVnY)>Q{Cds+|r!HlKdi| j0w8D=WMJR|(nf3oJYFme0w6JvyI??xD?<^P4-y9eY Swift.String + @objc deinit +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftmodule new file mode 100644 index 0000000000000000000000000000000000000000..f3bfa36d0f3cbd3eaf380b9d928f9d59166708b9 GIT binary patch literal 15784 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 Framework1 +- Framework1 -> Framework2 (prebuilt) + +Note: to re-create `Framework2.framework` run `ios_app_with_transitive_framework/Framework2/build.sh` \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Project.swift new file mode 100644 index 00000000..61788c6b --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Project.swift @@ -0,0 +1,29 @@ +import ProjectDescription + +let project = Project( + name: "StaticFramework1", + targets: [ + .target( + name: "StaticFramework1", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.StaticFramework1", + infoPlist: .default, + sources: "Sources/**", + dependencies: [ + .framework(path: "../Framework2/prebuilt/iOS/Framework2.framework") + ] + ), + .target( + name: "StaticFramework1Tests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.StaticFramework1Tests", + infoPlist: .default, + sources: "Tests/**", + dependencies: [ + .target(name: "StaticFramework1") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift new file mode 100644 index 00000000..db42cbcb --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift @@ -0,0 +1,16 @@ +import Foundation +import Framework2 + +public class Framework1File { + private let framework2File = Framework2File() + + public init() {} + + public func hello() -> String { + "Framework1File.hello()" + } + + public func helloFromFramework2() -> String { + "Framework1File -> \(framework2File.hello())" + } +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift new file mode 100644 index 00000000..864f65b9 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift @@ -0,0 +1,19 @@ +import XCTest + +@testable import StaticFramework1 + +class Framework1Tests: XCTestCase { + func testHello() { + let sut = Framework1File() + + XCTAssertEqual("Framework1File.hello()", sut.hello()) + } + + #if canImport(Framework2) + func testHelloFromFramework2() { + let sut = Framework1File() + + XCTAssertEqual("Framework1File -> Framework2File.hello()", sut.helloFromFramework2()) + } + #endif +} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Tuist/Config.swift new file mode 100644 index 00000000..ff8e64fa --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Tuist/Config.swift @@ -0,0 +1,3 @@ +import ProjectDescription + +let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Workspace.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Workspace.swift new file mode 100644 index 00000000..789a84b4 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Workspace.swift @@ -0,0 +1,6 @@ +import ProjectDescription + +let workspace = Workspace( + name: "Workspace", + projects: ["App", "Framework1", "StaticFramework1"] +) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist new file mode 100644 index 00000000..a11b3ce7 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright ©. All rights reserved. + NSPrincipalClass + + + diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Project.swift new file mode 100644 index 00000000..ba681482 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Project.swift @@ -0,0 +1,30 @@ +import ProjectDescription + +let project = Project( + name: "Core", + targets: [ + .target( + name: "Core", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.Core", + infoPlist: "Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ] + ), + .target( + name: "CoreTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.CoreTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "Core") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift new file mode 100644 index 00000000..ba66705e --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift @@ -0,0 +1,5 @@ +import Foundation + +public class CoreClass { + public init() {} +} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist new file mode 100644 index 00000000..f1d34193 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright ©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift new file mode 100644 index 00000000..0f871eaa --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift @@ -0,0 +1,6 @@ +import Foundation +import XCTest + +@testable import Core + +final class CoreClassTests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist new file mode 100644 index 00000000..a11b3ce7 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright ©. All rights reserved. + NSPrincipalClass + + + diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Project.swift new file mode 100644 index 00000000..7c856ddb --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Project.swift @@ -0,0 +1,35 @@ +import ProjectDescription + +let project = Project( + name: "Data", + targets: [ + .target( + name: "Data", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.Data", + infoPlist: "Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ], + dependencies: [ + /* Target dependencies can be defined here */ + // .framework(path: "Frameworks/MyFramework.framework") + .project(target: "Core", path: "../CoreFramework") + ] + ), + .target( + name: "DataTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.DataFrameworkTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "Data") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift new file mode 100644 index 00000000..a0969ef0 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift @@ -0,0 +1,8 @@ +import Core +import Foundation + +public class DataClass { + let core = CoreClass() + + public init() {} +} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist new file mode 100644 index 00000000..f1d34193 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright ©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift new file mode 100644 index 00000000..ece49c68 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift @@ -0,0 +1,6 @@ +import Foundation +import XCTest + +@testable import Data + +final class DataClassTests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist new file mode 100644 index 00000000..a11b3ce7 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright ©. All rights reserved. + NSPrincipalClass + + + diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Project.swift new file mode 100644 index 00000000..5de9222c --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Project.swift @@ -0,0 +1,38 @@ +import ProjectDescription + +let project = Project( + name: "FrameworkA", + targets: [ + .target( + name: "FrameworkA", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.FrameworkA", + infoPlist: "Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ], + dependencies: [ + /* Target dependencies can be defined here */ + // .framework(path: "Frameworks/MyFramework.framework") + .project(target: "FeatureContracts", path: "../FeatureContracts"), + .project(target: "Core", path: "../CoreFramework"), + .project(target: "Data", path: "../DataFramework"), + .project(target: "UIComponents", path: "../UIComponentsFramework"), + ] + ), + .target( + name: "FrameworkATests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.FrameworkATests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "FrameworkA") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift new file mode 100644 index 00000000..a7a5e54c --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift @@ -0,0 +1,10 @@ +import FeatureContracts +import Foundation + +class FrameworkA { + func run(featureB: FeatureBContract) { + featureB.run() + let a = featureB.expose() + print(a) + } +} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist new file mode 100644 index 00000000..f1d34193 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright ©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift new file mode 100644 index 00000000..ea9d8b47 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift @@ -0,0 +1,6 @@ +import Foundation +import XCTest + +@testable import FrameworkA + +final class FrameworkATests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist new file mode 100644 index 00000000..a11b3ce7 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright ©. All rights reserved. + NSPrincipalClass + + + diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Project.swift new file mode 100644 index 00000000..bec52d44 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Project.swift @@ -0,0 +1,36 @@ +import ProjectDescription + +let project = Project( + name: "FeatureContracts", + targets: [ + .target( + name: "FeatureContracts", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.FeatureContracts", + infoPlist: "Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ], + dependencies: [ + /* Target dependencies can be defined here */ + // .framework(path: "Frameworks/MyFramework.framework") + .project(target: "Data", path: "../DataFramework"), + .project(target: "Core", path: "../CoreFramework"), + ] + ), + .target( + name: "FeatureContractsTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.FeatureContractsTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "FeatureContracts") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift new file mode 100644 index 00000000..9fd1f935 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift @@ -0,0 +1,5 @@ +import Foundation + +public protocol FeatureAContract { + func run() +} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift new file mode 100644 index 00000000..f628db70 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift @@ -0,0 +1,7 @@ +import Core +import Foundation + +public protocol FeatureBContract { + func run() + func expose() -> CoreClass +} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist new file mode 100644 index 00000000..f1d34193 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright ©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift new file mode 100644 index 00000000..2f8b4bef --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift @@ -0,0 +1,6 @@ +import Foundation +import XCTest + +@testable import FrameworkA + +final class FrameworkAContractTests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist new file mode 100644 index 00000000..a11b3ce7 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright ©. All rights reserved. + NSPrincipalClass + + + diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Project.swift new file mode 100644 index 00000000..bbb6e80c --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Project.swift @@ -0,0 +1,35 @@ +import ProjectDescription + +let project = Project( + name: "UIComponents", + targets: [ + .target( + name: "UIComponents", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.UIComponents", + infoPlist: "Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ], + dependencies: [ + /* Target dependencies can be defined here */ + // .framework(path: "Frameworks/MyFramework.framework") + .project(target: "FeatureContracts", path: "../FeatureContracts") + ] + ), + .target( + name: "UIComponentsTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.UIComponentsTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "UIComponents") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift new file mode 100644 index 00000000..1e75a106 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift @@ -0,0 +1,7 @@ +import Data +import Foundation +import UIKit + +class UIComponentA: UIView { + let data = DataClass() +} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist new file mode 100644 index 00000000..f1d34193 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright ©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift new file mode 100644 index 00000000..0f09132d --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift @@ -0,0 +1,6 @@ +import Foundation +import XCTest + +@testable import UIComponents + +final class UIComponentATests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist new file mode 100644 index 00000000..c407fafb --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSHumanReadableCopyright + Copyright ©. All rights reserved. + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Project.swift new file mode 100644 index 00000000..5f6763a1 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Project.swift @@ -0,0 +1,35 @@ +import ProjectDescription + +let project = Project( + name: "StaticApp", + targets: [ + .target( + name: "StaticApp", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.StaticApp", + infoPlist: "Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ], + dependencies: [ + /* Target dependencies can be defined here */ + // .framework(path: "Frameworks/MyFramework.framework") + .project(target: "FrameworkA", path: "../Frameworks/FeatureAFramework") + ] + ), + .target( + name: "StaticAppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.StaticAppTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "StaticApp") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift new file mode 100644 index 00000000..9796fd0b --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift @@ -0,0 +1,18 @@ +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func application( + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() + return true + } +} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist new file mode 100644 index 00000000..f1d34193 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright ©. All rights reserved. + + diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift new file mode 100644 index 00000000..c3e283c6 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift @@ -0,0 +1,6 @@ +import Foundation +import XCTest + +@testable import StaticApp + +final class StaticAppTests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Tuist/Config.swift new file mode 100644 index 00000000..ff8e64fa --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Tuist/Config.swift @@ -0,0 +1,3 @@ +import ProjectDescription + +let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.swift new file mode 100644 index 00000000..160c99f4 --- /dev/null +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.swift @@ -0,0 +1,9 @@ +import ProjectDescription + +let workspace = Workspace( + name: "Workspace", + projects: [ + "StaticApp", + "Frameworks/**", + ] +) diff --git a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Info.plist b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Info.plist new file mode 100644 index 00000000..82ed201d --- /dev/null +++ b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Info.plist @@ -0,0 +1,28 @@ + + + + + ATSApplicationFontsPath + Fonts + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright ©. All rights reserved. + NSPrincipalClass + NSApplication + + diff --git a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift new file mode 100644 index 00000000..737b4827 --- /dev/null +++ b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift @@ -0,0 +1,3 @@ +import AppKit + +_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv) diff --git a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Project.swift b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Project.swift new file mode 100644 index 00000000..ee9777cc --- /dev/null +++ b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Project.swift @@ -0,0 +1,25 @@ +import ProjectDescription + +let project = Project( + name: "App with SystemExtension", + targets: [ + .target( + name: "MainApp", + destinations: [.mac], + product: .app, + bundleId: "io.tuist.MainApp", + infoPlist: "MainApp/Info.plist", + sources: ["MainApp/Sources/**"], + dependencies: [ + .target(name: "SystemExtension") + ] + ), + .target( + name: "SystemExtension", + destinations: [.mac], + product: .systemExtension, + bundleId: "io.tuist.SystemExtension", + sources: ["SystemExtension/Sources/**"] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift new file mode 100644 index 00000000..06697d60 --- /dev/null +++ b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift @@ -0,0 +1,3 @@ +import Foundation + +print("System Extension") diff --git a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Tuist/Config.swift b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Tuist/Config.swift new file mode 100644 index 00000000..ff8e64fa --- /dev/null +++ b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Tuist/Config.swift @@ -0,0 +1,3 @@ +import ProjectDescription + +let config = Config() diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..13613e3e --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/Contents.json b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift new file mode 100644 index 00000000..526e0783 --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift @@ -0,0 +1,20 @@ +import ModuleA +import SwiftUI + +struct ContentView: View { + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world!") + Text("\(#stringify(1 + 1))") + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift new file mode 100644 index 00000000..9eb4ee19 --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift @@ -0,0 +1,15 @@ +import ModuleA +import SwiftUI + +@main +struct TestApp: App { + init() { + ModuleA.test() + } + + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift new file mode 100644 index 00000000..9f31c11e --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift @@ -0,0 +1,23 @@ +import SwiftCompilerPlugin +import SwiftSyntax +import SwiftSyntaxMacros + +@main +struct ModuleAMacros: CompilerPlugin { + var providingMacros: [Macro.Type] = [ + StringifyMacro.self + ] +} + +public struct StringifyMacro: ExpressionMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in _: some MacroExpansionContext + ) -> ExprSyntax { + guard let argument = node.arguments.first?.expression else { + fatalError("compiler bug: the macro does not have any arguments") + } + + return "(\(argument), \(literal: argument.description))" + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift new file mode 100644 index 00000000..3bef61c5 --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift @@ -0,0 +1,3 @@ +@freestanding(expression) +public macro stringify(_ value: T) -> (T, String) = + #externalMacro(module: "ModuleAMacros", type: "StringifyMacro") diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift new file mode 100644 index 00000000..f5405e80 --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift @@ -0,0 +1,12 @@ +import CasePaths + +@CasePathable +enum AppAction { + case home +} + +public enum ModuleA { + public static func test() { + print("Module A") + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift new file mode 100644 index 00000000..3b7d89df --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift @@ -0,0 +1,23 @@ +import SwiftSyntaxMacros +import SwiftSyntaxMacrosTestSupport +import XCTest + +@testable import ModuleAMacros_Testable + +final class StringifyMacroTests: XCTestCase { + let testMacros: [String: Macro.Type] = [ + "stringify": StringifyMacro.self + ] + + func testStringifyStruct() throws { + assertMacroExpansion( + """ + #stringify(1+1) + """, + expandedSource: """ + (1 + 1, "1+1") + """, + macros: testMacros + ) + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Project.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Project.swift new file mode 100644 index 00000000..7285e815 --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Project.swift @@ -0,0 +1,107 @@ +import ProjectDescription + +let project = Project( + name: "AppWithWatchApp", + targets: [ + .target( + name: "App", + destinations: [.iPhone, .appleVision], + product: .app, + bundleId: "io.tuist.App", + infoPlist: .default, + sources: [ + "App/Sources/**" + ], + resources: [ + "App/Resources/**" + ], + dependencies: [ + .target(name: "WatchApp", condition: .when([.ios])), + .target(name: "ModuleA"), + ] + ), + .target( + name: "WatchApp", + destinations: [.appleWatch], + product: .app, + bundleId: "io.tuist.App.watchkitapp", + infoPlist: nil, + sources: "WatchApp/Sources/**", + resources: "WatchApp/Resources/**", + dependencies: [ + .target(name: "ModuleA") + ], + settings: .settings( + base: [ + "GENERATE_INFOPLIST_FILE": true, + "CURRENT_PROJECT_VERSION": "1.0", + "MARKETING_VERSION": "1.0", + "INFOPLIST_KEY_UISupportedInterfaceOrientations": [ + "UIInterfaceOrientationPortrait", + "UIInterfaceOrientationPortraitUpsideDown", + ], + "INFOPLIST_KEY_WKCompanionAppBundleIdentifier": "io.tuist.App", + "INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp": false, + ] + ) + ), + .target( + name: "ModuleA", + destinations: [.iPhone, .appleVision, .appleWatch], + product: .framework, + productName: "ModuleA", + bundleId: "io.tuist.modulea", + sources: [ + "Modules/ModuleA/Sources/**" + ], + dependencies: [ + .external(name: "CasePaths"), + .target(name: "ModuleAMacros"), + ] + ), + .target( + name: "ModuleATests", + destinations: [.iPhone, .appleVision, .appleWatch], + product: .unitTests, + productName: "ModuleATests", + bundleId: "io.tuist.moduleatests", + sources: [ + "Modules/ModuleA/Tests/**" + ], + dependencies: [ + .target(name: "ModuleA"), + .target(name: "ModuleAMacros_Testable"), + .external(name: "SwiftSyntaxMacrosTestSupport"), + ] + ), + .target( + name: "ModuleAMacros", + destinations: .macOS, + product: .macro, + productName: "ModuleAMacros", + bundleId: "io.tuist.moduleamacros", + deploymentTargets: .macOS("14.0"), + sources: [ + "Modules/ModuleA/Macros/Sources/**" + ], + dependencies: [ + .external(name: "SwiftSyntaxMacros"), + .external(name: "SwiftCompilerPlugin"), + ] + ), + .target( + name: "ModuleAMacros_Testable", + destinations: [.iPhone, .appleVision, .appleWatch], // Must match platform of the test target + product: .framework, // Must match be a linkable product + productName: "ModuleAMacros_Testable", + bundleId: "io.tuist.moduleamacros.testable", + sources: [ + "Modules/ModuleA/Macros/Sources/**" + ], + dependencies: [ + .external(name: "SwiftSyntaxMacros"), + .external(name: "SwiftCompilerPlugin"), + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.resolved b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.resolved new file mode 100644 index 00000000..105e045a --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.resolved @@ -0,0 +1,32 @@ +{ + "pins" : [ + { + "identity" : "swift-case-paths", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-case-paths", + "state" : { + "revision" : "bc92c4b27f9a84bfb498cdbfdf35d5a357e9161f", + "version" : "1.5.6" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax", + "state" : { + "revision" : "2bc86522d115234d1f588efe2bcb4ce4be8f8b82", + "version" : "510.0.3" + } + }, + { + "identity" : "xctest-dynamic-overlay", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", + "state" : { + "revision" : "a3f634d1a409c7979cabc0a71b3f26ffa9fc8af1", + "version" : "1.4.3" + } + } + ], + "version" : 2 +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.swift new file mode 100644 index 00000000..bcb99be2 --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.swift @@ -0,0 +1,23 @@ +// swift-tools-version: 5.9 +import PackageDescription + +#if TUIST + import ProjectDescription + + let packageSettings = PackageSettings( + baseSettings: .settings( + base: [ + "ENABLE_USER_SCRIPT_SANDBOXING": true + ] + ) + ) + +#endif + +let package = Package( + name: "Dependencies", + dependencies: [ + .package(url: "https://github.com/pointfreeco/swift-case-paths", from: "1.5.6"), + .package(url: "https://github.com/apple/swift-syntax", "510.0.3"..<"601.0.0-prerelease"), + ] +) diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AccentColor.colorset/Contents.json b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..49c81cd8 --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "watchos", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/Contents.json b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift new file mode 100644 index 00000000..e6b1de31 --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift @@ -0,0 +1,18 @@ +import SwiftUI + +struct ContentView: View { + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world!") + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift new file mode 100644 index 00000000..ac218bca --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift @@ -0,0 +1,21 @@ +import CasePaths +import ModuleA +import SwiftUI + +@CasePathable +enum WatchAppAction { + case home +} + +@main +struct WatchApp: App { + init() { + ModuleA.test() + } + + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift new file mode 100644 index 00000000..37cf404a --- /dev/null +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift @@ -0,0 +1,5 @@ +import Foundation + +public enum WatchConfig { + public static let title: String = "Hello, watchOS" +} diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Project.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Project.swift new file mode 100644 index 00000000..118ad94d --- /dev/null +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Project.swift @@ -0,0 +1,28 @@ +import ProjectDescription + +let project = Project( + name: "ProjectA", + organizationName: "tuist.io", + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.app", + deploymentTargets: DeploymentTargets.iOS("13.0"), + infoPlist: .default, + sources: ["Targets/App/Sources/**"] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.AppTests", + infoPlist: .default, + sources: ["Targets/App/Tests/**"], + dependencies: [ + .target(name: "App") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Sources/AppDelegate.swift new file mode 100644 index 00000000..6db37c4c --- /dev/null +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Sources/AppDelegate.swift @@ -0,0 +1,19 @@ +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func application( + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() + + return true + } +} diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Tests/AppTests.swift new file mode 100644 index 00000000..eaf76af2 --- /dev/null +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Tests/AppTests.swift @@ -0,0 +1,8 @@ +import Foundation +import XCTest + +final class AppTests: XCTestCase { + func test_twoPlusTwo_isFour() { + XCTAssertEqual(2 + 2, 4) + } +} diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/.gitignore b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/.gitignore new file mode 100644 index 00000000..c8512dae --- /dev/null +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/.gitignore @@ -0,0 +1,67 @@ +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Xcode ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +### Xcode Patch ### +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno + +### Projects ### +*.xcodeproj +*.xcworkspace + +### Tuist derived files ### +graph.dot +Derived/ diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Project.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Project.swift new file mode 100644 index 00000000..57a15ba1 --- /dev/null +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Project.swift @@ -0,0 +1,28 @@ +import ProjectDescription + +let project = Project( + name: "ProjectB", + organizationName: "tuist.io", + targets: [ + .target( + name: "App", + destinations: [.iPhone], + product: .app, + bundleId: "io.tuist.app", + deploymentTargets: .iOS("13.0"), + infoPlist: .default, + sources: ["Targets/App/Sources/**"] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.AppTests", + infoPlist: .default, + sources: ["Targets/App/Tests/**"], + dependencies: [ + .target(name: "App") + ] + ), + ] +) diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Sources/AppDelegate.swift new file mode 100644 index 00000000..6db37c4c --- /dev/null +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Sources/AppDelegate.swift @@ -0,0 +1,19 @@ +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func application( + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() + + return true + } +} diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Tests/AppTests.swift new file mode 100644 index 00000000..eaf76af2 --- /dev/null +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Tests/AppTests.swift @@ -0,0 +1,8 @@ +import Foundation +import XCTest + +final class AppTests: XCTestCase { + func test_twoPlusTwo_isFour() { + XCTAssertEqual(2 + 2, 4) + } +} diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/Workspace.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/Workspace.swift new file mode 100644 index 00000000..677724db --- /dev/null +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/Workspace.swift @@ -0,0 +1,9 @@ +import ProjectDescription + +let workspace = Workspace( + name: "Tuist", + projects: [ + "ProjectA", + "ProjectB", + ] +) diff --git a/Sources/TestSupport/Mocks/MockBuildFilesAndPhases.swift b/Sources/TestSupport/Mocks/MockBuildFilesAndPhases.swift new file mode 100644 index 00000000..cc167709 --- /dev/null +++ b/Sources/TestSupport/Mocks/MockBuildFilesAndPhases.swift @@ -0,0 +1,139 @@ +import Foundation +import Path +import XcodeGraph +@testable @preconcurrency import XcodeProj + +public extension PBXBuildFile { + static func mock( + file: PBXFileElement, + settings: [String: Any]? = nil, + pbxProj: PBXProj + ) -> PBXBuildFile { + let buildFile = PBXBuildFile(file: file, settings: settings) + pbxProj.add(object: buildFile) + return buildFile + } +} + +public extension PBXBuildRule { + static func mock( + compilerSpec: String = BuildRule.CompilerSpec.appleClang.rawValue, + fileType: String = BuildRule.FileType.cSource.rawValue, + isEditable: Bool = true, + filePatterns: String? = "*.cpp;*.cxx;*.cc", + name: String = "Default Build Rule", + dependencyFile: String? = nil, + outputFiles: [String] = ["$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).o"], + inputFiles: [String] = [], + outputFilesCompilerFlags: [String]? = nil, + script: String? = nil, + runOncePerArchitecture: Bool? = nil, + pbxProj: PBXProj + ) -> PBXBuildRule { + let rule = PBXBuildRule( + compilerSpec: compilerSpec, + fileType: fileType, + isEditable: isEditable, + filePatterns: filePatterns, + name: name, + dependencyFile: dependencyFile, + outputFiles: outputFiles, + inputFiles: inputFiles, + outputFilesCompilerFlags: outputFilesCompilerFlags, + script: script, + runOncePerArchitecture: runOncePerArchitecture + ) + pbxProj.add(object: rule) + return rule + } +} + +public extension PBXSourcesBuildPhase { + static func mock( + files: [PBXBuildFile], + pbxProj: PBXProj + ) -> PBXSourcesBuildPhase { + let phase = PBXSourcesBuildPhase(files: files) + pbxProj.add(object: phase) + return phase + } +} + +public extension PBXResourcesBuildPhase { + static func mock( + files: [PBXBuildFile], + pbxProj: PBXProj + ) -> PBXResourcesBuildPhase { + let phase = PBXResourcesBuildPhase(files: files) + pbxProj.add(object: phase) + return phase + } +} + +public extension PBXFrameworksBuildPhase { + static func mock( + files: [PBXBuildFile], + pbxProj: PBXProj + ) -> PBXFrameworksBuildPhase { + let phase = PBXFrameworksBuildPhase(files: files) + pbxProj.add(object: phase) + return phase + } +} + +public extension PBXShellScriptBuildPhase { + static func mock( + name: String? = "Embed Precompiled Frameworks", + shellScript: String = "#!/bin/sh\necho 'Mock Shell Script'", + inputPaths: [String] = [], + outputPaths: [String] = [], + inputFileListPaths: [String]? = nil, + outputFileListPaths: [String]? = nil, + shellPath: String = "/bin/sh", + buildActionMask: UInt = PBXBuildPhase.defaultBuildActionMask, + runOnlyForDeploymentPostprocessing: Bool = false, + showEnvVarsInLog: Bool = true, + alwaysOutOfDate: Bool = false, + dependencyFile: String? = nil, + pbxProj: PBXProj + ) -> PBXShellScriptBuildPhase { + let script = PBXShellScriptBuildPhase( + files: [], + name: name, + inputPaths: inputPaths, + outputPaths: outputPaths, + inputFileListPaths: inputFileListPaths, + outputFileListPaths: outputFileListPaths, + shellPath: shellPath, + shellScript: shellScript, + buildActionMask: buildActionMask, + runOnlyForDeploymentPostprocessing: runOnlyForDeploymentPostprocessing, + showEnvVarsInLog: showEnvVarsInLog, + alwaysOutOfDate: alwaysOutOfDate, + dependencyFile: dependencyFile + ) + pbxProj.add(object: script) + return script + } +} + +public extension PBXCopyFilesBuildPhase { + static func mock( + name: String? = "Embed Frameworks", + dstPath: String = "", + dstSubfolderSpec: PBXCopyFilesBuildPhase.SubFolder = .frameworks, + files: [PBXBuildFile] = [], + pbxProj: PBXProj + ) -> PBXCopyFilesBuildPhase { + let phase = PBXCopyFilesBuildPhase( + dstPath: dstPath, + dstSubfolderSpec: dstSubfolderSpec, + name: name, + buildActionMask: PBXBuildPhase.defaultBuildActionMask, + files: files, + runOnlyForDeploymentPostprocessing: false + ) + pbxProj.add(object: phase) + return phase + } +} diff --git a/Sources/TestSupport/Mocks/MockBuildSettings.swift b/Sources/TestSupport/Mocks/MockBuildSettings.swift new file mode 100644 index 00000000..a5ee35a2 --- /dev/null +++ b/Sources/TestSupport/Mocks/MockBuildSettings.swift @@ -0,0 +1,66 @@ +// +// Mc.swift +// XcodeGraphMapper +// +// Created by Andy Kolean on 12/13/24. +// + + +import Foundation +import Path +import XcodeGraph +@testable @preconcurrency import XcodeProj + +public extension XCBuildConfiguration { + static func mock( + name: String = "Debug", + buildSettings: [String: Sendable] = MockDefaults.defaultDebugSettings, + baseConfiguration: PBXFileReference? = nil, + pbxProj: PBXProj + ) -> XCBuildConfiguration { + let anySettings = buildSettings.reduce(into: [String: Any]()) { $0[$1.key] = $1.value } + let config = XCBuildConfiguration( + name: name, + baseConfiguration: baseConfiguration, + buildSettings: anySettings + ) + pbxProj.add(object: config) + return config + } +} + +public extension XCConfigurationList { + static func mock( + configs: [(name: String, settings: [String: Sendable])] = [ + ("Debug", MockDefaults.defaultDebugSettings), + ("Release", MockDefaults.defaultReleaseSettings), + ], + defaultConfigurationName: String = "Release", + defaultConfigurationIsVisible: Bool = false, + proj: PBXProj + ) -> XCConfigurationList { + let configsAny: [(String, [String: Any])] = configs.map { name, sendableSettings in + let anySettings = sendableSettings.reduce(into: [String: Any]()) { $0[$1.key] = $1.value } + return (name, anySettings) + } + + let buildConfigs: [XCBuildConfiguration] = configsAny.map { name, settings in + let config = XCBuildConfiguration( + name: name, + baseConfiguration: nil, + buildSettings: settings + ) + proj.add(object: config) + return config + } + + let configList = XCConfigurationList( + buildConfigurations: buildConfigs, + defaultConfigurationName: defaultConfigurationName, + defaultConfigurationIsVisible: defaultConfigurationIsVisible + ) + proj.add(object: configList) + + return configList + } +} diff --git a/Sources/TestSupport/Mocks/MockDefaults.swift b/Sources/TestSupport/Mocks/MockDefaults.swift new file mode 100644 index 00000000..c3de298d --- /dev/null +++ b/Sources/TestSupport/Mocks/MockDefaults.swift @@ -0,0 +1,31 @@ +// +// MockDefaults.swift +// XcodeGraphMapper +// +// Created by Andy Kolean on 12/13/24. +// + + +import Foundation +import Path +import XcodeGraph +@testable @preconcurrency import XcodeProj + +public struct MockDefaults { + public static let defaultDebugSettings: [String: Sendable] = [ + "PRODUCT_NAME": "$(TARGET_NAME)", + "ENABLE_STRICT_OBJC_MSGSEND": "YES", + "SDKROOT": "iphoneos", + "PRODUCT_BUNDLE_IDENTIFIER": "com.test.app", + ] + + public static let defaultReleaseSettings: [String: Sendable] = [ + "PRODUCT_NAME": "$(TARGET_NAME)", + "VALIDATE_PRODUCT": "YES", + "SDKROOT": "iphoneos", + ] + + public static let defaultProjectAttributes: [String: Sendable] = [ + "BuildIndependentTargetsInParallel": "YES" + ] +} diff --git a/Sources/TestSupport/Mocks/MockFileCreator.swift b/Sources/TestSupport/Mocks/MockFileCreator.swift new file mode 100644 index 00000000..5e755737 --- /dev/null +++ b/Sources/TestSupport/Mocks/MockFileCreator.swift @@ -0,0 +1,18 @@ +import Foundation + +public class MockFileCreator { + public static func createTemporaryExecutable( + name: String = "mockLipo_\(UUID().uuidString)", + withContent content: String + ) throws -> String { + let tempDirectory = FileManager.default.temporaryDirectory + let mockExecutablePath = tempDirectory.appendingPathComponent(name).path + + try content.write(toFile: mockExecutablePath, atomically: true, encoding: .utf8) + + try FileManager.default.setAttributes( + [.posixPermissions: 0o755], ofItemAtPath: mockExecutablePath) + + return mockExecutablePath + } +} diff --git a/Sources/TestSupport/Mocks/MockFileStructure.swift b/Sources/TestSupport/Mocks/MockFileStructure.swift new file mode 100644 index 00000000..71d25d28 --- /dev/null +++ b/Sources/TestSupport/Mocks/MockFileStructure.swift @@ -0,0 +1,143 @@ +import Foundation +import Path +import XcodeGraph +@testable @preconcurrency import XcodeProj + +public extension PBXFileReference { + static func mock( + sourceTree: PBXSourceTree = .group, + name: String? = nil, + explicitFileType: String? = nil, + path: String = "AppDelegate.swift", + lastKnownFileType: String? = "sourcecode.swift", + includeInIndex: Bool? = nil, + pbxProj: PBXProj, + addToMainGroup: Bool = true + ) -> PBXFileReference { + let file = PBXFileReference( + sourceTree: sourceTree, + name: name, + explicitFileType: explicitFileType, + lastKnownFileType: lastKnownFileType, + path: path, + includeInIndex: includeInIndex + ) + pbxProj.add(object: file) + if addToMainGroup, let project = pbxProj.projects.first, + let mainGroup = project.mainGroup { + mainGroup.children.append(file) + } + return file + } + + static func mockProject( + path: String = "App.xcodeproj", + name: String? = "App", + sourceTree: PBXSourceTree = .sourceRoot, + lastKnownFileType: String? = nil, + explicitFileType: String? = nil, + includeInIndex: Bool? = nil, + pbxProj: PBXProj + ) -> PBXFileReference { + let file = PBXFileReference( + sourceTree: sourceTree, + name: name, + explicitFileType: explicitFileType, + lastKnownFileType: lastKnownFileType, + path: path, + includeInIndex: includeInIndex + ) + pbxProj.add(object: file) + return file + } +} + +public extension PBXVariantGroup { + static func mockVariant( + children: [PBXFileElement] = [], + sourceTree: PBXSourceTree = .group, + name: String? = "MainGroup", + path: String? = "/tmp/TestProject", + pbxProj: PBXProj, + addToMainGroup: Bool = true + ) -> PBXVariantGroup { + let group = PBXVariantGroup( + children: children, + sourceTree: sourceTree, + name: name, + path: path + ) + pbxProj.add(objects: children) + pbxProj.add(object: group) + if addToMainGroup, let project = pbxProj.projects.first, let mainGroup = project.mainGroup { + mainGroup.children.append(group) + } + + return group + } +} + +public extension PBXGroup { + static func mock( + children: [PBXFileElement] = [], + sourceTree: PBXSourceTree = .group, + name: String? = "MainGroup", + path: String? = "/tmp/TestProject", + pbxProj: PBXProj, + addToMainGroup: Bool = true + ) -> PBXGroup { + let group = PBXGroup( + children: children, + sourceTree: sourceTree, + name: name, + path: path + ) + pbxProj.add(objects: children) + pbxProj.add(object: group) + if addToMainGroup, let project = pbxProj.projects.first, let mainGroup = project.mainGroup { + mainGroup.children.append(group) + } + + return group + } +} + +public extension XCVersionGroup { + static func mock( + currentVersion: PBXFileReference? = nil, + children: [PBXFileElement] = [], + path: String = "DefaultGroup", + sourceTree: PBXSourceTree = .group, + versionGroupType: String? = nil, + name: String? = nil, + includeInIndex: Bool? = nil, + wrapsLines: Bool? = nil, + usesTabs: Bool? = nil, + indentWidth: UInt? = nil, + tabWidth: UInt? = nil, + pbxProj: PBXProj + ) -> XCVersionGroup { + let group = XCVersionGroup( + currentVersion: currentVersion, + path: path, + name: name, + sourceTree: sourceTree, + versionGroupType: versionGroupType, + includeInIndex: includeInIndex, + wrapsLines: wrapsLines, + usesTabs: usesTabs, + indentWidth: indentWidth, + tabWidth: tabWidth + ) + if let currentVersion = currentVersion { + pbxProj.add(object: currentVersion) + } + if let project = pbxProj.projects.first, let mainGroup = project.mainGroup { + mainGroup.children.append(group) + } + group.children = children + pbxProj.add(object: group) + pbxProj.add(objects: children) + return group + } +} diff --git a/Sources/TestSupport/Mocks/MockProjectAndWorkspace.swift b/Sources/TestSupport/Mocks/MockProjectAndWorkspace.swift new file mode 100644 index 00000000..e4224593 --- /dev/null +++ b/Sources/TestSupport/Mocks/MockProjectAndWorkspace.swift @@ -0,0 +1,138 @@ +import Foundation +import Path +import XcodeGraph +@testable @preconcurrency import XcodeProj + +extension PBXProject { + public static func mock( + name: String = "MainApp", + buildConfigurationList: XCConfigurationList? = nil, + compatibilityVersion: String = "Xcode 14.0", + mainGroup: PBXGroup? = nil, + developmentRegion: String = "en", + knownRegions: [String] = ["Base", "en"], + productsGroup: PBXGroup? = nil, + targets: [PBXTarget]? = nil, + attributes: [String: Any] = MockDefaults.defaultProjectAttributes, + packageReferences: [XCRemoteSwiftPackageReference] = [], + pbxProj: PBXProj + ) -> PBXProject { + let resolvedMainGroup = + mainGroup + ?? PBXGroup.mock( + children: [], + sourceTree: .group, + name: "MainGroup", + path: "/tmp/TestProject", + pbxProj: pbxProj, + addToMainGroup: false + ) + + let resolvedBuildConfigList = buildConfigurationList ?? XCConfigurationList.mock(proj: pbxProj) + pbxProj.add(object: resolvedBuildConfigList) + + if let productsGroup = productsGroup { + pbxProj.add(object: productsGroup) + } + + let projectRef = PBXFileReference.mock( + name: "App", + path: "App.xcodeproj", + pbxProj: pbxProj, + addToMainGroup: false + ) + + let proj = PBXProject( + name: name, + buildConfigurationList: resolvedBuildConfigList, + compatibilityVersion: compatibilityVersion, + preferredProjectObjectVersion: nil, + minimizedProjectReferenceProxies: nil, + mainGroup: resolvedMainGroup, + developmentRegion: developmentRegion, + hasScannedForEncodings: 0, + knownRegions: knownRegions, + productsGroup: productsGroup, + projectDirPath: "", + projects: [["B900DB68213936CC004AEC3E": projectRef]], + projectRoots: [""], + targets: targets ?? [], + packages: packageReferences, + attributes: attributes, + targetAttributes: [:] + ) + + pbxProj.add(object: proj) + pbxProj.rootObject = proj + return proj + } +} + +extension XCWorkspace { + public static func mock( + files: [String] = [ + "App/MainApp.xcodeproj", + "Framework1/Framework1.xcodeproj", + "StaticFramework1/StaticFramework1.xcodeproj", + ] + ) -> XCWorkspace { + let children = files.map { path in + XCWorkspaceDataElement.file(XCWorkspaceDataFileRef(location: .group(path))) + } + return XCWorkspace(data: XCWorkspaceData(children: children)) + } +} + +extension XcodeProj { + public static func mock( + projectName: String = "MainApp", + targets: [PBXTarget] = [], + schemes: [XCScheme] = [] + ) -> XcodeProj { + let pbxProj = PBXProj() + let target = targets.first ?? PBXNativeTarget.mock(pbxProj: pbxProj) + + let _ = XCBuildConfiguration.mock( + name: "Debug", + buildSettings: MockDefaults.defaultDebugSettings, + pbxProj: pbxProj + ) + let _ = XCBuildConfiguration.mock( + name: "Release", + buildSettings: MockDefaults.defaultReleaseSettings, + pbxProj: pbxProj + ) + + let configList = XCConfigurationList.mock( + configs: [ + ("Debug", MockDefaults.defaultDebugSettings), + ("Release", MockDefaults.defaultReleaseSettings), + ], + proj: pbxProj + ) + target.buildConfigurationList = configList + + let pbxProject = PBXProject.mock( + name: projectName, + buildConfigurationList: configList, + targets: [target], + pbxProj: pbxProj + ) + pbxProj.rootObject = pbxProject + + let workspace = XCWorkspace.mock(files: ["App/\(projectName).xcodeproj"]) + return XcodeProj(workspace: workspace, pbxproj: pbxProj) + } +} + +extension PBXObjectReference { + public static func mock(objects: PBXObjects) -> PBXObjectReference { + PBXObjectReference(objects: objects) + } +} + +extension PBXProj { + public func add(objects: [PBXObject]) { + objects.forEach { add(object: $0) } + } +} diff --git a/Sources/TestSupport/Mocks/MockProjectProvider.swift b/Sources/TestSupport/Mocks/MockProjectProvider.swift new file mode 100644 index 00000000..c0375bf0 --- /dev/null +++ b/Sources/TestSupport/Mocks/MockProjectProvider.swift @@ -0,0 +1,50 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj + +@testable import XcodeProjToGraph + +struct MockWorkspaceProvider: WorkspaceProviding { + var workspaceDirectory: AbsolutePath + var xcWorkspacePath: AbsolutePath + var xcworkspace: XCWorkspace + + public init(xcWorkspacePath: AbsolutePath, xcworkspace: XCWorkspace) { + self.xcWorkspacePath = xcWorkspacePath + self.workspaceDirectory = xcWorkspacePath.parentDirectory + self.xcworkspace = xcworkspace + } +} + +struct MockProjectProvider: ProjectProviding { + let sourceDirectory: AbsolutePath + let xcodeProjPath: AbsolutePath + let xcodeProj: XcodeProj + var pbxProj: PBXProj { + xcodeProj.pbxproj + } + + init( + sourceDirectory: String = "/tmp", + projectName: String = "TestProject", + configurationList: XCConfigurationList? = nil, + pbxProj: PBXProj = PBXProj() + ) { + let configurationList = configurationList ?? .mock(proj: pbxProj) + self.sourceDirectory = try! AbsolutePath.resolvePath(sourceDirectory) + self.xcodeProjPath = self.sourceDirectory.appending(component: "TestProject.xcodproj") + // minimal project setup + let pbxProject = PBXProject.mock( + name: projectName, buildConfigurationList: configurationList, pbxProj: pbxProj) + pbxProj.add(object: pbxProject) + pbxProj.add(object: configurationList) + pbxProj.rootObject = pbxProject + + self.xcodeProj = XcodeProj(workspace: XCWorkspace(), pbxproj: pbxProj) + } + + func pbxProject() throws -> PBXProject { + return xcodeProj.pbxproj.projects.first! + } +} diff --git a/Sources/TestSupport/Mocks/MockSchemesAndUserData.swift b/Sources/TestSupport/Mocks/MockSchemesAndUserData.swift new file mode 100644 index 00000000..b2d34c98 --- /dev/null +++ b/Sources/TestSupport/Mocks/MockSchemesAndUserData.swift @@ -0,0 +1,79 @@ +import Foundation +import Path +import XcodeGraph +@testable @preconcurrency import XcodeProj + +public extension XCScheme.TestableReference { + static func mock( + skipped: Bool, + parallelization: XCScheme.TestParallelization = .none, + randomExecutionOrdering: Bool = false, + buildableReference: XCScheme.BuildableReference, + locationScenarioReference: XCScheme.LocationScenarioReference? = nil, + skippedTests: [XCScheme.TestItem] = [], + selectedTests: [XCScheme.TestItem] = [], + useTestSelectionWhitelist: Bool? = nil + ) -> XCScheme.TestableReference { + XCScheme.TestableReference( + skipped: skipped, + parallelization: parallelization, + randomExecutionOrdering: randomExecutionOrdering, + buildableReference: buildableReference, + locationScenarioReference: locationScenarioReference, + skippedTests: skippedTests, + selectedTests: selectedTests, + useTestSelectionWhitelist: useTestSelectionWhitelist + ) + } +} + +public extension XCScheme { + static func mock( + name: String = "DefaultScheme", + buildAction: BuildAction? = nil, + testAction: TestAction? = nil, + launchAction: LaunchAction? = nil, + archiveAction: ArchiveAction? = nil, + profileAction: ProfileAction? = nil, + analyzeAction: AnalyzeAction? = nil, + wasCreatedForAppExtension: Bool? = nil + ) -> XCScheme { + XCScheme( + name: name, + lastUpgradeVersion: "1.3", + version: "1.3", + buildAction: buildAction, + testAction: testAction, + launchAction: launchAction, + profileAction: profileAction, + analyzeAction: analyzeAction, + archiveAction: archiveAction, + wasCreatedForAppExtension: wasCreatedForAppExtension + ) + } +} + +public extension XCUserData { + static func mock( + userName: String = "user", + schemes: [XCScheme] = [], + schemeManagement: XCSchemeManagement? = XCSchemeManagement( + schemeUserState: [ + XCSchemeManagement.UserStateScheme( + name: "App.xcscheme", + shared: true, + orderHint: 0, + isShown: true + ) + ], + suppressBuildableAutocreation: nil + ) + ) -> XCUserData { + XCUserData( + userName: userName, + schemes: schemes, + breakpoints: nil, + schemeManagement: schemeManagement + ) + } +} diff --git a/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift b/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift new file mode 100644 index 00000000..04c3f9e6 --- /dev/null +++ b/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift @@ -0,0 +1,172 @@ +import Foundation +import Path +import XcodeGraph +@testable @preconcurrency import XcodeProj + +public extension PBXTargetDependency { + static func mock( + name: String? = "App", + target: PBXTarget? = nil, + targetProxy: PBXContainerItemProxy? = nil, + platformFilter: String? = nil, + platformFilters: [String]? = nil, + pbxProj: PBXProj + ) -> PBXTargetDependency { + let dependency = PBXTargetDependency( + name: name, + platformFilter: platformFilter, + platformFilters: platformFilters, + target: target, + targetProxy: targetProxy + ) + pbxProj.add(object: dependency) + return dependency + } +} + +public extension PBXContainerItemProxy { + static func mock( + containerPortal: PBXContainerItemProxy.ContainerPortal, + proxyType: PBXContainerItemProxy.ProxyType = .nativeTarget, + remoteGlobalID: PBXContainerItemProxy.RemoteGlobalID = .string("TARGET_REF"), + remoteInfo: String? = "App", + pbxProj: PBXProj + ) -> PBXContainerItemProxy { + let proxy = PBXContainerItemProxy( + containerPortal: containerPortal, + remoteGlobalID: remoteGlobalID, + proxyType: proxyType, + remoteInfo: remoteInfo + ) + pbxProj.add(object: proxy) + return proxy + } +} + +public extension PBXTargetDependency { + static func mockTargetDependency( + name: String, + platformFilters: [String]? = nil, + platformFilter: String? = nil, + pbxProj: PBXProj + ) -> PBXTargetDependency { + let target = PBXNativeTarget.mock( + name: name, + productType: .application, + pbxProj: pbxProj + ) + + let dep = PBXTargetDependency( + name: nil, + target: target + ) + dep.platformFilter = platformFilter + dep.platformFilters = platformFilters + pbxProj.add(object: dep) + return dep + } + + static func mockPackageProductDependency( + productName: String, + pbxProj: PBXProj + ) -> PBXTargetDependency { + let productRef = XCSwiftPackageProductDependency.mock( + productName: productName, + pbxProj: pbxProj + ) + let dep = PBXTargetDependency(name: nil, product: productRef) + pbxProj.add(object: dep) + return dep + } + + static func mockProxyDependency( + remoteInfo: String, + proxyType: PBXContainerItemProxy.ProxyType, + containerPortal: PBXContainerItemProxy.ContainerPortal, + pbxProj: PBXProj, + platformFilter: String? = nil, + platformFilters: [String]? = nil, + remoteObject: PBXObject? = nil + ) -> PBXTargetDependency { + let proxy = PBXContainerItemProxy( + containerPortal: containerPortal, + remoteGlobalID: .string("GLOBAL_ID"), + proxyType: proxyType, + remoteInfo: remoteInfo + ) + pbxProj.add(object: proxy) + + if let remoteObject = remoteObject { + proxy.remoteGlobalID = .object(remoteObject) + } + + let dep = PBXTargetDependency(name: nil, target: nil, targetProxy: proxy) + dep.platformFilter = platformFilter + dep.platformFilters = platformFilters + pbxProj.add(object: dep) + return dep + } +} + +public extension XCSwiftPackageProductDependency { + static func mock( + productName: String, + package: XCRemoteSwiftPackageReference? = nil, + isPlugin: Bool = false, + pbxProj: PBXProj + ) -> XCSwiftPackageProductDependency { + let dep = XCSwiftPackageProductDependency( + productName: productName, package: package, isPlugin: isPlugin + ) + pbxProj.add(object: dep) + return dep + } +} + +public extension PBXNativeTarget { + static func mock( + name: String = "App", + buildConfigurationList: XCConfigurationList? = nil, + buildRules: [PBXBuildRule]? = nil, + buildPhases: [PBXBuildPhase]? = nil, + dependencies: [PBXTargetDependency] = [], + productInstallPath: String? = nil, + productType: PBXProductType = .application, + product: PBXFileReference? = nil, + pbxProj: PBXProj + ) -> PBXNativeTarget { + let resolvedProduct = + product + ?? PBXFileReference.mock( + sourceTree: .buildProductsDir, + explicitFileType: "wrapper.application", + path: "App.app", + lastKnownFileType: nil, + includeInIndex: false, + pbxProj: pbxProj + ) + + let resolvedBuildConfigList = buildConfigurationList ?? XCConfigurationList.mock(proj: pbxProj) + let resolvedBuildRules = buildRules ?? [PBXBuildRule.mock(pbxProj: pbxProj)] + let resolvedBuildPhases = + buildPhases ?? [ + PBXSourcesBuildPhase.mock(files: [], pbxProj: pbxProj), + PBXResourcesBuildPhase.mock(files: [], pbxProj: pbxProj), + PBXFrameworksBuildPhase.mock(files: [], pbxProj: pbxProj), + ] + + let target = PBXNativeTarget( + name: name, + buildConfigurationList: resolvedBuildConfigList, + buildPhases: resolvedBuildPhases, + buildRules: resolvedBuildRules, + dependencies: dependencies, + productInstallPath: productInstallPath, + productName: name, + product: resolvedProduct, + productType: productType + ) + pbxProj.add(object: target) + return target + } +} diff --git a/Sources/TestSupport/WorkspaceFixture.swift b/Sources/TestSupport/WorkspaceFixture.swift new file mode 100644 index 00000000..26a7543e --- /dev/null +++ b/Sources/TestSupport/WorkspaceFixture.swift @@ -0,0 +1,30 @@ +import Foundation +import Path +import XcodeGraph + +// MARK: - Workspace Fixtures +public enum WorkspaceFixture: String, CaseIterable { + case commandLineToolWithDynamicFramework = + "command_line_tool_with_dynamic_framework/CommandLineTool" + case iosAppWithRemoteSwiftPackage = "ios_app_with_remote_swift_package/App" + case iosAppWithSpmDependencies = "ios_app_with_spm_dependencies/App" + case iosAppWithExtensions = "ios_app_with_extensions/App" + case iosAppWithMultiConfigs = "ios_app_with_multi_configs/Workspace" + case iosWorkspaceWithMicrofeatureArchitectureStaticLinking = + "ios_workspace_with_microfeature_architecture_static_linking/Workspace" + case multiplatformAppWithMacrosAndEmbeddedWatchosApp = + "multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp" + case iosAppLarge = "ios_app_large/App" + case ios_app_with_transitive_framework = "ios_app_with_transitive_framework/Workspace" + case macosAppWithSystemExtension = "macos_app_with_system_extension/App with SystemExtension" + case iosAppWithStaticLibraries = + "ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries" + + public var fileExtension: String { "xcworkspace" } + + public func absolutePath() throws -> AbsolutePath { + return try AbsolutePath.resolvePath( + "/Users/andykolean/Developer/XcodeGraphMapper/Tests/TestSupport/Fixtures/\(rawValue).xcworkspace" + ) + } +} diff --git a/Sources/XcodeGraph/Graph/GraphDependency.swift b/Sources/XcodeGraph/Graph/GraphDependency.swift index 005cc1e8..37988426 100644 --- a/Sources/XcodeGraph/Graph/GraphDependency.swift +++ b/Sources/XcodeGraph/Graph/GraphDependency.swift @@ -1,8 +1,8 @@ import Foundation import Path -public enum GraphDependency: Hashable, CustomStringConvertible, Comparable, Codable { - public struct XCFramework: Hashable, CustomStringConvertible, Comparable, Codable { +public enum GraphDependency: Hashable, CustomStringConvertible, Comparable, Codable, Sendable { + public struct XCFramework: Hashable, CustomStringConvertible, Comparable, Codable, Sendable { public let path: AbsolutePath public let infoPlist: XCFrameworkInfoPlist public let linking: BinaryLinking @@ -39,7 +39,7 @@ public enum GraphDependency: Hashable, CustomStringConvertible, Comparable, Coda } } - public enum PackageProductType: String, Hashable, CustomStringConvertible, Comparable, Codable { + public enum PackageProductType: String, Hashable, CustomStringConvertible, Comparable, Codable, Sendable { public var description: String { rawValue } diff --git a/Sources/XcodeGraph/Graph/GraphEdge.swift b/Sources/XcodeGraph/Graph/GraphEdge.swift index da6a3975..2ad7e166 100644 --- a/Sources/XcodeGraph/Graph/GraphEdge.swift +++ b/Sources/XcodeGraph/Graph/GraphEdge.swift @@ -2,7 +2,7 @@ import Foundation /// A directed edge linking representing a dependent relationship /// e.g. `from` (MainApp) depends on `to` (UIKit) -public struct GraphEdge: Hashable, Codable { +public struct GraphEdge: Hashable, Codable, Sendable { public let from: GraphDependency public let to: GraphDependency public init(from: GraphDependency, to: GraphDependency) { diff --git a/Sources/XcodeGraph/Models/BinaryArchitecture.swift b/Sources/XcodeGraph/Models/BinaryArchitecture.swift index ce2321a3..5d402c72 100644 --- a/Sources/XcodeGraph/Models/BinaryArchitecture.swift +++ b/Sources/XcodeGraph/Models/BinaryArchitecture.swift @@ -1,6 +1,6 @@ import Foundation -public enum BinaryArchitecture: String, Codable { +public enum BinaryArchitecture: String, Codable, Sendable { case x8664 = "x86_64" case i386 case armv7 @@ -11,7 +11,7 @@ public enum BinaryArchitecture: String, Codable { case arm64e } -public enum BinaryLinking: String, Hashable, Codable { +public enum BinaryLinking: String, Hashable, Codable, Sendable { case `static`, dynamic } diff --git a/Sources/XcodeGraph/Models/Metadata/TargetMetadata.swift b/Sources/XcodeGraph/Models/Metadata/TargetMetadata.swift index e72de39d..56a184a4 100644 --- a/Sources/XcodeGraph/Models/Metadata/TargetMetadata.swift +++ b/Sources/XcodeGraph/Models/Metadata/TargetMetadata.swift @@ -1,5 +1,5 @@ /// The metadata associated with a target. -public struct TargetMetadata: Codable, Equatable { +public struct TargetMetadata: Codable, Equatable, Sendable { public var tags: Set public init( diff --git a/Sources/XcodeGraph/Models/SDKSource.swift b/Sources/XcodeGraph/Models/SDKSource.swift index 2c52a66e..b0d12fce 100644 --- a/Sources/XcodeGraph/Models/SDKSource.swift +++ b/Sources/XcodeGraph/Models/SDKSource.swift @@ -1,6 +1,6 @@ import Foundation -public enum SDKSource: String, Equatable, Codable { +public enum SDKSource: String, Equatable, Codable, Sendable { case developer // Platforms/iPhoneOS.platform/Developer/Library case system // Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library diff --git a/Sources/XcodeGraph/Models/XCFrameworkInfoPlist.swift b/Sources/XcodeGraph/Models/XCFrameworkInfoPlist.swift index dadd42f3..2d4fb129 100644 --- a/Sources/XcodeGraph/Models/XCFrameworkInfoPlist.swift +++ b/Sources/XcodeGraph/Models/XCFrameworkInfoPlist.swift @@ -2,14 +2,14 @@ import Foundation import Path /// It represents th Info.plist contained in an .xcframework bundle. -public struct XCFrameworkInfoPlist: Codable, Hashable, Equatable { +public struct XCFrameworkInfoPlist: Codable, Hashable, Equatable, Sendable { private enum CodingKeys: String, CodingKey { case libraries = "AvailableLibraries" } /// It represents a library inside an .xcframework - public struct Library: Codable, Hashable, Equatable { - public enum Platform: String, CaseIterable, Codable { + public struct Library: Codable, Hashable, Equatable, Sendable { + public enum Platform: String, CaseIterable, Codable, Sendable { case iOS = "ios" case macOS = "macos" case tvOS = "tvos" diff --git a/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift new file mode 100644 index 00000000..9afafcbb --- /dev/null +++ b/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift @@ -0,0 +1,88 @@ +import Foundation +import Path +import XcodeGraph + +enum FileExtension: String { + case xcodeproj + case xcworkspace + case framework + case xcframework + case staticLibrary = "a" + case dynamicLibrary = "dylib" + case textBasedDynamicLibrary = "tbd" + case coreData = "xcdatamodeld" + case playground = "playground" +} + +extension AbsolutePath { + public static func resolvePaths( + _ paths: [String]?, + file: String = #file, + line: Int = #line, + function: String = #function + ) throws -> [AbsolutePath] { + return try paths?.compactMap { try AbsolutePath.resolvePath($0) } ?? [] + } + + public static func resolveOptionalPath( + _ path: String?, + file: String = #file, + line: Int = #line, + function: String = #function + ) throws -> AbsolutePath? { + guard let path = path else { return nil } + return try AbsolutePath.resolvePath(path) + } + + public static func resolvePath( + _ path: String, + relativeTo: AbsolutePath? = nil, + file: String = #file, + line: Int = #line, + function: String = #function + ) throws -> AbsolutePath { + do { + if let relativeTo { + return try AbsolutePath(validating: path, relativeTo: relativeTo) + } + return try AbsolutePath(validating: path) + } catch { + let message = """ + Invalid absolute path: '\(path)' + Thrown in \(function) at \(file):\(line) + Original error: \(error) + """ + throw NSError( + domain: "GraphMapperError", code: 1, + userInfo: [ + NSLocalizedDescriptionKey: message + ]) + } + } + + + public func mapByExtension(condition: PlatformCondition?) -> TargetDependency? { + let status: LinkingStatus = .required + let absPath = self + switch absPath.fileExtension { + case .framework: + return .framework(path: absPath, status: status, condition: condition) + case .xcframework: + return .xcframework(path: absPath, status: status, condition: condition) + case .dynamicLibrary, .textBasedDynamicLibrary, .staticLibrary: + return .library( + path: absPath, + publicHeaders: absPath.parentDirectory, + swiftModuleMap: nil, + condition: condition + ) + default: + return nil + } + } + + var fileExtension: FileExtension? { + guard let ext = self.extension?.lowercased() else { return nil } + return FileExtension(rawValue: ext) + } +} diff --git a/Sources/XcodeProjToGraph/Extensions/Package+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/Package+Extensions.swift new file mode 100644 index 00000000..02d12b10 --- /dev/null +++ b/Sources/XcodeProjToGraph/Extensions/Package+Extensions.swift @@ -0,0 +1,13 @@ +import XcodeGraph + +extension Package { + /// Returns a URL or identifier for the package based on whether it's remote or local. + public var url: String { + switch self { + case .remote(let url, _): + return url + case .local(let path): + return path.pathString + } + } +} diff --git a/Sources/XcodeProjToGraph/Extensions/Platform+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/Platform+Extensions.swift new file mode 100644 index 00000000..dc67f6cd --- /dev/null +++ b/Sources/XcodeProjToGraph/Extensions/Platform+Extensions.swift @@ -0,0 +1,28 @@ +import XcodeGraph + +extension Platform { + /// Initializes a `Platform` instance from an SDK root string (e.g., "iphoneos", "macosx"). + /// Returns `nil` if no matching platform is found. + public init?(sdkroot: String) { + guard let platform = Platform.allCases.first(where: { $0.xcodeSdkRoot == sdkroot }) else { + return nil + } + self = platform + } + + /// Returns a set of `Destination` values supported by this platform. + public var destinations: Destinations { + switch self { + case .iOS: + return [.iPad, .iPhone, .macCatalyst, .macWithiPadDesign, .appleVisionWithiPadDesign] + case .macOS: + return [.mac] + case .tvOS: + return [.appleTv] + case .watchOS: + return [.appleWatch] + case .visionOS: + return [.appleVision] + } + } +} diff --git a/Sources/XcodeProjToGraph/Extensions/PlatformFilter+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/PlatformFilter+Extensions.swift new file mode 100644 index 00000000..e652dbf5 --- /dev/null +++ b/Sources/XcodeProjToGraph/Extensions/PlatformFilter+Extensions.swift @@ -0,0 +1,25 @@ +import XcodeGraph + +extension PlatformFilter { + /// Initializes a `PlatformFilter` from a string that matches Xcodeproj values. + init?(rawValue: String) { + switch rawValue { + case PlatformFilter.ios.xcodeprojValue: + self = .ios + case PlatformFilter.macos.xcodeprojValue: + self = .macos + case PlatformFilter.tvos.xcodeprojValue: + self = .tvos + case PlatformFilter.catalyst.xcodeprojValue: + self = .catalyst + case PlatformFilter.driverkit.xcodeprojValue: + self = .driverkit + case PlatformFilter.watchos.xcodeprojValue: + self = .watchos + case PlatformFilter.visionos.xcodeprojValue: + self = .visionos + default: + return nil + } + } +} diff --git a/Sources/XcodeProjToGraph/Extensions/Sendable+Retroactive.swift b/Sources/XcodeProjToGraph/Extensions/Sendable+Retroactive.swift new file mode 100644 index 00000000..8886ed78 --- /dev/null +++ b/Sources/XcodeProjToGraph/Extensions/Sendable+Retroactive.swift @@ -0,0 +1,16 @@ +import XcodeProj + +extension PBXTargetDependency: @unchecked @retroactive Sendable {} +extension XCWorkspace: @unchecked @retroactive Sendable {} +extension PBXBuildRule: @unchecked @retroactive Sendable {} +extension XCScheme: @unchecked @retroactive Sendable {} +extension XCScheme.BuildAction.Entry: @unchecked @retroactive Sendable {} +extension XCScheme.TestableReference: @unchecked @retroactive Sendable {} +extension PBXTarget: @unchecked @retroactive Sendable {} +extension XCRemoteSwiftPackageReference: @unchecked @retroactive Sendable {} +extension XCLocalSwiftPackageReference: @unchecked @retroactive Sendable {} +extension PBXBuildFile: @unchecked @retroactive Sendable {} +extension PBXCopyFilesBuildPhase: @unchecked @retroactive Sendable {} +extension PBXShellScriptBuildPhase: @unchecked @retroactive Sendable {} +extension XcodeProj: @unchecked @retroactive Sendable {} +extension PBXBuildPhase: @unchecked @retroactive Sendable {} diff --git a/Sources/XcodeProjToGraph/Extensions/Sequence+Async.swift b/Sources/XcodeProjToGraph/Extensions/Sequence+Async.swift new file mode 100644 index 00000000..0c2e4890 --- /dev/null +++ b/Sources/XcodeProjToGraph/Extensions/Sequence+Async.swift @@ -0,0 +1,24 @@ +import Foundation + +extension Sequence where Element: Sendable { + func asyncCompactMap(_ transform: @escaping @Sendable (Element) async throws -> T?) + async throws -> [T] + { + var results = [T]() + try await withThrowingTaskGroup(of: T?.self) { group in + for element in self { + group.addTask { + try await transform(element) + } + } + + for try await value in group { + if let value = value { + results.append(value) + } + } + } + + return results + } +} diff --git a/Sources/XcodeProjToGraph/Extensions/TargetDependency+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/TargetDependency+Extensions.swift new file mode 100644 index 00000000..0e1f3eb8 --- /dev/null +++ b/Sources/XcodeProjToGraph/Extensions/TargetDependency+Extensions.swift @@ -0,0 +1,26 @@ +// TargetDependency+Extensions +import XcodeGraph + +extension TargetDependency { + /// Extracts the name of the dependency for relevant cases, such as target, project, SDK, package, and libraries. + public var name: String { + switch self { + case .target(let name, _, _): + return name + case .project(let target, _, _, _): + return target + case .sdk(let name, _, _): + return name + case .package(let product, _, _): + return product + case .framework(let path, _, _): + return path.basenameWithoutExt + case .xcframework(let path, _, _): + return path.basenameWithoutExt + case .library(let path, _, _, _): + return path.basenameWithoutExt + case .xctest: + return "xctest" + } + } +} diff --git a/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift new file mode 100644 index 00000000..fb995324 --- /dev/null +++ b/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift @@ -0,0 +1,36 @@ +import Path +import XcodeProj + +extension XCWorkspaceDataFileRef { + func absolutePath(srcPath: AbsolutePath) throws -> AbsolutePath { + switch location { + case .absolute(let path): + let absolutePath = try AbsolutePath.resolvePath(path) + return absolutePath + case .container(let subPath): + let relativePath = try RelativePath(validating: subPath) + let absolutePath = srcPath.appending(relativePath) + return absolutePath + case .developer(let subPath): + let relativePath = try RelativePath(validating: subPath) + let developerPath = try AbsolutePath.resolvePath("/Applications/Xcode.app/Contents/Developer") + let absolutePath = developerPath.appending(relativePath) + return absolutePath + case .group(let subPath): + // Group paths are relative to the workspace file itself + let relativePath = try RelativePath(validating: subPath) + let absolutePath = srcPath.appending(relativePath) + return absolutePath + case .current(let subPath): + // Current paths are relative to the current directory (commonly workspace path) + let relativePath = try RelativePath(validating: subPath) + let absolutePath = srcPath.appending(relativePath) + return absolutePath + case .other(let type, let subPath): + // Handle other path types by prefixing with the type and appending the subpath + let relativePath = try RelativePath(validating: "\(type)/\(subPath)") + let absolutePath = srcPath.appending(relativePath) + return absolutePath + } + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseConstants.swift b/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseConstants.swift new file mode 100644 index 00000000..098d07a4 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseConstants.swift @@ -0,0 +1,48 @@ +import Foundation +import Path + +/// Constants related to various build phases and their default values. +enum BuildPhaseConstants { + /// The default name for a run script build phase if none is provided. + static let defaultScriptName = "Run Script" + /// The default shell path used by run script build phases. + static let defaultShellPath = "/bin/sh" + /// A placeholder name used when a shell script build phase has no name. + static let unnamedScriptPhase = "Unnamed Shell Script Phase" + /// The default name for a copy files build phase if none is provided. + static let copyFilesDefault = "Copy Files" +} + +/// Attributes indicating header visibility within a build target. +enum HeaderAttribute: String { + /// Indicates that a header is public and can be exposed outside the module. + case `public` = "Public" + /// Indicates that a header is private and not exposed outside the module. + case `private` = "Private" +} + +/// Attributes related to code generation behavior for source files. +enum CodeGenAttribute: String { + /// Indicates that code generation is enabled publicly. + case `public` = "codegen" + /// Indicates that code generation is restricted to private scopes. + case `private` = "private_codegen" + /// Indicates that code generation is scoped to the project only. + case project = "project_codegen" + /// Indicates that code generation is disabled for the file. + case disabled = "no_codegen" +} + +/// Commonly referenced directory names within a project. +enum DirectoryName { + /// The directory used to store headers. + static let headers = "Headers" +} + +/// Attributes that can be assigned to build files in certain build phases. +enum BuildFileAttribute: String { + /// Indicates that the file should be code signed on copy during a copy files build phase. + case codeSignOnCopy = "CodeSignOnCopy" +} + + diff --git a/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift b/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift new file mode 100644 index 00000000..bb166dc3 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift @@ -0,0 +1,421 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// A protocol defining how to map various build phases of a target into domain models. +/// +/// Conformers transform raw Xcode build phase data (from `PBXTarget` and associated `XcodeProj` structures) +/// into typed domain models like `SourceFile`, `ResourceFileElement`, `Headers`, `TargetScript`, and more. +/// +/// This allows downstream tools or processes to work with a structured, semantic representation of the build +/// steps involved in an Xcode target. +protocol BuildPhaseMapping: Sendable { + /// Maps source files from the target's Sources build phase. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `SourceFile` instances representing the target’s source files. + /// - Throws: If file references cannot be resolved or paths are invalid. + func mapSources(target: PBXTarget) async throws -> [SourceFile] + + /// Maps resource files from the target's Resources build phase. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `ResourceFileElement` instances representing the target’s resources. + /// - Throws: If resource references cannot be resolved or paths are invalid. + func mapResources(target: PBXTarget) async throws -> [ResourceFileElement] + + /// Maps headers from the target’s Headers build phase. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: A `Headers` instance if headers are present, or `nil` if none found. + /// - Throws: If header file references cannot be resolved. + func mapHeaders(target: PBXTarget) async throws -> Headers? + + /// Maps scripts from shell script build phases. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `TargetScript` instances representing each shell script build phase. + /// - Throws: If script file references or paths cannot be resolved. + func mapScripts(target: PBXTarget) async throws -> [TargetScript] + + /// Maps copy files build phases. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `CopyFilesAction` instances describing how files are copied at build time. + /// - Throws: If file references or paths cannot be resolved. + func mapCopyFiles(target: PBXTarget) async throws -> [CopyFilesAction] + + /// Maps Core Data models from the target’s resource phases. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `CoreDataModel` instances describing the target’s Core Data models. + /// - Throws: If model paths cannot be resolved. + func mapCoreDataModels(target: PBXTarget) async throws -> [CoreDataModel] + + /// Maps raw script build phases for debugging or analysis. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `RawScriptBuildPhase` instances representing the raw script phases. + func mapRawScriptBuildPhases(target: PBXTarget) async throws -> [RawScriptBuildPhase] + + /// Maps additional files that are not included in any build phase. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `FileElement` for files that are part of the project but not in build phases. + /// - Throws: If file references or paths cannot be resolved. + func mapAdditionalFiles(target: PBXTarget) async throws -> [FileElement] + + /// Maps frameworks referenced by the target’s frameworks build phase. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `TargetDependency` instances representing frameworks. + /// - Throws: If framework references or paths cannot be resolved. + func mapFrameworks(target: PBXTarget) async throws -> [TargetDependency] +} + +/// A mapper responsible for converting the build phases of a `PBXTarget` into corresponding domain models. +/// +/// The `BuildPhaseMapper` leverages `ProjectProviding` to resolve file paths and uses XcodeProj’s APIs to +/// navigate build phases (sources, resources, headers, scripts, copy files, and frameworks). +/// +/// By producing strongly-typed domain models (`SourceFile`, `ResourceFileElement`, `Headers`, `TargetScript`, +/// etc.), it enables subsequent steps (like code generation, analysis, or custom tooling) to operate on a well-structured, +/// semantic representation of the target’s build phases. +public final class BuildPhaseMapper: BuildPhaseMapping { + private let projectProvider: ProjectProviding + + /// Creates a new `BuildPhaseMapper`. + /// + /// - Parameter projectProvider: Provides access to the project’s paths, files, and parsed structures. + public init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + } + + public func mapSources(target: PBXTarget) async throws -> [SourceFile] { + guard let sourcesPhase = try target.sourcesBuildPhase() else { return [] } + return try await sourcesPhase.files?.asyncCompactMap { try await self.mapSourceFile($0) }.sorted { $0.path < $1.path } ?? [] + } + + public func mapResources(target: PBXTarget) async throws -> [ResourceFileElement] { + guard let resourcesPhase = try target.resourcesBuildPhase() else { return [] } + var resources = [ResourceFileElement]() + for buildFile in resourcesPhase.files ?? [] { + let resourceElements = try await mapResourceElement(buildFile) + resources.append(contentsOf: resourceElements) + } + return resources.sorted { $0.path < $1.path } + } + + public func mapHeaders(target: PBXTarget) async throws -> Headers? { + guard let headersPhase = try target.headersBuildPhase() else { return nil } + + var publicHeaders = [AbsolutePath]() + var privateHeaders = [AbsolutePath]() + var projectHeaders = [AbsolutePath]() + + for buildFile in headersPhase.files ?? [] { + if let headerInfo = try await mapHeaderFile(buildFile) { + switch headerInfo.visibility { + case .public: publicHeaders.append(headerInfo.path) + case .private: privateHeaders.append(headerInfo.path) + case .project: projectHeaders.append(headerInfo.path) + } + } + } + + return Headers( + public: publicHeaders, + private: privateHeaders, + project: projectHeaders + ) + } + + public func mapScripts(target: PBXTarget) async throws -> [TargetScript] { + let scriptPhases = target.buildPhases.compactMap { $0 as? PBXShellScriptBuildPhase } + return try await scriptPhases.asyncCompactMap { try await self.mapScriptPhase($0, in: target) } + } + + public func mapCopyFiles(target: PBXTarget) async throws -> [CopyFilesAction] { + let copyFilesPhases = target.buildPhases.compactMap { $0 as? PBXCopyFilesBuildPhase } + return try await copyFilesPhases.asyncCompactMap { try await self.mapCopyFilesPhase($0) }.sorted { $0.name < $1.name } + } + + public func mapCoreDataModels(target: PBXTarget) async throws -> [CoreDataModel] { + guard let resourcesPhase = try target.resourcesBuildPhase() else { return [] } + return try resourcesPhase.files?.compactMap { try self.mapCoreDataModel($0) } + ?? [] + } + + public func mapRawScriptBuildPhases(target: PBXTarget) async throws -> [RawScriptBuildPhase] { + let scriptPhases = target.runScriptBuildPhases() + return scriptPhases.compactMap { mapShellScriptBuildPhase($0) } + } + + public func mapAdditionalFiles(target: PBXTarget) async throws -> [FileElement] { + let xcodeProj = projectProvider.xcodeProj + guard let pbxProject = xcodeProj.pbxproj.projects.first, + let mainGroup = pbxProject.mainGroup + else { + throw MappingError.noProjectsFound + } + + let allFiles = try await collectFiles(from: mainGroup) + let filesInBuildPhases = try await getFilesInBuildPhases(target: target) + let additionalFiles = allFiles.subtracting(filesInBuildPhases) + + return additionalFiles.map { FileElement.file(path: $0) } + } + + public func mapFrameworks(target: PBXTarget) async throws -> [TargetDependency] { + let frameworksPhases = target.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase } + let allFrameworkFiles = frameworksPhases.flatMap { $0.files ?? [] } + return try await allFrameworkFiles.asyncCompactMap { try await self.mapFrameworkDependency($0) } + } + + // MARK: - Private Helpers + + private func mapDstSubfolderSpec(_ subfolderSpec: PBXCopyFilesBuildPhase.SubFolder?) + -> CopyFilesAction.Destination + { + switch subfolderSpec { + case .absolutePath: return .absolutePath + case .productsDirectory: return .productsDirectory + case .wrapper: return .wrapper + case .executables: return .executables + case .resources: return .resources + case .javaResources: return .javaResources + case .frameworks: return .frameworks + case .sharedFrameworks: return .sharedFrameworks + case .sharedSupport: return .sharedSupport + case .plugins: return .plugins + default: return .productsDirectory + } + } + + private func determineScriptOrder(target: PBXTarget, scriptPhase: PBXShellScriptBuildPhase) + -> TargetScript.Order + { + guard let scriptPhaseIndex = target.buildPhases.firstIndex(of: scriptPhase) else { + return .pre + } + if let sourcesPhaseIndex = target.buildPhases.firstIndex(where: { $0.buildPhase == .sources }) { + return scriptPhaseIndex > sourcesPhaseIndex ? .post : .pre + } + return scriptPhaseIndex == 0 ? .pre : .post + } + + private func mapSourceFile(_ buildFile: PBXBuildFile) async throws -> SourceFile? { + guard let fileRef = buildFile.file, + let pathString = try fileRef.fullPath(sourceRoot: projectProvider.sourcePathString) + else { return nil } + + let absPath = try AbsolutePath.resolvePath(pathString) + let settings = buildFile.settings ?? [:] + let compilerFlags: String? = settings.string(for: .compilerFlags) + let attributes: [String]? = settings.stringArray(for: .attributes) + + return SourceFile( + path: absPath, + compilerFlags: compilerFlags, + codeGen: mapCodeGenAttribute(attributes) + ) + } + + private func mapCopyFilesPhase(_ phase: PBXCopyFilesBuildPhase) async throws -> CopyFilesAction? { + let files = + try await phase.files?.asyncCompactMap { buildFile -> CopyFileElement? in + guard let fileRef = buildFile.file, + let pathString = try fileRef.fullPath( + sourceRoot: self.projectProvider.sourcePathString) + else { return nil } + + let absolutePath = try AbsolutePath.resolvePath(pathString) + let attributes: [String]? = buildFile.settings?.stringArray(for: .attributes) + let codeSignOnCopy = + attributes?.contains(BuildFileAttribute.codeSignOnCopy.rawValue) ?? false + + return .file(path: absolutePath, condition: nil, codeSignOnCopy: codeSignOnCopy) + } ?? [] + + return CopyFilesAction( + name: phase.name ?? BuildPhaseConstants.copyFilesDefault, + destination: mapDstSubfolderSpec(phase.dstSubfolderSpec), + subpath: phase.dstPath.flatMap { $0.isEmpty ? nil : $0 }, + files: files.sorted { $0.path < $1.path } + ) + } + + private func getFilesInBuildPhases(target: PBXTarget) async throws -> Set { + return Set( + try await target.buildPhases.asyncCompactMap { $0.files } + .flatMap { $0 } + .asyncCompactMap { buildFile -> AbsolutePath? in + guard let fileRef = buildFile.file, + let filePath = try fileRef.fullPath( + sourceRoot: self.projectProvider.sourcePathString) + else { + return nil + } + return try AbsolutePath.resolvePath(filePath) + }) + } + + private func mapResourceElement(_ buildFile: PBXBuildFile) async throws -> [ResourceFileElement] { + try await self.mapResourceElement(buildFile.file) + } + + + private func mapResourceElement(_ fileElement: PBXFileElement?) async throws -> [ResourceFileElement] { + if let fileRef = fileElement, + let pathString = try fileRef.fullPath(sourceRoot: projectProvider.sourcePathString) + { + let absPath = try AbsolutePath.resolvePath(pathString) + return [.file(path: absPath)] + } + return [] + } + + private func mapVariantGroup(_ variantGroup: PBXVariantGroup) async throws + -> [ResourceFileElement] + { + var elements = [ResourceFileElement]() + for child in variantGroup.children { + let childFiles = try await self.mapResourceElement(child) + elements.append(contentsOf: childFiles) + } + return elements + } + + private func collectFiles(from group: PBXGroup) async throws -> Set { + var files = Set() + for child in group.children { + if let file = child as? PBXFileReference, + let pathString = try file.fullPath(sourceRoot: projectProvider.sourcePathString), + let absPath = try? AbsolutePath.resolvePath(pathString) + { + files.insert(absPath) + } else if let subgroup = child as? PBXGroup { + files.formUnion(try await collectFiles(from: subgroup)) + } + } + return files + } + + private func mapFrameworkDependency(_ buildFile: PBXBuildFile) async throws -> TargetDependency? { + guard let fileRef = buildFile.file, + let filePath = try fileRef.fullPath( + sourceRoot: projectProvider.sourceDirectory.pathString) + else { return nil } + + let absPath = try AbsolutePath.resolvePath(filePath) + return absPath.mapByExtension(condition: nil) + } + + private func mapHeaderFile(_ buildFile: PBXBuildFile) async throws -> HeaderInfo? { + guard let pbxElement = buildFile.file, + let pathString = try pbxElement.fullPath(sourceRoot: projectProvider.sourcePathString) + else { return nil } + + let attributes: [String]? = buildFile.settings?.stringArray(for: .attributes) + let absolutePath = try AbsolutePath.resolvePath(pathString) + + let visibility: HeaderInfo.HeaderVisibility + if attributes?.contains(HeaderAttribute.public.rawValue) == true { + visibility = .public + } else if attributes?.contains(HeaderAttribute.private.rawValue) == true { + visibility = .private + } else { + visibility = .project + } + + return HeaderInfo(path: absolutePath, visibility: visibility) + } + + private func mapScriptPhase(_ scriptPhase: PBXShellScriptBuildPhase, in target: PBXTarget) + async throws -> TargetScript? + { + guard let shellScript = scriptPhase.shellScript else { return nil } + + return TargetScript( + name: scriptPhase.name ?? BuildPhaseConstants.defaultScriptName, + order: determineScriptOrder(target: target, scriptPhase: scriptPhase), + script: .embedded(shellScript), + inputPaths: scriptPhase.inputPaths, + inputFileListPaths: try AbsolutePath.resolvePaths(scriptPhase.inputFileListPaths), + outputPaths: scriptPhase.outputPaths, + outputFileListPaths: try AbsolutePath.resolvePaths(scriptPhase.outputFileListPaths), + showEnvVarsInLog: scriptPhase.showEnvVarsInLog, + basedOnDependencyAnalysis: scriptPhase.alwaysOutOfDate ? false : nil, + runForInstallBuildsOnly: scriptPhase.runOnlyForDeploymentPostprocessing, + shellPath: scriptPhase.shellPath ?? BuildPhaseConstants.defaultShellPath, + dependencyFile: try AbsolutePath.resolveOptionalPath(scriptPhase.dependencyFile) + ) + } + + private func mapShellScriptBuildPhase(_ buildPhase: PBXShellScriptBuildPhase) + -> RawScriptBuildPhase + { + let name = buildPhase.name() ?? BuildPhaseConstants.unnamedScriptPhase + let shellPath = buildPhase.shellPath ?? BuildPhaseConstants.defaultShellPath + let script = buildPhase.shellScript ?? "" + let showEnvVarsInLog = buildPhase.showEnvVarsInLog + + return RawScriptBuildPhase( + name: name, + script: script, + showEnvVarsInLog: showEnvVarsInLog, + hashable: false, + shellPath: shellPath + ) + } + + private func mapCoreDataModel(_ buildFile: PBXBuildFile) throws -> CoreDataModel? { + guard let versionGroup = buildFile.file as? XCVersionGroup, + versionGroup.path?.hasSuffix(FileExtension.coreData.rawValue) == true, + let modelPathString = try versionGroup.fullPath(sourceRoot: projectProvider.sourcePathString) + else { + return nil + } + + let absModelPath = try AbsolutePath.resolvePath(modelPathString) + let versions = versionGroup.children.compactMap { $0.path } + let validatedVersions = try versions.map { + try AbsolutePath.resolvePath($0, relativeTo: absModelPath) + } + let currentVersion = + versionGroup.currentVersion?.path ?? validatedVersions.first?.pathString ?? "" + + return CoreDataModel( + path: absModelPath, + versions: validatedVersions, + currentVersion: currentVersion + ) + } + + private func mapCodeGenAttribute(_ attributes: [String]?) -> FileCodeGen? { + guard let attributes = attributes else { return nil } + + if attributes.contains(FileCodeGen.public.rawValue) { + return .public + } else if attributes.contains(FileCodeGen.private.rawValue) { + return .private + } else if attributes.contains(FileCodeGen.project.rawValue) { + return .project + } else if attributes.contains(FileCodeGen.disabled.rawValue) { + return .disabled + } + return nil + } +} + +private struct HeaderInfo { + let path: AbsolutePath + let visibility: HeaderVisibility + + enum HeaderVisibility { + case `public` + case `private` + case project + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Build/BuildRuleMapper.swift b/Sources/XcodeProjToGraph/Mappers/Build/BuildRuleMapper.swift new file mode 100644 index 00000000..f71d9b9a --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Build/BuildRuleMapper.swift @@ -0,0 +1,63 @@ +import Foundation +import Path +import XcodeGraph +@preconcurrency import XcodeProj + +/// A protocol defining how to map `PBXBuildRule` instances into `BuildRule` domain models. +/// +/// Conforming types transform build rules defined in Xcode projects into a structured `BuildRule` model, +/// enabling further analysis or code generation steps to operate on a well-defined representation of these rules. +protocol BuildRuleMapping: Sendable { + /// Maps the build rules of a given `PBXTarget` into an array of `BuildRule` models. + /// + /// - Parameter target: The `PBXTarget` whose build rules are to be mapped. + /// - Returns: An array of `BuildRule` models representing the target’s build rules. + /// - Throws: If resolving or mapping any of the build rules fails. + func mapBuildRules(target: PBXTarget) async throws -> [BuildRule] +} + +/// A mapper that converts `PBXBuildRule` objects into `BuildRule` domain models. +/// +/// `BuildRuleMapper` attempts to translate each `PBXBuildRule` into a `BuildRule` by resolving +/// the compiler specification and file type. If a rule references an unknown compiler spec or +/// file type, that particular rule is skipped. +final class BuildRuleMapper: BuildRuleMapping { + public func mapBuildRules(target: PBXTarget) async throws -> [BuildRule] { + return try await target.buildRules.asyncCompactMap { pbxBuildRule in + guard let compilerSpec = self.mapCompilerSpec(pbxBuildRule.compilerSpec), + let fileType = self.mapFileType(pbxBuildRule.fileType) + else { + // Unknown compiler spec or file type encountered. Skipping this build rule. + return nil + } + + return BuildRule( + compilerSpec: compilerSpec, + fileType: fileType, + filePatterns: pbxBuildRule.filePatterns, + name: pbxBuildRule.name, + outputFiles: pbxBuildRule.outputFiles, + inputFiles: pbxBuildRule.inputFiles, + outputFilesCompilerFlags: pbxBuildRule.outputFilesCompilerFlags, + script: pbxBuildRule.script, + runOncePerArchitecture: pbxBuildRule.runOncePerArchitecture + ) + } + } + + /// Maps a compiler specification string to a `BuildRule.CompilerSpec`. + /// + /// - Parameter compilerSpec: The compiler specification string from the `PBXBuildRule`. + /// - Returns: A `BuildRule.CompilerSpec` instance if recognized; otherwise, `nil`. + public func mapCompilerSpec(_ compilerSpec: String) -> BuildRule.CompilerSpec? { + BuildRule.CompilerSpec(rawValue: compilerSpec) + } + + /// Maps a file type string to a `BuildRule.FileType`. + /// + /// - Parameter fileType: The file type string from the `PBXBuildRule`. + /// - Returns: A `BuildRule.FileType` instance if recognized; otherwise, `nil`. + public func mapFileType(_ fileType: String) -> BuildRule.FileType? { + BuildRule.FileType(rawValue: fileType) + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift new file mode 100644 index 00000000..9ae4d191 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift @@ -0,0 +1,165 @@ +import Foundation +import Path +import XcodeGraph +@preconcurrency import XcodeProj + +/// A protocol that defines how to map `PBXTargetDependency` instances into `TargetDependency` domain models. +/// +/// Conforming types resolve various dependency references—such as direct targets, packages, or proxy references— +/// and translate them into a consistent `TargetDependency` representation. This enables downstream operations +/// like graph analysis, code generation, or dependency visualization to work from a uniform model of dependencies. +protocol DependencyMapping: Sendable { + /// Maps all dependencies of a given `PBXTarget` into an array of `TargetDependency` models. + /// + /// - Parameter target: The `PBXTarget` whose dependencies are to be mapped. + /// - Returns: An array of `TargetDependency` models representing the target's dependencies. + /// - Throws: If any dependency cannot be resolved or mapped correctly. + func mapDependencies(target: PBXTarget) async throws -> [TargetDependency] +} + +/// A protocol that defines how to map a single `PBXTargetDependency` into a `TargetDependency` model. +/// +/// Different implementations may specialize in certain types of dependencies (e.g., direct targets, package products, +/// or proxy references). The `DependencyMapper` uses multiple `DependencyTypeMapper` instances in sequence to attempt +/// resolving each dependency. +protocol DependencyTypeMapper: Sendable { + /// Maps a single `PBXTargetDependency` into a `TargetDependency` model. + /// + /// - Parameter dependency: The `PBXTargetDependency` to map. + /// - Returns: A `TargetDependency` model if the dependency can be resolved by this mapper, or `nil` if not. + /// - Throws: If mapping fails due to issues like invalid paths or missing targets. + func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? +} + +/// A mapper that orchestrates the mapping of all target dependencies by leveraging multiple specialized mappers. +/// +/// The `DependencyMapper` tries each registered `DependencyTypeMapper` in turn, returning the first successful result. +/// This design allows for easy extension of dependency types without modifying a single large mapper. +final class DependencyMapper: DependencyMapping { + private let projectProvider: ProjectProviding + private let typeMappers: [DependencyTypeMapper] + + /// Creates a new `DependencyMapper` with a given project provider. + /// + /// - Parameter projectProvider: Provides access to the project's directories, files, and parsed structures. + init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + self.typeMappers = [ + DirectTargetMapper(), + PackageProductMapper(), + ProxyDependencyMapper(projectProvider: projectProvider), + ] + } + + public func mapDependencies(target: PBXTarget) async throws -> [TargetDependency] { + return try await target.dependencies.asyncCompactMap { [typeMappers] dependency in + for mapper in typeMappers { + if let mapped = try await mapper.mapDependency(dependency) { + return mapped + } + } + return nil + } + } +} + +/// A mapper that handles direct target dependencies, translating them into `.target` `TargetDependency` models. +final class DirectTargetMapper: DependencyTypeMapper { + public func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? { + guard let target = dependency.target else { return nil } + let condition = PlatformConditionMapper.mapCondition(dependency: dependency) + return .target(name: target.name, status: .required, condition: condition) + } +} + +/// A mapper that handles package product dependencies, converting them into `.package` `TargetDependency` models. +final class PackageProductMapper: DependencyTypeMapper { + public func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? { + guard let product = dependency.product else { return nil } + let condition = PlatformConditionMapper.mapCondition(dependency: dependency) + return .package( + product: product.productName, + type: .runtime, + condition: condition + ) + } +} + +/// A mapper that resolves proxy dependencies, which may point to native targets in other projects or file references. +/// +/// Depending on the proxy type, this mapper may return a `.target` or `.project` dependency, or file-based dependencies. +final class ProxyDependencyMapper: DependencyTypeMapper { + private let projectProvider: ProjectProviding + private let fileMapper: FileDependencyMapper + + init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + self.fileMapper = FileDependencyMapper(projectProvider: projectProvider) + } + + public func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? { + guard let targetProxy = dependency.targetProxy, + let proxyType = targetProxy.proxyType + else { return nil } + + let condition = PlatformConditionMapper.mapCondition(dependency: dependency) + + switch proxyType { + case .nativeTarget: + return try await mapNativeTargetProxy(targetProxy, condition: condition) + case .reference: + return try await mapReferenceProxy(targetProxy, condition: condition) + default: + return nil + } + } + + private func mapNativeTargetProxy( + _ targetProxy: PBXContainerItemProxy, + condition: PlatformCondition? + ) async throws -> TargetDependency? { + guard let remoteInfo = targetProxy.remoteInfo else { return nil } + + switch targetProxy.containerPortal { + case .project(_): + return .target(name: remoteInfo, status: .required, condition: condition) + case .fileReference(let fileReference): + guard let projectRelativePath = fileReference.path else { return nil } + let fullPath = projectProvider.sourceDirectory.pathString + projectRelativePath + let absPath = try AbsolutePath.resolvePath(fullPath) + return .project( + target: remoteInfo, + path: absPath, + status: .required, + condition: condition + ) + case .unknownObject: + return nil + } + } + + private func mapReferenceProxy( + _ targetProxy: PBXContainerItemProxy, + condition: PlatformCondition? + ) async throws -> TargetDependency? { + guard let remoteGlobalID = targetProxy.remoteGlobalID else { return nil } + + switch remoteGlobalID { + case .object(let object): + if let fileReference = object as? PBXFileReference { + return try await fileMapper.mapDependency( + pathString: fileReference.path, + condition: condition + ) + } else if let referenceProxy = object as? PBXReferenceProxy { + return try await fileMapper.mapDependency( + pathString: referenceProxy.path, + condition: condition + ) + } + return nil + case .string: + return nil + } + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/FileDependencyMapper.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/FileDependencyMapper.swift new file mode 100644 index 00000000..1a78eb20 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Dependency/FileDependencyMapper.swift @@ -0,0 +1,22 @@ +import Path +import XcodeGraph +import XcodeProj + +/// A helper responsible for mapping file-based dependencies (like frameworks or libraries) into `TargetDependency` models. +final class FileDependencyMapper: Sendable { + private let projectProvider: ProjectProviding + + init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + } + + public func mapDependency(pathString: String?, condition: PlatformCondition?) async throws + -> TargetDependency? + { + guard let pathString = pathString else { return nil } + let validatedPath = projectProvider.sourceDirectory.appending( + try RelativePath(validating: pathString)) + let absPath = try AbsolutePath.resolvePath(validatedPath.pathString) + return absPath.mapByExtension(condition: condition) + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift new file mode 100644 index 00000000..1b7af2c6 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift @@ -0,0 +1,19 @@ +import XcodeGraph +import XcodeProj + +/// A mapper for platform-related conditions, extracting platform filters from `PBXTargetDependency`. +enum PlatformConditionMapper { + /// Maps the platform filters specified on a `PBXTargetDependency` into a `PlatformCondition`. + /// + /// - Parameter dependency: The `PBXTargetDependency` to inspect. + /// - Returns: A `PlatformCondition` representing the platforms this dependency applies to, or `nil` if none. + static public func mapCondition(dependency: PBXTargetDependency) -> PlatformCondition? { + var filters = Set(dependency.platformFilters ?? []) + if let singleFilter = dependency.platformFilter { + filters.insert(singleFilter) + } + + let platformFilters = Set(filters.compactMap { PlatformFilter(rawValue: $0) }) + return PlatformCondition.when(platformFilters) + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift new file mode 100644 index 00000000..f20bd863 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift @@ -0,0 +1,272 @@ +// TargetDependency+GraphMapping + +import Foundation +import Path +import XcodeGraph +import XcodeProj + +extension TargetDependency { + /// Converts a `TargetDependency` into a corresponding `GraphDependency` model, + /// resolving any additional details (like linking types, binary paths, or architectures) + /// based on the dependency type. + /// + /// This method leverages information like the source directory and an all-targets map to + /// resolve project-based target dependencies and to construct the correct `GraphDependency` + /// variant (e.g., frameworks, libraries, SDKs, packages, etc.). + /// + /// - Parameters: + /// - sourceDirectory: The root directory from which to resolve relative paths. + /// - allTargetsMap: A dictionary mapping target names to `Target` models, used to + /// resolve project-based dependencies. + /// - Returns: A `GraphDependency` model representing this dependency. + /// - Throws: If a project-based dependency cannot be resolved (e.g., target not found). + public func graphDependency( + sourceDirectory: AbsolutePath, + allTargetsMap: [String: Target] + ) async throws -> GraphDependency { + switch self { + case .target(let name, let status, _): + return .target(name: name, path: sourceDirectory, status: status) + + case .project(let targetName, let projectPath, let status, _): + return try mapProjectGraphDependency( + projectPath: projectPath, + targetName: targetName, + status: status, + allTargetsMap: allTargetsMap + ) + + case .framework(let path, let status, _): + let binaryPath = path.appending(component: "\(self.name)") + let architectures = (try? await LipoTool.archs(paths: [binaryPath.pathString]).architectures) ?? [] + return .framework( + path: path, + binaryPath: binaryPath, + dsymPath: nil, + bcsymbolmapPaths: [], + linking: .dynamic, + architectures: architectures, + status: status + ) + + case .xcframework(let path, let status, _): + return .xcframework( + GraphDependency.XCFramework( + path: path, + infoPlist: .test(), + linking: .dynamic, + mergeable: false, + status: status, + macroPath: nil, + swiftModules: [], + moduleMaps: [] + ) + ) + + case .library(let path, let publicHeaders, let swiftModuleMap, _): + let linking: BinaryLinking = { + switch path.fileExtension { + case .staticLibrary: + return .static + case .dynamicLibrary, .textBasedDynamicLibrary: + return .dynamic + default: + return .dynamic + } + }() + let architectures = (try? await LipoTool.archs(paths: [path.pathString]).architectures) ?? [] + + return .library( + path: path, + publicHeaders: publicHeaders, + linking: linking, + architectures: architectures, + swiftModuleMap: swiftModuleMap + ) + + case .package(let product, let type, _): + return .packageProduct( + path: sourceDirectory, + product: product, + type: type.graphPackageType + ) + + case .sdk(let name, let status, _): + return .sdk( + name: name, + path: sourceDirectory, + status: status, + source: .developer + ) + + case .xctest: + return .xcframework( + GraphDependency.XCFramework( + path: sourceDirectory, + infoPlist: XCFrameworkInfoPlist.test(), + linking: .dynamic, + mergeable: false, + status: .required, + macroPath: nil, + swiftModules: [], + moduleMaps: [] + ) + ) + } + } + + /// Maps a project-based target dependency into a `GraphDependency` by resolving the target + /// and determining the appropriate dependency type (e.g., framework, library, bundle, app). + /// + /// - Parameters: + /// - projectPath: The absolute path of the project containing the target. + /// - targetName: The name of the target dependency. + /// - status: The linking status of the dependency. + /// - allTargetsMap: A dictionary mapping target names to `Target` models. + /// - Returns: A `GraphDependency` model representing the resolved project target dependency. + /// - Throws: If the target specified by `targetName` is not found in `allTargetsMap`. + public func mapProjectGraphDependency( + projectPath: AbsolutePath, + targetName: String, + status: LinkingStatus, + allTargetsMap: [String: Target] + ) throws -> GraphDependency { + guard let target = allTargetsMap[targetName] else { + throw MappingError.targetNotFound(targetName: targetName, path: projectPath) + } + + let product = target.product + let dependency: GraphDependency + + switch product { + case .framework, .staticFramework: + let linking: BinaryLinking = (product == .staticFramework) ? .static : .dynamic + dependency = .framework( + path: projectPath, + binaryPath: projectPath.appending(component: "\(targetName).framework"), + dsymPath: nil, + bcsymbolmapPaths: [], + linking: linking, + architectures: [], + status: status + ) + + case .staticLibrary, .dynamicLibrary: + let linking: BinaryLinking = (product == .staticLibrary) ? .static : .dynamic + let publicHeadersPath = projectPath.appending(component: "include") + dependency = .library( + path: projectPath.appending( + component: linking == .static + ? "lib\(targetName).a" + : "lib\(targetName).dylib" + ), + publicHeaders: publicHeadersPath, + linking: linking, + architectures: [], + swiftModuleMap: nil + ) + + case .bundle: + dependency = .bundle( + path: projectPath.appending(component: "\(targetName).bundle") + ) + + case .app, .commandLineTool: + dependency = .target( + name: targetName, + path: projectPath, + status: status + ) + + default: + + throw MappingError.unknownDependencyType(name: product.description) + } + + return dependency + } +} + +extension TargetDependency.PackageType { + /// Converts a `TargetDependency.PackageType` into a `GraphDependency.PackageProductType`. + var graphPackageType: GraphDependency.PackageProductType { + switch self { + case .runtime: + return .runtime + case .runtimeEmbedded: + return .runtimeEmbedded + case .plugin: + return .plugin + case .macro: + return .macro + } + } +} + +extension PBXProductType { + /// Maps a `PBXProductType` into a `Product` domain model. + /// + /// - Parameter pbxProductType: The `PBXProductType` to map. + /// - Returns: A `Product` model if known, or `nil` if the product type is unsupported. + func mapProductType() -> Product? { + switch self { + case .application, .messagesApplication, .onDemandInstallCapableApplication: + return .app + + case .framework, .xcFramework: + return .framework + + case .staticFramework: + return .staticFramework + + case .dynamicLibrary: + return .dynamicLibrary + + case .staticLibrary, .metalLibrary: + return .staticLibrary + + case .bundle, .ocUnitTestBundle: + return .bundle + + case .unitTestBundle: + return .unitTests + + case .uiTestBundle: + return .uiTests + + case .appExtension: + return .appExtension + + case .extensionKitExtension, .xcodeExtension: + return .extensionKitExtension + + case .commandLineTool: + return .commandLineTool + + case .messagesExtension: + return .messagesExtension + + case .stickerPack: + return .stickerPackExtension + + case .xpcService: + return .xpc + + case .watchApp, .watch2App, .watch2AppContainer: + return .watch2App + + case .watchExtension, .watch2Extension: + return .watch2Extension + + case .tvExtension: + return .tvTopShelfExtension + + case .systemExtension: + return .systemExtension + + // Unsupported or unknown cases + case .instrumentsPackage, .intentsServiceExtension, .driverExtension, .none: + return nil + } + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift b/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift new file mode 100644 index 00000000..28adca01 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift @@ -0,0 +1,132 @@ +import Foundation +import Path +import PathKit +import XcodeGraph +import XcodeProj + +/// Specifies the type of graph to generate. +/// +/// - `.workspace(WorkspaceProviding)`: Constructs a graph from a workspace provided by a type conforming to `WorkspaceProviding`. +/// - `.project(AbsolutePath)`: Constructs a graph from a single project located at the given path, treating it as a workspace with one project. +public enum GraphType: Sendable { + case workspace(WorkspaceProviding) + case project(AbsolutePath) +} + +/// A mapper that constructs a complete `XcodeGraph.Graph` from a given workspace or project. +/// +/// This mapper aggregates data from projects, packages, and dependencies to produce a fully +/// formed graph. It resolves each project, maps targets, packages, and dependencies, and then +/// assembles them into a final `XcodeGraph.Graph` model. +/// +/// The resulting graph can be used for analysis, generation of derived artifacts, or other +/// tooling tasks. +/// +/// Typical usage involves creating a `GraphMapper` with a specified `GraphType` and then calling +/// `xcodeGraph()` to produce the graph. +public final class GraphMapper: Sendable { + private let projectProviderClosure: @Sendable (AbsolutePath) async throws -> ProjectProviding + public let graphType: GraphType + + /// Initializes the mapper with a specified graph type and an optional project provider closure. + /// + /// - Parameters: + /// - graphType: The type of graph (workspace or project) to map. + /// - projectProviderClosure: A closure that, given a project path, returns a `ProjectProviding`. + /// By default, it initializes a `ProjectProvider` from the given `AbsolutePath`. + public init( + graphType: GraphType, + projectProviderClosure: @escaping @Sendable (AbsolutePath) async throws -> ProjectProviding = { + let xcodeProj = try XcodeProj(pathString: $0.pathString) + return ProjectProvider(xcodeProjPath: $0, xcodeProj: xcodeProj) + } + ) { + self.graphType = graphType + self.projectProviderClosure = projectProviderClosure + } + + /// Constructs an `XcodeGraph.Graph` by mapping all projects, packages, and dependencies within the specified workspace or project. + /// + /// - Returns: A fully mapped `XcodeGraph.Graph` containing projects, packages, dependencies, and conditions. + /// - Throws: An error if project mapping or dependency resolution fails. + public func xcodeGraph() async throws -> XcodeGraph.Graph { + var projectProviders = [AbsolutePath: ProjectProviding]() + var projects: [AbsolutePath: Project] = [:] + var packages: [AbsolutePath: [String: Package]] = [:] + var dependencies: [GraphDependency: Set] = [:] + var dependencyConditions: [GraphEdge: PlatformCondition] = [:] + + let workspace = + switch graphType { + case .workspace(let workspaceProvider): + try await WorkspaceMapper(workspaceProvider: workspaceProvider).map() + case .project(let absolutePath): + Workspace( + path: absolutePath.parentDirectory, + xcWorkspacePath: absolutePath.parentDirectory, + name: "Workspace", + projects: [absolutePath] + ) + } + + let projectResults = try await workspace.projects.lazy.asyncCompactMap { path in + do { + let provider = try await self.projectProviderClosure(path) + let projectMapper = ProjectMapper(projectProvider: provider) + let project = try await projectMapper.mapProject() + return (path, provider, project) + } catch { + return nil + } + } + + for (path, provider, project) in projectResults { + projectProviders[path] = provider + projects[path] = project + } + + let allTargetsMap = Dictionary( + projects.values.flatMap { $0.targets }, + uniquingKeysWith: { existing, _ in + existing + } + ) + + for (path, project) in projects { + if !project.packages.isEmpty { + packages[path] = Dictionary( + uniqueKeysWithValues: project.packages.map { ($0.url, $0) }) + } + + for (name, target) in project.targets { + let sourceDependency = GraphDependency.target(name: name, path: path.parentDirectory) + let edgesAndDependencies = try await target.dependencies.asyncCompactMap { targetDep in + let graphDep = try await targetDep.graphDependency( + sourceDirectory: path.parentDirectory, + allTargetsMap: allTargetsMap + ) + let edge = GraphEdge(from: sourceDependency, to: graphDep) + return (edge, targetDep.condition, graphDep) + } + + for (edge, condition, _) in edgesAndDependencies { + dependencyConditions[edge] = condition + } + + let targetDependencies = edgesAndDependencies.compactMap { $0.2 } + guard !targetDependencies.isEmpty else { continue } + dependencies[sourceDependency] = Set(targetDependencies) + } + } + + return Graph( + name: workspace.name, + path: workspace.path, + workspace: workspace, + projects: projects, + packages: packages, + dependencies: dependencies, + dependencyConditions: dependencyConditions + ) + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift b/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift new file mode 100644 index 00000000..d2dbea6a --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift @@ -0,0 +1,81 @@ +import Foundation +import Path + +/// Represents errors that may occur during project or dependency mapping processes. +enum MappingError: Error, LocalizedError, Equatable { + + // MARK: - Project Mapping Errors + + /// The provided path does not exist. + case pathNotFound(path: String) + + /// The provided project type is unknown. + case unknownProjectType(path: String) + + /// No projects were found in the Xcode project file. + case noProjectsFound + + /// The main files group is missing for a target. + case missingFilesGroup(targetName: String) + + /// The merged binary type for a target is missing. + case missingMergedBinaryType + + /// The repository URL is missing from the package reference. + case missingRepositoryURL(packageName: String) + + /// A generic mapping error with a message. + case generic(String) + + // MARK: - Target Mapping Errors + + /// The bundle identifier is missing from the build settings of a target. + case missingBundleIdentifier(targetName: String) + + /// The specified target could not be found. + case targetNotFound(targetName: String, path: AbsolutePath) + + // MARK: - Dependency Mapping Errors + + /// A required framework dependency was not found. + case frameworkNotFound(name: String, path: AbsolutePath) + + /// An unknown dependency type was encountered. + case unknownDependencyType(name: String) + + // MARK: - Error Descriptions + + /// A localized description of the error. + var errorDescription: String? { + switch self { + + // Project Mapping Cases + case .pathNotFound(let path): + return "The specified path does not exist: \(path)" + case .unknownProjectType(let path): + return "The project type for the path '\(path)' could not be determined." + case .noProjectsFound: + return "No Xcode projects were found." + case .missingFilesGroup(let targetName): + return "The files group is missing for the target '\(targetName)'." + case .missingMergedBinaryType: + return "The merged binary type is missing for the target." + case .missingRepositoryURL(let packageName): + return "The repository URL is missing for the package '\(packageName)'." + case .generic(let message): + return message + + // Target Mapping Cases + case .missingBundleIdentifier(let targetName): + return "The bundle identifier is missing for the target '\(targetName)'." + case .targetNotFound(let targetName, let path): + return "The target '\(targetName)' could not be found in the project at path: \(path.pathString)." + + // Dependency Mapping Cases + case .frameworkNotFound(let name, let path): + return "The required framework '\(name)' was not found at path: \(path.pathString)." + case .unknownDependencyType(let name): + return "An unknown dependency type '\(name)' was encountered." + } + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift b/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift new file mode 100644 index 00000000..3d67fe2b --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift @@ -0,0 +1,111 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// Specifies the type of project to parse. +/// - `.workspace(path)`: Indicates a `.xcworkspace` is present at the given path. +/// - `.xcodeProject(path)`: Indicates a `.xcodeproj` is present at the given path. +public enum ProjectType { + case workspace(AbsolutePath) + case xcodeProject(AbsolutePath) +} + +/// A parser responsible for identifying and parsing Xcode projects or workspaces into a `Graph`. +/// +/// `ProjectParser` determines whether the given path points to a workspace, a project, +/// or a directory containing one of these. It then delegates the actual mapping to `GraphMapper`. +public class ProjectParser { + public init() {} + + /// Parses the project or workspace at the given file system path into a `Graph`. + /// + /// - Parameter path: The path to a `.xcworkspace`, `.xcodeproj`, or a directory containing one. + /// - Returns: A `Graph` representing the parsed project structure. + /// - Throws: + /// - `MappingError.pathNotFound` if the given path does not exist. + /// - `MappingError.noProjectsFound` if no `.xcworkspace` or `.xcodeproj` can be found. + /// - Other errors thrown by `GraphMapper` during mapping. + public static func parse(atPath path: String) async throws -> Graph { + guard FileManager.default.fileExists(atPath: path) else { + throw MappingError.pathNotFound(path: path) + } + + let absolutePath = try AbsolutePath(validating: path) + let type = try determineProjectType(at: absolutePath) + return try await parse(projectType: type) + } + + /// Parses a given `ProjectType` into a `Graph`. + /// + /// - Parameter projectType: The identified `ProjectType` (workspace or project). + /// - Returns: A `Graph` model. + /// - Throws: Any errors encountered during graph mapping. + public static func parse(projectType: ProjectType) async throws -> Graph { + switch projectType { + case .workspace(let path): + return try await mapXCWorkspace(at: path) + case .xcodeProject(let path): + return try await mapXcodeProj(at: path) + } + } + + /// Maps a single `.xcodeproj` at the given path into a `Graph`. + /// + /// - Parameter path: The absolute path to the `.xcodeproj`. + /// - Returns: A `Graph` model of the project. + /// - Throws: Errors from `GraphMapper` if mapping fails. + public static func mapXcodeProj(at path: AbsolutePath) async throws -> Graph { + let graphMapper = GraphMapper(graphType: .project(path)) + return try await graphMapper.xcodeGraph() + } + + /// Maps a single `.xcworkspace` at the given path into a `Graph`. + /// + /// - Parameter path: The absolute path to the `.xcworkspace`. + /// - Returns: A `Graph` model of the workspace and its contained projects. + /// - Throws: Errors from `GraphMapper` if mapping fails. + public static func mapXCWorkspace(at path: AbsolutePath) async throws -> Graph { + let workspaceProvider = try WorkspaceProvider(xcWorkspacePath: path) + let graphMapper = GraphMapper(graphType: .workspace(workspaceProvider)) + return try await graphMapper.xcodeGraph() + } + + /// Determines the type of project at a given path by inspecting file extensions or directory contents. + /// + /// - Parameter path: The absolute path to check. + /// - Returns: A `ProjectType` representing either a `.workspace` or `.xcodeproj`. + /// - Throws: `MappingError.noProjectsFound` if no recognizable project files are found. + private static func determineProjectType(at path: AbsolutePath) throws -> ProjectType { + switch path.fileExtension { + case .xcworkspace: + return .workspace(path) + case .xcodeproj: + return .xcodeProject(path) + default: + return try findProjectInDirectory(at: path) + } + } + + /// Searches a directory for the first `.xcworkspace` or `.xcodeproj` file. + /// + /// - Parameter path: A directory path. + /// - Returns: A `ProjectType` if found. + /// - Throws: + /// - `MappingError.noProjectsFound` if neither a `.xcworkspace` nor `.xcodeproj` is located in the directory. + private static func findProjectInDirectory(at path: AbsolutePath) throws -> ProjectType { + let contents = try FileManager.default.contentsOfDirectory(atPath: path.pathString) + + // Look for the first .xcworkspace + if let workspaceName = contents.first(where: { $0.hasSuffix(".xcworkspace") }) { + return .workspace(path.appending(component: workspaceName)) + } + + // Look for the first .xcodeproj + if let projectName = contents.first(where: { $0.hasSuffix(".xcodeproj") }) { + return .xcodeProject(path.appending(component: projectName)) + } + + throw MappingError.noProjectsFound + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift b/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift new file mode 100644 index 00000000..e2456e96 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift @@ -0,0 +1,92 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// A protocol for mapping `XCSwiftPackageReference` instances to `Package` models. +protocol PackageMapping: Sendable { + /// Maps a remote Swift package reference to a `Package`. + /// + /// - Parameter package: The remote Swift package reference. + /// - Returns: A `Package` representing the remote package. + /// - Throws: If required repository information is missing or invalid. + func map(package: XCRemoteSwiftPackageReference) async throws -> Package + + /// Maps a local Swift package reference to a `Package`. + /// + /// - Parameter package: The local Swift package reference. + /// - Returns: A `Package` representing the local package. + /// - Throws: If the package path cannot be validated. + func map(package: XCLocalSwiftPackageReference) async throws -> Package +} + +/// A mapper that converts remote and local Swift package references into `Package` models. +/// +/// The `PackageMapper` uses the provided `ProjectProviding` to resolve local package paths relative +/// to the project's source directory. For remote packages, it uses the repository URL and version requirement +/// from the `XCRemoteSwiftPackageReference` to construct a `Package` with the appropriate `Requirement`. +final class PackageMapper: PackageMapping { + private let projectProvider: ProjectProviding + + /// Creates a new `PackageMapper`. + /// + /// - Parameter projectProvider: A provider that offers access to the project's directory structure + /// and additional metadata. + init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + } + + /// Maps an `XCRemoteSwiftPackageReference` to a `Package`. + /// + /// - Parameter package: The `XCRemoteSwiftPackageReference` to map. + /// - Returns: A `Package` instance representing the mapped remote package. + /// - Throws: `MappingError.missingRepositoryURL` if the repository URL is not found. + public func map(package: XCRemoteSwiftPackageReference) async throws -> Package { + guard let repositoryURL = package.repositoryURL else { + throw MappingError.missingRepositoryURL(packageName: package.name ?? "Unknown Package") + } + + let requirement = await mapRequirement(package: package) + return .remote(url: repositoryURL, requirement: requirement) + } + + /// Maps an `XCLocalSwiftPackageReference` to a `Package`. + /// + /// - Parameter package: The `XCLocalSwiftPackageReference` to map. + /// - Returns: A `Package` instance representing the mapped local package. + /// - Throws: If the relative path is invalid. + public func map(package: XCLocalSwiftPackageReference) async throws -> Package { + let relativePath = try RelativePath(validating: package.relativePath) + let path = projectProvider.sourceDirectory.appending(relativePath) + return .local(path: path) + } + + /// Maps the version requirement of an `XCRemoteSwiftPackageReference` to a `Package.Requirement`. + /// + /// This method converts the version requirement specified in the Xcode project into a `Requirement` + /// used by the internal `Package` model. It supports all standard SwiftPM versioning schemes, + /// including major/minor constraints, exact versions, ranges, branches, and revisions. + /// + /// - Parameter package: The `XCRemoteSwiftPackageReference` whose requirement to map. + /// - Returns: A `Package.Requirement` representing the version requirement. + public func mapRequirement(package: XCRemoteSwiftPackageReference) async -> Requirement { + guard let versionRequirement = package.versionRequirement else { + return .upToNextMajor("0.0.0") + } + + switch versionRequirement { + case .upToNextMajorVersion(let version): + return .upToNextMajor(version) + case .upToNextMinorVersion(let version): + return .upToNextMinor(version) + case .exact(let version): + return .exact(version) + case .range(let lowerBound, let upperBound): + return .range(from: lowerBound, to: upperBound) + case .branch(let branch): + return .branch(branch) + case .revision(let revision): + return .revision(revision) + } + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift b/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift new file mode 100644 index 00000000..7f0a52cb --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift @@ -0,0 +1,166 @@ +import Foundation +import Path +import PathKit +import XcodeGraph +import XcodeProj + +/// A type that maps a project structure into a `Project` model. +protocol ProjectMapping: Sendable { + /// Maps the current project into a `Project` model. + /// + /// - Returns: A fully constructed `Project` model. + /// - Throws: An error if the mapping process fails. + func mapProject() async throws -> Project +} + +/// A mapper responsible for translating a parsed Xcode project into a `Project` model. +/// +/// The `ProjectMapper` utilizes `SettingsMapper` to resolve project-level settings, +/// `TargetMapper` to map individual targets, and `PackageMapper` to resolve local and remote packages. +/// It also fetches and maps schemes using a `SchemeMapper`, integrates resource synthesizer definitions, +/// and aggregates all project-related data into a single `Project` instance. +public final class ProjectMapper: ProjectMapping { + private let projectProvider: ProjectProviding + + /// Initializes the mapper with a given project provider. + /// + /// - Parameter projectProvider: A `ProjectProviding` instance capable of supplying access + /// to the project's files, directories, and parsed structures. + public init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + } + + /// Maps the current project into a `Project` model. + /// + /// This method fetches project-level settings, targets, packages, and schemes, then consolidates them + /// into a single `Project` instance. It also retrieves resource synthesizers to facilitate code generation + /// tasks and other downstream tooling that relies on structured resource definitions. + /// + /// - Returns: A fully constructed `Project` model containing settings, targets, packages, and schemes. + /// - Throws: An error if any portion of the mapping process (e.g., reading project files or mapping targets) fails. + public func mapProject() async throws -> Project { + let settingsMapper = SettingsMapper() + let pbxProject = try self.projectProvider.pbxProject() + let settings = try await settingsMapper.map( + projectProvider: projectProvider, + configurationList: pbxProject.buildConfigurationList) + + let targetMapper = TargetMapper(projectProvider: projectProvider) + let targetsArray = try await pbxProject.targets.asyncCompactMap { pbxTarget in + try await targetMapper.map(pbxTarget: pbxTarget) + } + + let packageMapper = PackageMapper(projectProvider: projectProvider) + let remotePackages = try await pbxProject.remotePackages.asyncCompactMap { package in + try await packageMapper.map(package: package) + } + let localPackages = try await pbxProject.localPackages.asyncCompactMap { package in + try await packageMapper.map(package: package) + } + + let filesGroup = ProjectGroup.group(name: pbxProject.mainGroup?.name ?? "Project") + + let schemeMapper = try SchemeMapper(graphType: .project(projectProvider.sourceDirectory)) + let userSchemes = projectProvider.xcodeProj.userData.flatMap { $0.schemes } + let sharedSchemes = projectProvider.xcodeProj.sharedData?.schemes ?? [] + let schemes: [Scheme] = + try await schemeMapper.mapSchemesAsync(xcschemes: userSchemes, shared: false) + + (try await schemeMapper.mapSchemesAsync(xcschemes: sharedSchemes, shared: true)) + + let lastUpgradeCheck = pbxProject.attribute(for: .lastUpgradeCheck).flatMap { + Version(string: $0) + } + let defaultKnownRegions = pbxProject.knownRegions.isEmpty ? nil : pbxProject.knownRegions + + return Project( + path: projectProvider.sourceDirectory, + sourceRootPath: projectProvider.sourceDirectory, + xcodeProjPath: projectProvider.sourceDirectory, + name: pbxProject.name, + organizationName: pbxProject.attribute(for: .organization), + classPrefix: pbxProject.attribute(for: .classPrefix), + defaultKnownRegions: defaultKnownRegions, + developmentRegion: pbxProject.developmentRegion, + options: Project.Options( + automaticSchemesOptions: .disabled, + disableBundleAccessors: false, + disableShowEnvironmentVarsInScriptPhases: false, + disableSynthesizedResourceAccessors: false, + textSettings: .init(usesTabs: nil, indentWidth: nil, tabWidth: nil, wrapsLines: nil) + ), + settings: settings, + filesGroup: filesGroup, + targets: targetsArray.sorted(), + packages: remotePackages + localPackages, + schemes: schemes, + ideTemplateMacros: nil, + additionalFiles: [], + resourceSynthesizers: mapResourceSynthesizers(from: pbxProject), + lastUpgradeCheck: lastUpgradeCheck, + type: .local + ) + } + + /// Maps known resource synthesizer definitions from the given `PBXProject`. + /// + /// These synthesizers define how various resource types (e.g., strings, assets, plists) are transformed or accessed. + /// This information can be used downstream to generate code or to provide tooling support. + /// + /// - Parameter pbxProject: The `PBXProject` from which to derive resource synthesizer settings. + /// - Returns: An array of `ResourceSynthesizer` instances. + private func mapResourceSynthesizers(from pbxProject: PBXProject) -> [ResourceSynthesizer] { + let resourceTypes: + [(parser: ResourceSynthesizer.Parser, extensions: [String], template: String)] = [ + (.strings, ["strings", "stringsdict"], "Strings"), + (.assets, ["xcassets"], "Assets"), + (.plists, ["plist"], "Plists"), + (.fonts, ["ttf", "otf", "ttc"], "Fonts"), + (.coreData, ["xcdatamodeld"], "CoreData"), + (.interfaceBuilder, ["xib", "storyboard"], "InterfaceBuilder"), + (.json, ["json"], "JSON"), + (.yaml, ["yaml", "yml"], "YAML"), + (.files, ["txt", "md"], "Files"), + ] + + return resourceTypes.map { resourceType in + ResourceSynthesizer( + parser: resourceType.parser, + parserOptions: [:], + extensions: Set(resourceType.extensions), + template: .defaultTemplate(resourceType.template) + ) + } + } +} + +/// Attributes for project settings that can be retrieved from a `PBXProject`. +enum ProjectAttribute: String { + case classPrefix = "CLASSPREFIX" + case organization = "ORGANIZATIONNAME" + case lastUpgradeCheck = "LastUpgradeCheck" +} + +extension PBXProject { + /// Retrieves the value of a specific project attribute. + /// + /// - Parameter attr: The attribute key to look up. + /// - Returns: The value of the attribute if it exists, or `nil` if not found. + func attribute(for attr: ProjectAttribute) -> String? { + attributes[attr.rawValue] as? String + } +} + +extension SchemeMapper { + /// Maps the given Xcode schemes asynchronously. + /// + /// - Parameters: + /// - xcschemes: An array of `XCScheme` instances to map. + /// - shared: A Boolean indicating whether the schemes are shared. + /// - Returns: An array of mapped `Scheme` instances. + /// - Throws: If mapping any scheme fails. + func mapSchemesAsync(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] { + try await xcschemes.asyncCompactMap { scheme in + try await self.mapScheme(xcscheme: scheme, shared: shared) + } + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift b/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift new file mode 100644 index 00000000..be38c74e --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift @@ -0,0 +1,67 @@ +import Foundation +import Path +import PathKit +import XcodeGraph +@preconcurrency import XcodeProj + +/// A protocol defining how to provide access to an Xcode project and its underlying components. +/// +/// Conforming types must specify the project's source directory, the `.xcodeproj` path, +/// and a parsed `XcodeProj` instance. They also provide a convenient way to retrieve +/// the main `PBXProject` object from the project. +public protocol ProjectProviding: Sendable { + /// The absolute path to the directory containing the Xcode project. + var sourceDirectory: AbsolutePath { get } + + /// The absolute path to the `.xcodeproj` file. + var xcodeProjPath: AbsolutePath { get } + + /// The parsed `XcodeProj` instance representing the Xcode project. + var xcodeProj: XcodeProj { get } + + /// Returns the main `PBXProject` object from the `.xcodeproj`. + /// + /// - Throws: `MappingError.noProjectsFound` if no projects are found in the `.xcodeproj`. + /// - Returns: A `PBXProject` representing the primary project definition. + func pbxProject() throws -> PBXProject +} + +extension ProjectProviding { + /// A convenience property providing the source directory as a string. + public var sourcePathString: String { + sourceDirectory.pathString + } + + /// The source directory is assumed to be the parent of the `.xcodeproj` directory. + public var sourceDirectory: AbsolutePath { + xcodeProjPath.parentDirectory + } + + public func pbxProject() throws -> PBXProject { + guard let pbxProject = xcodeProj.pbxproj.projects.first else { + // TODO: - Add path assocaited value + throw MappingError.noProjectsFound + } + return pbxProject + } +} + +/// A concrete provider that supplies information about a particular Xcode project. +/// +/// `ProjectProvider` wraps a given `.xcodeproj` file, providing access to its +/// `XcodeProj` representation and the associated file paths. It simplifies operations +/// that need to read or analyze the project structure. +public struct ProjectProvider: ProjectProviding { + public let xcodeProj: XcodeProj + public let xcodeProjPath: AbsolutePath + + /// Initializes a new `ProjectProvider` with the given project path and `XcodeProj` instance. + /// + /// - Parameters: + /// - xcodeProjPath: The absolute path to the `.xcodeproj` file. + /// - xcodeProj: The parsed `XcodeProj` instance representing the project. + public init(xcodeProjPath: AbsolutePath, xcodeProj: XcodeProj) { + self.xcodeProjPath = xcodeProjPath + self.xcodeProj = xcodeProj + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/BuildSettings.swift b/Sources/XcodeProjToGraph/Mappers/Settings/BuildSettings.swift new file mode 100644 index 00000000..6e0b4c74 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Settings/BuildSettings.swift @@ -0,0 +1,100 @@ +import Foundation + +/// Keys representing various build settings that may appear in an Xcode project or workspace configuration. +enum BuildSettingKey: String { + case sdkroot = "SDKROOT" + case compilerFlags = "COMPILER_FLAGS" + case attributes = "ATTRIBUTES" + case environmentVariables = "ENVIRONMENT_VARIABLES" + case codeSignOnCopy = "CODE_SIGN_ON_COPY" + case dependencyFile = "DEPENDENCY_FILE" + case inputPaths = "INPUT_PATHS" + case outputPaths = "OUTPUT_PATHS" + case showEnvVarsInLog = "SHOW_ENV_VARS_IN_LOG" + case shellPath = "SHELL_PATH" + case launchArguments = "LAUNCH_ARGUMENTS" + case tags = "TAGS" + case mergedBinaryType = "MERGED_BINARY_TYPE" + case prune = "PRUNE" + case mergeable = "MERGEABLE" + case productBundleIdentifier = "PRODUCT_BUNDLE_IDENTIFIER" + case infoPlistFile = "INFOPLIST_FILE" + case codeSignEntitlements = "CODE_SIGN_ENTITLEMENTS" + case iPhoneOSDeploymentTarget = "IPHONEOS_DEPLOYMENT_TARGET" + case macOSDeploymentTarget = "MACOSX_DEPLOYMENT_TARGET" + case watchOSDeploymentTarget = "WATCHOS_DEPLOYMENT_TARGET" + case tvOSDeploymentTarget = "TVOS_DEPLOYMENT_TARGET" + case visionOSDeploymentTarget = "VISIONOS_DEPLOYMENT_TARGET" +} + +/// A protocol representing a type that can parse a build setting value from a generic `Any`. +protocol BuildSettingValue { + associatedtype Value + static func parse(_ any: Any) -> Value? +} + +/// A type that parses build settings as strings. +enum BuildSettingString: BuildSettingValue { + static func parse(_ any: Any) -> String? { + any as? String + } +} + +/// A type that parses build settings as arrays of strings. +enum BuildSettingStringArray: BuildSettingValue { + static func parse(_ any: Any) -> [String]? { + let arr = any as? [Any] + return arr?.compactMap { $0 as? String } + } +} + +/// A type that parses build settings as booleans. +enum BuildSettingBool: BuildSettingValue { + static func parse(_ any: Any) -> Bool? { + any as? Bool + } +} + +/// A type that parses build settings as dictionaries of strings to strings. +enum BuildSettingStringDict: BuildSettingValue { + static func parse(_ any: Any) -> [String: String]? { + any as? [String: String] + } +} + +extension Dictionary where Key == String, Value == Any { + /// Extracts a build setting value of a specified type from the dictionary. + /// + /// - Parameters: + /// - key: The `BuildSettingKey` to look up. + /// - type: The type conforming to `BuildSettingValue` indicating the expected value type. + /// - Returns: The parsed value if found and valid, or `nil` otherwise. + func extractBuildSetting(_ key: BuildSettingKey, as type: T.Type = T.self) + -> T.Value? + { + guard let value = self[key.rawValue] else { return nil } + return T.parse(value) + } +} + +extension Dictionary where Key == String, Value == Any { + /// Retrieves a string value for the given build setting key. + func string(for key: BuildSettingKey) -> String? { + extractBuildSetting(key, as: BuildSettingString.self) + } + + /// Retrieves an array of strings for the given build setting key. + func stringArray(for key: BuildSettingKey) -> [String]? { + extractBuildSetting(key, as: BuildSettingStringArray.self) + } + + /// Retrieves a boolean value for the given build setting key. + func bool(for key: BuildSettingKey) -> Bool? { + extractBuildSetting(key, as: BuildSettingBool.self) + } + + /// Retrieves a dictionary of strings for the given build setting key. + func stringDict(for key: BuildSettingKey) -> [String: String]? { + extractBuildSetting(key, as: BuildSettingStringDict.self) + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift b/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift new file mode 100644 index 00000000..97776523 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift @@ -0,0 +1,42 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// A utility that determines the variant of a build configuration (e.g., debug or release) +/// based on naming conventions and validates configuration names. +struct ConfigurationMatcher { + /// Represents a pattern mapping a set of keywords to a configuration variant. + private struct Pattern { + let keywords: Set + let variant: BuildConfiguration.Variant + } + + /// Common patterns for identifying build configuration variants. + private static let patterns: [Pattern] = [ + Pattern(keywords: ["debug", "development", "dev"], variant: .debug), + Pattern(keywords: ["release", "prod", "production"], variant: .release), + ] + + /// Returns the build configuration variant for a given configuration name. + /// + /// This method lowercases the name and checks if it contains any keywords for known variants. + /// If none match, it defaults to `.debug`. + /// + /// - Parameter name: The name of the build configuration. + /// - Returns: The determined `BuildConfiguration.Variant` for the given name. + static public func variant(forName name: String) -> BuildConfiguration.Variant { + let lowercased = name.lowercased() + return patterns.first { pattern in + pattern.keywords.contains { lowercased.contains($0) } + }?.variant ?? .debug + } + + /// Validates that a configuration name is non-empty and contains no whitespace. + /// + /// - Parameter name: The configuration name to validate. + /// - Returns: `true` if the name is valid; `false` otherwise. + static public func validateConfigurationName(_ name: String) -> Bool { + !name.isEmpty && name.rangeOfCharacter(from: .whitespaces) == nil + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift b/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift new file mode 100644 index 00000000..ffd06779 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift @@ -0,0 +1,107 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// A protocol defining how to map an Xcode project's configuration list into a `Settings` model. +protocol SettingsMapping: Sendable { + /// Maps a given `XCConfigurationList` into `Settings`. + /// + /// - Parameters: + /// - projectProvider: A provider for project-related paths and files. + /// - configurationList: The `XCConfigurationList` to map. + /// - Returns: A `Settings` model derived from the configuration list, or default settings if none are found. + /// - Throws: If build settings cannot be mapped correctly. + func map(projectProvider: ProjectProviding, configurationList: XCConfigurationList?) async throws + -> Settings +} + +/// A mapper responsible for converting an Xcode project's configuration list into a `Settings` domain model. +final class SettingsMapper: SettingsMapping { + + /// Creates a new `SettingsMapper`. + public init() {} + + public func map(projectProvider: ProjectProviding, configurationList: XCConfigurationList?) + async throws -> Settings + { + guard let configurationList = configurationList else { + return Settings.default + } + + var configurations: [BuildConfiguration: Configuration?] = [:] + for buildConfig in configurationList.buildConfigurations { + let buildSettings = buildConfig.buildSettings + let settingsDict = try await mapBuildSettings(buildSettings) + + var xcconfigAbsolutePath: AbsolutePath? + if let baseConfigRef = buildConfig.baseConfiguration, + let xcconfigPath = try baseConfigRef.fullPath( + sourceRoot: projectProvider.sourceDirectory.pathString) + { + xcconfigAbsolutePath = try AbsolutePath.resolvePath(xcconfigPath) + } + + let variant = variant(forName: buildConfig.name) + let buildConfiguration = BuildConfiguration(name: buildConfig.name, variant: variant) + configurations[buildConfiguration] = Configuration( + settings: settingsDict, + xcconfig: xcconfigAbsolutePath + ) + } + + return Settings( + base: [:], + baseDebug: [:], + configurations: configurations, + defaultSettings: .recommended + ) + } + + /// Maps a dictionary of raw build settings into a `SettingsDictionary`. + /// + /// The raw values are converted into `SettingValue` instances. String and array values are directly converted, + /// while other types are stringified as a fallback. + /// + /// - Parameter buildSettings: A dictionary representing the raw build settings. + /// - Returns: A `SettingsDictionary` with mapped `SettingValue` instances. + /// - Throws: If a setting value cannot be mapped. + public func mapBuildSettings(_ buildSettings: [String: Any]) async throws -> SettingsDictionary { + var settingsDict = SettingsDictionary() + for (key, value) in buildSettings { + settingsDict[key] = try await mapSettingValue(value) + } + return settingsDict + } + + /// Maps a raw setting value into a `SettingValue`. + /// + /// If the value is a string, it's mapped directly. + /// If it's an array, elements are mapped to strings if possible. + /// Otherwise, the value is stringified. + /// + /// - Parameter value: The raw setting value from the build settings. + /// - Returns: A `SettingValue` representing the mapped value. + private func mapSettingValue(_ value: Any) async throws -> SettingValue { + if let stringValue = value as? String { + return .string(stringValue) + } else if let arrayValue = value as? [Any] { + let stringArray = arrayValue.compactMap { $0 as? String } + return .array(stringArray) + } else { + // Fallback: convert non-string/non-array values to string + let stringValue = String(describing: value) + return .string(stringValue) + } + } + + /// Determines a build configuration variant (debug or release) based on its name. + /// + /// Uses `ConfigurationMatcher` to determine if the configuration name suggests a debug or release variant. + /// + /// - Parameter name: The name of the build configuration. + /// - Returns: The corresponding `BuildConfiguration.Variant`. + private func variant(forName name: String) -> BuildConfiguration.Variant { + ConfigurationMatcher.variant(forName: name) + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/XCConfigurationList+Helpers.swift b/Sources/XcodeProjToGraph/Mappers/Settings/XCConfigurationList+Helpers.swift new file mode 100644 index 00000000..b62832b6 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Settings/XCConfigurationList+Helpers.swift @@ -0,0 +1,36 @@ +import XcodeProj + +extension XCConfigurationList { + /// Retrieves a build setting value from the first configuration in which it is found. + /// + /// - Parameter key: The `BuildSettingKey` to look up. + /// - Returns: The value as a `String` if found, otherwise `nil`. + func stringSetting(for key: BuildSettingKey) -> String? { + for config in buildConfigurations { + if let value = config.buildSettings.string(for: key) { + return value + } + } + return nil + } + + /// Retrieves all deployment target values from all configurations and aggregates them. + /// + /// - Parameters: + /// - keys: A list of keys to search (e.g., `.iPhoneOSDeploymentTarget`, `.macOSDeploymentTarget`) + /// - Returns: A dictionary mapping `BuildSettingKey` to the found value. + func allDeploymentTargets(keys: [BuildSettingKey]) -> [BuildSettingKey: String] { + var results = [BuildSettingKey: String]() + + for key in keys { + for config in buildConfigurations { + if let value = config.buildSettings.string(for: key) { + results[key] = value + break // Once found, move to the next key + } + } + } + + return results + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildHeaders.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildHeaders.swift new file mode 100644 index 00000000..337fd92a --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildHeaders.swift @@ -0,0 +1,8 @@ +import XcodeProj + +extension PBXTarget { + /// Returns the headers build phase, if any. + public func headersBuildPhase() throws -> PBXHeadersBuildPhase? { + buildPhases.compactMap { $0 as? PBXHeadersBuildPhase }.first + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift new file mode 100644 index 00000000..fef5abd1 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift @@ -0,0 +1,53 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +extension PBXTarget { + /// Retrieves the path to the Info.plist file from the target's build settings. + /// + /// - Returns: The `INFOPLIST_FILE` value if present, otherwise `nil`. + public func infoPlistPath() throws -> String? { + buildConfigurationList?.stringSetting(for: .infoPlistFile) + } + + /// Retrieves the path to the entitlements file from the target's build settings. + /// + /// - Returns: The `CODE_SIGN_ENTITLEMENTS` value if present, otherwise `nil`. + public func entitlementsPath() throws -> String? { + buildConfigurationList?.stringSetting(for: .codeSignEntitlements) + } + + /// Retrieves deployment target versions for various platforms supported by this target. + /// + /// Checks build configurations for: + /// - `IPHONEOS_DEPLOYMENT_TARGET` + /// - `MACOSX_DEPLOYMENT_TARGET` + /// - `WATCHOS_DEPLOYMENT_TARGET` + /// - `TVOS_DEPLOYMENT_TARGET` + /// - `VISIONOS_DEPLOYMENT_TARGET` + /// + /// - Returns: A `DeploymentTargets` instance containing any discovered versions. + public func deploymentTargets() throws -> DeploymentTargets { + guard let configList = buildConfigurationList else { + return DeploymentTargets(iOS: nil, macOS: nil, watchOS: nil, tvOS: nil, visionOS: nil) + } + + let keys: [BuildSettingKey] = [ + .iPhoneOSDeploymentTarget, + .macOSDeploymentTarget, + .watchOSDeploymentTarget, + .tvOSDeploymentTarget, + .visionOSDeploymentTarget, + ] + + let targets = configList.allDeploymentTargets(keys: keys) + return DeploymentTargets( + iOS: targets[.iPhoneOSDeploymentTarget], + macOS: targets[.macOSDeploymentTarget], + watchOS: targets[.watchOSDeploymentTarget], + tvOS: targets[.tvOSDeploymentTarget], + visionOS: targets[.visionOSDeploymentTarget] + ) + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+PlatformInference.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+PlatformInference.swift new file mode 100644 index 00000000..7fa65da6 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+PlatformInference.swift @@ -0,0 +1,83 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +extension PBXTarget { + /// Maps the `PBXTarget.productType` to a domain `Product` model. + /// + /// If the product type is not explicitly handled, defaults to `.app`. + public func productType() -> Product { + return productType?.mapProductType() ?? .app + } + + /// Determines the set of `Destinations` supported by this target. + /// + /// Attempts to identify platforms from: + /// 1. `SDKROOT` (if present) + /// 2. Deployment targets + /// 3. Product type as a final fallback + /// + /// Supports multi-platform scenarios by unioning destinations from all inferred platforms. + /// + /// - Returns: A `Destinations` set representing all supported destinations. + /// - Throws: If retrieving deployment targets fails. + public func platform() throws -> Destinations { + if let sdkName = buildConfigurationList?.stringSetting(for: .sdkroot), + let root = Platform(sdkroot: sdkName) + { + return root.destinations + } else { + return try inferPlatformFromTarget() + } + } + + /// Infers the platform from deployment targets if `SDKROOT` is not set or recognized. + /// + /// Aggregates all platforms indicated by the deployment targets. If none are found, + /// picks a default based on product type: + /// - iOS for most apps, clips, and app extensions. + /// - macOS for frameworks, libraries, command line tools, macros, xpc, system extensions. + /// - tvOS for tvTopShelfExtension. + /// - iOS otherwise. + /// + /// - Returns: A `Destinations` set representing all inferred destinations. + /// - Throws: If retrieving deployment targets fails. + private func inferPlatformFromTarget() throws -> Destinations { + let deploymentTargets = try self.deploymentTargets() + var result = Destinations() + + if deploymentTargets.iOS != nil { + result.formUnion(Platform.iOS.destinations) + } + if deploymentTargets.macOS != nil { + result.formUnion(Platform.macOS.destinations) + } + if deploymentTargets.watchOS != nil { + result.formUnion(Platform.watchOS.destinations) + } + if deploymentTargets.tvOS != nil { + result.formUnion(Platform.tvOS.destinations) + } + if deploymentTargets.visionOS != nil { + result.formUnion(Platform.visionOS.destinations) + } + + guard result.isEmpty else { return result } + + // Fallback if no platform detected. + let product = productType?.mapProductType() ?? .app + + switch product { + case .app, .stickerPackExtension, .appClip, .appExtension: + return Platform.iOS.destinations + case .framework, .staticLibrary, .dynamicLibrary, .commandLineTool, .macro, .xpc, + .systemExtension: + return Platform.macOS.destinations + case .tvTopShelfExtension: + return Platform.tvOS.destinations + default: + return Platform.iOS.destinations + } + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeDiagnosticsOptions+XCScheme.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeDiagnosticsOptions+XCScheme.swift new file mode 100644 index 00000000..a2befd63 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeDiagnosticsOptions+XCScheme.swift @@ -0,0 +1,25 @@ +import XcodeGraph +import XcodeProj + +extension SchemeDiagnosticsOptions { + /// Creates a SchemeDiagnosticsOptions from a LaunchAction. + init(action: XCScheme.LaunchAction) { + self = SchemeDiagnosticsOptions( + addressSanitizerEnabled: action.enableAddressSanitizer, + detectStackUseAfterReturnEnabled: action.enableASanStackUseAfterReturn, + threadSanitizerEnabled: action.enableThreadSanitizer, + mainThreadCheckerEnabled: !action.disableMainThreadChecker, + performanceAntipatternCheckerEnabled: !action.disablePerformanceAntipatternChecker + ) + } + + /// Creates a SchemeDiagnosticsOptions from a TestAction. + init(action: XCScheme.TestAction) { + self = SchemeDiagnosticsOptions( + addressSanitizerEnabled: action.enableAddressSanitizer, + detectStackUseAfterReturnEnabled: action.enableASanStackUseAfterReturn, + threadSanitizerEnabled: action.enableThreadSanitizer, + mainThreadCheckerEnabled: !action.disableMainThreadChecker + ) + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift new file mode 100644 index 00000000..eee33864 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift @@ -0,0 +1,269 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// A protocol defining how to map XCScheme objects and their associated actions +/// into domain `Scheme` models. +protocol SchemeMapping: Sendable { + /// Maps an array of `XCScheme` instances into `Scheme` models. + /// + /// - Parameters: + /// - xcschemes: An array of `XCScheme` to map. + /// - shared: A Boolean indicating whether the schemes are shared. + /// - Returns: An array of mapped `Scheme` models. + /// - Throws: If any scheme cannot be mapped. + func mapSchemes(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] + + /// Maps a single `XCScheme` into a `Scheme` model. + /// + /// - Parameters: + /// - xcscheme: The `XCScheme` to map. + /// - shared: Indicates whether the scheme is shared. + /// - Returns: A `Scheme` model. + /// - Throws: If any scheme action cannot be mapped. + func mapScheme(xcscheme: XCScheme, shared: Bool) async throws -> Scheme + + /// Maps an `XCScheme.BuildAction` into a `BuildAction` model. + /// - Parameter action: The optional XCScheme.BuildAction. + /// - Returns: A `BuildAction` instance or `nil` if action is `nil`. + /// - Throws: If target references cannot be mapped. + func mapBuildAction(action: XCScheme.BuildAction?) async throws -> BuildAction? + + /// Maps an `XCScheme.LaunchAction` into a `RunAction` model. + /// - Parameter action: The optional XCScheme.LaunchAction. + /// - Returns: A `RunAction` instance or `nil` if action is `nil`. + /// - Throws: If the executable reference cannot be mapped. + func mapRunAction(action: XCScheme.LaunchAction?) async throws -> RunAction? + + /// Maps an `XCScheme.TestAction` into a `TestAction` model. + /// - Parameter action: The optional XCScheme.TestAction. + /// - Returns: A `TestAction` instance or `nil` if action is `nil`. + /// - Throws: If test targets cannot be mapped. + func mapTestAction(action: XCScheme.TestAction?) async throws -> TestAction? + + /// Maps an `XCScheme.ArchiveAction` into an `ArchiveAction` model. + /// - Parameter action: The optional `XCScheme.ArchiveAction`. + /// - Returns: An `ArchiveAction` instance or `nil` if action is `nil`. + func mapArchiveAction(action: XCScheme.ArchiveAction?) async throws -> ArchiveAction? + + /// Maps an `XCScheme.ProfileAction` into a `ProfileAction` model. + /// - Parameter action: The optional `XCScheme.ProfileAction`. + /// - Returns: A `ProfileAction` instance or `nil` if action is `nil`. + func mapProfileAction(action: XCScheme.ProfileAction?) async throws -> ProfileAction? + + /// Maps an `XCScheme.AnalyzeAction` into an `AnalyzeAction` model. + /// - Parameter action: The optional `XCScheme.AnalyzeAction`. + /// - Returns: An `AnalyzeAction` instance or `nil` if action is `nil`. + func mapAnalyzeAction(action: XCScheme.AnalyzeAction?) async throws -> AnalyzeAction? +} + +/// Defines the type of scheme mapper based on the source of the graph. +enum SchemeMapperType { + /// A workspace-based scheme mapper that may have multiple projects. + case workspace(workspacePath: AbsolutePath, pathProviders: [AbsolutePath: ProjectProviding]) + /// A project-based scheme mapper dealing with a single project. + case project(provider: ProjectProviding) +} + +/// A mapper responsible for converting `XCScheme` objects (and related Xcode scheme configurations) +/// into domain `Scheme` models. +/// +/// `SchemeMapper` handles the mapping of build, test, run, archive, profile, and analyze actions +/// within a scheme. It resolves references to targets, environment variables, and launch arguments, +/// producing a `Scheme` model that can be used for further analysis, generation, or tooling tasks. +final class SchemeMapper: SchemeMapping { + private let graphType: GraphType + + /// Initializes the mapper with the given graph type. + /// + /// - Parameter graphType: The graph type (workspace or project) influencing how target references are resolved. + /// - Throws: `MappingError.noProjectsFound` if the required project information is missing. + public init(graphType: GraphType) throws { + self.graphType = graphType + } + + public func mapSchemes(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] { + try await xcschemes.asyncCompactMap { xcscheme in + try await self.mapScheme(xcscheme: xcscheme, shared: shared) + } + } + + public func mapScheme(xcscheme: XCScheme, shared: Bool) async throws -> Scheme { + Scheme( + name: xcscheme.name, + shared: shared, + hidden: false, + buildAction: try await mapBuildAction(action: xcscheme.buildAction), + testAction: try await mapTestAction(action: xcscheme.testAction), + runAction: try await mapRunAction(action: xcscheme.launchAction), + archiveAction: try await mapArchiveAction(action: xcscheme.archiveAction), + profileAction: try await mapProfileAction(action: xcscheme.profileAction), + analyzeAction: try await mapAnalyzeAction(action: xcscheme.analyzeAction) + ) + } + + public func mapBuildAction(action: XCScheme.BuildAction?) async throws -> BuildAction? { + guard let action = action else { return nil } + + let targets = try await action.buildActionEntries.asyncCompactMap { entry in + let buildableReference = entry.buildableReference + return try await self.mapTargetReference(buildableReference: buildableReference) + } + + return BuildAction( + targets: targets, + preActions: [], + postActions: [], + runPostActionsOnFailure: action.runPostActionsOnFailure ?? false, + findImplicitDependencies: action.buildImplicitDependencies + ) + } + + public func mapTestAction(action: XCScheme.TestAction?) async throws -> TestAction? { + guard let action = action else { return nil } + + let testTargets = try await action.testables.asyncCompactMap { testable in + let targetReference = try await self.mapTargetReference( + buildableReference: testable.buildableReference) + return TestableTarget(target: targetReference, skipped: testable.skipped) + } + + let environmentVariables = + action.environmentVariables?.reduce(into: [String: EnvironmentVariable]()) { dict, variable in + dict[variable.variable] = EnvironmentVariable( + value: variable.value, isEnabled: variable.enabled) + } ?? [:] + + let launchArguments = + action.commandlineArguments?.arguments.map { + LaunchArgument(name: $0.name, isEnabled: $0.enabled) + } ?? [] + + let arguments = Arguments( + environmentVariables: environmentVariables, + launchArguments: launchArguments + ) + let diagnosticsOptions = SchemeDiagnosticsOptions(action: action) + + return TestAction( + targets: testTargets, + arguments: arguments, + configurationName: action.buildConfiguration, + attachDebugger: true, + coverage: action.codeCoverageEnabled, + codeCoverageTargets: [], + expandVariableFromTarget: nil, + preActions: [], + postActions: [], + diagnosticsOptions: diagnosticsOptions, + language: action.language, + region: action.region + ) + } + + public func mapRunAction(action: XCScheme.LaunchAction?) async throws -> RunAction? { + guard let action = action else { return nil } + + let executable: TargetReference? = try await { + if let buildableRef = action.runnable?.buildableReference { + return try await mapTargetReference(buildableReference: buildableRef) + } else { + return nil + } + }() + + let environmentVariables = + action.environmentVariables?.reduce(into: [String: EnvironmentVariable]()) { dict, variable in + dict[variable.variable] = EnvironmentVariable( + value: variable.value, isEnabled: variable.enabled) + } ?? [:] + + let launchArguments = + action.commandlineArguments?.arguments.map { + LaunchArgument(name: $0.name, isEnabled: $0.enabled) + } ?? [] + + let arguments = Arguments( + environmentVariables: environmentVariables, + launchArguments: launchArguments + ) + let diagnosticsOptions = SchemeDiagnosticsOptions(action: action) + let attachDebugger = action.selectedDebuggerIdentifier.isEmpty + + return RunAction( + configurationName: action.buildConfiguration, + attachDebugger: attachDebugger, + customLLDBInitFile: nil, + preActions: [], + postActions: [], + executable: executable, + filePath: nil, + arguments: arguments, + options: RunActionOptions(), + diagnosticsOptions: diagnosticsOptions + ) + } + + public func mapArchiveAction(action: XCScheme.ArchiveAction?) async throws -> ArchiveAction? { + guard let action = action else { return nil } + + return ArchiveAction( + configurationName: action.buildConfiguration, + revealArchiveInOrganizer: action.revealArchiveInOrganizer + ) + } + + public func mapProfileAction(action: XCScheme.ProfileAction?) async throws -> ProfileAction? { + guard let action = action else { return nil } + + let executable: TargetReference? = try await { + if let buildableRef = action.buildableProductRunnable?.buildableReference { + return try await mapTargetReference(buildableReference: buildableRef) + } else { + return nil + } + }() + + return ProfileAction( + configurationName: action.buildConfiguration, + executable: executable + ) + } + + public func mapAnalyzeAction(action: XCScheme.AnalyzeAction?) async throws -> AnalyzeAction? { + guard let action = action else { return nil } + return AnalyzeAction(configurationName: action.buildConfiguration) + } + + /// Maps a `XCScheme.BuildableReference` to a `TargetReference`. + /// + /// This involves resolving the container path and the target name. + /// Depending on whether we're dealing with a workspace or a standalone project, + /// the logic may differ. + /// + /// - Parameter buildableReference: The `XCScheme.BuildableReference` to map. + /// - Returns: A `TargetReference` representing the target in the given container. + /// - Throws: If the referenced container cannot be resolved. + private func mapTargetReference(buildableReference: XCScheme.BuildableReference) async throws + -> TargetReference + { + let targetName = buildableReference.blueprintName + let container = buildableReference.referencedContainer + + let projectPath: AbsolutePath + switch self.graphType { + case .workspace(let workspaceProvider): + let containerRelativePath = container.replacingOccurrences(of: "container:", with: "") + let relativePath = try RelativePath(validating: containerRelativePath) + projectPath = workspaceProvider.workspaceDirectory.appending(relativePath) + case .project(let path): + projectPath = path + } + + return TargetReference( + projectPath: projectPath, + name: targetName + ) + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift new file mode 100644 index 00000000..736d67ff --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift @@ -0,0 +1,280 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// A type that maps a `PBXTarget` into a domain `Target` model, extracting platform, product, settings, sources, +/// resources, scripts, dependencies, and other configuration details. +protocol TargetMapping: Sendable { + /// Maps the given PBX target into a `Target` domain model. + /// + /// - Parameter pbxTarget: The `PBXTarget` to map. + /// - Returns: A fully mapped `Target` model. + /// - Throws: A `MappingError` if required information is missing or invalid. + func map(pbxTarget: PBXTarget) async throws -> Target +} + +/// A mapper that converts a `PBXTarget` into a domain `Target` model. +/// +/// The `TargetMapper` relies on: +/// - `SettingsMapper` to map build settings and configurations. +/// - `BuildPhaseMapper` to map source files, resources, scripts, copy files, headers, and related build phases. +/// - `DependencyMapper` to map target dependencies. +/// - `BuildRuleMapper` to map custom build rules. +/// +/// The resulting `Target` object contains comprehensive information needed for further graph operations +/// such as code generation, analysis, or integration with other tooling. +public final class TargetMapper: TargetMapping { + private let projectProvider: ProjectProviding + private let settingsMapper: SettingsMapping + private let buildPhaseMapper: BuildPhaseMapping + private let dependencyMapper: DependencyMapping + private let buildRuleMapper: BuildRuleMapper + + /// Creates a new `TargetMapper` instance. + /// + /// - Parameter projectProvider: Provides access to the project’s paths, `XcodeProj`, and related information. + public init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + self.settingsMapper = SettingsMapper() + self.buildPhaseMapper = BuildPhaseMapper(projectProvider: projectProvider) + self.dependencyMapper = DependencyMapper(projectProvider: projectProvider) + self.buildRuleMapper = BuildRuleMapper() + } + + public func map(pbxTarget: PBXTarget) async throws -> Target { + let platform = try pbxTarget.platform() + let deploymentTargets = try pbxTarget.deploymentTargets() + let product = pbxTarget.productType() + + let settings = try await settingsMapper.map( + projectProvider: projectProvider, + configurationList: pbxTarget.buildConfigurationList + ) + let sources = try await buildPhaseMapper.mapSources(target: pbxTarget) + let resources = try await buildPhaseMapper.mapResources(target: pbxTarget) + let headers = try await buildPhaseMapper.mapHeaders(target: pbxTarget) + let scripts = try await buildPhaseMapper.mapScripts(target: pbxTarget) + let copyFiles = try await buildPhaseMapper.mapCopyFiles(target: pbxTarget) + let coreDataModels = try await buildPhaseMapper.mapCoreDataModels(target: pbxTarget) + let rawScriptBuildPhases = try await buildPhaseMapper.mapRawScriptBuildPhases(target: pbxTarget) + let additionalFiles: [FileElement] = [] // Currently no extra files + + let resourceFileElements = ResourceFileElements(resources) + let buildRules = try await buildRuleMapper.mapBuildRules(target: pbxTarget) + + let environmentVariables = pbxTarget.extractEnvironmentVariables() + + let launchArguments = try extractLaunchArguments(from: pbxTarget) + let filesGroup = try extractFilesGroup(from: pbxTarget) + let playgrounds = try await extractPlaygrounds(from: pbxTarget) + let prune = try extractPrune(from: pbxTarget) + let mergedBinaryType = try extractMergedBinaryType(from: pbxTarget) + let mergeable = try extractMergeable(from: pbxTarget) + let onDemandResourcesTags = try extractOnDemandResourcesTags(from: pbxTarget) + let metadata = try extractMetadata(from: pbxTarget) + + let targetDependencies = try await dependencyMapper.mapDependencies(target: pbxTarget) + let frameworkDependencies = try await buildPhaseMapper.mapFrameworks(target: pbxTarget) + let allDependencies = targetDependencies + frameworkDependencies + + return Target( + name: pbxTarget.name, + destinations: platform, + product: product, + productName: pbxTarget.productName ?? pbxTarget.name, + bundleId: try extractBundleIdentifier(from: pbxTarget), + deploymentTargets: deploymentTargets, + infoPlist: try extractInfoPlist(from: pbxTarget), + entitlements: try extractEntitlements(from: pbxTarget), + settings: settings, + sources: sources, + resources: resourceFileElements, + copyFiles: copyFiles, + headers: headers, + coreDataModels: coreDataModels, + scripts: scripts, + environmentVariables: environmentVariables, + launchArguments: launchArguments, + filesGroup: filesGroup, + dependencies: allDependencies.sorted { $0.name < $1.name }, + rawScriptBuildPhases: rawScriptBuildPhases, + playgrounds: playgrounds, + additionalFiles: additionalFiles, + buildRules: buildRules, + prune: prune, + mergedBinaryType: mergedBinaryType, + mergeable: mergeable, + onDemandResourcesTags: onDemandResourcesTags, + metadata: metadata + ) + } + + // MARK: - Helper Methods + + private func extractBundleIdentifier(from target: PBXTarget) throws -> String { + if let bundleId = target.debugBuildSettings.string(for: .productBundleIdentifier) { + return bundleId + } + throw MappingError.missingBundleIdentifier(targetName: target.name) + } + + private func extractInfoPlist(from target: PBXTarget) throws -> InfoPlist { + if let plistPath = try target.infoPlistPath() { + let path = try resolvePath(plistPath) + let plistDictionary = try readPlistAsDictionary(at: path) + return .dictionary(plistDictionary) + } + return .dictionary([:]) + } + + private func readPlistAsDictionary(at path: AbsolutePath) throws -> [String: Plist.Value] { + let fileURL = URL(fileURLWithPath: path.pathString) + let data = try Data(contentsOf: fileURL) + var format = PropertyListSerialization.PropertyListFormat.xml + guard + let plist = try PropertyListSerialization.propertyList( + from: data, + options: .mutableContainersAndLeaves, + format: &format + ) as? [String: Any] + else { + // TODO: - Better Error Message + throw MappingError.generic("Failed to cast plist contents to a dictionary.") + } + + return try plist.reduce(into: [String: Plist.Value]()) { result, item in + result[item.key] = try convertToPlistValue(item.value) + } + } + + private func convertToPlistValue(_ value: Any) throws -> Plist.Value { + switch value { + case let stringValue as String: + return .string(stringValue) + case let intValue as Int: + return .integer(intValue) + case let doubleValue as Double: + return .real(doubleValue) + case let boolValue as Bool: + return .boolean(boolValue) + case let arrayValue as [Any]: + let convertedArray = try arrayValue.map { try convertToPlistValue($0) } + return .array(convertedArray) + case let dictValue as [String: Any]: + let convertedDict = try dictValue.reduce(into: [String: Plist.Value]()) { + dictResult, dictItem in + dictResult[dictItem.key] = try convertToPlistValue(dictItem.value) + } + return .dictionary(convertedDict) + default: + return .string(String(describing: value)) + } + } + + private func extractEntitlements(from target: PBXTarget) throws -> Entitlements? { + if let entitlementsPath = try target.entitlementsPath() { + let resolvedPath = try resolvePath(entitlementsPath) + return Entitlements.file(path: resolvedPath) + } + return nil + } + + private func resolvePath(_ pathString: String) throws -> AbsolutePath { + let processedPath: String + if pathString.hasPrefix("$(SRCROOT)/") { + let relative = String(pathString.dropFirst("$(SRCROOT)/".count)) + processedPath = relative + } else if pathString == "$(SRCROOT)" { + processedPath = "" + } else { + processedPath = pathString + } + return projectProvider.sourceDirectory.appending(try RelativePath(validating: processedPath)) + } + + private func extractLaunchArguments(from target: PBXTarget) throws -> [LaunchArgument] { + guard let buildConfigList = target.buildConfigurationList else { return [] } + var launchArguments: [LaunchArgument] = [] + for buildConfig in buildConfigList.buildConfigurations { + if let args = buildConfig.buildSettings.stringArray(for: .launchArguments) { + launchArguments.append(contentsOf: args.map { LaunchArgument(name: $0, isEnabled: true) }) + } + } + return launchArguments.uniqued() + } + + private func extractFilesGroup(from target: PBXTarget) throws -> ProjectGroup { + guard let mainGroup = try projectProvider.pbxProject().mainGroup else { + throw MappingError.missingFilesGroup(targetName: target.name) + } + return ProjectGroup.group(name: mainGroup.name ?? "MainGroup") + } + + private func extractPlaygrounds(from target: PBXTarget) async throws -> [AbsolutePath] { + let sourceFiles = try await buildPhaseMapper.mapSources(target: target) + return sourceFiles.filter { $0.path.fileExtension == .playground }.map { $0.path } + } + + private func extractPrune(from target: PBXTarget) throws -> Bool { + target.debugBuildSettings.bool(for: .prune) ?? false + } + + private func extractMergedBinaryType(from target: PBXTarget) throws -> MergedBinaryType { + let mergedBinaryTypeString = target.debugBuildSettings.string(for: .mergedBinaryType) + return mergedBinaryTypeString == "automatic" ? .automatic : .disabled + } + + private func extractMergeable(from target: PBXTarget) throws -> Bool { + target.debugBuildSettings.bool(for: .mergeable) ?? false + } + + private func extractOnDemandResourcesTags(from target: PBXTarget) throws -> OnDemandResourcesTags? + { + // TODO: - implement if needed + return nil + } + + private func extractMetadata(from target: PBXTarget) throws -> TargetMetadata { + var tags: Set = [] + for buildConfig in target.buildConfigurationList?.buildConfigurations ?? [] { + if let tagsString = buildConfig.buildSettings.string(for: .tags) { + let extractedTags = tagsString.split(separator: ",").map { + $0.trimmingCharacters(in: .whitespaces) + } + tags.formUnion(extractedTags) + } + } + return TargetMetadata(tags: tags) + } +} + +extension PBXTarget { + struct EnvironmentExtractor { + static func extract(from buildSettings: BuildSettings) -> [String: EnvironmentVariable] { + guard let envVars = buildSettings.stringDict(for: .environmentVariables) else { + return [:] + } + return envVars.reduce(into: [:]) { result, pair in + result[pair.key] = EnvironmentVariable(value: pair.value, isEnabled: true) + } + } + } + + /// Extracts environment variables from all build configurations of the target. + /// + /// If multiple configurations define environment variables with the same name, the last one processed + /// takes precedence. + public func extractEnvironmentVariables() -> [String: EnvironmentVariable] { + buildConfigurationList?.buildConfigurations.reduce(into: [:]) { result, config in + result.merge(EnvironmentExtractor.extract(from: config.buildSettings)) { current, _ in current + } + } ?? [:] + } + + /// Returns the build settings from the "Debug" build configuration, or an empty dictionary if not present. + var debugBuildSettings: [String: Any] { + buildConfigurationList?.buildConfigurations.first(where: { $0.name == "Debug" })?.buildSettings + ?? [:] + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift new file mode 100644 index 00000000..79542843 --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift @@ -0,0 +1,128 @@ +import Foundation +import Path +import PathKit +import XcodeGraph +import XcodeProj + +/// A type that maps an `.xcworkspace` structure into a `Workspace` model. +protocol WorkspaceMapping: Sendable { + /// Maps the current workspace into a `Workspace` model. + /// + /// - Returns: A `Workspace` instance representing the mapped workspace. + /// - Throws: If any portion of the mapping process fails. + func map() async throws -> Workspace +} + +/// A mapper that translates a provided workspace into a `Workspace` model. +/// +/// The `WorkspaceMapper` extracts project paths, maps schemes, and sets up generation options and +/// additional files. The resulting `Workspace` can then be used as an input to other processes, +/// such as code generation, analysis, or further transformations. +public final class WorkspaceMapper: WorkspaceMapping { + private let workspaceProvider: WorkspaceProviding + + /// Creates a new `WorkspaceMapper`. + /// + /// - Parameter workspaceProvider: A provider capable of supplying a parsed `XCWorkspace` and its file paths. + public init(workspaceProvider: WorkspaceProviding) { + self.workspaceProvider = workspaceProvider + } + + /// Maps the current workspace into a `Workspace` model. + /// + /// This method identifies all `.xcodeproj` files in the workspace, maps any detected schemes, + /// and constructs a fully-populated `Workspace` instance. It sets default generation options, + /// and includes hooks for adding additional files or IDE template macros if needed. + /// + /// - Returns: A fully constructed `Workspace` instance. + /// - Throws: If extracting projects or mapping schemes fails. + public func map() async throws -> Workspace { + let xcworkspace = workspaceProvider.xcworkspace + let xcWorkspacePath = workspaceProvider.xcWorkspacePath + let srcPath = workspaceProvider.workspaceDirectory + let projectPaths = try extractProjectPaths(from: xcworkspace.data.children, srcPath: srcPath) + let projectAbsolutePaths = projectPaths.map { $0 } + + let workspaceName = xcWorkspacePath.basenameWithoutExt + let schemes = try await mapSchemes(from: srcPath) + + let ideTemplateMacros: IDETemplateMacros? = nil + let additionalFiles: [FileElement] = [] + let generationOptions = Workspace.GenerationOptions( + enableAutomaticXcodeSchemes: nil, + autogeneratedWorkspaceSchemes: .disabled, + lastXcodeUpgradeCheck: nil, + renderMarkdownReadme: false + ) + + return Workspace( + path: srcPath, + xcWorkspacePath: xcWorkspacePath, + name: workspaceName, + projects: projectAbsolutePaths, + schemes: schemes, + generationOptions: generationOptions, + ideTemplateMacros: ideTemplateMacros, + additionalFiles: additionalFiles + ) + } + + /// Recursively extracts all `.xcodeproj` paths from the workspace’s file and group references. + /// + /// - Parameters: + /// - elements: The array of `XCWorkspaceDataElement` representing files or groups in the workspace. + /// - srcPath: The source directory path used as a base for resolving relative references. + /// - Returns: An array of absolute paths to `.xcodeproj` directories. + /// - Throws: If resolving any referenced path fails. + private func extractProjectPaths(from elements: [XCWorkspaceDataElement], srcPath: AbsolutePath) + throws -> [AbsolutePath] + { + var paths = [AbsolutePath]() + + for element in elements { + switch element { + case .file(let ref): + let refPath = Path(ref.location.path) + if refPath.extension?.lowercased() == "xcodeproj" { + do { + let absPath = try ref.absolutePath(srcPath: srcPath) + paths.append(absPath) + } catch { + print("⚠️ Could not resolve absolute path for \(ref.location.path): \(error)") + } + } + case .group(let group): + let groupPaths = try extractProjectPaths( + from: group.children, + srcPath: srcPath.appending(component: group.location.path) + ) + paths.append(contentsOf: groupPaths) + } + } + + return paths + } + + /// Maps all shared schemes found within the workspace. + /// + /// - Parameter srcPath: The source path of the workspace. + /// - Returns: An array of mapped `Scheme` instances. + /// - Throws: If reading or mapping any of the schemes fails. + private func mapSchemes(from srcPath: AbsolutePath) async throws -> [Scheme] { + var schemes = [Scheme]() + let sharedDataPath = Path(srcPath.pathString) + "xcshareddata/xcschemes" + + if sharedDataPath.exists { + let schemePaths = try sharedDataPath.children().filter { $0.extension == "xcscheme" } + + for schemePath in schemePaths { + let xcscheme = try XCScheme(path: schemePath) + let schemeMapper = try SchemeMapper(graphType: .workspace(workspaceProvider)) + let scheme = try await schemeMapper.mapScheme(xcscheme: xcscheme, shared: true) + schemes.append(scheme) + } + } + + return schemes + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift new file mode 100644 index 00000000..026fd74e --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift @@ -0,0 +1,32 @@ +import Foundation +import Path +import PathKit +import XcodeGraph +import XcodeProj + +/// A type that provides access to a workspace and its underlying `.xcworkspace` file. +public protocol WorkspaceProviding: Sendable { + /// The absolute path to the workspace file. + var workspaceDirectory: AbsolutePath { get } + var xcWorkspacePath: AbsolutePath { get } + + /// The parsed `XCWorkspace` instance representing the workspace. + var xcworkspace: XCWorkspace { get } +} + +/// A concrete provider for workspaces, offering access to the `.xcworkspace` file and its parsed representation. +public struct WorkspaceProvider: WorkspaceProviding { + public let workspaceDirectory: AbsolutePath +public let xcWorkspacePath: AbsolutePath + public let xcworkspace: XCWorkspace + + /// Initializes a `WorkspaceProvider` with a given workspace path. + /// + /// - Parameter workspacePath: The absolute path to the `.xcworkspace` file. + /// - Throws: If the `.xcworkspace` file cannot be loaded or parsed. + public init(xcWorkspacePath: AbsolutePath) throws { + self.xcWorkspacePath = xcWorkspacePath + self.workspaceDirectory = xcWorkspacePath.parentDirectory + self.xcworkspace = try XCWorkspace(path: Path(xcWorkspacePath.pathString)) + } +} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift b/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift new file mode 100644 index 00000000..3484b683 --- /dev/null +++ b/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift @@ -0,0 +1,59 @@ +import Foundation + +/// Represents an executable command with its arguments, executable path, and a parser for the output. +/// +/// This enum is used to define commands like `lipo` or custom executables, encapsulating the logic +/// for their arguments, path, and output processing. +public enum Executable: Sendable { + /// A `lipo` command, used for managing universal binaries. + /// + /// - Parameters: + /// - arguments: The arguments to pass to `lipo`. + /// - parser: A closure to parse the `ProcessResult` into an `Output`. + /// - executablePath: The path to the `lipo` binary (default: `/usr/bin/lipo`). + case lipo(LipoArguments, @Sendable (ProcessResult) throws -> Output, executablePath: String = "/usr/bin/lipo") + + /// A custom executable command. + /// + /// - Parameters: + /// - executablePath: The path to the custom executable. + /// - arguments: The arguments to pass to the executable. + /// - parser: A closure to parse the `ProcessResult` into an `Output`. + case custom(String, [String], @Sendable (ProcessResult) throws -> Output) + + /// The path to the executable. + /// + /// - Returns: A `String` representing the absolute path to the executable. + public var path: String { + switch self { + case .lipo(_, _, let path): + return path + case .custom(let executablePath, _, _): + return executablePath + } + } + + /// The arguments to pass to the executable. + /// + /// - Returns: An array of `String` arguments. + public var arguments: [String] { + switch self { + case .lipo(let lipoArgs, _, _): + return lipoArgs.toArguments() + case .custom(_, let args, _): + return args + } + } + + /// A parser to convert the `ProcessResult` into the desired `Output` type. + /// + /// - Returns: A closure that takes a `ProcessResult` and returns an `Output` value or throws an error. + public var parser: (ProcessResult) throws -> Output { + switch self { + case .lipo(_, let parser, _): + return parser + case .custom(_, _, let parser): + return parser + } + } +} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArchsResult.swift b/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArchsResult.swift new file mode 100644 index 00000000..6dbd1230 --- /dev/null +++ b/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArchsResult.swift @@ -0,0 +1,38 @@ +import Foundation +@preconcurrency import XcodeGraph + +/// Represents the architectures extracted from running `lipo -archs`. +/// +/// `LipoArchsResult` provides a structured result indicating which architectures +/// are contained in a given binary. It uses `XcodeGraph.BinaryArchitecture` to +/// represent each architecture (e.g., arm64, x86_64). +public struct LipoArchsResult: Sendable { + /// The list of architectures reported by `lipo -archs`. + public let architectures: [XcodeGraph.BinaryArchitecture] +} + +/// Parses the output of a `ProcessResult` from a `lipo -archs` invocation into a `LipoArchsResult`. +/// +/// `lipo -archs` typically returns a single line of whitespace-separated architectures, +/// for example: `"arm64"` or `"arm64 x86_64"`. +/// +/// - Parameter result: The `ProcessResult` obtained from running the `lipo -archs` command. +/// - Returns: A `LipoArchsResult` containing all detected architectures. +/// - Throws: +/// - `ProcessRunnerError.failedToRunProcess` if `lipo` exits with a non-zero code. +/// - Any errors related to decoding or interpreting the output as architectures. +public func parseLipoArchsResult(_ result: ProcessResult) throws -> LipoArchsResult { + // Ensure that the process succeeded. If not, throw an error indicating lipo failed. + guard result.succeeded else { + throw ProcessRunnerError.failedToRunProcess("Lipo returned non-zero exit code.") + } + + // Trim whitespace and split by space to extract architecture identifiers. + let output = result.stdout.trimmingCharacters(in: .whitespacesAndNewlines) + let archs = output.split(separator: " ") + .map(String.init) + .compactMap(BinaryArchitecture.init) + + // Return the parsed architectures encapsulated in a LipoArchsResult. + return LipoArchsResult(architectures: archs) +} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArguments.swift b/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArguments.swift new file mode 100644 index 00000000..f79704aa --- /dev/null +++ b/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArguments.swift @@ -0,0 +1,29 @@ +import Foundation + +public struct LipoArguments: Sendable { + public enum Operation: Sendable { + case archs + + public var command: String { + switch self { + case .archs: + "-archs" + } + } + } + + public let operation: Operation + public let paths: [String] + + public init(operation: Operation, paths: [String]) { + self.operation = operation + self.paths = paths + } + + func toArguments() -> [String] { + var args: [String] = [] + args.append(operation.command) + args.append(contentsOf: paths) + return args + } +} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoTool.swift b/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoTool.swift new file mode 100644 index 00000000..ea490061 --- /dev/null +++ b/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoTool.swift @@ -0,0 +1,36 @@ +import Foundation + +/// A utility class for invoking `lipo` commands and parsing their results. +/// +/// `LipoTool` provides a high-level interface for running `lipo -archs` on given paths +/// to determine which architectures a binary contains. +public final class LipoTool { + /// Runs `lipo -archs` on the given paths and returns a `LipoArchsResult`. + /// + /// This method asynchronously executes `lipo -archs` using `ProcessRunner.run`, + /// then parses the output into a `LipoArchsResult`. The result includes all architectures + /// detected in the provided binary(ies). + /// + /// - Parameters: + /// - paths: An array of file paths to the binary files you want to inspect for architectures. + /// Typically, passing one path is common, but multiple paths can also be provided. + /// - executablePath: The path to the `lipo` executable. Defaults to `/usr/bin/lipo`. + /// + /// - Returns: A `LipoArchsResult` representing the architectures found. + /// + /// - Throws: + /// - `ProcessRunnerError` if there are issues running the `lipo` command or decoding its output. + /// - Any errors thrown by `parseLipoArchsResult` if the output is malformed. + /// + /// - Note: This method is `async` and may suspend. Ensure you're calling it from an asynchronous + /// context or within a `Task`. + @discardableResult + public static func archs( + paths: [String], + executablePath: String = "/usr/bin/lipo" + ) async throws -> LipoArchsResult { + let args = LipoArguments(operation: .archs, paths: paths) + let executable = Executable.lipo(args, parseLipoArchsResult, executablePath: executablePath) + return try await ProcessRunner.run(executable: executable, throwOnNonZeroExit: false) + } +} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/ProcessResult.swift b/Sources/XcodeProjToGraph/ProcessRunner/ProcessResult.swift new file mode 100644 index 00000000..c8167696 --- /dev/null +++ b/Sources/XcodeProjToGraph/ProcessRunner/ProcessResult.swift @@ -0,0 +1,33 @@ +import Foundation + +/// Represents the result of executing a process. +/// +/// This struct encapsulates the process's exit code, standard output, and standard error streams, +/// and provides a convenience property to determine if the process succeeded. +public struct ProcessResult: Sendable, CustomStringConvertible { + /// The exit code of the process. + /// + /// A value of `0` typically indicates success, while non-zero values represent errors. + public let exitCode: Int32 + + /// The standard output of the process as a `String`. + public let stdout: String + + /// The standard error output of the process as a `String`. + public let stderr: String + + /// Indicates whether the process exited successfully. + /// + /// - Returns: `true` if the exit code is `0`, otherwise `false`. + public var succeeded: Bool { + exitCode == 0 + } + + public var description: String { + """ + Exit Code: \(exitCode) + Stdout: \(stdout) + Stderr: \(stderr) + """ + } +} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift new file mode 100644 index 00000000..ffd57376 --- /dev/null +++ b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift @@ -0,0 +1,77 @@ +import Foundation + +public final class ProcessRunner { + /// Runs the given executable asynchronously and processes its result using the associated parser. + /// + /// - Parameters: + /// - executable: An `Executable` that defines the command, arguments, and output parser. + /// - environment: An optional dictionary of environment variables for the process. + /// - workingDirectory: An optional path for the process's working directory. + /// - throwOnNonZeroExit: If `true`, throws an error for non-zero exit codes. Defaults to `true`. + /// - Returns: The structured output parsed from the process's result. + /// - Throws: + /// - `ProcessRunnerError` for issues like non-zero exit codes, invalid UTF-8, or failure to run. + @discardableResult + public static func run( + executable: Executable, + environment: [String: String]? = nil, + workingDirectory: String? = nil, + throwOnNonZeroExit: Bool = true, + fileManager: FileManager = FileManager.default + ) async throws -> T { + let execPath = executable.path + + guard fileManager.isExecutableFile(atPath: execPath) else { + throw ProcessRunnerError.executableNotFound(execPath) + } + + return try await withCheckedThrowingContinuation { continuation in + let process = Process() + process.executableURL = URL(fileURLWithPath: execPath) + process.arguments = executable.arguments + process.environment = environment ?? ProcessInfo.processInfo.environment + if let wd = workingDirectory { + process.currentDirectoryURL = URL(fileURLWithPath: wd) + } + + let stdoutPipe = Pipe() + let stderrPipe = Pipe() + process.standardOutput = stdoutPipe + process.standardError = stderrPipe + + process.terminationHandler = { process in + let stdoutData = stdoutPipe.fileHandleForReading.readDataToEndOfFile() + let stderrData = stderrPipe.fileHandleForReading.readDataToEndOfFile() + + guard + let stdoutString = String(data: stdoutData, encoding: .utf8), + let stderrString = String(data: stderrData, encoding: .utf8) + else { + continuation.resume(throwing: ProcessRunnerError.invalidUTF8InOutput) + return + } + + let exitCode = process.terminationStatus + let result = ProcessResult(exitCode: exitCode, stdout: stdoutString, stderr: stderrString) + + if throwOnNonZeroExit && !result.succeeded { + continuation.resume(throwing: ProcessRunnerError.nonZeroExitCode(exitCode, result.stderr)) + return + } + + do { + let output = try executable.parser(result) + continuation.resume(returning: output) + } catch { + continuation.resume(throwing: error) + } + } + + do { + try process.run() + } catch { + continuation.resume(throwing: ProcessRunnerError.failedToRunProcess(error.localizedDescription)) + } + } + } +} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift new file mode 100644 index 00000000..ec9403c1 --- /dev/null +++ b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift @@ -0,0 +1,21 @@ +import Foundation + +public enum ProcessRunnerError: Error, LocalizedError, Equatable { + case executableNotFound(String) + case failedToRunProcess(String) + case invalidUTF8InOutput + case nonZeroExitCode(Int32, String) + + public var errorDescription: String? { + switch self { + case .executableNotFound(let cmd): + return "The executable '\(cmd)' was not found or is not executable." + case .failedToRunProcess(let reason): + return "Failed to run process: \(reason)" + case .invalidUTF8InOutput: + return "Could not decode output as UTF-8." + case let .nonZeroExitCode(code, stderr): + return "Command exited with code \(code). Stderr: \(stderr)" + } + } +} diff --git a/Sources/XcodeProjToGraph/XcodeProjToGraph.docc/Documentation.md b/Sources/XcodeProjToGraph/XcodeProjToGraph.docc/Documentation.md new file mode 100644 index 00000000..99d62059 --- /dev/null +++ b/Sources/XcodeProjToGraph/XcodeProjToGraph.docc/Documentation.md @@ -0,0 +1,13 @@ +# ``XcodeGraphMapper`` + +Summary + +## Overview + +Text + +## Topics + +### Group + +- ``Symbol`` \ No newline at end of file diff --git a/Tests/XcodeGraphTests/Extensions/XCTestCase+Extras.swift b/Tests/XcodeGraphTests/Extensions/XCTestCase+Extras.swift index 8befa2ce..066cd3e1 100644 --- a/Tests/XcodeGraphTests/Extensions/XCTestCase+Extras.swift +++ b/Tests/XcodeGraphTests/Extensions/XCTestCase+Extras.swift @@ -13,7 +13,7 @@ extension XCTestCase { XCTAssertEqual(subject, decoded, "The subject is not equal to it's encoded & decoded version") } - func XCTTry(_ closure: @autoclosure @escaping () throws -> T, file: StaticString = #file, line: UInt = #line) -> T { + func XCTTry(_ closure: @autoclosure @escaping () throws -> T, file: StaticString = #filePath, line: UInt = #line) -> T { var value: T! do { value = try closure() @@ -26,7 +26,7 @@ extension XCTestCase { func XCTAssertEqualDictionaries( _ first: [T: Any], _ second: [T: Any], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { let firstDictionary = NSDictionary(dictionary: first) diff --git a/Tests/XcodeGraphTests/Models/TargetTests.swift b/Tests/XcodeGraphTests/Models/TargetTests.swift index fb6a9d2c..b0013c02 100644 --- a/Tests/XcodeGraphTests/Models/TargetTests.swift +++ b/Tests/XcodeGraphTests/Models/TargetTests.swift @@ -16,23 +16,7 @@ final class TargetTests: XCTestCase { XCTAssertEqual( Target.validSourceExtensions, [ - "m", - "swift", - "mm", - "cpp", - "c++", - "cc", - "c", - "d", - "s", - "intentdefinition", - "xcmappingmodel", - "metal", - "mlmodel", - "docc", - "playground", - "rcproject", - "mlpackage", + "m", "swift", "mm", "cpp", "c++", "cc", "c", "d", "s", "intentdefinition", "metal", "mlmodel" ] ) } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/IntegrationTests.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/IntegrationTests.swift new file mode 100644 index 00000000..826862bf --- /dev/null +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/IntegrationTests.swift @@ -0,0 +1,198 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProjToGraph +import XcodeProj +import RegexBuilder + +@testable import TestSupport + +struct GraphDependencyTestableMap: Encodable, Comparable { + static func < (lhs: GraphDependencyTestableMap, rhs: GraphDependencyTestableMap) -> Bool { + lhs.key < rhs.key + } + + let key: GraphDependency + let values: [GraphDependency] + + init(key: GraphDependency, values: Set) { + self.key = key + self.values = Array(values).sorted() + } +} + +@Suite( + .snapshots( + // Change this re-recored etc + record: .failed + ) +) +struct IntegrationTests { + func assertGraph( + of fixture: () -> WorkspaceFixture, + name: (() -> String)? = nil, + dependencies: (() -> String)? = nil, + dependencyConditions: (() -> String)? = nil, + packages: (() -> String)? = nil, + workspace: (() -> String)? = nil, + projects: (() -> String)? = nil, + fileID: StaticString = #fileID, + file filePath: StaticString = #filePath, + function: StaticString = #function, + line: UInt = #line, + column: UInt = #column + ) async throws { + + let path = try fixture().absolutePath() + + let fullGraph: XcodeGraph.Graph = try await ProjectParser.parse(atPath: path.pathString) + + let graph = try fullGraph.normalizeGraphPaths().minimizeGraph() + + assertInlineSnapshot( + of: graph.name, + as: .dump, + message: "Dependency Conditions did not match", + syntaxDescriptor: InlineSnapshotSyntaxDescriptor( + trailingClosureLabel: "name", + trailingClosureOffset: 1 + ), + matches: name, + fileID: fileID, + file: filePath, + function: function, + line: line, + column: column + ) + assertInlineSnapshot( + of: graph.dependencies, + as: .dump, + message: "Dependencies did not match", + syntaxDescriptor: InlineSnapshotSyntaxDescriptor( + trailingClosureLabel: "dependencies", + trailingClosureOffset: 2 + ), + matches: dependencies, + fileID: fileID, + file: filePath, + function: function, + line: line, + column: column + ) + assertInlineSnapshot( + of: graph.dependencyConditions, + as: .dump, + message: "Dependency Conditions did not match", + syntaxDescriptor: InlineSnapshotSyntaxDescriptor( + trailingClosureLabel: "dependencyConditions", + trailingClosureOffset: 3 + ), + matches: dependencyConditions, + fileID: fileID, + file: filePath, + function: function, + line: line, + column: column + ) + assertInlineSnapshot( + of: graph.packages, + as: .dump, + message: "Packages did not match", + syntaxDescriptor: InlineSnapshotSyntaxDescriptor( + trailingClosureLabel: "packages", + trailingClosureOffset: 4 + ), + matches: packages, + fileID: fileID, + file: filePath, + function: function, + line: line, + column: column + ) + assertInlineSnapshot( + of: graph.workspace, + as: .dump, + message: "Workspace did not match", + syntaxDescriptor: InlineSnapshotSyntaxDescriptor( + trailingClosureLabel: "workspace", + trailingClosureOffset: 5 + ), + matches: workspace, + fileID: fileID, + file: filePath, + function: function, + line: line, + column: column + ) + assertInlineSnapshot( + of: graph.projects, + as: .dump, + message: "Projects did not match", + syntaxDescriptor: InlineSnapshotSyntaxDescriptor( + trailingClosureLabel: "projects", + trailingClosureOffset: 6 + ), + matches: projects, + fileID: fileID, + file: filePath, + function: function, + line: line, + column: column + ) + } +} + +extension XcodeGraph.Graph { + func normalizeGraphPaths() throws -> XcodeGraph.Graph { + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] + + let data = try encoder.encode(self) + var jsonString = String(decoding: data, as: UTF8.self) + + // Normalize any prefix before /Fixtures. + jsonString = jsonString.replacingOccurrences( + of: #"[^"]*?/Fixtures"#, + with: "/Fixtures", + options: [.regularExpression] + ) + + let decoder = JSONDecoder() + let normalizedGraph = try decoder.decode(XcodeGraph.Graph.self, from: Data(jsonString.utf8)) + + return normalizedGraph + } + + func minimizeGraph() -> Graph { + var graph = self + graph.workspace.schemes = [] + graph.workspace.generationOptions = .test() + + for (key, project) in graph.projects { + graph.projects[key]?.schemes = [] + graph.projects[key]?.resourceSynthesizers = [] + graph.projects[key]?.settings = Settings(configurations: [:]) + + for targetKey in project.targets.keys { + graph.projects[key]?.targets[targetKey]?.scripts = [] + graph.projects[key]?.targets[targetKey]?.playgrounds = [] + graph.projects[key]?.targets[targetKey]?.rawScriptBuildPhases = [] + graph.projects[key]?.targets[targetKey]?.playgrounds = [] + graph.projects[key]?.targets[targetKey]?.buildRules = [] + graph.projects[key]?.targets[targetKey]?.settings = nil + graph.projects[key]?.targets[targetKey]?.infoPlist = nil + graph.projects[key]?.targets[targetKey]?.destinations = [] + } + } + + return graph + } +} + +extension AbsolutePath: @retroactive AnySnapshotStringConvertible { + public var snapshotDescription: String { + return self.pathString + } +} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift new file mode 100644 index 00000000..505e6820 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift @@ -0,0 +1,233 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProjToGraph +import XcodeProj + +@testable import TestSupport + +extension IntegrationTests { + @Test + func commandLineToolWithDynamicFramework() async throws { + try await assertGraph { + .commandLineToolWithDynamicFramework + } name: { + """ + - "CommandLineTool" + + """ + }dependencies: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: target 'CommandLineTool' + ▿ target: (3 elements) + - name: "CommandLineTool" + - path: /Fixtures/command_line_tool_with_dynamic_framework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'DynamicFramework' + ▿ target: (3 elements) + - name: "DynamicFramework" + - path: /Fixtures/command_line_tool_with_dynamic_framework + - status: LinkingStatus.required + + """ + }dependencyConditions: { + """ + - 0 key/value pairs + + """ + }packages: { + """ + - 0 key/value pairs + + """ + }workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "CommandLineTool" + - path: /Fixtures/command_line_tool_with_dynamic_framework + ▿ projects: 1 element + - /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcworkspace + + """ + }projects: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcodeproj + ▿ value: CommandLineTool + - path: /Fixtures/command_line_tool_with_dynamic_framework + - sourceRootPath: /Fixtures/command_line_tool_with_dynamic_framework + - xcodeProjPath: /Fixtures/command_line_tool_with_dynamic_framework + - name: "CommandLineTool" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "CommandLineTool" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "com.example.commandlinetool" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "DynamicFramework" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "CommandLineTool" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: command line tool + - productName: "CommandLineTool" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift + ▿ (2 elements) + - key: "DynamicFramework" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "com.example.dynamicframework" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "DynamicFramework" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "DynamicFramework" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift new file mode 100644 index 00000000..ecaff656 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift @@ -0,0 +1,20 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProjToGraph +import XcodeProj + +@testable import TestSupport + +extension IntegrationTests { + @Test + func iosAppLarge() async throws { + let path = try WorkspaceFixture.iosAppLarge.absolutePath() + + let graph: XcodeGraph.Graph = try await ProjectParser.parse(projectType: .workspace(path)) + + #expect(graph.projects.first?.value.targets.count == 300) + } +} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift new file mode 100644 index 00000000..3d0a2b71 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift @@ -0,0 +1,758 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProjToGraph +import XcodeProj + + +@testable import TestSupport + +extension IntegrationTests { + @Test + func iosAppWithExtensions() async throws { + try await assertGraph { + .iosAppWithExtensions + } name: { + """ + - "App" + + """ + } dependencies: { + """ + ▿ 3 key/value pairs + ▿ (2 elements) + ▿ key: target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ value: 4 members + ▿ target 'AppIntentExtension' + ▿ target: (3 elements) + - name: "AppIntentExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'NotificationServiceExtension' + ▿ target: (3 elements) + - name: "NotificationServiceExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'StickersPackExtension' + ▿ target: (3 elements) + - name: "StickersPackExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'WidgetExtension' + ▿ target: (3 elements) + - name: "WidgetExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'AppWithMessagesExtension' + ▿ target: (3 elements) + - name: "AppWithMessagesExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ value: 2 members + ▿ target 'MessageExtension' + ▿ target: (3 elements) + - name: "MessageExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'NotificationServiceExtension' + ▿ target: (3 elements) + - name: "NotificationServiceExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'WidgetExtension' + ▿ target: (3 elements) + - name: "WidgetExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ value: 2 members + ▿ target 'Bundle' + ▿ target: (3 elements) + - name: "Bundle" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'StaticFramework' + ▿ target: (3 elements) + - name: "StaticFramework" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + + """ + }dependencyConditions: { + """ + - 0 key/value pairs + + """ + } packages: { + """ + - 0 key/value pairs + + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "App" + - path: /Fixtures/ios_app_with_extensions + ▿ projects: 1 element + - /Fixtures/ios_app_with_extensions/App.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_extensions/App.xcworkspace + + """ + }projects: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/ios_app_with_extensions/App.xcodeproj + ▿ value: App + - path: /Fixtures/ios_app_with_extensions + - sourceRootPath: /Fixtures/ios_app_with_extensions + - xcodeProjPath: /Fixtures/ios_app_with_extensions + - name: "App" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 9 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 3 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Embed ExtensionKit Extensions" + ▿ subpath: Optional + - some: "$(EXTENSIONS_FOLDER_PATH)" + ▿ CopyFilesAction + - destination: Destination.plugins + - files: 0 elements + - name: "Embed Foundation Extensions" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 4 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "AppIntentExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "NotificationServiceExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "StickersPackExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "WidgetExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ (2 elements) + - key: "AppIntentExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.AppIntentExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppIntentExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: extensionKit extension + - productName: "AppIntentExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ (2 elements) + - key: "AppWithMessagesExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App2" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.plugins + - files: 0 elements + - name: "Embed Foundation Extensions" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "MessageExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "NotificationServiceExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppWithMessagesExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "AppWithMessagesExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ (2 elements) + - key: "Bundle" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.Bundle" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Bundle" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: bundle + - productName: "Bundle" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + - sources: 0 elements + ▿ (2 elements) + - key: "MessageExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App2.MessageExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "MessageExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: iMessage extension + - productName: "MessageExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 2 elements + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 3 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ (2 elements) + - key: "NotificationServiceExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.NotificationServiceExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "NotificationServiceExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: app extension + - productName: "NotificationServiceExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ (2 elements) + - key: "StaticFramework" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.StaticFramework" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticFramework" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "StaticFramework" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ (2 elements) + - key: "StickersPackExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.StickersPackExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StickersPackExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: sticker pack extension + - productName: "StickersPackExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + - sources: 0 elements + ▿ (2 elements) + - key: "WidgetExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.WidgetExtension" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Bundle" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "StaticFramework" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "WidgetExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: app extension + - productName: "WidgetExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 3 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift new file mode 100644 index 00000000..0a9b6eca --- /dev/null +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift @@ -0,0 +1,563 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProjToGraph +import XcodeProj + +@testable import TestSupport + +extension IntegrationTests { + @Test + func iosAppWithMultiConfigs() async throws { + try await assertGraph { + .iosAppWithMultiConfigs + } name: { + """ + - "Workspace" + + """ + }dependencies: { + """ + ▿ 3 key/value pairs + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_multi_configs/App + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_multi_configs/App + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1Tests' + ▿ target: (3 elements) + - name: "Framework1Tests" + - path: /Fixtures/ios_app_with_multi_configs/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Framework1' + ▿ target: (3 elements) + - name: "Framework1" + - path: /Fixtures/ios_app_with_multi_configs/Framework1 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework2Tests' + ▿ target: (3 elements) + - name: "Framework2Tests" + - path: /Fixtures/ios_app_with_multi_configs/Framework2 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Framework2' + ▿ target: (3 elements) + - name: "Framework2" + - path: /Fixtures/ios_app_with_multi_configs/Framework2 + - status: LinkingStatus.required + + """ + }dependencyConditions: { + """ + - 0 key/value pairs + + """ + }packages: { + """ + - 0 key/value pairs + + """ + }workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "Workspace" + - path: /Fixtures/ios_app_with_multi_configs + ▿ projects: 3 elements + - /Fixtures/ios_app_with_multi_configs/App/MainApp.xcodeproj + - /Fixtures/ios_app_with_multi_configs/Framework1/Framework1.xcodeproj + - /Fixtures/ios_app_with_multi_configs/Framework2/Framework2.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_multi_configs/Workspace.xcworkspace + + """ + }projects: { + """ + ▿ 3 key/value pairs + ▿ (2 elements) + - key: /Fixtures/ios_app_with_multi_configs/App/MainApp.xcodeproj + ▿ value: MainApp + - path: /Fixtures/ios_app_with_multi_configs/App + - sourceRootPath: /Fixtures/ios_app_with_multi_configs/App + - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/App + - name: "MainApp" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.AppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_app_with_multi_configs/Framework1/Framework1.xcodeproj + ▿ value: Framework1 + - path: /Fixtures/ios_app_with_multi_configs/Framework1 + - sourceRootPath: /Fixtures/ios_app_with_multi_configs/Framework1 + - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/Framework1 + - name: "Framework1" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "Framework1" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Framework1" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift + ▿ (2 elements) + - key: "Framework1Tests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Framework1" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1Tests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "Framework1Tests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_app_with_multi_configs/Framework2/Framework2.xcodeproj + ▿ value: Framework2 + - path: /Fixtures/ios_app_with_multi_configs/Framework2 + - sourceRootPath: /Fixtures/ios_app_with_multi_configs/Framework2 + - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/Framework2 + - name: "Framework2" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "Framework2" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework2" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework2" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Framework2" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift + ▿ (2 elements) + - key: "Framework2Tests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework2Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Framework2" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework2Tests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "Framework2Tests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift new file mode 100644 index 00000000..d1b9cf61 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift @@ -0,0 +1,256 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProjToGraph +import XcodeProj + +@testable import TestSupport + +extension IntegrationTests { + @Test + func projectNoWorkspace() async throws { + let path = try WorkspaceFixture.iosAppWithRemoteSwiftPackage.absolutePath() + let graph: XcodeGraph.Graph = try await ProjectParser.parse(projectType: .xcodeProject(path)) + + try #require(graph != nil) + } + + @Test + func iosAppWithRemoteSwiftPackage() async throws { + try await assertGraph { + .iosAppWithRemoteSwiftPackage + } name: { + """ + - "App" + + """ + }dependencies: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_remote_swift_package + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_remote_swift_package + - status: LinkingStatus.required + + """ + }dependencyConditions: { + """ + - 0 key/value pairs + + """ + }packages: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj + ▿ value: 1 key/value pair + ▿ (2 elements) + - key: "https://github.com/ReactiveX/RxSwift" + ▿ value: Package + ▿ remote: (2 elements) + - url: "https://github.com/ReactiveX/RxSwift" + ▿ requirement: Requirement + - upToNextMajor: "5.0.0" + + """ + }workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "App" + - path: /Fixtures/ios_app_with_remote_swift_package + ▿ projects: 1 element + - /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_remote_swift_package/App.xcworkspace + + """ + }projects: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj + ▿ value: App + - path: /Fixtures/ios_app_with_remote_swift_package + - sourceRootPath: /Fixtures/ios_app_with_remote_swift_package + - xcodeProjPath: /Fixtures/ios_app_with_remote_swift_package + - name: "App" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.AppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift + ▿ packages: 1 element + ▿ Package + ▿ remote: (2 elements) + - url: "https://github.com/ReactiveX/RxSwift" + ▿ requirement: Requirement + - upToNextMajor: "5.0.0" + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift new file mode 100644 index 00000000..368ea659 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift @@ -0,0 +1,275 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProjToGraph +import XcodeProj + +@testable import TestSupport + +extension IntegrationTests { + @Test + func iosAppWithSpmDependencies() async throws { + try await assertGraph { + .iosAppWithSpmDependencies + } name: { + """ + - "App" + + """ + }dependencies: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_spm_dependencies + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_spm_dependencies + - status: LinkingStatus.required + + """ + }dependencyConditions: { + """ + - 0 key/value pairs + + """ + }packages: { + """ + - 0 key/value pairs + + """ + }workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "App" + - path: /Fixtures/ios_app_with_spm_dependencies + ▿ projects: 8 elements + - /Fixtures/ios_app_with_spm_dependencies/App.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/BigInt/BigInt.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/KSCrash/KSCrash.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/Mobile Buy SDK/Mobile Buy SDK.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/jwt-kit/jwt-kit.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/swift-asn1/swift-asn1.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/swift-certificates/swift-certificates.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/swift-crypto/swift-crypto.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_spm_dependencies/App.xcworkspace + + """ + }projects: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/ios_app_with_spm_dependencies/App.xcodeproj + ▿ value: App + - path: /Fixtures/ios_app_with_spm_dependencies + - sourceRootPath: /Fixtures/ios_app_with_spm_dependencies + - xcodeProjPath: /Fixtures/ios_app_with_spm_dependencies + - name: "App" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.app" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + ▿ iOS: Optional + - some: "16.0" + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 2 elements + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 4 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_spm_dependencies/Derived/Sources/TuistAssets+App.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_spm_dependencies/Derived/Sources/TuistBundle+App.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.app.tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + ▿ iOS: Optional + - some: "16.0" + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift new file mode 100644 index 00000000..df3e7c49 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift @@ -0,0 +1,605 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProjToGraph +import XcodeProj + +@testable import TestSupport + +extension IntegrationTests { + @Test + func iosAppWithStaticLibraries() async throws { + try await assertGraph { + .iosAppWithStaticLibraries + } name: { + """ + - "iOSAppWithTransistiveStaticLibraries" + + """ + }dependencies: { + """ + ▿ 4 key/value pairs + ▿ (2 elements) + ▿ key: target 'ATests' + ▿ target: (3 elements) + - name: "ATests" + - path: /Fixtures/ios_app_with_static_libraries/Modules/A + - status: LinkingStatus.required + ▿ value: 2 members + ▿ library 'libC.a' + ▿ library: (5 elements) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C + - linking: BinaryLinking.static + ▿ architectures: 2 elements + - BinaryArchitecture.x8664 + - BinaryArchitecture.arm64 + - swiftModuleMap: Optional.none + ▿ target 'A' + ▿ target: (3 elements) + - name: "A" + - path: /Fixtures/ios_app_with_static_libraries/Modules/A + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_static_libraries + - status: LinkingStatus.required + ▿ value: 1 member + ▿ library 'libC.a' + ▿ library: (5 elements) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C + - linking: BinaryLinking.static + ▿ architectures: 2 elements + - BinaryArchitecture.x8664 + - BinaryArchitecture.arm64 + - swiftModuleMap: Optional.none + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_static_libraries + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_static_libraries + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'BTests' + ▿ target: (3 elements) + - name: "BTests" + - path: /Fixtures/ios_app_with_static_libraries/Modules/B + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'B' + ▿ target: (3 elements) + - name: "B" + - path: /Fixtures/ios_app_with_static_libraries/Modules/B + - status: LinkingStatus.required + + """ + }dependencyConditions: { + """ + - 0 key/value pairs + + """ + }packages: { + """ + - 0 key/value pairs + + """ + }workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "iOSAppWithTransistiveStaticLibraries" + - path: /Fixtures/ios_app_with_static_libraries + ▿ projects: 3 elements + - /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcodeproj + - /Fixtures/ios_app_with_static_libraries/Modules/A/A.xcodeproj + - /Fixtures/ios_app_with_static_libraries/Modules/B/B.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcworkspace + + """ + }projects: { + """ + ▿ 3 key/value pairs + ▿ (2 elements) + - key: /Fixtures/ios_app_with_static_libraries/Modules/A/A.xcodeproj + ▿ value: A + - path: /Fixtures/ios_app_with_static_libraries/Modules/A + - sourceRootPath: /Fixtures/ios_app_with_static_libraries/Modules/A + - xcodeProjPath: /Fixtures/ios_app_with_static_libraries/Modules/A + - name: "A" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "A" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.A" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "A" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: static library + - productName: "A" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift + ▿ (2 elements) + - key: "ATests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.ATests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "A" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ library: (4 elements) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C + - swiftModuleMap: Optional.none + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "ATests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "ATests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_app_with_static_libraries/Modules/B/B.xcodeproj + ▿ value: B + - path: /Fixtures/ios_app_with_static_libraries/Modules/B + - sourceRootPath: /Fixtures/ios_app_with_static_libraries/Modules/B + - xcodeProjPath: /Fixtures/ios_app_with_static_libraries/Modules/B + - name: "B" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "B" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.B" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "B" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: static library + - productName: "B" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift + ▿ (2 elements) + - key: "BTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.BTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "B" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "BTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "BTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcodeproj + ▿ value: iOSAppWithTransistiveStaticLibraries + - path: /Fixtures/ios_app_with_static_libraries + - sourceRootPath: /Fixtures/ios_app_with_static_libraries + - xcodeProjPath: /Fixtures/ios_app_with_static_libraries + - name: "iOSAppWithTransistiveStaticLibraries" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ library: (4 elements) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C + - swiftModuleMap: Optional.none + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.AppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift new file mode 100644 index 00000000..5822bc1d --- /dev/null +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift @@ -0,0 +1,1084 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProjToGraph +import XcodeProj + +@testable import TestSupport + +extension IntegrationTests { + @Test + func iosWorkspaceWithMicrofeatureArchitectureStaticLinking() async throws { + try await assertGraph { + .iosWorkspaceWithMicrofeatureArchitectureStaticLinking + } name: { + """ + - "Workspace" + + """ + }dependencies: { + """ + ▿ 6 key/value pairs + ▿ (2 elements) + ▿ key: target 'CoreTests' + ▿ target: (3 elements) + - name: "CoreTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Core' + ▿ target: (3 elements) + - name: "Core" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'DataTests' + ▿ target: (3 elements) + - name: "DataTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Data' + ▿ target: (3 elements) + - name: "Data" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'FeatureContractsTests' + ▿ target: (3 elements) + - name: "FeatureContractsTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'FeatureContracts' + ▿ target: (3 elements) + - name: "FeatureContracts" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'FrameworkATests' + ▿ target: (3 elements) + - name: "FrameworkATests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'FrameworkA' + ▿ target: (3 elements) + - name: "FrameworkA" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'StaticAppTests' + ▿ target: (3 elements) + - name: "StaticAppTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'StaticApp' + ▿ target: (3 elements) + - name: "StaticApp" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'UIComponentsTests' + ▿ target: (3 elements) + - name: "UIComponentsTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'UIComponents' + ▿ target: (3 elements) + - name: "UIComponents" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - status: LinkingStatus.required + + """ + }dependencyConditions: { + """ + - 0 key/value pairs + + """ + }packages: { + """ + - 0 key/value pairs + + """ + }workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "Workspace" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking + ▿ projects: 6 elements + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Core.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Data.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/FrameworkA.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/FeatureContracts.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/UIComponents.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/StaticApp.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.xcworkspace + + """ + }projects: { + """ + ▿ 6 key/value pairs + ▿ (2 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Core.xcodeproj + ▿ value: Core + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - name: "Core" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "Core" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Core" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Core" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Core" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift + ▿ (2 elements) + - key: "CoreTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.CoreTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Core" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "CoreTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "CoreTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Data.xcodeproj + ▿ value: Data + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - name: "Data" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "Data" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Data" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Data" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Data" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift + ▿ (2 elements) + - key: "DataTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.DataFrameworkTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Data" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "DataTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "DataTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/FrameworkA.xcodeproj + ▿ value: FrameworkA + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - name: "FrameworkA" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "FrameworkA" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.FrameworkA" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "FrameworkA" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "FrameworkA" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift + ▿ (2 elements) + - key: "FrameworkATests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.FrameworkATests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "FrameworkA" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "FrameworkATests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "FrameworkATests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/FeatureContracts.xcodeproj + ▿ value: FeatureContracts + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - name: "FeatureContracts" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "FeatureContracts" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.FeatureContracts" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "FeatureContracts" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "FeatureContracts" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift + ▿ (2 elements) + - key: "FeatureContractsTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.FeatureContractsTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "FeatureContracts" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "FeatureContractsTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "FeatureContractsTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/UIComponents.xcodeproj + ▿ value: UIComponents + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - name: "UIComponents" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "UIComponents" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.UIComponents" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "UIComponents" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "UIComponents" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift + ▿ (2 elements) + - key: "UIComponentsTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.UIComponentsTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "UIComponents" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "UIComponentsTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "UIComponentsTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/StaticApp.xcodeproj + ▿ value: StaticApp + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - name: "StaticApp" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "StaticApp" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.StaticApp" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticApp" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "StaticApp" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "StaticAppTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.StaticAppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "StaticApp" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticAppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "StaticAppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift new file mode 100644 index 00000000..604cd690 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift @@ -0,0 +1,836 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProjToGraph +import XcodeProj +@testable import TestSupport + +extension IntegrationTests { + @Test + func ios_app_with_transitive_framework() async throws { + try await assertGraph { + .ios_app_with_transitive_framework + } name: { + """ + - "Workspace" + + """ + }dependencies: { + """ + ▿ 8 key/value pairs + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_transitive_framework/App + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_transitive_framework/App + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'AppUITests' + ▿ target: (3 elements) + - name: "AppUITests" + - path: /Fixtures/ios_app_with_transitive_framework/App + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_transitive_framework/App + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1-iOS' + ▿ target: (3 elements) + - name: "Framework1-iOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ framework 'Framework2.framework' + ▿ framework: (7 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 + - dsymPath: Optional.none + - bcsymbolmapPaths: 0 elements + - linking: BinaryLinking.dynamic + ▿ architectures: 2 elements + - BinaryArchitecture.x8664 + - BinaryArchitecture.arm64 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1-macOS' + ▿ target: (3 elements) + - name: "Framework1-macOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ framework 'Framework2.framework' + ▿ framework: (7 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework + - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Framework2 + - dsymPath: Optional.none + - bcsymbolmapPaths: 0 elements + - linking: BinaryLinking.dynamic + ▿ architectures: 1 element + - BinaryArchitecture.arm64 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1Tests-iOS' + ▿ target: (3 elements) + - name: "Framework1Tests-iOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Framework1-iOS' + ▿ target: (3 elements) + - name: "Framework1-iOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1Tests-macOS' + ▿ target: (3 elements) + - name: "Framework1Tests-macOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Framework1-macOS' + ▿ target: (3 elements) + - name: "Framework1-macOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'StaticFramework1' + ▿ target: (3 elements) + - name: "StaticFramework1" + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ framework 'Framework2.framework' + ▿ framework: (7 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 + - dsymPath: Optional.none + - bcsymbolmapPaths: 0 elements + - linking: BinaryLinking.dynamic + ▿ architectures: 2 elements + - BinaryArchitecture.x8664 + - BinaryArchitecture.arm64 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'StaticFramework1Tests' + ▿ target: (3 elements) + - name: "StaticFramework1Tests" + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - status: LinkingStatus.required + ▿ value: 2 members + ▿ framework 'Framework2.framework' + ▿ framework: (7 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 + - dsymPath: Optional.none + - bcsymbolmapPaths: 0 elements + - linking: BinaryLinking.dynamic + ▿ architectures: 2 elements + - BinaryArchitecture.x8664 + - BinaryArchitecture.arm64 + - status: LinkingStatus.required + ▿ target 'StaticFramework1' + ▿ target: (3 elements) + - name: "StaticFramework1" + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - status: LinkingStatus.required + + """ + }dependencyConditions: { + """ + - 0 key/value pairs + + """ + }packages: { + """ + - 0 key/value pairs + + """ + }workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "Workspace" + - path: /Fixtures/ios_app_with_transitive_framework + ▿ projects: 3 elements + - /Fixtures/ios_app_with_transitive_framework/App/MainApp.xcodeproj + - /Fixtures/ios_app_with_transitive_framework/Framework1/Framework1.xcodeproj + - /Fixtures/ios_app_with_transitive_framework/StaticFramework1/StaticFramework1.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_transitive_framework/Workspace.xcworkspace + + """ + }projects: { + """ + ▿ 3 key/value pairs + ▿ (2 elements) + - key: /Fixtures/ios_app_with_transitive_framework/App/MainApp.xcodeproj + ▿ value: MainApp + - path: /Fixtures/ios_app_with_transitive_framework/App + - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/App + - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/App + - name: "MainApp" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 3 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.AppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift + ▿ (2 elements) + - key: "AppUITests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.AppUITests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppUITests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: ui tests + - productName: "AppUITests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_app_with_transitive_framework/Framework1/Framework1.xcodeproj + ▿ value: Framework1 + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/Framework1 + - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/Framework1 + - name: "Framework1" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 4 key/value pairs + ▿ (2 elements) + - key: "Framework1-iOS" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ framework: (3 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1-iOS" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Framework1" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift + ▿ (2 elements) + - key: "Framework1-macOS" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ framework: (3 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1-macOS" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Framework1" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift + ▿ (2 elements) + - key: "Framework1Tests-iOS" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Framework1-iOS" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1Tests-iOS" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "Framework1Tests_iOS" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift + ▿ (2 elements) + - key: "Framework1Tests-macOS" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Framework1-macOS" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1Tests-macOS" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "Framework1Tests_macOS" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/StaticFramework1.xcodeproj + ▿ value: StaticFramework1 + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - name: "StaticFramework1" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "StaticFramework1" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.StaticFramework1" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ framework: (3 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticFramework1" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "StaticFramework1" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift + ▿ (2 elements) + - key: "StaticFramework1Tests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.StaticFramework1Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ framework: (3 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "StaticFramework1" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticFramework1Tests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "StaticFramework1Tests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift new file mode 100644 index 00000000..23625f51 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift @@ -0,0 +1,239 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProjToGraph +import XcodeProj + +@testable import TestSupport + +extension IntegrationTests { + @Test + func macosAppWithSystemExtension() async throws { + try await assertGraph { + .macosAppWithSystemExtension + } name: { + """ + - "App with SystemExtension" + + """ + }dependencies: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: target 'MainApp' + ▿ target: (3 elements) + - name: "MainApp" + - path: /Fixtures/macos_app_with_system_extension + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'SystemExtension' + ▿ target: (3 elements) + - name: "SystemExtension" + - path: /Fixtures/macos_app_with_system_extension + - status: LinkingStatus.required + + """ + }dependencyConditions: { + """ + - 0 key/value pairs + + """ + }packages: { + """ + - 0 key/value pairs + + """ + }workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "App with SystemExtension" + - path: /Fixtures/macos_app_with_system_extension + ▿ projects: 1 element + - /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcworkspace + + """ + }projects: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcodeproj + ▿ value: App with SystemExtension + - path: /Fixtures/macos_app_with_system_extension + - sourceRootPath: /Fixtures/macos_app_with_system_extension + - xcodeProjPath: /Fixtures/macos_app_with_system_extension + - name: "App with SystemExtension" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "MainApp" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.MainApp" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Embed System Extensions" + ▿ subpath: Optional + - some: "$(CONTENTS_FOLDER_PATH)/Library/SystemExtensions" + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "SystemExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "MainApp" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "MainApp" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift + ▿ (2 elements) + - key: "SystemExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.SystemExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "SystemExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: system extension + - productName: "SystemExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift new file mode 100644 index 00000000..e1ee0d99 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift @@ -0,0 +1,598 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProjToGraph +import XcodeProj + +@testable import TestSupport + +extension IntegrationTests { + @Test + func multiplatformAppWithMacrosAndEmbeddedWatchosApp() async throws { + try await assertGraph { + .multiplatformAppWithMacrosAndEmbeddedWatchosApp + } name: { + """ + - "AppWithWatchApp" + + """ + }dependencies: { + """ + ▿ 4 key/value pairs + ▿ (2 elements) + ▿ key: target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ value: 2 members + ▿ target 'ModuleA' + ▿ target: (3 elements) + - name: "ModuleA" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ target 'WatchApp' + ▿ target: (3 elements) + - name: "WatchApp" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'ModuleA' + ▿ target: (3 elements) + - name: "ModuleA" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'ModuleAMacros' + ▿ target: (3 elements) + - name: "ModuleAMacros" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'ModuleATests' + ▿ target: (3 elements) + - name: "ModuleATests" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ value: 2 members + ▿ target 'ModuleA' + ▿ target: (3 elements) + - name: "ModuleA" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ target 'ModuleAMacros_Testable' + ▿ target: (3 elements) + - name: "ModuleAMacros_Testable" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'WatchApp' + ▿ target: (3 elements) + - name: "WatchApp" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'ModuleA' + ▿ target: (3 elements) + - name: "ModuleA" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + + """ + }dependencyConditions: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: GraphEdge + ▿ from: target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ to: target 'WatchApp' + ▿ target: (3 elements) + - name: "WatchApp" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ value: PlatformCondition + ▿ platformFilters: 1 member + - PlatformFilter.ios + + """ + }packages: { + """ + - 0 key/value pairs + + """ + }workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "AppWithWatchApp" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + ▿ projects: 4 elements + - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp.xcodeproj + - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/.build/tuist-derived/swift-case-paths/swift-case-paths.xcodeproj + - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/.build/tuist-derived/swift-syntax/swift-syntax.xcodeproj + - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/.build/tuist-derived/xctest-dynamic-overlay/xctest-dynamic-overlay.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp.xcworkspace + + """ + }projects: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp.xcodeproj + ▿ value: AppWithWatchApp + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - sourceRootPath: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - xcodeProjPath: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - name: "AppWithWatchApp" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 6 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Embed Watch Content" + ▿ subpath: Optional + - some: "$(CONTENTS_FOLDER_PATH)/Watch" + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "ModuleA" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "WatchApp" + - status: LinkingStatus.required + ▿ condition: Optional + ▿ some: PlatformCondition + ▿ platformFilters: 1 member + - PlatformFilter.ios + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 4 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift + ▿ (2 elements) + - key: "ModuleA" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.modulea" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "ModuleAMacros" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "ModuleA" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "ModuleA" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift + ▿ (2 elements) + - key: "ModuleAMacros" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.moduleamacros" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + ▿ macOS: Optional + - some: "14.0" + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "ModuleAMacros" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: command line tool + - productName: "ModuleAMacros" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift + ▿ (2 elements) + - key: "ModuleAMacros_Testable" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.moduleamacros.testable" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "ModuleAMacros_Testable" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "ModuleAMacros_Testable" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift + ▿ (2 elements) + - key: "ModuleATests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.moduleatests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "ModuleA" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "ModuleAMacros_Testable" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "ModuleATests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "ModuleATests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift + ▿ (2 elements) + - key: "WatchApp" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.watchkitapp" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "ModuleA" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "WatchApp" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "WatchApp" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 5 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift new file mode 100644 index 00000000..3985feab --- /dev/null +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift @@ -0,0 +1,581 @@ +import Testing +import XcodeGraph +import XcodeProj + +@testable import TestSupport +@testable import XcodeProjToGraph + +struct BuildPhaseMapperTests { + @Test func testMapSources() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let fileRef = PBXFileReference.mock( + sourceTree: .group, + name: "main.swift", + path: "main.swift", + pbxProj: pbxProj + ) + + let buildFile = PBXBuildFile.mock( + file: fileRef, settings: ["COMPILER_FLAGS": "-DDEBUG"], pbxProj: pbxProj) + let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [sourcesPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let sources = try await mapper.mapSources(target: target) + + #expect(sources.count == 1) + let sourceFile = sources.first + try #require(sourceFile != nil) + #expect(sourceFile?.path.basename == "main.swift") + #expect(sourceFile?.compilerFlags == "-DDEBUG") + } + + @Test func testMapResources() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let assetRef = PBXFileReference.mock( + sourceTree: .group, + name: "Assets.xcassets", + path: "Assets.xcassets", + pbxProj: pbxProj + ) + + let buildFile = PBXBuildFile.mock(file: assetRef, pbxProj: pbxProj) + let resourcesPhase = PBXResourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [resourcesPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let resources = try await mapper.mapResources(target: target) + #expect(resources.count == 1) + let resource = resources.first + try #require(resource != nil) + switch resource! { + case .file(let path, _, _): + #expect(path.basename == "Assets.xcassets") + default: + Issue.record("Expected a file resource.") + } + } + + @Test func testMapFrameworks() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Create a framework file reference + let frameworkRef = PBXFileReference.mock( + sourceTree: .group, + name: "MyFramework.framework", + path: "Frameworks/MyFramework.framework", + pbxProj: pbxProj + ) + + let frameworkBuildFile = PBXBuildFile.mock(file: frameworkRef, pbxProj: pbxProj) + let frameworksPhase = PBXFrameworksBuildPhase.mock( + files: [frameworkBuildFile], pbxProj: pbxProj) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [frameworksPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let frameworks = try await mapper.mapFrameworks(target: target) + #expect(frameworks.count == 1) + let dependency = frameworks.first + try #require(dependency != nil) + #expect(dependency?.name == "MyFramework") + } + + @Test func testMapHeaders() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Public header + let publicHeaderRef = PBXFileReference.mock( + name: "PublicHeader.h", + path: "Include/PublicHeader.h", + pbxProj: pbxProj + ) + let publicBuildFile = PBXBuildFile.mock( + file: publicHeaderRef, settings: ["ATTRIBUTES": ["Public"]], pbxProj: pbxProj) + + // Private header + let privateHeaderRef = PBXFileReference.mock( + name: "PrivateHeader.h", + path: "Include/PrivateHeader.h", + pbxProj: pbxProj + ) + let privateBuildFile = PBXBuildFile.mock( + file: privateHeaderRef, settings: ["ATTRIBUTES": ["Private"]], pbxProj: pbxProj) + + // Project header (no attributes) + let projectHeaderRef = PBXFileReference.mock( + name: "ProjectHeader.h", + path: "Include/ProjectHeader.h", + pbxProj: pbxProj + ) + let projectBuildFile = PBXBuildFile.mock(file: projectHeaderRef, pbxProj: pbxProj) + + let headersPhase = PBXHeadersBuildPhase( + files: [publicBuildFile, privateBuildFile, projectBuildFile], + buildActionMask: PBXBuildPhase.defaultBuildActionMask, + runOnlyForDeploymentPostprocessing: false + ) + pbxProj.add(object: headersPhase) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [headersPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let headers = try await mapper.mapHeaders(target: target) + try #require(headers != nil) + #expect(headers?.public.map(\.basename).contains("PublicHeader.h") == true) + #expect(headers?.private.map(\.basename).contains("PrivateHeader.h") == true) + #expect(headers?.project.map(\.basename).contains("ProjectHeader.h") == true) + } + + @Test func testMapScripts() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let scriptPhase = PBXShellScriptBuildPhase.mock( + name: "Run Script", + shellScript: "echo Hello", + inputPaths: ["$(SRCROOT)/input.txt"], + outputPaths: ["$(DERIVED_FILE_DIR)/output.txt"], + pbxProj: pbxProj + ) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [scriptPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let scripts = try await mapper.mapScripts(target: target) + #expect(scripts.count == 1) + let script = scripts.first + try #require(script != nil) + #expect(script?.name == "Run Script") + #expect(script?.script == .embedded("echo Hello")) + #expect(script?.inputPaths == ["$(SRCROOT)/input.txt"]) + #expect(script?.outputPaths == ["$(DERIVED_FILE_DIR)/output.txt"]) + } + + @Test func testMapCopyFiles() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let fileRef = PBXFileReference.mock( + sourceTree: .group, + name: "MyLibrary.dylib", + path: "MyLibrary.dylib", + pbxProj: pbxProj + ) + // Setting an attribute for code sign on copy + let buildFile = PBXBuildFile.mock( + file: fileRef, settings: ["ATTRIBUTES": ["CodeSignOnCopy"]], pbxProj: pbxProj) + + let copyFilesPhase = PBXCopyFilesBuildPhase.mock( + name: "Embed Libraries", + dstPath: "Libraries", + dstSubfolderSpec: .frameworks, + files: [buildFile], + pbxProj: pbxProj + ) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [copyFilesPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let copyActions = try await mapper.mapCopyFiles(target: target) + #expect(copyActions.count == 1) + let action = copyActions.first + try #require(action != nil) + #expect(action?.name == "Embed Libraries") + #expect(action?.destination == .frameworks) + #expect(action?.subpath == "Libraries") + #expect(action?.files.count == 1) + let fileAction = action?.files.first + try #require(fileAction != nil) + #expect(fileAction?.codeSignOnCopy == true) + #expect(fileAction?.path.basename == "MyLibrary.dylib") + } + + @Test func testMapCoreDataModels() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Create a core data model version group + let versionChildRef = PBXFileReference.mock( + name: "Model.xcdatamodel", path: "Model.xcdatamodel", pbxProj: pbxProj) + + let versionGroup = XCVersionGroup.mock( + currentVersion: versionChildRef, + children: [versionChildRef], + path: "Model.xcdatamodeld", + sourceTree: .group, + versionGroupType: "wrapper.xcdatamodel", + name: "Model.xcdatamodeld", + pbxProj: pbxProj + ) + + let buildFile = PBXBuildFile.mock(file: versionGroup, pbxProj: pbxProj) + let resourcesPhase = PBXResourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [resourcesPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let models = try await mapper.mapCoreDataModels(target: target) + #expect(models.count == 1) + let model = models.first + try #require(model != nil) + #expect(model?.path.basename == "Model.xcdatamodeld") + #expect(model?.versions.count == 1) + #expect(model?.currentVersion.contains("Model.xcdatamodel") == true) + } + + @Test func testMapRawScriptBuildPhases() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let frameworksPhase = PBXShellScriptBuildPhase.mock(name: "Test Script", pbxProj: pbxProj) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [frameworksPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let rawPhases = try await mapper.mapRawScriptBuildPhases(target: target) + #expect(rawPhases.count == 1) + let rawPhase = rawPhases.first + try #require(rawPhase != nil) + #expect(rawPhase?.name == "Test Script") + } + + @Test func testMapAdditionalFiles() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Add files to main group that are not referenced by any build phase + if let project = pbxProj.projects.first, + let mainGroup = project.mainGroup + { + let fileRef1 = PBXFileReference.mock(name: "Extra1.txt", path: "Extra1.txt", pbxProj: pbxProj) + let fileRef2 = PBXFileReference.mock( + name: "Extra2.json", path: "Extra2.json", pbxProj: pbxProj) + mainGroup.children.append(fileRef1) + mainGroup.children.append(fileRef2) + } + + // Create a target that doesn't reference these files in build phases + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let additionalFiles = try await mapper.mapAdditionalFiles(target: target) + #expect(additionalFiles.count == 2) + let names = additionalFiles.map { $0.path.basename } + #expect(names.contains("Extra1.txt") == true) + #expect(names.contains("Extra2.json") == true) + } + + @Test func testMapSourceFile_missingFileRef() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Create a build file with no file reference + let buildFile = PBXBuildFile() + // E.g. don't set `file` property, or fileRef is nil by default in your mock initializer. + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let _ = try await mapper.mapSources( + target: PBXNativeTarget.mock(buildPhases: [], pbxProj: pbxProj)) + // Since no sources phase or buildFile with a fileRef is provided, add one manually: + // Actually, let's simulate calling mapSourceFile directly if possible: + // If it's private, we can create a scenario where mapSources includes that buildFile. + // Create a sources phase to include this buildFile + let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + let target = PBXNativeTarget.mock(buildPhases: [sourcesPhase], pbxProj: pbxProj) + + let sources = try await mapper.mapSources(target: target) + // Expect no crash and empty array since fileRef is nil + #expect(sources.isEmpty == true) + } + + @Test func testMapSourceFile_unresolvableFullPath() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/invalid/Path", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let fileRef = PBXFileReference( + name: "NonExistent.swift", + path: "NonExistent.swift" + // This path won't exist relative to /invalid/Path + ) + let buildFile = PBXBuildFile.mock(file: fileRef, pbxProj: pbxProj) + let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + let target = PBXNativeTarget.mock(buildPhases: [sourcesPhase], pbxProj: pbxProj) + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let sources = try await mapper.mapSources(target: target) + // Expect empty because fullPath could not be resolved + #expect(sources.isEmpty == true) + } + +// @Test func testMapVariantGroup() async throws { +// let mockProvider = MockProjectProvider( +// sourceDirectory: "/tmp/TestProject", +// projectName: "TestProject" +// ) +// let pbxProj = mockProvider.xcodeProj.pbxproj +// +// // Create file references for localized resources, but don't auto-add them to main group +// let fileRef1 = PBXFileReference.mock( +// name: "Localizable.strings", +// path: "en.lproj/Localizable.strings", +// pbxProj: pbxProj, +// addToMainGroup: false +// ) +// let fileRef2 = PBXFileReference.mock( +// name: "Localizable.strings", +// path: "fr.lproj/Localizable.strings", +// pbxProj: pbxProj, +// addToMainGroup: false +// ) +// +// // Create variant group without auto-adding it to the main group +// let variantGroup = PBXVariantGroup.mockVariant( +// children: [fileRef1, fileRef2], +// pbxProj: pbxProj, +// addToMainGroup: false +// ) +// +// // Manually add the variant group to the main group for proper path resolution +// if let project = pbxProj.projects.first, let mainGroup = project.mainGroup { +// mainGroup.children.append(variantGroup) +// } +// +// let buildFile = PBXBuildFile.mock(file: variantGroup, pbxProj: pbxProj) +// let resourcesPhase = PBXResourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) +// let target = PBXNativeTarget.mock( +// buildPhases: [resourcesPhase], +// pbxProj: pbxProj +// ) +// +// let mapper = BuildPhaseMapper(projectProvider: mockProvider) +// let resources = try await mapper.mapResources(target: target) +// +// #expect(resources.count == 2) +// #expect(resources.first?.path.basename == "Localizable.strings") +// } + + @Test func testCollectFiles_withNestedGroups() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Create file references at various levels + let fileRef1 = PBXFileReference.mock( + name: "RootFile.txt", path: "RootFile.txt", pbxProj: pbxProj, addToMainGroup: false) + + let subfileRef = PBXFileReference.mock( + name: "Subfile.txt", + path: "Subfile.txt", + pbxProj: pbxProj, + addToMainGroup: false + ) + let subgroup = PBXGroup.mock( + children: [subfileRef], name: "Subgroup", path: "Subgroup", pbxProj: pbxProj) + + // Variant group inside subgroup + let vfileRef = PBXFileReference.mock( + name: "VariantFile.strings", path: "en.lproj/VariantFile.strings", pbxProj: pbxProj, + addToMainGroup: false) + let variantGroup = PBXVariantGroup.mock(children: [vfileRef], pbxProj: pbxProj) + subgroup.children.append(variantGroup) + + if let project = pbxProj.projects.first, + let mainGroup = project.mainGroup + { + mainGroup.children.append(fileRef1) + mainGroup.children.append(subgroup) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + + let target = PBXNativeTarget.mock(buildPhases: [], pbxProj: pbxProj) + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let additionalFiles = try await mapper.mapAdditionalFiles(target: target) + // Expect 3 files: RootFile.txt, Subfile.txt, VariantFile.strings + #expect(additionalFiles.count == 3) + let names = additionalFiles.map { $0.path.basename } + #expect(names.sorted() == ["RootFile.txt", "Subfile.txt", "VariantFile.strings"].sorted()) + + } + + /// Validates all workspace fixtures. + @Test(arguments: [FileCodeGen.public, .private, .project, .disabled]) + func testCodeGenAttributes(_ fileCodeGen: FileCodeGen) async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let fileRef = PBXFileReference.mock(name: "File.swift", path: "File.swift", pbxProj: pbxProj) + let buildFile = PBXBuildFile.mock( + file: fileRef, settings: ["ATTRIBUTES": [fileCodeGen.rawValue]], pbxProj: pbxProj) + let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + let target = PBXNativeTarget.mock(buildPhases: [sourcesPhase], pbxProj: pbxProj) + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let sources = try await mapper.mapSources(target: target) + #expect(sources.count == 1) + let sourceFile = sources.first + try #require(sourceFile != nil) + #expect(sourceFile?.codeGen == fileCodeGen) + } + +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift new file mode 100644 index 00000000..1551f0a7 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift @@ -0,0 +1,124 @@ +import Testing +import XcodeGraph +import XcodeProj + +@testable import TestSupport +@testable import XcodeProjToGraph // Adjust to access BuildRuleMapper, BuildRule, etc. + +struct BuildRuleMapperTests { + let mapper = BuildRuleMapper() + + @Test func testMapBuildRulesWithKnownCompilerSpecAndFileType() async throws { + // Using a known compiler spec from the enum, e.g. .appleClang + let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue + let knownFileType = BuildRule.FileType.cSource.rawValue + let projectProvider = MockProjectProvider() + + let buildRule: PBXBuildRule = PBXBuildRule.mock( + compilerSpec: knownCompilerSpec, + fileType: knownFileType, + filePatterns: "*.c", + name: "C Rule", + outputFiles: ["$(DERIVED_FILE_DIR)/output.c.o"], + inputFiles: ["$(SRCROOT)/main.c"], + outputFilesCompilerFlags: ["-O2"], + script: "echo Building C sources", + runOncePerArchitecture: false, + pbxProj: projectProvider.pbxProj + ) + + let target = PBXNativeTarget.mock(buildRules: [buildRule], pbxProj: projectProvider.pbxProj) + let rules = try await mapper.mapBuildRules(target: target) + + #expect(rules.count == 1) + let rule = rules.first + try #require(rule != nil) + #expect(rule?.compilerSpec.rawValue == knownCompilerSpec) + #expect(rule?.fileType.rawValue == knownFileType) + #expect(rule?.filePatterns == "*.c") + #expect(rule?.name == "C Rule") + #expect(rule?.outputFiles == ["$(DERIVED_FILE_DIR)/output.c.o"]) + #expect(rule?.inputFiles == ["$(SRCROOT)/main.c"]) + #expect(rule?.outputFilesCompilerFlags == ["-O2"]) + #expect(rule?.script == "echo Building C sources") + #expect(rule?.runOncePerArchitecture == false) + } + + @Test func testMapBuildRulesWithUnknownCompilerSpec() async throws { + let projectProvider = MockProjectProvider() + let unknownCompilerSpec = "com.apple.compilers.unknown" + let knownFileType = "sourcecode.c.c" + + let buildRule = PBXBuildRule.mock( + compilerSpec: unknownCompilerSpec, + fileType: knownFileType, + pbxProj: projectProvider.pbxProj + ) + + let target = PBXNativeTarget.mock( + buildRules: [buildRule], + pbxProj: projectProvider.pbxProj) + let rules = try await mapper.mapBuildRules(target: target) + + // Unknown compiler spec means the rule should be skipped + #expect(rules.count == 0) + } + + @Test func testMapBuildRulesWithUnknownFileType() async throws { + let projectProvider = MockProjectProvider() + let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue + let unknownFileType = "sourcecode.unknown" + + let buildRule = PBXBuildRule.mock( + compilerSpec: knownCompilerSpec, + fileType: unknownFileType, + pbxProj: projectProvider.pbxProj + ) + + let target = PBXNativeTarget.mock( + buildRules: [buildRule], + pbxProj: projectProvider.pbxProj) + let rules = try await mapper.mapBuildRules(target: target) + + // Unknown file type means the rule should be skipped + #expect(rules.count == 0) + } + + @Test func testMapBuildRulesWithMixedValidAndInvalid() async throws { + let projectProvider = MockProjectProvider() + let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue + let knownFileType = BuildRule.FileType.cSource.rawValue + let unknownCompilerSpec = "com.apple.compilers.unknown" + let unknownFileType = "sourcecode.unknown" + + let validRule = PBXBuildRule.mock( + compilerSpec: knownCompilerSpec, + fileType: knownFileType, + name: "Valid Rule", + pbxProj: projectProvider.pbxProj + ) + + let invalidRuleUnknownCompiler = PBXBuildRule.mock( + compilerSpec: unknownCompilerSpec, + fileType: knownFileType, + name: "Invalid Compiler", + pbxProj: projectProvider.pbxProj + ) + + let invalidRuleUnknownFileType = PBXBuildRule.mock( + compilerSpec: knownCompilerSpec, + fileType: unknownFileType, + name: "Invalid FileType", + pbxProj: projectProvider.pbxProj + ) + + let target = PBXNativeTarget.mock( + buildRules: [validRule, invalidRuleUnknownCompiler, invalidRuleUnknownFileType], + pbxProj: projectProvider.pbxProj) + let rules = try await mapper.mapBuildRules(target: target) + + // Only the valid rule should be included + #expect(rules.count == 1) + #expect(rules.first?.name == "Valid Rule") + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift new file mode 100644 index 00000000..977eb398 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift @@ -0,0 +1,259 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj + +@testable import TestSupport +@testable import XcodeProjToGraph + +struct DependencyMapperTests { + + let mockProvider = MockProjectProvider() + let mapper: DependencyMapping + + init() { + self.mapper = DependencyMapper(projectProvider: mockProvider) + } + + @Test func testDirectTargetMapping() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let dep = PBXTargetDependency.mockTargetDependency( + name: "DirectTarget", + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) + + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + #expect(mapped.first == .target(name: "DirectTarget", status: .required, condition: nil)) + } + + @Test func testPackageProductMapping() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let dep = PBXTargetDependency.mockPackageProductDependency( + productName: "MyPackageProduct", + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) + + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + #expect(mapped.first == .package(product: "MyPackageProduct", type: .runtime, condition: nil)) + } + + @Test func testProxyNativeTarget() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + // Native target proxy referencing a target in the same project + let project = pbxProj.projects.first! + let dep = PBXTargetDependency.mockProxyDependency( + remoteInfo: "NativeTarget", + proxyType: .nativeTarget, + containerPortal: .project(project), + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) + + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + #expect(mapped.first == .target(name: "NativeTarget", status: .required, condition: nil)) + } + + @Test func testProxyProjectReference() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let fileRef = PBXFileReference.mock( + path: "OtherProject.xcodeproj", + pbxProj: pbxProj + ) + + let dep = PBXTargetDependency.mockProxyDependency( + remoteInfo: "OtherTarget", + proxyType: .nativeTarget, + containerPortal: .fileReference(fileRef), + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) + + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + let result = mapped.first! + let expectedPath = try AbsolutePath.resolvePath( + mockProvider.sourceDirectory.pathString + "OtherProject.xcodeproj") + #expect( + result + == .project(target: "OtherTarget", path: expectedPath, status: .required, condition: nil)) + } + + @Test func testProxyReferenceProxyLibrary() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let referenceProxy = PBXReferenceProxy( + fileType: "compiled.mach-o.dylib", + path: "libTest.dylib", + remote: nil, + sourceTree: .group + ) + pbxProj.add(object: referenceProxy) + + let projectRef = PBXProject.mock(name: "RemoteProject", pbxProj: pbxProj) + let dep = PBXTargetDependency.mockProxyDependency( + remoteInfo: "SomeRemoteInfo", + proxyType: .reference, + containerPortal: .project(projectRef), + pbxProj: pbxProj, + remoteObject: referenceProxy + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) + + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + let result: TargetDependency = mapped.first! + let expectedPath = mockProvider.sourceDirectory.appending(component: "libTest.dylib") + let publicHeaders = try AbsolutePath(validating: "/tmp") + #expect( + result + == TargetDependency.library( + path: expectedPath, publicHeaders: publicHeaders, swiftModuleMap: nil, condition: nil)) + } + + @Test func testProxyReferenceFileFramework() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let fileRef = PBXFileReference.mock( + path: "MyLib.framework", + pbxProj: pbxProj + ) + + let projectRef = PBXProject.mock(name: "RemoteProject", pbxProj: pbxProj) + let dep = PBXTargetDependency.mockProxyDependency( + remoteInfo: "SomeFramework", + proxyType: .reference, + containerPortal: .project(projectRef), + pbxProj: pbxProj, + remoteObject: fileRef + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) + + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + let result = mapped.first! + let expectedPath = mockProvider.sourceDirectory.appending(component: "MyLib.framework") + #expect( + result == TargetDependency.framework(path: expectedPath, status: .required, condition: nil)) + } + + @Test func testPlatformConditions() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let dep = PBXTargetDependency.mockTargetDependency( + name: "ConditionalTarget", + platformFilters: ["macos", "ios"], + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) + + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + let result = mapped.first! + let condition = PlatformCondition.when([.ios, .macos]) + #expect(result == .target(name: "ConditionalTarget", status: .required, condition: condition)) + } + + @Test func testNoMatches() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + // A dependency with no target, no product, no proxy - unhandled + let dep = PBXTargetDependency.mock(name: nil, pbxProj: pbxProj) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) + + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 0) + } + + @Test func testFileDependencyMapper() async throws { + // Test a known path extension scenario + let fdm = FileDependencyMapper(projectProvider: mockProvider) + let dependency = try await fdm.mapDependency(pathString: "libStatic.a", condition: nil) + let expectedPath = mockProvider.sourceDirectory.appending(component: "libStatic.a") + let publicHeaders = try AbsolutePath(validating: "/tmp") + #expect( + dependency + == TargetDependency.library( + path: expectedPath, publicHeaders: publicHeaders, swiftModuleMap: nil, condition: nil)) + } + + @Test func testSinglePlatformFilter() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let dep = PBXTargetDependency.mockTargetDependency( + name: "SinglePlatform", + platformFilter: "tvos", + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) + + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + #expect( + mapped.first == .target(name: "SinglePlatform", status: .required, condition: .when([.tvos]))) + } + + @Test func testInvalidPlatformFilter() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let dep = PBXTargetDependency.mockTargetDependency( + name: "UnknownPlatform", + platformFilter: "weirdos", + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) + + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + // Unknown platform => condition == nil + #expect(mapped.first == .target(name: "UnknownPlatform", status: .required, condition: nil)) + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift new file mode 100644 index 00000000..6b249aa7 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift @@ -0,0 +1,224 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj + +@testable import TestSupport +@testable import XcodeProjToGraph + +struct TargetDependencyExtensionsTests { + let sourceDirectory = try! AbsolutePath.resolvePath("/tmp/TestProject") + + // A dummy global target map for .project dependencies + let allTargetsMap: [String: Target] = [ + "MyProjectTarget": Target.test( + name: "MyProjectTarget", + product: .framework + ), + "MyProjectDynamicLibrary": Target.test( + name: "MyProjectDynamicLibrary", + product: .dynamicLibrary + ), + ] + + @Test func testTargetGraphDependency_Target() async throws { + let dependency = TargetDependency.target(name: "App", status: .required, condition: nil) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: allTargetsMap + ) + #expect(graphDep == .target(name: "App", path: sourceDirectory, status: .required)) + } + + @Test func testTargetGraphDependencyFramework_Project() async throws { + let dependency = TargetDependency.project( + target: "MyProjectTarget", + path: sourceDirectory, + status: .required, + condition: nil + ) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: allTargetsMap + ) + + #expect( + ({ + switch graphDep { + case let .framework(path, binaryPath, _, _, linking, archs, status): + return path == sourceDirectory + && binaryPath == sourceDirectory.appending(component: "MyProjectTarget.framework") + && linking == .dynamic && archs.isEmpty && status == .required + default: + return false + } + })() != false) + } + + @Test func testTargetGraphDependencyLibrary_Project() async throws { + let dependency = TargetDependency.project( + target: "MyProjectDynamicLibrary", + path: sourceDirectory, + status: .required, + condition: nil + ) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: allTargetsMap + ) + + switch graphDep { + case let .library(path, _, linking, _, _): + #expect( + path.pathString + == sourceDirectory.appending(component: "libMyProjectDynamicLibrary.dylib").pathString) + #expect(linking == .dynamic) + default: + Issue.record() + } + } + + @Test func testTargetGraphDependency_Framework() async throws { + let frameworkPath = sourceDirectory.appending(component: "MyFramework.framework") + let dependency = TargetDependency.framework( + path: frameworkPath, status: .required, condition: nil) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: [:] + ) + + #expect( + ({ + switch graphDep { + case let .framework(path, binaryPath, _, _, linking, archs, status): + return path == frameworkPath + && binaryPath == frameworkPath.appending(component: "MyFramework") + && linking == .dynamic && archs.isEmpty && status == .required + default: + return false + } + })() != false) + } + + @Test func testTargetGraphDependency_XCFramework() async throws { + let xcframeworkPath = sourceDirectory.appending(component: "MyXCFramework.xcframework") + let dependency = TargetDependency.xcframework( + path: xcframeworkPath, status: .required, condition: nil) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: [:] + ) + + #expect( + ({ + switch graphDep { + case let .xcframework(info): + return info.path == xcframeworkPath && info.linking == .dynamic + && info.status == .required + default: + return false + } + })() != false) + } + + @Test func testTargetGraphDependency_Library() async throws { + let libPath = sourceDirectory.appending(component: "libMyLib.a") + let headersPath = sourceDirectory.appending(component: "include") + let dependency = TargetDependency.library( + path: libPath, + publicHeaders: headersPath, + swiftModuleMap: nil, + condition: nil + ) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: [:] + ) + + #expect( + ({ + switch graphDep { + case let .library(path, publicHeaders, linking, archs, swiftModuleMap): + return path == libPath && publicHeaders == headersPath && linking == .static + && archs.isEmpty && swiftModuleMap == nil + default: + return false + } + })() != false) + } + + @Test func testTargetGraphDependency_Package() async throws { + let dependency = TargetDependency.package( + product: "MyPackageProduct", type: .runtime, condition: nil) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: [:] + ) + + #expect( + graphDep + == .packageProduct(path: sourceDirectory, product: "MyPackageProduct", type: .runtime)) + } + + @Test func testTargetGraphDependency_SDK() async throws { + let dependency = TargetDependency.sdk(name: "MySDK", status: .optional, condition: nil) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: [:] + ) + + #expect( + ({ + switch graphDep { + case let .sdk(name, path, status, source): + return name == "MySDK" && path == sourceDirectory && status == .optional + && source == .developer + default: + return false + } + })() != false) + } + + @Test func testTargetGraphDependency_XCTest() async throws { + let dependency = TargetDependency.xctest + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: [:] + ) + + #expect( + ({ + switch graphDep { + case let .xcframework(info): + return info.path == sourceDirectory && info.linking == .dynamic + && info.status == .required + default: + return false + } + })() != false) + } + + @Test func testMapProjectGraphDependency_TargetNotFound() async throws { + let dependency = TargetDependency.project( + target: "NonExistentTarget", + path: sourceDirectory, + status: .required, + condition: nil + ) + + do { + _ = try await dependency.graphDependency(sourceDirectory: sourceDirectory, allTargetsMap: [:]) + Issue.record("Expected to throw MappingError.targetNotFound") + } catch let error as MappingError { + switch error { + case .targetNotFound(let targetName, let path): + #expect(targetName == "NonExistentTarget") + #expect(path == sourceDirectory) + default: + Issue.record("Unexpected MappingError: \(error)") + } + } catch { + Issue.record("Unexpected error: \(error)") + } + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift new file mode 100644 index 00000000..4f48f28f --- /dev/null +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift @@ -0,0 +1,187 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj + +@testable import TestSupport +@testable import XcodeProjToGraph + +struct GraphMapperTests { + + @Test func testSingleProjectGraph() async throws { + // Setup a mock provider and a single project scenario + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/SingleProject", + projectName: "SingleProject" + ) + + // Add a single target to the project + let pbxProj = mockProvider.xcodeProj.pbxproj + let target = PBXNativeTarget.mock( + name: "App", + productType: .application, + pbxProj: pbxProj + ) + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + // GraphType for a single project + let projectPath = try AbsolutePath(validating: mockProvider.sourceDirectory.pathString) + let graphType = GraphType.project(projectPath) + + // Provide a closure that returns the mock provider + let mapper = GraphMapper(graphType: graphType) { path in + // We only handle this single path scenario + #expect(path == projectPath) + return mockProvider + } + + let graph = try await mapper.xcodeGraph() + + // Validate that the returned graph matches our expectations + #expect(graph.name == "Workspace") + #expect(graph.projects.count == 1) + #expect(graph.packages == [:]) + #expect(graph.dependencies == [:]) + #expect(graph.dependencyConditions == [:]) + + // Check that the workspace is created as a wrapper around the single project + #expect(graph.workspace.projects.count == 1) + #expect(graph.workspace.projects.first == projectPath) + #expect(graph.workspace.name == "Workspace") + } + + @Test func testWorkspaceGraphMultipleProjects() async throws { + // Setup two mock projects + let mockProviderA = MockProjectProvider( + sourceDirectory: "/tmp/Workspace/ProjectA", + projectName: "ProjectA" + ) + let mockProviderB = MockProjectProvider( + sourceDirectory: "/tmp/Workspace/ProjectB", + projectName: "ProjectB" + ) + + // Add a target to Project A + let pbxProjA = mockProviderA.xcodeProj.pbxproj + let targetA = PBXNativeTarget.mock( + name: "ATarget", + productType: .framework, + pbxProj: pbxProjA + ) + if let projectA = pbxProjA.projects.first { + projectA.targets.append(targetA) + } + + // Add a target to Project B + let pbxProjB = mockProviderB.xcodeProj.pbxproj + let targetB = PBXNativeTarget.mock( + name: "BTarget", + productType: .framework, + pbxProj: pbxProjB + ) + if let projectB = pbxProjB.projects.first { + projectB.targets.append(targetB) + } + + // Setup a workspace that references these two projects + let workspacePath = try AbsolutePath(validating: "/tmp/Workspace") + let projectAPath = try AbsolutePath(validating: "/tmp/Workspace/ProjectA.xcodeproj") + let projectBPath = try AbsolutePath(validating: "/tmp/Workspace/ProjectB.xcodeproj") + + let xcworkspace = XCWorkspace( + data: XCWorkspaceData(children: [ + .file(.init(location: .absolute(projectAPath.pathString))), + .file(.init(location: .absolute(projectBPath.pathString))), + + ]) + ) + + let provider = MockWorkspaceProvider(xcWorkspacePath: workspacePath, xcworkspace: xcworkspace) + + let graphType = GraphType.workspace(provider) + + // Provide a closure that returns the corresponding mock provider based on the project path + let mapper = GraphMapper(graphType: graphType) { path in + if path == projectAPath { + return mockProviderA + } else if path == projectBPath { + return mockProviderB + } else { + Issue.record("Unexpected project path requested: \(path)") + throw MappingError.noProjectsFound + } + } + + let graph = try await mapper.xcodeGraph() + + // Validate the graph + #expect(graph.workspace.name == "Workspace") + #expect(graph.workspace.projects.contains(projectAPath) == true) + #expect(graph.workspace.projects.contains(projectBPath) == true) + + // Check projects in the graph + #expect(graph.projects.count == 2) + let projectA = graph.projects[projectAPath] + let projectB = graph.projects[projectBPath] + try #require(projectA != nil) + try #require(projectB != nil) + #expect(projectA?.targets["ATarget"] != nil) + #expect(projectB?.targets["BTarget"] != nil) + + // Since we didn’t add packages or dependencies, these should be empty + #expect(graph.packages.isEmpty == true) + #expect(graph.dependencies.isEmpty == true) + #expect(graph.dependencyConditions.isEmpty == true) + } + + @Test func testGraphWithDependencies() async throws { + // Example test to confirm dependency mapping works + // Setup a single project with two targets: App depends on AFramework + + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/ProjectWithDeps", + projectName: "ProjectWithDeps" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let frameworkTarget = PBXNativeTarget.mock( + name: "AFramework", + productType: .framework, + pbxProj: pbxProj + ) + + let appTarget = PBXNativeTarget.mock( + name: "App", + productType: .application, + pbxProj: pbxProj + ) + + // Add a target dependency from App to AFramework + let dep = PBXTargetDependency.mockTargetDependency( + name: "AFramework", + pbxProj: pbxProj + ) + appTarget.dependencies.append(dep) + + if let project = pbxProj.projects.first { + project.targets.append(contentsOf: [frameworkTarget, appTarget]) + } + + let projectPath = try AbsolutePath(validating: mockProvider.xcodeProjPath.pathString) + let graphType = GraphType.project(projectPath) + + let mapper = GraphMapper(graphType: graphType) { path in + #expect(path == projectPath) + return mockProvider + } + + let graph = try await mapper.xcodeGraph() + + // Check that dependencies are mapped + let sourceDep = GraphDependency.target(name: "App", path: mockProvider.sourceDirectory) + let targetDep = GraphDependency.target(name: "AFramework", path: mockProvider.sourceDirectory) + #expect(graph.dependencies == [sourceDep: [targetDep]]) + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift new file mode 100644 index 00000000..8aa5ebc3 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift @@ -0,0 +1,133 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj + +@testable import TestSupport +@testable import XcodeProjToGraph + +struct PackageMapperTests { + let mapper: PackageMapper + let projectProvider: MockProjectProvider + + init() { + let provider = MockProjectProvider() + self.projectProvider = provider + self.mapper = PackageMapper(projectProvider: provider) + } + + @Test func testMapPackageWithValidURL() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .upToNextMajorVersion("1.0.0") + ) + + let result = try await mapper.map(package: package) + #expect( + result + == .remote( + url: "https://github.com/example/package.git", requirement: .upToNextMajor("1.0.0"))) + } + + @Test func testMapRequirementUpToNextMajor() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .upToNextMajorVersion("1.0.0") + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .upToNextMajor("1.0.0")) + } + + @Test func testMapRequirementUpToNextMinor() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .upToNextMinorVersion("1.2.0") + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .upToNextMinor("1.2.0")) + } + + @Test func testMapRequirementExact() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .exact("1.2.3") + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .exact("1.2.3")) + } + + @Test func testMapRequirementRange() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .range(from: "1.0.0", to: "2.0.0") + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .range(from: "1.0.0", to: "2.0.0")) + } + + @Test func testMapRequirementBranch() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .branch("main") + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .branch("main")) + } + + @Test func testMapRequirementRevision() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .revision("abc123") + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .revision("abc123")) + } + + @Test func testMapRequirementNoVersionRequirement() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: nil + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .upToNextMajor("0.0.0")) + } + + @Test func testMapLocalPackage() async throws { + // Arrange + let localPackage = XCLocalSwiftPackageReference.mock(relativePath: "Packages/Example") + + // Act + let result = try await mapper.map(package: localPackage) + + // Assert + let expectedPath = projectProvider.sourceDirectory.appending( + try RelativePath(validating: "Packages/Example")) + #expect(result == .local(path: expectedPath)) + } +} + +// Extension to support testing +extension XCRemoteSwiftPackageReference { + static func mock( + repositoryURL: String, + versionRequirement: VersionRequirement? + ) -> XCRemoteSwiftPackageReference { + return XCRemoteSwiftPackageReference( + repositoryURL: repositoryURL, + versionRequirement: versionRequirement + ) + } +} + +extension XCLocalSwiftPackageReference { + static func mock(relativePath: String) -> XCLocalSwiftPackageReference { + return XCLocalSwiftPackageReference(relativePath: relativePath) + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift new file mode 100644 index 00000000..b0b5b830 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift @@ -0,0 +1,158 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj + +@testable import TestSupport +@testable import XcodeProjToGraph + +struct ProjectMapperTests { + + @Test func testMapBasicProject() async throws { + let mockProvider = MockProjectProvider() + let mapper = ProjectMapper(projectProvider: mockProvider) + + let project = try await mapper.mapProject() + + #expect(project.name == "TestProject") + #expect(project.path == mockProvider.sourceDirectory) + #expect(project.sourceRootPath == mockProvider.sourceDirectory) + #expect(project.xcodeProjPath == mockProvider.sourceDirectory) + #expect(project.type == .local) + } + + @Test func testMapProjectWithCustomAttributes() async throws { + let pbxProj = PBXProj() + let provider = MockProjectProvider( + projectName: "CustomProject", + pbxProj: pbxProj + ) + + let mapper = ProjectMapper(projectProvider: provider) + + let customAttributes: [String: Any] = [ + "ORGANIZATIONNAME": "Example Org", + "CLASSPREFIX": "EX", + "LastUpgradeCheck": "1500", + ] + + provider.pbxProj.projects.first?.attributes = customAttributes + + let project = try await mapper.mapProject() + + #expect(project.name == "CustomProject") + #expect(project.organizationName == "Example Org") + #expect(project.classPrefix == "EX") + #expect(project.lastUpgradeCheck == "1500") + } + + @Test func testMapProjectWithTargets() async throws { + + let mockProvider = MockProjectProvider() + + let configList = XCConfigurationList.mock( + configs: [("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"])], + proj: mockProvider.pbxProj) + + let mapper = ProjectMapper(projectProvider: mockProvider) + + let target = PBXNativeTarget.mock( + name: "ExampleApp", + buildConfigurationList: configList, + productType: .application, + pbxProj: mockProvider.pbxProj + ) + try mockProvider.pbxProject().targets.append(target) + + let project = try await mapper.mapProject() + print(project.targets) + #expect(project.targets.count == 1) + #expect(project.targets.first?.value.name == "ExampleApp") + #expect(project.targets.first?.value.product == .app) + } + + @Test func testMapProjectWithRemotePackages() async throws { + let mockProvider = MockProjectProvider() + let package = XCRemoteSwiftPackageReference( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .upToNextMajorVersion("1.0.0") + ) + mockProvider.pbxProj.add(object: package) + try mockProvider.pbxProject().remotePackages.append(package) + let mapper = ProjectMapper(projectProvider: mockProvider) + + let project = try await mapper.mapProject() + + #expect(project.packages.count == 1) + guard case let .remote(url, requirement) = project.packages[0] else { + Issue.record("Expected remote package") + return + } + #expect(url == "https://github.com/example/package.git") + #expect(requirement == .upToNextMajor("1.0.0")) + } + + @Test func testMapProjectWithKnownRegions() async throws { + let mockProvider = MockProjectProvider() + try mockProvider.pbxProject().knownRegions = ["en", "es", "fr"] + let mapper = ProjectMapper(projectProvider: mockProvider) + + let project = try await mapper.mapProject() + + #expect(project.defaultKnownRegions?.count == 3) + #expect(project.defaultKnownRegions?.contains("en") == true) + #expect(project.defaultKnownRegions?.contains("es") == true) + #expect(project.defaultKnownRegions?.contains("fr") == true) + } + + @Test func testMapProjectWithDevelopmentRegion() async throws { + let mockProvider = MockProjectProvider() + try mockProvider.pbxProject().developmentRegion = "fr" + let mapper = ProjectMapper(projectProvider: mockProvider) + + let project = try await mapper.mapProject() + + #expect(project.developmentRegion == "fr") + } + + @Test func testMapProjectWithResourceSynthesizers() async throws { + let mockProvider = MockProjectProvider() + let mapper = ProjectMapper(projectProvider: mockProvider) + + let project = try await mapper.mapProject() + + // Test for expected resource synthesizers + let synthesizers = project.resourceSynthesizers + + // Check for strings synthesizer + let stringsSynthesizer = synthesizers.first { $0.parser == .strings } + #expect(stringsSynthesizer != nil) + #expect(stringsSynthesizer?.extensions.contains("strings") == true) + #expect(stringsSynthesizer?.extensions.contains("stringsdict") == true) + + // Check for assets synthesizer + let assetsSynthesizer = synthesizers.first { $0.parser == .assets } + #expect(assetsSynthesizer != nil) + #expect(assetsSynthesizer?.extensions.contains("xcassets") == true) + + // Verify all expected synthesizer types are present + let expectedParsers: Set = [ + .strings, .assets, .plists, .fonts, .coreData, + .interfaceBuilder, .json, .yaml, .files, + ] + let actualParsers = Set(synthesizers.map(\.parser)) + #expect(actualParsers == expectedParsers) + } + + @Test func testMapProjectWithSchemes() async throws { + let mockProvider = MockProjectProvider() + let scheme = XCScheme.mock(name: "TestScheme") + mockProvider.xcodeProj.sharedData = XCSharedData(schemes: [scheme]) + let mapper = ProjectMapper(projectProvider: mockProvider) + + let project = try await mapper.mapProject() + + #expect(project.schemes.count == 1) + #expect(project.schemes[0].name == "TestScheme") + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift new file mode 100644 index 00000000..ddae7380 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift @@ -0,0 +1,63 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj + +@testable import TestSupport +@testable import XcodeProjToGraph + +struct BuildSettingsTests { + /// Tests that a string value is correctly extracted from build settings. + @Test func testStringExtraction() async throws { + let settings: [String: Any] = ["COMPILER_FLAGS": "-ObjC"] + let value = settings.string(for: .compilerFlags) + try #require(value != nil) + #expect(value == "-ObjC") + } + + /// Tests that a boolean value is correctly extracted, and invalid types return nil. + @Test func testBoolExtraction() { + let settings: [String: Any] = ["PRUNE": true] + let boolValue = settings.bool(for: .prune) + #expect(boolValue == true) + + // Test invalid type + let invalidSettings: [String: Any] = ["PRUNE": "notABool"] + let invalidBool = invalidSettings.bool(for: .prune) + #expect(invalidBool == nil) + } + + /// Tests extracting a string array from build settings. + @Test func testStringArrayExtraction() async throws { + let settings: [String: Any] = ["LAUNCH_ARGUMENTS": ["-enableFeature", "-verbose"]] + let args = settings.stringArray(for: .launchArguments) + try #require(args != nil) + #expect(args?.count == 2) + #expect(args?.contains("-verbose") == true) + } + + /// Tests extracting a dictionary of strings (for environment variables). + @Test func testStringDictExtraction() async throws { + let settings: [String: Any] = ["ENVIRONMENT_VARIABLES": ["KEY": "VALUE"]] + let envVars = settings.stringDict(for: .environmentVariables) + try #require(envVars != nil) + #expect(envVars?["KEY"] == "VALUE") + } + + /// Tests that missing keys return nil. + @Test func testMissingKeyReturnsNil() { + let settings: [String: Any] = ["TAGS": "some,tags"] + #expect(settings.string(for: .productBundleIdentifier) == nil) + #expect(settings.bool(for: .mergeable) == nil) + } + + /// Tests that non-string array values are coerced to strings. + /// Example: If a setting is `[Any]` but some elements aren’t strings, they’re filtered out. + @Test func testCoerceAnyArrayToStringArray() async throws { + let settings: [String: Any] = ["LAUNCH_ARGUMENTS": ["-flag", 42, true]] + let args = settings.stringArray(for: .launchArguments) + try #require(args != nil) + // Non-string elements (42, true) should be discarded, leaving only ["-flag"]. + #expect(args == ["-flag"]) + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift new file mode 100644 index 00000000..8d334b67 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift @@ -0,0 +1,35 @@ +import Testing +import XcodeGraph + +@testable import XcodeProjToGraph + +struct ConfigurationMatcherTests { + + @Test func testVariantDetectionForDebug() async throws { + #expect(ConfigurationMatcher.variant(forName: "Debug") == .debug) + #expect(ConfigurationMatcher.variant(forName: "development") == .debug) + #expect(ConfigurationMatcher.variant(forName: "dev") == .debug) + } + + @Test func testVariantDetectionForRelease() async throws { + #expect(ConfigurationMatcher.variant(forName: "Release") == .release) + #expect(ConfigurationMatcher.variant(forName: "prod") == .release) + #expect(ConfigurationMatcher.variant(forName: "production") == .release) + } + + @Test func testVariantFallbackToDebug() async throws { + // Names that don't match debug/release keywords should fall back to debug + #expect(ConfigurationMatcher.variant(forName: "Staging") == .debug) + #expect(ConfigurationMatcher.variant(forName: "CustomConfig") == .debug) + } + + @Test func testValidateConfigurationName() async throws { + #expect(ConfigurationMatcher.validateConfigurationName("Debug") == true) + #expect(ConfigurationMatcher.validateConfigurationName("Release") == true) + + // Invalid names: empty, whitespace, or containing spaces + #expect(ConfigurationMatcher.validateConfigurationName("") == false) + #expect(ConfigurationMatcher.validateConfigurationName("Debug Config") == false) + #expect(ConfigurationMatcher.validateConfigurationName(" ") == false) + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift new file mode 100644 index 00000000..b7a7d4a5 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift @@ -0,0 +1,162 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj + +@testable import TestSupport // For MockFactory usage +@testable import XcodeProjToGraph + +struct SettingsMapperTests { + let mapper = SettingsMapper() + + @Test func testNilConfigurationListReturnsDefault() async throws { + let mockProvider = MockProjectProvider() + let settings = try await mapper.map(projectProvider: mockProvider, configurationList: nil) + #expect(settings == Settings.default) + } + + @Test func testSingleConfigurationMapping() async throws { + let pbxProj = PBXProj() + let configList = XCConfigurationList.mock( + configs: [("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.debug"])], proj: pbxProj + ) + let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) + + let settings = try await mapper.map( + projectProvider: mockProvider, configurationList: configList) + #expect(settings.configurations.count == 1) + + let configKey = settings.configurations.keys.first + try #require(configKey != nil) + #expect(configKey?.name == "Debug") + #expect(configKey?.variant == .debug) + + let debugConfig = settings.configurations[configKey!] + try #require(debugConfig != nil) + + // Now `debugConfig` is a `Configuration?`. + let actualDebugConfig = debugConfig! + try #require(actualDebugConfig != nil) + + #expect(actualDebugConfig!.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.debug") + } + + @Test func testMultipleConfigurations() async throws { + let pbxProj = PBXProj() + let configs: [(String, [String: Sendable])] = [ + ("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.debug"]), + ("Release", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.release"]), + ] + let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) + let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) + + let settings = try await mapper.map( + projectProvider: mockProvider, configurationList: configList) + #expect(settings.configurations.count == 2) + + let debugKey = settings.configurations.keys.first { $0.name == "Debug" } + let releaseKey = settings.configurations.keys.first { $0.name == "Release" } + + try #require(debugKey != nil) + try #require(releaseKey != nil) + #expect(debugKey?.variant == .debug) + #expect(releaseKey?.variant == .release) + + let debugConfig = settings.configurations[debugKey!] + let releaseConfig = settings.configurations[releaseKey!] + + try #require(debugConfig != nil) + try #require(releaseConfig != nil) + + let actualDebugConfig = debugConfig! + let actualReleaseConfig = releaseConfig! + + #expect(actualDebugConfig?.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.debug") + #expect(actualReleaseConfig?.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.release") + } + + @Test func testCoercionOfNonStringValues() async throws { + let pbxProj = PBXProj() + let configs: [(String, [String: Sendable])] = [ + ("Debug", ["SOME_NUMBER": 42]) + ] + let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) + let mockProvider = MockProjectProvider(configurationList: configList) + + let settings = try await mapper.map( + projectProvider: mockProvider, configurationList: configList) + let debugKey = settings.configurations.keys.first { $0.name == "Debug" } + try #require(debugKey != nil) + + let debugConfig = settings.configurations[debugKey!] + try #require(debugConfig != nil) + + let actualDebugConfig = debugConfig! + try #require(actualDebugConfig != nil) + + #expect(actualDebugConfig!.settings["SOME_NUMBER"] == "42") + } + + @Test func testXCConfigPathResolution() async throws { + let pbxProj = PBXProj() + let baseConfigRef = PBXFileReference.mock( + sourceTree: .sourceRoot, path: "Config.xcconfig", pbxProj: pbxProj) + let buildConfig = XCBuildConfiguration.mock( + name: "Debug", buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example"], + pbxProj: pbxProj) + buildConfig.baseConfiguration = baseConfigRef + + let configList = XCConfigurationList( + buildConfigurations: [buildConfig], + defaultConfigurationName: "Debug", + defaultConfigurationIsVisible: false + ) + + let mockProvider = MockProjectProvider( + sourceDirectory: "/Users/test/project", configurationList: configList) + let settings = try await mapper.map( + projectProvider: mockProvider, configurationList: configList) + + let debugKey = settings.configurations.keys.first { $0.name == "Debug" } + try #require(debugKey != nil) + + let debugConfig = settings.configurations[debugKey!] + try #require(debugConfig != nil) + + let actualDebugConfig = debugConfig! + try #require(actualDebugConfig != nil) + + let expectedPath = "/Users/test/project/Config.xcconfig" + #expect(actualDebugConfig!.xcconfig?.pathString == expectedPath) + } + + @Test func testArrayValueMapping() async throws { + let pbxProj = PBXProj() + let configs: [(String, [String: Sendable])] = [ + ("Debug", ["SOME_ARRAY": ["val1", "val2"]]) + ] + let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) + let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) + + let settings = try await mapper.map( + projectProvider: mockProvider, configurationList: configList) + + // Check we have one configuration + #expect(settings.configurations.count == 1) + + // Retrieve the Debug configuration + let debugKey = settings.configurations.keys.first { $0.name == "Debug" } + try #require(debugKey != nil) + let debugConfig = settings.configurations[debugKey!] + try #require(debugConfig != nil) + + let actualDebugConfig = debugConfig! + try #require(actualDebugConfig != nil) + + // Verify the array setting + // NOTE: actualDebugConfig.settings["SOME_ARRAY"] should return a SettingValue + // which is .array(["val1", "val2"]) + #expect(actualDebugConfig!.settings["SOME_ARRAY"] == ["val1", "val2"]) + } + +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift new file mode 100644 index 00000000..8bcdce5b --- /dev/null +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift @@ -0,0 +1,242 @@ +import Path +import Testing +@testable import XcodeProj +@testable import TestSupport +@testable import XcodeProjToGraph + +struct SchemeMapperTests { + let mockProvider: MockProjectProvider + let mapper: SchemeMapper + + init() async throws { + let mockProvider = MockProjectProvider() + self.mockProvider = mockProvider + self.mapper = try SchemeMapper(graphType: .project(mockProvider.sourceDirectory)) + } + + @Test func testMapSharedProjectSchemes() async throws { + // Setup shared scheme data + let xcscheme = XCScheme.mock(name: "SharedScheme") + + let schemes = try await mapper.mapSchemes(xcschemes: [xcscheme], shared: true) + #expect(schemes.count == 1) + #expect(schemes[0].name == "SharedScheme") + #expect(schemes[0].shared == true) + } + + @Test func testMapUserSchemes() async throws { + // Setup user scheme data + let xcscheme = XCScheme.mock(name: "UserScheme") + let schemes = try await mapper.mapSchemes(xcschemes: [xcscheme], shared: false) + + #expect(schemes.count == 1) + #expect(schemes[0].name == "UserScheme") + #expect(schemes[0].shared == false) + } + + @Test func testMapBuildAction() async throws { + let targetRef = XCScheme.BuildableReference( + referencedContainer: "container:App.xcodeproj", + blueprintIdentifier: "123", + buildableName: "App.app", + blueprintName: "App" + ) + + let buildActionEntry = XCScheme.BuildAction.Entry( + buildableReference: targetRef, + buildFor: [.running, .testing] + ) + + let buildAction = XCScheme.BuildAction( + buildActionEntries: [buildActionEntry], + parallelizeBuild: true, + buildImplicitDependencies: true, + runPostActionsOnFailure: true + ) + + let mappedAction = try await mapper.mapBuildAction(action: buildAction) + #expect(mappedAction != nil) + #expect(mappedAction?.targets.count == 1) + #expect(mappedAction?.targets[0].name == "App") + #expect(mappedAction?.runPostActionsOnFailure == true) + #expect(mappedAction?.findImplicitDependencies == true) + } + + @Test func testMapTestAction() async throws { + let targetRef = XCScheme.BuildableReference( + referencedContainer: "container:App.xcodeproj", + blueprintIdentifier: "123", + buildableName: "AppTests.xctest", + blueprintName: "AppTests" + ) + + let testableEntry = XCScheme.TestableReference.mock( + skipped: false, + buildableReference: targetRef + ) + + let envVar = XCScheme.EnvironmentVariable( + variable: "TEST_ENV", + value: "test_value", + enabled: true + ) + + let launchArg = XCScheme.CommandLineArguments.CommandLineArgument( + name: "test_arg", + enabled: true + ) + + let testAction = XCScheme.TestAction( + buildConfiguration: "Debug", + macroExpansion: nil, + testables: [testableEntry], + codeCoverageEnabled: true, + commandlineArguments: XCScheme.CommandLineArguments(arguments: [launchArg]), + environmentVariables: [envVar], + language: "en", + region: "US" + ) + + let mappedAction = try await mapper.mapTestAction(action: testAction) + #expect(mappedAction != nil) + #expect(mappedAction?.targets.count == 1) + #expect(mappedAction?.targets[0].target.name == "AppTests") + #expect(mappedAction?.configurationName == "Debug") + #expect(mappedAction?.coverage == true) + #expect(mappedAction?.arguments?.environmentVariables["TEST_ENV"]?.value == "test_value") + #expect(mappedAction?.arguments?.launchArguments.first?.name == "test_arg") + #expect(mappedAction?.language == "en") + #expect(mappedAction?.region == "US") + } + + @Test func testMapRunAction() async throws { + let targetRef = XCScheme.BuildableReference( + referencedContainer: "container:App.xcodeproj", + blueprintIdentifier: "123", + buildableName: "App.app", + blueprintName: "App" + ) + + let runnable = XCScheme.BuildableProductRunnable(buildableReference: targetRef) + + let envVar = XCScheme.EnvironmentVariable( + variable: "RUN_ENV", + value: "run_value", + enabled: true + ) + + let launchArg = XCScheme.CommandLineArguments.CommandLineArgument( + name: "run_arg", + enabled: true + ) + + let launchAction = XCScheme.LaunchAction( + pathRunnable: try XCScheme.PathRunnable(element: runnable.xmlElement()), + buildConfiguration: "Debug", + selectedDebuggerIdentifier: "", + commandlineArguments: XCScheme.CommandLineArguments(arguments: [launchArg]), + environmentVariables: [envVar] + ) + + let mappedAction = try await mapper.mapRunAction(action: launchAction) + #expect(mappedAction != nil) + #expect(mappedAction?.executable?.name == "App") + #expect(mappedAction?.configurationName == "Debug") + #expect(mappedAction?.attachDebugger == true) + #expect(mappedAction?.arguments?.environmentVariables["RUN_ENV"]?.value == "run_value") + #expect(mappedAction?.arguments?.launchArguments.first?.name == "run_arg") + } + + @Test func testMapArchiveAction() async throws { + let archiveAction = XCScheme.ArchiveAction( + buildConfiguration: "Release", + revealArchiveInOrganizer: true + ) + + let mappedAction = try await mapper.mapArchiveAction(action: archiveAction) + #expect(mappedAction != nil) + #expect(mappedAction?.configurationName == "Release") + #expect(mappedAction?.revealArchiveInOrganizer == true) + } + + @Test func testMapProfileAction() async throws { + let targetRef = XCScheme.BuildableReference( + referencedContainer: "container:App.xcodeproj", + blueprintIdentifier: "123", + buildableName: "App.app", + blueprintName: "App" + ) + + let runnable = XCScheme.BuildableProductRunnable(buildableReference: targetRef) + + let profileAction = XCScheme.ProfileAction( + runnable: runnable, + buildConfiguration: "Release" + ) + + let mappedAction = try await mapper.mapProfileAction(action: profileAction) + #expect(mappedAction != nil) + #expect(mappedAction?.executable?.name == "App") + #expect(mappedAction?.configurationName == "Release") + } + + @Test func testMapAnalyzeAction() async throws { + let analyzeAction = XCScheme.AnalyzeAction(buildConfiguration: "Debug") + + let mappedAction = try await mapper.mapAnalyzeAction(action: analyzeAction) + #expect(mappedAction != nil) + #expect(mappedAction?.configurationName == "Debug") + } + + @Test func testMapTargetReference() async throws { + let targetRef = XCScheme.BuildableReference( + referencedContainer: "container:App.xcodeproj", + blueprintIdentifier: "123", + buildableName: "App.app", + blueprintName: "App" + ) + + // Create a build action entry that uses the target reference + let buildActionEntry = XCScheme.BuildAction.Entry( + buildableReference: targetRef, + buildFor: [.running] + ) + + // Create a scheme with a build action that uses our target reference + let buildAction = XCScheme.BuildAction( + buildActionEntries: [buildActionEntry], + parallelizeBuild: true, + buildImplicitDependencies: true + ) + + let scheme = XCScheme.mock(buildAction: buildAction) + + let mapped = try await mapper.mapScheme(xcscheme: scheme, shared: true) + + // Verify the target reference was properly mapped + let mappedBuildAction = try #require(mapped.buildAction) + + #expect(mappedBuildAction.targets.count == 1) + #expect(mappedBuildAction.targets[0].name == "App") + #expect(mappedBuildAction.targets[0].projectPath == mockProvider.sourceDirectory) + } + + @Test func testNilActions() async throws { + let scheme = XCScheme.mock( + buildAction: nil, + testAction: nil, + launchAction: nil, + archiveAction: nil, + profileAction: nil, + analyzeAction: nil + ) + + let mapped = try await mapper.mapScheme(xcscheme: scheme, shared: true) + #expect(mapped.buildAction == nil) + #expect(mapped.testAction == nil) + #expect(mapped.runAction == nil) + #expect(mapped.profileAction == nil) + #expect(mapped.analyzeAction == nil) + #expect(mapped.archiveAction == nil) + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift new file mode 100644 index 00000000..e9dc7c01 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift @@ -0,0 +1,153 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj + +@testable import TestSupport +@testable import XcodeProjToGraph + +struct PBXTargetMapperTests { + let mockProvider = MockProjectProvider() + let mapper: TargetMapping + + init() { + self.mapper = TargetMapper(projectProvider: mockProvider) + } + + @Test func testMapBasicTarget() async throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"] + ) + + let mapped = try await mapper.map(pbxTarget: target) + #expect(mapped.name == "App") + #expect(mapped.product == .app) + #expect(mapped.productName == "App") + #expect(mapped.bundleId == "com.example.app") + + } + + @Test func testMapTargetWithMissingBundleId() async throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [:] + ) + + await #expect(throws: MappingError.missingBundleIdentifier(targetName: "App")) { + _ = try await mapper.map(pbxTarget: target) + } + } + + @Test func testMapTargetWithEnvironmentVariables() async throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "ENVIRONMENT_VARIABLES": ["TEST_VAR": "test_value"], + ] + ) + + let mapped = try await mapper.map(pbxTarget: target) + #expect(mapped.environmentVariables["TEST_VAR"]?.value == "test_value") + #expect(mapped.environmentVariables["TEST_VAR"]?.isEnabled == true) + } + + @Test func testMapTargetWithLaunchArguments() async throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "LAUNCH_ARGUMENTS": ["-debug", "--verbose"], + ] + ) + + let mapped = try await mapper.map(pbxTarget: target) + let expected = [ + LaunchArgument(name: "-debug", isEnabled: true), + LaunchArgument(name: "--verbose", isEnabled: true), + ] + #expect(mapped.launchArguments == expected) + + } + + @Test func testMapTargetWithSourceFiles() async throws { + let sourceFile = PBXFileReference.mock( + path: "ViewController.swift", + lastKnownFileType: "sourcecode.swift", + pbxProj: mockProvider.pbxProj + ) + let buildFile = PBXBuildFile.mock(file: sourceFile, pbxProj: mockProvider.pbxProj) + let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: mockProvider.pbxProj) + + let target = createTarget( + name: "App", + productType: .application, + buildPhases: [sourcesPhase], + buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"] + ) + + let mapped = try await mapper.map(pbxTarget: target) + #expect(mapped.sources.count == 1) + #expect(mapped.sources[0].path.basename == "ViewController.swift") + } + + @Test func testMapTargetWithMetadata() async throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "TAGS": "tag1, tag2, tag3", + ] + ) + + let mapped = try await mapper.map(pbxTarget: target) + #expect(mapped.metadata.tags == Set(["tag1", "tag2", "tag3"])) + } + + // MARK: - Helper Methods + + private func createTarget( + name: String, + productType: PBXProductType, + buildPhases: [PBXBuildPhase] = [], + buildSettings: [String: Any] = [:], + dependencies: [PBXTargetDependency] = [] + ) -> PBXNativeTarget { + let debugConfig = XCBuildConfiguration( + name: "Debug", + buildSettings: buildSettings + ) + + let releaseConfig = XCBuildConfiguration( + name: "Release", + buildSettings: buildSettings + ) + + let configurationList = XCConfigurationList( + buildConfigurations: [debugConfig, releaseConfig], + defaultConfigurationName: "Release" + ) + + mockProvider.pbxProj.add(object: debugConfig) + mockProvider.pbxProj.add(object: releaseConfig) + mockProvider.pbxProj.add(object: configurationList) + + let target = PBXNativeTarget.mock( + name: name, + buildConfigurationList: configurationList, + buildRules: [], + buildPhases: buildPhases, + dependencies: dependencies, + productType: productType, + pbxProj: mockProvider.pbxProj + ) + + return target + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Workspace/WorkspaceMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Workspace/WorkspaceMapperTests.swift new file mode 100644 index 00000000..e69de29b diff --git a/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift b/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift new file mode 100644 index 00000000..1b68592e --- /dev/null +++ b/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift @@ -0,0 +1,99 @@ +import Foundation +import Path +import Testing +import XcodeGraph +import XcodeProj + +@testable import XcodeProjToGraph + +@Suite +struct ProjectParserTests { + private func createMockDirectory(withContents contents: [String]) throws -> AbsolutePath { + let tempDirectory = FileManager.default.temporaryDirectory + let mockDirectory = tempDirectory.appendingPathComponent("MockDirectory_\(UUID().uuidString)") + .path + try FileManager.default.createDirectory( + atPath: mockDirectory, withIntermediateDirectories: true) + + for item in contents { + let itemPath = mockDirectory + "/" + item + if item.hasSuffix(".xcworkspace") || item.hasSuffix(".xcodeproj") { + try FileManager.default.createDirectory(atPath: itemPath, withIntermediateDirectories: true) + } else { + FileManager.default.createFile(atPath: itemPath, contents: nil) + } + } + + return try AbsolutePath(validating: mockDirectory) + } + + /// Test parsing a valid `.xcworkspace` file + @Test func testParseWorkspace() async throws { + // Arrange + let mockDirectory = try createMockDirectory(withContents: ["MyWorkspace.xcworkspace"]) + let workspacePath = mockDirectory.appending(component: "MyWorkspace.xcworkspace") + + // Act + let graph = try await ProjectParser.parse(atPath: workspacePath.pathString) + + // Assert + #expect(graph.name == "MyWorkspace") + } + + /// Test parsing a valid `.xcodeproj` file + @Test func testParseXcodeProject() async throws { + // Arrange + let mockDirectory = try createMockDirectory(withContents: ["MyProject.xcodeproj"]) + let projectPath = mockDirectory.appending(component: "MyProject.xcodeproj") + + // Act + let graph = try await ProjectParser.parse(atPath: projectPath.pathString) + + // Assert + #expect(graph.name == "Workspace") + } + + /// Test parsing when directory contains both `.xcworkspace` and `.xcodeproj` + @Test func testParseDirectoryWithWorkspaceAndProject() async throws { + // Arrange + let mockDirectory = try createMockDirectory(withContents: [ + "MyWorkspace.xcworkspace", "MyProject.xcodeproj", + ]) + + // Act + let graph = try await ProjectParser.parse(atPath: mockDirectory.pathString) + + #expect(graph.name == "MyWorkspace") + } + + /// Test parsing when the directory contains no valid project files + @Test func testParseDirectoryNoProjects() async throws { + // Arrange + let mockDirectory = try createMockDirectory(withContents: ["ReadMe.md", "file.txt"]) + + // Act & Assert + await #expect(throws: MappingError.noProjectsFound) { + try await ProjectParser.parse(atPath: mockDirectory.pathString) + } + } + + /// Test handling a non-existent path + @Test func testParseNonExistentPath() async throws { + // Act & Assert + await #expect(throws: MappingError.pathNotFound(path: "/non/existent/path")) { + try await ProjectParser.parse(atPath: "/non/existent/path") + } + } + + /// Test parsing when only `.xcodeproj` exists in the directory + @Test func testParseDirectoryOnlyXcodeProj() async throws { + // Arrange + let mockDirectory = try createMockDirectory(withContents: ["MyProject.xcodeproj"]) + + // Act + let graph = try await ProjectParser.parse(atPath: mockDirectory.pathString) + + // Assert + #expect(graph.name == "Workspace") + } +} diff --git a/Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift b/Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift new file mode 100644 index 00000000..846ff632 --- /dev/null +++ b/Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift @@ -0,0 +1,88 @@ +import Foundation +import Testing +import XcodeProjToGraph +import TestSupport + +@Suite +struct LipoToolTests { + /// Test that `LipoTool.archs` successfully parses valid output. + @Test func testArchs_ValidOutput() async throws { + // Arrange + let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo "arm64 x86_64" + exit 0 + """) + + // Act + let result = try await LipoTool.archs( + paths: ["/mock/path/to/file"], executablePath: mockExecutablePath) + + // Assert + #expect(result.architectures == [.arm64, .x8664]) + } + + /// Test that `LipoTool.archs` handles a single architecture output. + @Test func testArchs_SingleArchitecture() async throws { + // Arrange + let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo "arm64" + exit 0 + """) + + // Act + let result = try await LipoTool.archs( + paths: ["/mock/path/to/file"], executablePath: mockExecutablePath) + + // Assert + #expect(result.architectures == [.arm64]) + } + + /// Test that `LipoTool.archs` throws an error on non-zero exit code. + @Test func testArchs_NonZeroExitCode() async throws { + // Arrange + let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo "Error: invalid usage" + exit 1 + """) + + // Act & Assert + await #expect(throws: ProcessRunnerError.failedToRunProcess("Lipo returned non-zero exit code.")) { + try await LipoTool.archs(paths: ["/mock/path/to/file"], executablePath: mockExecutablePath) + } + } + + /// Test that `LipoTool.archs` handles empty output gracefully. + @Test func testArchs_EmptyOutput() async throws { + // Arrange + let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo "" + exit 0 + """) + + // Act + let result = try await LipoTool.archs( + paths: ["/mock/path/to/file"], executablePath: mockExecutablePath) + + // Assert + #expect(result.architectures.isEmpty == true) + } + + /// Test that `LipoTool.archs` throws an error if the executable does not exist. + @Test func testArchs_ExecutableNotFound() async throws { + // Arrange + let nonExistentExecutable = "/nonexistent/path/to/lipo" + + // Act & Assert + await #expect(throws: ProcessRunnerError.executableNotFound(nonExistentExecutable)) { + try await LipoTool.archs(paths: ["/mock/path/to/file"], executablePath: nonExistentExecutable) + } + } +} diff --git a/Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift b/Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift new file mode 100644 index 00000000..2078df7b --- /dev/null +++ b/Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift @@ -0,0 +1,187 @@ +import Foundation +import Testing +import XcodeProjToGraph + +@Suite +struct ProcessRunnerTests { + private func createTemporaryExecutable( + name: String = "mockExecutable_\(UUID().uuidString)", + withContent content: String + ) throws -> String { + let tempDirectory = FileManager.default.temporaryDirectory + let mockExecutablePath = tempDirectory.appendingPathComponent(name).path + + // Write the content to the temporary file + try content.write(toFile: mockExecutablePath, atomically: true, encoding: .utf8) + + // Make the file executable + try FileManager.default.setAttributes( + [.posixPermissions: 0o755], ofItemAtPath: mockExecutablePath) + + return mockExecutablePath + } + + /// Test that `ProcessRunner` runs a valid executable successfully and parses the result. + @Test func testRun_ValidExecutable_Success() async throws { + // Arrange + let mockExecutablePath = try createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo "Hello, World!" + exit 0 + """ + ) + + let mockExecutable = Executable.custom( + mockExecutablePath, + [], + { result in + result.stdout.trimmingCharacters(in: .whitespacesAndNewlines) + } + ) + + // Act + let output: String = try await ProcessRunner.run( + executable: mockExecutable, + environment: nil, + workingDirectory: nil, + throwOnNonZeroExit: true + ) + + // Assert + #expect(output == "Hello, World!") + } + + /// Test that `ProcessRunner` throws an error if the executable does not exist. + @Test func testRun_ExecutableNotFound_ThrowsError() async throws { + // Arrange + let nonExistentExecutable = Executable.custom( + "/nonexistent/path", + [], + { _ in } + ) + + // Act & Assert + await #expect(throws: ProcessRunnerError.executableNotFound("/nonexistent/path")) { + try await ProcessRunner.run( + executable: nonExistentExecutable, + environment: nil, + workingDirectory: nil, + throwOnNonZeroExit: true + ) + } + } + + /// Test that `ProcessRunner` throws an error on non-zero exit when `throwOnNonZeroExit` is enabled. + @Test func testRun_NonZeroExitCode_ThrowsError() async throws { + // Arrange + let mockExecutablePath = try createTemporaryExecutable( + withContent: """ + #!/bin/sh + exit 1 + """) + + let mockExecutable = Executable.custom( + mockExecutablePath, + [], + { _ in } + ) + + // Act & Assert + await #expect(throws: ProcessRunnerError.nonZeroExitCode(1, "")) { + try await ProcessRunner.run( + executable: mockExecutable, + environment: nil, + workingDirectory: nil, + throwOnNonZeroExit: true + ) + } + } + + /// Test that `ProcessRunner` does not throw on non-zero exit when `throwOnNonZeroExit` is disabled. + @Test func testRun_NonZeroExitCode_NoThrow() async throws { + // Arrange + let mockExecutablePath = try createTemporaryExecutable( + withContent: """ + #!/bin/sh + exit 1 + """) + + let mockExecutable = Executable.custom( + mockExecutablePath, + [], + { result in + result.exitCode // Simply return the exit code for validation. + } + ) + + // Act + let exitCode: Int32 = try await ProcessRunner.run( + executable: mockExecutable, + environment: nil, + workingDirectory: nil, + throwOnNonZeroExit: false + ) + + #expect(exitCode == 1) + } + + /// Test that `ProcessRunner` parses UTF-8 output correctly. + @Test func testRun_ParsesUtf8Output() async throws { + // Arrange + let mockExecutablePath = try createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo "你好, 世界!" + exit 0 + """) + + let mockExecutable = Executable.custom( + mockExecutablePath, + [], + { result in + result.stdout.trimmingCharacters(in: .whitespacesAndNewlines) + } + ) + + // Act + let output: String = try await ProcessRunner.run( + executable: mockExecutable, + environment: nil, + workingDirectory: nil, + throwOnNonZeroExit: true + ) + + // Assert + #expect(output == "你好, 世界!") + } + + /// Test that `ProcessRunner` throws an error if the output is not valid UTF-8. + @Test func testRun_InvalidUtf8Output_ThrowsError() async throws { + // Arrange + let mockExecutablePath = try createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo -e '\\xff' # Invalid UTF-8 sequence + + """) + + let invalidUtf8Executable = Executable.custom( + mockExecutablePath, + [], + { _ in + throw ProcessRunnerError.invalidUTF8InOutput + } + ) + + // Act & Assert + await #expect(throws: ProcessRunnerError.invalidUTF8InOutput) { + try await ProcessRunner.run( + executable: invalidUtf8Executable, + environment: nil, + workingDirectory: nil, + throwOnNonZeroExit: false + ) + } + } +} diff --git a/Tuist/ProjectDescriptionHelpers/Module.swift b/Tuist/ProjectDescriptionHelpers/Module.swift index c6c1c37e..9ae3f552 100644 --- a/Tuist/ProjectDescriptionHelpers/Module.swift +++ b/Tuist/ProjectDescriptionHelpers/Module.swift @@ -3,6 +3,8 @@ import ProjectDescription public enum Module: String, CaseIterable { case xcodeGraph = "XcodeGraph" + case xcodeProjToGraph = "XcodeProjToGraph" + case testSupport = "TestSupport" public var isRunnable: Bool { switch self { @@ -78,14 +80,16 @@ public enum Module: String, CaseIterable { public var unitTestsTargetName: String? { switch self { - default: + case .xcodeGraph, .xcodeProjToGraph: return "\(rawValue)Tests" + case .testSupport: + return nil } } public var integrationTestsTargetName: String? { switch self { - case .xcodeGraph: + case .xcodeGraph, .xcodeProjToGraph, .testSupport: return nil } } @@ -123,15 +127,33 @@ public enum Module: String, CaseIterable { .external(name: "AnyCodable"), .external(name: "Path"), ] + case .xcodeProjToGraph: + [ + .target(name: Module.xcodeGraph.rawValue), + .external(name: "Path"), + .external(name: "XcodeProj"), + ] + case .testSupport: + [ + .target(name: Module.xcodeProjToGraph.rawValue) + ] + } return dependencies } public var unitTestDependencies: [TargetDependency] { var dependencies: [TargetDependency] = switch self { - case .xcodeGraph: + case .xcodeGraph, .testSupport: + [ + ] + case .xcodeProjToGraph: [ + .target(name: Module.testSupport.rawValue), + .external(name: "InlineSnapshotTesting"), ] + + } dependencies = dependencies + [.target(name: targetName)] return dependencies @@ -139,7 +161,7 @@ public enum Module: String, CaseIterable { public var testingDependencies: [TargetDependency] { let dependencies: [TargetDependency] = switch self { - case .xcodeGraph: + case .xcodeGraph, .xcodeProjToGraph, .testSupport: [ ] } @@ -148,7 +170,7 @@ public enum Module: String, CaseIterable { public var integrationTestsDependencies: [TargetDependency] { var dependencies: [TargetDependency] = switch self { - case .xcodeGraph: + case .xcodeGraph, .xcodeProjToGraph, .testSupport: [] } dependencies.append(.target(name: targetName)) From 3209d11e79d679a84f869cb1e20dfbf77f2ac800 Mon Sep 17 00:00:00 2001 From: Andy Kolean Date: Sun, 15 Dec 2024 16:41:56 -0500 Subject: [PATCH 02/40] lint files --- Package.swift | 14 +- .../App/Sources/ContentView.swift | 16 +- .../App/Sources/MyApp.swift | 44 +- .../Project.swift | 42 +- .../App/Sources/App.swift | 8 +- .../App/Sources/ContentView.swift | 14 +- .../LocalSwiftPackage/Package.swift | 18 +- .../LocalSwiftPackage/LocalSwiftPackage.swift | 2 +- .../Project.swift | 50 +- .../App/Sources/App.swift | 8 +- .../App/Sources/ContentView.swift | 14 +- .../LocalSwiftPackage/Package.swift | 30 +- .../LocalSwiftPackage/LocalSwiftPackage.swift | 4 +- .../Project.swift | 50 +- .../DynamicFramework/DynamicFramework.swift | 2 +- .../Project.swift | 44 +- .../Fixtures/ios_app_large/Project.swift | 22 +- .../ios_app_large/Sources/AppDelegate.swift | 28 +- .../Sources/AppIntentExtension.swift | 8 +- .../Sources/AppIntentExtensionExtension.swift | 2 +- .../Sources/MessagesViewController.swift | 72 +- .../NotificationService.swift | 40 +- .../ios_app_with_extensions/Project.swift | 248 +- .../Sources/AppDelegate.swift | 24 +- .../Sources/StaticFramework.swift | 2 +- .../WidgetExtension/Sources/Widget.swift | 98 +- .../App/Project.swift | 98 +- .../App/Sources/AppDelegate.swift | 24 +- .../App/Tests/AppDelegateTests.swift | 8 +- .../Framework1/Project.swift | 72 +- .../Framework1/Sources/Framework1File.swift | 16 +- .../Tests/Framework1FileTests.swift | 16 +- .../Framework2/Project.swift | 72 +- .../Framework2/Sources/Framework2File.swift | 8 +- .../Tests/Framework2FileTests.swift | 8 +- .../Workspace.swift | 4 +- .../Project.swift | 66 +- .../Sources/AppDelegate.swift | 30 +- .../App/Sources/AppApp.swift | 8 +- .../App/Sources/ContentView.swift | 34 +- .../AppTests/AppTests.swift | 26 +- .../Project.swift | 60 +- .../Tuist/Package.swift | 18 +- .../Modules/A/Project.swift | 62 +- .../Modules/A/Sources/A.swift | 12 +- .../Modules/A/Tests/ATests.swift | 6 +- .../Modules/B/Project.swift | 52 +- .../Modules/B/Sources/B.swift | 8 +- .../Modules/B/Tests/BTests.swift | 6 +- .../Modules/C/Project.swift | 54 +- .../Modules/C/Sources/C.swift | 8 +- .../Modules/C/Tests/CTests.swift | 6 +- .../Project.swift | 50 +- .../Sources/AppDelegate.swift | 26 +- .../Tests/AppTests.swift | 6 +- .../App/Project.swift | 72 +- .../App/Sources/AppDelegate.swift | 20 +- .../App/Tests/AppDelegateTests.swift | 8 +- .../App/UITests/AppUITest.swift | 34 +- .../Framework1/Project.swift | 98 +- .../Framework1/Sources/Framework1File.swift | 16 +- .../Tests/Framework1FileTests.swift | 20 +- .../Framework2/Project.swift | 50 +- .../Framework2/Sources/Framework2File.swift | 8 +- .../StaticFramework1/Project.swift | 50 +- .../Sources/Framework1File.swift | 16 +- .../Tests/Framework1FileTests.swift | 20 +- .../Workspace.swift | 4 +- .../Frameworks/CoreFramework/Project.swift | 52 +- .../CoreFramework/Sources/CoreClass.swift | 2 +- .../Frameworks/DataFramework/Project.swift | 62 +- .../DataFramework/Sources/DataClass.swift | 4 +- .../FeatureAFramework/Project.swift | 68 +- .../Sources/FrameworkA.swift | 10 +- .../Frameworks/FeatureContracts/Project.swift | 64 +- .../Sources/FeatureAContract.swift | 2 +- .../Sources/FeatureBContract.swift | 4 +- .../UIComponentsFramework/Project.swift | 62 +- .../Sources/UIComponentA.swift | 2 +- .../StaticApp/Project.swift | 62 +- .../StaticApp/Sources/AppDelegate.swift | 24 +- .../Workspace.swift | 10 +- .../Project.swift | 42 +- .../App/Sources/ContentView.swift | 22 +- .../App/Sources/TestApp.swift | 14 +- .../ModuleA/Macros/Sources/Macros.swift | 24 +- .../Modules/ModuleA/Sources/Macros.swift | 2 +- .../Modules/ModuleA/Sources/ModuleA.swift | 8 +- .../Modules/ModuleA/Tests/ModuleATests.swift | 28 +- .../Project.swift | 206 +- .../Tuist/Package.swift | 24 +- .../WatchApp/Sources/ContentView.swift | 20 +- .../WatchApp/Sources/WatchApp.swift | 16 +- .../WatchApp/Sources/WatchConfig.swift | 2 +- .../ProjectA/Project.swift | 48 +- .../Targets/App/Sources/AppDelegate.swift | 24 +- .../ProjectA/Targets/App/Tests/AppTests.swift | 6 +- .../ProjectB/Project.swift | 48 +- .../Targets/App/Sources/AppDelegate.swift | 24 +- .../ProjectB/Targets/App/Tests/AppTests.swift | 6 +- .../Workspace.swift | 10 +- .../Mocks/MockBuildFilesAndPhases.swift | 28 +- .../TestSupport/Mocks/MockBuildSettings.swift | 16 +- Sources/TestSupport/Mocks/MockDefaults.swift | 12 +- .../TestSupport/Mocks/MockFileCreator.swift | 23 +- .../TestSupport/Mocks/MockFileStructure.swift | 23 +- .../Mocks/MockProjectAndWorkspace.swift | 30 +- .../Mocks/MockProjectProvider.swift | 65 +- .../Mocks/MockSchemesAndUserData.swift | 14 +- .../Mocks/MockTargetsAndDependencies.swift | 42 +- Sources/TestSupport/WorkspaceFixture.swift | 43 +- .../Extensions/AbsolutePath+Extensions.swift | 146 +- .../Extensions/Package+Extensions.swift | 16 +- .../Extensions/Platform+Extensions.swift | 42 +- .../PlatformFilter+Extensions.swift | 40 +- .../Extensions/Sequence+Async.swift | 34 +- .../TargetDependency+Extensions.swift | 40 +- .../XCWorkspaceDataFileRef+Extensions.swift | 60 +- .../Mappers/Build/BuildPhaseConstants.swift | 50 +- .../Mappers/Build/BuildPhaseMapper.swift | 734 +++--- .../Mappers/Build/BuildRuleMapper.swift | 80 +- .../Mappers/Dependency/DependencyMapper.swift | 238 +- .../Dependency/FileDependencyMapper.swift | 27 +- .../Dependency/PlatformConditionMapper.swift | 24 +- .../TargetDependency+GraphMapping.swift | 468 ++-- .../Mappers/Graph/GraphMapper.swift | 191 +- .../Mappers/Graph/MappingError.swift | 20 +- .../Mappers/Graph/ProjectParser.swift | 164 +- .../Mappers/Project/PackageMapper.swift | 134 +- .../Mappers/Project/ProjectMapper.swift | 253 +- .../Mappers/Project/ProjectProvider.swift | 72 +- .../Mappers/Settings/BuildSettings.swift | 136 +- .../Settings/ConfigurationMatcher.swift | 62 +- .../Mappers/Settings/SettingsMapper.swift | 168 +- .../XCConfigurationList+Helpers.swift | 54 +- .../PBXTarget+BuildHeaders.swift | 8 +- .../PBXTarget+BuildSettings.swift | 84 +- .../PBXTarget+PlatformInference.swift | 136 +- .../SchemeDiagnosticsOptions+XCScheme.swift | 38 +- .../TargetAndSchemes/SchemeMapper.swift | 483 ++-- .../TargetAndSchemes/TargetMapper.swift | 434 ++-- .../Mappers/Workspace/WorkspaceMapper.swift | 194 +- .../Mappers/Workspace/WorkspaceProvider.swift | 32 +- .../ProcessRunner/Executable.swift | 12 +- .../ProcessRunner/Lipo/LipoTool.swift | 2 +- .../ProcessRunner/ProcessRunner.swift | 9 +- .../ProcessRunner/ProcessRunnerError.swift | 30 +- .../XcodeGraphTests/Models/TargetTests.swift | 2 +- .../IntegrationTests/IntegrationTests.swift | 51 +- ...+commandLineToolWithDynamicFramework.swift | 420 ++-- .../IntegrationTests+iosAppLarge.swift | 14 +- ...ntegrationTests+iosAppWithExtensions.swift | 1443 ++++++------ ...egrationTests+iosAppWithMultiConfigs.swift | 1062 ++++----- ...onTests+iosAppWithRemoteSwiftPackage.swift | 462 ++-- ...ationTests+iosAppWithSpmDependencies.swift | 504 ++-- ...ationTests+iosAppWithStaticLibraries.swift | 1144 ++++----- ...icrofeatureArchitectureStaticLinking.swift | 2072 ++++++++--------- ...ts+ios_app_with_transitive_framework.swift | 1608 ++++++------- ...ionTests+macosAppWithSystemExtension.swift | 432 ++-- ...rmAppWithMacrosAndEmbeddedWatchosApp.swift | 1146 ++++----- .../Xcode/Build/BuildPhaseMapperTests.swift | 1018 ++++---- .../Xcode/Build/BuildRuleMapperTests.swift | 235 +- .../Dependency/DependencyMapperTests.swift | 455 ++-- .../TargetDependencyExtensionsTests.swift | 427 ++-- .../Xcode/GraphMapper/GraphMapperTests.swift | 343 ++- .../Xcode/Project/PackageMapperTests.swift | 235 +- .../Xcode/Project/ProjectMapperTests.swift | 291 ++- .../Xcode/Settings/BuildSettingsTests.swift | 106 +- .../Settings/ConfigurationMatcherTests.swift | 47 +- .../Xcode/Settings/SettingsMapperTests.swift | 313 +-- .../Xcode/Target/SchemeMapperTests.swift | 470 ++-- .../Xcode/Target/TargetMapperTests.swift | 282 ++- .../ParserTests/ProjectParserTests.swift | 141 +- .../ProcessTests/LipoToolTests.swift | 141 +- .../ProcessTests/ProcessRunnerTests.swift | 359 +-- Tuist/ProjectDescriptionHelpers/Module.swift | 9 +- 176 files changed, 11730 insertions(+), 11699 deletions(-) diff --git a/Package.swift b/Package.swift index 4aea2c18..68f34628 100644 --- a/Package.swift +++ b/Package.swift @@ -18,24 +18,24 @@ let targets: [Target] = [ dependencies: [ "XcodeGraph", .product(name: "Path", package: "Path"), - .product(name: "XcodeProj", package: "XcodeProj") + .product(name: "XcodeProj", package: "XcodeProj"), ], path: "Sources/XcodeProjToGraph" ), .target( name: "TestSupport", dependencies: [ - "XcodeProjToGraph" + "XcodeProjToGraph", ], path: "Sources/TestSupport", resources: [ - .copy("Fixtures") + .copy("Fixtures"), ] ), .testTarget( name: "XcodeGraphTests", dependencies: [ - "XcodeGraph" + "XcodeGraph", ], path: "Tests/XcodeGraphTests" ), @@ -58,15 +58,15 @@ let package = Package( name: "XcodeGraph", targets: ["XcodeGraph"] ), - .library(name: "XcodeProjToGraph", targets: ["XcodeProjToGraph"]) + .library(name: "XcodeProjToGraph", targets: ["XcodeProjToGraph"]), ], dependencies: [ .package(url: "https://github.com/Flight-School/AnyCodable", .upToNextMajor(from: "0.6.7")), .package(url: "https://github.com/tuist/Path.git", .upToNextMajor(from: "0.3.8")), .package(url: "https://github.com/tuist/XcodeProj", from: "8.25.0"), .package( - url: "https://github.com/pointfreeco/swift-snapshot-testing", - from: "1.17.0" + url: "https://github.com/pointfreeco/swift-snapshot-testing", + from: "1.17.0" ), ], diff --git a/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/ContentView.swift index 9a777ffa..48f62ebe 100644 --- a/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/ContentView.swift +++ b/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/ContentView.swift @@ -1,16 +1,16 @@ import SwiftUI public struct ContentView: View { - public init() {} + public init() {} - public var body: some View { - Text("Hello, World!") - .padding() - } + public var body: some View { + Text("Hello, World!") + .padding() + } } struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } + static var previews: some View { + ContentView() + } } diff --git a/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/MyApp.swift b/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/MyApp.swift index 062a6c94..99a17a49 100644 --- a/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/MyApp.swift +++ b/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/MyApp.swift @@ -3,34 +3,34 @@ import SwiftUI @main struct MyApp: App { - var body: some Scene { - WindowGroup { - ContentView() + var body: some Scene { + WindowGroup { + ContentView() + } } - } } @Reducer struct Counter { - struct State: Equatable { - var count = 0 - } + struct State: Equatable { + var count = 0 + } - enum Action { - case decrementButtonTapped - case incrementButtonTapped - } + enum Action { + case decrementButtonTapped + case incrementButtonTapped + } - var body: some Reducer { - Reduce { state, action in - switch action { - case .decrementButtonTapped: - state.count -= 1 - return .none - case .incrementButtonTapped: - state.count += 1 - return .none - } + var body: some Reducer { + Reduce { state, action in + switch action { + case .decrementButtonTapped: + state.count -= 1 + return .none + case .incrementButtonTapped: + state.count += 1 + return .none + } + } } - } } diff --git a/Sources/TestSupport/Fixtures/app_with_composable_architecture/Project.swift b/Sources/TestSupport/Fixtures/app_with_composable_architecture/Project.swift index 35f89b58..f8edd26b 100644 --- a/Sources/TestSupport/Fixtures/app_with_composable_architecture/Project.swift +++ b/Sources/TestSupport/Fixtures/app_with_composable_architecture/Project.swift @@ -1,25 +1,25 @@ import ProjectDescription let project = Project( - name: "App", - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: .extendingDefault( - with: [ - "UILaunchScreen": [ - "UIColorName": "", - "UIImageName": "", - ] - ] - ), - sources: ["App/Sources/**"], - dependencies: [ - .external(name: "ComposableArchitecture") - ] - ) - ] + name: "App", + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: .extendingDefault( + with: [ + "UILaunchScreen": [ + "UIColorName": "", + "UIImageName": "", + ], + ] + ), + sources: ["App/Sources/**"], + dependencies: [ + .external(name: "ComposableArchitecture"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/App.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/App.swift index 6ca35d65..7cb2ea61 100644 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/App.swift +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/App.swift @@ -2,9 +2,9 @@ import SwiftUI @main struct MyApp: App { - var body: some Scene { - WindowGroup { - ContentView() + var body: some Scene { + WindowGroup { + ContentView() + } } - } } diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/ContentView.swift index fd34c2f1..bcdf9eae 100644 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/ContentView.swift +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/ContentView.swift @@ -2,12 +2,12 @@ import LocalSwiftPackage import SwiftUI public struct ContentView: View { - public init() { - _ = LocalSwiftPackage() - } + public init() { + _ = LocalSwiftPackage() + } - public var body: some View { - Text("Hello, World!") - .padding() - } + public var body: some View { + Text("Hello, World!") + .padding() + } } diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Package.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Package.swift index af29ec24..31c72917 100644 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Package.swift +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Package.swift @@ -3,13 +3,13 @@ import PackageDescription let package = Package( - name: "LocalSwiftPackage", - products: [ - .library(name: "LocalSwiftPackage", targets: ["LocalSwiftPackage"]) - ], - targets: [ - .target( - name: "LocalSwiftPackage" - ) - ] + name: "LocalSwiftPackage", + products: [ + .library(name: "LocalSwiftPackage", targets: ["LocalSwiftPackage"]), + ], + targets: [ + .target( + name: "LocalSwiftPackage" + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift index 0e51666a..e4719258 100644 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift @@ -1,3 +1,3 @@ public final class LocalSwiftPackage { - public init() {} + public init() {} } diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/Project.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/Project.swift index d4685ec9..082f7ec9 100644 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/Project.swift +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/Project.swift @@ -1,29 +1,29 @@ import ProjectDescription let project = Project( - name: "App", - packages: [ - .package(path: "LocalSwiftPackage") - ], - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: .extendingDefault( - with: [ - "UILaunchScreen": [ - "UIColorName": "", - "UIImageName": "", - ] - ] - ), - sources: ["App/Sources/**"], - resources: [], - dependencies: [ - .package(product: "LocalSwiftPackage", type: .runtimeEmbedded) - ] - ) - ] + name: "App", + packages: [ + .package(path: "LocalSwiftPackage"), + ], + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: .extendingDefault( + with: [ + "UILaunchScreen": [ + "UIColorName": "", + "UIImageName": "", + ], + ] + ), + sources: ["App/Sources/**"], + resources: [], + dependencies: [ + .package(product: "LocalSwiftPackage", type: .runtimeEmbedded), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/App.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/App.swift index 6ca35d65..7cb2ea61 100644 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/App.swift +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/App.swift @@ -2,9 +2,9 @@ import SwiftUI @main struct MyApp: App { - var body: some Scene { - WindowGroup { - ContentView() + var body: some Scene { + WindowGroup { + ContentView() + } } - } } diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/ContentView.swift index fd34c2f1..bcdf9eae 100644 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/ContentView.swift +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/ContentView.swift @@ -2,12 +2,12 @@ import LocalSwiftPackage import SwiftUI public struct ContentView: View { - public init() { - _ = LocalSwiftPackage() - } + public init() { + _ = LocalSwiftPackage() + } - public var body: some View { - Text("Hello, World!") - .padding() - } + public var body: some View { + Text("Hello, World!") + .padding() + } } diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Package.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Package.swift index 62fc3932..16ec68c6 100644 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Package.swift +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Package.swift @@ -3,19 +3,19 @@ import PackageDescription let package = Package( - name: "LocalSwiftPackage", - products: [ - .library(name: "LocalSwiftPackage", targets: ["LocalSwiftPackage"]) - ], - dependencies: [ - .package(url: "https://github.com/apple/swift-collections", from: "1.0.0") - ], - targets: [ - .target( - name: "LocalSwiftPackage", - dependencies: [ - .product(name: "Collections", package: "swift-collections") - ] - ) - ] + name: "LocalSwiftPackage", + products: [ + .library(name: "LocalSwiftPackage", targets: ["LocalSwiftPackage"]), + ], + dependencies: [ + .package(url: "https://github.com/apple/swift-collections", from: "1.0.0"), + ], + targets: [ + .target( + name: "LocalSwiftPackage", + dependencies: [ + .product(name: "Collections", package: "swift-collections"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift index c40facea..3d455074 100644 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift @@ -1,6 +1,6 @@ import Collections public final class LocalSwiftPackage { - public init() {} - public var deque: Deque = [] + public init() {} + public var deque: Deque = [] } diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/Project.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/Project.swift index 58474d5a..96abc5b9 100644 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/Project.swift +++ b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/Project.swift @@ -1,29 +1,29 @@ import ProjectDescription let project = Project( - name: "App", - packages: [ - .package(path: "LocalSwiftPackage") - ], - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: .extendingDefault( - with: [ - "UILaunchScreen": [ - "UIColorName": "", - "UIImageName": "", - ] - ] - ), - sources: ["App/Sources/**"], - resources: [], - dependencies: [ - .package(product: "LocalSwiftPackage") - ] - ) - ] + name: "App", + packages: [ + .package(path: "LocalSwiftPackage"), + ], + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: .extendingDefault( + with: [ + "UILaunchScreen": [ + "UIColorName": "", + "UIImageName": "", + ], + ] + ), + sources: ["App/Sources/**"], + resources: [], + dependencies: [ + .package(product: "LocalSwiftPackage"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift index 521b6409..85f562cc 100644 --- a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift +++ b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift @@ -1,5 +1,5 @@ import Foundation public struct DynamicFramework { - public init() {} + public init() {} } diff --git a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Project.swift b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Project.swift index b2595958..137199a9 100644 --- a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Project.swift +++ b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Project.swift @@ -1,26 +1,26 @@ import ProjectDescription let project = Project( - name: "CommandLineTool", - targets: [ - .target( - name: "CommandLineTool", - destinations: [.mac], - product: .commandLineTool, - bundleId: "com.example.commandlinetool", - infoPlist: .default, - sources: "CommandLineTool/**", - dependencies: [ - .target(name: "DynamicFramework") - ] - ), - .target( - name: "DynamicFramework", - destinations: [.mac], - product: .framework, - bundleId: "com.example.dynamicframework", - infoPlist: .default, - sources: "DynamicFramework/**" - ), - ] + name: "CommandLineTool", + targets: [ + .target( + name: "CommandLineTool", + destinations: [.mac], + product: .commandLineTool, + bundleId: "com.example.commandlinetool", + infoPlist: .default, + sources: "CommandLineTool/**", + dependencies: [ + .target(name: "DynamicFramework"), + ] + ), + .target( + name: "DynamicFramework", + destinations: [.mac], + product: .framework, + bundleId: "com.example.dynamicframework", + infoPlist: .default, + sources: "DynamicFramework/**" + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_large/Project.swift b/Sources/TestSupport/Fixtures/ios_app_large/Project.swift index c68b640a..225feb0e 100644 --- a/Sources/TestSupport/Fixtures/ios_app_large/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_large/Project.swift @@ -1,18 +1,18 @@ import ProjectDescription func target(name: String) -> Target { - .target( - name: name, - destinations: .iOS, - product: .app, - bundleId: "io.tuist.\(name)", - infoPlist: .file(path: .relativeToManifest("Info.plist")), - sources: .paths([.relativeToManifest("Sources/**")]), - settings: .settings(base: ["CODE_SIGN_IDENTITY": "", "CODE_SIGNING_REQUIRED": "NO"]) - ) + .target( + name: name, + destinations: .iOS, + product: .app, + bundleId: "io.tuist.\(name)", + infoPlist: .file(path: .relativeToManifest("Info.plist")), + sources: .paths([.relativeToManifest("Sources/**")]), + settings: .settings(base: ["CODE_SIGN_IDENTITY": "", "CODE_SIGNING_REQUIRED": "NO"]) + ) } let project = Project( - name: "App", - targets: (1...300).map { target(name: "App\($0)") } + name: "App", + targets: (1 ... 300).map { target(name: "App\($0)") } ) diff --git a/Sources/TestSupport/Fixtures/ios_app_large/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_large/Sources/AppDelegate.swift index 14f15f2b..c20f5076 100644 --- a/Sources/TestSupport/Fixtures/ios_app_large/Sources/AppDelegate.swift +++ b/Sources/TestSupport/Fixtures/ios_app_large/Sources/AppDelegate.swift @@ -2,20 +2,20 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? + var window: UIWindow? - func application( - _: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() - return true - } + func application( + _: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() + return true + } - func hello() -> String { - "AppDelegate.hello()" - } + func hello() -> String { + "AppDelegate.hello()" + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift index dd03d4b0..ff50fc5f 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift @@ -1,9 +1,9 @@ import AppIntents struct AppIntentExtension: AppIntent { - static var title: LocalizedStringResource = "AppIntentExtension" + static var title: LocalizedStringResource = "AppIntentExtension" - func perform() async throws -> some IntentResult { - .result() - } + func perform() async throws -> some IntentResult { + .result() + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift index 5df8a56a..1fbdaa9a 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift @@ -2,5 +2,5 @@ import AppIntents @main struct AppIntentExtensionExtension: AppIntentsExtension { - // No implementation + // No implementation } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift index fdd9284c..59071594 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift @@ -2,56 +2,52 @@ import Messages import UIKit class MessagesViewController: MSMessagesAppViewController { - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view. - } - // MARK: - Conversation Handling + // MARK: - Conversation Handling - override func willBecomeActive(with _: MSConversation) { - // Called when the extension is about to move from the inactive to active state. - // This will happen when the extension is about to present UI. + override func willBecomeActive(with _: MSConversation) { + // Called when the extension is about to move from the inactive to active state. + // This will happen when the extension is about to present UI. - // Use this method to configure the extension and restore previously stored state. - } + // Use this method to configure the extension and restore previously stored state. + } - override func didResignActive(with _: MSConversation) { - // Called when the extension is about to move from the active to inactive state. - // This will happen when the user dismisses the extension, changes to a different - // conversation or quits Messages. + override func didResignActive(with _: MSConversation) { + // Called when the extension is about to move from the active to inactive state. + // This will happen when the user dismisses the extension, changes to a different + // conversation or quits Messages. - // Use this method to release shared resources, save user data, invalidate timers, - // and store enough state information to restore your extension to its current state - // in case it is terminated later. - } + // Use this method to release shared resources, save user data, invalidate timers, + // and store enough state information to restore your extension to its current state + // in case it is terminated later. + } - override func didReceive(_: MSMessage, conversation _: MSConversation) { - // Called when a message arrives that was generated by another instance of this - // extension on a remote device. + override func didReceive(_: MSMessage, conversation _: MSConversation) { + // Called when a message arrives that was generated by another instance of this + // extension on a remote device. - // Use this method to trigger UI updates in response to the message. - } + // Use this method to trigger UI updates in response to the message. + } - override func didStartSending(_: MSMessage, conversation _: MSConversation) { - // Called when the user taps the send button. - } + override func didStartSending(_: MSMessage, conversation _: MSConversation) { + // Called when the user taps the send button. + } - override func didCancelSending(_: MSMessage, conversation _: MSConversation) { - // Called when the user deletes the message without sending it. + override func didCancelSending(_: MSMessage, conversation _: MSConversation) { + // Called when the user deletes the message without sending it. - // Use this to clean up state related to the deleted message. - } + // Use this to clean up state related to the deleted message. + } - override func willTransition(to _: MSMessagesAppPresentationStyle) { - // Called before the extension transitions to a new presentation style. + override func willTransition(to _: MSMessagesAppPresentationStyle) { + // Called before the extension transitions to a new presentation style. - // Use this method to prepare for the change in presentation style. - } + // Use this method to prepare for the change in presentation style. + } - override func didTransition(to _: MSMessagesAppPresentationStyle) { - // Called after the extension transitions to a new presentation style. + override func didTransition(to _: MSMessagesAppPresentationStyle) { + // Called after the extension transitions to a new presentation style. - // Use this method to finalize any behaviors associated with the change in presentation style. - } + // Use this method to finalize any behaviors associated with the change in presentation style. + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift index 8b8ebc75..b6b54e84 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift @@ -1,30 +1,30 @@ import UserNotifications class NotificationService: UNNotificationServiceExtension { - var contentHandler: ((UNNotificationContent) -> Void)? - var bestAttemptContent: UNMutableNotificationContent? + var contentHandler: ((UNNotificationContent) -> Void)? + var bestAttemptContent: UNMutableNotificationContent? - override func didReceive( - _ request: UNNotificationRequest, - withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void - ) { - self.contentHandler = contentHandler - bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) + override func didReceive( + _ request: UNNotificationRequest, + withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void + ) { + self.contentHandler = contentHandler + bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) - if let bestAttemptContent { - // Modify the notification content here... - bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" + if let bestAttemptContent { + // Modify the notification content here... + bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" - contentHandler(bestAttemptContent) + contentHandler(bestAttemptContent) + } } - } - override func serviceExtensionTimeWillExpire() { - // Called just before the extension will be terminated by the system. - // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will - // be used. - if let contentHandler, let bestAttemptContent { - contentHandler(bestAttemptContent) + override func serviceExtensionTimeWillExpire() { + // Called just before the extension will be terminated by the system. + // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will + // be used. + if let contentHandler, let bestAttemptContent { + contentHandler(bestAttemptContent) + } } - } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Project.swift index 7de95ae0..194d9ba5 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Project.swift @@ -1,128 +1,128 @@ import ProjectDescription let project = Project( - name: "App", - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: "Info.plist", - sources: ["Sources/**"], - dependencies: [ - .target(name: "StickersPackExtension"), - .target(name: "NotificationServiceExtension"), - .target(name: "WidgetExtension"), - .target(name: "AppIntentExtension"), - ] - ), - // We need a separate app to test out Message Extensions - // as having both stickers pack and message extensions in one app - // doesn't seem to be supported. - .target( - name: "AppWithMessagesExtension", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App2", - infoPlist: "Info.plist", - sources: ["Sources/**"], - dependencies: [ - .target(name: "MessageExtension"), - .target(name: "NotificationServiceExtension"), - ] - ), - .target( - name: "StickersPackExtension", - destinations: .iOS, - product: .stickerPackExtension, - bundleId: "io.tuist.App.StickersPackExtension", - infoPlist: .extendingDefault(with: [ - "CFBundleDisplayName": "$(PRODUCT_NAME)", - "NSExtension": [ - "NSExtensionPointIdentifier": "com.apple.message-payload-provider", - "NSExtensionPrincipalClass": "StickerBrowserViewController", - ], - ]), - sources: [], - resources: ["StickersPackExtension/**"], - dependencies: [] - ), - .target( - name: "NotificationServiceExtension", - destinations: .iOS, - product: .appExtension, - bundleId: "io.tuist.App.NotificationServiceExtension", - infoPlist: .extendingDefault(with: [ - "CFBundleDisplayName": "$(PRODUCT_NAME)", - "NSExtension": [ - "NSExtensionPointIdentifier": "com.apple.usernotifications.service", - "NSExtensionPrincipalClass": "$(PRODUCT_MODULE_NAME).NotificationService", - ], - ]), - sources: "NotificationServiceExtension/**", - dependencies: [] - ), - .target( - name: "MessageExtension", - destinations: .iOS, - product: .messagesExtension, - bundleId: "io.tuist.App2.MessageExtension", - infoPlist: .extendingDefault(with: [ - "CFBundleDisplayName": "$(PRODUCT_NAME)", - "NSExtension": [ - "NSExtensionMainStoryboard": "MainInterface", - "NSExtensionPointIdentifier": "com.apple.message-payload-provider", - ], - ]), - sources: "MessageExtension/Sources/**", - resources: "MessageExtension/Resources/**", - dependencies: [] - ), - .target( - name: "WidgetExtension", - destinations: .iOS, - product: .appExtension, - bundleId: "io.tuist.App.WidgetExtension", - infoPlist: .extendingDefault(with: [ - "CFBundleDisplayName": "$(PRODUCT_NAME)", - "NSExtension": [ - "NSExtensionPointIdentifier": "com.apple.widgetkit-extension" - ], - ]), - sources: "WidgetExtension/Sources/**", - resources: "WidgetExtension/Resources/**", - dependencies: [ - .target(name: "Bundle"), - .target(name: "StaticFramework"), - ] - ), - .target( - name: "StaticFramework", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.App.StaticFramework", - infoPlist: .default, - sources: "StaticFramework/Sources/**" - ), - .target( - name: "AppIntentExtension", - destinations: .iOS, - product: .extensionKitExtension, - bundleId: "io.tuist.App.AppIntentExtension", - infoPlist: .extendingDefault(with: [ - "EXAppExtensionAttributes": [ - "EXExtensionPointIdentifier": "com.apple.appintents-extension" - ] - ]), - sources: "AppIntentExtension/Sources/**" - ), - .target( - name: "Bundle", - destinations: .iOS, - product: .bundle, - bundleId: "io.tuist.App.Bundle", - resources: "Bundle/**" - ), - ] + name: "App", + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: "Info.plist", + sources: ["Sources/**"], + dependencies: [ + .target(name: "StickersPackExtension"), + .target(name: "NotificationServiceExtension"), + .target(name: "WidgetExtension"), + .target(name: "AppIntentExtension"), + ] + ), + // We need a separate app to test out Message Extensions + // as having both stickers pack and message extensions in one app + // doesn't seem to be supported. + .target( + name: "AppWithMessagesExtension", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App2", + infoPlist: "Info.plist", + sources: ["Sources/**"], + dependencies: [ + .target(name: "MessageExtension"), + .target(name: "NotificationServiceExtension"), + ] + ), + .target( + name: "StickersPackExtension", + destinations: .iOS, + product: .stickerPackExtension, + bundleId: "io.tuist.App.StickersPackExtension", + infoPlist: .extendingDefault(with: [ + "CFBundleDisplayName": "$(PRODUCT_NAME)", + "NSExtension": [ + "NSExtensionPointIdentifier": "com.apple.message-payload-provider", + "NSExtensionPrincipalClass": "StickerBrowserViewController", + ], + ]), + sources: [], + resources: ["StickersPackExtension/**"], + dependencies: [] + ), + .target( + name: "NotificationServiceExtension", + destinations: .iOS, + product: .appExtension, + bundleId: "io.tuist.App.NotificationServiceExtension", + infoPlist: .extendingDefault(with: [ + "CFBundleDisplayName": "$(PRODUCT_NAME)", + "NSExtension": [ + "NSExtensionPointIdentifier": "com.apple.usernotifications.service", + "NSExtensionPrincipalClass": "$(PRODUCT_MODULE_NAME).NotificationService", + ], + ]), + sources: "NotificationServiceExtension/**", + dependencies: [] + ), + .target( + name: "MessageExtension", + destinations: .iOS, + product: .messagesExtension, + bundleId: "io.tuist.App2.MessageExtension", + infoPlist: .extendingDefault(with: [ + "CFBundleDisplayName": "$(PRODUCT_NAME)", + "NSExtension": [ + "NSExtensionMainStoryboard": "MainInterface", + "NSExtensionPointIdentifier": "com.apple.message-payload-provider", + ], + ]), + sources: "MessageExtension/Sources/**", + resources: "MessageExtension/Resources/**", + dependencies: [] + ), + .target( + name: "WidgetExtension", + destinations: .iOS, + product: .appExtension, + bundleId: "io.tuist.App.WidgetExtension", + infoPlist: .extendingDefault(with: [ + "CFBundleDisplayName": "$(PRODUCT_NAME)", + "NSExtension": [ + "NSExtensionPointIdentifier": "com.apple.widgetkit-extension", + ], + ]), + sources: "WidgetExtension/Sources/**", + resources: "WidgetExtension/Resources/**", + dependencies: [ + .target(name: "Bundle"), + .target(name: "StaticFramework"), + ] + ), + .target( + name: "StaticFramework", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.App.StaticFramework", + infoPlist: .default, + sources: "StaticFramework/Sources/**" + ), + .target( + name: "AppIntentExtension", + destinations: .iOS, + product: .extensionKitExtension, + bundleId: "io.tuist.App.AppIntentExtension", + infoPlist: .extendingDefault(with: [ + "EXAppExtensionAttributes": [ + "EXExtensionPointIdentifier": "com.apple.appintents-extension", + ], + ]), + sources: "AppIntentExtension/Sources/**" + ), + .target( + name: "Bundle", + destinations: .iOS, + product: .bundle, + bundleId: "io.tuist.App.Bundle", + resources: "Bundle/**" + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift index 9796fd0b..19603be9 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift @@ -2,17 +2,17 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? + var window: UIWindow? - func application( - _: UIApplication, - didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() - return true - } + func application( + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() + return true + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift index cc50ecff..60900e58 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift @@ -1,5 +1,5 @@ import Foundation public struct StaticFramework { - public init() {} + public init() {} } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift index 21d02b91..eac88f57 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift @@ -1,69 +1,69 @@ #if canImport(WidgetKit) - import SwiftUI - import WidgetKit + import SwiftUI + import WidgetKit - struct Provider: TimelineProvider { - public typealias Entry = SimpleEntry + struct Provider: TimelineProvider { + public typealias Entry = SimpleEntry - func placeholder(in _: Context) -> SimpleEntry { - SimpleEntry(date: Date()) - } + func placeholder(in _: Context) -> SimpleEntry { + SimpleEntry(date: Date()) + } - func getSnapshot(in _: Context, completion _: @escaping (SimpleEntry) -> Void) {} + func getSnapshot(in _: Context, completion _: @escaping (SimpleEntry) -> Void) {} - func getTimeline(in _: Context, completion _: @escaping (Timeline) -> Void) {} + func getTimeline(in _: Context, completion _: @escaping (Timeline) -> Void) {} - public func snapshot(with _: Context, completion: @escaping (SimpleEntry) -> Void) { - let entry = SimpleEntry(date: Date()) - completion(entry) - } + public func snapshot(with _: Context, completion: @escaping (SimpleEntry) -> Void) { + let entry = SimpleEntry(date: Date()) + completion(entry) + } - public func timeline(with _: Context, completion: @escaping (Timeline) -> Void) { - var entries: [SimpleEntry] = [] + public func timeline(with _: Context, completion: @escaping (Timeline) -> Void) { + var entries: [SimpleEntry] = [] - // Generate a timeline consisting of five entries an hour apart, starting from the current date. - let currentDate = Date() - for hourOffset in 0..<5 { - let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! - let entry = SimpleEntry(date: entryDate) - entries.append(entry) - } + // Generate a timeline consisting of five entries an hour apart, starting from the current date. + let currentDate = Date() + for hourOffset in 0 ..< 5 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! + let entry = SimpleEntry(date: entryDate) + entries.append(entry) + } - let timeline = Timeline(entries: entries, policy: .atEnd) - completion(timeline) + let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) + } } - } - struct SimpleEntry: TimelineEntry { - public let date: Date - } + struct SimpleEntry: TimelineEntry { + public let date: Date + } - struct PlaceholderView: View { - var body: some View { - Text("Placeholder View") + struct PlaceholderView: View { + var body: some View { + Text("Placeholder View") + } } - } - struct MyWidgetEntryView: View { - var entry: Provider.Entry + struct MyWidgetEntryView: View { + var entry: Provider.Entry - var body: some View { - Text(entry.date, style: .time) + var body: some View { + Text(entry.date, style: .time) + } } - } - - @main - struct MyWidget: Widget { - private let kind: String = "MyWidget" - - public var body: some WidgetConfiguration { - StaticConfiguration(kind: kind, provider: Provider()) { entry in - MyWidgetEntryView(entry: entry) - } - .configurationDisplayName("MyWidget") - .description("This is an example widget.") + + @main + struct MyWidget: Widget { + private let kind: String = "MyWidget" + + public var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: Provider()) { entry in + MyWidgetEntryView(entry: entry) + } + .configurationDisplayName("MyWidget") + .description("This is an example widget.") + } } - } #endif diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Project.swift index 5281caf5..fe92251b 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Project.swift @@ -1,62 +1,62 @@ import ProjectDescription let settings: Settings = .settings( - base: [ - "PROJECT_BASE": "PROJECT_BASE" - ], - configurations: [ - .debug(name: "Debug", xcconfig: "../ConfigurationFiles/Debug.xcconfig"), - .release(name: "Beta", xcconfig: "../ConfigurationFiles/Beta.xcconfig"), - .release(name: "Release", xcconfig: "../ConfigurationFiles/Release.xcconfig"), - ] + base: [ + "PROJECT_BASE": "PROJECT_BASE", + ], + configurations: [ + .debug(name: "Debug", xcconfig: "../ConfigurationFiles/Debug.xcconfig"), + .release(name: "Beta", xcconfig: "../ConfigurationFiles/Beta.xcconfig"), + .release(name: "Release", xcconfig: "../ConfigurationFiles/Release.xcconfig"), + ] ) let betaScheme: Scheme = .scheme( - name: "App-Beta", - shared: true, - buildAction: .buildAction(targets: ["App"]), - runAction: .runAction(configuration: "Beta", executable: "App"), - archiveAction: .archiveAction(configuration: "Beta"), - profileAction: .profileAction(configuration: "Release", executable: "App"), - analyzeAction: .analyzeAction(configuration: "Debug") + name: "App-Beta", + shared: true, + buildAction: .buildAction(targets: ["App"]), + runAction: .runAction(configuration: "Beta", executable: "App"), + archiveAction: .archiveAction(configuration: "Beta"), + profileAction: .profileAction(configuration: "Release", executable: "App"), + analyzeAction: .analyzeAction(configuration: "Debug") ) let betaArchiveOnlyScheme: Scheme = .scheme( - name: "App-Beta-ArchiveOnly", - shared: true, - archiveAction: .archiveAction(configuration: "Beta") + name: "App-Beta-ArchiveOnly", + shared: true, + archiveAction: .archiveAction(configuration: "Beta") ) let project = Project( - name: "MainApp", - settings: settings, - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: "Support/App-Info.plist", - sources: "Sources/**", - dependencies: [ - .project(target: "Framework1", path: "../Framework1"), - .project(target: "Framework2", path: "../Framework2"), - ] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.AppTests", - infoPlist: "Support/AppTests-Info.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "App") - ] - ), - ], - schemes: [ - betaScheme, - betaArchiveOnlyScheme, - ] + name: "MainApp", + settings: settings, + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: "Support/App-Info.plist", + sources: "Sources/**", + dependencies: [ + .project(target: "Framework1", path: "../Framework1"), + .project(target: "Framework2", path: "../Framework2"), + ] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.AppTests", + infoPlist: "Support/AppTests-Info.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "App"), + ] + ), + ], + schemes: [ + betaScheme, + betaArchiveOnlyScheme, + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift index 862a74f6..7c643d2c 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift @@ -4,20 +4,20 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? + var window: UIWindow? - func applicationDidFinishLaunching(_: UIApplication) { - let framework1 = Framework1File() - let framework2 = Framework2File() + func applicationDidFinishLaunching(_: UIApplication) { + let framework1 = Framework1File() + let framework2 = Framework2File() - print(hello()) + print(hello()) - print("AppDelegate -> \(framework1.hello())") - print("AppDelegate -> \(framework1.helloFromFramework2())") - print("AppDelegate -> \(framework2.hello())") - } + print("AppDelegate -> \(framework1.hello())") + print("AppDelegate -> \(framework1.helloFromFramework2())") + print("AppDelegate -> \(framework2.hello())") + } - func hello() -> String { - "AppDelegate.hello()" - } + func hello() -> String { + "AppDelegate.hello()" + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift index cf59e05b..27fb5d7e 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift @@ -3,9 +3,9 @@ import XCTest @testable import App class AppDelegateTests: XCTestCase { - func testHello() { - let sut = AppDelegate() + func testHello() { + let sut = AppDelegate() - XCTAssertEqual("AppDelegate.hello()", sut.hello()) - } + XCTAssertEqual("AppDelegate.hello()", sut.hello()) + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Project.swift index 34fba0ea..f275b144 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Project.swift @@ -1,43 +1,43 @@ import ProjectDescription let settings: Settings = .settings( - base: [ - "PROJECT_BASE": "PROJECT_BASE" - ], - configurations: [ - .debug(name: "Debug", xcconfig: "../ConfigurationFiles/Debug.xcconfig"), - .release(name: "Beta", xcconfig: "../ConfigurationFiles/Beta.xcconfig"), - .release(name: "Release", xcconfig: "../ConfigurationFiles/Release.xcconfig"), - ] + base: [ + "PROJECT_BASE": "PROJECT_BASE", + ], + configurations: [ + .debug(name: "Debug", xcconfig: "../ConfigurationFiles/Debug.xcconfig"), + .release(name: "Beta", xcconfig: "../ConfigurationFiles/Beta.xcconfig"), + .release(name: "Release", xcconfig: "../ConfigurationFiles/Release.xcconfig"), + ] ) let project = Project( - name: "Framework1", - settings: settings, - targets: [ - .target( - name: "Framework1", - destinations: .iOS, - product: .framework, - productName: "Framework1", - bundleId: "io.tuist.Framework1", - infoPlist: "Support/Framework1-Info.plist", - sources: "Sources/**", - dependencies: [ - .project(target: "Framework2", path: "../Framework2") - ] - ), - .target( - name: "Framework1Tests", - destinations: .iOS, - product: .unitTests, - productName: "Framework1Tests", - bundleId: "io.tuist.Framework1Tests", - infoPlist: "Support/Framework1Tests-Info.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "Framework1") - ] - ), - ] + name: "Framework1", + settings: settings, + targets: [ + .target( + name: "Framework1", + destinations: .iOS, + product: .framework, + productName: "Framework1", + bundleId: "io.tuist.Framework1", + infoPlist: "Support/Framework1-Info.plist", + sources: "Sources/**", + dependencies: [ + .project(target: "Framework2", path: "../Framework2"), + ] + ), + .target( + name: "Framework1Tests", + destinations: .iOS, + product: .unitTests, + productName: "Framework1Tests", + bundleId: "io.tuist.Framework1Tests", + infoPlist: "Support/Framework1Tests-Info.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "Framework1"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift index db42cbcb..6a448706 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift @@ -2,15 +2,15 @@ import Foundation import Framework2 public class Framework1File { - private let framework2File = Framework2File() + private let framework2File = Framework2File() - public init() {} + public init() {} - public func hello() -> String { - "Framework1File.hello()" - } + public func hello() -> String { + "Framework1File.hello()" + } - public func helloFromFramework2() -> String { - "Framework1File -> \(framework2File.hello())" - } + public func helloFromFramework2() -> String { + "Framework1File -> \(framework2File.hello())" + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift index 9a1ef6da..8086614a 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift @@ -3,15 +3,15 @@ import XCTest @testable import Framework1 class Framework1Tests: XCTestCase { - func testHello() { - let sut = Framework1File() + func testHello() { + let sut = Framework1File() - XCTAssertEqual("Framework1File.hello()", sut.hello()) - } + XCTAssertEqual("Framework1File.hello()", sut.hello()) + } - func testHelloFromFramework2() { - let sut = Framework1File() + func testHelloFromFramework2() { + let sut = Framework1File() - XCTAssertEqual("Framework1File -> Framework2File.hello()", sut.helloFromFramework2()) - } + XCTAssertEqual("Framework1File -> Framework2File.hello()", sut.helloFromFramework2()) + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Project.swift index 383a060f..bbec1c7f 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Project.swift @@ -1,47 +1,47 @@ import ProjectDescription let settings: Settings = .settings( - configurations: [ - .debug(name: "Debug", xcconfig: "../ConfigurationFiles/Debug.xcconfig"), - .release(name: "Beta", xcconfig: "../ConfigurationFiles/Beta.xcconfig"), - .release(name: "Release", xcconfig: "../ConfigurationFiles/Release.xcconfig"), - ] + configurations: [ + .debug(name: "Debug", xcconfig: "../ConfigurationFiles/Debug.xcconfig"), + .release(name: "Beta", xcconfig: "../ConfigurationFiles/Beta.xcconfig"), + .release(name: "Release", xcconfig: "../ConfigurationFiles/Release.xcconfig"), + ] ) // Targets can override select configurations if needed let targetSettings: Settings = .settings( - base: [ - "TARGET_BASE": "TARGET_BASE" - ], - configurations: [ - .release(name: "Beta", xcconfig: "../ConfigurationFiles/Target.Beta.xcconfig") - ] + base: [ + "TARGET_BASE": "TARGET_BASE", + ], + configurations: [ + .release(name: "Beta", xcconfig: "../ConfigurationFiles/Target.Beta.xcconfig"), + ] ) let project = Project( - name: "Framework2", - settings: settings, - targets: [ - .target( - name: "Framework2", - destinations: .iOS, - product: .framework, - bundleId: "io.tuist.Framework2", - infoPlist: "Support/Framework2-Info.plist", - sources: "Sources/**", - dependencies: [], - settings: targetSettings - ), - .target( - name: "Framework2Tests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.Framework2Tests", - infoPlist: "Support/Framework2Tests-Info.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "Framework2") - ] - ), - ] + name: "Framework2", + settings: settings, + targets: [ + .target( + name: "Framework2", + destinations: .iOS, + product: .framework, + bundleId: "io.tuist.Framework2", + infoPlist: "Support/Framework2-Info.plist", + sources: "Sources/**", + dependencies: [], + settings: targetSettings + ), + .target( + name: "Framework2Tests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.Framework2Tests", + infoPlist: "Support/Framework2Tests-Info.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "Framework2"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift index f3102dcd..62754f40 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift @@ -1,9 +1,9 @@ import Foundation public class Framework2File { - public init() {} + public init() {} - public func hello() -> String { - "Framework2File.hello()" - } + public func hello() -> String { + "Framework2File.hello()" + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift index c96eef5f..c5f88aba 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift @@ -3,9 +3,9 @@ import XCTest @testable import Framework2 class Framework2Tests: XCTestCase { - func testHello() { - let sut = Framework2File() + func testHello() { + let sut = Framework2File() - XCTAssertEqual("Framework2File.hello()", sut.hello()) - } + XCTAssertEqual("Framework2File.hello()", sut.hello()) + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Workspace.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Workspace.swift index f9fb261a..929bf3b5 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Workspace.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Workspace.swift @@ -1,6 +1,6 @@ import ProjectDescription let workspace = Workspace( - name: "Workspace", - projects: ["App", "Framework1", "Framework2"] + name: "Workspace", + projects: ["App", "Framework1", "Framework2"] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Project.swift index 113474ef..68086b05 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Project.swift @@ -1,37 +1,37 @@ import ProjectDescription let project = Project( - name: "App", - packages: [ - .package(url: "https://github.com/ReactiveX/RxSwift", .upToNextMajor(from: "5.0.0")) - ], - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: "Support/Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ], - dependencies: [ - .package(product: "RxSwift"), - .package(product: "RxBlocking"), - ] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.AppTests", - infoPlist: "Support/Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "App") - ] - ), - ] + name: "App", + packages: [ + .package(url: "https://github.com/ReactiveX/RxSwift", .upToNextMajor(from: "5.0.0")), + ], + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: "Support/Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ], + dependencies: [ + .package(product: "RxSwift"), + .package(product: "RxBlocking"), + ] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.AppTests", + infoPlist: "Support/Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "App"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift index 2049b986..034e8222 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift @@ -4,22 +4,22 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? + var window: UIWindow? - func application( - _: UIApplication, - didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - // To make sure RxSwift is available - let observable = RxSwift.Observable.just("Test") + func application( + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + // To make sure RxSwift is available + let observable = RxSwift.Observable.just("Test") - let result = RxBlocking.MaterializedSequenceResult.completed(elements: [1, 2]) + let result = RxBlocking.MaterializedSequenceResult.completed(elements: [1, 2]) - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() - return true - } + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() + return true + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift index 9a54aeba..1295f66a 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift @@ -2,9 +2,9 @@ import SwiftUI @main struct AppApp: App { - var body: some Scene { - WindowGroup { - ContentView() + var body: some Scene { + WindowGroup { + ContentView() + } } - } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift index ecd023f7..8641548a 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift @@ -5,26 +5,26 @@ import Pay import SwiftUI struct ContentView: View { - init() { - // Use Mobile Buy SDK - _ = Card.CreditCard(firstName: "", lastName: "", number: "", expiryMonth: "", expiryYear: "") - _ = PayAddress() - // Use KSCrash - _ = CrashInstallationStandard() - // Use JWTKit - _ = JWTKit.ES256PrivateKey() - } + init() { + // Use Mobile Buy SDK + _ = Card.CreditCard(firstName: "", lastName: "", number: "", expiryMonth: "", expiryYear: "") + _ = PayAddress() + // Use KSCrash + _ = CrashInstallationStandard() + // Use JWTKit + _ = JWTKit.ES256PrivateKey() + } - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - Text("Hello, world!") + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + Text("Hello, world!") + } + .padding() } - .padding() - } } #Preview { - ContentView() + ContentView() } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift index 2e6edc5b..3413db38 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift @@ -3,19 +3,19 @@ import XCTest @testable import App final class AppTests: XCTestCase { - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Project.swift index bce1f982..d23b92ff 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Project.swift @@ -1,34 +1,34 @@ import ProjectDescription let project = Project( - name: "App", - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.app", - deploymentTargets: .iOS("16.0"), - infoPlist: .default, - sources: "App/Sources/**", - resources: "App/Resources/**", - dependencies: [ - .external(name: "Buy"), - .external(name: "Pay"), - .external(name: "Installations"), - .external(name: "JWTKit"), - .sdk(name: "c++", type: .library, status: .required), - ] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.app.tests", - deploymentTargets: .iOS("16.0"), - infoPlist: .default, - sources: "AppTests/**", - dependencies: [.target(name: "App")] - ), - ] + name: "App", + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.app", + deploymentTargets: .iOS("16.0"), + infoPlist: .default, + sources: "App/Sources/**", + resources: "App/Resources/**", + dependencies: [ + .external(name: "Buy"), + .external(name: "Pay"), + .external(name: "Installations"), + .external(name: "JWTKit"), + .sdk(name: "c++", type: .library, status: .required), + ] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.app.tests", + deploymentTargets: .iOS("16.0"), + infoPlist: .default, + sources: "AppTests/**", + dependencies: [.target(name: "App")] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.swift index b607e964..fc630526 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.swift @@ -2,13 +2,13 @@ @preconcurrency import PackageDescription let package = Package( - name: "PackageName", - dependencies: [ - // Has space symbols in package name - .package(url: "https://github.com/Shopify/mobile-buy-sdk-ios", exact: "12.0.0"), - // Has targets with slash symbols in their names - .package(url: "https://github.com/kstenerud/KSCrash", exact: "2.0.0-rc.3"), - // Has custom `swiftSettings` and uses the package access level - .package(url: "https://github.com/vapor/jwt-kit.git", .upToNextMajor(from: "5.0.0-beta.2.1")), - ] + name: "PackageName", + dependencies: [ + // Has space symbols in package name + .package(url: "https://github.com/Shopify/mobile-buy-sdk-ios", exact: "12.0.0"), + // Has targets with slash symbols in their names + .package(url: "https://github.com/kstenerud/KSCrash", exact: "2.0.0-rc.3"), + // Has custom `swiftSettings` and uses the package access level + .package(url: "https://github.com/vapor/jwt-kit.git", .upToNextMajor(from: "5.0.0-beta.2.1")), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Project.swift index 625f477d..9dfa3e4a 100755 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Project.swift @@ -1,36 +1,36 @@ import ProjectDescription let project = Project( - name: "A", - targets: [ - .target( - name: "A", - destinations: .iOS, - product: .staticLibrary, - bundleId: "io.tuist.A", - infoPlist: nil, - sources: "Sources/**", - dependencies: [ - .project(target: "B", path: "../B"), - .library( - path: "../C/prebuilt/C/libC.a", - publicHeaders: "../C/prebuilt/C", - swiftModuleMap: "../C/prebuilt/C/C.swiftmodule" - ), - ], + name: "A", + targets: [ + .target( + name: "A", + destinations: .iOS, + product: .staticLibrary, + bundleId: "io.tuist.A", + infoPlist: nil, + sources: "Sources/**", + dependencies: [ + .project(target: "B", path: "../B"), + .library( + path: "../C/prebuilt/C/libC.a", + publicHeaders: "../C/prebuilt/C", + swiftModuleMap: "../C/prebuilt/C/C.swiftmodule" + ), + ], - settings: .settings(base: ["HEADER_SEARCH_PATHS": "$(SRCROOT)/CustomHeaders"]) - ), - .target( - name: "ATests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.ATests", - infoPlist: nil, - sources: "Tests/**", - dependencies: [ - .target(name: "A") - ] - ), - ] + settings: .settings(base: ["HEADER_SEARCH_PATHS": "$(SRCROOT)/CustomHeaders"]) + ), + .target( + name: "ATests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.ATests", + infoPlist: nil, + sources: "Tests/**", + dependencies: [ + .target(name: "A"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift index 55130f98..a9cd1519 100755 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift @@ -2,11 +2,11 @@ import B import C public enum A { - public static let value: String = "aValue" + public static let value: String = "aValue" - public static func printFromA() { - print("print from A") - B.printFromB() - C.printFromC() - } + public static func printFromA() { + print("print from A") + B.printFromB() + C.printFromC() + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift index c1848d89..974713b4 100755 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift @@ -4,7 +4,7 @@ import XCTest @testable import A final class ATests: XCTestCase { - func test_value() { - XCTAssertEqual(A.value, "aValue") - } + func test_value() { + XCTAssertEqual(A.value, "aValue") + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Project.swift index 5b80005d..50e3d978 100755 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Project.swift @@ -1,30 +1,30 @@ import ProjectDescription let project = Project( - name: "B", - targets: [ - .target( - name: "B", - destinations: .iOS, - product: .staticLibrary, - bundleId: "io.tuist.B", - infoPlist: "Info.plist", - sources: "Sources/**", - dependencies: [ - /* Target dependencies can be defined here */ - /* .framework(path: "framework") */ - ] - ), - .target( - name: "BTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.BTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "B") - ] - ), - ] + name: "B", + targets: [ + .target( + name: "B", + destinations: .iOS, + product: .staticLibrary, + bundleId: "io.tuist.B", + infoPlist: "Info.plist", + sources: "Sources/**", + dependencies: [ + /* Target dependencies can be defined here */ + /* .framework(path: "framework") */ + ] + ), + .target( + name: "BTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.BTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "B"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift index 10a98b5a..92fcf9d6 100755 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift @@ -1,9 +1,9 @@ import Foundation public enum B { - public static let value: String = "bValue" + public static let value: String = "bValue" - public static func printFromB() { - print("print from B") - } + public static func printFromB() { + print("print from B") + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift index c262f528..718b056f 100755 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift @@ -4,7 +4,7 @@ import XCTest @testable import B final class BTests: XCTestCase { - func test_value() { - XCTAssertEqual(B.value, "bValue") - } + func test_value() { + XCTAssertEqual(B.value, "bValue") + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Project.swift index 11bb4d1c..c78a1249 100755 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Project.swift @@ -1,31 +1,31 @@ import ProjectDescription let project = Project( - name: "C", - targets: [ - .target( - name: "C", - destinations: .iOS, - product: .staticLibrary, - bundleId: "io.tuist.C", - infoPlist: "Info.plist", - sources: "Sources/**", - dependencies: [ - /* Target dependencies can be defined here */ - /* .framework(path: "framework") */ - ], - settings: .settings(base: ["BUILD_LIBRARY_FOR_DISTRIBUTION": "YES"]) - ), - .target( - name: "CTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.BTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "C") - ] - ), - ] + name: "C", + targets: [ + .target( + name: "C", + destinations: .iOS, + product: .staticLibrary, + bundleId: "io.tuist.C", + infoPlist: "Info.plist", + sources: "Sources/**", + dependencies: [ + /* Target dependencies can be defined here */ + /* .framework(path: "framework") */ + ], + settings: .settings(base: ["BUILD_LIBRARY_FOR_DISTRIBUTION": "YES"]) + ), + .target( + name: "CTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.BTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "C"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Sources/C.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Sources/C.swift index 31ab0a24..7d7ac4ce 100755 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Sources/C.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Sources/C.swift @@ -1,9 +1,9 @@ import Foundation public enum C { - public static let value: String = "cValue" + public static let value: String = "cValue" - public static func printFromC() { - print("print from C") - } + public static func printFromC() { + print("print from C") + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests/CTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests/CTests.swift index 8ab03e78..0e81b037 100755 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests/CTests.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests/CTests.swift @@ -4,7 +4,7 @@ import XCTest @testable import C final class BTests: XCTestCase { - func test_value() { - XCTAssertEqual(C.value, "cValue") - } + func test_value() { + XCTAssertEqual(C.value, "cValue") + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Project.swift index bc51dda9..fb70657a 100755 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Project.swift @@ -1,29 +1,29 @@ import ProjectDescription let project = Project( - name: "iOSAppWithTransistiveStaticLibraries", - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: "Info.plist", - sources: "Sources/**", - dependencies: [ - .project(target: "A", path: "Modules/A") - ] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.AppTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "App") - ] - ), - ] + name: "iOSAppWithTransistiveStaticLibraries", + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: "Info.plist", + sources: "Sources/**", + dependencies: [ + .project(target: "A", path: "Modules/A"), + ] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.AppTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "App"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift index 9eaed6c1..8b7921af 100755 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift @@ -3,23 +3,23 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? + var window: UIWindow? - func application( - _: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() + func application( + _: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() - A.printFromA() + A.printFromA() - return true - } + return true + } } public enum AClassInThisBundle { - public static let value: String = "aValue" + public static let value: String = "aValue" } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift index 18a4eda2..c21d831c 100755 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift @@ -4,7 +4,7 @@ import XCTest @testable import App final class AppTests: XCTestCase { - func test_application() { - XCTAssertEqual(App.AClassInThisBundle.value, "aValue") - } + func test_application() { + XCTAssertEqual(App.AClassInThisBundle.value, "aValue") + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Project.swift index 4fbc6fc6..7cdc60c8 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Project.swift @@ -1,40 +1,40 @@ import ProjectDescription let project = Project( - name: "MainApp", - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: "Config/App-Info.plist", - sources: "Sources/**", - dependencies: [ - .project(target: "Framework1-iOS", path: "../Framework1") - ] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.AppTests", - infoPlist: "Config/AppTests-Info.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "App") - ] - ), - .target( - name: "AppUITests", - destinations: .iOS, - product: .uiTests, - bundleId: "io.tuist.AppUITests", - infoPlist: "Config/AppTests-Info.plist", - sources: "UITests/**", - dependencies: [ - .target(name: "App") - ] - ), - ] + name: "MainApp", + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.App", + infoPlist: "Config/App-Info.plist", + sources: "Sources/**", + dependencies: [ + .project(target: "Framework1-iOS", path: "../Framework1"), + ] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.AppTests", + infoPlist: "Config/AppTests-Info.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "App"), + ] + ), + .target( + name: "AppUITests", + destinations: .iOS, + product: .uiTests, + bundleId: "io.tuist.AppUITests", + infoPlist: "Config/AppTests-Info.plist", + sources: "UITests/**", + dependencies: [ + .target(name: "App"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift index 2b97535e..b6e56621 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift @@ -3,17 +3,17 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? + var window: UIWindow? - func applicationDidFinishLaunching(_: UIApplication) { - let framework1 = Framework1File() + func applicationDidFinishLaunching(_: UIApplication) { + let framework1 = Framework1File() - print(hello()) - print("AppDelegate -> \(framework1.hello())") - print("AppDelegate -> \(framework1.helloFromFramework2())") - } + print(hello()) + print("AppDelegate -> \(framework1.hello())") + print("AppDelegate -> \(framework1.helloFromFramework2())") + } - func hello() -> String { - "AppDelegate.hello()" - } + func hello() -> String { + "AppDelegate.hello()" + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift index cf59e05b..27fb5d7e 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift @@ -3,9 +3,9 @@ import XCTest @testable import App class AppDelegateTests: XCTestCase { - func testHello() { - let sut = AppDelegate() + func testHello() { + let sut = AppDelegate() - XCTAssertEqual("AppDelegate.hello()", sut.hello()) - } + XCTAssertEqual("AppDelegate.hello()", sut.hello()) + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift index 90376ef8..85fb9d5f 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift @@ -1,26 +1,26 @@ import XCTest class AppUITest: XCTestCase { - override func setUp() { - // Put setup code here. This method is called before the invocation of each test method in the class. + override func setUp() { + // Put setup code here. This method is called before the invocation of each test method in the class. - // In UI tests it is usually best to stop immediately when a failure occurs. - continueAfterFailure = false + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false - // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test - // method. - XCUIApplication().launch() + // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test + // method. + XCUIApplication().launch() - // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before - // they run. The setUp method is a good place to do this. - } + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before + // they run. The setUp method is a good place to do this. + } - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } - func testExample() { - // Use recording to get started writing UI tests. - // Use XCTAssert and related functions to verify your tests produce the correct results. - } + func testExample() { + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Project.swift index bf1a3b58..9628d4d5 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Project.swift @@ -1,53 +1,53 @@ import ProjectDescription let project = Project( - name: "Framework1", - targets: [ - .target( - name: "Framework1-iOS", - destinations: .iOS, - product: .framework, - productName: "Framework1", - bundleId: "io.tuist.Framework1", - infoPlist: "Config/Framework1-Info.plist", - sources: "Sources/**", - dependencies: [ - .framework(path: "../Framework2/prebuilt/iOS/Framework2.framework") - ] - ), - .target( - name: "Framework1-macOS", - destinations: [.mac], - product: .framework, - productName: "Framework1", - bundleId: "io.tuist.Framework1", - infoPlist: "Config/Framework1-Info.plist", - sources: "Sources/**", - dependencies: [ - .framework(path: "../Framework2/prebuilt/Mac/Framework2.framework") - ] - ), - .target( - name: "Framework1Tests-iOS", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.Framework1Tests", - infoPlist: "Tests/Info.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "Framework1-iOS") - ] - ), - .target( - name: "Framework1Tests-macOS", - destinations: [.mac], - product: .unitTests, - bundleId: "io.tuist.Framework1Tests", - infoPlist: "Tests/Info.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "Framework1-macOS") - ] - ), - ] + name: "Framework1", + targets: [ + .target( + name: "Framework1-iOS", + destinations: .iOS, + product: .framework, + productName: "Framework1", + bundleId: "io.tuist.Framework1", + infoPlist: "Config/Framework1-Info.plist", + sources: "Sources/**", + dependencies: [ + .framework(path: "../Framework2/prebuilt/iOS/Framework2.framework"), + ] + ), + .target( + name: "Framework1-macOS", + destinations: [.mac], + product: .framework, + productName: "Framework1", + bundleId: "io.tuist.Framework1", + infoPlist: "Config/Framework1-Info.plist", + sources: "Sources/**", + dependencies: [ + .framework(path: "../Framework2/prebuilt/Mac/Framework2.framework"), + ] + ), + .target( + name: "Framework1Tests-iOS", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.Framework1Tests", + infoPlist: "Tests/Info.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "Framework1-iOS"), + ] + ), + .target( + name: "Framework1Tests-macOS", + destinations: [.mac], + product: .unitTests, + bundleId: "io.tuist.Framework1Tests", + infoPlist: "Tests/Info.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "Framework1-macOS"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift index db42cbcb..6a448706 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift @@ -2,15 +2,15 @@ import Foundation import Framework2 public class Framework1File { - private let framework2File = Framework2File() + private let framework2File = Framework2File() - public init() {} + public init() {} - public func hello() -> String { - "Framework1File.hello()" - } + public func hello() -> String { + "Framework1File.hello()" + } - public func helloFromFramework2() -> String { - "Framework1File -> \(framework2File.hello())" - } + public func helloFromFramework2() -> String { + "Framework1File -> \(framework2File.hello())" + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift index 2aebdd35..dc794524 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift @@ -3,17 +3,17 @@ import XCTest @testable import Framework1 class Framework1Tests: XCTestCase { - func testHello() { - let sut = Framework1File() + func testHello() { + let sut = Framework1File() - XCTAssertEqual("Framework1File.hello()", sut.hello()) - } + XCTAssertEqual("Framework1File.hello()", sut.hello()) + } - #if canImport(Framework2) - func testHelloFromFramework2() { - let sut = Framework1File() + #if canImport(Framework2) + func testHelloFromFramework2() { + let sut = Framework1File() - XCTAssertEqual("Framework1File -> Framework2File.hello()", sut.helloFromFramework2()) - } - #endif + XCTAssertEqual("Framework1File -> Framework2File.hello()", sut.helloFromFramework2()) + } + #endif } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Project.swift index b1878805..93ebb56d 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Project.swift @@ -1,29 +1,29 @@ import ProjectDescription let project = Project( - name: "Framework2", - targets: [ - .target( - name: "Framework2-iOS", - destinations: .iOS, - product: .framework, - productName: "Framework2", - bundleId: "io.tuist.Framework2", - infoPlist: "Config/Framework2-Info.plist", - sources: "Sources/**", - dependencies: [], - settings: .settings(base: ["BUILD_LIBRARY_FOR_DISTRIBUTION": "YES"]) - ), - .target( - name: "Framework2-macOS", - destinations: [.mac], - product: .framework, - productName: "Framework2", - bundleId: "io.tuist.Framework2", - infoPlist: "Config/Framework2-Info.plist", - sources: "Sources/**", - dependencies: [], - settings: .settings(base: ["BUILD_LIBRARY_FOR_DISTRIBUTION": "YES"]) - ), - ] + name: "Framework2", + targets: [ + .target( + name: "Framework2-iOS", + destinations: .iOS, + product: .framework, + productName: "Framework2", + bundleId: "io.tuist.Framework2", + infoPlist: "Config/Framework2-Info.plist", + sources: "Sources/**", + dependencies: [], + settings: .settings(base: ["BUILD_LIBRARY_FOR_DISTRIBUTION": "YES"]) + ), + .target( + name: "Framework2-macOS", + destinations: [.mac], + product: .framework, + productName: "Framework2", + bundleId: "io.tuist.Framework2", + infoPlist: "Config/Framework2-Info.plist", + sources: "Sources/**", + dependencies: [], + settings: .settings(base: ["BUILD_LIBRARY_FOR_DISTRIBUTION": "YES"]) + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Sources/Framework2File.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Sources/Framework2File.swift index f3102dcd..62754f40 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Sources/Framework2File.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Sources/Framework2File.swift @@ -1,9 +1,9 @@ import Foundation public class Framework2File { - public init() {} + public init() {} - public func hello() -> String { - "Framework2File.hello()" - } + public func hello() -> String { + "Framework2File.hello()" + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Project.swift index 61788c6b..ab1af823 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Project.swift @@ -1,29 +1,29 @@ import ProjectDescription let project = Project( - name: "StaticFramework1", - targets: [ - .target( - name: "StaticFramework1", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.StaticFramework1", - infoPlist: .default, - sources: "Sources/**", - dependencies: [ - .framework(path: "../Framework2/prebuilt/iOS/Framework2.framework") - ] - ), - .target( - name: "StaticFramework1Tests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.StaticFramework1Tests", - infoPlist: .default, - sources: "Tests/**", - dependencies: [ - .target(name: "StaticFramework1") - ] - ), - ] + name: "StaticFramework1", + targets: [ + .target( + name: "StaticFramework1", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.StaticFramework1", + infoPlist: .default, + sources: "Sources/**", + dependencies: [ + .framework(path: "../Framework2/prebuilt/iOS/Framework2.framework"), + ] + ), + .target( + name: "StaticFramework1Tests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.StaticFramework1Tests", + infoPlist: .default, + sources: "Tests/**", + dependencies: [ + .target(name: "StaticFramework1"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift index db42cbcb..6a448706 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift @@ -2,15 +2,15 @@ import Foundation import Framework2 public class Framework1File { - private let framework2File = Framework2File() + private let framework2File = Framework2File() - public init() {} + public init() {} - public func hello() -> String { - "Framework1File.hello()" - } + public func hello() -> String { + "Framework1File.hello()" + } - public func helloFromFramework2() -> String { - "Framework1File -> \(framework2File.hello())" - } + public func helloFromFramework2() -> String { + "Framework1File -> \(framework2File.hello())" + } } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift index 864f65b9..609faf2b 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift @@ -3,17 +3,17 @@ import XCTest @testable import StaticFramework1 class Framework1Tests: XCTestCase { - func testHello() { - let sut = Framework1File() + func testHello() { + let sut = Framework1File() - XCTAssertEqual("Framework1File.hello()", sut.hello()) - } + XCTAssertEqual("Framework1File.hello()", sut.hello()) + } - #if canImport(Framework2) - func testHelloFromFramework2() { - let sut = Framework1File() + #if canImport(Framework2) + func testHelloFromFramework2() { + let sut = Framework1File() - XCTAssertEqual("Framework1File -> Framework2File.hello()", sut.helloFromFramework2()) - } - #endif + XCTAssertEqual("Framework1File -> Framework2File.hello()", sut.helloFromFramework2()) + } + #endif } diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Workspace.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Workspace.swift index 789a84b4..d63c5df6 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Workspace.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Workspace.swift @@ -1,6 +1,6 @@ import ProjectDescription let workspace = Workspace( - name: "Workspace", - projects: ["App", "Framework1", "StaticFramework1"] + name: "Workspace", + projects: ["App", "Framework1", "StaticFramework1"] ) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Project.swift index ba681482..f5d10ede 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Project.swift @@ -1,30 +1,30 @@ import ProjectDescription let project = Project( - name: "Core", - targets: [ - .target( - name: "Core", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.Core", - infoPlist: "Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ] - ), - .target( - name: "CoreTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.CoreTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "Core") - ] - ), - ] + name: "Core", + targets: [ + .target( + name: "Core", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.Core", + infoPlist: "Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ] + ), + .target( + name: "CoreTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.CoreTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "Core"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift index ba66705e..4fa1dac1 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift @@ -1,5 +1,5 @@ import Foundation public class CoreClass { - public init() {} + public init() {} } diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Project.swift index 7c856ddb..f1c3b5cb 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Project.swift @@ -1,35 +1,35 @@ import ProjectDescription let project = Project( - name: "Data", - targets: [ - .target( - name: "Data", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.Data", - infoPlist: "Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ], - dependencies: [ - /* Target dependencies can be defined here */ - // .framework(path: "Frameworks/MyFramework.framework") - .project(target: "Core", path: "../CoreFramework") - ] - ), - .target( - name: "DataTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.DataFrameworkTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "Data") - ] - ), - ] + name: "Data", + targets: [ + .target( + name: "Data", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.Data", + infoPlist: "Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ], + dependencies: [ + /* Target dependencies can be defined here */ + // .framework(path: "Frameworks/MyFramework.framework") + .project(target: "Core", path: "../CoreFramework"), + ] + ), + .target( + name: "DataTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.DataFrameworkTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "Data"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift index a0969ef0..3f40c7cf 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift @@ -2,7 +2,7 @@ import Core import Foundation public class DataClass { - let core = CoreClass() + let core = CoreClass() - public init() {} + public init() {} } diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Project.swift index 5de9222c..4d1c420c 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Project.swift @@ -1,38 +1,38 @@ import ProjectDescription let project = Project( - name: "FrameworkA", - targets: [ - .target( - name: "FrameworkA", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.FrameworkA", - infoPlist: "Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ], - dependencies: [ - /* Target dependencies can be defined here */ - // .framework(path: "Frameworks/MyFramework.framework") - .project(target: "FeatureContracts", path: "../FeatureContracts"), - .project(target: "Core", path: "../CoreFramework"), - .project(target: "Data", path: "../DataFramework"), - .project(target: "UIComponents", path: "../UIComponentsFramework"), - ] - ), - .target( - name: "FrameworkATests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.FrameworkATests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "FrameworkA") - ] - ), - ] + name: "FrameworkA", + targets: [ + .target( + name: "FrameworkA", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.FrameworkA", + infoPlist: "Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ], + dependencies: [ + /* Target dependencies can be defined here */ + // .framework(path: "Frameworks/MyFramework.framework") + .project(target: "FeatureContracts", path: "../FeatureContracts"), + .project(target: "Core", path: "../CoreFramework"), + .project(target: "Data", path: "../DataFramework"), + .project(target: "UIComponents", path: "../UIComponentsFramework"), + ] + ), + .target( + name: "FrameworkATests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.FrameworkATests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "FrameworkA"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift index a7a5e54c..4bd4ac87 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift @@ -2,9 +2,9 @@ import FeatureContracts import Foundation class FrameworkA { - func run(featureB: FeatureBContract) { - featureB.run() - let a = featureB.expose() - print(a) - } + func run(featureB: FeatureBContract) { + featureB.run() + let a = featureB.expose() + print(a) + } } diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Project.swift index bec52d44..77e4fc63 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Project.swift @@ -1,36 +1,36 @@ import ProjectDescription let project = Project( - name: "FeatureContracts", - targets: [ - .target( - name: "FeatureContracts", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.FeatureContracts", - infoPlist: "Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ], - dependencies: [ - /* Target dependencies can be defined here */ - // .framework(path: "Frameworks/MyFramework.framework") - .project(target: "Data", path: "../DataFramework"), - .project(target: "Core", path: "../CoreFramework"), - ] - ), - .target( - name: "FeatureContractsTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.FeatureContractsTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "FeatureContracts") - ] - ), - ] + name: "FeatureContracts", + targets: [ + .target( + name: "FeatureContracts", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.FeatureContracts", + infoPlist: "Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ], + dependencies: [ + /* Target dependencies can be defined here */ + // .framework(path: "Frameworks/MyFramework.framework") + .project(target: "Data", path: "../DataFramework"), + .project(target: "Core", path: "../CoreFramework"), + ] + ), + .target( + name: "FeatureContractsTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.FeatureContractsTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "FeatureContracts"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift index 9fd1f935..dc57816f 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift @@ -1,5 +1,5 @@ import Foundation public protocol FeatureAContract { - func run() + func run() } diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift index f628db70..f41a3561 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift @@ -2,6 +2,6 @@ import Core import Foundation public protocol FeatureBContract { - func run() - func expose() -> CoreClass + func run() + func expose() -> CoreClass } diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Project.swift index bbb6e80c..f4b82d87 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Project.swift @@ -1,35 +1,35 @@ import ProjectDescription let project = Project( - name: "UIComponents", - targets: [ - .target( - name: "UIComponents", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.UIComponents", - infoPlist: "Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ], - dependencies: [ - /* Target dependencies can be defined here */ - // .framework(path: "Frameworks/MyFramework.framework") - .project(target: "FeatureContracts", path: "../FeatureContracts") - ] - ), - .target( - name: "UIComponentsTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.UIComponentsTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "UIComponents") - ] - ), - ] + name: "UIComponents", + targets: [ + .target( + name: "UIComponents", + destinations: .iOS, + product: .staticFramework, + bundleId: "io.tuist.UIComponents", + infoPlist: "Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ], + dependencies: [ + /* Target dependencies can be defined here */ + // .framework(path: "Frameworks/MyFramework.framework") + .project(target: "FeatureContracts", path: "../FeatureContracts"), + ] + ), + .target( + name: "UIComponentsTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.UIComponentsTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "UIComponents"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift index 1e75a106..7783b747 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift @@ -3,5 +3,5 @@ import Foundation import UIKit class UIComponentA: UIView { - let data = DataClass() + let data = DataClass() } diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Project.swift index 5f6763a1..b2e3abe6 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Project.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Project.swift @@ -1,35 +1,35 @@ import ProjectDescription let project = Project( - name: "StaticApp", - targets: [ - .target( - name: "StaticApp", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.StaticApp", - infoPlist: "Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ], - dependencies: [ - /* Target dependencies can be defined here */ - // .framework(path: "Frameworks/MyFramework.framework") - .project(target: "FrameworkA", path: "../Frameworks/FeatureAFramework") - ] - ), - .target( - name: "StaticAppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.StaticAppTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "StaticApp") - ] - ), - ] + name: "StaticApp", + targets: [ + .target( + name: "StaticApp", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.StaticApp", + infoPlist: "Info.plist", + sources: ["Sources/**"], + resources: [ + /* Path to resources can be defined here */ + // "Resources/**" + ], + dependencies: [ + /* Target dependencies can be defined here */ + // .framework(path: "Frameworks/MyFramework.framework") + .project(target: "FrameworkA", path: "../Frameworks/FeatureAFramework"), + ] + ), + .target( + name: "StaticAppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.StaticAppTests", + infoPlist: "Tests.plist", + sources: "Tests/**", + dependencies: [ + .target(name: "StaticApp"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift index 9796fd0b..19603be9 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift @@ -2,17 +2,17 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? + var window: UIWindow? - func application( - _: UIApplication, - didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() - return true - } + func application( + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() + return true + } } diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.swift index 160c99f4..a0dbefd1 100644 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.swift +++ b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.swift @@ -1,9 +1,9 @@ import ProjectDescription let workspace = Workspace( - name: "Workspace", - projects: [ - "StaticApp", - "Frameworks/**", - ] + name: "Workspace", + projects: [ + "StaticApp", + "Frameworks/**", + ] ) diff --git a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Project.swift b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Project.swift index ee9777cc..20d324dd 100644 --- a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Project.swift +++ b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Project.swift @@ -1,25 +1,25 @@ import ProjectDescription let project = Project( - name: "App with SystemExtension", - targets: [ - .target( - name: "MainApp", - destinations: [.mac], - product: .app, - bundleId: "io.tuist.MainApp", - infoPlist: "MainApp/Info.plist", - sources: ["MainApp/Sources/**"], - dependencies: [ - .target(name: "SystemExtension") - ] - ), - .target( - name: "SystemExtension", - destinations: [.mac], - product: .systemExtension, - bundleId: "io.tuist.SystemExtension", - sources: ["SystemExtension/Sources/**"] - ), - ] + name: "App with SystemExtension", + targets: [ + .target( + name: "MainApp", + destinations: [.mac], + product: .app, + bundleId: "io.tuist.MainApp", + infoPlist: "MainApp/Info.plist", + sources: ["MainApp/Sources/**"], + dependencies: [ + .target(name: "SystemExtension"), + ] + ), + .target( + name: "SystemExtension", + destinations: [.mac], + product: .systemExtension, + bundleId: "io.tuist.SystemExtension", + sources: ["SystemExtension/Sources/**"] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift index 526e0783..6c1f47a2 100644 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift @@ -2,19 +2,19 @@ import ModuleA import SwiftUI struct ContentView: View { - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundColor(.accentColor) - Text("Hello, world!") - Text("\(#stringify(1 + 1))") + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world!") + Text("\(#stringify(1 + 1))") + } } - } } struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } + static var previews: some View { + ContentView() + } } diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift index 9eb4ee19..78f112a8 100644 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift @@ -3,13 +3,13 @@ import SwiftUI @main struct TestApp: App { - init() { - ModuleA.test() - } + init() { + ModuleA.test() + } - var body: some Scene { - WindowGroup { - ContentView() + var body: some Scene { + WindowGroup { + ContentView() + } } - } } diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift index 9f31c11e..3624b5cb 100644 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift @@ -4,20 +4,20 @@ import SwiftSyntaxMacros @main struct ModuleAMacros: CompilerPlugin { - var providingMacros: [Macro.Type] = [ - StringifyMacro.self - ] + var providingMacros: [Macro.Type] = [ + StringifyMacro.self, + ] } public struct StringifyMacro: ExpressionMacro { - public static func expansion( - of node: some FreestandingMacroExpansionSyntax, - in _: some MacroExpansionContext - ) -> ExprSyntax { - guard let argument = node.arguments.first?.expression else { - fatalError("compiler bug: the macro does not have any arguments") - } + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in _: some MacroExpansionContext + ) -> ExprSyntax { + guard let argument = node.arguments.first?.expression else { + fatalError("compiler bug: the macro does not have any arguments") + } - return "(\(argument), \(literal: argument.description))" - } + return "(\(argument), \(literal: argument.description))" + } } diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift index 3bef61c5..2a8156b3 100644 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift @@ -1,3 +1,3 @@ @freestanding(expression) public macro stringify(_ value: T) -> (T, String) = - #externalMacro(module: "ModuleAMacros", type: "StringifyMacro") + #externalMacro(module: "ModuleAMacros", type: "StringifyMacro") diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift index f5405e80..b99b065a 100644 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift @@ -2,11 +2,11 @@ import CasePaths @CasePathable enum AppAction { - case home + case home } public enum ModuleA { - public static func test() { - print("Module A") - } + public static func test() { + print("Module A") + } } diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift index 3b7d89df..ba961a38 100644 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift @@ -5,19 +5,19 @@ import XCTest @testable import ModuleAMacros_Testable final class StringifyMacroTests: XCTestCase { - let testMacros: [String: Macro.Type] = [ - "stringify": StringifyMacro.self - ] + let testMacros: [String: Macro.Type] = [ + "stringify": StringifyMacro.self, + ] - func testStringifyStruct() throws { - assertMacroExpansion( - """ - #stringify(1+1) - """, - expandedSource: """ - (1 + 1, "1+1") - """, - macros: testMacros - ) - } + func testStringifyStruct() throws { + assertMacroExpansion( + """ + #stringify(1+1) + """, + expandedSource: """ + (1 + 1, "1+1") + """, + macros: testMacros + ) + } } diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Project.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Project.swift index 7285e815..82bebfd9 100644 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Project.swift +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Project.swift @@ -1,107 +1,107 @@ import ProjectDescription let project = Project( - name: "AppWithWatchApp", - targets: [ - .target( - name: "App", - destinations: [.iPhone, .appleVision], - product: .app, - bundleId: "io.tuist.App", - infoPlist: .default, - sources: [ - "App/Sources/**" - ], - resources: [ - "App/Resources/**" - ], - dependencies: [ - .target(name: "WatchApp", condition: .when([.ios])), - .target(name: "ModuleA"), - ] - ), - .target( - name: "WatchApp", - destinations: [.appleWatch], - product: .app, - bundleId: "io.tuist.App.watchkitapp", - infoPlist: nil, - sources: "WatchApp/Sources/**", - resources: "WatchApp/Resources/**", - dependencies: [ - .target(name: "ModuleA") - ], - settings: .settings( - base: [ - "GENERATE_INFOPLIST_FILE": true, - "CURRENT_PROJECT_VERSION": "1.0", - "MARKETING_VERSION": "1.0", - "INFOPLIST_KEY_UISupportedInterfaceOrientations": [ - "UIInterfaceOrientationPortrait", - "UIInterfaceOrientationPortraitUpsideDown", - ], - "INFOPLIST_KEY_WKCompanionAppBundleIdentifier": "io.tuist.App", - "INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp": false, - ] - ) - ), - .target( - name: "ModuleA", - destinations: [.iPhone, .appleVision, .appleWatch], - product: .framework, - productName: "ModuleA", - bundleId: "io.tuist.modulea", - sources: [ - "Modules/ModuleA/Sources/**" - ], - dependencies: [ - .external(name: "CasePaths"), - .target(name: "ModuleAMacros"), - ] - ), - .target( - name: "ModuleATests", - destinations: [.iPhone, .appleVision, .appleWatch], - product: .unitTests, - productName: "ModuleATests", - bundleId: "io.tuist.moduleatests", - sources: [ - "Modules/ModuleA/Tests/**" - ], - dependencies: [ - .target(name: "ModuleA"), - .target(name: "ModuleAMacros_Testable"), - .external(name: "SwiftSyntaxMacrosTestSupport"), - ] - ), - .target( - name: "ModuleAMacros", - destinations: .macOS, - product: .macro, - productName: "ModuleAMacros", - bundleId: "io.tuist.moduleamacros", - deploymentTargets: .macOS("14.0"), - sources: [ - "Modules/ModuleA/Macros/Sources/**" - ], - dependencies: [ - .external(name: "SwiftSyntaxMacros"), - .external(name: "SwiftCompilerPlugin"), - ] - ), - .target( - name: "ModuleAMacros_Testable", - destinations: [.iPhone, .appleVision, .appleWatch], // Must match platform of the test target - product: .framework, // Must match be a linkable product - productName: "ModuleAMacros_Testable", - bundleId: "io.tuist.moduleamacros.testable", - sources: [ - "Modules/ModuleA/Macros/Sources/**" - ], - dependencies: [ - .external(name: "SwiftSyntaxMacros"), - .external(name: "SwiftCompilerPlugin"), - ] - ), - ] + name: "AppWithWatchApp", + targets: [ + .target( + name: "App", + destinations: [.iPhone, .appleVision], + product: .app, + bundleId: "io.tuist.App", + infoPlist: .default, + sources: [ + "App/Sources/**", + ], + resources: [ + "App/Resources/**", + ], + dependencies: [ + .target(name: "WatchApp", condition: .when([.ios])), + .target(name: "ModuleA"), + ] + ), + .target( + name: "WatchApp", + destinations: [.appleWatch], + product: .app, + bundleId: "io.tuist.App.watchkitapp", + infoPlist: nil, + sources: "WatchApp/Sources/**", + resources: "WatchApp/Resources/**", + dependencies: [ + .target(name: "ModuleA"), + ], + settings: .settings( + base: [ + "GENERATE_INFOPLIST_FILE": true, + "CURRENT_PROJECT_VERSION": "1.0", + "MARKETING_VERSION": "1.0", + "INFOPLIST_KEY_UISupportedInterfaceOrientations": [ + "UIInterfaceOrientationPortrait", + "UIInterfaceOrientationPortraitUpsideDown", + ], + "INFOPLIST_KEY_WKCompanionAppBundleIdentifier": "io.tuist.App", + "INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp": false, + ] + ) + ), + .target( + name: "ModuleA", + destinations: [.iPhone, .appleVision, .appleWatch], + product: .framework, + productName: "ModuleA", + bundleId: "io.tuist.modulea", + sources: [ + "Modules/ModuleA/Sources/**", + ], + dependencies: [ + .external(name: "CasePaths"), + .target(name: "ModuleAMacros"), + ] + ), + .target( + name: "ModuleATests", + destinations: [.iPhone, .appleVision, .appleWatch], + product: .unitTests, + productName: "ModuleATests", + bundleId: "io.tuist.moduleatests", + sources: [ + "Modules/ModuleA/Tests/**", + ], + dependencies: [ + .target(name: "ModuleA"), + .target(name: "ModuleAMacros_Testable"), + .external(name: "SwiftSyntaxMacrosTestSupport"), + ] + ), + .target( + name: "ModuleAMacros", + destinations: .macOS, + product: .macro, + productName: "ModuleAMacros", + bundleId: "io.tuist.moduleamacros", + deploymentTargets: .macOS("14.0"), + sources: [ + "Modules/ModuleA/Macros/Sources/**", + ], + dependencies: [ + .external(name: "SwiftSyntaxMacros"), + .external(name: "SwiftCompilerPlugin"), + ] + ), + .target( + name: "ModuleAMacros_Testable", + destinations: [.iPhone, .appleVision, .appleWatch], // Must match platform of the test target + product: .framework, // Must match be a linkable product + productName: "ModuleAMacros_Testable", + bundleId: "io.tuist.moduleamacros.testable", + sources: [ + "Modules/ModuleA/Macros/Sources/**", + ], + dependencies: [ + .external(name: "SwiftSyntaxMacros"), + .external(name: "SwiftCompilerPlugin"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.swift index bcb99be2..de8d34a9 100644 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.swift +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.swift @@ -2,22 +2,22 @@ import PackageDescription #if TUIST - import ProjectDescription + import ProjectDescription - let packageSettings = PackageSettings( - baseSettings: .settings( - base: [ - "ENABLE_USER_SCRIPT_SANDBOXING": true - ] + let packageSettings = PackageSettings( + baseSettings: .settings( + base: [ + "ENABLE_USER_SCRIPT_SANDBOXING": true, + ] + ) ) - ) #endif let package = Package( - name: "Dependencies", - dependencies: [ - .package(url: "https://github.com/pointfreeco/swift-case-paths", from: "1.5.6"), - .package(url: "https://github.com/apple/swift-syntax", "510.0.3"..<"601.0.0-prerelease"), - ] + name: "Dependencies", + dependencies: [ + .package(url: "https://github.com/pointfreeco/swift-case-paths", from: "1.5.6"), + .package(url: "https://github.com/apple/swift-syntax", "510.0.3" ..< "601.0.0-prerelease"), + ] ) diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift index e6b1de31..8b74b2b1 100644 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift @@ -1,18 +1,18 @@ import SwiftUI struct ContentView: View { - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundColor(.accentColor) - Text("Hello, world!") + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world!") + } } - } } struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } + static var previews: some View { + ContentView() + } } diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift index ac218bca..0755c22e 100644 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift @@ -4,18 +4,18 @@ import SwiftUI @CasePathable enum WatchAppAction { - case home + case home } @main struct WatchApp: App { - init() { - ModuleA.test() - } + init() { + ModuleA.test() + } - var body: some Scene { - WindowGroup { - ContentView() + var body: some Scene { + WindowGroup { + ContentView() + } } - } } diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift index 37cf404a..4485cd7c 100644 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift +++ b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift @@ -1,5 +1,5 @@ import Foundation public enum WatchConfig { - public static let title: String = "Hello, watchOS" + public static let title: String = "Hello, watchOS" } diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Project.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Project.swift index 118ad94d..ca2b3dc2 100644 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Project.swift +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Project.swift @@ -1,28 +1,28 @@ import ProjectDescription let project = Project( - name: "ProjectA", - organizationName: "tuist.io", - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.app", - deploymentTargets: DeploymentTargets.iOS("13.0"), - infoPlist: .default, - sources: ["Targets/App/Sources/**"] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.AppTests", - infoPlist: .default, - sources: ["Targets/App/Tests/**"], - dependencies: [ - .target(name: "App") - ] - ), - ] + name: "ProjectA", + organizationName: "tuist.io", + targets: [ + .target( + name: "App", + destinations: .iOS, + product: .app, + bundleId: "io.tuist.app", + deploymentTargets: DeploymentTargets.iOS("13.0"), + infoPlist: .default, + sources: ["Targets/App/Sources/**"] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.AppTests", + infoPlist: .default, + sources: ["Targets/App/Tests/**"], + dependencies: [ + .target(name: "App"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Sources/AppDelegate.swift index 6db37c4c..4cde399e 100644 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Sources/AppDelegate.swift +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Sources/AppDelegate.swift @@ -2,18 +2,18 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? + var window: UIWindow? - func application( - _: UIApplication, - didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() + func application( + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() - return true - } + return true + } } diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Tests/AppTests.swift index eaf76af2..70c453ba 100644 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Tests/AppTests.swift +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Tests/AppTests.swift @@ -2,7 +2,7 @@ import Foundation import XCTest final class AppTests: XCTestCase { - func test_twoPlusTwo_isFour() { - XCTAssertEqual(2 + 2, 4) - } + func test_twoPlusTwo_isFour() { + XCTAssertEqual(2 + 2, 4) + } } diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Project.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Project.swift index 57a15ba1..2eea208d 100644 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Project.swift +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Project.swift @@ -1,28 +1,28 @@ import ProjectDescription let project = Project( - name: "ProjectB", - organizationName: "tuist.io", - targets: [ - .target( - name: "App", - destinations: [.iPhone], - product: .app, - bundleId: "io.tuist.app", - deploymentTargets: .iOS("13.0"), - infoPlist: .default, - sources: ["Targets/App/Sources/**"] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.AppTests", - infoPlist: .default, - sources: ["Targets/App/Tests/**"], - dependencies: [ - .target(name: "App") - ] - ), - ] + name: "ProjectB", + organizationName: "tuist.io", + targets: [ + .target( + name: "App", + destinations: [.iPhone], + product: .app, + bundleId: "io.tuist.app", + deploymentTargets: .iOS("13.0"), + infoPlist: .default, + sources: ["Targets/App/Sources/**"] + ), + .target( + name: "AppTests", + destinations: .iOS, + product: .unitTests, + bundleId: "io.tuist.AppTests", + infoPlist: .default, + sources: ["Targets/App/Tests/**"], + dependencies: [ + .target(name: "App"), + ] + ), + ] ) diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Sources/AppDelegate.swift index 6db37c4c..4cde399e 100644 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Sources/AppDelegate.swift +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Sources/AppDelegate.swift @@ -2,18 +2,18 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? + var window: UIWindow? - func application( - _: UIApplication, - didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() + func application( + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = UIViewController() + viewController.view.backgroundColor = .white + window?.rootViewController = viewController + window?.makeKeyAndVisible() - return true - } + return true + } } diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Tests/AppTests.swift index eaf76af2..70c453ba 100644 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Tests/AppTests.swift +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Tests/AppTests.swift @@ -2,7 +2,7 @@ import Foundation import XCTest final class AppTests: XCTestCase { - func test_twoPlusTwo_isFour() { - XCTAssertEqual(2 + 2, 4) - } + func test_twoPlusTwo_isFour() { + XCTAssertEqual(2 + 2, 4) + } } diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/Workspace.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/Workspace.swift index 677724db..09929f52 100644 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/Workspace.swift +++ b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/Workspace.swift @@ -1,9 +1,9 @@ import ProjectDescription let workspace = Workspace( - name: "Tuist", - projects: [ - "ProjectA", - "ProjectB", - ] + name: "Tuist", + projects: [ + "ProjectA", + "ProjectB", + ] ) diff --git a/Sources/TestSupport/Mocks/MockBuildFilesAndPhases.swift b/Sources/TestSupport/Mocks/MockBuildFilesAndPhases.swift index cc167709..1966b6ad 100644 --- a/Sources/TestSupport/Mocks/MockBuildFilesAndPhases.swift +++ b/Sources/TestSupport/Mocks/MockBuildFilesAndPhases.swift @@ -3,8 +3,8 @@ import Path import XcodeGraph @testable @preconcurrency import XcodeProj -public extension PBXBuildFile { - static func mock( +extension PBXBuildFile { + public static func mock( file: PBXFileElement, settings: [String: Any]? = nil, pbxProj: PBXProj @@ -15,8 +15,8 @@ public extension PBXBuildFile { } } -public extension PBXBuildRule { - static func mock( +extension PBXBuildRule { + public static func mock( compilerSpec: String = BuildRule.CompilerSpec.appleClang.rawValue, fileType: String = BuildRule.FileType.cSource.rawValue, isEditable: Bool = true, @@ -48,8 +48,8 @@ public extension PBXBuildRule { } } -public extension PBXSourcesBuildPhase { - static func mock( +extension PBXSourcesBuildPhase { + public static func mock( files: [PBXBuildFile], pbxProj: PBXProj ) -> PBXSourcesBuildPhase { @@ -59,8 +59,8 @@ public extension PBXSourcesBuildPhase { } } -public extension PBXResourcesBuildPhase { - static func mock( +extension PBXResourcesBuildPhase { + public static func mock( files: [PBXBuildFile], pbxProj: PBXProj ) -> PBXResourcesBuildPhase { @@ -70,8 +70,8 @@ public extension PBXResourcesBuildPhase { } } -public extension PBXFrameworksBuildPhase { - static func mock( +extension PBXFrameworksBuildPhase { + public static func mock( files: [PBXBuildFile], pbxProj: PBXProj ) -> PBXFrameworksBuildPhase { @@ -81,8 +81,8 @@ public extension PBXFrameworksBuildPhase { } } -public extension PBXShellScriptBuildPhase { - static func mock( +extension PBXShellScriptBuildPhase { + public static func mock( name: String? = "Embed Precompiled Frameworks", shellScript: String = "#!/bin/sh\necho 'Mock Shell Script'", inputPaths: [String] = [], @@ -117,8 +117,8 @@ public extension PBXShellScriptBuildPhase { } } -public extension PBXCopyFilesBuildPhase { - static func mock( +extension PBXCopyFilesBuildPhase { + public static func mock( name: String? = "Embed Frameworks", dstPath: String = "", dstSubfolderSpec: PBXCopyFilesBuildPhase.SubFolder = .frameworks, diff --git a/Sources/TestSupport/Mocks/MockBuildSettings.swift b/Sources/TestSupport/Mocks/MockBuildSettings.swift index a5ee35a2..4f0a7100 100644 --- a/Sources/TestSupport/Mocks/MockBuildSettings.swift +++ b/Sources/TestSupport/Mocks/MockBuildSettings.swift @@ -1,18 +1,10 @@ -// -// Mc.swift -// XcodeGraphMapper -// -// Created by Andy Kolean on 12/13/24. -// - - import Foundation import Path import XcodeGraph @testable @preconcurrency import XcodeProj -public extension XCBuildConfiguration { - static func mock( +extension XCBuildConfiguration { + public static func mock( name: String = "Debug", buildSettings: [String: Sendable] = MockDefaults.defaultDebugSettings, baseConfiguration: PBXFileReference? = nil, @@ -29,8 +21,8 @@ public extension XCBuildConfiguration { } } -public extension XCConfigurationList { - static func mock( +extension XCConfigurationList { + public static func mock( configs: [(name: String, settings: [String: Sendable])] = [ ("Debug", MockDefaults.defaultDebugSettings), ("Release", MockDefaults.defaultReleaseSettings), diff --git a/Sources/TestSupport/Mocks/MockDefaults.swift b/Sources/TestSupport/Mocks/MockDefaults.swift index c3de298d..3a8b01b9 100644 --- a/Sources/TestSupport/Mocks/MockDefaults.swift +++ b/Sources/TestSupport/Mocks/MockDefaults.swift @@ -1,17 +1,9 @@ -// -// MockDefaults.swift -// XcodeGraphMapper -// -// Created by Andy Kolean on 12/13/24. -// - - import Foundation import Path import XcodeGraph @testable @preconcurrency import XcodeProj -public struct MockDefaults { +public enum MockDefaults { public static let defaultDebugSettings: [String: Sendable] = [ "PRODUCT_NAME": "$(TARGET_NAME)", "ENABLE_STRICT_OBJC_MSGSEND": "YES", @@ -26,6 +18,6 @@ public struct MockDefaults { ] public static let defaultProjectAttributes: [String: Sendable] = [ - "BuildIndependentTargetsInParallel": "YES" + "BuildIndependentTargetsInParallel": "YES", ] } diff --git a/Sources/TestSupport/Mocks/MockFileCreator.swift b/Sources/TestSupport/Mocks/MockFileCreator.swift index 5e755737..b15cea44 100644 --- a/Sources/TestSupport/Mocks/MockFileCreator.swift +++ b/Sources/TestSupport/Mocks/MockFileCreator.swift @@ -1,18 +1,19 @@ import Foundation public class MockFileCreator { - public static func createTemporaryExecutable( - name: String = "mockLipo_\(UUID().uuidString)", - withContent content: String - ) throws -> String { - let tempDirectory = FileManager.default.temporaryDirectory - let mockExecutablePath = tempDirectory.appendingPathComponent(name).path + public static func createTemporaryExecutable( + name: String = "mockLipo_\(UUID().uuidString)", + withContent content: String + ) throws -> String { + let tempDirectory = FileManager.default.temporaryDirectory + let mockExecutablePath = tempDirectory.appendingPathComponent(name).path - try content.write(toFile: mockExecutablePath, atomically: true, encoding: .utf8) + try content.write(toFile: mockExecutablePath, atomically: true, encoding: .utf8) - try FileManager.default.setAttributes( - [.posixPermissions: 0o755], ofItemAtPath: mockExecutablePath) + try FileManager.default.setAttributes( + [.posixPermissions: 0o755], ofItemAtPath: mockExecutablePath + ) - return mockExecutablePath - } + return mockExecutablePath + } } diff --git a/Sources/TestSupport/Mocks/MockFileStructure.swift b/Sources/TestSupport/Mocks/MockFileStructure.swift index 71d25d28..ae447fa7 100644 --- a/Sources/TestSupport/Mocks/MockFileStructure.swift +++ b/Sources/TestSupport/Mocks/MockFileStructure.swift @@ -3,8 +3,8 @@ import Path import XcodeGraph @testable @preconcurrency import XcodeProj -public extension PBXFileReference { - static func mock( +extension PBXFileReference { + public static func mock( sourceTree: PBXSourceTree = .group, name: String? = nil, explicitFileType: String? = nil, @@ -24,13 +24,14 @@ public extension PBXFileReference { ) pbxProj.add(object: file) if addToMainGroup, let project = pbxProj.projects.first, - let mainGroup = project.mainGroup { + let mainGroup = project.mainGroup + { mainGroup.children.append(file) } return file } - static func mockProject( + public static func mockProject( path: String = "App.xcodeproj", name: String? = "App", sourceTree: PBXSourceTree = .sourceRoot, @@ -52,8 +53,8 @@ public extension PBXFileReference { } } -public extension PBXVariantGroup { - static func mockVariant( +extension PBXVariantGroup { + public static func mockVariant( children: [PBXFileElement] = [], sourceTree: PBXSourceTree = .group, name: String? = "MainGroup", @@ -77,8 +78,8 @@ public extension PBXVariantGroup { } } -public extension PBXGroup { - static func mock( +extension PBXGroup { + public static func mock( children: [PBXFileElement] = [], sourceTree: PBXSourceTree = .group, name: String? = "MainGroup", @@ -102,8 +103,8 @@ public extension PBXGroup { } } -public extension XCVersionGroup { - static func mock( +extension XCVersionGroup { + public static func mock( currentVersion: PBXFileReference? = nil, children: [PBXFileElement] = [], path: String = "DefaultGroup", @@ -129,7 +130,7 @@ public extension XCVersionGroup { indentWidth: indentWidth, tabWidth: tabWidth ) - if let currentVersion = currentVersion { + if let currentVersion { pbxProj.add(object: currentVersion) } if let project = pbxProj.projects.first, let mainGroup = project.mainGroup { diff --git a/Sources/TestSupport/Mocks/MockProjectAndWorkspace.swift b/Sources/TestSupport/Mocks/MockProjectAndWorkspace.swift index e4224593..c12677bc 100644 --- a/Sources/TestSupport/Mocks/MockProjectAndWorkspace.swift +++ b/Sources/TestSupport/Mocks/MockProjectAndWorkspace.swift @@ -19,19 +19,19 @@ extension PBXProject { ) -> PBXProject { let resolvedMainGroup = mainGroup - ?? PBXGroup.mock( - children: [], - sourceTree: .group, - name: "MainGroup", - path: "/tmp/TestProject", - pbxProj: pbxProj, - addToMainGroup: false - ) + ?? PBXGroup.mock( + children: [], + sourceTree: .group, + name: "MainGroup", + path: "/tmp/TestProject", + pbxProj: pbxProj, + addToMainGroup: false + ) let resolvedBuildConfigList = buildConfigurationList ?? XCConfigurationList.mock(proj: pbxProj) pbxProj.add(object: resolvedBuildConfigList) - if let productsGroup = productsGroup { + if let productsGroup { pbxProj.add(object: productsGroup) } @@ -87,17 +87,17 @@ extension XcodeProj { public static func mock( projectName: String = "MainApp", targets: [PBXTarget] = [], - schemes: [XCScheme] = [] + schemes _: [XCScheme] = [] ) -> XcodeProj { let pbxProj = PBXProj() let target = targets.first ?? PBXNativeTarget.mock(pbxProj: pbxProj) - let _ = XCBuildConfiguration.mock( + _ = XCBuildConfiguration.mock( name: "Debug", buildSettings: MockDefaults.defaultDebugSettings, pbxProj: pbxProj ) - let _ = XCBuildConfiguration.mock( + _ = XCBuildConfiguration.mock( name: "Release", buildSettings: MockDefaults.defaultReleaseSettings, pbxProj: pbxProj @@ -132,7 +132,7 @@ extension PBXObjectReference { } extension PBXProj { - public func add(objects: [PBXObject]) { - objects.forEach { add(object: $0) } - } + public func add(objects: [PBXObject]) { + objects.forEach { add(object: $0) } + } } diff --git a/Sources/TestSupport/Mocks/MockProjectProvider.swift b/Sources/TestSupport/Mocks/MockProjectProvider.swift index c0375bf0..db566072 100644 --- a/Sources/TestSupport/Mocks/MockProjectProvider.swift +++ b/Sources/TestSupport/Mocks/MockProjectProvider.swift @@ -8,43 +8,44 @@ import XcodeProj struct MockWorkspaceProvider: WorkspaceProviding { var workspaceDirectory: AbsolutePath var xcWorkspacePath: AbsolutePath - var xcworkspace: XCWorkspace + var xcworkspace: XCWorkspace - public init(xcWorkspacePath: AbsolutePath, xcworkspace: XCWorkspace) { - self.xcWorkspacePath = xcWorkspacePath - self.workspaceDirectory = xcWorkspacePath.parentDirectory - self.xcworkspace = xcworkspace - } + public init(xcWorkspacePath: AbsolutePath, xcworkspace: XCWorkspace) { + self.xcWorkspacePath = xcWorkspacePath + workspaceDirectory = xcWorkspacePath.parentDirectory + self.xcworkspace = xcworkspace + } } struct MockProjectProvider: ProjectProviding { - let sourceDirectory: AbsolutePath - let xcodeProjPath: AbsolutePath - let xcodeProj: XcodeProj - var pbxProj: PBXProj { - xcodeProj.pbxproj - } + let sourceDirectory: AbsolutePath + let xcodeProjPath: AbsolutePath + let xcodeProj: XcodeProj + var pbxProj: PBXProj { + xcodeProj.pbxproj + } - init( - sourceDirectory: String = "/tmp", - projectName: String = "TestProject", - configurationList: XCConfigurationList? = nil, - pbxProj: PBXProj = PBXProj() - ) { - let configurationList = configurationList ?? .mock(proj: pbxProj) - self.sourceDirectory = try! AbsolutePath.resolvePath(sourceDirectory) - self.xcodeProjPath = self.sourceDirectory.appending(component: "TestProject.xcodproj") - // minimal project setup - let pbxProject = PBXProject.mock( - name: projectName, buildConfigurationList: configurationList, pbxProj: pbxProj) - pbxProj.add(object: pbxProject) - pbxProj.add(object: configurationList) - pbxProj.rootObject = pbxProject + init( + sourceDirectory: String = "/tmp", + projectName: String = "TestProject", + configurationList: XCConfigurationList? = nil, + pbxProj: PBXProj = PBXProj() + ) { + let configurationList = configurationList ?? .mock(proj: pbxProj) + self.sourceDirectory = try! AbsolutePath.resolvePath(sourceDirectory) + xcodeProjPath = self.sourceDirectory.appending(component: "TestProject.xcodproj") + // minimal project setup + let pbxProject = PBXProject.mock( + name: projectName, buildConfigurationList: configurationList, pbxProj: pbxProj + ) + pbxProj.add(object: pbxProject) + pbxProj.add(object: configurationList) + pbxProj.rootObject = pbxProject - self.xcodeProj = XcodeProj(workspace: XCWorkspace(), pbxproj: pbxProj) - } + xcodeProj = XcodeProj(workspace: XCWorkspace(), pbxproj: pbxProj) + } - func pbxProject() throws -> PBXProject { - return xcodeProj.pbxproj.projects.first! - } + func pbxProject() throws -> PBXProject { + return xcodeProj.pbxproj.projects.first! + } } diff --git a/Sources/TestSupport/Mocks/MockSchemesAndUserData.swift b/Sources/TestSupport/Mocks/MockSchemesAndUserData.swift index b2d34c98..c744a4dd 100644 --- a/Sources/TestSupport/Mocks/MockSchemesAndUserData.swift +++ b/Sources/TestSupport/Mocks/MockSchemesAndUserData.swift @@ -3,8 +3,8 @@ import Path import XcodeGraph @testable @preconcurrency import XcodeProj -public extension XCScheme.TestableReference { - static func mock( +extension XCScheme.TestableReference { + public static func mock( skipped: Bool, parallelization: XCScheme.TestParallelization = .none, randomExecutionOrdering: Bool = false, @@ -27,8 +27,8 @@ public extension XCScheme.TestableReference { } } -public extension XCScheme { - static func mock( +extension XCScheme { + public static func mock( name: String = "DefaultScheme", buildAction: BuildAction? = nil, testAction: TestAction? = nil, @@ -53,8 +53,8 @@ public extension XCScheme { } } -public extension XCUserData { - static func mock( +extension XCUserData { + public static func mock( userName: String = "user", schemes: [XCScheme] = [], schemeManagement: XCSchemeManagement? = XCSchemeManagement( @@ -64,7 +64,7 @@ public extension XCUserData { shared: true, orderHint: 0, isShown: true - ) + ), ], suppressBuildableAutocreation: nil ) diff --git a/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift b/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift index 04c3f9e6..3a5e2b78 100644 --- a/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift +++ b/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift @@ -3,8 +3,8 @@ import Path import XcodeGraph @testable @preconcurrency import XcodeProj -public extension PBXTargetDependency { - static func mock( +extension PBXTargetDependency { + public static func mock( name: String? = "App", target: PBXTarget? = nil, targetProxy: PBXContainerItemProxy? = nil, @@ -24,8 +24,8 @@ public extension PBXTargetDependency { } } -public extension PBXContainerItemProxy { - static func mock( +extension PBXContainerItemProxy { + public static func mock( containerPortal: PBXContainerItemProxy.ContainerPortal, proxyType: PBXContainerItemProxy.ProxyType = .nativeTarget, remoteGlobalID: PBXContainerItemProxy.RemoteGlobalID = .string("TARGET_REF"), @@ -43,8 +43,8 @@ public extension PBXContainerItemProxy { } } -public extension PBXTargetDependency { - static func mockTargetDependency( +extension PBXTargetDependency { + public static func mockTargetDependency( name: String, platformFilters: [String]? = nil, platformFilter: String? = nil, @@ -66,7 +66,7 @@ public extension PBXTargetDependency { return dep } - static func mockPackageProductDependency( + public static func mockPackageProductDependency( productName: String, pbxProj: PBXProj ) -> PBXTargetDependency { @@ -79,7 +79,7 @@ public extension PBXTargetDependency { return dep } - static func mockProxyDependency( + public static func mockProxyDependency( remoteInfo: String, proxyType: PBXContainerItemProxy.ProxyType, containerPortal: PBXContainerItemProxy.ContainerPortal, @@ -96,7 +96,7 @@ public extension PBXTargetDependency { ) pbxProj.add(object: proxy) - if let remoteObject = remoteObject { + if let remoteObject { proxy.remoteGlobalID = .object(remoteObject) } @@ -108,8 +108,8 @@ public extension PBXTargetDependency { } } -public extension XCSwiftPackageProductDependency { - static func mock( +extension XCSwiftPackageProductDependency { + public static func mock( productName: String, package: XCRemoteSwiftPackageReference? = nil, isPlugin: Bool = false, @@ -123,8 +123,8 @@ public extension XCSwiftPackageProductDependency { } } -public extension PBXNativeTarget { - static func mock( +extension PBXNativeTarget { + public static func mock( name: String = "App", buildConfigurationList: XCConfigurationList? = nil, buildRules: [PBXBuildRule]? = nil, @@ -137,14 +137,14 @@ public extension PBXNativeTarget { ) -> PBXNativeTarget { let resolvedProduct = product - ?? PBXFileReference.mock( - sourceTree: .buildProductsDir, - explicitFileType: "wrapper.application", - path: "App.app", - lastKnownFileType: nil, - includeInIndex: false, - pbxProj: pbxProj - ) + ?? PBXFileReference.mock( + sourceTree: .buildProductsDir, + explicitFileType: "wrapper.application", + path: "App.app", + lastKnownFileType: nil, + includeInIndex: false, + pbxProj: pbxProj + ) let resolvedBuildConfigList = buildConfigurationList ?? XCConfigurationList.mock(proj: pbxProj) let resolvedBuildRules = buildRules ?? [PBXBuildRule.mock(pbxProj: pbxProj)] diff --git a/Sources/TestSupport/WorkspaceFixture.swift b/Sources/TestSupport/WorkspaceFixture.swift index 26a7543e..9652fd92 100644 --- a/Sources/TestSupport/WorkspaceFixture.swift +++ b/Sources/TestSupport/WorkspaceFixture.swift @@ -3,28 +3,29 @@ import Path import XcodeGraph // MARK: - Workspace Fixtures + public enum WorkspaceFixture: String, CaseIterable { - case commandLineToolWithDynamicFramework = - "command_line_tool_with_dynamic_framework/CommandLineTool" - case iosAppWithRemoteSwiftPackage = "ios_app_with_remote_swift_package/App" - case iosAppWithSpmDependencies = "ios_app_with_spm_dependencies/App" - case iosAppWithExtensions = "ios_app_with_extensions/App" - case iosAppWithMultiConfigs = "ios_app_with_multi_configs/Workspace" - case iosWorkspaceWithMicrofeatureArchitectureStaticLinking = - "ios_workspace_with_microfeature_architecture_static_linking/Workspace" - case multiplatformAppWithMacrosAndEmbeddedWatchosApp = - "multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp" - case iosAppLarge = "ios_app_large/App" - case ios_app_with_transitive_framework = "ios_app_with_transitive_framework/Workspace" - case macosAppWithSystemExtension = "macos_app_with_system_extension/App with SystemExtension" - case iosAppWithStaticLibraries = - "ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries" + case commandLineToolWithDynamicFramework = + "command_line_tool_with_dynamic_framework/CommandLineTool" + case iosAppWithRemoteSwiftPackage = "ios_app_with_remote_swift_package/App" + case iosAppWithSpmDependencies = "ios_app_with_spm_dependencies/App" + case iosAppWithExtensions = "ios_app_with_extensions/App" + case iosAppWithMultiConfigs = "ios_app_with_multi_configs/Workspace" + case iosWorkspaceWithMicrofeatureArchitectureStaticLinking = + "ios_workspace_with_microfeature_architecture_static_linking/Workspace" + case multiplatformAppWithMacrosAndEmbeddedWatchosApp = + "multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp" + case iosAppLarge = "ios_app_large/App" + case ios_app_with_transitive_framework = "ios_app_with_transitive_framework/Workspace" + case macosAppWithSystemExtension = "macos_app_with_system_extension/App with SystemExtension" + case iosAppWithStaticLibraries = + "ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries" - public var fileExtension: String { "xcworkspace" } + public var fileExtension: String { "xcworkspace" } - public func absolutePath() throws -> AbsolutePath { - return try AbsolutePath.resolvePath( - "/Users/andykolean/Developer/XcodeGraphMapper/Tests/TestSupport/Fixtures/\(rawValue).xcworkspace" - ) - } + public func absolutePath() throws -> AbsolutePath { + return try AbsolutePath.resolvePath( + "/Users/andykolean/Developer/XcodeGraphMapper/Tests/TestSupport/Fixtures/\(rawValue).xcworkspace" + ) + } } diff --git a/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift index 9afafcbb..55ddbc86 100644 --- a/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift +++ b/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift @@ -3,86 +3,86 @@ import Path import XcodeGraph enum FileExtension: String { - case xcodeproj - case xcworkspace - case framework - case xcframework - case staticLibrary = "a" - case dynamicLibrary = "dylib" - case textBasedDynamicLibrary = "tbd" - case coreData = "xcdatamodeld" - case playground = "playground" + case xcodeproj + case xcworkspace + case framework + case xcframework + case staticLibrary = "a" + case dynamicLibrary = "dylib" + case textBasedDynamicLibrary = "tbd" + case coreData = "xcdatamodeld" + case playground } extension AbsolutePath { - public static func resolvePaths( - _ paths: [String]?, - file: String = #file, - line: Int = #line, - function: String = #function - ) throws -> [AbsolutePath] { - return try paths?.compactMap { try AbsolutePath.resolvePath($0) } ?? [] - } - - public static func resolveOptionalPath( - _ path: String?, - file: String = #file, - line: Int = #line, - function: String = #function - ) throws -> AbsolutePath? { - guard let path = path else { return nil } - return try AbsolutePath.resolvePath(path) - } + public static func resolvePaths( + _ paths: [String]?, + file _: String = #file, + line _: Int = #line, + function _: String = #function + ) throws -> [AbsolutePath] { + return try paths?.compactMap { try AbsolutePath.resolvePath($0) } ?? [] + } - public static func resolvePath( - _ path: String, - relativeTo: AbsolutePath? = nil, - file: String = #file, - line: Int = #line, - function: String = #function - ) throws -> AbsolutePath { - do { - if let relativeTo { - return try AbsolutePath(validating: path, relativeTo: relativeTo) - } - return try AbsolutePath(validating: path) - } catch { - let message = """ - Invalid absolute path: '\(path)' - Thrown in \(function) at \(file):\(line) - Original error: \(error) - """ - throw NSError( - domain: "GraphMapperError", code: 1, - userInfo: [ - NSLocalizedDescriptionKey: message - ]) + public static func resolveOptionalPath( + _ path: String?, + file _: String = #file, + line _: Int = #line, + function _: String = #function + ) throws -> AbsolutePath? { + guard let path else { return nil } + return try AbsolutePath.resolvePath(path) } - } + public static func resolvePath( + _ path: String, + relativeTo: AbsolutePath? = nil, + file: String = #file, + line: Int = #line, + function: String = #function + ) throws -> AbsolutePath { + do { + if let relativeTo { + return try AbsolutePath(validating: path, relativeTo: relativeTo) + } + return try AbsolutePath(validating: path) + } catch { + let message = """ + Invalid absolute path: '\(path)' + Thrown in \(function) at \(file):\(line) + Original error: \(error) + """ + throw NSError( + domain: "GraphMapperError", code: 1, + userInfo: [ + NSLocalizedDescriptionKey: message, + ] + ) + } + } - public func mapByExtension(condition: PlatformCondition?) -> TargetDependency? { - let status: LinkingStatus = .required - let absPath = self - switch absPath.fileExtension { - case .framework: - return .framework(path: absPath, status: status, condition: condition) - case .xcframework: - return .xcframework(path: absPath, status: status, condition: condition) - case .dynamicLibrary, .textBasedDynamicLibrary, .staticLibrary: - return .library( - path: absPath, - publicHeaders: absPath.parentDirectory, - swiftModuleMap: nil, - condition: condition - ) - default: - return nil + public func mapByExtension(condition: PlatformCondition?) -> TargetDependency? { + let status: LinkingStatus = .required + let absPath = self + switch absPath.fileExtension { + case .framework: + return .framework(path: absPath, status: status, condition: condition) + case .xcframework: + return .xcframework(path: absPath, status: status, condition: condition) + case .dynamicLibrary, .textBasedDynamicLibrary, .staticLibrary: + return .library( + path: absPath, + publicHeaders: absPath.parentDirectory, + swiftModuleMap: nil, + condition: condition + ) + default: + return nil + } } - } - var fileExtension: FileExtension? { - guard let ext = self.extension?.lowercased() else { return nil } - return FileExtension(rawValue: ext) - } + var fileExtension: FileExtension? { + guard let ext = self.extension?.lowercased() else { return nil } + return FileExtension(rawValue: ext) + } } diff --git a/Sources/XcodeProjToGraph/Extensions/Package+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/Package+Extensions.swift index 02d12b10..503be76f 100644 --- a/Sources/XcodeProjToGraph/Extensions/Package+Extensions.swift +++ b/Sources/XcodeProjToGraph/Extensions/Package+Extensions.swift @@ -1,13 +1,13 @@ import XcodeGraph extension Package { - /// Returns a URL or identifier for the package based on whether it's remote or local. - public var url: String { - switch self { - case .remote(let url, _): - return url - case .local(let path): - return path.pathString + /// Returns a URL or identifier for the package based on whether it's remote or local. + public var url: String { + switch self { + case let .remote(url, _): + return url + case let .local(path): + return path.pathString + } } - } } diff --git a/Sources/XcodeProjToGraph/Extensions/Platform+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/Platform+Extensions.swift index dc67f6cd..1ab4d705 100644 --- a/Sources/XcodeProjToGraph/Extensions/Platform+Extensions.swift +++ b/Sources/XcodeProjToGraph/Extensions/Platform+Extensions.swift @@ -1,28 +1,28 @@ import XcodeGraph extension Platform { - /// Initializes a `Platform` instance from an SDK root string (e.g., "iphoneos", "macosx"). - /// Returns `nil` if no matching platform is found. - public init?(sdkroot: String) { - guard let platform = Platform.allCases.first(where: { $0.xcodeSdkRoot == sdkroot }) else { - return nil + /// Initializes a `Platform` instance from an SDK root string (e.g., "iphoneos", "macosx"). + /// Returns `nil` if no matching platform is found. + public init?(sdkroot: String) { + guard let platform = Platform.allCases.first(where: { $0.xcodeSdkRoot == sdkroot }) else { + return nil + } + self = platform } - self = platform - } - /// Returns a set of `Destination` values supported by this platform. - public var destinations: Destinations { - switch self { - case .iOS: - return [.iPad, .iPhone, .macCatalyst, .macWithiPadDesign, .appleVisionWithiPadDesign] - case .macOS: - return [.mac] - case .tvOS: - return [.appleTv] - case .watchOS: - return [.appleWatch] - case .visionOS: - return [.appleVision] + /// Returns a set of `Destination` values supported by this platform. + public var destinations: Destinations { + switch self { + case .iOS: + return [.iPad, .iPhone, .macCatalyst, .macWithiPadDesign, .appleVisionWithiPadDesign] + case .macOS: + return [.mac] + case .tvOS: + return [.appleTv] + case .watchOS: + return [.appleWatch] + case .visionOS: + return [.appleVision] + } } - } } diff --git a/Sources/XcodeProjToGraph/Extensions/PlatformFilter+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/PlatformFilter+Extensions.swift index e652dbf5..d3906440 100644 --- a/Sources/XcodeProjToGraph/Extensions/PlatformFilter+Extensions.swift +++ b/Sources/XcodeProjToGraph/Extensions/PlatformFilter+Extensions.swift @@ -1,25 +1,25 @@ import XcodeGraph extension PlatformFilter { - /// Initializes a `PlatformFilter` from a string that matches Xcodeproj values. - init?(rawValue: String) { - switch rawValue { - case PlatformFilter.ios.xcodeprojValue: - self = .ios - case PlatformFilter.macos.xcodeprojValue: - self = .macos - case PlatformFilter.tvos.xcodeprojValue: - self = .tvos - case PlatformFilter.catalyst.xcodeprojValue: - self = .catalyst - case PlatformFilter.driverkit.xcodeprojValue: - self = .driverkit - case PlatformFilter.watchos.xcodeprojValue: - self = .watchos - case PlatformFilter.visionos.xcodeprojValue: - self = .visionos - default: - return nil + /// Initializes a `PlatformFilter` from a string that matches Xcodeproj values. + init?(rawValue: String) { + switch rawValue { + case PlatformFilter.ios.xcodeprojValue: + self = .ios + case PlatformFilter.macos.xcodeprojValue: + self = .macos + case PlatformFilter.tvos.xcodeprojValue: + self = .tvos + case PlatformFilter.catalyst.xcodeprojValue: + self = .catalyst + case PlatformFilter.driverkit.xcodeprojValue: + self = .driverkit + case PlatformFilter.watchos.xcodeprojValue: + self = .watchos + case PlatformFilter.visionos.xcodeprojValue: + self = .visionos + default: + return nil + } } - } } diff --git a/Sources/XcodeProjToGraph/Extensions/Sequence+Async.swift b/Sources/XcodeProjToGraph/Extensions/Sequence+Async.swift index 0c2e4890..13cea053 100644 --- a/Sources/XcodeProjToGraph/Extensions/Sequence+Async.swift +++ b/Sources/XcodeProjToGraph/Extensions/Sequence+Async.swift @@ -1,24 +1,24 @@ import Foundation extension Sequence where Element: Sendable { - func asyncCompactMap(_ transform: @escaping @Sendable (Element) async throws -> T?) - async throws -> [T] - { - var results = [T]() - try await withThrowingTaskGroup(of: T?.self) { group in - for element in self { - group.addTask { - try await transform(element) - } - } + func asyncCompactMap(_ transform: @escaping @Sendable (Element) async throws -> T?) + async throws -> [T] + { + var results = [T]() + try await withThrowingTaskGroup(of: T?.self) { group in + for element in self { + group.addTask { + try await transform(element) + } + } - for try await value in group { - if let value = value { - results.append(value) + for try await value in group { + if let value { + results.append(value) + } + } } - } - } - return results - } + return results + } } diff --git a/Sources/XcodeProjToGraph/Extensions/TargetDependency+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/TargetDependency+Extensions.swift index 0e1f3eb8..a6d0f65a 100644 --- a/Sources/XcodeProjToGraph/Extensions/TargetDependency+Extensions.swift +++ b/Sources/XcodeProjToGraph/Extensions/TargetDependency+Extensions.swift @@ -2,25 +2,25 @@ import XcodeGraph extension TargetDependency { - /// Extracts the name of the dependency for relevant cases, such as target, project, SDK, package, and libraries. - public var name: String { - switch self { - case .target(let name, _, _): - return name - case .project(let target, _, _, _): - return target - case .sdk(let name, _, _): - return name - case .package(let product, _, _): - return product - case .framework(let path, _, _): - return path.basenameWithoutExt - case .xcframework(let path, _, _): - return path.basenameWithoutExt - case .library(let path, _, _, _): - return path.basenameWithoutExt - case .xctest: - return "xctest" + /// Extracts the name of the dependency for relevant cases, such as target, project, SDK, package, and libraries. + public var name: String { + switch self { + case let .target(name, _, _): + return name + case let .project(target, _, _, _): + return target + case let .sdk(name, _, _): + return name + case let .package(product, _, _): + return product + case let .framework(path, _, _): + return path.basenameWithoutExt + case let .xcframework(path, _, _): + return path.basenameWithoutExt + case let .library(path, _, _, _): + return path.basenameWithoutExt + case .xctest: + return "xctest" + } } - } } diff --git a/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift index fb995324..513ab45a 100644 --- a/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift +++ b/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift @@ -2,35 +2,35 @@ import Path import XcodeProj extension XCWorkspaceDataFileRef { - func absolutePath(srcPath: AbsolutePath) throws -> AbsolutePath { - switch location { - case .absolute(let path): - let absolutePath = try AbsolutePath.resolvePath(path) - return absolutePath - case .container(let subPath): - let relativePath = try RelativePath(validating: subPath) - let absolutePath = srcPath.appending(relativePath) - return absolutePath - case .developer(let subPath): - let relativePath = try RelativePath(validating: subPath) - let developerPath = try AbsolutePath.resolvePath("/Applications/Xcode.app/Contents/Developer") - let absolutePath = developerPath.appending(relativePath) - return absolutePath - case .group(let subPath): - // Group paths are relative to the workspace file itself - let relativePath = try RelativePath(validating: subPath) - let absolutePath = srcPath.appending(relativePath) - return absolutePath - case .current(let subPath): - // Current paths are relative to the current directory (commonly workspace path) - let relativePath = try RelativePath(validating: subPath) - let absolutePath = srcPath.appending(relativePath) - return absolutePath - case .other(let type, let subPath): - // Handle other path types by prefixing with the type and appending the subpath - let relativePath = try RelativePath(validating: "\(type)/\(subPath)") - let absolutePath = srcPath.appending(relativePath) - return absolutePath + func absolutePath(srcPath: AbsolutePath) throws -> AbsolutePath { + switch location { + case let .absolute(path): + let absolutePath = try AbsolutePath.resolvePath(path) + return absolutePath + case let .container(subPath): + let relativePath = try RelativePath(validating: subPath) + let absolutePath = srcPath.appending(relativePath) + return absolutePath + case let .developer(subPath): + let relativePath = try RelativePath(validating: subPath) + let developerPath = try AbsolutePath.resolvePath("/Applications/Xcode.app/Contents/Developer") + let absolutePath = developerPath.appending(relativePath) + return absolutePath + case let .group(subPath): + // Group paths are relative to the workspace file itself + let relativePath = try RelativePath(validating: subPath) + let absolutePath = srcPath.appending(relativePath) + return absolutePath + case let .current(subPath): + // Current paths are relative to the current directory (commonly workspace path) + let relativePath = try RelativePath(validating: subPath) + let absolutePath = srcPath.appending(relativePath) + return absolutePath + case let .other(type, subPath): + // Handle other path types by prefixing with the type and appending the subpath + let relativePath = try RelativePath(validating: "\(type)/\(subPath)") + let absolutePath = srcPath.appending(relativePath) + return absolutePath + } } - } } diff --git a/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseConstants.swift b/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseConstants.swift index 098d07a4..d8468e4a 100644 --- a/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseConstants.swift +++ b/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseConstants.swift @@ -3,46 +3,44 @@ import Path /// Constants related to various build phases and their default values. enum BuildPhaseConstants { - /// The default name for a run script build phase if none is provided. - static let defaultScriptName = "Run Script" - /// The default shell path used by run script build phases. - static let defaultShellPath = "/bin/sh" - /// A placeholder name used when a shell script build phase has no name. - static let unnamedScriptPhase = "Unnamed Shell Script Phase" - /// The default name for a copy files build phase if none is provided. - static let copyFilesDefault = "Copy Files" + /// The default name for a run script build phase if none is provided. + static let defaultScriptName = "Run Script" + /// The default shell path used by run script build phases. + static let defaultShellPath = "/bin/sh" + /// A placeholder name used when a shell script build phase has no name. + static let unnamedScriptPhase = "Unnamed Shell Script Phase" + /// The default name for a copy files build phase if none is provided. + static let copyFilesDefault = "Copy Files" } /// Attributes indicating header visibility within a build target. enum HeaderAttribute: String { - /// Indicates that a header is public and can be exposed outside the module. - case `public` = "Public" - /// Indicates that a header is private and not exposed outside the module. - case `private` = "Private" + /// Indicates that a header is public and can be exposed outside the module. + case `public` = "Public" + /// Indicates that a header is private and not exposed outside the module. + case `private` = "Private" } /// Attributes related to code generation behavior for source files. enum CodeGenAttribute: String { - /// Indicates that code generation is enabled publicly. - case `public` = "codegen" - /// Indicates that code generation is restricted to private scopes. - case `private` = "private_codegen" - /// Indicates that code generation is scoped to the project only. - case project = "project_codegen" - /// Indicates that code generation is disabled for the file. - case disabled = "no_codegen" + /// Indicates that code generation is enabled publicly. + case `public` = "codegen" + /// Indicates that code generation is restricted to private scopes. + case `private` = "private_codegen" + /// Indicates that code generation is scoped to the project only. + case project = "project_codegen" + /// Indicates that code generation is disabled for the file. + case disabled = "no_codegen" } /// Commonly referenced directory names within a project. enum DirectoryName { - /// The directory used to store headers. - static let headers = "Headers" + /// The directory used to store headers. + static let headers = "Headers" } /// Attributes that can be assigned to build files in certain build phases. enum BuildFileAttribute: String { - /// Indicates that the file should be code signed on copy during a copy files build phase. - case codeSignOnCopy = "CodeSignOnCopy" + /// Indicates that the file should be code signed on copy during a copy files build phase. + case codeSignOnCopy = "CodeSignOnCopy" } - - diff --git a/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift b/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift index bb166dc3..53e5b20e 100644 --- a/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift @@ -11,67 +11,67 @@ import XcodeProj /// This allows downstream tools or processes to work with a structured, semantic representation of the build /// steps involved in an Xcode target. protocol BuildPhaseMapping: Sendable { - /// Maps source files from the target's Sources build phase. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `SourceFile` instances representing the target’s source files. - /// - Throws: If file references cannot be resolved or paths are invalid. - func mapSources(target: PBXTarget) async throws -> [SourceFile] - - /// Maps resource files from the target's Resources build phase. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `ResourceFileElement` instances representing the target’s resources. - /// - Throws: If resource references cannot be resolved or paths are invalid. - func mapResources(target: PBXTarget) async throws -> [ResourceFileElement] - - /// Maps headers from the target’s Headers build phase. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: A `Headers` instance if headers are present, or `nil` if none found. - /// - Throws: If header file references cannot be resolved. - func mapHeaders(target: PBXTarget) async throws -> Headers? - - /// Maps scripts from shell script build phases. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `TargetScript` instances representing each shell script build phase. - /// - Throws: If script file references or paths cannot be resolved. - func mapScripts(target: PBXTarget) async throws -> [TargetScript] - - /// Maps copy files build phases. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `CopyFilesAction` instances describing how files are copied at build time. - /// - Throws: If file references or paths cannot be resolved. - func mapCopyFiles(target: PBXTarget) async throws -> [CopyFilesAction] - - /// Maps Core Data models from the target’s resource phases. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `CoreDataModel` instances describing the target’s Core Data models. - /// - Throws: If model paths cannot be resolved. - func mapCoreDataModels(target: PBXTarget) async throws -> [CoreDataModel] - - /// Maps raw script build phases for debugging or analysis. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `RawScriptBuildPhase` instances representing the raw script phases. - func mapRawScriptBuildPhases(target: PBXTarget) async throws -> [RawScriptBuildPhase] - - /// Maps additional files that are not included in any build phase. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `FileElement` for files that are part of the project but not in build phases. - /// - Throws: If file references or paths cannot be resolved. - func mapAdditionalFiles(target: PBXTarget) async throws -> [FileElement] - - /// Maps frameworks referenced by the target’s frameworks build phase. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `TargetDependency` instances representing frameworks. - /// - Throws: If framework references or paths cannot be resolved. - func mapFrameworks(target: PBXTarget) async throws -> [TargetDependency] + /// Maps source files from the target's Sources build phase. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `SourceFile` instances representing the target’s source files. + /// - Throws: If file references cannot be resolved or paths are invalid. + func mapSources(target: PBXTarget) async throws -> [SourceFile] + + /// Maps resource files from the target's Resources build phase. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `ResourceFileElement` instances representing the target’s resources. + /// - Throws: If resource references cannot be resolved or paths are invalid. + func mapResources(target: PBXTarget) async throws -> [ResourceFileElement] + + /// Maps headers from the target’s Headers build phase. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: A `Headers` instance if headers are present, or `nil` if none found. + /// - Throws: If header file references cannot be resolved. + func mapHeaders(target: PBXTarget) async throws -> Headers? + + /// Maps scripts from shell script build phases. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `TargetScript` instances representing each shell script build phase. + /// - Throws: If script file references or paths cannot be resolved. + func mapScripts(target: PBXTarget) async throws -> [TargetScript] + + /// Maps copy files build phases. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `CopyFilesAction` instances describing how files are copied at build time. + /// - Throws: If file references or paths cannot be resolved. + func mapCopyFiles(target: PBXTarget) async throws -> [CopyFilesAction] + + /// Maps Core Data models from the target’s resource phases. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `CoreDataModel` instances describing the target’s Core Data models. + /// - Throws: If model paths cannot be resolved. + func mapCoreDataModels(target: PBXTarget) async throws -> [CoreDataModel] + + /// Maps raw script build phases for debugging or analysis. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `RawScriptBuildPhase` instances representing the raw script phases. + func mapRawScriptBuildPhases(target: PBXTarget) async throws -> [RawScriptBuildPhase] + + /// Maps additional files that are not included in any build phase. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `FileElement` for files that are part of the project but not in build phases. + /// - Throws: If file references or paths cannot be resolved. + func mapAdditionalFiles(target: PBXTarget) async throws -> [FileElement] + + /// Maps frameworks referenced by the target’s frameworks build phase. + /// + /// - Parameter target: The Xcode target to map. + /// - Returns: An array of `TargetDependency` instances representing frameworks. + /// - Throws: If framework references or paths cannot be resolved. + func mapFrameworks(target: PBXTarget) async throws -> [TargetDependency] } /// A mapper responsible for converting the build phases of a `PBXTarget` into corresponding domain models. @@ -83,339 +83,343 @@ protocol BuildPhaseMapping: Sendable { /// etc.), it enables subsequent steps (like code generation, analysis, or custom tooling) to operate on a well-structured, /// semantic representation of the target’s build phases. public final class BuildPhaseMapper: BuildPhaseMapping { - private let projectProvider: ProjectProviding - - /// Creates a new `BuildPhaseMapper`. - /// - /// - Parameter projectProvider: Provides access to the project’s paths, files, and parsed structures. - public init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - } - - public func mapSources(target: PBXTarget) async throws -> [SourceFile] { - guard let sourcesPhase = try target.sourcesBuildPhase() else { return [] } - return try await sourcesPhase.files?.asyncCompactMap { try await self.mapSourceFile($0) }.sorted { $0.path < $1.path } ?? [] - } - - public func mapResources(target: PBXTarget) async throws -> [ResourceFileElement] { - guard let resourcesPhase = try target.resourcesBuildPhase() else { return [] } - var resources = [ResourceFileElement]() - for buildFile in resourcesPhase.files ?? [] { - let resourceElements = try await mapResourceElement(buildFile) - resources.append(contentsOf: resourceElements) + private let projectProvider: ProjectProviding + + /// Creates a new `BuildPhaseMapper`. + /// + /// - Parameter projectProvider: Provides access to the project’s paths, files, and parsed structures. + public init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + } + + public func mapSources(target: PBXTarget) async throws -> [SourceFile] { + guard let sourcesPhase = try target.sourcesBuildPhase() else { return [] } + return try await sourcesPhase.files?.asyncCompactMap { try await self.mapSourceFile($0) } + .sorted { $0.path < $1.path } ?? [] } - return resources.sorted { $0.path < $1.path } - } - - public func mapHeaders(target: PBXTarget) async throws -> Headers? { - guard let headersPhase = try target.headersBuildPhase() else { return nil } - - var publicHeaders = [AbsolutePath]() - var privateHeaders = [AbsolutePath]() - var projectHeaders = [AbsolutePath]() - - for buildFile in headersPhase.files ?? [] { - if let headerInfo = try await mapHeaderFile(buildFile) { - switch headerInfo.visibility { - case .public: publicHeaders.append(headerInfo.path) - case .private: privateHeaders.append(headerInfo.path) - case .project: projectHeaders.append(headerInfo.path) + + public func mapResources(target: PBXTarget) async throws -> [ResourceFileElement] { + guard let resourcesPhase = try target.resourcesBuildPhase() else { return [] } + var resources = [ResourceFileElement]() + for buildFile in resourcesPhase.files ?? [] { + let resourceElements = try await mapResourceElement(buildFile) + resources.append(contentsOf: resourceElements) } - } + return resources.sorted { $0.path < $1.path } } - return Headers( - public: publicHeaders, - private: privateHeaders, - project: projectHeaders - ) - } - - public func mapScripts(target: PBXTarget) async throws -> [TargetScript] { - let scriptPhases = target.buildPhases.compactMap { $0 as? PBXShellScriptBuildPhase } - return try await scriptPhases.asyncCompactMap { try await self.mapScriptPhase($0, in: target) } - } - - public func mapCopyFiles(target: PBXTarget) async throws -> [CopyFilesAction] { - let copyFilesPhases = target.buildPhases.compactMap { $0 as? PBXCopyFilesBuildPhase } - return try await copyFilesPhases.asyncCompactMap { try await self.mapCopyFilesPhase($0) }.sorted { $0.name < $1.name } - } - - public func mapCoreDataModels(target: PBXTarget) async throws -> [CoreDataModel] { - guard let resourcesPhase = try target.resourcesBuildPhase() else { return [] } - return try resourcesPhase.files?.compactMap { try self.mapCoreDataModel($0) } - ?? [] - } - - public func mapRawScriptBuildPhases(target: PBXTarget) async throws -> [RawScriptBuildPhase] { - let scriptPhases = target.runScriptBuildPhases() - return scriptPhases.compactMap { mapShellScriptBuildPhase($0) } - } - - public func mapAdditionalFiles(target: PBXTarget) async throws -> [FileElement] { - let xcodeProj = projectProvider.xcodeProj - guard let pbxProject = xcodeProj.pbxproj.projects.first, - let mainGroup = pbxProject.mainGroup - else { - throw MappingError.noProjectsFound + public func mapHeaders(target: PBXTarget) async throws -> Headers? { + guard let headersPhase = try target.headersBuildPhase() else { return nil } + + var publicHeaders = [AbsolutePath]() + var privateHeaders = [AbsolutePath]() + var projectHeaders = [AbsolutePath]() + + for buildFile in headersPhase.files ?? [] { + if let headerInfo = try await mapHeaderFile(buildFile) { + switch headerInfo.visibility { + case .public: publicHeaders.append(headerInfo.path) + case .private: privateHeaders.append(headerInfo.path) + case .project: projectHeaders.append(headerInfo.path) + } + } + } + + return Headers( + public: publicHeaders, + private: privateHeaders, + project: projectHeaders + ) + } + + public func mapScripts(target: PBXTarget) async throws -> [TargetScript] { + let scriptPhases = target.buildPhases.compactMap { $0 as? PBXShellScriptBuildPhase } + return try await scriptPhases.asyncCompactMap { try await self.mapScriptPhase($0, in: target) } + } + + public func mapCopyFiles(target: PBXTarget) async throws -> [CopyFilesAction] { + let copyFilesPhases = target.buildPhases.compactMap { $0 as? PBXCopyFilesBuildPhase } + return try await copyFilesPhases.asyncCompactMap { try await self.mapCopyFilesPhase($0) }.sorted { $0.name < $1.name } + } + + public func mapCoreDataModels(target: PBXTarget) async throws -> [CoreDataModel] { + guard let resourcesPhase = try target.resourcesBuildPhase() else { return [] } + return try resourcesPhase.files?.compactMap { try self.mapCoreDataModel($0) } + ?? [] + } + + public func mapRawScriptBuildPhases(target: PBXTarget) async throws -> [RawScriptBuildPhase] { + let scriptPhases = target.runScriptBuildPhases() + return scriptPhases.compactMap { mapShellScriptBuildPhase($0) } + } + + public func mapAdditionalFiles(target: PBXTarget) async throws -> [FileElement] { + let xcodeProj = projectProvider.xcodeProj + guard let pbxProject = xcodeProj.pbxproj.projects.first, + let mainGroup = pbxProject.mainGroup + else { + throw MappingError.noProjectsFound + } + + let allFiles = try await collectFiles(from: mainGroup) + let filesInBuildPhases = try await getFilesInBuildPhases(target: target) + let additionalFiles = allFiles.subtracting(filesInBuildPhases) + + return additionalFiles.map { FileElement.file(path: $0) } } - let allFiles = try await collectFiles(from: mainGroup) - let filesInBuildPhases = try await getFilesInBuildPhases(target: target) - let additionalFiles = allFiles.subtracting(filesInBuildPhases) - - return additionalFiles.map { FileElement.file(path: $0) } - } - - public func mapFrameworks(target: PBXTarget) async throws -> [TargetDependency] { - let frameworksPhases = target.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase } - let allFrameworkFiles = frameworksPhases.flatMap { $0.files ?? [] } - return try await allFrameworkFiles.asyncCompactMap { try await self.mapFrameworkDependency($0) } - } - - // MARK: - Private Helpers - - private func mapDstSubfolderSpec(_ subfolderSpec: PBXCopyFilesBuildPhase.SubFolder?) - -> CopyFilesAction.Destination - { - switch subfolderSpec { - case .absolutePath: return .absolutePath - case .productsDirectory: return .productsDirectory - case .wrapper: return .wrapper - case .executables: return .executables - case .resources: return .resources - case .javaResources: return .javaResources - case .frameworks: return .frameworks - case .sharedFrameworks: return .sharedFrameworks - case .sharedSupport: return .sharedSupport - case .plugins: return .plugins - default: return .productsDirectory + public func mapFrameworks(target: PBXTarget) async throws -> [TargetDependency] { + let frameworksPhases = target.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase } + let allFrameworkFiles = frameworksPhases.flatMap { $0.files ?? [] } + return try await allFrameworkFiles.asyncCompactMap { try await self.mapFrameworkDependency($0) } } - } - private func determineScriptOrder(target: PBXTarget, scriptPhase: PBXShellScriptBuildPhase) - -> TargetScript.Order - { - guard let scriptPhaseIndex = target.buildPhases.firstIndex(of: scriptPhase) else { - return .pre + // MARK: - Private Helpers + + private func mapDstSubfolderSpec(_ subfolderSpec: PBXCopyFilesBuildPhase.SubFolder?) + -> CopyFilesAction.Destination + { + switch subfolderSpec { + case .absolutePath: return .absolutePath + case .productsDirectory: return .productsDirectory + case .wrapper: return .wrapper + case .executables: return .executables + case .resources: return .resources + case .javaResources: return .javaResources + case .frameworks: return .frameworks + case .sharedFrameworks: return .sharedFrameworks + case .sharedSupport: return .sharedSupport + case .plugins: return .plugins + default: return .productsDirectory + } } - if let sourcesPhaseIndex = target.buildPhases.firstIndex(where: { $0.buildPhase == .sources }) { - return scriptPhaseIndex > sourcesPhaseIndex ? .post : .pre + + private func determineScriptOrder(target: PBXTarget, scriptPhase: PBXShellScriptBuildPhase) + -> TargetScript.Order + { + guard let scriptPhaseIndex = target.buildPhases.firstIndex(of: scriptPhase) else { + return .pre + } + if let sourcesPhaseIndex = target.buildPhases.firstIndex(where: { $0.buildPhase == .sources }) { + return scriptPhaseIndex > sourcesPhaseIndex ? .post : .pre + } + return scriptPhaseIndex == 0 ? .pre : .post } - return scriptPhaseIndex == 0 ? .pre : .post - } - - private func mapSourceFile(_ buildFile: PBXBuildFile) async throws -> SourceFile? { - guard let fileRef = buildFile.file, - let pathString = try fileRef.fullPath(sourceRoot: projectProvider.sourcePathString) - else { return nil } - - let absPath = try AbsolutePath.resolvePath(pathString) - let settings = buildFile.settings ?? [:] - let compilerFlags: String? = settings.string(for: .compilerFlags) - let attributes: [String]? = settings.stringArray(for: .attributes) - - return SourceFile( - path: absPath, - compilerFlags: compilerFlags, - codeGen: mapCodeGenAttribute(attributes) - ) - } - - private func mapCopyFilesPhase(_ phase: PBXCopyFilesBuildPhase) async throws -> CopyFilesAction? { - let files = - try await phase.files?.asyncCompactMap { buildFile -> CopyFileElement? in + + private func mapSourceFile(_ buildFile: PBXBuildFile) async throws -> SourceFile? { guard let fileRef = buildFile.file, - let pathString = try fileRef.fullPath( - sourceRoot: self.projectProvider.sourcePathString) + let pathString = try fileRef.fullPath(sourceRoot: projectProvider.sourcePathString) else { return nil } - let absolutePath = try AbsolutePath.resolvePath(pathString) - let attributes: [String]? = buildFile.settings?.stringArray(for: .attributes) - let codeSignOnCopy = - attributes?.contains(BuildFileAttribute.codeSignOnCopy.rawValue) ?? false - - return .file(path: absolutePath, condition: nil, codeSignOnCopy: codeSignOnCopy) - } ?? [] - - return CopyFilesAction( - name: phase.name ?? BuildPhaseConstants.copyFilesDefault, - destination: mapDstSubfolderSpec(phase.dstSubfolderSpec), - subpath: phase.dstPath.flatMap { $0.isEmpty ? nil : $0 }, - files: files.sorted { $0.path < $1.path } - ) - } - - private func getFilesInBuildPhases(target: PBXTarget) async throws -> Set { - return Set( - try await target.buildPhases.asyncCompactMap { $0.files } - .flatMap { $0 } - .asyncCompactMap { buildFile -> AbsolutePath? in - guard let fileRef = buildFile.file, - let filePath = try fileRef.fullPath( - sourceRoot: self.projectProvider.sourcePathString) - else { - return nil - } - return try AbsolutePath.resolvePath(filePath) - }) - } + let absPath = try AbsolutePath.resolvePath(pathString) + let settings = buildFile.settings ?? [:] + let compilerFlags: String? = settings.string(for: .compilerFlags) + let attributes: [String]? = settings.stringArray(for: .attributes) - private func mapResourceElement(_ buildFile: PBXBuildFile) async throws -> [ResourceFileElement] { - try await self.mapResourceElement(buildFile.file) + return SourceFile( + path: absPath, + compilerFlags: compilerFlags, + codeGen: mapCodeGenAttribute(attributes) + ) + } + + private func mapCopyFilesPhase(_ phase: PBXCopyFilesBuildPhase) async throws -> CopyFilesAction? { + let files = + try await phase.files?.asyncCompactMap { buildFile -> CopyFileElement? in + guard let fileRef = buildFile.file, + let pathString = try fileRef.fullPath( + sourceRoot: self.projectProvider.sourcePathString + ) + else { return nil } + + let absolutePath = try AbsolutePath.resolvePath(pathString) + let attributes: [String]? = buildFile.settings?.stringArray(for: .attributes) + let codeSignOnCopy = + attributes?.contains(BuildFileAttribute.codeSignOnCopy.rawValue) ?? false + + return .file(path: absolutePath, condition: nil, codeSignOnCopy: codeSignOnCopy) + } ?? [] + + return CopyFilesAction( + name: phase.name ?? BuildPhaseConstants.copyFilesDefault, + destination: mapDstSubfolderSpec(phase.dstSubfolderSpec), + subpath: phase.dstPath.flatMap { $0.isEmpty ? nil : $0 }, + files: files.sorted { $0.path < $1.path } + ) } + private func getFilesInBuildPhases(target: PBXTarget) async throws -> Set { + return Set( + try await target.buildPhases.asyncCompactMap { $0.files } + .flatMap { $0 } + .asyncCompactMap { buildFile -> AbsolutePath? in + guard let fileRef = buildFile.file, + let filePath = try fileRef.fullPath( + sourceRoot: self.projectProvider.sourcePathString + ) + else { + return nil + } + return try AbsolutePath.resolvePath(filePath) + } + ) + } + + private func mapResourceElement(_ buildFile: PBXBuildFile) async throws -> [ResourceFileElement] { + try await mapResourceElement(buildFile.file) + } private func mapResourceElement(_ fileElement: PBXFileElement?) async throws -> [ResourceFileElement] { - if let fileRef = fileElement, - let pathString = try fileRef.fullPath(sourceRoot: projectProvider.sourcePathString) + if let fileRef = fileElement, + let pathString = try fileRef.fullPath(sourceRoot: projectProvider.sourcePathString) + { + let absPath = try AbsolutePath.resolvePath(pathString) + return [.file(path: absPath)] + } + return [] + } + + private func mapVariantGroup(_ variantGroup: PBXVariantGroup) async throws + -> [ResourceFileElement] { - let absPath = try AbsolutePath.resolvePath(pathString) - return [.file(path: absPath)] + var elements = [ResourceFileElement]() + for child in variantGroup.children { + let childFiles = try await mapResourceElement(child) + elements.append(contentsOf: childFiles) + } + return elements } - return [] - } - - private func mapVariantGroup(_ variantGroup: PBXVariantGroup) async throws - -> [ResourceFileElement] - { - var elements = [ResourceFileElement]() - for child in variantGroup.children { - let childFiles = try await self.mapResourceElement(child) - elements.append(contentsOf: childFiles) + + private func collectFiles(from group: PBXGroup) async throws -> Set { + var files = Set() + for child in group.children { + if let file = child as? PBXFileReference, + let pathString = try file.fullPath(sourceRoot: projectProvider.sourcePathString), + let absPath = try? AbsolutePath.resolvePath(pathString) + { + files.insert(absPath) + } else if let subgroup = child as? PBXGroup { + files.formUnion(try await collectFiles(from: subgroup)) + } + } + return files } - return elements - } - - private func collectFiles(from group: PBXGroup) async throws -> Set { - var files = Set() - for child in group.children { - if let file = child as? PBXFileReference, - let pathString = try file.fullPath(sourceRoot: projectProvider.sourcePathString), - let absPath = try? AbsolutePath.resolvePath(pathString) - { - files.insert(absPath) - } else if let subgroup = child as? PBXGroup { - files.formUnion(try await collectFiles(from: subgroup)) - } + + private func mapFrameworkDependency(_ buildFile: PBXBuildFile) async throws -> TargetDependency? { + guard let fileRef = buildFile.file, + let filePath = try fileRef.fullPath( + sourceRoot: projectProvider.sourceDirectory.pathString + ) + else { return nil } + + let absPath = try AbsolutePath.resolvePath(filePath) + return absPath.mapByExtension(condition: nil) } - return files - } - - private func mapFrameworkDependency(_ buildFile: PBXBuildFile) async throws -> TargetDependency? { - guard let fileRef = buildFile.file, - let filePath = try fileRef.fullPath( - sourceRoot: projectProvider.sourceDirectory.pathString) - else { return nil } - - let absPath = try AbsolutePath.resolvePath(filePath) - return absPath.mapByExtension(condition: nil) - } - - private func mapHeaderFile(_ buildFile: PBXBuildFile) async throws -> HeaderInfo? { - guard let pbxElement = buildFile.file, - let pathString = try pbxElement.fullPath(sourceRoot: projectProvider.sourcePathString) - else { return nil } - - let attributes: [String]? = buildFile.settings?.stringArray(for: .attributes) - let absolutePath = try AbsolutePath.resolvePath(pathString) - - let visibility: HeaderInfo.HeaderVisibility - if attributes?.contains(HeaderAttribute.public.rawValue) == true { - visibility = .public - } else if attributes?.contains(HeaderAttribute.private.rawValue) == true { - visibility = .private - } else { - visibility = .project + + private func mapHeaderFile(_ buildFile: PBXBuildFile) async throws -> HeaderInfo? { + guard let pbxElement = buildFile.file, + let pathString = try pbxElement.fullPath(sourceRoot: projectProvider.sourcePathString) + else { return nil } + + let attributes: [String]? = buildFile.settings?.stringArray(for: .attributes) + let absolutePath = try AbsolutePath.resolvePath(pathString) + + let visibility: HeaderInfo.HeaderVisibility + if attributes?.contains(HeaderAttribute.public.rawValue) == true { + visibility = .public + } else if attributes?.contains(HeaderAttribute.private.rawValue) == true { + visibility = .private + } else { + visibility = .project + } + + return HeaderInfo(path: absolutePath, visibility: visibility) } - return HeaderInfo(path: absolutePath, visibility: visibility) - } - - private func mapScriptPhase(_ scriptPhase: PBXShellScriptBuildPhase, in target: PBXTarget) - async throws -> TargetScript? - { - guard let shellScript = scriptPhase.shellScript else { return nil } - - return TargetScript( - name: scriptPhase.name ?? BuildPhaseConstants.defaultScriptName, - order: determineScriptOrder(target: target, scriptPhase: scriptPhase), - script: .embedded(shellScript), - inputPaths: scriptPhase.inputPaths, - inputFileListPaths: try AbsolutePath.resolvePaths(scriptPhase.inputFileListPaths), - outputPaths: scriptPhase.outputPaths, - outputFileListPaths: try AbsolutePath.resolvePaths(scriptPhase.outputFileListPaths), - showEnvVarsInLog: scriptPhase.showEnvVarsInLog, - basedOnDependencyAnalysis: scriptPhase.alwaysOutOfDate ? false : nil, - runForInstallBuildsOnly: scriptPhase.runOnlyForDeploymentPostprocessing, - shellPath: scriptPhase.shellPath ?? BuildPhaseConstants.defaultShellPath, - dependencyFile: try AbsolutePath.resolveOptionalPath(scriptPhase.dependencyFile) - ) - } - - private func mapShellScriptBuildPhase(_ buildPhase: PBXShellScriptBuildPhase) - -> RawScriptBuildPhase - { - let name = buildPhase.name() ?? BuildPhaseConstants.unnamedScriptPhase - let shellPath = buildPhase.shellPath ?? BuildPhaseConstants.defaultShellPath - let script = buildPhase.shellScript ?? "" - let showEnvVarsInLog = buildPhase.showEnvVarsInLog - - return RawScriptBuildPhase( - name: name, - script: script, - showEnvVarsInLog: showEnvVarsInLog, - hashable: false, - shellPath: shellPath - ) - } - - private func mapCoreDataModel(_ buildFile: PBXBuildFile) throws -> CoreDataModel? { - guard let versionGroup = buildFile.file as? XCVersionGroup, - versionGroup.path?.hasSuffix(FileExtension.coreData.rawValue) == true, - let modelPathString = try versionGroup.fullPath(sourceRoot: projectProvider.sourcePathString) - else { - return nil + private func mapScriptPhase(_ scriptPhase: PBXShellScriptBuildPhase, in target: PBXTarget) + async throws -> TargetScript? + { + guard let shellScript = scriptPhase.shellScript else { return nil } + + return TargetScript( + name: scriptPhase.name ?? BuildPhaseConstants.defaultScriptName, + order: determineScriptOrder(target: target, scriptPhase: scriptPhase), + script: .embedded(shellScript), + inputPaths: scriptPhase.inputPaths, + inputFileListPaths: try AbsolutePath.resolvePaths(scriptPhase.inputFileListPaths), + outputPaths: scriptPhase.outputPaths, + outputFileListPaths: try AbsolutePath.resolvePaths(scriptPhase.outputFileListPaths), + showEnvVarsInLog: scriptPhase.showEnvVarsInLog, + basedOnDependencyAnalysis: scriptPhase.alwaysOutOfDate ? false : nil, + runForInstallBuildsOnly: scriptPhase.runOnlyForDeploymentPostprocessing, + shellPath: scriptPhase.shellPath ?? BuildPhaseConstants.defaultShellPath, + dependencyFile: try AbsolutePath.resolveOptionalPath(scriptPhase.dependencyFile) + ) + } + + private func mapShellScriptBuildPhase(_ buildPhase: PBXShellScriptBuildPhase) + -> RawScriptBuildPhase + { + let name = buildPhase.name() ?? BuildPhaseConstants.unnamedScriptPhase + let shellPath = buildPhase.shellPath ?? BuildPhaseConstants.defaultShellPath + let script = buildPhase.shellScript ?? "" + let showEnvVarsInLog = buildPhase.showEnvVarsInLog + + return RawScriptBuildPhase( + name: name, + script: script, + showEnvVarsInLog: showEnvVarsInLog, + hashable: false, + shellPath: shellPath + ) } - let absModelPath = try AbsolutePath.resolvePath(modelPathString) - let versions = versionGroup.children.compactMap { $0.path } - let validatedVersions = try versions.map { - try AbsolutePath.resolvePath($0, relativeTo: absModelPath) + private func mapCoreDataModel(_ buildFile: PBXBuildFile) throws -> CoreDataModel? { + guard let versionGroup = buildFile.file as? XCVersionGroup, + versionGroup.path?.hasSuffix(FileExtension.coreData.rawValue) == true, + let modelPathString = try versionGroup.fullPath(sourceRoot: projectProvider.sourcePathString) + else { + return nil + } + + let absModelPath = try AbsolutePath.resolvePath(modelPathString) + let versions = versionGroup.children.compactMap(\.path) + let validatedVersions = try versions.map { + try AbsolutePath.resolvePath($0, relativeTo: absModelPath) + } + let currentVersion = + versionGroup.currentVersion?.path ?? validatedVersions.first?.pathString ?? "" + + return CoreDataModel( + path: absModelPath, + versions: validatedVersions, + currentVersion: currentVersion + ) } - let currentVersion = - versionGroup.currentVersion?.path ?? validatedVersions.first?.pathString ?? "" - - return CoreDataModel( - path: absModelPath, - versions: validatedVersions, - currentVersion: currentVersion - ) - } - - private func mapCodeGenAttribute(_ attributes: [String]?) -> FileCodeGen? { - guard let attributes = attributes else { return nil } - - if attributes.contains(FileCodeGen.public.rawValue) { - return .public - } else if attributes.contains(FileCodeGen.private.rawValue) { - return .private - } else if attributes.contains(FileCodeGen.project.rawValue) { - return .project - } else if attributes.contains(FileCodeGen.disabled.rawValue) { - return .disabled + + private func mapCodeGenAttribute(_ attributes: [String]?) -> FileCodeGen? { + guard let attributes else { return nil } + + if attributes.contains(FileCodeGen.public.rawValue) { + return .public + } else if attributes.contains(FileCodeGen.private.rawValue) { + return .private + } else if attributes.contains(FileCodeGen.project.rawValue) { + return .project + } else if attributes.contains(FileCodeGen.disabled.rawValue) { + return .disabled + } + return nil } - return nil - } } private struct HeaderInfo { - let path: AbsolutePath - let visibility: HeaderVisibility - - enum HeaderVisibility { - case `public` - case `private` - case project - } + let path: AbsolutePath + let visibility: HeaderVisibility + + enum HeaderVisibility { + case `public` + case `private` + case project + } } diff --git a/Sources/XcodeProjToGraph/Mappers/Build/BuildRuleMapper.swift b/Sources/XcodeProjToGraph/Mappers/Build/BuildRuleMapper.swift index f71d9b9a..377761f6 100644 --- a/Sources/XcodeProjToGraph/Mappers/Build/BuildRuleMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Build/BuildRuleMapper.swift @@ -8,12 +8,12 @@ import XcodeGraph /// Conforming types transform build rules defined in Xcode projects into a structured `BuildRule` model, /// enabling further analysis or code generation steps to operate on a well-defined representation of these rules. protocol BuildRuleMapping: Sendable { - /// Maps the build rules of a given `PBXTarget` into an array of `BuildRule` models. - /// - /// - Parameter target: The `PBXTarget` whose build rules are to be mapped. - /// - Returns: An array of `BuildRule` models representing the target’s build rules. - /// - Throws: If resolving or mapping any of the build rules fails. - func mapBuildRules(target: PBXTarget) async throws -> [BuildRule] + /// Maps the build rules of a given `PBXTarget` into an array of `BuildRule` models. + /// + /// - Parameter target: The `PBXTarget` whose build rules are to be mapped. + /// - Returns: An array of `BuildRule` models representing the target’s build rules. + /// - Throws: If resolving or mapping any of the build rules fails. + func mapBuildRules(target: PBXTarget) async throws -> [BuildRule] } /// A mapper that converts `PBXBuildRule` objects into `BuildRule` domain models. @@ -22,42 +22,42 @@ protocol BuildRuleMapping: Sendable { /// the compiler specification and file type. If a rule references an unknown compiler spec or /// file type, that particular rule is skipped. final class BuildRuleMapper: BuildRuleMapping { - public func mapBuildRules(target: PBXTarget) async throws -> [BuildRule] { - return try await target.buildRules.asyncCompactMap { pbxBuildRule in - guard let compilerSpec = self.mapCompilerSpec(pbxBuildRule.compilerSpec), - let fileType = self.mapFileType(pbxBuildRule.fileType) - else { - // Unknown compiler spec or file type encountered. Skipping this build rule. - return nil - } + public func mapBuildRules(target: PBXTarget) async throws -> [BuildRule] { + return try await target.buildRules.asyncCompactMap { pbxBuildRule in + guard let compilerSpec = self.mapCompilerSpec(pbxBuildRule.compilerSpec), + let fileType = self.mapFileType(pbxBuildRule.fileType) + else { + // Unknown compiler spec or file type encountered. Skipping this build rule. + return nil + } - return BuildRule( - compilerSpec: compilerSpec, - fileType: fileType, - filePatterns: pbxBuildRule.filePatterns, - name: pbxBuildRule.name, - outputFiles: pbxBuildRule.outputFiles, - inputFiles: pbxBuildRule.inputFiles, - outputFilesCompilerFlags: pbxBuildRule.outputFilesCompilerFlags, - script: pbxBuildRule.script, - runOncePerArchitecture: pbxBuildRule.runOncePerArchitecture - ) + return BuildRule( + compilerSpec: compilerSpec, + fileType: fileType, + filePatterns: pbxBuildRule.filePatterns, + name: pbxBuildRule.name, + outputFiles: pbxBuildRule.outputFiles, + inputFiles: pbxBuildRule.inputFiles, + outputFilesCompilerFlags: pbxBuildRule.outputFilesCompilerFlags, + script: pbxBuildRule.script, + runOncePerArchitecture: pbxBuildRule.runOncePerArchitecture + ) + } } - } - /// Maps a compiler specification string to a `BuildRule.CompilerSpec`. - /// - /// - Parameter compilerSpec: The compiler specification string from the `PBXBuildRule`. - /// - Returns: A `BuildRule.CompilerSpec` instance if recognized; otherwise, `nil`. - public func mapCompilerSpec(_ compilerSpec: String) -> BuildRule.CompilerSpec? { - BuildRule.CompilerSpec(rawValue: compilerSpec) - } + /// Maps a compiler specification string to a `BuildRule.CompilerSpec`. + /// + /// - Parameter compilerSpec: The compiler specification string from the `PBXBuildRule`. + /// - Returns: A `BuildRule.CompilerSpec` instance if recognized; otherwise, `nil`. + public func mapCompilerSpec(_ compilerSpec: String) -> BuildRule.CompilerSpec? { + BuildRule.CompilerSpec(rawValue: compilerSpec) + } - /// Maps a file type string to a `BuildRule.FileType`. - /// - /// - Parameter fileType: The file type string from the `PBXBuildRule`. - /// - Returns: A `BuildRule.FileType` instance if recognized; otherwise, `nil`. - public func mapFileType(_ fileType: String) -> BuildRule.FileType? { - BuildRule.FileType(rawValue: fileType) - } + /// Maps a file type string to a `BuildRule.FileType`. + /// + /// - Parameter fileType: The file type string from the `PBXBuildRule`. + /// - Returns: A `BuildRule.FileType` instance if recognized; otherwise, `nil`. + public func mapFileType(_ fileType: String) -> BuildRule.FileType? { + BuildRule.FileType(rawValue: fileType) + } } diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift index 9ae4d191..643a50ed 100644 --- a/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift @@ -9,12 +9,12 @@ import XcodeGraph /// and translate them into a consistent `TargetDependency` representation. This enables downstream operations /// like graph analysis, code generation, or dependency visualization to work from a uniform model of dependencies. protocol DependencyMapping: Sendable { - /// Maps all dependencies of a given `PBXTarget` into an array of `TargetDependency` models. - /// - /// - Parameter target: The `PBXTarget` whose dependencies are to be mapped. - /// - Returns: An array of `TargetDependency` models representing the target's dependencies. - /// - Throws: If any dependency cannot be resolved or mapped correctly. - func mapDependencies(target: PBXTarget) async throws -> [TargetDependency] + /// Maps all dependencies of a given `PBXTarget` into an array of `TargetDependency` models. + /// + /// - Parameter target: The `PBXTarget` whose dependencies are to be mapped. + /// - Returns: An array of `TargetDependency` models representing the target's dependencies. + /// - Throws: If any dependency cannot be resolved or mapped correctly. + func mapDependencies(target: PBXTarget) async throws -> [TargetDependency] } /// A protocol that defines how to map a single `PBXTargetDependency` into a `TargetDependency` model. @@ -23,12 +23,12 @@ protocol DependencyMapping: Sendable { /// or proxy references). The `DependencyMapper` uses multiple `DependencyTypeMapper` instances in sequence to attempt /// resolving each dependency. protocol DependencyTypeMapper: Sendable { - /// Maps a single `PBXTargetDependency` into a `TargetDependency` model. - /// - /// - Parameter dependency: The `PBXTargetDependency` to map. - /// - Returns: A `TargetDependency` model if the dependency can be resolved by this mapper, or `nil` if not. - /// - Throws: If mapping fails due to issues like invalid paths or missing targets. - func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? + /// Maps a single `PBXTargetDependency` into a `TargetDependency` model. + /// + /// - Parameter dependency: The `PBXTargetDependency` to map. + /// - Returns: A `TargetDependency` model if the dependency can be resolved by this mapper, or `nil` if not. + /// - Throws: If mapping fails due to issues like invalid paths or missing targets. + func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? } /// A mapper that orchestrates the mapping of all target dependencies by leveraging multiple specialized mappers. @@ -36,130 +36,130 @@ protocol DependencyTypeMapper: Sendable { /// The `DependencyMapper` tries each registered `DependencyTypeMapper` in turn, returning the first successful result. /// This design allows for easy extension of dependency types without modifying a single large mapper. final class DependencyMapper: DependencyMapping { - private let projectProvider: ProjectProviding - private let typeMappers: [DependencyTypeMapper] - - /// Creates a new `DependencyMapper` with a given project provider. - /// - /// - Parameter projectProvider: Provides access to the project's directories, files, and parsed structures. - init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - self.typeMappers = [ - DirectTargetMapper(), - PackageProductMapper(), - ProxyDependencyMapper(projectProvider: projectProvider), - ] - } - - public func mapDependencies(target: PBXTarget) async throws -> [TargetDependency] { - return try await target.dependencies.asyncCompactMap { [typeMappers] dependency in - for mapper in typeMappers { - if let mapped = try await mapper.mapDependency(dependency) { - return mapped + private let projectProvider: ProjectProviding + private let typeMappers: [DependencyTypeMapper] + + /// Creates a new `DependencyMapper` with a given project provider. + /// + /// - Parameter projectProvider: Provides access to the project's directories, files, and parsed structures. + init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + typeMappers = [ + DirectTargetMapper(), + PackageProductMapper(), + ProxyDependencyMapper(projectProvider: projectProvider), + ] + } + + public func mapDependencies(target: PBXTarget) async throws -> [TargetDependency] { + return try await target.dependencies.asyncCompactMap { [typeMappers] dependency in + for mapper in typeMappers { + if let mapped = try await mapper.mapDependency(dependency) { + return mapped + } + } + return nil } - } - return nil } - } } /// A mapper that handles direct target dependencies, translating them into `.target` `TargetDependency` models. final class DirectTargetMapper: DependencyTypeMapper { - public func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? { - guard let target = dependency.target else { return nil } - let condition = PlatformConditionMapper.mapCondition(dependency: dependency) - return .target(name: target.name, status: .required, condition: condition) - } + public func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? { + guard let target = dependency.target else { return nil } + let condition = PlatformConditionMapper.mapCondition(dependency: dependency) + return .target(name: target.name, status: .required, condition: condition) + } } /// A mapper that handles package product dependencies, converting them into `.package` `TargetDependency` models. final class PackageProductMapper: DependencyTypeMapper { - public func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? { - guard let product = dependency.product else { return nil } - let condition = PlatformConditionMapper.mapCondition(dependency: dependency) - return .package( - product: product.productName, - type: .runtime, - condition: condition - ) - } + public func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? { + guard let product = dependency.product else { return nil } + let condition = PlatformConditionMapper.mapCondition(dependency: dependency) + return .package( + product: product.productName, + type: .runtime, + condition: condition + ) + } } /// A mapper that resolves proxy dependencies, which may point to native targets in other projects or file references. /// /// Depending on the proxy type, this mapper may return a `.target` or `.project` dependency, or file-based dependencies. final class ProxyDependencyMapper: DependencyTypeMapper { - private let projectProvider: ProjectProviding - private let fileMapper: FileDependencyMapper - - init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - self.fileMapper = FileDependencyMapper(projectProvider: projectProvider) - } - - public func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? { - guard let targetProxy = dependency.targetProxy, - let proxyType = targetProxy.proxyType - else { return nil } - - let condition = PlatformConditionMapper.mapCondition(dependency: dependency) - - switch proxyType { - case .nativeTarget: - return try await mapNativeTargetProxy(targetProxy, condition: condition) - case .reference: - return try await mapReferenceProxy(targetProxy, condition: condition) - default: - return nil + private let projectProvider: ProjectProviding + private let fileMapper: FileDependencyMapper + + init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + fileMapper = FileDependencyMapper(projectProvider: projectProvider) } - } - - private func mapNativeTargetProxy( - _ targetProxy: PBXContainerItemProxy, - condition: PlatformCondition? - ) async throws -> TargetDependency? { - guard let remoteInfo = targetProxy.remoteInfo else { return nil } - - switch targetProxy.containerPortal { - case .project(_): - return .target(name: remoteInfo, status: .required, condition: condition) - case .fileReference(let fileReference): - guard let projectRelativePath = fileReference.path else { return nil } - let fullPath = projectProvider.sourceDirectory.pathString + projectRelativePath - let absPath = try AbsolutePath.resolvePath(fullPath) - return .project( - target: remoteInfo, - path: absPath, - status: .required, - condition: condition - ) - case .unknownObject: - return nil + + public func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? { + guard let targetProxy = dependency.targetProxy, + let proxyType = targetProxy.proxyType + else { return nil } + + let condition = PlatformConditionMapper.mapCondition(dependency: dependency) + + switch proxyType { + case .nativeTarget: + return try await mapNativeTargetProxy(targetProxy, condition: condition) + case .reference: + return try await mapReferenceProxy(targetProxy, condition: condition) + default: + return nil + } } - } - - private func mapReferenceProxy( - _ targetProxy: PBXContainerItemProxy, - condition: PlatformCondition? - ) async throws -> TargetDependency? { - guard let remoteGlobalID = targetProxy.remoteGlobalID else { return nil } - - switch remoteGlobalID { - case .object(let object): - if let fileReference = object as? PBXFileReference { - return try await fileMapper.mapDependency( - pathString: fileReference.path, - condition: condition - ) - } else if let referenceProxy = object as? PBXReferenceProxy { - return try await fileMapper.mapDependency( - pathString: referenceProxy.path, - condition: condition - ) - } - return nil - case .string: - return nil + + private func mapNativeTargetProxy( + _ targetProxy: PBXContainerItemProxy, + condition: PlatformCondition? + ) async throws -> TargetDependency? { + guard let remoteInfo = targetProxy.remoteInfo else { return nil } + + switch targetProxy.containerPortal { + case .project: + return .target(name: remoteInfo, status: .required, condition: condition) + case let .fileReference(fileReference): + guard let projectRelativePath = fileReference.path else { return nil } + let fullPath = projectProvider.sourceDirectory.pathString + projectRelativePath + let absPath = try AbsolutePath.resolvePath(fullPath) + return .project( + target: remoteInfo, + path: absPath, + status: .required, + condition: condition + ) + case .unknownObject: + return nil + } + } + + private func mapReferenceProxy( + _ targetProxy: PBXContainerItemProxy, + condition: PlatformCondition? + ) async throws -> TargetDependency? { + guard let remoteGlobalID = targetProxy.remoteGlobalID else { return nil } + + switch remoteGlobalID { + case let .object(object): + if let fileReference = object as? PBXFileReference { + return try await fileMapper.mapDependency( + pathString: fileReference.path, + condition: condition + ) + } else if let referenceProxy = object as? PBXReferenceProxy { + return try await fileMapper.mapDependency( + pathString: referenceProxy.path, + condition: condition + ) + } + return nil + case .string: + return nil + } } - } } diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/FileDependencyMapper.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/FileDependencyMapper.swift index 1a78eb20..7deb2c7d 100644 --- a/Sources/XcodeProjToGraph/Mappers/Dependency/FileDependencyMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Dependency/FileDependencyMapper.swift @@ -4,19 +4,20 @@ import XcodeProj /// A helper responsible for mapping file-based dependencies (like frameworks or libraries) into `TargetDependency` models. final class FileDependencyMapper: Sendable { - private let projectProvider: ProjectProviding + private let projectProvider: ProjectProviding - init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - } + init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + } - public func mapDependency(pathString: String?, condition: PlatformCondition?) async throws - -> TargetDependency? - { - guard let pathString = pathString else { return nil } - let validatedPath = projectProvider.sourceDirectory.appending( - try RelativePath(validating: pathString)) - let absPath = try AbsolutePath.resolvePath(validatedPath.pathString) - return absPath.mapByExtension(condition: condition) - } + public func mapDependency(pathString: String?, condition: PlatformCondition?) async throws + -> TargetDependency? + { + guard let pathString else { return nil } + let validatedPath = projectProvider.sourceDirectory.appending( + try RelativePath(validating: pathString) + ) + let absPath = try AbsolutePath.resolvePath(validatedPath.pathString) + return absPath.mapByExtension(condition: condition) + } } diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift index 1b7af2c6..f85ee5a0 100644 --- a/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift @@ -3,17 +3,17 @@ import XcodeProj /// A mapper for platform-related conditions, extracting platform filters from `PBXTargetDependency`. enum PlatformConditionMapper { - /// Maps the platform filters specified on a `PBXTargetDependency` into a `PlatformCondition`. - /// - /// - Parameter dependency: The `PBXTargetDependency` to inspect. - /// - Returns: A `PlatformCondition` representing the platforms this dependency applies to, or `nil` if none. - static public func mapCondition(dependency: PBXTargetDependency) -> PlatformCondition? { - var filters = Set(dependency.platformFilters ?? []) - if let singleFilter = dependency.platformFilter { - filters.insert(singleFilter) - } + /// Maps the platform filters specified on a `PBXTargetDependency` into a `PlatformCondition`. + /// + /// - Parameter dependency: The `PBXTargetDependency` to inspect. + /// - Returns: A `PlatformCondition` representing the platforms this dependency applies to, or `nil` if none. + public static func mapCondition(dependency: PBXTargetDependency) -> PlatformCondition? { + var filters = Set(dependency.platformFilters ?? []) + if let singleFilter = dependency.platformFilter { + filters.insert(singleFilter) + } - let platformFilters = Set(filters.compactMap { PlatformFilter(rawValue: $0) }) - return PlatformCondition.when(platformFilters) - } + let platformFilters = Set(filters.compactMap { PlatformFilter(rawValue: $0) }) + return PlatformCondition.when(platformFilters) + } } diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift index f20bd863..0404a5b8 100644 --- a/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift +++ b/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift @@ -1,272 +1,270 @@ -// TargetDependency+GraphMapping - import Foundation import Path import XcodeGraph import XcodeProj extension TargetDependency { - /// Converts a `TargetDependency` into a corresponding `GraphDependency` model, - /// resolving any additional details (like linking types, binary paths, or architectures) - /// based on the dependency type. - /// - /// This method leverages information like the source directory and an all-targets map to - /// resolve project-based target dependencies and to construct the correct `GraphDependency` - /// variant (e.g., frameworks, libraries, SDKs, packages, etc.). - /// - /// - Parameters: - /// - sourceDirectory: The root directory from which to resolve relative paths. - /// - allTargetsMap: A dictionary mapping target names to `Target` models, used to - /// resolve project-based dependencies. - /// - Returns: A `GraphDependency` model representing this dependency. - /// - Throws: If a project-based dependency cannot be resolved (e.g., target not found). - public func graphDependency( - sourceDirectory: AbsolutePath, - allTargetsMap: [String: Target] - ) async throws -> GraphDependency { - switch self { - case .target(let name, let status, _): - return .target(name: name, path: sourceDirectory, status: status) - - case .project(let targetName, let projectPath, let status, _): - return try mapProjectGraphDependency( - projectPath: projectPath, - targetName: targetName, - status: status, - allTargetsMap: allTargetsMap - ) - - case .framework(let path, let status, _): - let binaryPath = path.appending(component: "\(self.name)") - let architectures = (try? await LipoTool.archs(paths: [binaryPath.pathString]).architectures) ?? [] - return .framework( - path: path, - binaryPath: binaryPath, - dsymPath: nil, - bcsymbolmapPaths: [], - linking: .dynamic, - architectures: architectures, - status: status - ) - - case .xcframework(let path, let status, _): - return .xcframework( - GraphDependency.XCFramework( - path: path, - infoPlist: .test(), - linking: .dynamic, - mergeable: false, - status: status, - macroPath: nil, - swiftModules: [], - moduleMaps: [] - ) - ) - - case .library(let path, let publicHeaders, let swiftModuleMap, _): - let linking: BinaryLinking = { - switch path.fileExtension { - case .staticLibrary: - return .static - case .dynamicLibrary, .textBasedDynamicLibrary: - return .dynamic - default: - return .dynamic + /// Converts a `TargetDependency` into a corresponding `GraphDependency` model, + /// resolving any additional details (like linking types, binary paths, or architectures) + /// based on the dependency type. + /// + /// This method leverages information like the source directory and an all-targets map to + /// resolve project-based target dependencies and to construct the correct `GraphDependency` + /// variant (e.g., frameworks, libraries, SDKs, packages, etc.). + /// + /// - Parameters: + /// - sourceDirectory: The root directory from which to resolve relative paths. + /// - allTargetsMap: A dictionary mapping target names to `Target` models, used to + /// resolve project-based dependencies. + /// - Returns: A `GraphDependency` model representing this dependency. + /// - Throws: If a project-based dependency cannot be resolved (e.g., target not found). + public func graphDependency( + sourceDirectory: AbsolutePath, + allTargetsMap: [String: Target] + ) async throws -> GraphDependency { + switch self { + case let .target(name, status, _): + return .target(name: name, path: sourceDirectory, status: status) + + case let .project(targetName, projectPath, status, _): + return try mapProjectGraphDependency( + projectPath: projectPath, + targetName: targetName, + status: status, + allTargetsMap: allTargetsMap + ) + + case let .framework(path, status, _): + let binaryPath = path.appending(component: "\(name)") + let architectures = (try? await LipoTool.archs(paths: [binaryPath.pathString]).architectures) ?? [] + return .framework( + path: path, + binaryPath: binaryPath, + dsymPath: nil, + bcsymbolmapPaths: [], + linking: .dynamic, + architectures: architectures, + status: status + ) + + case let .xcframework(path, status, _): + return .xcframework( + GraphDependency.XCFramework( + path: path, + infoPlist: .test(), + linking: .dynamic, + mergeable: false, + status: status, + macroPath: nil, + swiftModules: [], + moduleMaps: [] + ) + ) + + case let .library(path, publicHeaders, swiftModuleMap, _): + let linking: BinaryLinking = { + switch path.fileExtension { + case .staticLibrary: + return .static + case .dynamicLibrary, .textBasedDynamicLibrary: + return .dynamic + default: + return .dynamic + } + }() + let architectures = (try? await LipoTool.archs(paths: [path.pathString]).architectures) ?? [] + + return .library( + path: path, + publicHeaders: publicHeaders, + linking: linking, + architectures: architectures, + swiftModuleMap: swiftModuleMap + ) + + case let .package(product, type, _): + return .packageProduct( + path: sourceDirectory, + product: product, + type: type.graphPackageType + ) + + case let .sdk(name, status, _): + return .sdk( + name: name, + path: sourceDirectory, + status: status, + source: .developer + ) + + case .xctest: + return .xcframework( + GraphDependency.XCFramework( + path: sourceDirectory, + infoPlist: XCFrameworkInfoPlist.test(), + linking: .dynamic, + mergeable: false, + status: .required, + macroPath: nil, + swiftModules: [], + moduleMaps: [] + ) + ) } - }() - let architectures = (try? await LipoTool.archs(paths: [path.pathString]).architectures) ?? [] - - return .library( - path: path, - publicHeaders: publicHeaders, - linking: linking, - architectures: architectures, - swiftModuleMap: swiftModuleMap - ) - - case .package(let product, let type, _): - return .packageProduct( - path: sourceDirectory, - product: product, - type: type.graphPackageType - ) - - case .sdk(let name, let status, _): - return .sdk( - name: name, - path: sourceDirectory, - status: status, - source: .developer - ) - - case .xctest: - return .xcframework( - GraphDependency.XCFramework( - path: sourceDirectory, - infoPlist: XCFrameworkInfoPlist.test(), - linking: .dynamic, - mergeable: false, - status: .required, - macroPath: nil, - swiftModules: [], - moduleMaps: [] - ) - ) - } - } - - /// Maps a project-based target dependency into a `GraphDependency` by resolving the target - /// and determining the appropriate dependency type (e.g., framework, library, bundle, app). - /// - /// - Parameters: - /// - projectPath: The absolute path of the project containing the target. - /// - targetName: The name of the target dependency. - /// - status: The linking status of the dependency. - /// - allTargetsMap: A dictionary mapping target names to `Target` models. - /// - Returns: A `GraphDependency` model representing the resolved project target dependency. - /// - Throws: If the target specified by `targetName` is not found in `allTargetsMap`. - public func mapProjectGraphDependency( - projectPath: AbsolutePath, - targetName: String, - status: LinkingStatus, - allTargetsMap: [String: Target] - ) throws -> GraphDependency { - guard let target = allTargetsMap[targetName] else { - throw MappingError.targetNotFound(targetName: targetName, path: projectPath) } - let product = target.product - let dependency: GraphDependency - - switch product { - case .framework, .staticFramework: - let linking: BinaryLinking = (product == .staticFramework) ? .static : .dynamic - dependency = .framework( - path: projectPath, - binaryPath: projectPath.appending(component: "\(targetName).framework"), - dsymPath: nil, - bcsymbolmapPaths: [], - linking: linking, - architectures: [], - status: status - ) - - case .staticLibrary, .dynamicLibrary: - let linking: BinaryLinking = (product == .staticLibrary) ? .static : .dynamic - let publicHeadersPath = projectPath.appending(component: "include") - dependency = .library( - path: projectPath.appending( - component: linking == .static - ? "lib\(targetName).a" - : "lib\(targetName).dylib" - ), - publicHeaders: publicHeadersPath, - linking: linking, - architectures: [], - swiftModuleMap: nil - ) - - case .bundle: - dependency = .bundle( - path: projectPath.appending(component: "\(targetName).bundle") - ) - - case .app, .commandLineTool: - dependency = .target( - name: targetName, - path: projectPath, - status: status - ) - - default: - - throw MappingError.unknownDependencyType(name: product.description) - } + /// Maps a project-based target dependency into a `GraphDependency` by resolving the target + /// and determining the appropriate dependency type (e.g., framework, library, bundle, app). + /// + /// - Parameters: + /// - projectPath: The absolute path of the project containing the target. + /// - targetName: The name of the target dependency. + /// - status: The linking status of the dependency. + /// - allTargetsMap: A dictionary mapping target names to `Target` models. + /// - Returns: A `GraphDependency` model representing the resolved project target dependency. + /// - Throws: If the target specified by `targetName` is not found in `allTargetsMap`. + public func mapProjectGraphDependency( + projectPath: AbsolutePath, + targetName: String, + status: LinkingStatus, + allTargetsMap: [String: Target] + ) throws -> GraphDependency { + guard let target = allTargetsMap[targetName] else { + throw MappingError.targetNotFound(targetName: targetName, path: projectPath) + } + + let product = target.product + let dependency: GraphDependency + + switch product { + case .framework, .staticFramework: + let linking: BinaryLinking = (product == .staticFramework) ? .static : .dynamic + dependency = .framework( + path: projectPath, + binaryPath: projectPath.appending(component: "\(targetName).framework"), + dsymPath: nil, + bcsymbolmapPaths: [], + linking: linking, + architectures: [], + status: status + ) + + case .staticLibrary, .dynamicLibrary: + let linking: BinaryLinking = (product == .staticLibrary) ? .static : .dynamic + let publicHeadersPath = projectPath.appending(component: "include") + dependency = .library( + path: projectPath.appending( + component: linking == .static + ? "lib\(targetName).a" + : "lib\(targetName).dylib" + ), + publicHeaders: publicHeadersPath, + linking: linking, + architectures: [], + swiftModuleMap: nil + ) + + case .bundle: + dependency = .bundle( + path: projectPath.appending(component: "\(targetName).bundle") + ) + + case .app, .commandLineTool: + dependency = .target( + name: targetName, + path: projectPath, + status: status + ) - return dependency - } + default: + + throw MappingError.unknownDependencyType(name: product.description) + } + + return dependency + } } extension TargetDependency.PackageType { - /// Converts a `TargetDependency.PackageType` into a `GraphDependency.PackageProductType`. - var graphPackageType: GraphDependency.PackageProductType { - switch self { - case .runtime: - return .runtime - case .runtimeEmbedded: - return .runtimeEmbedded - case .plugin: - return .plugin - case .macro: - return .macro + /// Converts a `TargetDependency.PackageType` into a `GraphDependency.PackageProductType`. + var graphPackageType: GraphDependency.PackageProductType { + switch self { + case .runtime: + return .runtime + case .runtimeEmbedded: + return .runtimeEmbedded + case .plugin: + return .plugin + case .macro: + return .macro + } } - } } extension PBXProductType { - /// Maps a `PBXProductType` into a `Product` domain model. - /// - /// - Parameter pbxProductType: The `PBXProductType` to map. - /// - Returns: A `Product` model if known, or `nil` if the product type is unsupported. - func mapProductType() -> Product? { - switch self { - case .application, .messagesApplication, .onDemandInstallCapableApplication: - return .app + /// Maps a `PBXProductType` into a `Product` domain model. + /// + /// - Parameter pbxProductType: The `PBXProductType` to map. + /// - Returns: A `Product` model if known, or `nil` if the product type is unsupported. + func mapProductType() -> Product? { + switch self { + case .application, .messagesApplication, .onDemandInstallCapableApplication: + return .app - case .framework, .xcFramework: - return .framework + case .framework, .xcFramework: + return .framework - case .staticFramework: - return .staticFramework + case .staticFramework: + return .staticFramework - case .dynamicLibrary: - return .dynamicLibrary + case .dynamicLibrary: + return .dynamicLibrary - case .staticLibrary, .metalLibrary: - return .staticLibrary + case .staticLibrary, .metalLibrary: + return .staticLibrary - case .bundle, .ocUnitTestBundle: - return .bundle + case .bundle, .ocUnitTestBundle: + return .bundle - case .unitTestBundle: - return .unitTests + case .unitTestBundle: + return .unitTests - case .uiTestBundle: - return .uiTests + case .uiTestBundle: + return .uiTests - case .appExtension: - return .appExtension + case .appExtension: + return .appExtension - case .extensionKitExtension, .xcodeExtension: - return .extensionKitExtension + case .extensionKitExtension, .xcodeExtension: + return .extensionKitExtension - case .commandLineTool: - return .commandLineTool + case .commandLineTool: + return .commandLineTool - case .messagesExtension: - return .messagesExtension + case .messagesExtension: + return .messagesExtension - case .stickerPack: - return .stickerPackExtension + case .stickerPack: + return .stickerPackExtension - case .xpcService: - return .xpc + case .xpcService: + return .xpc - case .watchApp, .watch2App, .watch2AppContainer: - return .watch2App + case .watchApp, .watch2App, .watch2AppContainer: + return .watch2App - case .watchExtension, .watch2Extension: - return .watch2Extension + case .watchExtension, .watch2Extension: + return .watch2Extension - case .tvExtension: - return .tvTopShelfExtension + case .tvExtension: + return .tvTopShelfExtension - case .systemExtension: - return .systemExtension + case .systemExtension: + return .systemExtension - // Unsupported or unknown cases - case .instrumentsPackage, .intentsServiceExtension, .driverExtension, .none: - return nil + // Unsupported or unknown cases + case .instrumentsPackage, .intentsServiceExtension, .driverExtension, .none: + return nil + } } - } } diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift b/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift index 28adca01..c5fdb75f 100644 --- a/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift @@ -7,10 +7,11 @@ import XcodeProj /// Specifies the type of graph to generate. /// /// - `.workspace(WorkspaceProviding)`: Constructs a graph from a workspace provided by a type conforming to `WorkspaceProviding`. -/// - `.project(AbsolutePath)`: Constructs a graph from a single project located at the given path, treating it as a workspace with one project. +/// - `.project(AbsolutePath)`: Constructs a graph from a single project located at the given path, treating it as a workspace +/// with one project. public enum GraphType: Sendable { - case workspace(WorkspaceProviding) - case project(AbsolutePath) + case workspace(WorkspaceProviding) + case project(AbsolutePath) } /// A mapper that constructs a complete `XcodeGraph.Graph` from a given workspace or project. @@ -25,108 +26,110 @@ public enum GraphType: Sendable { /// Typical usage involves creating a `GraphMapper` with a specified `GraphType` and then calling /// `xcodeGraph()` to produce the graph. public final class GraphMapper: Sendable { - private let projectProviderClosure: @Sendable (AbsolutePath) async throws -> ProjectProviding - public let graphType: GraphType + private let projectProviderClosure: @Sendable (AbsolutePath) async throws -> ProjectProviding + public let graphType: GraphType - /// Initializes the mapper with a specified graph type and an optional project provider closure. - /// - /// - Parameters: - /// - graphType: The type of graph (workspace or project) to map. - /// - projectProviderClosure: A closure that, given a project path, returns a `ProjectProviding`. - /// By default, it initializes a `ProjectProvider` from the given `AbsolutePath`. - public init( - graphType: GraphType, - projectProviderClosure: @escaping @Sendable (AbsolutePath) async throws -> ProjectProviding = { - let xcodeProj = try XcodeProj(pathString: $0.pathString) - return ProjectProvider(xcodeProjPath: $0, xcodeProj: xcodeProj) + /// Initializes the mapper with a specified graph type and an optional project provider closure. + /// + /// - Parameters: + /// - graphType: The type of graph (workspace or project) to map. + /// - projectProviderClosure: A closure that, given a project path, returns a `ProjectProviding`. + /// By default, it initializes a `ProjectProvider` from the given `AbsolutePath`. + public init( + graphType: GraphType, + projectProviderClosure: @escaping @Sendable (AbsolutePath) async throws -> ProjectProviding = { + let xcodeProj = try XcodeProj(pathString: $0.pathString) + return ProjectProvider(xcodeProjPath: $0, xcodeProj: xcodeProj) + } + ) { + self.graphType = graphType + self.projectProviderClosure = projectProviderClosure } - ) { - self.graphType = graphType - self.projectProviderClosure = projectProviderClosure - } - /// Constructs an `XcodeGraph.Graph` by mapping all projects, packages, and dependencies within the specified workspace or project. - /// - /// - Returns: A fully mapped `XcodeGraph.Graph` containing projects, packages, dependencies, and conditions. - /// - Throws: An error if project mapping or dependency resolution fails. - public func xcodeGraph() async throws -> XcodeGraph.Graph { - var projectProviders = [AbsolutePath: ProjectProviding]() - var projects: [AbsolutePath: Project] = [:] - var packages: [AbsolutePath: [String: Package]] = [:] - var dependencies: [GraphDependency: Set] = [:] - var dependencyConditions: [GraphEdge: PlatformCondition] = [:] + /// Constructs an `XcodeGraph.Graph` by mapping all projects, packages, and dependencies within the specified workspace or + /// project. + /// + /// - Returns: A fully mapped `XcodeGraph.Graph` containing projects, packages, dependencies, and conditions. + /// - Throws: An error if project mapping or dependency resolution fails. + public func xcodeGraph() async throws -> XcodeGraph.Graph { + var projectProviders = [AbsolutePath: ProjectProviding]() + var projects: [AbsolutePath: Project] = [:] + var packages: [AbsolutePath: [String: Package]] = [:] + var dependencies: [GraphDependency: Set] = [:] + var dependencyConditions: [GraphEdge: PlatformCondition] = [:] - let workspace = - switch graphType { - case .workspace(let workspaceProvider): - try await WorkspaceMapper(workspaceProvider: workspaceProvider).map() - case .project(let absolutePath): - Workspace( - path: absolutePath.parentDirectory, - xcWorkspacePath: absolutePath.parentDirectory, - name: "Workspace", - projects: [absolutePath] - ) - } + let workspace = + switch graphType { + case let .workspace(workspaceProvider): + try await WorkspaceMapper(workspaceProvider: workspaceProvider).map() + case let .project(absolutePath): + Workspace( + path: absolutePath.parentDirectory, + xcWorkspacePath: absolutePath.parentDirectory, + name: "Workspace", + projects: [absolutePath] + ) + } - let projectResults = try await workspace.projects.lazy.asyncCompactMap { path in - do { - let provider = try await self.projectProviderClosure(path) - let projectMapper = ProjectMapper(projectProvider: provider) - let project = try await projectMapper.mapProject() - return (path, provider, project) - } catch { - return nil - } - } + let projectResults = try await workspace.projects.lazy.asyncCompactMap { path in + do { + let provider = try await self.projectProviderClosure(path) + let projectMapper = ProjectMapper(projectProvider: provider) + let project = try await projectMapper.mapProject() + return (path, provider, project) + } catch { + return nil + } + } - for (path, provider, project) in projectResults { - projectProviders[path] = provider - projects[path] = project - } + for (path, provider, project) in projectResults { + projectProviders[path] = provider + projects[path] = project + } - let allTargetsMap = Dictionary( - projects.values.flatMap { $0.targets }, - uniquingKeysWith: { existing, _ in - existing - } - ) + let allTargetsMap = Dictionary( + projects.values.flatMap(\.targets), + uniquingKeysWith: { existing, _ in + existing + } + ) - for (path, project) in projects { - if !project.packages.isEmpty { - packages[path] = Dictionary( - uniqueKeysWithValues: project.packages.map { ($0.url, $0) }) - } + for (path, project) in projects { + if !project.packages.isEmpty { + packages[path] = Dictionary( + uniqueKeysWithValues: project.packages.map { ($0.url, $0) } + ) + } - for (name, target) in project.targets { - let sourceDependency = GraphDependency.target(name: name, path: path.parentDirectory) - let edgesAndDependencies = try await target.dependencies.asyncCompactMap { targetDep in - let graphDep = try await targetDep.graphDependency( - sourceDirectory: path.parentDirectory, - allTargetsMap: allTargetsMap - ) - let edge = GraphEdge(from: sourceDependency, to: graphDep) - return (edge, targetDep.condition, graphDep) - } + for (name, target) in project.targets { + let sourceDependency = GraphDependency.target(name: name, path: path.parentDirectory) + let edgesAndDependencies = try await target.dependencies.asyncCompactMap { targetDep in + let graphDep = try await targetDep.graphDependency( + sourceDirectory: path.parentDirectory, + allTargetsMap: allTargetsMap + ) + let edge = GraphEdge(from: sourceDependency, to: graphDep) + return (edge, targetDep.condition, graphDep) + } + + for (edge, condition, _) in edgesAndDependencies { + dependencyConditions[edge] = condition + } - for (edge, condition, _) in edgesAndDependencies { - dependencyConditions[edge] = condition + let targetDependencies = edgesAndDependencies.compactMap(\.2) + guard !targetDependencies.isEmpty else { continue } + dependencies[sourceDependency] = Set(targetDependencies) + } } - let targetDependencies = edgesAndDependencies.compactMap { $0.2 } - guard !targetDependencies.isEmpty else { continue } - dependencies[sourceDependency] = Set(targetDependencies) - } + return Graph( + name: workspace.name, + path: workspace.path, + workspace: workspace, + projects: projects, + packages: packages, + dependencies: dependencies, + dependencyConditions: dependencyConditions + ) } - - return Graph( - name: workspace.name, - path: workspace.path, - workspace: workspace, - projects: projects, - packages: packages, - dependencies: dependencies, - dependencyConditions: dependencyConditions - ) - } } diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift b/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift index d2dbea6a..0328e50a 100644 --- a/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift +++ b/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift @@ -3,7 +3,6 @@ import Path /// Represents errors that may occur during project or dependency mapping processes. enum MappingError: Error, LocalizedError, Equatable { - // MARK: - Project Mapping Errors /// The provided path does not exist. @@ -48,33 +47,32 @@ enum MappingError: Error, LocalizedError, Equatable { /// A localized description of the error. var errorDescription: String? { switch self { - // Project Mapping Cases - case .pathNotFound(let path): + case let .pathNotFound(path): return "The specified path does not exist: \(path)" - case .unknownProjectType(let path): + case let .unknownProjectType(path): return "The project type for the path '\(path)' could not be determined." case .noProjectsFound: return "No Xcode projects were found." - case .missingFilesGroup(let targetName): + case let .missingFilesGroup(targetName): return "The files group is missing for the target '\(targetName)'." case .missingMergedBinaryType: return "The merged binary type is missing for the target." - case .missingRepositoryURL(let packageName): + case let .missingRepositoryURL(packageName): return "The repository URL is missing for the package '\(packageName)'." - case .generic(let message): + case let .generic(message): return message // Target Mapping Cases - case .missingBundleIdentifier(let targetName): + case let .missingBundleIdentifier(targetName): return "The bundle identifier is missing for the target '\(targetName)'." - case .targetNotFound(let targetName, let path): + case let .targetNotFound(targetName, path): return "The target '\(targetName)' could not be found in the project at path: \(path.pathString)." // Dependency Mapping Cases - case .frameworkNotFound(let name, let path): + case let .frameworkNotFound(name, path): return "The required framework '\(name)' was not found at path: \(path.pathString)." - case .unknownDependencyType(let name): + case let .unknownDependencyType(name): return "An unknown dependency type '\(name)' was encountered." } } diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift b/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift index 3d67fe2b..3e13d195 100644 --- a/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift +++ b/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift @@ -7,8 +7,8 @@ import XcodeProj /// - `.workspace(path)`: Indicates a `.xcworkspace` is present at the given path. /// - `.xcodeProject(path)`: Indicates a `.xcodeproj` is present at the given path. public enum ProjectType { - case workspace(AbsolutePath) - case xcodeProject(AbsolutePath) + case workspace(AbsolutePath) + case xcodeProject(AbsolutePath) } /// A parser responsible for identifying and parsing Xcode projects or workspaces into a `Graph`. @@ -16,96 +16,96 @@ public enum ProjectType { /// `ProjectParser` determines whether the given path points to a workspace, a project, /// or a directory containing one of these. It then delegates the actual mapping to `GraphMapper`. public class ProjectParser { - public init() {} + public init() {} - /// Parses the project or workspace at the given file system path into a `Graph`. - /// - /// - Parameter path: The path to a `.xcworkspace`, `.xcodeproj`, or a directory containing one. - /// - Returns: A `Graph` representing the parsed project structure. - /// - Throws: - /// - `MappingError.pathNotFound` if the given path does not exist. - /// - `MappingError.noProjectsFound` if no `.xcworkspace` or `.xcodeproj` can be found. - /// - Other errors thrown by `GraphMapper` during mapping. - public static func parse(atPath path: String) async throws -> Graph { - guard FileManager.default.fileExists(atPath: path) else { - throw MappingError.pathNotFound(path: path) - } + /// Parses the project or workspace at the given file system path into a `Graph`. + /// + /// - Parameter path: The path to a `.xcworkspace`, `.xcodeproj`, or a directory containing one. + /// - Returns: A `Graph` representing the parsed project structure. + /// - Throws: + /// - `MappingError.pathNotFound` if the given path does not exist. + /// - `MappingError.noProjectsFound` if no `.xcworkspace` or `.xcodeproj` can be found. + /// - Other errors thrown by `GraphMapper` during mapping. + public static func parse(atPath path: String) async throws -> Graph { + guard FileManager.default.fileExists(atPath: path) else { + throw MappingError.pathNotFound(path: path) + } - let absolutePath = try AbsolutePath(validating: path) - let type = try determineProjectType(at: absolutePath) - return try await parse(projectType: type) - } + let absolutePath = try AbsolutePath(validating: path) + let type = try determineProjectType(at: absolutePath) + return try await parse(projectType: type) + } - /// Parses a given `ProjectType` into a `Graph`. - /// - /// - Parameter projectType: The identified `ProjectType` (workspace or project). - /// - Returns: A `Graph` model. - /// - Throws: Any errors encountered during graph mapping. - public static func parse(projectType: ProjectType) async throws -> Graph { - switch projectType { - case .workspace(let path): - return try await mapXCWorkspace(at: path) - case .xcodeProject(let path): - return try await mapXcodeProj(at: path) + /// Parses a given `ProjectType` into a `Graph`. + /// + /// - Parameter projectType: The identified `ProjectType` (workspace or project). + /// - Returns: A `Graph` model. + /// - Throws: Any errors encountered during graph mapping. + public static func parse(projectType: ProjectType) async throws -> Graph { + switch projectType { + case let .workspace(path): + return try await mapXCWorkspace(at: path) + case let .xcodeProject(path): + return try await mapXcodeProj(at: path) + } } - } - /// Maps a single `.xcodeproj` at the given path into a `Graph`. - /// - /// - Parameter path: The absolute path to the `.xcodeproj`. - /// - Returns: A `Graph` model of the project. - /// - Throws: Errors from `GraphMapper` if mapping fails. - public static func mapXcodeProj(at path: AbsolutePath) async throws -> Graph { - let graphMapper = GraphMapper(graphType: .project(path)) - return try await graphMapper.xcodeGraph() - } + /// Maps a single `.xcodeproj` at the given path into a `Graph`. + /// + /// - Parameter path: The absolute path to the `.xcodeproj`. + /// - Returns: A `Graph` model of the project. + /// - Throws: Errors from `GraphMapper` if mapping fails. + public static func mapXcodeProj(at path: AbsolutePath) async throws -> Graph { + let graphMapper = GraphMapper(graphType: .project(path)) + return try await graphMapper.xcodeGraph() + } - /// Maps a single `.xcworkspace` at the given path into a `Graph`. - /// - /// - Parameter path: The absolute path to the `.xcworkspace`. - /// - Returns: A `Graph` model of the workspace and its contained projects. - /// - Throws: Errors from `GraphMapper` if mapping fails. - public static func mapXCWorkspace(at path: AbsolutePath) async throws -> Graph { - let workspaceProvider = try WorkspaceProvider(xcWorkspacePath: path) - let graphMapper = GraphMapper(graphType: .workspace(workspaceProvider)) - return try await graphMapper.xcodeGraph() - } + /// Maps a single `.xcworkspace` at the given path into a `Graph`. + /// + /// - Parameter path: The absolute path to the `.xcworkspace`. + /// - Returns: A `Graph` model of the workspace and its contained projects. + /// - Throws: Errors from `GraphMapper` if mapping fails. + public static func mapXCWorkspace(at path: AbsolutePath) async throws -> Graph { + let workspaceProvider = try WorkspaceProvider(xcWorkspacePath: path) + let graphMapper = GraphMapper(graphType: .workspace(workspaceProvider)) + return try await graphMapper.xcodeGraph() + } - /// Determines the type of project at a given path by inspecting file extensions or directory contents. - /// - /// - Parameter path: The absolute path to check. - /// - Returns: A `ProjectType` representing either a `.workspace` or `.xcodeproj`. - /// - Throws: `MappingError.noProjectsFound` if no recognizable project files are found. - private static func determineProjectType(at path: AbsolutePath) throws -> ProjectType { - switch path.fileExtension { - case .xcworkspace: - return .workspace(path) - case .xcodeproj: - return .xcodeProject(path) - default: - return try findProjectInDirectory(at: path) + /// Determines the type of project at a given path by inspecting file extensions or directory contents. + /// + /// - Parameter path: The absolute path to check. + /// - Returns: A `ProjectType` representing either a `.workspace` or `.xcodeproj`. + /// - Throws: `MappingError.noProjectsFound` if no recognizable project files are found. + private static func determineProjectType(at path: AbsolutePath) throws -> ProjectType { + switch path.fileExtension { + case .xcworkspace: + return .workspace(path) + case .xcodeproj: + return .xcodeProject(path) + default: + return try findProjectInDirectory(at: path) + } } - } - /// Searches a directory for the first `.xcworkspace` or `.xcodeproj` file. - /// - /// - Parameter path: A directory path. - /// - Returns: A `ProjectType` if found. - /// - Throws: - /// - `MappingError.noProjectsFound` if neither a `.xcworkspace` nor `.xcodeproj` is located in the directory. - private static func findProjectInDirectory(at path: AbsolutePath) throws -> ProjectType { - let contents = try FileManager.default.contentsOfDirectory(atPath: path.pathString) + /// Searches a directory for the first `.xcworkspace` or `.xcodeproj` file. + /// + /// - Parameter path: A directory path. + /// - Returns: A `ProjectType` if found. + /// - Throws: + /// - `MappingError.noProjectsFound` if neither a `.xcworkspace` nor `.xcodeproj` is located in the directory. + private static func findProjectInDirectory(at path: AbsolutePath) throws -> ProjectType { + let contents = try FileManager.default.contentsOfDirectory(atPath: path.pathString) - // Look for the first .xcworkspace - if let workspaceName = contents.first(where: { $0.hasSuffix(".xcworkspace") }) { - return .workspace(path.appending(component: workspaceName)) - } + // Look for the first .xcworkspace + if let workspaceName = contents.first(where: { $0.hasSuffix(".xcworkspace") }) { + return .workspace(path.appending(component: workspaceName)) + } - // Look for the first .xcodeproj - if let projectName = contents.first(where: { $0.hasSuffix(".xcodeproj") }) { - return .xcodeProject(path.appending(component: projectName)) - } + // Look for the first .xcodeproj + if let projectName = contents.first(where: { $0.hasSuffix(".xcodeproj") }) { + return .xcodeProject(path.appending(component: projectName)) + } - throw MappingError.noProjectsFound - } + throw MappingError.noProjectsFound + } } diff --git a/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift b/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift index e2456e96..7b07af6b 100644 --- a/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift @@ -5,19 +5,19 @@ import XcodeProj /// A protocol for mapping `XCSwiftPackageReference` instances to `Package` models. protocol PackageMapping: Sendable { - /// Maps a remote Swift package reference to a `Package`. - /// - /// - Parameter package: The remote Swift package reference. - /// - Returns: A `Package` representing the remote package. - /// - Throws: If required repository information is missing or invalid. - func map(package: XCRemoteSwiftPackageReference) async throws -> Package + /// Maps a remote Swift package reference to a `Package`. + /// + /// - Parameter package: The remote Swift package reference. + /// - Returns: A `Package` representing the remote package. + /// - Throws: If required repository information is missing or invalid. + func map(package: XCRemoteSwiftPackageReference) async throws -> Package - /// Maps a local Swift package reference to a `Package`. - /// - /// - Parameter package: The local Swift package reference. - /// - Returns: A `Package` representing the local package. - /// - Throws: If the package path cannot be validated. - func map(package: XCLocalSwiftPackageReference) async throws -> Package + /// Maps a local Swift package reference to a `Package`. + /// + /// - Parameter package: The local Swift package reference. + /// - Returns: A `Package` representing the local package. + /// - Throws: If the package path cannot be validated. + func map(package: XCLocalSwiftPackageReference) async throws -> Package } /// A mapper that converts remote and local Swift package references into `Package` models. @@ -26,67 +26,67 @@ protocol PackageMapping: Sendable { /// to the project's source directory. For remote packages, it uses the repository URL and version requirement /// from the `XCRemoteSwiftPackageReference` to construct a `Package` with the appropriate `Requirement`. final class PackageMapper: PackageMapping { - private let projectProvider: ProjectProviding + private let projectProvider: ProjectProviding - /// Creates a new `PackageMapper`. - /// - /// - Parameter projectProvider: A provider that offers access to the project's directory structure - /// and additional metadata. - init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - } - - /// Maps an `XCRemoteSwiftPackageReference` to a `Package`. - /// - /// - Parameter package: The `XCRemoteSwiftPackageReference` to map. - /// - Returns: A `Package` instance representing the mapped remote package. - /// - Throws: `MappingError.missingRepositoryURL` if the repository URL is not found. - public func map(package: XCRemoteSwiftPackageReference) async throws -> Package { - guard let repositoryURL = package.repositoryURL else { - throw MappingError.missingRepositoryURL(packageName: package.name ?? "Unknown Package") + /// Creates a new `PackageMapper`. + /// + /// - Parameter projectProvider: A provider that offers access to the project's directory structure + /// and additional metadata. + init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider } - let requirement = await mapRequirement(package: package) - return .remote(url: repositoryURL, requirement: requirement) - } + /// Maps an `XCRemoteSwiftPackageReference` to a `Package`. + /// + /// - Parameter package: The `XCRemoteSwiftPackageReference` to map. + /// - Returns: A `Package` instance representing the mapped remote package. + /// - Throws: `MappingError.missingRepositoryURL` if the repository URL is not found. + public func map(package: XCRemoteSwiftPackageReference) async throws -> Package { + guard let repositoryURL = package.repositoryURL else { + throw MappingError.missingRepositoryURL(packageName: package.name ?? "Unknown Package") + } - /// Maps an `XCLocalSwiftPackageReference` to a `Package`. - /// - /// - Parameter package: The `XCLocalSwiftPackageReference` to map. - /// - Returns: A `Package` instance representing the mapped local package. - /// - Throws: If the relative path is invalid. - public func map(package: XCLocalSwiftPackageReference) async throws -> Package { - let relativePath = try RelativePath(validating: package.relativePath) - let path = projectProvider.sourceDirectory.appending(relativePath) - return .local(path: path) - } + let requirement = await mapRequirement(package: package) + return .remote(url: repositoryURL, requirement: requirement) + } - /// Maps the version requirement of an `XCRemoteSwiftPackageReference` to a `Package.Requirement`. - /// - /// This method converts the version requirement specified in the Xcode project into a `Requirement` - /// used by the internal `Package` model. It supports all standard SwiftPM versioning schemes, - /// including major/minor constraints, exact versions, ranges, branches, and revisions. - /// - /// - Parameter package: The `XCRemoteSwiftPackageReference` whose requirement to map. - /// - Returns: A `Package.Requirement` representing the version requirement. - public func mapRequirement(package: XCRemoteSwiftPackageReference) async -> Requirement { - guard let versionRequirement = package.versionRequirement else { - return .upToNextMajor("0.0.0") + /// Maps an `XCLocalSwiftPackageReference` to a `Package`. + /// + /// - Parameter package: The `XCLocalSwiftPackageReference` to map. + /// - Returns: A `Package` instance representing the mapped local package. + /// - Throws: If the relative path is invalid. + public func map(package: XCLocalSwiftPackageReference) async throws -> Package { + let relativePath = try RelativePath(validating: package.relativePath) + let path = projectProvider.sourceDirectory.appending(relativePath) + return .local(path: path) } - switch versionRequirement { - case .upToNextMajorVersion(let version): - return .upToNextMajor(version) - case .upToNextMinorVersion(let version): - return .upToNextMinor(version) - case .exact(let version): - return .exact(version) - case .range(let lowerBound, let upperBound): - return .range(from: lowerBound, to: upperBound) - case .branch(let branch): - return .branch(branch) - case .revision(let revision): - return .revision(revision) + /// Maps the version requirement of an `XCRemoteSwiftPackageReference` to a `Package.Requirement`. + /// + /// This method converts the version requirement specified in the Xcode project into a `Requirement` + /// used by the internal `Package` model. It supports all standard SwiftPM versioning schemes, + /// including major/minor constraints, exact versions, ranges, branches, and revisions. + /// + /// - Parameter package: The `XCRemoteSwiftPackageReference` whose requirement to map. + /// - Returns: A `Package.Requirement` representing the version requirement. + public func mapRequirement(package: XCRemoteSwiftPackageReference) async -> Requirement { + guard let versionRequirement = package.versionRequirement else { + return .upToNextMajor("0.0.0") + } + + switch versionRequirement { + case let .upToNextMajorVersion(version): + return .upToNextMajor(version) + case let .upToNextMinorVersion(version): + return .upToNextMinor(version) + case let .exact(version): + return .exact(version) + case let .range(lowerBound, upperBound): + return .range(from: lowerBound, to: upperBound) + case let .branch(branch): + return .branch(branch) + case let .revision(revision): + return .revision(revision) + } } - } } diff --git a/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift b/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift index 7f0a52cb..f2fcd0fe 100644 --- a/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift @@ -6,11 +6,11 @@ import XcodeProj /// A type that maps a project structure into a `Project` model. protocol ProjectMapping: Sendable { - /// Maps the current project into a `Project` model. - /// - /// - Returns: A fully constructed `Project` model. - /// - Throws: An error if the mapping process fails. - func mapProject() async throws -> Project + /// Maps the current project into a `Project` model. + /// + /// - Returns: A fully constructed `Project` model. + /// - Throws: An error if the mapping process fails. + func mapProject() async throws -> Project } /// A mapper responsible for translating a parsed Xcode project into a `Project` model. @@ -20,147 +20,148 @@ protocol ProjectMapping: Sendable { /// It also fetches and maps schemes using a `SchemeMapper`, integrates resource synthesizer definitions, /// and aggregates all project-related data into a single `Project` instance. public final class ProjectMapper: ProjectMapping { - private let projectProvider: ProjectProviding + private let projectProvider: ProjectProviding - /// Initializes the mapper with a given project provider. - /// - /// - Parameter projectProvider: A `ProjectProviding` instance capable of supplying access - /// to the project's files, directories, and parsed structures. - public init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - } + /// Initializes the mapper with a given project provider. + /// + /// - Parameter projectProvider: A `ProjectProviding` instance capable of supplying access + /// to the project's files, directories, and parsed structures. + public init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + } - /// Maps the current project into a `Project` model. - /// - /// This method fetches project-level settings, targets, packages, and schemes, then consolidates them - /// into a single `Project` instance. It also retrieves resource synthesizers to facilitate code generation - /// tasks and other downstream tooling that relies on structured resource definitions. - /// - /// - Returns: A fully constructed `Project` model containing settings, targets, packages, and schemes. - /// - Throws: An error if any portion of the mapping process (e.g., reading project files or mapping targets) fails. - public func mapProject() async throws -> Project { - let settingsMapper = SettingsMapper() - let pbxProject = try self.projectProvider.pbxProject() - let settings = try await settingsMapper.map( - projectProvider: projectProvider, - configurationList: pbxProject.buildConfigurationList) + /// Maps the current project into a `Project` model. + /// + /// This method fetches project-level settings, targets, packages, and schemes, then consolidates them + /// into a single `Project` instance. It also retrieves resource synthesizers to facilitate code generation + /// tasks and other downstream tooling that relies on structured resource definitions. + /// + /// - Returns: A fully constructed `Project` model containing settings, targets, packages, and schemes. + /// - Throws: An error if any portion of the mapping process (e.g., reading project files or mapping targets) fails. + public func mapProject() async throws -> Project { + let settingsMapper = SettingsMapper() + let pbxProject = try projectProvider.pbxProject() + let settings = try await settingsMapper.map( + projectProvider: projectProvider, + configurationList: pbxProject.buildConfigurationList + ) - let targetMapper = TargetMapper(projectProvider: projectProvider) - let targetsArray = try await pbxProject.targets.asyncCompactMap { pbxTarget in - try await targetMapper.map(pbxTarget: pbxTarget) - } + let targetMapper = TargetMapper(projectProvider: projectProvider) + let targetsArray = try await pbxProject.targets.asyncCompactMap { pbxTarget in + try await targetMapper.map(pbxTarget: pbxTarget) + } - let packageMapper = PackageMapper(projectProvider: projectProvider) - let remotePackages = try await pbxProject.remotePackages.asyncCompactMap { package in - try await packageMapper.map(package: package) - } - let localPackages = try await pbxProject.localPackages.asyncCompactMap { package in - try await packageMapper.map(package: package) - } + let packageMapper = PackageMapper(projectProvider: projectProvider) + let remotePackages = try await pbxProject.remotePackages.asyncCompactMap { package in + try await packageMapper.map(package: package) + } + let localPackages = try await pbxProject.localPackages.asyncCompactMap { package in + try await packageMapper.map(package: package) + } - let filesGroup = ProjectGroup.group(name: pbxProject.mainGroup?.name ?? "Project") + let filesGroup = ProjectGroup.group(name: pbxProject.mainGroup?.name ?? "Project") - let schemeMapper = try SchemeMapper(graphType: .project(projectProvider.sourceDirectory)) - let userSchemes = projectProvider.xcodeProj.userData.flatMap { $0.schemes } - let sharedSchemes = projectProvider.xcodeProj.sharedData?.schemes ?? [] - let schemes: [Scheme] = - try await schemeMapper.mapSchemesAsync(xcschemes: userSchemes, shared: false) - + (try await schemeMapper.mapSchemesAsync(xcschemes: sharedSchemes, shared: true)) + let schemeMapper = try SchemeMapper(graphType: .project(projectProvider.sourceDirectory)) + let userSchemes = projectProvider.xcodeProj.userData.flatMap(\.schemes) + let sharedSchemes = projectProvider.xcodeProj.sharedData?.schemes ?? [] + let schemes: [Scheme] = + try await schemeMapper.mapSchemesAsync(xcschemes: userSchemes, shared: false) + + (try await schemeMapper.mapSchemesAsync(xcschemes: sharedSchemes, shared: true)) - let lastUpgradeCheck = pbxProject.attribute(for: .lastUpgradeCheck).flatMap { - Version(string: $0) - } - let defaultKnownRegions = pbxProject.knownRegions.isEmpty ? nil : pbxProject.knownRegions + let lastUpgradeCheck = pbxProject.attribute(for: .lastUpgradeCheck).flatMap { + Version(string: $0) + } + let defaultKnownRegions = pbxProject.knownRegions.isEmpty ? nil : pbxProject.knownRegions - return Project( - path: projectProvider.sourceDirectory, - sourceRootPath: projectProvider.sourceDirectory, - xcodeProjPath: projectProvider.sourceDirectory, - name: pbxProject.name, - organizationName: pbxProject.attribute(for: .organization), - classPrefix: pbxProject.attribute(for: .classPrefix), - defaultKnownRegions: defaultKnownRegions, - developmentRegion: pbxProject.developmentRegion, - options: Project.Options( - automaticSchemesOptions: .disabled, - disableBundleAccessors: false, - disableShowEnvironmentVarsInScriptPhases: false, - disableSynthesizedResourceAccessors: false, - textSettings: .init(usesTabs: nil, indentWidth: nil, tabWidth: nil, wrapsLines: nil) - ), - settings: settings, - filesGroup: filesGroup, - targets: targetsArray.sorted(), - packages: remotePackages + localPackages, - schemes: schemes, - ideTemplateMacros: nil, - additionalFiles: [], - resourceSynthesizers: mapResourceSynthesizers(from: pbxProject), - lastUpgradeCheck: lastUpgradeCheck, - type: .local - ) - } + return Project( + path: projectProvider.sourceDirectory, + sourceRootPath: projectProvider.sourceDirectory, + xcodeProjPath: projectProvider.sourceDirectory, + name: pbxProject.name, + organizationName: pbxProject.attribute(for: .organization), + classPrefix: pbxProject.attribute(for: .classPrefix), + defaultKnownRegions: defaultKnownRegions, + developmentRegion: pbxProject.developmentRegion, + options: Project.Options( + automaticSchemesOptions: .disabled, + disableBundleAccessors: false, + disableShowEnvironmentVarsInScriptPhases: false, + disableSynthesizedResourceAccessors: false, + textSettings: .init(usesTabs: nil, indentWidth: nil, tabWidth: nil, wrapsLines: nil) + ), + settings: settings, + filesGroup: filesGroup, + targets: targetsArray.sorted(), + packages: remotePackages + localPackages, + schemes: schemes, + ideTemplateMacros: nil, + additionalFiles: [], + resourceSynthesizers: mapResourceSynthesizers(from: pbxProject), + lastUpgradeCheck: lastUpgradeCheck, + type: .local + ) + } - /// Maps known resource synthesizer definitions from the given `PBXProject`. - /// - /// These synthesizers define how various resource types (e.g., strings, assets, plists) are transformed or accessed. - /// This information can be used downstream to generate code or to provide tooling support. - /// - /// - Parameter pbxProject: The `PBXProject` from which to derive resource synthesizer settings. - /// - Returns: An array of `ResourceSynthesizer` instances. - private func mapResourceSynthesizers(from pbxProject: PBXProject) -> [ResourceSynthesizer] { - let resourceTypes: - [(parser: ResourceSynthesizer.Parser, extensions: [String], template: String)] = [ - (.strings, ["strings", "stringsdict"], "Strings"), - (.assets, ["xcassets"], "Assets"), - (.plists, ["plist"], "Plists"), - (.fonts, ["ttf", "otf", "ttc"], "Fonts"), - (.coreData, ["xcdatamodeld"], "CoreData"), - (.interfaceBuilder, ["xib", "storyboard"], "InterfaceBuilder"), - (.json, ["json"], "JSON"), - (.yaml, ["yaml", "yml"], "YAML"), - (.files, ["txt", "md"], "Files"), - ] + /// Maps known resource synthesizer definitions from the given `PBXProject`. + /// + /// These synthesizers define how various resource types (e.g., strings, assets, plists) are transformed or accessed. + /// This information can be used downstream to generate code or to provide tooling support. + /// + /// - Parameter pbxProject: The `PBXProject` from which to derive resource synthesizer settings. + /// - Returns: An array of `ResourceSynthesizer` instances. + private func mapResourceSynthesizers(from _: PBXProject) -> [ResourceSynthesizer] { + let resourceTypes: + [(parser: ResourceSynthesizer.Parser, extensions: [String], template: String)] = [ + (.strings, ["strings", "stringsdict"], "Strings"), + (.assets, ["xcassets"], "Assets"), + (.plists, ["plist"], "Plists"), + (.fonts, ["ttf", "otf", "ttc"], "Fonts"), + (.coreData, ["xcdatamodeld"], "CoreData"), + (.interfaceBuilder, ["xib", "storyboard"], "InterfaceBuilder"), + (.json, ["json"], "JSON"), + (.yaml, ["yaml", "yml"], "YAML"), + (.files, ["txt", "md"], "Files"), + ] - return resourceTypes.map { resourceType in - ResourceSynthesizer( - parser: resourceType.parser, - parserOptions: [:], - extensions: Set(resourceType.extensions), - template: .defaultTemplate(resourceType.template) - ) + return resourceTypes.map { resourceType in + ResourceSynthesizer( + parser: resourceType.parser, + parserOptions: [:], + extensions: Set(resourceType.extensions), + template: .defaultTemplate(resourceType.template) + ) + } } - } } /// Attributes for project settings that can be retrieved from a `PBXProject`. enum ProjectAttribute: String { - case classPrefix = "CLASSPREFIX" - case organization = "ORGANIZATIONNAME" - case lastUpgradeCheck = "LastUpgradeCheck" + case classPrefix = "CLASSPREFIX" + case organization = "ORGANIZATIONNAME" + case lastUpgradeCheck = "LastUpgradeCheck" } extension PBXProject { - /// Retrieves the value of a specific project attribute. - /// - /// - Parameter attr: The attribute key to look up. - /// - Returns: The value of the attribute if it exists, or `nil` if not found. - func attribute(for attr: ProjectAttribute) -> String? { - attributes[attr.rawValue] as? String - } + /// Retrieves the value of a specific project attribute. + /// + /// - Parameter attr: The attribute key to look up. + /// - Returns: The value of the attribute if it exists, or `nil` if not found. + func attribute(for attr: ProjectAttribute) -> String? { + attributes[attr.rawValue] as? String + } } extension SchemeMapper { - /// Maps the given Xcode schemes asynchronously. - /// - /// - Parameters: - /// - xcschemes: An array of `XCScheme` instances to map. - /// - shared: A Boolean indicating whether the schemes are shared. - /// - Returns: An array of mapped `Scheme` instances. - /// - Throws: If mapping any scheme fails. - func mapSchemesAsync(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] { - try await xcschemes.asyncCompactMap { scheme in - try await self.mapScheme(xcscheme: scheme, shared: shared) + /// Maps the given Xcode schemes asynchronously. + /// + /// - Parameters: + /// - xcschemes: An array of `XCScheme` instances to map. + /// - shared: A Boolean indicating whether the schemes are shared. + /// - Returns: An array of mapped `Scheme` instances. + /// - Throws: If mapping any scheme fails. + func mapSchemesAsync(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] { + try await xcschemes.asyncCompactMap { scheme in + try await self.mapScheme(xcscheme: scheme, shared: shared) + } } - } } diff --git a/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift b/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift index be38c74e..128e326e 100644 --- a/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift +++ b/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift @@ -10,40 +10,40 @@ import XcodeGraph /// and a parsed `XcodeProj` instance. They also provide a convenient way to retrieve /// the main `PBXProject` object from the project. public protocol ProjectProviding: Sendable { - /// The absolute path to the directory containing the Xcode project. - var sourceDirectory: AbsolutePath { get } + /// The absolute path to the directory containing the Xcode project. + var sourceDirectory: AbsolutePath { get } - /// The absolute path to the `.xcodeproj` file. - var xcodeProjPath: AbsolutePath { get } + /// The absolute path to the `.xcodeproj` file. + var xcodeProjPath: AbsolutePath { get } - /// The parsed `XcodeProj` instance representing the Xcode project. - var xcodeProj: XcodeProj { get } + /// The parsed `XcodeProj` instance representing the Xcode project. + var xcodeProj: XcodeProj { get } - /// Returns the main `PBXProject` object from the `.xcodeproj`. - /// - /// - Throws: `MappingError.noProjectsFound` if no projects are found in the `.xcodeproj`. - /// - Returns: A `PBXProject` representing the primary project definition. - func pbxProject() throws -> PBXProject + /// Returns the main `PBXProject` object from the `.xcodeproj`. + /// + /// - Throws: `MappingError.noProjectsFound` if no projects are found in the `.xcodeproj`. + /// - Returns: A `PBXProject` representing the primary project definition. + func pbxProject() throws -> PBXProject } extension ProjectProviding { - /// A convenience property providing the source directory as a string. - public var sourcePathString: String { - sourceDirectory.pathString - } + /// A convenience property providing the source directory as a string. + public var sourcePathString: String { + sourceDirectory.pathString + } - /// The source directory is assumed to be the parent of the `.xcodeproj` directory. - public var sourceDirectory: AbsolutePath { - xcodeProjPath.parentDirectory - } + /// The source directory is assumed to be the parent of the `.xcodeproj` directory. + public var sourceDirectory: AbsolutePath { + xcodeProjPath.parentDirectory + } - public func pbxProject() throws -> PBXProject { - guard let pbxProject = xcodeProj.pbxproj.projects.first else { - // TODO: - Add path assocaited value - throw MappingError.noProjectsFound + public func pbxProject() throws -> PBXProject { + guard let pbxProject = xcodeProj.pbxproj.projects.first else { + // TODO: - Add path assocaited value + throw MappingError.noProjectsFound + } + return pbxProject } - return pbxProject - } } /// A concrete provider that supplies information about a particular Xcode project. @@ -52,16 +52,16 @@ extension ProjectProviding { /// `XcodeProj` representation and the associated file paths. It simplifies operations /// that need to read or analyze the project structure. public struct ProjectProvider: ProjectProviding { - public let xcodeProj: XcodeProj - public let xcodeProjPath: AbsolutePath + public let xcodeProj: XcodeProj + public let xcodeProjPath: AbsolutePath - /// Initializes a new `ProjectProvider` with the given project path and `XcodeProj` instance. - /// - /// - Parameters: - /// - xcodeProjPath: The absolute path to the `.xcodeproj` file. - /// - xcodeProj: The parsed `XcodeProj` instance representing the project. - public init(xcodeProjPath: AbsolutePath, xcodeProj: XcodeProj) { - self.xcodeProjPath = xcodeProjPath - self.xcodeProj = xcodeProj - } + /// Initializes a new `ProjectProvider` with the given project path and `XcodeProj` instance. + /// + /// - Parameters: + /// - xcodeProjPath: The absolute path to the `.xcodeproj` file. + /// - xcodeProj: The parsed `XcodeProj` instance representing the project. + public init(xcodeProjPath: AbsolutePath, xcodeProj: XcodeProj) { + self.xcodeProjPath = xcodeProjPath + self.xcodeProj = xcodeProj + } } diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/BuildSettings.swift b/Sources/XcodeProjToGraph/Mappers/Settings/BuildSettings.swift index 6e0b4c74..e5652b26 100644 --- a/Sources/XcodeProjToGraph/Mappers/Settings/BuildSettings.swift +++ b/Sources/XcodeProjToGraph/Mappers/Settings/BuildSettings.swift @@ -2,99 +2,99 @@ import Foundation /// Keys representing various build settings that may appear in an Xcode project or workspace configuration. enum BuildSettingKey: String { - case sdkroot = "SDKROOT" - case compilerFlags = "COMPILER_FLAGS" - case attributes = "ATTRIBUTES" - case environmentVariables = "ENVIRONMENT_VARIABLES" - case codeSignOnCopy = "CODE_SIGN_ON_COPY" - case dependencyFile = "DEPENDENCY_FILE" - case inputPaths = "INPUT_PATHS" - case outputPaths = "OUTPUT_PATHS" - case showEnvVarsInLog = "SHOW_ENV_VARS_IN_LOG" - case shellPath = "SHELL_PATH" - case launchArguments = "LAUNCH_ARGUMENTS" - case tags = "TAGS" - case mergedBinaryType = "MERGED_BINARY_TYPE" - case prune = "PRUNE" - case mergeable = "MERGEABLE" - case productBundleIdentifier = "PRODUCT_BUNDLE_IDENTIFIER" - case infoPlistFile = "INFOPLIST_FILE" - case codeSignEntitlements = "CODE_SIGN_ENTITLEMENTS" - case iPhoneOSDeploymentTarget = "IPHONEOS_DEPLOYMENT_TARGET" - case macOSDeploymentTarget = "MACOSX_DEPLOYMENT_TARGET" - case watchOSDeploymentTarget = "WATCHOS_DEPLOYMENT_TARGET" - case tvOSDeploymentTarget = "TVOS_DEPLOYMENT_TARGET" - case visionOSDeploymentTarget = "VISIONOS_DEPLOYMENT_TARGET" + case sdkroot = "SDKROOT" + case compilerFlags = "COMPILER_FLAGS" + case attributes = "ATTRIBUTES" + case environmentVariables = "ENVIRONMENT_VARIABLES" + case codeSignOnCopy = "CODE_SIGN_ON_COPY" + case dependencyFile = "DEPENDENCY_FILE" + case inputPaths = "INPUT_PATHS" + case outputPaths = "OUTPUT_PATHS" + case showEnvVarsInLog = "SHOW_ENV_VARS_IN_LOG" + case shellPath = "SHELL_PATH" + case launchArguments = "LAUNCH_ARGUMENTS" + case tags = "TAGS" + case mergedBinaryType = "MERGED_BINARY_TYPE" + case prune = "PRUNE" + case mergeable = "MERGEABLE" + case productBundleIdentifier = "PRODUCT_BUNDLE_IDENTIFIER" + case infoPlistFile = "INFOPLIST_FILE" + case codeSignEntitlements = "CODE_SIGN_ENTITLEMENTS" + case iPhoneOSDeploymentTarget = "IPHONEOS_DEPLOYMENT_TARGET" + case macOSDeploymentTarget = "MACOSX_DEPLOYMENT_TARGET" + case watchOSDeploymentTarget = "WATCHOS_DEPLOYMENT_TARGET" + case tvOSDeploymentTarget = "TVOS_DEPLOYMENT_TARGET" + case visionOSDeploymentTarget = "VISIONOS_DEPLOYMENT_TARGET" } /// A protocol representing a type that can parse a build setting value from a generic `Any`. protocol BuildSettingValue { - associatedtype Value - static func parse(_ any: Any) -> Value? + associatedtype Value + static func parse(_ any: Any) -> Value? } /// A type that parses build settings as strings. enum BuildSettingString: BuildSettingValue { - static func parse(_ any: Any) -> String? { - any as? String - } + static func parse(_ any: Any) -> String? { + any as? String + } } /// A type that parses build settings as arrays of strings. enum BuildSettingStringArray: BuildSettingValue { - static func parse(_ any: Any) -> [String]? { - let arr = any as? [Any] - return arr?.compactMap { $0 as? String } - } + static func parse(_ any: Any) -> [String]? { + let arr = any as? [Any] + return arr?.compactMap { $0 as? String } + } } /// A type that parses build settings as booleans. enum BuildSettingBool: BuildSettingValue { - static func parse(_ any: Any) -> Bool? { - any as? Bool - } + static func parse(_ any: Any) -> Bool? { + any as? Bool + } } /// A type that parses build settings as dictionaries of strings to strings. enum BuildSettingStringDict: BuildSettingValue { - static func parse(_ any: Any) -> [String: String]? { - any as? [String: String] - } + static func parse(_ any: Any) -> [String: String]? { + any as? [String: String] + } } -extension Dictionary where Key == String, Value == Any { - /// Extracts a build setting value of a specified type from the dictionary. - /// - /// - Parameters: - /// - key: The `BuildSettingKey` to look up. - /// - type: The type conforming to `BuildSettingValue` indicating the expected value type. - /// - Returns: The parsed value if found and valid, or `nil` otherwise. - func extractBuildSetting(_ key: BuildSettingKey, as type: T.Type = T.self) - -> T.Value? - { - guard let value = self[key.rawValue] else { return nil } - return T.parse(value) - } +extension [String: Any] { + /// Extracts a build setting value of a specified type from the dictionary. + /// + /// - Parameters: + /// - key: The `BuildSettingKey` to look up. + /// - type: The type conforming to `BuildSettingValue` indicating the expected value type. + /// - Returns: The parsed value if found and valid, or `nil` otherwise. + func extractBuildSetting(_ key: BuildSettingKey, as _: T.Type = T.self) + -> T.Value? + { + guard let value = self[key.rawValue] else { return nil } + return T.parse(value) + } } -extension Dictionary where Key == String, Value == Any { - /// Retrieves a string value for the given build setting key. - func string(for key: BuildSettingKey) -> String? { - extractBuildSetting(key, as: BuildSettingString.self) - } +extension [String: Any] { + /// Retrieves a string value for the given build setting key. + func string(for key: BuildSettingKey) -> String? { + extractBuildSetting(key, as: BuildSettingString.self) + } - /// Retrieves an array of strings for the given build setting key. - func stringArray(for key: BuildSettingKey) -> [String]? { - extractBuildSetting(key, as: BuildSettingStringArray.self) - } + /// Retrieves an array of strings for the given build setting key. + func stringArray(for key: BuildSettingKey) -> [String]? { + extractBuildSetting(key, as: BuildSettingStringArray.self) + } - /// Retrieves a boolean value for the given build setting key. - func bool(for key: BuildSettingKey) -> Bool? { - extractBuildSetting(key, as: BuildSettingBool.self) - } + /// Retrieves a boolean value for the given build setting key. + func bool(for key: BuildSettingKey) -> Bool? { + extractBuildSetting(key, as: BuildSettingBool.self) + } - /// Retrieves a dictionary of strings for the given build setting key. - func stringDict(for key: BuildSettingKey) -> [String: String]? { - extractBuildSetting(key, as: BuildSettingStringDict.self) - } + /// Retrieves a dictionary of strings for the given build setting key. + func stringDict(for key: BuildSettingKey) -> [String: String]? { + extractBuildSetting(key, as: BuildSettingStringDict.self) + } } diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift b/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift index 97776523..8583c06f 100644 --- a/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift +++ b/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift @@ -5,38 +5,38 @@ import XcodeProj /// A utility that determines the variant of a build configuration (e.g., debug or release) /// based on naming conventions and validates configuration names. -struct ConfigurationMatcher { - /// Represents a pattern mapping a set of keywords to a configuration variant. - private struct Pattern { - let keywords: Set - let variant: BuildConfiguration.Variant - } +enum ConfigurationMatcher { + /// Represents a pattern mapping a set of keywords to a configuration variant. + private struct Pattern { + let keywords: Set + let variant: BuildConfiguration.Variant + } - /// Common patterns for identifying build configuration variants. - private static let patterns: [Pattern] = [ - Pattern(keywords: ["debug", "development", "dev"], variant: .debug), - Pattern(keywords: ["release", "prod", "production"], variant: .release), - ] + /// Common patterns for identifying build configuration variants. + private static let patterns: [Pattern] = [ + Pattern(keywords: ["debug", "development", "dev"], variant: .debug), + Pattern(keywords: ["release", "prod", "production"], variant: .release), + ] - /// Returns the build configuration variant for a given configuration name. - /// - /// This method lowercases the name and checks if it contains any keywords for known variants. - /// If none match, it defaults to `.debug`. - /// - /// - Parameter name: The name of the build configuration. - /// - Returns: The determined `BuildConfiguration.Variant` for the given name. - static public func variant(forName name: String) -> BuildConfiguration.Variant { - let lowercased = name.lowercased() - return patterns.first { pattern in - pattern.keywords.contains { lowercased.contains($0) } - }?.variant ?? .debug - } + /// Returns the build configuration variant for a given configuration name. + /// + /// This method lowercases the name and checks if it contains any keywords for known variants. + /// If none match, it defaults to `.debug`. + /// + /// - Parameter name: The name of the build configuration. + /// - Returns: The determined `BuildConfiguration.Variant` for the given name. + public static func variant(forName name: String) -> BuildConfiguration.Variant { + let lowercased = name.lowercased() + return patterns.first { pattern in + pattern.keywords.contains { lowercased.contains($0) } + }?.variant ?? .debug + } - /// Validates that a configuration name is non-empty and contains no whitespace. - /// - /// - Parameter name: The configuration name to validate. - /// - Returns: `true` if the name is valid; `false` otherwise. - static public func validateConfigurationName(_ name: String) -> Bool { - !name.isEmpty && name.rangeOfCharacter(from: .whitespaces) == nil - } + /// Validates that a configuration name is non-empty and contains no whitespace. + /// + /// - Parameter name: The configuration name to validate. + /// - Returns: `true` if the name is valid; `false` otherwise. + public static func validateConfigurationName(_ name: String) -> Bool { + !name.isEmpty && name.rangeOfCharacter(from: .whitespaces) == nil + } } diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift b/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift index ffd06779..bbf5065a 100644 --- a/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift @@ -5,103 +5,103 @@ import XcodeProj /// A protocol defining how to map an Xcode project's configuration list into a `Settings` model. protocol SettingsMapping: Sendable { - /// Maps a given `XCConfigurationList` into `Settings`. - /// - /// - Parameters: - /// - projectProvider: A provider for project-related paths and files. - /// - configurationList: The `XCConfigurationList` to map. - /// - Returns: A `Settings` model derived from the configuration list, or default settings if none are found. - /// - Throws: If build settings cannot be mapped correctly. - func map(projectProvider: ProjectProviding, configurationList: XCConfigurationList?) async throws - -> Settings + /// Maps a given `XCConfigurationList` into `Settings`. + /// + /// - Parameters: + /// - projectProvider: A provider for project-related paths and files. + /// - configurationList: The `XCConfigurationList` to map. + /// - Returns: A `Settings` model derived from the configuration list, or default settings if none are found. + /// - Throws: If build settings cannot be mapped correctly. + func map(projectProvider: ProjectProviding, configurationList: XCConfigurationList?) async throws + -> Settings } /// A mapper responsible for converting an Xcode project's configuration list into a `Settings` domain model. final class SettingsMapper: SettingsMapping { + /// Creates a new `SettingsMapper`. + public init() {} - /// Creates a new `SettingsMapper`. - public init() {} + public func map(projectProvider: ProjectProviding, configurationList: XCConfigurationList?) + async throws -> Settings + { + guard let configurationList else { + return Settings.default + } - public func map(projectProvider: ProjectProviding, configurationList: XCConfigurationList?) - async throws -> Settings - { - guard let configurationList = configurationList else { - return Settings.default - } + var configurations: [BuildConfiguration: Configuration?] = [:] + for buildConfig in configurationList.buildConfigurations { + let buildSettings = buildConfig.buildSettings + let settingsDict = try await mapBuildSettings(buildSettings) - var configurations: [BuildConfiguration: Configuration?] = [:] - for buildConfig in configurationList.buildConfigurations { - let buildSettings = buildConfig.buildSettings - let settingsDict = try await mapBuildSettings(buildSettings) + var xcconfigAbsolutePath: AbsolutePath? + if let baseConfigRef = buildConfig.baseConfiguration, + let xcconfigPath = try baseConfigRef.fullPath( + sourceRoot: projectProvider.sourceDirectory.pathString + ) + { + xcconfigAbsolutePath = try AbsolutePath.resolvePath(xcconfigPath) + } - var xcconfigAbsolutePath: AbsolutePath? - if let baseConfigRef = buildConfig.baseConfiguration, - let xcconfigPath = try baseConfigRef.fullPath( - sourceRoot: projectProvider.sourceDirectory.pathString) - { - xcconfigAbsolutePath = try AbsolutePath.resolvePath(xcconfigPath) - } + let variant = variant(forName: buildConfig.name) + let buildConfiguration = BuildConfiguration(name: buildConfig.name, variant: variant) + configurations[buildConfiguration] = Configuration( + settings: settingsDict, + xcconfig: xcconfigAbsolutePath + ) + } - let variant = variant(forName: buildConfig.name) - let buildConfiguration = BuildConfiguration(name: buildConfig.name, variant: variant) - configurations[buildConfiguration] = Configuration( - settings: settingsDict, - xcconfig: xcconfigAbsolutePath - ) + return Settings( + base: [:], + baseDebug: [:], + configurations: configurations, + defaultSettings: .recommended + ) } - return Settings( - base: [:], - baseDebug: [:], - configurations: configurations, - defaultSettings: .recommended - ) - } - - /// Maps a dictionary of raw build settings into a `SettingsDictionary`. - /// - /// The raw values are converted into `SettingValue` instances. String and array values are directly converted, - /// while other types are stringified as a fallback. - /// - /// - Parameter buildSettings: A dictionary representing the raw build settings. - /// - Returns: A `SettingsDictionary` with mapped `SettingValue` instances. - /// - Throws: If a setting value cannot be mapped. - public func mapBuildSettings(_ buildSettings: [String: Any]) async throws -> SettingsDictionary { - var settingsDict = SettingsDictionary() - for (key, value) in buildSettings { - settingsDict[key] = try await mapSettingValue(value) + /// Maps a dictionary of raw build settings into a `SettingsDictionary`. + /// + /// The raw values are converted into `SettingValue` instances. String and array values are directly converted, + /// while other types are stringified as a fallback. + /// + /// - Parameter buildSettings: A dictionary representing the raw build settings. + /// - Returns: A `SettingsDictionary` with mapped `SettingValue` instances. + /// - Throws: If a setting value cannot be mapped. + public func mapBuildSettings(_ buildSettings: [String: Any]) async throws -> SettingsDictionary { + var settingsDict = SettingsDictionary() + for (key, value) in buildSettings { + settingsDict[key] = try await mapSettingValue(value) + } + return settingsDict } - return settingsDict - } - /// Maps a raw setting value into a `SettingValue`. - /// - /// If the value is a string, it's mapped directly. - /// If it's an array, elements are mapped to strings if possible. - /// Otherwise, the value is stringified. - /// - /// - Parameter value: The raw setting value from the build settings. - /// - Returns: A `SettingValue` representing the mapped value. - private func mapSettingValue(_ value: Any) async throws -> SettingValue { - if let stringValue = value as? String { - return .string(stringValue) - } else if let arrayValue = value as? [Any] { - let stringArray = arrayValue.compactMap { $0 as? String } - return .array(stringArray) - } else { - // Fallback: convert non-string/non-array values to string - let stringValue = String(describing: value) - return .string(stringValue) + /// Maps a raw setting value into a `SettingValue`. + /// + /// If the value is a string, it's mapped directly. + /// If it's an array, elements are mapped to strings if possible. + /// Otherwise, the value is stringified. + /// + /// - Parameter value: The raw setting value from the build settings. + /// - Returns: A `SettingValue` representing the mapped value. + private func mapSettingValue(_ value: Any) async throws -> SettingValue { + if let stringValue = value as? String { + return .string(stringValue) + } else if let arrayValue = value as? [Any] { + let stringArray = arrayValue.compactMap { $0 as? String } + return .array(stringArray) + } else { + // Fallback: convert non-string/non-array values to string + let stringValue = String(describing: value) + return .string(stringValue) + } } - } - /// Determines a build configuration variant (debug or release) based on its name. - /// - /// Uses `ConfigurationMatcher` to determine if the configuration name suggests a debug or release variant. - /// - /// - Parameter name: The name of the build configuration. - /// - Returns: The corresponding `BuildConfiguration.Variant`. - private func variant(forName name: String) -> BuildConfiguration.Variant { - ConfigurationMatcher.variant(forName: name) - } + /// Determines a build configuration variant (debug or release) based on its name. + /// + /// Uses `ConfigurationMatcher` to determine if the configuration name suggests a debug or release variant. + /// + /// - Parameter name: The name of the build configuration. + /// - Returns: The corresponding `BuildConfiguration.Variant`. + private func variant(forName name: String) -> BuildConfiguration.Variant { + ConfigurationMatcher.variant(forName: name) + } } diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/XCConfigurationList+Helpers.swift b/Sources/XcodeProjToGraph/Mappers/Settings/XCConfigurationList+Helpers.swift index b62832b6..059082a1 100644 --- a/Sources/XcodeProjToGraph/Mappers/Settings/XCConfigurationList+Helpers.swift +++ b/Sources/XcodeProjToGraph/Mappers/Settings/XCConfigurationList+Helpers.swift @@ -1,36 +1,36 @@ import XcodeProj extension XCConfigurationList { - /// Retrieves a build setting value from the first configuration in which it is found. - /// - /// - Parameter key: The `BuildSettingKey` to look up. - /// - Returns: The value as a `String` if found, otherwise `nil`. - func stringSetting(for key: BuildSettingKey) -> String? { - for config in buildConfigurations { - if let value = config.buildSettings.string(for: key) { - return value - } + /// Retrieves a build setting value from the first configuration in which it is found. + /// + /// - Parameter key: The `BuildSettingKey` to look up. + /// - Returns: The value as a `String` if found, otherwise `nil`. + func stringSetting(for key: BuildSettingKey) -> String? { + for config in buildConfigurations { + if let value = config.buildSettings.string(for: key) { + return value + } + } + return nil } - return nil - } - /// Retrieves all deployment target values from all configurations and aggregates them. - /// - /// - Parameters: - /// - keys: A list of keys to search (e.g., `.iPhoneOSDeploymentTarget`, `.macOSDeploymentTarget`) - /// - Returns: A dictionary mapping `BuildSettingKey` to the found value. - func allDeploymentTargets(keys: [BuildSettingKey]) -> [BuildSettingKey: String] { - var results = [BuildSettingKey: String]() + /// Retrieves all deployment target values from all configurations and aggregates them. + /// + /// - Parameters: + /// - keys: A list of keys to search (e.g., `.iPhoneOSDeploymentTarget`, `.macOSDeploymentTarget`) + /// - Returns: A dictionary mapping `BuildSettingKey` to the found value. + func allDeploymentTargets(keys: [BuildSettingKey]) -> [BuildSettingKey: String] { + var results = [BuildSettingKey: String]() - for key in keys { - for config in buildConfigurations { - if let value = config.buildSettings.string(for: key) { - results[key] = value - break // Once found, move to the next key + for key in keys { + for config in buildConfigurations { + if let value = config.buildSettings.string(for: key) { + results[key] = value + break // Once found, move to the next key + } + } } - } - } - return results - } + return results + } } diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildHeaders.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildHeaders.swift index 337fd92a..cd9dceff 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildHeaders.swift +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildHeaders.swift @@ -1,8 +1,8 @@ import XcodeProj extension PBXTarget { - /// Returns the headers build phase, if any. - public func headersBuildPhase() throws -> PBXHeadersBuildPhase? { - buildPhases.compactMap { $0 as? PBXHeadersBuildPhase }.first - } + /// Returns the headers build phase, if any. + public func headersBuildPhase() throws -> PBXHeadersBuildPhase? { + buildPhases.compactMap { $0 as? PBXHeadersBuildPhase }.first + } } diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift index fef5abd1..217f9704 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift @@ -4,50 +4,50 @@ import XcodeGraph import XcodeProj extension PBXTarget { - /// Retrieves the path to the Info.plist file from the target's build settings. - /// - /// - Returns: The `INFOPLIST_FILE` value if present, otherwise `nil`. - public func infoPlistPath() throws -> String? { - buildConfigurationList?.stringSetting(for: .infoPlistFile) - } - - /// Retrieves the path to the entitlements file from the target's build settings. - /// - /// - Returns: The `CODE_SIGN_ENTITLEMENTS` value if present, otherwise `nil`. - public func entitlementsPath() throws -> String? { - buildConfigurationList?.stringSetting(for: .codeSignEntitlements) - } + /// Retrieves the path to the Info.plist file from the target's build settings. + /// + /// - Returns: The `INFOPLIST_FILE` value if present, otherwise `nil`. + public func infoPlistPath() throws -> String? { + buildConfigurationList?.stringSetting(for: .infoPlistFile) + } - /// Retrieves deployment target versions for various platforms supported by this target. - /// - /// Checks build configurations for: - /// - `IPHONEOS_DEPLOYMENT_TARGET` - /// - `MACOSX_DEPLOYMENT_TARGET` - /// - `WATCHOS_DEPLOYMENT_TARGET` - /// - `TVOS_DEPLOYMENT_TARGET` - /// - `VISIONOS_DEPLOYMENT_TARGET` - /// - /// - Returns: A `DeploymentTargets` instance containing any discovered versions. - public func deploymentTargets() throws -> DeploymentTargets { - guard let configList = buildConfigurationList else { - return DeploymentTargets(iOS: nil, macOS: nil, watchOS: nil, tvOS: nil, visionOS: nil) + /// Retrieves the path to the entitlements file from the target's build settings. + /// + /// - Returns: The `CODE_SIGN_ENTITLEMENTS` value if present, otherwise `nil`. + public func entitlementsPath() throws -> String? { + buildConfigurationList?.stringSetting(for: .codeSignEntitlements) } - let keys: [BuildSettingKey] = [ - .iPhoneOSDeploymentTarget, - .macOSDeploymentTarget, - .watchOSDeploymentTarget, - .tvOSDeploymentTarget, - .visionOSDeploymentTarget, - ] + /// Retrieves deployment target versions for various platforms supported by this target. + /// + /// Checks build configurations for: + /// - `IPHONEOS_DEPLOYMENT_TARGET` + /// - `MACOSX_DEPLOYMENT_TARGET` + /// - `WATCHOS_DEPLOYMENT_TARGET` + /// - `TVOS_DEPLOYMENT_TARGET` + /// - `VISIONOS_DEPLOYMENT_TARGET` + /// + /// - Returns: A `DeploymentTargets` instance containing any discovered versions. + public func deploymentTargets() throws -> DeploymentTargets { + guard let configList = buildConfigurationList else { + return DeploymentTargets(iOS: nil, macOS: nil, watchOS: nil, tvOS: nil, visionOS: nil) + } - let targets = configList.allDeploymentTargets(keys: keys) - return DeploymentTargets( - iOS: targets[.iPhoneOSDeploymentTarget], - macOS: targets[.macOSDeploymentTarget], - watchOS: targets[.watchOSDeploymentTarget], - tvOS: targets[.tvOSDeploymentTarget], - visionOS: targets[.visionOSDeploymentTarget] - ) - } + let keys: [BuildSettingKey] = [ + .iPhoneOSDeploymentTarget, + .macOSDeploymentTarget, + .watchOSDeploymentTarget, + .tvOSDeploymentTarget, + .visionOSDeploymentTarget, + ] + + let targets = configList.allDeploymentTargets(keys: keys) + return DeploymentTargets( + iOS: targets[.iPhoneOSDeploymentTarget], + macOS: targets[.macOSDeploymentTarget], + watchOS: targets[.watchOSDeploymentTarget], + tvOS: targets[.tvOSDeploymentTarget], + visionOS: targets[.visionOSDeploymentTarget] + ) + } } diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+PlatformInference.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+PlatformInference.swift index 7fa65da6..8377b043 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+PlatformInference.swift +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+PlatformInference.swift @@ -4,80 +4,80 @@ import XcodeGraph import XcodeProj extension PBXTarget { - /// Maps the `PBXTarget.productType` to a domain `Product` model. - /// - /// If the product type is not explicitly handled, defaults to `.app`. - public func productType() -> Product { - return productType?.mapProductType() ?? .app - } + /// Maps the `PBXTarget.productType` to a domain `Product` model. + /// + /// If the product type is not explicitly handled, defaults to `.app`. + public func productType() -> Product { + return productType?.mapProductType() ?? .app + } - /// Determines the set of `Destinations` supported by this target. - /// - /// Attempts to identify platforms from: - /// 1. `SDKROOT` (if present) - /// 2. Deployment targets - /// 3. Product type as a final fallback - /// - /// Supports multi-platform scenarios by unioning destinations from all inferred platforms. - /// - /// - Returns: A `Destinations` set representing all supported destinations. - /// - Throws: If retrieving deployment targets fails. - public func platform() throws -> Destinations { - if let sdkName = buildConfigurationList?.stringSetting(for: .sdkroot), - let root = Platform(sdkroot: sdkName) - { - return root.destinations - } else { - return try inferPlatformFromTarget() + /// Determines the set of `Destinations` supported by this target. + /// + /// Attempts to identify platforms from: + /// 1. `SDKROOT` (if present) + /// 2. Deployment targets + /// 3. Product type as a final fallback + /// + /// Supports multi-platform scenarios by unioning destinations from all inferred platforms. + /// + /// - Returns: A `Destinations` set representing all supported destinations. + /// - Throws: If retrieving deployment targets fails. + public func platform() throws -> Destinations { + if let sdkName = buildConfigurationList?.stringSetting(for: .sdkroot), + let root = Platform(sdkroot: sdkName) + { + return root.destinations + } else { + return try inferPlatformFromTarget() + } } - } - /// Infers the platform from deployment targets if `SDKROOT` is not set or recognized. - /// - /// Aggregates all platforms indicated by the deployment targets. If none are found, - /// picks a default based on product type: - /// - iOS for most apps, clips, and app extensions. - /// - macOS for frameworks, libraries, command line tools, macros, xpc, system extensions. - /// - tvOS for tvTopShelfExtension. - /// - iOS otherwise. - /// - /// - Returns: A `Destinations` set representing all inferred destinations. - /// - Throws: If retrieving deployment targets fails. - private func inferPlatformFromTarget() throws -> Destinations { - let deploymentTargets = try self.deploymentTargets() - var result = Destinations() + /// Infers the platform from deployment targets if `SDKROOT` is not set or recognized. + /// + /// Aggregates all platforms indicated by the deployment targets. If none are found, + /// picks a default based on product type: + /// - iOS for most apps, clips, and app extensions. + /// - macOS for frameworks, libraries, command line tools, macros, xpc, system extensions. + /// - tvOS for tvTopShelfExtension. + /// - iOS otherwise. + /// + /// - Returns: A `Destinations` set representing all inferred destinations. + /// - Throws: If retrieving deployment targets fails. + private func inferPlatformFromTarget() throws -> Destinations { + let deploymentTargets = try deploymentTargets() + var result = Destinations() - if deploymentTargets.iOS != nil { - result.formUnion(Platform.iOS.destinations) - } - if deploymentTargets.macOS != nil { - result.formUnion(Platform.macOS.destinations) - } - if deploymentTargets.watchOS != nil { - result.formUnion(Platform.watchOS.destinations) - } - if deploymentTargets.tvOS != nil { - result.formUnion(Platform.tvOS.destinations) - } - if deploymentTargets.visionOS != nil { - result.formUnion(Platform.visionOS.destinations) - } + if deploymentTargets.iOS != nil { + result.formUnion(Platform.iOS.destinations) + } + if deploymentTargets.macOS != nil { + result.formUnion(Platform.macOS.destinations) + } + if deploymentTargets.watchOS != nil { + result.formUnion(Platform.watchOS.destinations) + } + if deploymentTargets.tvOS != nil { + result.formUnion(Platform.tvOS.destinations) + } + if deploymentTargets.visionOS != nil { + result.formUnion(Platform.visionOS.destinations) + } - guard result.isEmpty else { return result } + guard result.isEmpty else { return result } - // Fallback if no platform detected. - let product = productType?.mapProductType() ?? .app + // Fallback if no platform detected. + let product = productType?.mapProductType() ?? .app - switch product { - case .app, .stickerPackExtension, .appClip, .appExtension: - return Platform.iOS.destinations - case .framework, .staticLibrary, .dynamicLibrary, .commandLineTool, .macro, .xpc, - .systemExtension: - return Platform.macOS.destinations - case .tvTopShelfExtension: - return Platform.tvOS.destinations - default: - return Platform.iOS.destinations + switch product { + case .app, .stickerPackExtension, .appClip, .appExtension: + return Platform.iOS.destinations + case .framework, .staticLibrary, .dynamicLibrary, .commandLineTool, .macro, .xpc, + .systemExtension: + return Platform.macOS.destinations + case .tvTopShelfExtension: + return Platform.tvOS.destinations + default: + return Platform.iOS.destinations + } } - } } diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeDiagnosticsOptions+XCScheme.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeDiagnosticsOptions+XCScheme.swift index a2befd63..ebbf3f2c 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeDiagnosticsOptions+XCScheme.swift +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeDiagnosticsOptions+XCScheme.swift @@ -2,24 +2,24 @@ import XcodeGraph import XcodeProj extension SchemeDiagnosticsOptions { - /// Creates a SchemeDiagnosticsOptions from a LaunchAction. - init(action: XCScheme.LaunchAction) { - self = SchemeDiagnosticsOptions( - addressSanitizerEnabled: action.enableAddressSanitizer, - detectStackUseAfterReturnEnabled: action.enableASanStackUseAfterReturn, - threadSanitizerEnabled: action.enableThreadSanitizer, - mainThreadCheckerEnabled: !action.disableMainThreadChecker, - performanceAntipatternCheckerEnabled: !action.disablePerformanceAntipatternChecker - ) - } + /// Creates a SchemeDiagnosticsOptions from a LaunchAction. + init(action: XCScheme.LaunchAction) { + self = SchemeDiagnosticsOptions( + addressSanitizerEnabled: action.enableAddressSanitizer, + detectStackUseAfterReturnEnabled: action.enableASanStackUseAfterReturn, + threadSanitizerEnabled: action.enableThreadSanitizer, + mainThreadCheckerEnabled: !action.disableMainThreadChecker, + performanceAntipatternCheckerEnabled: !action.disablePerformanceAntipatternChecker + ) + } - /// Creates a SchemeDiagnosticsOptions from a TestAction. - init(action: XCScheme.TestAction) { - self = SchemeDiagnosticsOptions( - addressSanitizerEnabled: action.enableAddressSanitizer, - detectStackUseAfterReturnEnabled: action.enableASanStackUseAfterReturn, - threadSanitizerEnabled: action.enableThreadSanitizer, - mainThreadCheckerEnabled: !action.disableMainThreadChecker - ) - } + /// Creates a SchemeDiagnosticsOptions from a TestAction. + init(action: XCScheme.TestAction) { + self = SchemeDiagnosticsOptions( + addressSanitizerEnabled: action.enableAddressSanitizer, + detectStackUseAfterReturnEnabled: action.enableASanStackUseAfterReturn, + threadSanitizerEnabled: action.enableThreadSanitizer, + mainThreadCheckerEnabled: !action.disableMainThreadChecker + ) + } } diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift index eee33864..25ec2783 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift @@ -6,64 +6,64 @@ import XcodeProj /// A protocol defining how to map XCScheme objects and their associated actions /// into domain `Scheme` models. protocol SchemeMapping: Sendable { - /// Maps an array of `XCScheme` instances into `Scheme` models. - /// - /// - Parameters: - /// - xcschemes: An array of `XCScheme` to map. - /// - shared: A Boolean indicating whether the schemes are shared. - /// - Returns: An array of mapped `Scheme` models. - /// - Throws: If any scheme cannot be mapped. - func mapSchemes(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] - - /// Maps a single `XCScheme` into a `Scheme` model. - /// - /// - Parameters: - /// - xcscheme: The `XCScheme` to map. - /// - shared: Indicates whether the scheme is shared. - /// - Returns: A `Scheme` model. - /// - Throws: If any scheme action cannot be mapped. - func mapScheme(xcscheme: XCScheme, shared: Bool) async throws -> Scheme - - /// Maps an `XCScheme.BuildAction` into a `BuildAction` model. - /// - Parameter action: The optional XCScheme.BuildAction. - /// - Returns: A `BuildAction` instance or `nil` if action is `nil`. - /// - Throws: If target references cannot be mapped. - func mapBuildAction(action: XCScheme.BuildAction?) async throws -> BuildAction? - - /// Maps an `XCScheme.LaunchAction` into a `RunAction` model. - /// - Parameter action: The optional XCScheme.LaunchAction. - /// - Returns: A `RunAction` instance or `nil` if action is `nil`. - /// - Throws: If the executable reference cannot be mapped. - func mapRunAction(action: XCScheme.LaunchAction?) async throws -> RunAction? - - /// Maps an `XCScheme.TestAction` into a `TestAction` model. - /// - Parameter action: The optional XCScheme.TestAction. - /// - Returns: A `TestAction` instance or `nil` if action is `nil`. - /// - Throws: If test targets cannot be mapped. - func mapTestAction(action: XCScheme.TestAction?) async throws -> TestAction? - - /// Maps an `XCScheme.ArchiveAction` into an `ArchiveAction` model. - /// - Parameter action: The optional `XCScheme.ArchiveAction`. - /// - Returns: An `ArchiveAction` instance or `nil` if action is `nil`. - func mapArchiveAction(action: XCScheme.ArchiveAction?) async throws -> ArchiveAction? - - /// Maps an `XCScheme.ProfileAction` into a `ProfileAction` model. - /// - Parameter action: The optional `XCScheme.ProfileAction`. - /// - Returns: A `ProfileAction` instance or `nil` if action is `nil`. - func mapProfileAction(action: XCScheme.ProfileAction?) async throws -> ProfileAction? - - /// Maps an `XCScheme.AnalyzeAction` into an `AnalyzeAction` model. - /// - Parameter action: The optional `XCScheme.AnalyzeAction`. - /// - Returns: An `AnalyzeAction` instance or `nil` if action is `nil`. - func mapAnalyzeAction(action: XCScheme.AnalyzeAction?) async throws -> AnalyzeAction? + /// Maps an array of `XCScheme` instances into `Scheme` models. + /// + /// - Parameters: + /// - xcschemes: An array of `XCScheme` to map. + /// - shared: A Boolean indicating whether the schemes are shared. + /// - Returns: An array of mapped `Scheme` models. + /// - Throws: If any scheme cannot be mapped. + func mapSchemes(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] + + /// Maps a single `XCScheme` into a `Scheme` model. + /// + /// - Parameters: + /// - xcscheme: The `XCScheme` to map. + /// - shared: Indicates whether the scheme is shared. + /// - Returns: A `Scheme` model. + /// - Throws: If any scheme action cannot be mapped. + func mapScheme(xcscheme: XCScheme, shared: Bool) async throws -> Scheme + + /// Maps an `XCScheme.BuildAction` into a `BuildAction` model. + /// - Parameter action: The optional XCScheme.BuildAction. + /// - Returns: A `BuildAction` instance or `nil` if action is `nil`. + /// - Throws: If target references cannot be mapped. + func mapBuildAction(action: XCScheme.BuildAction?) async throws -> BuildAction? + + /// Maps an `XCScheme.LaunchAction` into a `RunAction` model. + /// - Parameter action: The optional XCScheme.LaunchAction. + /// - Returns: A `RunAction` instance or `nil` if action is `nil`. + /// - Throws: If the executable reference cannot be mapped. + func mapRunAction(action: XCScheme.LaunchAction?) async throws -> RunAction? + + /// Maps an `XCScheme.TestAction` into a `TestAction` model. + /// - Parameter action: The optional XCScheme.TestAction. + /// - Returns: A `TestAction` instance or `nil` if action is `nil`. + /// - Throws: If test targets cannot be mapped. + func mapTestAction(action: XCScheme.TestAction?) async throws -> TestAction? + + /// Maps an `XCScheme.ArchiveAction` into an `ArchiveAction` model. + /// - Parameter action: The optional `XCScheme.ArchiveAction`. + /// - Returns: An `ArchiveAction` instance or `nil` if action is `nil`. + func mapArchiveAction(action: XCScheme.ArchiveAction?) async throws -> ArchiveAction? + + /// Maps an `XCScheme.ProfileAction` into a `ProfileAction` model. + /// - Parameter action: The optional `XCScheme.ProfileAction`. + /// - Returns: A `ProfileAction` instance or `nil` if action is `nil`. + func mapProfileAction(action: XCScheme.ProfileAction?) async throws -> ProfileAction? + + /// Maps an `XCScheme.AnalyzeAction` into an `AnalyzeAction` model. + /// - Parameter action: The optional `XCScheme.AnalyzeAction`. + /// - Returns: An `AnalyzeAction` instance or `nil` if action is `nil`. + func mapAnalyzeAction(action: XCScheme.AnalyzeAction?) async throws -> AnalyzeAction? } /// Defines the type of scheme mapper based on the source of the graph. enum SchemeMapperType { - /// A workspace-based scheme mapper that may have multiple projects. - case workspace(workspacePath: AbsolutePath, pathProviders: [AbsolutePath: ProjectProviding]) - /// A project-based scheme mapper dealing with a single project. - case project(provider: ProjectProviding) + /// A workspace-based scheme mapper that may have multiple projects. + case workspace(workspacePath: AbsolutePath, pathProviders: [AbsolutePath: ProjectProviding]) + /// A project-based scheme mapper dealing with a single project. + case project(provider: ProjectProviding) } /// A mapper responsible for converting `XCScheme` objects (and related Xcode scheme configurations) @@ -73,197 +73,200 @@ enum SchemeMapperType { /// within a scheme. It resolves references to targets, environment variables, and launch arguments, /// producing a `Scheme` model that can be used for further analysis, generation, or tooling tasks. final class SchemeMapper: SchemeMapping { - private let graphType: GraphType - - /// Initializes the mapper with the given graph type. - /// - /// - Parameter graphType: The graph type (workspace or project) influencing how target references are resolved. - /// - Throws: `MappingError.noProjectsFound` if the required project information is missing. - public init(graphType: GraphType) throws { - self.graphType = graphType - } - - public func mapSchemes(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] { - try await xcschemes.asyncCompactMap { xcscheme in - try await self.mapScheme(xcscheme: xcscheme, shared: shared) + private let graphType: GraphType + + /// Initializes the mapper with the given graph type. + /// + /// - Parameter graphType: The graph type (workspace or project) influencing how target references are resolved. + /// - Throws: `MappingError.noProjectsFound` if the required project information is missing. + public init(graphType: GraphType) throws { + self.graphType = graphType } - } - - public func mapScheme(xcscheme: XCScheme, shared: Bool) async throws -> Scheme { - Scheme( - name: xcscheme.name, - shared: shared, - hidden: false, - buildAction: try await mapBuildAction(action: xcscheme.buildAction), - testAction: try await mapTestAction(action: xcscheme.testAction), - runAction: try await mapRunAction(action: xcscheme.launchAction), - archiveAction: try await mapArchiveAction(action: xcscheme.archiveAction), - profileAction: try await mapProfileAction(action: xcscheme.profileAction), - analyzeAction: try await mapAnalyzeAction(action: xcscheme.analyzeAction) - ) - } - - public func mapBuildAction(action: XCScheme.BuildAction?) async throws -> BuildAction? { - guard let action = action else { return nil } - - let targets = try await action.buildActionEntries.asyncCompactMap { entry in - let buildableReference = entry.buildableReference - return try await self.mapTargetReference(buildableReference: buildableReference) + + public func mapSchemes(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] { + try await xcschemes.asyncCompactMap { xcscheme in + try await self.mapScheme(xcscheme: xcscheme, shared: shared) + } + } + + public func mapScheme(xcscheme: XCScheme, shared: Bool) async throws -> Scheme { + Scheme( + name: xcscheme.name, + shared: shared, + hidden: false, + buildAction: try await mapBuildAction(action: xcscheme.buildAction), + testAction: try await mapTestAction(action: xcscheme.testAction), + runAction: try await mapRunAction(action: xcscheme.launchAction), + archiveAction: try await mapArchiveAction(action: xcscheme.archiveAction), + profileAction: try await mapProfileAction(action: xcscheme.profileAction), + analyzeAction: try await mapAnalyzeAction(action: xcscheme.analyzeAction) + ) } - return BuildAction( - targets: targets, - preActions: [], - postActions: [], - runPostActionsOnFailure: action.runPostActionsOnFailure ?? false, - findImplicitDependencies: action.buildImplicitDependencies - ) - } - - public func mapTestAction(action: XCScheme.TestAction?) async throws -> TestAction? { - guard let action = action else { return nil } - - let testTargets = try await action.testables.asyncCompactMap { testable in - let targetReference = try await self.mapTargetReference( - buildableReference: testable.buildableReference) - return TestableTarget(target: targetReference, skipped: testable.skipped) + public func mapBuildAction(action: XCScheme.BuildAction?) async throws -> BuildAction? { + guard let action else { return nil } + + let targets = try await action.buildActionEntries.asyncCompactMap { entry in + let buildableReference = entry.buildableReference + return try await self.mapTargetReference(buildableReference: buildableReference) + } + + return BuildAction( + targets: targets, + preActions: [], + postActions: [], + runPostActionsOnFailure: action.runPostActionsOnFailure ?? false, + findImplicitDependencies: action.buildImplicitDependencies + ) } - let environmentVariables = - action.environmentVariables?.reduce(into: [String: EnvironmentVariable]()) { dict, variable in - dict[variable.variable] = EnvironmentVariable( - value: variable.value, isEnabled: variable.enabled) - } ?? [:] - - let launchArguments = - action.commandlineArguments?.arguments.map { - LaunchArgument(name: $0.name, isEnabled: $0.enabled) - } ?? [] - - let arguments = Arguments( - environmentVariables: environmentVariables, - launchArguments: launchArguments - ) - let diagnosticsOptions = SchemeDiagnosticsOptions(action: action) - - return TestAction( - targets: testTargets, - arguments: arguments, - configurationName: action.buildConfiguration, - attachDebugger: true, - coverage: action.codeCoverageEnabled, - codeCoverageTargets: [], - expandVariableFromTarget: nil, - preActions: [], - postActions: [], - diagnosticsOptions: diagnosticsOptions, - language: action.language, - region: action.region - ) - } - - public func mapRunAction(action: XCScheme.LaunchAction?) async throws -> RunAction? { - guard let action = action else { return nil } - - let executable: TargetReference? = try await { - if let buildableRef = action.runnable?.buildableReference { - return try await mapTargetReference(buildableReference: buildableRef) - } else { - return nil - } - }() - - let environmentVariables = - action.environmentVariables?.reduce(into: [String: EnvironmentVariable]()) { dict, variable in - dict[variable.variable] = EnvironmentVariable( - value: variable.value, isEnabled: variable.enabled) - } ?? [:] - - let launchArguments = - action.commandlineArguments?.arguments.map { - LaunchArgument(name: $0.name, isEnabled: $0.enabled) - } ?? [] - - let arguments = Arguments( - environmentVariables: environmentVariables, - launchArguments: launchArguments - ) - let diagnosticsOptions = SchemeDiagnosticsOptions(action: action) - let attachDebugger = action.selectedDebuggerIdentifier.isEmpty - - return RunAction( - configurationName: action.buildConfiguration, - attachDebugger: attachDebugger, - customLLDBInitFile: nil, - preActions: [], - postActions: [], - executable: executable, - filePath: nil, - arguments: arguments, - options: RunActionOptions(), - diagnosticsOptions: diagnosticsOptions - ) - } - - public func mapArchiveAction(action: XCScheme.ArchiveAction?) async throws -> ArchiveAction? { - guard let action = action else { return nil } - - return ArchiveAction( - configurationName: action.buildConfiguration, - revealArchiveInOrganizer: action.revealArchiveInOrganizer - ) - } - - public func mapProfileAction(action: XCScheme.ProfileAction?) async throws -> ProfileAction? { - guard let action = action else { return nil } - - let executable: TargetReference? = try await { - if let buildableRef = action.buildableProductRunnable?.buildableReference { - return try await mapTargetReference(buildableReference: buildableRef) - } else { - return nil - } - }() - - return ProfileAction( - configurationName: action.buildConfiguration, - executable: executable - ) - } - - public func mapAnalyzeAction(action: XCScheme.AnalyzeAction?) async throws -> AnalyzeAction? { - guard let action = action else { return nil } - return AnalyzeAction(configurationName: action.buildConfiguration) - } - - /// Maps a `XCScheme.BuildableReference` to a `TargetReference`. - /// - /// This involves resolving the container path and the target name. - /// Depending on whether we're dealing with a workspace or a standalone project, - /// the logic may differ. - /// - /// - Parameter buildableReference: The `XCScheme.BuildableReference` to map. - /// - Returns: A `TargetReference` representing the target in the given container. - /// - Throws: If the referenced container cannot be resolved. - private func mapTargetReference(buildableReference: XCScheme.BuildableReference) async throws - -> TargetReference - { - let targetName = buildableReference.blueprintName - let container = buildableReference.referencedContainer - - let projectPath: AbsolutePath - switch self.graphType { - case .workspace(let workspaceProvider): - let containerRelativePath = container.replacingOccurrences(of: "container:", with: "") - let relativePath = try RelativePath(validating: containerRelativePath) - projectPath = workspaceProvider.workspaceDirectory.appending(relativePath) - case .project(let path): - projectPath = path + public func mapTestAction(action: XCScheme.TestAction?) async throws -> TestAction? { + guard let action else { return nil } + + let testTargets = try await action.testables.asyncCompactMap { testable in + let targetReference = try await self.mapTargetReference( + buildableReference: testable.buildableReference + ) + return TestableTarget(target: targetReference, skipped: testable.skipped) + } + + let environmentVariables = + action.environmentVariables?.reduce(into: [String: EnvironmentVariable]()) { dict, variable in + dict[variable.variable] = EnvironmentVariable( + value: variable.value, isEnabled: variable.enabled + ) + } ?? [:] + + let launchArguments = + action.commandlineArguments?.arguments.map { + LaunchArgument(name: $0.name, isEnabled: $0.enabled) + } ?? [] + + let arguments = Arguments( + environmentVariables: environmentVariables, + launchArguments: launchArguments + ) + let diagnosticsOptions = SchemeDiagnosticsOptions(action: action) + + return TestAction( + targets: testTargets, + arguments: arguments, + configurationName: action.buildConfiguration, + attachDebugger: true, + coverage: action.codeCoverageEnabled, + codeCoverageTargets: [], + expandVariableFromTarget: nil, + preActions: [], + postActions: [], + diagnosticsOptions: diagnosticsOptions, + language: action.language, + region: action.region + ) } - return TargetReference( - projectPath: projectPath, - name: targetName - ) - } + public func mapRunAction(action: XCScheme.LaunchAction?) async throws -> RunAction? { + guard let action else { return nil } + + let executable: TargetReference? = try await { + if let buildableRef = action.runnable?.buildableReference { + return try await mapTargetReference(buildableReference: buildableRef) + } else { + return nil + } + }() + + let environmentVariables = + action.environmentVariables?.reduce(into: [String: EnvironmentVariable]()) { dict, variable in + dict[variable.variable] = EnvironmentVariable( + value: variable.value, isEnabled: variable.enabled + ) + } ?? [:] + + let launchArguments = + action.commandlineArguments?.arguments.map { + LaunchArgument(name: $0.name, isEnabled: $0.enabled) + } ?? [] + + let arguments = Arguments( + environmentVariables: environmentVariables, + launchArguments: launchArguments + ) + let diagnosticsOptions = SchemeDiagnosticsOptions(action: action) + let attachDebugger = action.selectedDebuggerIdentifier.isEmpty + + return RunAction( + configurationName: action.buildConfiguration, + attachDebugger: attachDebugger, + customLLDBInitFile: nil, + preActions: [], + postActions: [], + executable: executable, + filePath: nil, + arguments: arguments, + options: RunActionOptions(), + diagnosticsOptions: diagnosticsOptions + ) + } + + public func mapArchiveAction(action: XCScheme.ArchiveAction?) async throws -> ArchiveAction? { + guard let action else { return nil } + + return ArchiveAction( + configurationName: action.buildConfiguration, + revealArchiveInOrganizer: action.revealArchiveInOrganizer + ) + } + + public func mapProfileAction(action: XCScheme.ProfileAction?) async throws -> ProfileAction? { + guard let action else { return nil } + + let executable: TargetReference? = try await { + if let buildableRef = action.buildableProductRunnable?.buildableReference { + return try await mapTargetReference(buildableReference: buildableRef) + } else { + return nil + } + }() + + return ProfileAction( + configurationName: action.buildConfiguration, + executable: executable + ) + } + + public func mapAnalyzeAction(action: XCScheme.AnalyzeAction?) async throws -> AnalyzeAction? { + guard let action else { return nil } + return AnalyzeAction(configurationName: action.buildConfiguration) + } + + /// Maps a `XCScheme.BuildableReference` to a `TargetReference`. + /// + /// This involves resolving the container path and the target name. + /// Depending on whether we're dealing with a workspace or a standalone project, + /// the logic may differ. + /// + /// - Parameter buildableReference: The `XCScheme.BuildableReference` to map. + /// - Returns: A `TargetReference` representing the target in the given container. + /// - Throws: If the referenced container cannot be resolved. + private func mapTargetReference(buildableReference: XCScheme.BuildableReference) async throws + -> TargetReference + { + let targetName = buildableReference.blueprintName + let container = buildableReference.referencedContainer + + let projectPath: AbsolutePath + switch graphType { + case let .workspace(workspaceProvider): + let containerRelativePath = container.replacingOccurrences(of: "container:", with: "") + let relativePath = try RelativePath(validating: containerRelativePath) + projectPath = workspaceProvider.workspaceDirectory.appending(relativePath) + case let .project(path): + projectPath = path + } + + return TargetReference( + projectPath: projectPath, + name: targetName + ) + } } diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift index 736d67ff..64d45825 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift @@ -6,12 +6,12 @@ import XcodeProj /// A type that maps a `PBXTarget` into a domain `Target` model, extracting platform, product, settings, sources, /// resources, scripts, dependencies, and other configuration details. protocol TargetMapping: Sendable { - /// Maps the given PBX target into a `Target` domain model. - /// - /// - Parameter pbxTarget: The `PBXTarget` to map. - /// - Returns: A fully mapped `Target` model. - /// - Throws: A `MappingError` if required information is missing or invalid. - func map(pbxTarget: PBXTarget) async throws -> Target + /// Maps the given PBX target into a `Target` domain model. + /// + /// - Parameter pbxTarget: The `PBXTarget` to map. + /// - Returns: A fully mapped `Target` model. + /// - Throws: A `MappingError` if required information is missing or invalid. + func map(pbxTarget: PBXTarget) async throws -> Target } /// A mapper that converts a `PBXTarget` into a domain `Target` model. @@ -25,256 +25,254 @@ protocol TargetMapping: Sendable { /// The resulting `Target` object contains comprehensive information needed for further graph operations /// such as code generation, analysis, or integration with other tooling. public final class TargetMapper: TargetMapping { - private let projectProvider: ProjectProviding - private let settingsMapper: SettingsMapping - private let buildPhaseMapper: BuildPhaseMapping - private let dependencyMapper: DependencyMapping - private let buildRuleMapper: BuildRuleMapper + private let projectProvider: ProjectProviding + private let settingsMapper: SettingsMapping + private let buildPhaseMapper: BuildPhaseMapping + private let dependencyMapper: DependencyMapping + private let buildRuleMapper: BuildRuleMapper - /// Creates a new `TargetMapper` instance. - /// - /// - Parameter projectProvider: Provides access to the project’s paths, `XcodeProj`, and related information. - public init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - self.settingsMapper = SettingsMapper() - self.buildPhaseMapper = BuildPhaseMapper(projectProvider: projectProvider) - self.dependencyMapper = DependencyMapper(projectProvider: projectProvider) - self.buildRuleMapper = BuildRuleMapper() - } + /// Creates a new `TargetMapper` instance. + /// + /// - Parameter projectProvider: Provides access to the project’s paths, `XcodeProj`, and related information. + public init(projectProvider: ProjectProviding) { + self.projectProvider = projectProvider + settingsMapper = SettingsMapper() + buildPhaseMapper = BuildPhaseMapper(projectProvider: projectProvider) + dependencyMapper = DependencyMapper(projectProvider: projectProvider) + buildRuleMapper = BuildRuleMapper() + } - public func map(pbxTarget: PBXTarget) async throws -> Target { - let platform = try pbxTarget.platform() - let deploymentTargets = try pbxTarget.deploymentTargets() - let product = pbxTarget.productType() + public func map(pbxTarget: PBXTarget) async throws -> Target { + let platform = try pbxTarget.platform() + let deploymentTargets = try pbxTarget.deploymentTargets() + let product = pbxTarget.productType() - let settings = try await settingsMapper.map( - projectProvider: projectProvider, - configurationList: pbxTarget.buildConfigurationList - ) - let sources = try await buildPhaseMapper.mapSources(target: pbxTarget) - let resources = try await buildPhaseMapper.mapResources(target: pbxTarget) - let headers = try await buildPhaseMapper.mapHeaders(target: pbxTarget) - let scripts = try await buildPhaseMapper.mapScripts(target: pbxTarget) - let copyFiles = try await buildPhaseMapper.mapCopyFiles(target: pbxTarget) - let coreDataModels = try await buildPhaseMapper.mapCoreDataModels(target: pbxTarget) - let rawScriptBuildPhases = try await buildPhaseMapper.mapRawScriptBuildPhases(target: pbxTarget) - let additionalFiles: [FileElement] = [] // Currently no extra files + let settings = try await settingsMapper.map( + projectProvider: projectProvider, + configurationList: pbxTarget.buildConfigurationList + ) + let sources = try await buildPhaseMapper.mapSources(target: pbxTarget) + let resources = try await buildPhaseMapper.mapResources(target: pbxTarget) + let headers = try await buildPhaseMapper.mapHeaders(target: pbxTarget) + let scripts = try await buildPhaseMapper.mapScripts(target: pbxTarget) + let copyFiles = try await buildPhaseMapper.mapCopyFiles(target: pbxTarget) + let coreDataModels = try await buildPhaseMapper.mapCoreDataModels(target: pbxTarget) + let rawScriptBuildPhases = try await buildPhaseMapper.mapRawScriptBuildPhases(target: pbxTarget) + let additionalFiles: [FileElement] = [] // Currently no extra files - let resourceFileElements = ResourceFileElements(resources) - let buildRules = try await buildRuleMapper.mapBuildRules(target: pbxTarget) + let resourceFileElements = ResourceFileElements(resources) + let buildRules = try await buildRuleMapper.mapBuildRules(target: pbxTarget) - let environmentVariables = pbxTarget.extractEnvironmentVariables() + let environmentVariables = pbxTarget.extractEnvironmentVariables() - let launchArguments = try extractLaunchArguments(from: pbxTarget) - let filesGroup = try extractFilesGroup(from: pbxTarget) - let playgrounds = try await extractPlaygrounds(from: pbxTarget) - let prune = try extractPrune(from: pbxTarget) - let mergedBinaryType = try extractMergedBinaryType(from: pbxTarget) - let mergeable = try extractMergeable(from: pbxTarget) - let onDemandResourcesTags = try extractOnDemandResourcesTags(from: pbxTarget) - let metadata = try extractMetadata(from: pbxTarget) + let launchArguments = try extractLaunchArguments(from: pbxTarget) + let filesGroup = try extractFilesGroup(from: pbxTarget) + let playgrounds = try await extractPlaygrounds(from: pbxTarget) + let prune = try extractPrune(from: pbxTarget) + let mergedBinaryType = try extractMergedBinaryType(from: pbxTarget) + let mergeable = try extractMergeable(from: pbxTarget) + let onDemandResourcesTags = try extractOnDemandResourcesTags(from: pbxTarget) + let metadata = try extractMetadata(from: pbxTarget) - let targetDependencies = try await dependencyMapper.mapDependencies(target: pbxTarget) - let frameworkDependencies = try await buildPhaseMapper.mapFrameworks(target: pbxTarget) - let allDependencies = targetDependencies + frameworkDependencies + let targetDependencies = try await dependencyMapper.mapDependencies(target: pbxTarget) + let frameworkDependencies = try await buildPhaseMapper.mapFrameworks(target: pbxTarget) + let allDependencies = targetDependencies + frameworkDependencies - return Target( - name: pbxTarget.name, - destinations: platform, - product: product, - productName: pbxTarget.productName ?? pbxTarget.name, - bundleId: try extractBundleIdentifier(from: pbxTarget), - deploymentTargets: deploymentTargets, - infoPlist: try extractInfoPlist(from: pbxTarget), - entitlements: try extractEntitlements(from: pbxTarget), - settings: settings, - sources: sources, - resources: resourceFileElements, - copyFiles: copyFiles, - headers: headers, - coreDataModels: coreDataModels, - scripts: scripts, - environmentVariables: environmentVariables, - launchArguments: launchArguments, - filesGroup: filesGroup, - dependencies: allDependencies.sorted { $0.name < $1.name }, - rawScriptBuildPhases: rawScriptBuildPhases, - playgrounds: playgrounds, - additionalFiles: additionalFiles, - buildRules: buildRules, - prune: prune, - mergedBinaryType: mergedBinaryType, - mergeable: mergeable, - onDemandResourcesTags: onDemandResourcesTags, - metadata: metadata - ) - } + return Target( + name: pbxTarget.name, + destinations: platform, + product: product, + productName: pbxTarget.productName ?? pbxTarget.name, + bundleId: try extractBundleIdentifier(from: pbxTarget), + deploymentTargets: deploymentTargets, + infoPlist: try extractInfoPlist(from: pbxTarget), + entitlements: try extractEntitlements(from: pbxTarget), + settings: settings, + sources: sources, + resources: resourceFileElements, + copyFiles: copyFiles, + headers: headers, + coreDataModels: coreDataModels, + scripts: scripts, + environmentVariables: environmentVariables, + launchArguments: launchArguments, + filesGroup: filesGroup, + dependencies: allDependencies.sorted { $0.name < $1.name }, + rawScriptBuildPhases: rawScriptBuildPhases, + playgrounds: playgrounds, + additionalFiles: additionalFiles, + buildRules: buildRules, + prune: prune, + mergedBinaryType: mergedBinaryType, + mergeable: mergeable, + onDemandResourcesTags: onDemandResourcesTags, + metadata: metadata + ) + } - // MARK: - Helper Methods + // MARK: - Helper Methods - private func extractBundleIdentifier(from target: PBXTarget) throws -> String { - if let bundleId = target.debugBuildSettings.string(for: .productBundleIdentifier) { - return bundleId + private func extractBundleIdentifier(from target: PBXTarget) throws -> String { + if let bundleId = target.debugBuildSettings.string(for: .productBundleIdentifier) { + return bundleId + } + throw MappingError.missingBundleIdentifier(targetName: target.name) } - throw MappingError.missingBundleIdentifier(targetName: target.name) - } - private func extractInfoPlist(from target: PBXTarget) throws -> InfoPlist { - if let plistPath = try target.infoPlistPath() { - let path = try resolvePath(plistPath) - let plistDictionary = try readPlistAsDictionary(at: path) - return .dictionary(plistDictionary) + private func extractInfoPlist(from target: PBXTarget) throws -> InfoPlist { + if let plistPath = try target.infoPlistPath() { + let path = try resolvePath(plistPath) + let plistDictionary = try readPlistAsDictionary(at: path) + return .dictionary(plistDictionary) + } + return .dictionary([:]) } - return .dictionary([:]) - } - private func readPlistAsDictionary(at path: AbsolutePath) throws -> [String: Plist.Value] { - let fileURL = URL(fileURLWithPath: path.pathString) - let data = try Data(contentsOf: fileURL) - var format = PropertyListSerialization.PropertyListFormat.xml - guard - let plist = try PropertyListSerialization.propertyList( - from: data, - options: .mutableContainersAndLeaves, - format: &format - ) as? [String: Any] - else { - // TODO: - Better Error Message - throw MappingError.generic("Failed to cast plist contents to a dictionary.") - } + private func readPlistAsDictionary(at path: AbsolutePath) throws -> [String: Plist.Value] { + let fileURL = URL(fileURLWithPath: path.pathString) + let data = try Data(contentsOf: fileURL) + var format = PropertyListSerialization.PropertyListFormat.xml + guard let plist = try PropertyListSerialization.propertyList( + from: data, + options: .mutableContainersAndLeaves, + format: &format + ) as? [String: Any] + else { + // TODO: - Better Error Message + throw MappingError.generic("Failed to cast plist contents to a dictionary.") + } - return try plist.reduce(into: [String: Plist.Value]()) { result, item in - result[item.key] = try convertToPlistValue(item.value) + return try plist.reduce(into: [String: Plist.Value]()) { result, item in + result[item.key] = try convertToPlistValue(item.value) + } } - } - private func convertToPlistValue(_ value: Any) throws -> Plist.Value { - switch value { - case let stringValue as String: - return .string(stringValue) - case let intValue as Int: - return .integer(intValue) - case let doubleValue as Double: - return .real(doubleValue) - case let boolValue as Bool: - return .boolean(boolValue) - case let arrayValue as [Any]: - let convertedArray = try arrayValue.map { try convertToPlistValue($0) } - return .array(convertedArray) - case let dictValue as [String: Any]: - let convertedDict = try dictValue.reduce(into: [String: Plist.Value]()) { - dictResult, dictItem in - dictResult[dictItem.key] = try convertToPlistValue(dictItem.value) - } - return .dictionary(convertedDict) - default: - return .string(String(describing: value)) + private func convertToPlistValue(_ value: Any) throws -> Plist.Value { + switch value { + case let stringValue as String: + return .string(stringValue) + case let intValue as Int: + return .integer(intValue) + case let doubleValue as Double: + return .real(doubleValue) + case let boolValue as Bool: + return .boolean(boolValue) + case let arrayValue as [Any]: + let convertedArray = try arrayValue.map { try convertToPlistValue($0) } + return .array(convertedArray) + case let dictValue as [String: Any]: + let convertedDict = try dictValue.reduce(into: [String: Plist.Value]()) { + dictResult, dictItem in + dictResult[dictItem.key] = try convertToPlistValue(dictItem.value) + } + return .dictionary(convertedDict) + default: + return .string(String(describing: value)) + } } - } - private func extractEntitlements(from target: PBXTarget) throws -> Entitlements? { - if let entitlementsPath = try target.entitlementsPath() { - let resolvedPath = try resolvePath(entitlementsPath) - return Entitlements.file(path: resolvedPath) + private func extractEntitlements(from target: PBXTarget) throws -> Entitlements? { + if let entitlementsPath = try target.entitlementsPath() { + let resolvedPath = try resolvePath(entitlementsPath) + return Entitlements.file(path: resolvedPath) + } + return nil } - return nil - } - private func resolvePath(_ pathString: String) throws -> AbsolutePath { - let processedPath: String - if pathString.hasPrefix("$(SRCROOT)/") { - let relative = String(pathString.dropFirst("$(SRCROOT)/".count)) - processedPath = relative - } else if pathString == "$(SRCROOT)" { - processedPath = "" - } else { - processedPath = pathString + private func resolvePath(_ pathString: String) throws -> AbsolutePath { + let processedPath: String + if pathString.hasPrefix("$(SRCROOT)/") { + let relative = String(pathString.dropFirst("$(SRCROOT)/".count)) + processedPath = relative + } else if pathString == "$(SRCROOT)" { + processedPath = "" + } else { + processedPath = pathString + } + return projectProvider.sourceDirectory.appending(try RelativePath(validating: processedPath)) } - return projectProvider.sourceDirectory.appending(try RelativePath(validating: processedPath)) - } - private func extractLaunchArguments(from target: PBXTarget) throws -> [LaunchArgument] { - guard let buildConfigList = target.buildConfigurationList else { return [] } - var launchArguments: [LaunchArgument] = [] - for buildConfig in buildConfigList.buildConfigurations { - if let args = buildConfig.buildSettings.stringArray(for: .launchArguments) { - launchArguments.append(contentsOf: args.map { LaunchArgument(name: $0, isEnabled: true) }) - } + private func extractLaunchArguments(from target: PBXTarget) throws -> [LaunchArgument] { + guard let buildConfigList = target.buildConfigurationList else { return [] } + var launchArguments: [LaunchArgument] = [] + for buildConfig in buildConfigList.buildConfigurations { + if let args = buildConfig.buildSettings.stringArray(for: .launchArguments) { + launchArguments.append(contentsOf: args.map { LaunchArgument(name: $0, isEnabled: true) }) + } + } + return launchArguments.uniqued() } - return launchArguments.uniqued() - } - private func extractFilesGroup(from target: PBXTarget) throws -> ProjectGroup { - guard let mainGroup = try projectProvider.pbxProject().mainGroup else { - throw MappingError.missingFilesGroup(targetName: target.name) + private func extractFilesGroup(from target: PBXTarget) throws -> ProjectGroup { + guard let mainGroup = try projectProvider.pbxProject().mainGroup else { + throw MappingError.missingFilesGroup(targetName: target.name) + } + return ProjectGroup.group(name: mainGroup.name ?? "MainGroup") } - return ProjectGroup.group(name: mainGroup.name ?? "MainGroup") - } - private func extractPlaygrounds(from target: PBXTarget) async throws -> [AbsolutePath] { - let sourceFiles = try await buildPhaseMapper.mapSources(target: target) - return sourceFiles.filter { $0.path.fileExtension == .playground }.map { $0.path } - } + private func extractPlaygrounds(from target: PBXTarget) async throws -> [AbsolutePath] { + let sourceFiles = try await buildPhaseMapper.mapSources(target: target) + return sourceFiles.filter { $0.path.fileExtension == .playground }.map(\.path) + } - private func extractPrune(from target: PBXTarget) throws -> Bool { - target.debugBuildSettings.bool(for: .prune) ?? false - } + private func extractPrune(from target: PBXTarget) throws -> Bool { + target.debugBuildSettings.bool(for: .prune) ?? false + } - private func extractMergedBinaryType(from target: PBXTarget) throws -> MergedBinaryType { - let mergedBinaryTypeString = target.debugBuildSettings.string(for: .mergedBinaryType) - return mergedBinaryTypeString == "automatic" ? .automatic : .disabled - } + private func extractMergedBinaryType(from target: PBXTarget) throws -> MergedBinaryType { + let mergedBinaryTypeString = target.debugBuildSettings.string(for: .mergedBinaryType) + return mergedBinaryTypeString == "automatic" ? .automatic : .disabled + } - private func extractMergeable(from target: PBXTarget) throws -> Bool { - target.debugBuildSettings.bool(for: .mergeable) ?? false - } + private func extractMergeable(from target: PBXTarget) throws -> Bool { + target.debugBuildSettings.bool(for: .mergeable) ?? false + } - private func extractOnDemandResourcesTags(from target: PBXTarget) throws -> OnDemandResourcesTags? - { - // TODO: - implement if needed - return nil - } + private func extractOnDemandResourcesTags(from _: PBXTarget) throws -> OnDemandResourcesTags? { + // TODO: - implement if needed + return nil + } - private func extractMetadata(from target: PBXTarget) throws -> TargetMetadata { - var tags: Set = [] - for buildConfig in target.buildConfigurationList?.buildConfigurations ?? [] { - if let tagsString = buildConfig.buildSettings.string(for: .tags) { - let extractedTags = tagsString.split(separator: ",").map { - $0.trimmingCharacters(in: .whitespaces) + private func extractMetadata(from target: PBXTarget) throws -> TargetMetadata { + var tags: Set = [] + for buildConfig in target.buildConfigurationList?.buildConfigurations ?? [] { + if let tagsString = buildConfig.buildSettings.string(for: .tags) { + let extractedTags = tagsString.split(separator: ",").map { + $0.trimmingCharacters(in: .whitespaces) + } + tags.formUnion(extractedTags) + } } - tags.formUnion(extractedTags) - } + return TargetMetadata(tags: tags) } - return TargetMetadata(tags: tags) - } } extension PBXTarget { - struct EnvironmentExtractor { - static func extract(from buildSettings: BuildSettings) -> [String: EnvironmentVariable] { - guard let envVars = buildSettings.stringDict(for: .environmentVariables) else { - return [:] - } - return envVars.reduce(into: [:]) { result, pair in - result[pair.key] = EnvironmentVariable(value: pair.value, isEnabled: true) - } + enum EnvironmentExtractor { + static func extract(from buildSettings: BuildSettings) -> [String: EnvironmentVariable] { + guard let envVars = buildSettings.stringDict(for: .environmentVariables) else { + return [:] + } + return envVars.reduce(into: [:]) { result, pair in + result[pair.key] = EnvironmentVariable(value: pair.value, isEnabled: true) + } + } } - } - /// Extracts environment variables from all build configurations of the target. - /// - /// If multiple configurations define environment variables with the same name, the last one processed - /// takes precedence. - public func extractEnvironmentVariables() -> [String: EnvironmentVariable] { - buildConfigurationList?.buildConfigurations.reduce(into: [:]) { result, config in - result.merge(EnvironmentExtractor.extract(from: config.buildSettings)) { current, _ in current - } - } ?? [:] - } + /// Extracts environment variables from all build configurations of the target. + /// + /// If multiple configurations define environment variables with the same name, the last one processed + /// takes precedence. + public func extractEnvironmentVariables() -> [String: EnvironmentVariable] { + buildConfigurationList?.buildConfigurations.reduce(into: [:]) { result, config in + result.merge(EnvironmentExtractor.extract(from: config.buildSettings)) { current, _ in current + } + } ?? [:] + } - /// Returns the build settings from the "Debug" build configuration, or an empty dictionary if not present. - var debugBuildSettings: [String: Any] { - buildConfigurationList?.buildConfigurations.first(where: { $0.name == "Debug" })?.buildSettings - ?? [:] - } + /// Returns the build settings from the "Debug" build configuration, or an empty dictionary if not present. + var debugBuildSettings: [String: Any] { + buildConfigurationList?.buildConfigurations.first(where: { $0.name == "Debug" })?.buildSettings + ?? [:] + } } diff --git a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift index 79542843..1c911360 100644 --- a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift @@ -6,11 +6,11 @@ import XcodeProj /// A type that maps an `.xcworkspace` structure into a `Workspace` model. protocol WorkspaceMapping: Sendable { - /// Maps the current workspace into a `Workspace` model. - /// - /// - Returns: A `Workspace` instance representing the mapped workspace. - /// - Throws: If any portion of the mapping process fails. - func map() async throws -> Workspace + /// Maps the current workspace into a `Workspace` model. + /// + /// - Returns: A `Workspace` instance representing the mapped workspace. + /// - Throws: If any portion of the mapping process fails. + func map() async throws -> Workspace } /// A mapper that translates a provided workspace into a `Workspace` model. @@ -19,110 +19,110 @@ protocol WorkspaceMapping: Sendable { /// additional files. The resulting `Workspace` can then be used as an input to other processes, /// such as code generation, analysis, or further transformations. public final class WorkspaceMapper: WorkspaceMapping { - private let workspaceProvider: WorkspaceProviding + private let workspaceProvider: WorkspaceProviding - /// Creates a new `WorkspaceMapper`. - /// - /// - Parameter workspaceProvider: A provider capable of supplying a parsed `XCWorkspace` and its file paths. - public init(workspaceProvider: WorkspaceProviding) { - self.workspaceProvider = workspaceProvider - } + /// Creates a new `WorkspaceMapper`. + /// + /// - Parameter workspaceProvider: A provider capable of supplying a parsed `XCWorkspace` and its file paths. + public init(workspaceProvider: WorkspaceProviding) { + self.workspaceProvider = workspaceProvider + } - /// Maps the current workspace into a `Workspace` model. - /// - /// This method identifies all `.xcodeproj` files in the workspace, maps any detected schemes, - /// and constructs a fully-populated `Workspace` instance. It sets default generation options, - /// and includes hooks for adding additional files or IDE template macros if needed. - /// - /// - Returns: A fully constructed `Workspace` instance. - /// - Throws: If extracting projects or mapping schemes fails. - public func map() async throws -> Workspace { - let xcworkspace = workspaceProvider.xcworkspace - let xcWorkspacePath = workspaceProvider.xcWorkspacePath - let srcPath = workspaceProvider.workspaceDirectory - let projectPaths = try extractProjectPaths(from: xcworkspace.data.children, srcPath: srcPath) - let projectAbsolutePaths = projectPaths.map { $0 } + /// Maps the current workspace into a `Workspace` model. + /// + /// This method identifies all `.xcodeproj` files in the workspace, maps any detected schemes, + /// and constructs a fully-populated `Workspace` instance. It sets default generation options, + /// and includes hooks for adding additional files or IDE template macros if needed. + /// + /// - Returns: A fully constructed `Workspace` instance. + /// - Throws: If extracting projects or mapping schemes fails. + public func map() async throws -> Workspace { + let xcworkspace = workspaceProvider.xcworkspace + let xcWorkspacePath = workspaceProvider.xcWorkspacePath + let srcPath = workspaceProvider.workspaceDirectory + let projectPaths = try extractProjectPaths(from: xcworkspace.data.children, srcPath: srcPath) + let projectAbsolutePaths = projectPaths.map { $0 } - let workspaceName = xcWorkspacePath.basenameWithoutExt - let schemes = try await mapSchemes(from: srcPath) + let workspaceName = xcWorkspacePath.basenameWithoutExt + let schemes = try await mapSchemes(from: srcPath) - let ideTemplateMacros: IDETemplateMacros? = nil - let additionalFiles: [FileElement] = [] - let generationOptions = Workspace.GenerationOptions( - enableAutomaticXcodeSchemes: nil, - autogeneratedWorkspaceSchemes: .disabled, - lastXcodeUpgradeCheck: nil, - renderMarkdownReadme: false - ) + let ideTemplateMacros: IDETemplateMacros? = nil + let additionalFiles: [FileElement] = [] + let generationOptions = Workspace.GenerationOptions( + enableAutomaticXcodeSchemes: nil, + autogeneratedWorkspaceSchemes: .disabled, + lastXcodeUpgradeCheck: nil, + renderMarkdownReadme: false + ) - return Workspace( - path: srcPath, - xcWorkspacePath: xcWorkspacePath, - name: workspaceName, - projects: projectAbsolutePaths, - schemes: schemes, - generationOptions: generationOptions, - ideTemplateMacros: ideTemplateMacros, - additionalFiles: additionalFiles - ) - } + return Workspace( + path: srcPath, + xcWorkspacePath: xcWorkspacePath, + name: workspaceName, + projects: projectAbsolutePaths, + schemes: schemes, + generationOptions: generationOptions, + ideTemplateMacros: ideTemplateMacros, + additionalFiles: additionalFiles + ) + } - /// Recursively extracts all `.xcodeproj` paths from the workspace’s file and group references. - /// - /// - Parameters: - /// - elements: The array of `XCWorkspaceDataElement` representing files or groups in the workspace. - /// - srcPath: The source directory path used as a base for resolving relative references. - /// - Returns: An array of absolute paths to `.xcodeproj` directories. - /// - Throws: If resolving any referenced path fails. - private func extractProjectPaths(from elements: [XCWorkspaceDataElement], srcPath: AbsolutePath) - throws -> [AbsolutePath] - { - var paths = [AbsolutePath]() + /// Recursively extracts all `.xcodeproj` paths from the workspace’s file and group references. + /// + /// - Parameters: + /// - elements: The array of `XCWorkspaceDataElement` representing files or groups in the workspace. + /// - srcPath: The source directory path used as a base for resolving relative references. + /// - Returns: An array of absolute paths to `.xcodeproj` directories. + /// - Throws: If resolving any referenced path fails. + private func extractProjectPaths(from elements: [XCWorkspaceDataElement], srcPath: AbsolutePath) + throws -> [AbsolutePath] + { + var paths = [AbsolutePath]() - for element in elements { - switch element { - case .file(let ref): - let refPath = Path(ref.location.path) - if refPath.extension?.lowercased() == "xcodeproj" { - do { - let absPath = try ref.absolutePath(srcPath: srcPath) - paths.append(absPath) - } catch { - print("⚠️ Could not resolve absolute path for \(ref.location.path): \(error)") - } + for element in elements { + switch element { + case let .file(ref): + let refPath = Path(ref.location.path) + if refPath.extension?.lowercased() == "xcodeproj" { + do { + let absPath = try ref.absolutePath(srcPath: srcPath) + paths.append(absPath) + } catch { + print("⚠️ Could not resolve absolute path for \(ref.location.path): \(error)") + } + } + case let .group(group): + let groupPaths = try extractProjectPaths( + from: group.children, + srcPath: srcPath.appending(component: group.location.path) + ) + paths.append(contentsOf: groupPaths) + } } - case .group(let group): - let groupPaths = try extractProjectPaths( - from: group.children, - srcPath: srcPath.appending(component: group.location.path) - ) - paths.append(contentsOf: groupPaths) - } + + return paths } - return paths - } + /// Maps all shared schemes found within the workspace. + /// + /// - Parameter srcPath: The source path of the workspace. + /// - Returns: An array of mapped `Scheme` instances. + /// - Throws: If reading or mapping any of the schemes fails. + private func mapSchemes(from srcPath: AbsolutePath) async throws -> [Scheme] { + var schemes = [Scheme]() + let sharedDataPath = Path(srcPath.pathString) + "xcshareddata/xcschemes" - /// Maps all shared schemes found within the workspace. - /// - /// - Parameter srcPath: The source path of the workspace. - /// - Returns: An array of mapped `Scheme` instances. - /// - Throws: If reading or mapping any of the schemes fails. - private func mapSchemes(from srcPath: AbsolutePath) async throws -> [Scheme] { - var schemes = [Scheme]() - let sharedDataPath = Path(srcPath.pathString) + "xcshareddata/xcschemes" + if sharedDataPath.exists { + let schemePaths = try sharedDataPath.children().filter { $0.extension == "xcscheme" } - if sharedDataPath.exists { - let schemePaths = try sharedDataPath.children().filter { $0.extension == "xcscheme" } + for schemePath in schemePaths { + let xcscheme = try XCScheme(path: schemePath) + let schemeMapper = try SchemeMapper(graphType: .workspace(workspaceProvider)) + let scheme = try await schemeMapper.mapScheme(xcscheme: xcscheme, shared: true) + schemes.append(scheme) + } + } - for schemePath in schemePaths { - let xcscheme = try XCScheme(path: schemePath) - let schemeMapper = try SchemeMapper(graphType: .workspace(workspaceProvider)) - let scheme = try await schemeMapper.mapScheme(xcscheme: xcscheme, shared: true) - schemes.append(scheme) - } + return schemes } - - return schemes - } } diff --git a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift index 026fd74e..408a4c07 100644 --- a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift +++ b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift @@ -6,27 +6,27 @@ import XcodeProj /// A type that provides access to a workspace and its underlying `.xcworkspace` file. public protocol WorkspaceProviding: Sendable { - /// The absolute path to the workspace file. - var workspaceDirectory: AbsolutePath { get } + /// The absolute path to the workspace file. + var workspaceDirectory: AbsolutePath { get } var xcWorkspacePath: AbsolutePath { get } - /// The parsed `XCWorkspace` instance representing the workspace. - var xcworkspace: XCWorkspace { get } + /// The parsed `XCWorkspace` instance representing the workspace. + var xcworkspace: XCWorkspace { get } } /// A concrete provider for workspaces, offering access to the `.xcworkspace` file and its parsed representation. public struct WorkspaceProvider: WorkspaceProviding { - public let workspaceDirectory: AbsolutePath -public let xcWorkspacePath: AbsolutePath - public let xcworkspace: XCWorkspace + public let workspaceDirectory: AbsolutePath + public let xcWorkspacePath: AbsolutePath + public let xcworkspace: XCWorkspace - /// Initializes a `WorkspaceProvider` with a given workspace path. - /// - /// - Parameter workspacePath: The absolute path to the `.xcworkspace` file. - /// - Throws: If the `.xcworkspace` file cannot be loaded or parsed. - public init(xcWorkspacePath: AbsolutePath) throws { - self.xcWorkspacePath = xcWorkspacePath - self.workspaceDirectory = xcWorkspacePath.parentDirectory - self.xcworkspace = try XCWorkspace(path: Path(xcWorkspacePath.pathString)) - } + /// Initializes a `WorkspaceProvider` with a given workspace path. + /// + /// - Parameter workspacePath: The absolute path to the `.xcworkspace` file. + /// - Throws: If the `.xcworkspace` file cannot be loaded or parsed. + public init(xcWorkspacePath: AbsolutePath) throws { + self.xcWorkspacePath = xcWorkspacePath + workspaceDirectory = xcWorkspacePath.parentDirectory + xcworkspace = try XCWorkspace(path: Path(xcWorkspacePath.pathString)) + } } diff --git a/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift b/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift index 3484b683..2c3fb416 100644 --- a/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift +++ b/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift @@ -26,9 +26,9 @@ public enum Executable: Sendable { /// - Returns: A `String` representing the absolute path to the executable. public var path: String { switch self { - case .lipo(_, _, let path): + case let .lipo(_, _, path): return path - case .custom(let executablePath, _, _): + case let .custom(executablePath, _, _): return executablePath } } @@ -38,9 +38,9 @@ public enum Executable: Sendable { /// - Returns: An array of `String` arguments. public var arguments: [String] { switch self { - case .lipo(let lipoArgs, _, _): + case let .lipo(lipoArgs, _, _): return lipoArgs.toArguments() - case .custom(_, let args, _): + case let .custom(_, args, _): return args } } @@ -50,9 +50,9 @@ public enum Executable: Sendable { /// - Returns: A closure that takes a `ProcessResult` and returns an `Output` value or throws an error. public var parser: (ProcessResult) throws -> Output { switch self { - case .lipo(_, let parser, _): + case let .lipo(_, parser, _): return parser - case .custom(_, _, let parser): + case let .custom(_, _, parser): return parser } } diff --git a/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoTool.swift b/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoTool.swift index ea490061..e8e2315d 100644 --- a/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoTool.swift +++ b/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoTool.swift @@ -4,7 +4,7 @@ import Foundation /// /// `LipoTool` provides a high-level interface for running `lipo -archs` on given paths /// to determine which architectures a binary contains. -public final class LipoTool { +public enum LipoTool { /// Runs `lipo -archs` on the given paths and returns a `LipoArchsResult`. /// /// This method asynchronously executes `lipo -archs` using `ProcessRunner.run`, diff --git a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift index ffd57376..fa0113ec 100644 --- a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift +++ b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift @@ -1,6 +1,6 @@ import Foundation -public final class ProcessRunner { +public enum ProcessRunner { /// Runs the given executable asynchronously and processes its result using the associated parser. /// /// - Parameters: @@ -43,9 +43,8 @@ public final class ProcessRunner { let stdoutData = stdoutPipe.fileHandleForReading.readDataToEndOfFile() let stderrData = stderrPipe.fileHandleForReading.readDataToEndOfFile() - guard - let stdoutString = String(data: stdoutData, encoding: .utf8), - let stderrString = String(data: stderrData, encoding: .utf8) + guard let stdoutString = String(data: stdoutData, encoding: .utf8), + let stderrString = String(data: stderrData, encoding: .utf8) else { continuation.resume(throwing: ProcessRunnerError.invalidUTF8InOutput) return @@ -54,7 +53,7 @@ public final class ProcessRunner { let exitCode = process.terminationStatus let result = ProcessResult(exitCode: exitCode, stdout: stdoutString, stderr: stderrString) - if throwOnNonZeroExit && !result.succeeded { + if throwOnNonZeroExit, !result.succeeded { continuation.resume(throwing: ProcessRunnerError.nonZeroExitCode(exitCode, result.stderr)) return } diff --git a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift index ec9403c1..7262ee8a 100644 --- a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift +++ b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift @@ -1,21 +1,21 @@ import Foundation public enum ProcessRunnerError: Error, LocalizedError, Equatable { - case executableNotFound(String) - case failedToRunProcess(String) - case invalidUTF8InOutput - case nonZeroExitCode(Int32, String) + case executableNotFound(String) + case failedToRunProcess(String) + case invalidUTF8InOutput + case nonZeroExitCode(Int32, String) - public var errorDescription: String? { - switch self { - case .executableNotFound(let cmd): - return "The executable '\(cmd)' was not found or is not executable." - case .failedToRunProcess(let reason): - return "Failed to run process: \(reason)" - case .invalidUTF8InOutput: - return "Could not decode output as UTF-8." - case let .nonZeroExitCode(code, stderr): - return "Command exited with code \(code). Stderr: \(stderr)" + public var errorDescription: String? { + switch self { + case let .executableNotFound(cmd): + return "The executable '\(cmd)' was not found or is not executable." + case let .failedToRunProcess(reason): + return "Failed to run process: \(reason)" + case .invalidUTF8InOutput: + return "Could not decode output as UTF-8." + case let .nonZeroExitCode(code, stderr): + return "Command exited with code \(code). Stderr: \(stderr)" + } } - } } diff --git a/Tests/XcodeGraphTests/Models/TargetTests.swift b/Tests/XcodeGraphTests/Models/TargetTests.swift index b0013c02..ebbe0927 100644 --- a/Tests/XcodeGraphTests/Models/TargetTests.swift +++ b/Tests/XcodeGraphTests/Models/TargetTests.swift @@ -16,7 +16,7 @@ final class TargetTests: XCTestCase { XCTAssertEqual( Target.validSourceExtensions, [ - "m", "swift", "mm", "cpp", "c++", "cc", "c", "d", "s", "intentdefinition", "metal", "mlmodel" + "m", "swift", "mm", "cpp", "c++", "cc", "c", "d", "s", "intentdefinition", "metal", "mlmodel", ] ) } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/IntegrationTests.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/IntegrationTests.swift index 826862bf..2178d2e0 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/IntegrationTests.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/IntegrationTests.swift @@ -1,11 +1,11 @@ import Foundation import InlineSnapshotTesting import Path +import RegexBuilder import Testing import XcodeGraph -import XcodeProjToGraph import XcodeProj -import RegexBuilder +import XcodeProjToGraph @testable import TestSupport @@ -44,7 +44,6 @@ struct IntegrationTests { line: UInt = #line, column: UInt = #column ) async throws { - let path = try fixture().absolutePath() let fullGraph: XcodeGraph.Graph = try await ProjectParser.parse(atPath: path.pathString) @@ -166,33 +165,33 @@ extension XcodeGraph.Graph { } func minimizeGraph() -> Graph { - var graph = self - graph.workspace.schemes = [] - graph.workspace.generationOptions = .test() - - for (key, project) in graph.projects { - graph.projects[key]?.schemes = [] - graph.projects[key]?.resourceSynthesizers = [] - graph.projects[key]?.settings = Settings(configurations: [:]) - - for targetKey in project.targets.keys { - graph.projects[key]?.targets[targetKey]?.scripts = [] - graph.projects[key]?.targets[targetKey]?.playgrounds = [] - graph.projects[key]?.targets[targetKey]?.rawScriptBuildPhases = [] - graph.projects[key]?.targets[targetKey]?.playgrounds = [] - graph.projects[key]?.targets[targetKey]?.buildRules = [] - graph.projects[key]?.targets[targetKey]?.settings = nil - graph.projects[key]?.targets[targetKey]?.infoPlist = nil - graph.projects[key]?.targets[targetKey]?.destinations = [] - } + var graph = self + graph.workspace.schemes = [] + graph.workspace.generationOptions = .test() + + for (key, project) in graph.projects { + graph.projects[key]?.schemes = [] + graph.projects[key]?.resourceSynthesizers = [] + graph.projects[key]?.settings = Settings(configurations: [:]) + + for targetKey in project.targets.keys { + graph.projects[key]?.targets[targetKey]?.scripts = [] + graph.projects[key]?.targets[targetKey]?.playgrounds = [] + graph.projects[key]?.targets[targetKey]?.rawScriptBuildPhases = [] + graph.projects[key]?.targets[targetKey]?.playgrounds = [] + graph.projects[key]?.targets[targetKey]?.buildRules = [] + graph.projects[key]?.targets[targetKey]?.settings = nil + graph.projects[key]?.targets[targetKey]?.infoPlist = nil + graph.projects[key]?.targets[targetKey]?.destinations = [] } + } - return graph + return graph } } extension AbsolutePath: @retroactive AnySnapshotStringConvertible { - public var snapshotDescription: String { - return self.pathString - } + public var snapshotDescription: String { + return pathString + } } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift index 505e6820..8d1c1ea4 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift @@ -3,231 +3,231 @@ import InlineSnapshotTesting import Path import Testing import XcodeGraph -import XcodeProjToGraph import XcodeProj +import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test - func commandLineToolWithDynamicFramework() async throws { - try await assertGraph { - .commandLineToolWithDynamicFramework - } name: { - """ - - "CommandLineTool" + @Test + func commandLineToolWithDynamicFramework() async throws { + try await assertGraph { + .commandLineToolWithDynamicFramework + } name: { + """ + - "CommandLineTool" - """ - }dependencies: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - ▿ key: target 'CommandLineTool' - ▿ target: (3 elements) - - name: "CommandLineTool" - - path: /Fixtures/command_line_tool_with_dynamic_framework - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'DynamicFramework' - ▿ target: (3 elements) - - name: "DynamicFramework" - - path: /Fixtures/command_line_tool_with_dynamic_framework - - status: LinkingStatus.required + """ + } dependencies: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: target 'CommandLineTool' + ▿ target: (3 elements) + - name: "CommandLineTool" + - path: /Fixtures/command_line_tool_with_dynamic_framework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'DynamicFramework' + ▿ target: (3 elements) + - name: "DynamicFramework" + - path: /Fixtures/command_line_tool_with_dynamic_framework + - status: LinkingStatus.required - """ - }dependencyConditions: { - """ - - 0 key/value pairs + """ + } dependencyConditions: { + """ + - 0 key/value pairs - """ - }packages: { - """ - - 0 key/value pairs + """ + } packages: { + """ + - 0 key/value pairs - """ - }workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "CommandLineTool" - - path: /Fixtures/command_line_tool_with_dynamic_framework - ▿ projects: 1 element - - /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcworkspace + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "CommandLineTool" + - path: /Fixtures/command_line_tool_with_dynamic_framework + ▿ projects: 1 element + - /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcworkspace - """ - }projects: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcodeproj - ▿ value: CommandLineTool - - path: /Fixtures/command_line_tool_with_dynamic_framework - - sourceRootPath: /Fixtures/command_line_tool_with_dynamic_framework - - xcodeProjPath: /Fixtures/command_line_tool_with_dynamic_framework - - name: "CommandLineTool" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs + """ + } projects: { + """ + ▿ 1 key/value pair ▿ (2 elements) - - key: "CommandLineTool" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "com.example.commandlinetool" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcodeproj + ▿ value: CommandLineTool + - path: /Fixtures/command_line_tool_with_dynamic_framework + - sourceRootPath: /Fixtures/command_line_tool_with_dynamic_framework + - xcodeProjPath: /Fixtures/command_line_tool_with_dynamic_framework + - name: "CommandLineTool" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "CommandLineTool" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "com.example.commandlinetool" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "DynamicFramework" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "CommandLineTool" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: command line tool + - productName: "CommandLineTool" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift + ▿ (2 elements) + - key: "DynamicFramework" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "com.example.dynamicframework" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "DynamicFramework" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "DynamicFramework" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "CommandLineTool" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: command line tool - - productName: "CommandLineTool" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift - ▿ (2 elements) - - key: "DynamicFramework" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "com.example.dynamicframework" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "DynamicFramework" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "DynamicFramework" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project - """ + """ + } } - } } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift index ecaff656..ff3da7c4 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift @@ -3,18 +3,18 @@ import InlineSnapshotTesting import Path import Testing import XcodeGraph -import XcodeProjToGraph import XcodeProj +import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test - func iosAppLarge() async throws { - let path = try WorkspaceFixture.iosAppLarge.absolutePath() + @Test + func iosAppLarge() async throws { + let path = try WorkspaceFixture.iosAppLarge.absolutePath() - let graph: XcodeGraph.Graph = try await ProjectParser.parse(projectType: .workspace(path)) + let graph: XcodeGraph.Graph = try await ProjectParser.parse(projectType: .workspace(path)) - #expect(graph.projects.first?.value.targets.count == 300) - } + #expect(graph.projects.first?.value.targets.count == 300) + } } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift index 3d0a2b71..61439aea 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift @@ -3,756 +3,755 @@ import InlineSnapshotTesting import Path import Testing import XcodeGraph -import XcodeProjToGraph import XcodeProj - +import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test + @Test func iosAppWithExtensions() async throws { try await assertGraph { .iosAppWithExtensions } name: { - """ - - "App" + """ + - "App" - """ + """ } dependencies: { - """ - ▿ 3 key/value pairs - ▿ (2 elements) - ▿ key: target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ value: 4 members - ▿ target 'AppIntentExtension' + """ + ▿ 3 key/value pairs + ▿ (2 elements) + ▿ key: target 'App' ▿ target: (3 elements) - - name: "AppIntentExtension" + - name: "App" - path: /Fixtures/ios_app_with_extensions - status: LinkingStatus.required - ▿ target 'NotificationServiceExtension' - ▿ target: (3 elements) - - name: "NotificationServiceExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ target 'StickersPackExtension' + ▿ value: 4 members + ▿ target 'AppIntentExtension' + ▿ target: (3 elements) + - name: "AppIntentExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'NotificationServiceExtension' + ▿ target: (3 elements) + - name: "NotificationServiceExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'StickersPackExtension' + ▿ target: (3 elements) + - name: "StickersPackExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'WidgetExtension' + ▿ target: (3 elements) + - name: "WidgetExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'AppWithMessagesExtension' ▿ target: (3 elements) - - name: "StickersPackExtension" + - name: "AppWithMessagesExtension" - path: /Fixtures/ios_app_with_extensions - status: LinkingStatus.required - ▿ target 'WidgetExtension' + ▿ value: 2 members + ▿ target 'MessageExtension' + ▿ target: (3 elements) + - name: "MessageExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'NotificationServiceExtension' + ▿ target: (3 elements) + - name: "NotificationServiceExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'WidgetExtension' ▿ target: (3 elements) - name: "WidgetExtension" - path: /Fixtures/ios_app_with_extensions - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'AppWithMessagesExtension' - ▿ target: (3 elements) - - name: "AppWithMessagesExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ value: 2 members - ▿ target 'MessageExtension' - ▿ target: (3 elements) - - name: "MessageExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ target 'NotificationServiceExtension' - ▿ target: (3 elements) - - name: "NotificationServiceExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'WidgetExtension' - ▿ target: (3 elements) - - name: "WidgetExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ value: 2 members - ▿ target 'Bundle' - ▿ target: (3 elements) - - name: "Bundle" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ target 'StaticFramework' - ▿ target: (3 elements) - - name: "StaticFramework" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required + ▿ value: 2 members + ▿ target 'Bundle' + ▿ target: (3 elements) + - name: "Bundle" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'StaticFramework' + ▿ target: (3 elements) + - name: "StaticFramework" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required - """ - }dependencyConditions: { - """ - - 0 key/value pairs + """ + } dependencyConditions: { + """ + - 0 key/value pairs - """ + """ } packages: { - """ - - 0 key/value pairs + """ + - 0 key/value pairs - """ + """ } workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "App" - - path: /Fixtures/ios_app_with_extensions - ▿ projects: 1 element - - /Fixtures/ios_app_with_extensions/App.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_app_with_extensions/App.xcworkspace + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "App" + - path: /Fixtures/ios_app_with_extensions + ▿ projects: 1 element + - /Fixtures/ios_app_with_extensions/App.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_extensions/App.xcworkspace - """ - }projects: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/ios_app_with_extensions/App.xcodeproj - ▿ value: App - - path: /Fixtures/ios_app_with_extensions - - sourceRootPath: /Fixtures/ios_app_with_extensions - - xcodeProjPath: /Fixtures/ios_app_with_extensions - - name: "App" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 9 key/value pairs - ▿ (2 elements) - - key: "App" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App" - ▿ copyFiles: 3 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Embed ExtensionKit Extensions" - ▿ subpath: Optional - - some: "$(EXTENSIONS_FOLDER_PATH)" - ▿ CopyFilesAction - - destination: Destination.plugins - - files: 0 elements - - name: "Embed Foundation Extensions" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 4 elements - ▿ TargetDependency - ▿ target: (3 elements) - - name: "AppIntentExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "NotificationServiceExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "StickersPackExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "WidgetExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 2 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc - ▿ (2 elements) - - key: "AppIntentExtension" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App.AppIntentExtension" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppIntentExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: extensionKit extension - - productName: "AppIntentExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 2 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift - ▿ (2 elements) - - key: "AppWithMessagesExtension" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App2" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.plugins - - files: 0 elements - - name: "Embed Foundation Extensions" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 2 elements - ▿ TargetDependency - ▿ target: (3 elements) - - name: "MessageExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "NotificationServiceExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppWithMessagesExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "AppWithMessagesExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 2 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc - ▿ (2 elements) - - key: "Bundle" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App.Bundle" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Bundle" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: bundle - - productName: "Bundle" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 1 element - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - - sources: 0 elements - ▿ (2 elements) - - key: "MessageExtension" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App2.MessageExtension" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "MessageExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: iMessage extension - - productName: "MessageExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 2 elements - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 3 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift - ▿ (2 elements) - - key: "NotificationServiceExtension" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App.NotificationServiceExtension" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "NotificationServiceExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: app extension - - productName: "NotificationServiceExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift - ▿ (2 elements) - - key: "StaticFramework" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App.StaticFramework" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "StaticFramework" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "StaticFramework" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift - ▿ (2 elements) - - key: "StickersPackExtension" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App.StickersPackExtension" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "StickersPackExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: sticker pack extension - - productName: "StickersPackExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 1 element - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - - sources: 0 elements - ▿ (2 elements) - - key: "WidgetExtension" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App.WidgetExtension" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 2 elements - ▿ TargetDependency - ▿ target: (3 elements) - - name: "Bundle" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "StaticFramework" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "WidgetExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: app extension - - productName: "WidgetExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 1 element - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 3 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project + """ + } projects: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/ios_app_with_extensions/App.xcodeproj + ▿ value: App + - path: /Fixtures/ios_app_with_extensions + - sourceRootPath: /Fixtures/ios_app_with_extensions + - xcodeProjPath: /Fixtures/ios_app_with_extensions + - name: "App" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 9 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 3 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Embed ExtensionKit Extensions" + ▿ subpath: Optional + - some: "$(EXTENSIONS_FOLDER_PATH)" + ▿ CopyFilesAction + - destination: Destination.plugins + - files: 0 elements + - name: "Embed Foundation Extensions" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 4 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "AppIntentExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "NotificationServiceExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "StickersPackExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "WidgetExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ (2 elements) + - key: "AppIntentExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.AppIntentExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppIntentExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: extensionKit extension + - productName: "AppIntentExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ (2 elements) + - key: "AppWithMessagesExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App2" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.plugins + - files: 0 elements + - name: "Embed Foundation Extensions" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "MessageExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "NotificationServiceExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppWithMessagesExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "AppWithMessagesExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ (2 elements) + - key: "Bundle" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.Bundle" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Bundle" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: bundle + - productName: "Bundle" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + - sources: 0 elements + ▿ (2 elements) + - key: "MessageExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App2.MessageExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "MessageExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: iMessage extension + - productName: "MessageExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 2 elements + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 3 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ (2 elements) + - key: "NotificationServiceExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.NotificationServiceExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "NotificationServiceExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: app extension + - productName: "NotificationServiceExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ (2 elements) + - key: "StaticFramework" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.StaticFramework" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticFramework" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "StaticFramework" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ (2 elements) + - key: "StickersPackExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.StickersPackExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StickersPackExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: sticker pack extension + - productName: "StickersPackExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + - sources: 0 elements + ▿ (2 elements) + - key: "WidgetExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.WidgetExtension" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Bundle" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "StaticFramework" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "WidgetExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: app extension + - productName: "WidgetExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 3 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project - """ + """ } } } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift index 0a9b6eca..8559e611 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift @@ -3,561 +3,561 @@ import InlineSnapshotTesting import Path import Testing import XcodeGraph -import XcodeProjToGraph import XcodeProj +import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test - func iosAppWithMultiConfigs() async throws { - try await assertGraph { - .iosAppWithMultiConfigs - } name: { - """ - - "Workspace" + @Test + func iosAppWithMultiConfigs() async throws { + try await assertGraph { + .iosAppWithMultiConfigs + } name: { + """ + - "Workspace" - """ - }dependencies: { - """ - ▿ 3 key/value pairs - ▿ (2 elements) - ▿ key: target 'AppTests' - ▿ target: (3 elements) - - name: "AppTests" - - path: /Fixtures/ios_app_with_multi_configs/App - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_multi_configs/App - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'Framework1Tests' - ▿ target: (3 elements) - - name: "Framework1Tests" - - path: /Fixtures/ios_app_with_multi_configs/Framework1 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'Framework1' - ▿ target: (3 elements) - - name: "Framework1" - - path: /Fixtures/ios_app_with_multi_configs/Framework1 - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'Framework2Tests' - ▿ target: (3 elements) - - name: "Framework2Tests" - - path: /Fixtures/ios_app_with_multi_configs/Framework2 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'Framework2' - ▿ target: (3 elements) - - name: "Framework2" - - path: /Fixtures/ios_app_with_multi_configs/Framework2 - - status: LinkingStatus.required + """ + } dependencies: { + """ + ▿ 3 key/value pairs + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_multi_configs/App + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_multi_configs/App + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1Tests' + ▿ target: (3 elements) + - name: "Framework1Tests" + - path: /Fixtures/ios_app_with_multi_configs/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Framework1' + ▿ target: (3 elements) + - name: "Framework1" + - path: /Fixtures/ios_app_with_multi_configs/Framework1 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework2Tests' + ▿ target: (3 elements) + - name: "Framework2Tests" + - path: /Fixtures/ios_app_with_multi_configs/Framework2 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Framework2' + ▿ target: (3 elements) + - name: "Framework2" + - path: /Fixtures/ios_app_with_multi_configs/Framework2 + - status: LinkingStatus.required - """ - }dependencyConditions: { - """ - - 0 key/value pairs + """ + } dependencyConditions: { + """ + - 0 key/value pairs - """ - }packages: { - """ - - 0 key/value pairs + """ + } packages: { + """ + - 0 key/value pairs - """ - }workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "Workspace" - - path: /Fixtures/ios_app_with_multi_configs - ▿ projects: 3 elements - - /Fixtures/ios_app_with_multi_configs/App/MainApp.xcodeproj - - /Fixtures/ios_app_with_multi_configs/Framework1/Framework1.xcodeproj - - /Fixtures/ios_app_with_multi_configs/Framework2/Framework2.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_app_with_multi_configs/Workspace.xcworkspace + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "Workspace" + - path: /Fixtures/ios_app_with_multi_configs + ▿ projects: 3 elements + - /Fixtures/ios_app_with_multi_configs/App/MainApp.xcodeproj + - /Fixtures/ios_app_with_multi_configs/Framework1/Framework1.xcodeproj + - /Fixtures/ios_app_with_multi_configs/Framework2/Framework2.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_multi_configs/Workspace.xcworkspace - """ - }projects: { - """ - ▿ 3 key/value pairs - ▿ (2 elements) - - key: /Fixtures/ios_app_with_multi_configs/App/MainApp.xcodeproj - ▿ value: MainApp - - path: /Fixtures/ios_app_with_multi_configs/App - - sourceRootPath: /Fixtures/ios_app_with_multi_configs/App - - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/App - - name: "MainApp" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "App" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift + """ + } projects: { + """ + ▿ 3 key/value pairs ▿ (2 elements) - - key: "AppTests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.AppTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_app_with_multi_configs/App/MainApp.xcodeproj + ▿ value: MainApp + - path: /Fixtures/ios_app_with_multi_configs/App + - sourceRootPath: /Fixtures/ios_app_with_multi_configs/App + - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/App + - name: "MainApp" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "App" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.AppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "AppTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_app_with_multi_configs/Framework1/Framework1.xcodeproj - ▿ value: Framework1 - - path: /Fixtures/ios_app_with_multi_configs/Framework1 - - sourceRootPath: /Fixtures/ios_app_with_multi_configs/Framework1 - - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/Framework1 - - name: "Framework1" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "Framework1" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.Framework1" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework1" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "Framework1" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project ▿ (2 elements) - - key: "Framework1Tests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.Framework1Tests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_app_with_multi_configs/Framework1/Framework1.xcodeproj + ▿ value: Framework1 + - path: /Fixtures/ios_app_with_multi_configs/Framework1 + - sourceRootPath: /Fixtures/ios_app_with_multi_configs/Framework1 + - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/Framework1 + - name: "Framework1" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "Framework1" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "Framework1" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Framework1" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift + ▿ (2 elements) + - key: "Framework1Tests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Framework1" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1Tests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "Framework1Tests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework1Tests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "Framework1Tests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_app_with_multi_configs/Framework2/Framework2.xcodeproj - ▿ value: Framework2 - - path: /Fixtures/ios_app_with_multi_configs/Framework2 - - sourceRootPath: /Fixtures/ios_app_with_multi_configs/Framework2 - - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/Framework2 - - name: "Framework2" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "Framework2" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.Framework2" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework2" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "Framework2" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project ▿ (2 elements) - - key: "Framework2Tests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.Framework2Tests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_app_with_multi_configs/Framework2/Framework2.xcodeproj + ▿ value: Framework2 + - path: /Fixtures/ios_app_with_multi_configs/Framework2 + - sourceRootPath: /Fixtures/ios_app_with_multi_configs/Framework2 + - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/Framework2 + - name: "Framework2" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "Framework2" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework2" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "Framework2" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Framework2" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift + ▿ (2 elements) + - key: "Framework2Tests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework2Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Framework2" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework2Tests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "Framework2Tests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework2Tests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "Framework2Tests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project - """ + """ + } } - } } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift index d1b9cf61..974a8e26 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift @@ -3,254 +3,254 @@ import InlineSnapshotTesting import Path import Testing import XcodeGraph -import XcodeProjToGraph import XcodeProj +import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test - func projectNoWorkspace() async throws { - let path = try WorkspaceFixture.iosAppWithRemoteSwiftPackage.absolutePath() - let graph: XcodeGraph.Graph = try await ProjectParser.parse(projectType: .xcodeProject(path)) + @Test + func projectNoWorkspace() async throws { + let path = try WorkspaceFixture.iosAppWithRemoteSwiftPackage.absolutePath() + let graph: XcodeGraph.Graph = try await ProjectParser.parse(projectType: .xcodeProject(path)) - try #require(graph != nil) - } + try #require(graph != nil) + } - @Test - func iosAppWithRemoteSwiftPackage() async throws { - try await assertGraph { - .iosAppWithRemoteSwiftPackage - } name: { - """ - - "App" + @Test + func iosAppWithRemoteSwiftPackage() async throws { + try await assertGraph { + .iosAppWithRemoteSwiftPackage + } name: { + """ + - "App" - """ - }dependencies: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - ▿ key: target 'AppTests' - ▿ target: (3 elements) - - name: "AppTests" - - path: /Fixtures/ios_app_with_remote_swift_package - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_remote_swift_package - - status: LinkingStatus.required + """ + } dependencies: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_remote_swift_package + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_remote_swift_package + - status: LinkingStatus.required - """ - }dependencyConditions: { - """ - - 0 key/value pairs + """ + } dependencyConditions: { + """ + - 0 key/value pairs - """ - }packages: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj - ▿ value: 1 key/value pair - ▿ (2 elements) - - key: "https://github.com/ReactiveX/RxSwift" - ▿ value: Package - ▿ remote: (2 elements) - - url: "https://github.com/ReactiveX/RxSwift" - ▿ requirement: Requirement - - upToNextMajor: "5.0.0" + """ + } packages: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj + ▿ value: 1 key/value pair + ▿ (2 elements) + - key: "https://github.com/ReactiveX/RxSwift" + ▿ value: Package + ▿ remote: (2 elements) + - url: "https://github.com/ReactiveX/RxSwift" + ▿ requirement: Requirement + - upToNextMajor: "5.0.0" - """ - }workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "App" - - path: /Fixtures/ios_app_with_remote_swift_package - ▿ projects: 1 element - - /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_app_with_remote_swift_package/App.xcworkspace + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "App" + - path: /Fixtures/ios_app_with_remote_swift_package + ▿ projects: 1 element + - /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_remote_swift_package/App.xcworkspace - """ - }projects: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj - ▿ value: App - - path: /Fixtures/ios_app_with_remote_swift_package - - sourceRootPath: /Fixtures/ios_app_with_remote_swift_package - - xcodeProjPath: /Fixtures/ios_app_with_remote_swift_package - - name: "App" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs + """ + } projects: { + """ + ▿ 1 key/value pair ▿ (2 elements) - - key: "App" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members + - key: /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj + ▿ value: App + - path: /Fixtures/ios_app_with_remote_swift_package + - sourceRootPath: /Fixtures/ios_app_with_remote_swift_package + - xcodeProjPath: /Fixtures/ios_app_with_remote_swift_package - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift - ▿ (2 elements) - - key: "AppTests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.AppTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "App" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.AppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift + ▿ packages: 1 element + ▿ Package + ▿ remote: (2 elements) + - url: "https://github.com/ReactiveX/RxSwift" + ▿ requirement: Requirement + - upToNextMajor: "5.0.0" + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "AppTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift - ▿ packages: 1 element - ▿ Package - ▿ remote: (2 elements) - - url: "https://github.com/ReactiveX/RxSwift" - ▿ requirement: Requirement - - upToNextMajor: "5.0.0" - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project - """ + """ + } } - } } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift index 368ea659..204c04f4 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift @@ -3,273 +3,273 @@ import InlineSnapshotTesting import Path import Testing import XcodeGraph -import XcodeProjToGraph import XcodeProj +import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test - func iosAppWithSpmDependencies() async throws { - try await assertGraph { - .iosAppWithSpmDependencies - } name: { - """ - - "App" + @Test + func iosAppWithSpmDependencies() async throws { + try await assertGraph { + .iosAppWithSpmDependencies + } name: { + """ + - "App" - """ - }dependencies: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - ▿ key: target 'AppTests' - ▿ target: (3 elements) - - name: "AppTests" - - path: /Fixtures/ios_app_with_spm_dependencies - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_spm_dependencies - - status: LinkingStatus.required + """ + } dependencies: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_spm_dependencies + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_spm_dependencies + - status: LinkingStatus.required - """ - }dependencyConditions: { - """ - - 0 key/value pairs + """ + } dependencyConditions: { + """ + - 0 key/value pairs - """ - }packages: { - """ - - 0 key/value pairs + """ + } packages: { + """ + - 0 key/value pairs - """ - }workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "App" - - path: /Fixtures/ios_app_with_spm_dependencies - ▿ projects: 8 elements - - /Fixtures/ios_app_with_spm_dependencies/App.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/BigInt/BigInt.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/KSCrash/KSCrash.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/Mobile Buy SDK/Mobile Buy SDK.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/jwt-kit/jwt-kit.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/swift-asn1/swift-asn1.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/swift-certificates/swift-certificates.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/swift-crypto/swift-crypto.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_app_with_spm_dependencies/App.xcworkspace + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "App" + - path: /Fixtures/ios_app_with_spm_dependencies + ▿ projects: 8 elements + - /Fixtures/ios_app_with_spm_dependencies/App.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/BigInt/BigInt.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/KSCrash/KSCrash.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/Mobile Buy SDK/Mobile Buy SDK.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/jwt-kit/jwt-kit.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/swift-asn1/swift-asn1.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/swift-certificates/swift-certificates.xcodeproj + - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/swift-crypto/swift-crypto.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_spm_dependencies/App.xcworkspace - """ - }projects: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/ios_app_with_spm_dependencies/App.xcodeproj - ▿ value: App - - path: /Fixtures/ios_app_with_spm_dependencies - - sourceRootPath: /Fixtures/ios_app_with_spm_dependencies - - xcodeProjPath: /Fixtures/ios_app_with_spm_dependencies - - name: "App" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs + """ + } projects: { + """ + ▿ 1 key/value pair ▿ (2 elements) - - key: "App" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.app" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - ▿ iOS: Optional - - some: "16.0" - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members + - key: /Fixtures/ios_app_with_spm_dependencies/App.xcodeproj + ▿ value: App + - path: /Fixtures/ios_app_with_spm_dependencies + - sourceRootPath: /Fixtures/ios_app_with_spm_dependencies + - xcodeProjPath: /Fixtures/ios_app_with_spm_dependencies - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 2 elements - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 4 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_spm_dependencies/Derived/Sources/TuistAssets+App.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_spm_dependencies/Derived/Sources/TuistBundle+App.swift - ▿ (2 elements) - - key: "AppTests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.app.tests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.app" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + ▿ iOS: Optional + - some: "16.0" + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "App" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - ▿ iOS: Optional - - some: "16.0" - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 2 elements + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 4 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_spm_dependencies/Derived/Sources/TuistAssets+App.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_spm_dependencies/Derived/Sources/TuistBundle+App.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.app.tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + ▿ iOS: Optional + - some: "16.0" + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "AppTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project - """ + """ + } } - } } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift index df3e7c49..5a3acfcb 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift @@ -3,603 +3,603 @@ import InlineSnapshotTesting import Path import Testing import XcodeGraph -import XcodeProjToGraph import XcodeProj +import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test - func iosAppWithStaticLibraries() async throws { - try await assertGraph { - .iosAppWithStaticLibraries - } name: { - """ - - "iOSAppWithTransistiveStaticLibraries" + @Test + func iosAppWithStaticLibraries() async throws { + try await assertGraph { + .iosAppWithStaticLibraries + } name: { + """ + - "iOSAppWithTransistiveStaticLibraries" - """ - }dependencies: { - """ - ▿ 4 key/value pairs - ▿ (2 elements) - ▿ key: target 'ATests' - ▿ target: (3 elements) - - name: "ATests" - - path: /Fixtures/ios_app_with_static_libraries/Modules/A - - status: LinkingStatus.required - ▿ value: 2 members - ▿ library 'libC.a' - ▿ library: (5 elements) - - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a - - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C - - linking: BinaryLinking.static - ▿ architectures: 2 elements - - BinaryArchitecture.x8664 - - BinaryArchitecture.arm64 - - swiftModuleMap: Optional.none - ▿ target 'A' - ▿ target: (3 elements) - - name: "A" - - path: /Fixtures/ios_app_with_static_libraries/Modules/A - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_static_libraries - - status: LinkingStatus.required - ▿ value: 1 member - ▿ library 'libC.a' - ▿ library: (5 elements) - - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a - - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C - - linking: BinaryLinking.static - ▿ architectures: 2 elements - - BinaryArchitecture.x8664 - - BinaryArchitecture.arm64 - - swiftModuleMap: Optional.none - ▿ (2 elements) - ▿ key: target 'AppTests' - ▿ target: (3 elements) - - name: "AppTests" - - path: /Fixtures/ios_app_with_static_libraries - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_static_libraries - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'BTests' - ▿ target: (3 elements) - - name: "BTests" - - path: /Fixtures/ios_app_with_static_libraries/Modules/B - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'B' - ▿ target: (3 elements) - - name: "B" - - path: /Fixtures/ios_app_with_static_libraries/Modules/B - - status: LinkingStatus.required + """ + } dependencies: { + """ + ▿ 4 key/value pairs + ▿ (2 elements) + ▿ key: target 'ATests' + ▿ target: (3 elements) + - name: "ATests" + - path: /Fixtures/ios_app_with_static_libraries/Modules/A + - status: LinkingStatus.required + ▿ value: 2 members + ▿ library 'libC.a' + ▿ library: (5 elements) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C + - linking: BinaryLinking.static + ▿ architectures: 2 elements + - BinaryArchitecture.x8664 + - BinaryArchitecture.arm64 + - swiftModuleMap: Optional.none + ▿ target 'A' + ▿ target: (3 elements) + - name: "A" + - path: /Fixtures/ios_app_with_static_libraries/Modules/A + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_static_libraries + - status: LinkingStatus.required + ▿ value: 1 member + ▿ library 'libC.a' + ▿ library: (5 elements) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C + - linking: BinaryLinking.static + ▿ architectures: 2 elements + - BinaryArchitecture.x8664 + - BinaryArchitecture.arm64 + - swiftModuleMap: Optional.none + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_static_libraries + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_static_libraries + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'BTests' + ▿ target: (3 elements) + - name: "BTests" + - path: /Fixtures/ios_app_with_static_libraries/Modules/B + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'B' + ▿ target: (3 elements) + - name: "B" + - path: /Fixtures/ios_app_with_static_libraries/Modules/B + - status: LinkingStatus.required - """ - }dependencyConditions: { - """ - - 0 key/value pairs + """ + } dependencyConditions: { + """ + - 0 key/value pairs - """ - }packages: { - """ - - 0 key/value pairs + """ + } packages: { + """ + - 0 key/value pairs - """ - }workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "iOSAppWithTransistiveStaticLibraries" - - path: /Fixtures/ios_app_with_static_libraries - ▿ projects: 3 elements - - /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcodeproj - - /Fixtures/ios_app_with_static_libraries/Modules/A/A.xcodeproj - - /Fixtures/ios_app_with_static_libraries/Modules/B/B.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcworkspace + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "iOSAppWithTransistiveStaticLibraries" + - path: /Fixtures/ios_app_with_static_libraries + ▿ projects: 3 elements + - /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcodeproj + - /Fixtures/ios_app_with_static_libraries/Modules/A/A.xcodeproj + - /Fixtures/ios_app_with_static_libraries/Modules/B/B.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcworkspace - """ - }projects: { - """ - ▿ 3 key/value pairs - ▿ (2 elements) - - key: /Fixtures/ios_app_with_static_libraries/Modules/A/A.xcodeproj - ▿ value: A - - path: /Fixtures/ios_app_with_static_libraries/Modules/A - - sourceRootPath: /Fixtures/ios_app_with_static_libraries/Modules/A - - xcodeProjPath: /Fixtures/ios_app_with_static_libraries/Modules/A - - name: "A" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs + """ + } projects: { + """ + ▿ 3 key/value pairs ▿ (2 elements) - - key: "A" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.A" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members + - key: /Fixtures/ios_app_with_static_libraries/Modules/A/A.xcodeproj + ▿ value: A + - path: /Fixtures/ios_app_with_static_libraries/Modules/A + - sourceRootPath: /Fixtures/ios_app_with_static_libraries/Modules/A + - xcodeProjPath: /Fixtures/ios_app_with_static_libraries/Modules/A - name: "A" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: static library - - productName: "A" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift - ▿ (2 elements) - - key: "ATests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.ATests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 2 elements - ▿ TargetDependency - ▿ target: (3 elements) + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "A" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.A" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "A" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ library: (4 elements) - - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a - - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C - - swiftModuleMap: Optional.none - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: static library + - productName: "A" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift + ▿ (2 elements) + - key: "ATests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.ATests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "A" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ library: (4 elements) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C + - swiftModuleMap: Optional.none + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "ATests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "ATests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "ATests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "ATests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_app_with_static_libraries/Modules/B/B.xcodeproj - ▿ value: B - - path: /Fixtures/ios_app_with_static_libraries/Modules/B - - sourceRootPath: /Fixtures/ios_app_with_static_libraries/Modules/B - - xcodeProjPath: /Fixtures/ios_app_with_static_libraries/Modules/B - - name: "B" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "B" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.B" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "B" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: static library - - productName: "B" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project ▿ (2 elements) - - key: "BTests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.BTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_app_with_static_libraries/Modules/B/B.xcodeproj + ▿ value: B + - path: /Fixtures/ios_app_with_static_libraries/Modules/B + - sourceRootPath: /Fixtures/ios_app_with_static_libraries/Modules/B + - xcodeProjPath: /Fixtures/ios_app_with_static_libraries/Modules/B + - name: "B" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "B" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.B" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "B" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: static library + - productName: "B" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift + ▿ (2 elements) + - key: "BTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.BTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "B" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "BTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "BTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "BTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "BTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcodeproj - ▿ value: iOSAppWithTransistiveStaticLibraries - - path: /Fixtures/ios_app_with_static_libraries - - sourceRootPath: /Fixtures/ios_app_with_static_libraries - - xcodeProjPath: /Fixtures/ios_app_with_static_libraries - - name: "iOSAppWithTransistiveStaticLibraries" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "App" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ library: (4 elements) - - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a - - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C - - swiftModuleMap: Optional.none - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project ▿ (2 elements) - - key: "AppTests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.AppTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcodeproj + ▿ value: iOSAppWithTransistiveStaticLibraries + - path: /Fixtures/ios_app_with_static_libraries + - sourceRootPath: /Fixtures/ios_app_with_static_libraries + - xcodeProjPath: /Fixtures/ios_app_with_static_libraries + - name: "iOSAppWithTransistiveStaticLibraries" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ library: (4 elements) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C + - swiftModuleMap: Optional.none + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "App" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.AppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "AppTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project - """ + """ + } } - } } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift index 5822bc1d..9e26a527 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift @@ -3,1082 +3,1082 @@ import InlineSnapshotTesting import Path import Testing import XcodeGraph -import XcodeProjToGraph import XcodeProj +import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test - func iosWorkspaceWithMicrofeatureArchitectureStaticLinking() async throws { - try await assertGraph { - .iosWorkspaceWithMicrofeatureArchitectureStaticLinking - } name: { - """ - - "Workspace" + @Test + func iosWorkspaceWithMicrofeatureArchitectureStaticLinking() async throws { + try await assertGraph { + .iosWorkspaceWithMicrofeatureArchitectureStaticLinking + } name: { + """ + - "Workspace" - """ - }dependencies: { - """ - ▿ 6 key/value pairs - ▿ (2 elements) - ▿ key: target 'CoreTests' - ▿ target: (3 elements) - - name: "CoreTests" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'Core' - ▿ target: (3 elements) - - name: "Core" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'DataTests' - ▿ target: (3 elements) - - name: "DataTests" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'Data' - ▿ target: (3 elements) - - name: "Data" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'FeatureContractsTests' - ▿ target: (3 elements) - - name: "FeatureContractsTests" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'FeatureContracts' - ▿ target: (3 elements) - - name: "FeatureContracts" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'FrameworkATests' - ▿ target: (3 elements) - - name: "FrameworkATests" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'FrameworkA' - ▿ target: (3 elements) - - name: "FrameworkA" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'StaticAppTests' - ▿ target: (3 elements) - - name: "StaticAppTests" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'StaticApp' - ▿ target: (3 elements) - - name: "StaticApp" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'UIComponentsTests' - ▿ target: (3 elements) - - name: "UIComponentsTests" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'UIComponents' - ▿ target: (3 elements) - - name: "UIComponents" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework - - status: LinkingStatus.required + """ + } dependencies: { + """ + ▿ 6 key/value pairs + ▿ (2 elements) + ▿ key: target 'CoreTests' + ▿ target: (3 elements) + - name: "CoreTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Core' + ▿ target: (3 elements) + - name: "Core" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'DataTests' + ▿ target: (3 elements) + - name: "DataTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Data' + ▿ target: (3 elements) + - name: "Data" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'FeatureContractsTests' + ▿ target: (3 elements) + - name: "FeatureContractsTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'FeatureContracts' + ▿ target: (3 elements) + - name: "FeatureContracts" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'FrameworkATests' + ▿ target: (3 elements) + - name: "FrameworkATests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'FrameworkA' + ▿ target: (3 elements) + - name: "FrameworkA" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'StaticAppTests' + ▿ target: (3 elements) + - name: "StaticAppTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'StaticApp' + ▿ target: (3 elements) + - name: "StaticApp" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'UIComponentsTests' + ▿ target: (3 elements) + - name: "UIComponentsTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'UIComponents' + ▿ target: (3 elements) + - name: "UIComponents" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - status: LinkingStatus.required - """ - }dependencyConditions: { - """ - - 0 key/value pairs + """ + } dependencyConditions: { + """ + - 0 key/value pairs - """ - }packages: { - """ - - 0 key/value pairs + """ + } packages: { + """ + - 0 key/value pairs - """ - }workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "Workspace" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking - ▿ projects: 6 elements - - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Core.xcodeproj - - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Data.xcodeproj - - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/FrameworkA.xcodeproj - - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/FeatureContracts.xcodeproj - - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/UIComponents.xcodeproj - - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/StaticApp.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.xcworkspace + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "Workspace" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking + ▿ projects: 6 elements + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Core.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Data.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/FrameworkA.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/FeatureContracts.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/UIComponents.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/StaticApp.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.xcworkspace - """ - }projects: { - """ - ▿ 6 key/value pairs - ▿ (2 elements) - - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Core.xcodeproj - ▿ value: Core - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework - - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework - - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework - - name: "Core" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs + """ + } projects: { + """ + ▿ 6 key/value pairs ▿ (2 elements) - - key: "Core" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.Core" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Core.xcodeproj + ▿ value: Core + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework - name: "Core" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "Core" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift - ▿ (2 elements) - - key: "CoreTests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.CoreTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "Core" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Core" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "Core" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Core" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift + ▿ (2 elements) + - key: "CoreTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.CoreTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Core" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "CoreTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "CoreTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "CoreTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "CoreTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Data.xcodeproj - ▿ value: Data - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework - - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework - - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework - - name: "Data" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "Data" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.Data" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Data" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "Data" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project ▿ (2 elements) - - key: "DataTests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.DataFrameworkTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Data.xcodeproj + ▿ value: Data + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - name: "Data" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "Data" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Data" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "Data" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Data" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift + ▿ (2 elements) + - key: "DataTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.DataFrameworkTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Data" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "DataTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "DataTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "DataTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "DataTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/FrameworkA.xcodeproj - ▿ value: FrameworkA - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework - - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework - - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework - - name: "FrameworkA" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "FrameworkA" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.FrameworkA" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "FrameworkA" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "FrameworkA" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project ▿ (2 elements) - - key: "FrameworkATests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.FrameworkATests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/FrameworkA.xcodeproj + ▿ value: FrameworkA + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - name: "FrameworkA" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "FrameworkA" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.FrameworkA" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "FrameworkA" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "FrameworkA" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift + ▿ (2 elements) + - key: "FrameworkATests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.FrameworkATests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "FrameworkA" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "FrameworkATests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "FrameworkATests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "FrameworkATests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "FrameworkATests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/FeatureContracts.xcodeproj - ▿ value: FeatureContracts - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts - - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts - - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts - - name: "FeatureContracts" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "FeatureContracts" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.FeatureContracts" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "FeatureContracts" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "FeatureContracts" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 2 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project ▿ (2 elements) - - key: "FeatureContractsTests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.FeatureContractsTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/FeatureContracts.xcodeproj + ▿ value: FeatureContracts + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - name: "FeatureContracts" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "FeatureContracts" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.FeatureContracts" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "FeatureContracts" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "FeatureContracts" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift + ▿ (2 elements) + - key: "FeatureContractsTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.FeatureContractsTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "FeatureContracts" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "FeatureContractsTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "FeatureContractsTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "FeatureContractsTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "FeatureContractsTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/UIComponents.xcodeproj - ▿ value: UIComponents - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework - - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework - - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework - - name: "UIComponents" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "UIComponents" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.UIComponents" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "UIComponents" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "UIComponents" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project ▿ (2 elements) - - key: "UIComponentsTests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.UIComponentsTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/UIComponents.xcodeproj + ▿ value: UIComponents + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - name: "UIComponents" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "UIComponents" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.UIComponents" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "UIComponents" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "UIComponents" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift + ▿ (2 elements) + - key: "UIComponentsTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.UIComponentsTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "UIComponents" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "UIComponentsTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "UIComponentsTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "UIComponentsTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "UIComponentsTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/StaticApp.xcodeproj - ▿ value: StaticApp - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp - - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp - - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp - - name: "StaticApp" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "StaticApp" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.StaticApp" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "StaticApp" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "StaticApp" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project ▿ (2 elements) - - key: "StaticAppTests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.StaticAppTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/StaticApp.xcodeproj + ▿ value: StaticApp + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - name: "StaticApp" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "StaticApp" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.StaticApp" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "StaticApp" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "StaticApp" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "StaticAppTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.StaticAppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "StaticApp" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticAppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "StaticAppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "StaticAppTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "StaticAppTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project - """ + """ + } } - } } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift index 604cd690..fb04f120 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift @@ -3,834 +3,834 @@ import InlineSnapshotTesting import Path import Testing import XcodeGraph -import XcodeProjToGraph import XcodeProj +import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test - func ios_app_with_transitive_framework() async throws { - try await assertGraph { - .ios_app_with_transitive_framework - } name: { - """ - - "Workspace" + @Test + func ios_app_with_transitive_framework() async throws { + try await assertGraph { + .ios_app_with_transitive_framework + } name: { + """ + - "Workspace" - """ - }dependencies: { - """ - ▿ 8 key/value pairs - ▿ (2 elements) - ▿ key: target 'AppTests' - ▿ target: (3 elements) - - name: "AppTests" - - path: /Fixtures/ios_app_with_transitive_framework/App - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_transitive_framework/App - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'AppUITests' - ▿ target: (3 elements) - - name: "AppUITests" - - path: /Fixtures/ios_app_with_transitive_framework/App - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_transitive_framework/App - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'Framework1-iOS' - ▿ target: (3 elements) - - name: "Framework1-iOS" - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ framework 'Framework2.framework' - ▿ framework: (7 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 - - dsymPath: Optional.none - - bcsymbolmapPaths: 0 elements - - linking: BinaryLinking.dynamic - ▿ architectures: 2 elements - - BinaryArchitecture.x8664 - - BinaryArchitecture.arm64 - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'Framework1-macOS' - ▿ target: (3 elements) - - name: "Framework1-macOS" - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ framework 'Framework2.framework' - ▿ framework: (7 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework - - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Framework2 - - dsymPath: Optional.none - - bcsymbolmapPaths: 0 elements - - linking: BinaryLinking.dynamic - ▿ architectures: 1 element - - BinaryArchitecture.arm64 - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'Framework1Tests-iOS' - ▿ target: (3 elements) - - name: "Framework1Tests-iOS" - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'Framework1-iOS' - ▿ target: (3 elements) - - name: "Framework1-iOS" - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'Framework1Tests-macOS' - ▿ target: (3 elements) - - name: "Framework1Tests-macOS" - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'Framework1-macOS' - ▿ target: (3 elements) - - name: "Framework1-macOS" - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'StaticFramework1' - ▿ target: (3 elements) - - name: "StaticFramework1" - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ framework 'Framework2.framework' - ▿ framework: (7 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 - - dsymPath: Optional.none - - bcsymbolmapPaths: 0 elements - - linking: BinaryLinking.dynamic - ▿ architectures: 2 elements - - BinaryArchitecture.x8664 - - BinaryArchitecture.arm64 - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'StaticFramework1Tests' - ▿ target: (3 elements) - - name: "StaticFramework1Tests" - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 - - status: LinkingStatus.required - ▿ value: 2 members - ▿ framework 'Framework2.framework' - ▿ framework: (7 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 - - dsymPath: Optional.none - - bcsymbolmapPaths: 0 elements - - linking: BinaryLinking.dynamic - ▿ architectures: 2 elements - - BinaryArchitecture.x8664 - - BinaryArchitecture.arm64 - - status: LinkingStatus.required - ▿ target 'StaticFramework1' - ▿ target: (3 elements) - - name: "StaticFramework1" - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 - - status: LinkingStatus.required + """ + } dependencies: { + """ + ▿ 8 key/value pairs + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_transitive_framework/App + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_transitive_framework/App + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'AppUITests' + ▿ target: (3 elements) + - name: "AppUITests" + - path: /Fixtures/ios_app_with_transitive_framework/App + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_transitive_framework/App + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1-iOS' + ▿ target: (3 elements) + - name: "Framework1-iOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ framework 'Framework2.framework' + ▿ framework: (7 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 + - dsymPath: Optional.none + - bcsymbolmapPaths: 0 elements + - linking: BinaryLinking.dynamic + ▿ architectures: 2 elements + - BinaryArchitecture.x8664 + - BinaryArchitecture.arm64 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1-macOS' + ▿ target: (3 elements) + - name: "Framework1-macOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ framework 'Framework2.framework' + ▿ framework: (7 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework + - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Framework2 + - dsymPath: Optional.none + - bcsymbolmapPaths: 0 elements + - linking: BinaryLinking.dynamic + ▿ architectures: 1 element + - BinaryArchitecture.arm64 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1Tests-iOS' + ▿ target: (3 elements) + - name: "Framework1Tests-iOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Framework1-iOS' + ▿ target: (3 elements) + - name: "Framework1-iOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1Tests-macOS' + ▿ target: (3 elements) + - name: "Framework1Tests-macOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Framework1-macOS' + ▿ target: (3 elements) + - name: "Framework1-macOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'StaticFramework1' + ▿ target: (3 elements) + - name: "StaticFramework1" + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ framework 'Framework2.framework' + ▿ framework: (7 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 + - dsymPath: Optional.none + - bcsymbolmapPaths: 0 elements + - linking: BinaryLinking.dynamic + ▿ architectures: 2 elements + - BinaryArchitecture.x8664 + - BinaryArchitecture.arm64 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'StaticFramework1Tests' + ▿ target: (3 elements) + - name: "StaticFramework1Tests" + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - status: LinkingStatus.required + ▿ value: 2 members + ▿ framework 'Framework2.framework' + ▿ framework: (7 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 + - dsymPath: Optional.none + - bcsymbolmapPaths: 0 elements + - linking: BinaryLinking.dynamic + ▿ architectures: 2 elements + - BinaryArchitecture.x8664 + - BinaryArchitecture.arm64 + - status: LinkingStatus.required + ▿ target 'StaticFramework1' + ▿ target: (3 elements) + - name: "StaticFramework1" + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - status: LinkingStatus.required - """ - }dependencyConditions: { - """ - - 0 key/value pairs + """ + } dependencyConditions: { + """ + - 0 key/value pairs - """ - }packages: { - """ - - 0 key/value pairs + """ + } packages: { + """ + - 0 key/value pairs - """ - }workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "Workspace" - - path: /Fixtures/ios_app_with_transitive_framework - ▿ projects: 3 elements - - /Fixtures/ios_app_with_transitive_framework/App/MainApp.xcodeproj - - /Fixtures/ios_app_with_transitive_framework/Framework1/Framework1.xcodeproj - - /Fixtures/ios_app_with_transitive_framework/StaticFramework1/StaticFramework1.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_app_with_transitive_framework/Workspace.xcworkspace + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "Workspace" + - path: /Fixtures/ios_app_with_transitive_framework + ▿ projects: 3 elements + - /Fixtures/ios_app_with_transitive_framework/App/MainApp.xcodeproj + - /Fixtures/ios_app_with_transitive_framework/Framework1/Framework1.xcodeproj + - /Fixtures/ios_app_with_transitive_framework/StaticFramework1/StaticFramework1.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_transitive_framework/Workspace.xcworkspace - """ - }projects: { - """ - ▿ 3 key/value pairs - ▿ (2 elements) - - key: /Fixtures/ios_app_with_transitive_framework/App/MainApp.xcodeproj - ▿ value: MainApp - - path: /Fixtures/ios_app_with_transitive_framework/App - - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/App - - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/App - - name: "MainApp" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 3 key/value pairs + """ + } projects: { + """ + ▿ 3 key/value pairs ▿ (2 elements) - - key: "App" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift - ▿ (2 elements) - - key: "AppTests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.AppTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_app_with_transitive_framework/App/MainApp.xcodeproj + ▿ value: MainApp + - path: /Fixtures/ios_app_with_transitive_framework/App + - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/App + - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/App + - name: "MainApp" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 3 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "App" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.AppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift + ▿ (2 elements) + - key: "AppUITests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.AppUITests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppUITests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: ui tests + - productName: "AppUITests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "AppTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift - ▿ (2 elements) - - key: "AppUITests" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.AppUITests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "App" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppUITests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: ui tests - - productName: "AppUITests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_app_with_transitive_framework/Framework1/Framework1.xcodeproj - ▿ value: Framework1 - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/Framework1 - - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/Framework1 - - name: "Framework1" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 4 key/value pairs + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project ▿ (2 elements) - - key: "Framework1-iOS" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.Framework1" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ framework: (3 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework1-iOS" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "Framework1" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift - ▿ (2 elements) - - key: "Framework1-macOS" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.Framework1" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ framework: (3 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework1-macOS" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "Framework1" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift - ▿ (2 elements) - - key: "Framework1Tests-iOS" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.Framework1Tests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_app_with_transitive_framework/Framework1/Framework1.xcodeproj + ▿ value: Framework1 + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/Framework1 + - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/Framework1 + - name: "Framework1" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 4 key/value pairs + ▿ (2 elements) + - key: "Framework1-iOS" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ framework: (3 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "Framework1-iOS" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework1Tests-iOS" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "Framework1Tests_iOS" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift - ▿ (2 elements) - - key: "Framework1Tests-macOS" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.Framework1Tests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Framework1" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift + ▿ (2 elements) + - key: "Framework1-macOS" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ framework: (3 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "Framework1-macOS" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Framework1" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift + ▿ (2 elements) + - key: "Framework1Tests-iOS" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Framework1-iOS" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1Tests-iOS" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "Framework1Tests_iOS" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift + ▿ (2 elements) + - key: "Framework1Tests-macOS" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Framework1-macOS" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1Tests-macOS" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "Framework1Tests_macOS" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework1Tests-macOS" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "Framework1Tests_macOS" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/StaticFramework1.xcodeproj - ▿ value: StaticFramework1 - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 - - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 - - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 - - name: "StaticFramework1" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "StaticFramework1" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.StaticFramework1" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ framework: (3 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "StaticFramework1" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "StaticFramework1" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project ▿ (2 elements) - - key: "StaticFramework1Tests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.StaticFramework1Tests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 2 elements - ▿ TargetDependency - ▿ framework: (3 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/StaticFramework1.xcodeproj + ▿ value: StaticFramework1 + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - name: "StaticFramework1" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "StaticFramework1" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.StaticFramework1" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ framework: (3 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "StaticFramework1" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "StaticFramework1" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift + ▿ (2 elements) + - key: "StaticFramework1Tests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.StaticFramework1Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ framework: (3 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "StaticFramework1" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticFramework1Tests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "StaticFramework1Tests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "StaticFramework1Tests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "StaticFramework1Tests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project - """ + """ + } } - } } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift index 23625f51..f089f6ac 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift @@ -3,237 +3,237 @@ import InlineSnapshotTesting import Path import Testing import XcodeGraph -import XcodeProjToGraph import XcodeProj +import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test - func macosAppWithSystemExtension() async throws { - try await assertGraph { - .macosAppWithSystemExtension - } name: { - """ - - "App with SystemExtension" + @Test + func macosAppWithSystemExtension() async throws { + try await assertGraph { + .macosAppWithSystemExtension + } name: { + """ + - "App with SystemExtension" - """ - }dependencies: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - ▿ key: target 'MainApp' - ▿ target: (3 elements) - - name: "MainApp" - - path: /Fixtures/macos_app_with_system_extension - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'SystemExtension' - ▿ target: (3 elements) - - name: "SystemExtension" - - path: /Fixtures/macos_app_with_system_extension - - status: LinkingStatus.required + """ + } dependencies: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: target 'MainApp' + ▿ target: (3 elements) + - name: "MainApp" + - path: /Fixtures/macos_app_with_system_extension + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'SystemExtension' + ▿ target: (3 elements) + - name: "SystemExtension" + - path: /Fixtures/macos_app_with_system_extension + - status: LinkingStatus.required - """ - }dependencyConditions: { - """ - - 0 key/value pairs + """ + } dependencyConditions: { + """ + - 0 key/value pairs - """ - }packages: { - """ - - 0 key/value pairs + """ + } packages: { + """ + - 0 key/value pairs - """ - }workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "App with SystemExtension" - - path: /Fixtures/macos_app_with_system_extension - ▿ projects: 1 element - - /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcworkspace + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "App with SystemExtension" + - path: /Fixtures/macos_app_with_system_extension + ▿ projects: 1 element + - /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcworkspace - """ - }projects: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcodeproj - ▿ value: App with SystemExtension - - path: /Fixtures/macos_app_with_system_extension - - sourceRootPath: /Fixtures/macos_app_with_system_extension - - xcodeProjPath: /Fixtures/macos_app_with_system_extension - - name: "App with SystemExtension" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs + """ + } projects: { + """ + ▿ 1 key/value pair ▿ (2 elements) - - key: "MainApp" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.MainApp" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Embed System Extensions" - ▿ subpath: Optional - - some: "$(CONTENTS_FOLDER_PATH)/Library/SystemExtensions" - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcodeproj + ▿ value: App with SystemExtension + - path: /Fixtures/macos_app_with_system_extension + - sourceRootPath: /Fixtures/macos_app_with_system_extension + - xcodeProjPath: /Fixtures/macos_app_with_system_extension + - name: "App with SystemExtension" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "MainApp" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.MainApp" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Embed System Extensions" + ▿ subpath: Optional + - some: "$(CONTENTS_FOLDER_PATH)/Library/SystemExtensions" + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "SystemExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "MainApp" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "MainApp" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift + ▿ (2 elements) + - key: "SystemExtension" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.SystemExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "SystemExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: system extension + - productName: "SystemExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "MainApp" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "MainApp" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift - ▿ (2 elements) - - key: "SystemExtension" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.SystemExtension" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "SystemExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: system extension - - productName: "SystemExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project - """ + """ + } } - } } diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift index e1ee0d99..63b88282 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift @@ -3,596 +3,596 @@ import InlineSnapshotTesting import Path import Testing import XcodeGraph -import XcodeProjToGraph import XcodeProj +import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test - func multiplatformAppWithMacrosAndEmbeddedWatchosApp() async throws { - try await assertGraph { - .multiplatformAppWithMacrosAndEmbeddedWatchosApp - } name: { - """ - - "AppWithWatchApp" + @Test + func multiplatformAppWithMacrosAndEmbeddedWatchosApp() async throws { + try await assertGraph { + .multiplatformAppWithMacrosAndEmbeddedWatchosApp + } name: { + """ + - "AppWithWatchApp" - """ - }dependencies: { - """ - ▿ 4 key/value pairs - ▿ (2 elements) - ▿ key: target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ value: 2 members - ▿ target 'ModuleA' - ▿ target: (3 elements) - - name: "ModuleA" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ target 'WatchApp' - ▿ target: (3 elements) - - name: "WatchApp" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'ModuleA' - ▿ target: (3 elements) - - name: "ModuleA" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'ModuleAMacros' - ▿ target: (3 elements) - - name: "ModuleAMacros" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'ModuleATests' - ▿ target: (3 elements) - - name: "ModuleATests" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ value: 2 members - ▿ target 'ModuleA' - ▿ target: (3 elements) - - name: "ModuleA" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ target 'ModuleAMacros_Testable' - ▿ target: (3 elements) - - name: "ModuleAMacros_Testable" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'WatchApp' - ▿ target: (3 elements) - - name: "WatchApp" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'ModuleA' - ▿ target: (3 elements) - - name: "ModuleA" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required + """ + } dependencies: { + """ + ▿ 4 key/value pairs + ▿ (2 elements) + ▿ key: target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ value: 2 members + ▿ target 'ModuleA' + ▿ target: (3 elements) + - name: "ModuleA" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ target 'WatchApp' + ▿ target: (3 elements) + - name: "WatchApp" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'ModuleA' + ▿ target: (3 elements) + - name: "ModuleA" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'ModuleAMacros' + ▿ target: (3 elements) + - name: "ModuleAMacros" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'ModuleATests' + ▿ target: (3 elements) + - name: "ModuleATests" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ value: 2 members + ▿ target 'ModuleA' + ▿ target: (3 elements) + - name: "ModuleA" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ target 'ModuleAMacros_Testable' + ▿ target: (3 elements) + - name: "ModuleAMacros_Testable" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'WatchApp' + ▿ target: (3 elements) + - name: "WatchApp" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'ModuleA' + ▿ target: (3 elements) + - name: "ModuleA" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required - """ - }dependencyConditions: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - ▿ key: GraphEdge - ▿ from: target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ to: target 'WatchApp' - ▿ target: (3 elements) - - name: "WatchApp" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ value: PlatformCondition - ▿ platformFilters: 1 member - - PlatformFilter.ios + """ + } dependencyConditions: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: GraphEdge + ▿ from: target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ to: target 'WatchApp' + ▿ target: (3 elements) + - name: "WatchApp" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - status: LinkingStatus.required + ▿ value: PlatformCondition + ▿ platformFilters: 1 member + - PlatformFilter.ios - """ - }packages: { - """ - - 0 key/value pairs + """ + } packages: { + """ + - 0 key/value pairs - """ - }workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "AppWithWatchApp" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - ▿ projects: 4 elements - - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp.xcodeproj - - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/.build/tuist-derived/swift-case-paths/swift-case-paths.xcodeproj - - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/.build/tuist-derived/swift-syntax/swift-syntax.xcodeproj - - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/.build/tuist-derived/xctest-dynamic-overlay/xctest-dynamic-overlay.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp.xcworkspace + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "AppWithWatchApp" + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + ▿ projects: 4 elements + - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp.xcodeproj + - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/.build/tuist-derived/swift-case-paths/swift-case-paths.xcodeproj + - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/.build/tuist-derived/swift-syntax/swift-syntax.xcodeproj + - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/.build/tuist-derived/xctest-dynamic-overlay/xctest-dynamic-overlay.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp.xcworkspace - """ - }projects: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp.xcodeproj - ▿ value: AppWithWatchApp - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - sourceRootPath: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - xcodeProjPath: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - name: "AppWithWatchApp" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 6 key/value pairs + """ + } projects: { + """ + ▿ 1 key/value pair ▿ (2 elements) - - key: "App" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Embed Watch Content" - ▿ subpath: Optional - - some: "$(CONTENTS_FOLDER_PATH)/Watch" - - coreDataModels: 0 elements - ▿ dependencies: 2 elements - ▿ TargetDependency - ▿ target: (3 elements) + - key: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp.xcodeproj + ▿ value: AppWithWatchApp + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - sourceRootPath: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - xcodeProjPath: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app + - name: "AppWithWatchApp" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 6 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Embed Watch Content" + ▿ subpath: Optional + - some: "$(CONTENTS_FOLDER_PATH)/Watch" + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "ModuleA" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "WatchApp" + - status: LinkingStatus.required + ▿ condition: Optional + ▿ some: PlatformCondition + ▿ platformFilters: 1 member + - PlatformFilter.ios + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 4 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift + ▿ (2 elements) + - key: "ModuleA" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.modulea" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "ModuleAMacros" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "ModuleA" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "WatchApp" - - status: LinkingStatus.required - ▿ condition: Optional - ▿ some: PlatformCondition - ▿ platformFilters: 1 member - - PlatformFilter.ios - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 1 element - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 4 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift - ▿ (2 elements) - - key: "ModuleA" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.modulea" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "ModuleA" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift + ▿ (2 elements) + - key: "ModuleAMacros" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.moduleamacros" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + ▿ macOS: Optional + - some: "14.0" + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "ModuleAMacros" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "ModuleA" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "ModuleA" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 2 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift - ▿ (2 elements) - - key: "ModuleAMacros" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.moduleamacros" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - ▿ macOS: Optional - - some: "14.0" - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "ModuleAMacros" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: command line tool - - productName: "ModuleAMacros" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift - ▿ (2 elements) - - key: "ModuleAMacros_Testable" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.moduleamacros.testable" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "ModuleAMacros_Testable" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "ModuleAMacros_Testable" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift - ▿ (2 elements) - - key: "ModuleATests" - ▿ value: Target - - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.moduleatests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 2 elements - ▿ TargetDependency - ▿ target: (3 elements) - - name: "ModuleA" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: command line tool + - productName: "ModuleAMacros" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift + ▿ (2 elements) + - key: "ModuleAMacros_Testable" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.moduleamacros.testable" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members - name: "ModuleAMacros_Testable" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "ModuleAMacros_Testable" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift + ▿ (2 elements) + - key: "ModuleATests" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.moduleatests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "ModuleA" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "ModuleAMacros_Testable" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "ModuleATests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "ModuleATests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift + ▿ (2 elements) + - key: "WatchApp" + ▿ value: Target + - additionalFiles: 0 elements + - buildRules: 0 elements + - bundleId: "io.tuist.App.watchkitapp" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "ModuleA" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "WatchApp" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "WatchApp" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 5 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members ▿ filesGroup: ProjectGroup ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "ModuleATests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "ModuleATests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift - ▿ (2 elements) - - key: "WatchApp" - ▿ value: Target + - name: "Project" - additionalFiles: 0 elements - - buildRules: 0 elements - - bundleId: "io.tuist.App.watchkitapp" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "ModuleA" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "WatchApp" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "WatchApp" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 1 element - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 5 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project - """ + """ + } } - } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift index 3985feab..72017d11 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift @@ -6,457 +6,465 @@ import XcodeProj @testable import XcodeProjToGraph struct BuildPhaseMapperTests { - @Test func testMapSources() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - let fileRef = PBXFileReference.mock( - sourceTree: .group, - name: "main.swift", - path: "main.swift", - pbxProj: pbxProj - ) - - let buildFile = PBXBuildFile.mock( - file: fileRef, settings: ["COMPILER_FLAGS": "-DDEBUG"], pbxProj: pbxProj) - let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) - - let target = PBXNativeTarget.mock( - name: "App", - buildConfigurationList: nil, - buildRules: [], - buildPhases: [sourcesPhase], - dependencies: [], - productType: .application, - pbxProj: pbxProj - ) - - if let project = pbxProj.projects.first { - project.targets.append(target) + @Test func testMapSources() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let fileRef = PBXFileReference.mock( + sourceTree: .group, + name: "main.swift", + path: "main.swift", + pbxProj: pbxProj + ) + + let buildFile = PBXBuildFile.mock( + file: fileRef, settings: ["COMPILER_FLAGS": "-DDEBUG"], pbxProj: pbxProj + ) + let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [sourcesPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let sources = try await mapper.mapSources(target: target) + + #expect(sources.count == 1) + let sourceFile = sources.first + try #require(sourceFile != nil) + #expect(sourceFile?.path.basename == "main.swift") + #expect(sourceFile?.compilerFlags == "-DDEBUG") } - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let sources = try await mapper.mapSources(target: target) - - #expect(sources.count == 1) - let sourceFile = sources.first - try #require(sourceFile != nil) - #expect(sourceFile?.path.basename == "main.swift") - #expect(sourceFile?.compilerFlags == "-DDEBUG") - } - - @Test func testMapResources() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - let assetRef = PBXFileReference.mock( - sourceTree: .group, - name: "Assets.xcassets", - path: "Assets.xcassets", - pbxProj: pbxProj - ) - - let buildFile = PBXBuildFile.mock(file: assetRef, pbxProj: pbxProj) - let resourcesPhase = PBXResourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) - - let target = PBXNativeTarget.mock( - name: "App", - buildConfigurationList: nil, - buildRules: [], - buildPhases: [resourcesPhase], - dependencies: [], - productType: .application, - pbxProj: pbxProj - ) - - if let project = pbxProj.projects.first { - project.targets.append(target) + @Test func testMapResources() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let assetRef = PBXFileReference.mock( + sourceTree: .group, + name: "Assets.xcassets", + path: "Assets.xcassets", + pbxProj: pbxProj + ) + + let buildFile = PBXBuildFile.mock(file: assetRef, pbxProj: pbxProj) + let resourcesPhase = PBXResourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [resourcesPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let resources = try await mapper.mapResources(target: target) + #expect(resources.count == 1) + let resource = resources.first + try #require(resource != nil) + switch resource! { + case let .file(path, _, _): + #expect(path.basename == "Assets.xcassets") + default: + Issue.record("Expected a file resource.") + } } - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let resources = try await mapper.mapResources(target: target) - #expect(resources.count == 1) - let resource = resources.first - try #require(resource != nil) - switch resource! { - case .file(let path, _, _): - #expect(path.basename == "Assets.xcassets") - default: - Issue.record("Expected a file resource.") + @Test func testMapFrameworks() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Create a framework file reference + let frameworkRef = PBXFileReference.mock( + sourceTree: .group, + name: "MyFramework.framework", + path: "Frameworks/MyFramework.framework", + pbxProj: pbxProj + ) + + let frameworkBuildFile = PBXBuildFile.mock(file: frameworkRef, pbxProj: pbxProj) + let frameworksPhase = PBXFrameworksBuildPhase.mock( + files: [frameworkBuildFile], pbxProj: pbxProj + ) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [frameworksPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let frameworks = try await mapper.mapFrameworks(target: target) + #expect(frameworks.count == 1) + let dependency = frameworks.first + try #require(dependency != nil) + #expect(dependency?.name == "MyFramework") } - } - - @Test func testMapFrameworks() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - // Create a framework file reference - let frameworkRef = PBXFileReference.mock( - sourceTree: .group, - name: "MyFramework.framework", - path: "Frameworks/MyFramework.framework", - pbxProj: pbxProj - ) - - let frameworkBuildFile = PBXBuildFile.mock(file: frameworkRef, pbxProj: pbxProj) - let frameworksPhase = PBXFrameworksBuildPhase.mock( - files: [frameworkBuildFile], pbxProj: pbxProj) - - let target = PBXNativeTarget.mock( - name: "App", - buildConfigurationList: nil, - buildRules: [], - buildPhases: [frameworksPhase], - dependencies: [], - productType: .application, - pbxProj: pbxProj - ) - - if let project = pbxProj.projects.first { - project.targets.append(target) + + @Test func testMapHeaders() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Public header + let publicHeaderRef = PBXFileReference.mock( + name: "PublicHeader.h", + path: "Include/PublicHeader.h", + pbxProj: pbxProj + ) + let publicBuildFile = PBXBuildFile.mock( + file: publicHeaderRef, settings: ["ATTRIBUTES": ["Public"]], pbxProj: pbxProj + ) + + // Private header + let privateHeaderRef = PBXFileReference.mock( + name: "PrivateHeader.h", + path: "Include/PrivateHeader.h", + pbxProj: pbxProj + ) + let privateBuildFile = PBXBuildFile.mock( + file: privateHeaderRef, settings: ["ATTRIBUTES": ["Private"]], pbxProj: pbxProj + ) + + // Project header (no attributes) + let projectHeaderRef = PBXFileReference.mock( + name: "ProjectHeader.h", + path: "Include/ProjectHeader.h", + pbxProj: pbxProj + ) + let projectBuildFile = PBXBuildFile.mock(file: projectHeaderRef, pbxProj: pbxProj) + + let headersPhase = PBXHeadersBuildPhase( + files: [publicBuildFile, privateBuildFile, projectBuildFile], + buildActionMask: PBXBuildPhase.defaultBuildActionMask, + runOnlyForDeploymentPostprocessing: false + ) + pbxProj.add(object: headersPhase) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [headersPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let headers = try await mapper.mapHeaders(target: target) + try #require(headers != nil) + #expect(headers?.public.map(\.basename).contains("PublicHeader.h") == true) + #expect(headers?.private.map(\.basename).contains("PrivateHeader.h") == true) + #expect(headers?.project.map(\.basename).contains("ProjectHeader.h") == true) } - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let frameworks = try await mapper.mapFrameworks(target: target) - #expect(frameworks.count == 1) - let dependency = frameworks.first - try #require(dependency != nil) - #expect(dependency?.name == "MyFramework") - } - - @Test func testMapHeaders() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - // Public header - let publicHeaderRef = PBXFileReference.mock( - name: "PublicHeader.h", - path: "Include/PublicHeader.h", - pbxProj: pbxProj - ) - let publicBuildFile = PBXBuildFile.mock( - file: publicHeaderRef, settings: ["ATTRIBUTES": ["Public"]], pbxProj: pbxProj) - - // Private header - let privateHeaderRef = PBXFileReference.mock( - name: "PrivateHeader.h", - path: "Include/PrivateHeader.h", - pbxProj: pbxProj - ) - let privateBuildFile = PBXBuildFile.mock( - file: privateHeaderRef, settings: ["ATTRIBUTES": ["Private"]], pbxProj: pbxProj) - - // Project header (no attributes) - let projectHeaderRef = PBXFileReference.mock( - name: "ProjectHeader.h", - path: "Include/ProjectHeader.h", - pbxProj: pbxProj - ) - let projectBuildFile = PBXBuildFile.mock(file: projectHeaderRef, pbxProj: pbxProj) - - let headersPhase = PBXHeadersBuildPhase( - files: [publicBuildFile, privateBuildFile, projectBuildFile], - buildActionMask: PBXBuildPhase.defaultBuildActionMask, - runOnlyForDeploymentPostprocessing: false - ) - pbxProj.add(object: headersPhase) - - let target = PBXNativeTarget.mock( - name: "App", - buildConfigurationList: nil, - buildRules: [], - buildPhases: [headersPhase], - dependencies: [], - productType: .application, - pbxProj: pbxProj - ) - - if let project = pbxProj.projects.first { - project.targets.append(target) + @Test func testMapScripts() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let scriptPhase = PBXShellScriptBuildPhase.mock( + name: "Run Script", + shellScript: "echo Hello", + inputPaths: ["$(SRCROOT)/input.txt"], + outputPaths: ["$(DERIVED_FILE_DIR)/output.txt"], + pbxProj: pbxProj + ) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [scriptPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let scripts = try await mapper.mapScripts(target: target) + #expect(scripts.count == 1) + let script = scripts.first + try #require(script != nil) + #expect(script?.name == "Run Script") + #expect(script?.script == .embedded("echo Hello")) + #expect(script?.inputPaths == ["$(SRCROOT)/input.txt"]) + #expect(script?.outputPaths == ["$(DERIVED_FILE_DIR)/output.txt"]) } - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let headers = try await mapper.mapHeaders(target: target) - try #require(headers != nil) - #expect(headers?.public.map(\.basename).contains("PublicHeader.h") == true) - #expect(headers?.private.map(\.basename).contains("PrivateHeader.h") == true) - #expect(headers?.project.map(\.basename).contains("ProjectHeader.h") == true) - } - - @Test func testMapScripts() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - let scriptPhase = PBXShellScriptBuildPhase.mock( - name: "Run Script", - shellScript: "echo Hello", - inputPaths: ["$(SRCROOT)/input.txt"], - outputPaths: ["$(DERIVED_FILE_DIR)/output.txt"], - pbxProj: pbxProj - ) - - let target = PBXNativeTarget.mock( - name: "App", - buildConfigurationList: nil, - buildRules: [], - buildPhases: [scriptPhase], - dependencies: [], - productType: .application, - pbxProj: pbxProj - ) - - if let project = pbxProj.projects.first { - project.targets.append(target) + @Test func testMapCopyFiles() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let fileRef = PBXFileReference.mock( + sourceTree: .group, + name: "MyLibrary.dylib", + path: "MyLibrary.dylib", + pbxProj: pbxProj + ) + // Setting an attribute for code sign on copy + let buildFile = PBXBuildFile.mock( + file: fileRef, settings: ["ATTRIBUTES": ["CodeSignOnCopy"]], pbxProj: pbxProj + ) + + let copyFilesPhase = PBXCopyFilesBuildPhase.mock( + name: "Embed Libraries", + dstPath: "Libraries", + dstSubfolderSpec: .frameworks, + files: [buildFile], + pbxProj: pbxProj + ) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [copyFilesPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let copyActions = try await mapper.mapCopyFiles(target: target) + #expect(copyActions.count == 1) + let action = copyActions.first + try #require(action != nil) + #expect(action?.name == "Embed Libraries") + #expect(action?.destination == .frameworks) + #expect(action?.subpath == "Libraries") + #expect(action?.files.count == 1) + let fileAction = action?.files.first + try #require(fileAction != nil) + #expect(fileAction?.codeSignOnCopy == true) + #expect(fileAction?.path.basename == "MyLibrary.dylib") } - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let scripts = try await mapper.mapScripts(target: target) - #expect(scripts.count == 1) - let script = scripts.first - try #require(script != nil) - #expect(script?.name == "Run Script") - #expect(script?.script == .embedded("echo Hello")) - #expect(script?.inputPaths == ["$(SRCROOT)/input.txt"]) - #expect(script?.outputPaths == ["$(DERIVED_FILE_DIR)/output.txt"]) - } - - @Test func testMapCopyFiles() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - let fileRef = PBXFileReference.mock( - sourceTree: .group, - name: "MyLibrary.dylib", - path: "MyLibrary.dylib", - pbxProj: pbxProj - ) - // Setting an attribute for code sign on copy - let buildFile = PBXBuildFile.mock( - file: fileRef, settings: ["ATTRIBUTES": ["CodeSignOnCopy"]], pbxProj: pbxProj) - - let copyFilesPhase = PBXCopyFilesBuildPhase.mock( - name: "Embed Libraries", - dstPath: "Libraries", - dstSubfolderSpec: .frameworks, - files: [buildFile], - pbxProj: pbxProj - ) - - let target = PBXNativeTarget.mock( - name: "App", - buildConfigurationList: nil, - buildRules: [], - buildPhases: [copyFilesPhase], - dependencies: [], - productType: .application, - pbxProj: pbxProj - ) - if let project = pbxProj.projects.first { - project.targets.append(target) + @Test func testMapCoreDataModels() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Create a core data model version group + let versionChildRef = PBXFileReference.mock( + name: "Model.xcdatamodel", path: "Model.xcdatamodel", pbxProj: pbxProj + ) + + let versionGroup = XCVersionGroup.mock( + currentVersion: versionChildRef, + children: [versionChildRef], + path: "Model.xcdatamodeld", + sourceTree: .group, + versionGroupType: "wrapper.xcdatamodel", + name: "Model.xcdatamodeld", + pbxProj: pbxProj + ) + + let buildFile = PBXBuildFile.mock(file: versionGroup, pbxProj: pbxProj) + let resourcesPhase = PBXResourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [resourcesPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let models = try await mapper.mapCoreDataModels(target: target) + #expect(models.count == 1) + let model = models.first + try #require(model != nil) + #expect(model?.path.basename == "Model.xcdatamodeld") + #expect(model?.versions.count == 1) + #expect(model?.currentVersion.contains("Model.xcdatamodel") == true) } - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let copyActions = try await mapper.mapCopyFiles(target: target) - #expect(copyActions.count == 1) - let action = copyActions.first - try #require(action != nil) - #expect(action?.name == "Embed Libraries") - #expect(action?.destination == .frameworks) - #expect(action?.subpath == "Libraries") - #expect(action?.files.count == 1) - let fileAction = action?.files.first - try #require(fileAction != nil) - #expect(fileAction?.codeSignOnCopy == true) - #expect(fileAction?.path.basename == "MyLibrary.dylib") - } - - @Test func testMapCoreDataModels() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - // Create a core data model version group - let versionChildRef = PBXFileReference.mock( - name: "Model.xcdatamodel", path: "Model.xcdatamodel", pbxProj: pbxProj) - - let versionGroup = XCVersionGroup.mock( - currentVersion: versionChildRef, - children: [versionChildRef], - path: "Model.xcdatamodeld", - sourceTree: .group, - versionGroupType: "wrapper.xcdatamodel", - name: "Model.xcdatamodeld", - pbxProj: pbxProj - ) - - let buildFile = PBXBuildFile.mock(file: versionGroup, pbxProj: pbxProj) - let resourcesPhase = PBXResourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) - - let target = PBXNativeTarget.mock( - name: "App", - buildConfigurationList: nil, - buildRules: [], - buildPhases: [resourcesPhase], - dependencies: [], - productType: .application, - pbxProj: pbxProj - ) - - if let project = pbxProj.projects.first { - project.targets.append(target) + @Test func testMapRawScriptBuildPhases() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let frameworksPhase = PBXShellScriptBuildPhase.mock(name: "Test Script", pbxProj: pbxProj) + + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [frameworksPhase], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let rawPhases = try await mapper.mapRawScriptBuildPhases(target: target) + #expect(rawPhases.count == 1) + let rawPhase = rawPhases.first + try #require(rawPhase != nil) + #expect(rawPhase?.name == "Test Script") } - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let models = try await mapper.mapCoreDataModels(target: target) - #expect(models.count == 1) - let model = models.first - try #require(model != nil) - #expect(model?.path.basename == "Model.xcdatamodeld") - #expect(model?.versions.count == 1) - #expect(model?.currentVersion.contains("Model.xcdatamodel") == true) - } - - @Test func testMapRawScriptBuildPhases() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - let frameworksPhase = PBXShellScriptBuildPhase.mock(name: "Test Script", pbxProj: pbxProj) - - let target = PBXNativeTarget.mock( - name: "App", - buildConfigurationList: nil, - buildRules: [], - buildPhases: [frameworksPhase], - dependencies: [], - productType: .application, - pbxProj: pbxProj - ) - - if let project = pbxProj.projects.first { - project.targets.append(target) + @Test func testMapAdditionalFiles() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Add files to main group that are not referenced by any build phase + if let project = pbxProj.projects.first, + let mainGroup = project.mainGroup + { + let fileRef1 = PBXFileReference.mock(name: "Extra1.txt", path: "Extra1.txt", pbxProj: pbxProj) + let fileRef2 = PBXFileReference.mock( + name: "Extra2.json", path: "Extra2.json", pbxProj: pbxProj + ) + mainGroup.children.append(fileRef1) + mainGroup.children.append(fileRef2) + } + + // Create a target that doesn't reference these files in build phases + let target = PBXNativeTarget.mock( + name: "App", + buildConfigurationList: nil, + buildRules: [], + buildPhases: [], + dependencies: [], + productType: .application, + pbxProj: pbxProj + ) + + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let additionalFiles = try await mapper.mapAdditionalFiles(target: target) + #expect(additionalFiles.count == 2) + let names = additionalFiles.map(\.path.basename) + #expect(names.contains("Extra1.txt") == true) + #expect(names.contains("Extra2.json") == true) } - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let rawPhases = try await mapper.mapRawScriptBuildPhases(target: target) - #expect(rawPhases.count == 1) - let rawPhase = rawPhases.first - try #require(rawPhase != nil) - #expect(rawPhase?.name == "Test Script") - } - - @Test func testMapAdditionalFiles() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - // Add files to main group that are not referenced by any build phase - if let project = pbxProj.projects.first, - let mainGroup = project.mainGroup - { - let fileRef1 = PBXFileReference.mock(name: "Extra1.txt", path: "Extra1.txt", pbxProj: pbxProj) - let fileRef2 = PBXFileReference.mock( - name: "Extra2.json", path: "Extra2.json", pbxProj: pbxProj) - mainGroup.children.append(fileRef1) - mainGroup.children.append(fileRef2) + @Test func testMapSourceFile_missingFileRef() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Create a build file with no file reference + let buildFile = PBXBuildFile() + // E.g. don't set `file` property, or fileRef is nil by default in your mock initializer. + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + _ = try await mapper.mapSources( + target: PBXNativeTarget.mock(buildPhases: [], pbxProj: pbxProj) + ) + // Since no sources phase or buildFile with a fileRef is provided, add one manually: + // Actually, let's simulate calling mapSourceFile directly if possible: + // If it's private, we can create a scenario where mapSources includes that buildFile. + // Create a sources phase to include this buildFile + let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + let target = PBXNativeTarget.mock(buildPhases: [sourcesPhase], pbxProj: pbxProj) + + let sources = try await mapper.mapSources(target: target) + // Expect no crash and empty array since fileRef is nil + #expect(sources.isEmpty == true) } - // Create a target that doesn't reference these files in build phases - let target = PBXNativeTarget.mock( - name: "App", - buildConfigurationList: nil, - buildRules: [], - buildPhases: [], - dependencies: [], - productType: .application, - pbxProj: pbxProj - ) - - if let project = pbxProj.projects.first { - project.targets.append(target) + @Test func testMapSourceFile_unresolvableFullPath() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/invalid/Path", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let fileRef = PBXFileReference( + name: "NonExistent.swift", + path: "NonExistent.swift" + // This path won't exist relative to /invalid/Path + ) + let buildFile = PBXBuildFile.mock(file: fileRef, pbxProj: pbxProj) + let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + let target = PBXNativeTarget.mock(buildPhases: [sourcesPhase], pbxProj: pbxProj) + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let sources = try await mapper.mapSources(target: target) + // Expect empty because fullPath could not be resolved + #expect(sources.isEmpty == true) } - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let additionalFiles = try await mapper.mapAdditionalFiles(target: target) - #expect(additionalFiles.count == 2) - let names = additionalFiles.map { $0.path.basename } - #expect(names.contains("Extra1.txt") == true) - #expect(names.contains("Extra2.json") == true) - } - - @Test func testMapSourceFile_missingFileRef() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - // Create a build file with no file reference - let buildFile = PBXBuildFile() - // E.g. don't set `file` property, or fileRef is nil by default in your mock initializer. - - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let _ = try await mapper.mapSources( - target: PBXNativeTarget.mock(buildPhases: [], pbxProj: pbxProj)) - // Since no sources phase or buildFile with a fileRef is provided, add one manually: - // Actually, let's simulate calling mapSourceFile directly if possible: - // If it's private, we can create a scenario where mapSources includes that buildFile. - // Create a sources phase to include this buildFile - let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) - let target = PBXNativeTarget.mock(buildPhases: [sourcesPhase], pbxProj: pbxProj) - - let sources = try await mapper.mapSources(target: target) - // Expect no crash and empty array since fileRef is nil - #expect(sources.isEmpty == true) - } - - @Test func testMapSourceFile_unresolvableFullPath() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/invalid/Path", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - let fileRef = PBXFileReference( - name: "NonExistent.swift", - path: "NonExistent.swift" - // This path won't exist relative to /invalid/Path - ) - let buildFile = PBXBuildFile.mock(file: fileRef, pbxProj: pbxProj) - let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) - let target = PBXNativeTarget.mock(buildPhases: [sourcesPhase], pbxProj: pbxProj) - - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let sources = try await mapper.mapSources(target: target) - // Expect empty because fullPath could not be resolved - #expect(sources.isEmpty == true) - } - -// @Test func testMapVariantGroup() async throws { + // @Test func testMapVariantGroup() async throws { // let mockProvider = MockProjectProvider( // sourceDirectory: "/tmp/TestProject", // projectName: "TestProject" @@ -501,81 +509,83 @@ struct BuildPhaseMapperTests { // // #expect(resources.count == 2) // #expect(resources.first?.path.basename == "Localizable.strings") -// } - - @Test func testCollectFiles_withNestedGroups() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - // Create file references at various levels - let fileRef1 = PBXFileReference.mock( - name: "RootFile.txt", path: "RootFile.txt", pbxProj: pbxProj, addToMainGroup: false) - - let subfileRef = PBXFileReference.mock( - name: "Subfile.txt", - path: "Subfile.txt", - pbxProj: pbxProj, - addToMainGroup: false - ) - let subgroup = PBXGroup.mock( - children: [subfileRef], name: "Subgroup", path: "Subgroup", pbxProj: pbxProj) - - // Variant group inside subgroup - let vfileRef = PBXFileReference.mock( - name: "VariantFile.strings", path: "en.lproj/VariantFile.strings", pbxProj: pbxProj, - addToMainGroup: false) - let variantGroup = PBXVariantGroup.mock(children: [vfileRef], pbxProj: pbxProj) - subgroup.children.append(variantGroup) - - if let project = pbxProj.projects.first, - let mainGroup = project.mainGroup - { - mainGroup.children.append(fileRef1) - mainGroup.children.append(subgroup) - } - - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - - let target = PBXNativeTarget.mock(buildPhases: [], pbxProj: pbxProj) - if let project = pbxProj.projects.first { - project.targets.append(target) + // } + + @Test func testCollectFiles_withNestedGroups() async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Create file references at various levels + let fileRef1 = PBXFileReference.mock( + name: "RootFile.txt", path: "RootFile.txt", pbxProj: pbxProj, addToMainGroup: false + ) + + let subfileRef = PBXFileReference.mock( + name: "Subfile.txt", + path: "Subfile.txt", + pbxProj: pbxProj, + addToMainGroup: false + ) + let subgroup = PBXGroup.mock( + children: [subfileRef], name: "Subgroup", path: "Subgroup", pbxProj: pbxProj + ) + + // Variant group inside subgroup + let vfileRef = PBXFileReference.mock( + name: "VariantFile.strings", path: "en.lproj/VariantFile.strings", pbxProj: pbxProj, + addToMainGroup: false + ) + let variantGroup = PBXVariantGroup.mock(children: [vfileRef], pbxProj: pbxProj) + subgroup.children.append(variantGroup) + + if let project = pbxProj.projects.first, + let mainGroup = project.mainGroup + { + mainGroup.children.append(fileRef1) + mainGroup.children.append(subgroup) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + + let target = PBXNativeTarget.mock(buildPhases: [], pbxProj: pbxProj) + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let additionalFiles = try await mapper.mapAdditionalFiles(target: target) + // Expect 3 files: RootFile.txt, Subfile.txt, VariantFile.strings + #expect(additionalFiles.count == 3) + let names = additionalFiles.map(\.path.basename) + #expect(names.sorted() == ["RootFile.txt", "Subfile.txt", "VariantFile.strings"].sorted()) } - let additionalFiles = try await mapper.mapAdditionalFiles(target: target) - // Expect 3 files: RootFile.txt, Subfile.txt, VariantFile.strings - #expect(additionalFiles.count == 3) - let names = additionalFiles.map { $0.path.basename } - #expect(names.sorted() == ["RootFile.txt", "Subfile.txt", "VariantFile.strings"].sorted()) - - } - - /// Validates all workspace fixtures. - @Test(arguments: [FileCodeGen.public, .private, .project, .disabled]) - func testCodeGenAttributes(_ fileCodeGen: FileCodeGen) async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - let fileRef = PBXFileReference.mock(name: "File.swift", path: "File.swift", pbxProj: pbxProj) - let buildFile = PBXBuildFile.mock( - file: fileRef, settings: ["ATTRIBUTES": [fileCodeGen.rawValue]], pbxProj: pbxProj) - let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) - let target = PBXNativeTarget.mock(buildPhases: [sourcesPhase], pbxProj: pbxProj) - if let project = pbxProj.projects.first { - project.targets.append(target) + /// Validates all workspace fixtures. + @Test(arguments: [FileCodeGen.public, .private, .project, .disabled]) + func testCodeGenAttributes(_ fileCodeGen: FileCodeGen) async throws { + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/TestProject", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let fileRef = PBXFileReference.mock(name: "File.swift", path: "File.swift", pbxProj: pbxProj) + let buildFile = PBXBuildFile.mock( + file: fileRef, settings: ["ATTRIBUTES": [fileCodeGen.rawValue]], pbxProj: pbxProj + ) + let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + let target = PBXNativeTarget.mock(buildPhases: [sourcesPhase], pbxProj: pbxProj) + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let sources = try await mapper.mapSources(target: target) + #expect(sources.count == 1) + let sourceFile = sources.first + try #require(sourceFile != nil) + #expect(sourceFile?.codeGen == fileCodeGen) } - - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let sources = try await mapper.mapSources(target: target) - #expect(sources.count == 1) - let sourceFile = sources.first - try #require(sourceFile != nil) - #expect(sourceFile?.codeGen == fileCodeGen) - } - } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift index 1551f0a7..ea9d2bc8 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift @@ -3,122 +3,125 @@ import XcodeGraph import XcodeProj @testable import TestSupport -@testable import XcodeProjToGraph // Adjust to access BuildRuleMapper, BuildRule, etc. +@testable import XcodeProjToGraph // Adjust to access BuildRuleMapper, BuildRule, etc. struct BuildRuleMapperTests { - let mapper = BuildRuleMapper() - - @Test func testMapBuildRulesWithKnownCompilerSpecAndFileType() async throws { - // Using a known compiler spec from the enum, e.g. .appleClang - let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue - let knownFileType = BuildRule.FileType.cSource.rawValue - let projectProvider = MockProjectProvider() - - let buildRule: PBXBuildRule = PBXBuildRule.mock( - compilerSpec: knownCompilerSpec, - fileType: knownFileType, - filePatterns: "*.c", - name: "C Rule", - outputFiles: ["$(DERIVED_FILE_DIR)/output.c.o"], - inputFiles: ["$(SRCROOT)/main.c"], - outputFilesCompilerFlags: ["-O2"], - script: "echo Building C sources", - runOncePerArchitecture: false, - pbxProj: projectProvider.pbxProj - ) - - let target = PBXNativeTarget.mock(buildRules: [buildRule], pbxProj: projectProvider.pbxProj) - let rules = try await mapper.mapBuildRules(target: target) - - #expect(rules.count == 1) - let rule = rules.first - try #require(rule != nil) - #expect(rule?.compilerSpec.rawValue == knownCompilerSpec) - #expect(rule?.fileType.rawValue == knownFileType) - #expect(rule?.filePatterns == "*.c") - #expect(rule?.name == "C Rule") - #expect(rule?.outputFiles == ["$(DERIVED_FILE_DIR)/output.c.o"]) - #expect(rule?.inputFiles == ["$(SRCROOT)/main.c"]) - #expect(rule?.outputFilesCompilerFlags == ["-O2"]) - #expect(rule?.script == "echo Building C sources") - #expect(rule?.runOncePerArchitecture == false) - } - - @Test func testMapBuildRulesWithUnknownCompilerSpec() async throws { - let projectProvider = MockProjectProvider() - let unknownCompilerSpec = "com.apple.compilers.unknown" - let knownFileType = "sourcecode.c.c" - - let buildRule = PBXBuildRule.mock( - compilerSpec: unknownCompilerSpec, - fileType: knownFileType, - pbxProj: projectProvider.pbxProj - ) - - let target = PBXNativeTarget.mock( - buildRules: [buildRule], - pbxProj: projectProvider.pbxProj) - let rules = try await mapper.mapBuildRules(target: target) - - // Unknown compiler spec means the rule should be skipped - #expect(rules.count == 0) - } - - @Test func testMapBuildRulesWithUnknownFileType() async throws { - let projectProvider = MockProjectProvider() - let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue - let unknownFileType = "sourcecode.unknown" - - let buildRule = PBXBuildRule.mock( - compilerSpec: knownCompilerSpec, - fileType: unknownFileType, - pbxProj: projectProvider.pbxProj - ) - - let target = PBXNativeTarget.mock( - buildRules: [buildRule], - pbxProj: projectProvider.pbxProj) - let rules = try await mapper.mapBuildRules(target: target) - - // Unknown file type means the rule should be skipped - #expect(rules.count == 0) - } - - @Test func testMapBuildRulesWithMixedValidAndInvalid() async throws { - let projectProvider = MockProjectProvider() - let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue - let knownFileType = BuildRule.FileType.cSource.rawValue - let unknownCompilerSpec = "com.apple.compilers.unknown" - let unknownFileType = "sourcecode.unknown" - - let validRule = PBXBuildRule.mock( - compilerSpec: knownCompilerSpec, - fileType: knownFileType, - name: "Valid Rule", - pbxProj: projectProvider.pbxProj - ) - - let invalidRuleUnknownCompiler = PBXBuildRule.mock( - compilerSpec: unknownCompilerSpec, - fileType: knownFileType, - name: "Invalid Compiler", - pbxProj: projectProvider.pbxProj - ) - - let invalidRuleUnknownFileType = PBXBuildRule.mock( - compilerSpec: knownCompilerSpec, - fileType: unknownFileType, - name: "Invalid FileType", - pbxProj: projectProvider.pbxProj - ) - - let target = PBXNativeTarget.mock( - buildRules: [validRule, invalidRuleUnknownCompiler, invalidRuleUnknownFileType], - pbxProj: projectProvider.pbxProj) - let rules = try await mapper.mapBuildRules(target: target) - - // Only the valid rule should be included - #expect(rules.count == 1) - #expect(rules.first?.name == "Valid Rule") - } + let mapper = BuildRuleMapper() + + @Test func testMapBuildRulesWithKnownCompilerSpecAndFileType() async throws { + // Using a known compiler spec from the enum, e.g. .appleClang + let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue + let knownFileType = BuildRule.FileType.cSource.rawValue + let projectProvider = MockProjectProvider() + + let buildRule = PBXBuildRule.mock( + compilerSpec: knownCompilerSpec, + fileType: knownFileType, + filePatterns: "*.c", + name: "C Rule", + outputFiles: ["$(DERIVED_FILE_DIR)/output.c.o"], + inputFiles: ["$(SRCROOT)/main.c"], + outputFilesCompilerFlags: ["-O2"], + script: "echo Building C sources", + runOncePerArchitecture: false, + pbxProj: projectProvider.pbxProj + ) + + let target = PBXNativeTarget.mock(buildRules: [buildRule], pbxProj: projectProvider.pbxProj) + let rules = try await mapper.mapBuildRules(target: target) + + #expect(rules.count == 1) + let rule = rules.first + try #require(rule != nil) + #expect(rule?.compilerSpec.rawValue == knownCompilerSpec) + #expect(rule?.fileType.rawValue == knownFileType) + #expect(rule?.filePatterns == "*.c") + #expect(rule?.name == "C Rule") + #expect(rule?.outputFiles == ["$(DERIVED_FILE_DIR)/output.c.o"]) + #expect(rule?.inputFiles == ["$(SRCROOT)/main.c"]) + #expect(rule?.outputFilesCompilerFlags == ["-O2"]) + #expect(rule?.script == "echo Building C sources") + #expect(rule?.runOncePerArchitecture == false) + } + + @Test func testMapBuildRulesWithUnknownCompilerSpec() async throws { + let projectProvider = MockProjectProvider() + let unknownCompilerSpec = "com.apple.compilers.unknown" + let knownFileType = "sourcecode.c.c" + + let buildRule = PBXBuildRule.mock( + compilerSpec: unknownCompilerSpec, + fileType: knownFileType, + pbxProj: projectProvider.pbxProj + ) + + let target = PBXNativeTarget.mock( + buildRules: [buildRule], + pbxProj: projectProvider.pbxProj + ) + let rules = try await mapper.mapBuildRules(target: target) + + // Unknown compiler spec means the rule should be skipped + #expect(rules.count == 0) + } + + @Test func testMapBuildRulesWithUnknownFileType() async throws { + let projectProvider = MockProjectProvider() + let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue + let unknownFileType = "sourcecode.unknown" + + let buildRule = PBXBuildRule.mock( + compilerSpec: knownCompilerSpec, + fileType: unknownFileType, + pbxProj: projectProvider.pbxProj + ) + + let target = PBXNativeTarget.mock( + buildRules: [buildRule], + pbxProj: projectProvider.pbxProj + ) + let rules = try await mapper.mapBuildRules(target: target) + + // Unknown file type means the rule should be skipped + #expect(rules.count == 0) + } + + @Test func testMapBuildRulesWithMixedValidAndInvalid() async throws { + let projectProvider = MockProjectProvider() + let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue + let knownFileType = BuildRule.FileType.cSource.rawValue + let unknownCompilerSpec = "com.apple.compilers.unknown" + let unknownFileType = "sourcecode.unknown" + + let validRule = PBXBuildRule.mock( + compilerSpec: knownCompilerSpec, + fileType: knownFileType, + name: "Valid Rule", + pbxProj: projectProvider.pbxProj + ) + + let invalidRuleUnknownCompiler = PBXBuildRule.mock( + compilerSpec: unknownCompilerSpec, + fileType: knownFileType, + name: "Invalid Compiler", + pbxProj: projectProvider.pbxProj + ) + + let invalidRuleUnknownFileType = PBXBuildRule.mock( + compilerSpec: knownCompilerSpec, + fileType: unknownFileType, + name: "Invalid FileType", + pbxProj: projectProvider.pbxProj + ) + + let target = PBXNativeTarget.mock( + buildRules: [validRule, invalidRuleUnknownCompiler, invalidRuleUnknownFileType], + pbxProj: projectProvider.pbxProj + ) + let rules = try await mapper.mapBuildRules(target: target) + + // Only the valid rule should be included + #expect(rules.count == 1) + #expect(rules.first?.name == "Valid Rule") + } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift index 977eb398..0f190395 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift @@ -7,253 +7,260 @@ import XcodeProj @testable import XcodeProjToGraph struct DependencyMapperTests { + let mockProvider = MockProjectProvider() + let mapper: DependencyMapping - let mockProvider = MockProjectProvider() - let mapper: DependencyMapping + init() { + mapper = DependencyMapper(projectProvider: mockProvider) + } - init() { - self.mapper = DependencyMapper(projectProvider: mockProvider) - } + @Test func testDirectTargetMapping() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let dep = PBXTargetDependency.mockTargetDependency( + name: "DirectTarget", + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) - @Test func testDirectTargetMapping() async throws { - let pbxProj = mockProvider.xcodeProj.pbxproj - let dep = PBXTargetDependency.mockTargetDependency( - name: "DirectTarget", - pbxProj: pbxProj - ) - let target = PBXNativeTarget.mock( - name: "App", - dependencies: [dep], - productType: .application, - pbxProj: pbxProj - ) + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + #expect(mapped.first == .target(name: "DirectTarget", status: .required, condition: nil)) + } - let mapped = try await mapper.mapDependencies(target: target) - #expect(mapped.count == 1) - #expect(mapped.first == .target(name: "DirectTarget", status: .required, condition: nil)) - } + @Test func testPackageProductMapping() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let dep = PBXTargetDependency.mockPackageProductDependency( + productName: "MyPackageProduct", + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) - @Test func testPackageProductMapping() async throws { - let pbxProj = mockProvider.xcodeProj.pbxproj - let dep = PBXTargetDependency.mockPackageProductDependency( - productName: "MyPackageProduct", - pbxProj: pbxProj - ) - let target = PBXNativeTarget.mock( - name: "App", - dependencies: [dep], - productType: .application, - pbxProj: pbxProj - ) + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + #expect(mapped.first == .package(product: "MyPackageProduct", type: .runtime, condition: nil)) + } - let mapped = try await mapper.mapDependencies(target: target) - #expect(mapped.count == 1) - #expect(mapped.first == .package(product: "MyPackageProduct", type: .runtime, condition: nil)) - } + @Test func testProxyNativeTarget() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + // Native target proxy referencing a target in the same project + let project = pbxProj.projects.first! + let dep = PBXTargetDependency.mockProxyDependency( + remoteInfo: "NativeTarget", + proxyType: .nativeTarget, + containerPortal: .project(project), + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) - @Test func testProxyNativeTarget() async throws { - let pbxProj = mockProvider.xcodeProj.pbxproj - // Native target proxy referencing a target in the same project - let project = pbxProj.projects.first! - let dep = PBXTargetDependency.mockProxyDependency( - remoteInfo: "NativeTarget", - proxyType: .nativeTarget, - containerPortal: .project(project), - pbxProj: pbxProj - ) - let target = PBXNativeTarget.mock( - name: "App", - dependencies: [dep], - productType: .application, - pbxProj: pbxProj - ) + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + #expect(mapped.first == .target(name: "NativeTarget", status: .required, condition: nil)) + } - let mapped = try await mapper.mapDependencies(target: target) - #expect(mapped.count == 1) - #expect(mapped.first == .target(name: "NativeTarget", status: .required, condition: nil)) - } + @Test func testProxyProjectReference() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let fileRef = PBXFileReference.mock( + path: "OtherProject.xcodeproj", + pbxProj: pbxProj + ) - @Test func testProxyProjectReference() async throws { - let pbxProj = mockProvider.xcodeProj.pbxproj - let fileRef = PBXFileReference.mock( - path: "OtherProject.xcodeproj", - pbxProj: pbxProj - ) + let dep = PBXTargetDependency.mockProxyDependency( + remoteInfo: "OtherTarget", + proxyType: .nativeTarget, + containerPortal: .fileReference(fileRef), + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) - let dep = PBXTargetDependency.mockProxyDependency( - remoteInfo: "OtherTarget", - proxyType: .nativeTarget, - containerPortal: .fileReference(fileRef), - pbxProj: pbxProj - ) - let target = PBXNativeTarget.mock( - name: "App", - dependencies: [dep], - productType: .application, - pbxProj: pbxProj - ) + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + let result = mapped.first! + let expectedPath = try AbsolutePath.resolvePath( + mockProvider.sourceDirectory.pathString + "OtherProject.xcodeproj" + ) + #expect( + result + == .project(target: "OtherTarget", path: expectedPath, status: .required, condition: nil) + ) + } - let mapped = try await mapper.mapDependencies(target: target) - #expect(mapped.count == 1) - let result = mapped.first! - let expectedPath = try AbsolutePath.resolvePath( - mockProvider.sourceDirectory.pathString + "OtherProject.xcodeproj") - #expect( - result - == .project(target: "OtherTarget", path: expectedPath, status: .required, condition: nil)) - } + @Test func testProxyReferenceProxyLibrary() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let referenceProxy = PBXReferenceProxy( + fileType: "compiled.mach-o.dylib", + path: "libTest.dylib", + remote: nil, + sourceTree: .group + ) + pbxProj.add(object: referenceProxy) - @Test func testProxyReferenceProxyLibrary() async throws { - let pbxProj = mockProvider.xcodeProj.pbxproj - let referenceProxy = PBXReferenceProxy( - fileType: "compiled.mach-o.dylib", - path: "libTest.dylib", - remote: nil, - sourceTree: .group - ) - pbxProj.add(object: referenceProxy) + let projectRef = PBXProject.mock(name: "RemoteProject", pbxProj: pbxProj) + let dep = PBXTargetDependency.mockProxyDependency( + remoteInfo: "SomeRemoteInfo", + proxyType: .reference, + containerPortal: .project(projectRef), + pbxProj: pbxProj, + remoteObject: referenceProxy + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) - let projectRef = PBXProject.mock(name: "RemoteProject", pbxProj: pbxProj) - let dep = PBXTargetDependency.mockProxyDependency( - remoteInfo: "SomeRemoteInfo", - proxyType: .reference, - containerPortal: .project(projectRef), - pbxProj: pbxProj, - remoteObject: referenceProxy - ) - let target = PBXNativeTarget.mock( - name: "App", - dependencies: [dep], - productType: .application, - pbxProj: pbxProj - ) + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + let result: TargetDependency = mapped.first! + let expectedPath = mockProvider.sourceDirectory.appending(component: "libTest.dylib") + let publicHeaders = try AbsolutePath(validating: "/tmp") + #expect( + result + == TargetDependency.library( + path: expectedPath, publicHeaders: publicHeaders, swiftModuleMap: nil, condition: nil + ) + ) + } - let mapped = try await mapper.mapDependencies(target: target) - #expect(mapped.count == 1) - let result: TargetDependency = mapped.first! - let expectedPath = mockProvider.sourceDirectory.appending(component: "libTest.dylib") - let publicHeaders = try AbsolutePath(validating: "/tmp") - #expect( - result - == TargetDependency.library( - path: expectedPath, publicHeaders: publicHeaders, swiftModuleMap: nil, condition: nil)) - } + @Test func testProxyReferenceFileFramework() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let fileRef = PBXFileReference.mock( + path: "MyLib.framework", + pbxProj: pbxProj + ) - @Test func testProxyReferenceFileFramework() async throws { - let pbxProj = mockProvider.xcodeProj.pbxproj - let fileRef = PBXFileReference.mock( - path: "MyLib.framework", - pbxProj: pbxProj - ) + let projectRef = PBXProject.mock(name: "RemoteProject", pbxProj: pbxProj) + let dep = PBXTargetDependency.mockProxyDependency( + remoteInfo: "SomeFramework", + proxyType: .reference, + containerPortal: .project(projectRef), + pbxProj: pbxProj, + remoteObject: fileRef + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) - let projectRef = PBXProject.mock(name: "RemoteProject", pbxProj: pbxProj) - let dep = PBXTargetDependency.mockProxyDependency( - remoteInfo: "SomeFramework", - proxyType: .reference, - containerPortal: .project(projectRef), - pbxProj: pbxProj, - remoteObject: fileRef - ) - let target = PBXNativeTarget.mock( - name: "App", - dependencies: [dep], - productType: .application, - pbxProj: pbxProj - ) + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + let result = mapped.first! + let expectedPath = mockProvider.sourceDirectory.appending(component: "MyLib.framework") + #expect( + result == TargetDependency.framework(path: expectedPath, status: .required, condition: nil) + ) + } - let mapped = try await mapper.mapDependencies(target: target) - #expect(mapped.count == 1) - let result = mapped.first! - let expectedPath = mockProvider.sourceDirectory.appending(component: "MyLib.framework") - #expect( - result == TargetDependency.framework(path: expectedPath, status: .required, condition: nil)) - } + @Test func testPlatformConditions() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let dep = PBXTargetDependency.mockTargetDependency( + name: "ConditionalTarget", + platformFilters: ["macos", "ios"], + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) - @Test func testPlatformConditions() async throws { - let pbxProj = mockProvider.xcodeProj.pbxproj - let dep = PBXTargetDependency.mockTargetDependency( - name: "ConditionalTarget", - platformFilters: ["macos", "ios"], - pbxProj: pbxProj - ) - let target = PBXNativeTarget.mock( - name: "App", - dependencies: [dep], - productType: .application, - pbxProj: pbxProj - ) + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + let result = mapped.first! + let condition = PlatformCondition.when([.ios, .macos]) + #expect(result == .target(name: "ConditionalTarget", status: .required, condition: condition)) + } - let mapped = try await mapper.mapDependencies(target: target) - #expect(mapped.count == 1) - let result = mapped.first! - let condition = PlatformCondition.when([.ios, .macos]) - #expect(result == .target(name: "ConditionalTarget", status: .required, condition: condition)) - } + @Test func testNoMatches() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + // A dependency with no target, no product, no proxy - unhandled + let dep = PBXTargetDependency.mock(name: nil, pbxProj: pbxProj) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) - @Test func testNoMatches() async throws { - let pbxProj = mockProvider.xcodeProj.pbxproj - // A dependency with no target, no product, no proxy - unhandled - let dep = PBXTargetDependency.mock(name: nil, pbxProj: pbxProj) - let target = PBXNativeTarget.mock( - name: "App", - dependencies: [dep], - productType: .application, - pbxProj: pbxProj - ) + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 0) + } - let mapped = try await mapper.mapDependencies(target: target) - #expect(mapped.count == 0) - } + @Test func testFileDependencyMapper() async throws { + // Test a known path extension scenario + let fdm = FileDependencyMapper(projectProvider: mockProvider) + let dependency = try await fdm.mapDependency(pathString: "libStatic.a", condition: nil) + let expectedPath = mockProvider.sourceDirectory.appending(component: "libStatic.a") + let publicHeaders = try AbsolutePath(validating: "/tmp") + #expect( + dependency + == TargetDependency.library( + path: expectedPath, publicHeaders: publicHeaders, swiftModuleMap: nil, condition: nil + ) + ) + } - @Test func testFileDependencyMapper() async throws { - // Test a known path extension scenario - let fdm = FileDependencyMapper(projectProvider: mockProvider) - let dependency = try await fdm.mapDependency(pathString: "libStatic.a", condition: nil) - let expectedPath = mockProvider.sourceDirectory.appending(component: "libStatic.a") - let publicHeaders = try AbsolutePath(validating: "/tmp") - #expect( - dependency - == TargetDependency.library( - path: expectedPath, publicHeaders: publicHeaders, swiftModuleMap: nil, condition: nil)) - } + @Test func testSinglePlatformFilter() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let dep = PBXTargetDependency.mockTargetDependency( + name: "SinglePlatform", + platformFilter: "tvos", + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) - @Test func testSinglePlatformFilter() async throws { - let pbxProj = mockProvider.xcodeProj.pbxproj - let dep = PBXTargetDependency.mockTargetDependency( - name: "SinglePlatform", - platformFilter: "tvos", - pbxProj: pbxProj - ) - let target = PBXNativeTarget.mock( - name: "App", - dependencies: [dep], - productType: .application, - pbxProj: pbxProj - ) + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + #expect( + mapped.first == .target(name: "SinglePlatform", status: .required, condition: .when([.tvos])) + ) + } - let mapped = try await mapper.mapDependencies(target: target) - #expect(mapped.count == 1) - #expect( - mapped.first == .target(name: "SinglePlatform", status: .required, condition: .when([.tvos]))) - } + @Test func testInvalidPlatformFilter() async throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let dep = PBXTargetDependency.mockTargetDependency( + name: "UnknownPlatform", + platformFilter: "weirdos", + pbxProj: pbxProj + ) + let target = PBXNativeTarget.mock( + name: "App", + dependencies: [dep], + productType: .application, + pbxProj: pbxProj + ) - @Test func testInvalidPlatformFilter() async throws { - let pbxProj = mockProvider.xcodeProj.pbxproj - let dep = PBXTargetDependency.mockTargetDependency( - name: "UnknownPlatform", - platformFilter: "weirdos", - pbxProj: pbxProj - ) - let target = PBXNativeTarget.mock( - name: "App", - dependencies: [dep], - productType: .application, - pbxProj: pbxProj - ) - - let mapped = try await mapper.mapDependencies(target: target) - #expect(mapped.count == 1) - // Unknown platform => condition == nil - #expect(mapped.first == .target(name: "UnknownPlatform", status: .required, condition: nil)) - } + let mapped = try await mapper.mapDependencies(target: target) + #expect(mapped.count == 1) + // Unknown platform => condition == nil + #expect(mapped.first == .target(name: "UnknownPlatform", status: .required, condition: nil)) + } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift index 6b249aa7..d376164b 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift @@ -7,218 +7,229 @@ import XcodeProj @testable import XcodeProjToGraph struct TargetDependencyExtensionsTests { - let sourceDirectory = try! AbsolutePath.resolvePath("/tmp/TestProject") - - // A dummy global target map for .project dependencies - let allTargetsMap: [String: Target] = [ - "MyProjectTarget": Target.test( - name: "MyProjectTarget", - product: .framework - ), - "MyProjectDynamicLibrary": Target.test( - name: "MyProjectDynamicLibrary", - product: .dynamicLibrary - ), - ] - - @Test func testTargetGraphDependency_Target() async throws { - let dependency = TargetDependency.target(name: "App", status: .required, condition: nil) - let graphDep = try await dependency.graphDependency( - sourceDirectory: sourceDirectory, - allTargetsMap: allTargetsMap - ) - #expect(graphDep == .target(name: "App", path: sourceDirectory, status: .required)) - } - - @Test func testTargetGraphDependencyFramework_Project() async throws { - let dependency = TargetDependency.project( - target: "MyProjectTarget", - path: sourceDirectory, - status: .required, - condition: nil - ) - let graphDep = try await dependency.graphDependency( - sourceDirectory: sourceDirectory, - allTargetsMap: allTargetsMap - ) - - #expect( - ({ - switch graphDep { - case let .framework(path, binaryPath, _, _, linking, archs, status): - return path == sourceDirectory - && binaryPath == sourceDirectory.appending(component: "MyProjectTarget.framework") - && linking == .dynamic && archs.isEmpty && status == .required - default: - return false - } - })() != false) - } - - @Test func testTargetGraphDependencyLibrary_Project() async throws { - let dependency = TargetDependency.project( - target: "MyProjectDynamicLibrary", - path: sourceDirectory, - status: .required, - condition: nil - ) - let graphDep = try await dependency.graphDependency( - sourceDirectory: sourceDirectory, - allTargetsMap: allTargetsMap - ) - - switch graphDep { - case let .library(path, _, linking, _, _): - #expect( - path.pathString - == sourceDirectory.appending(component: "libMyProjectDynamicLibrary.dylib").pathString) - #expect(linking == .dynamic) - default: - Issue.record() + let sourceDirectory = try! AbsolutePath.resolvePath("/tmp/TestProject") + + // A dummy global target map for .project dependencies + let allTargetsMap: [String: Target] = [ + "MyProjectTarget": Target.test( + name: "MyProjectTarget", + product: .framework + ), + "MyProjectDynamicLibrary": Target.test( + name: "MyProjectDynamicLibrary", + product: .dynamicLibrary + ), + ] + + @Test func testTargetGraphDependency_Target() async throws { + let dependency = TargetDependency.target(name: "App", status: .required, condition: nil) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: allTargetsMap + ) + #expect(graphDep == .target(name: "App", path: sourceDirectory, status: .required)) } - } - - @Test func testTargetGraphDependency_Framework() async throws { - let frameworkPath = sourceDirectory.appending(component: "MyFramework.framework") - let dependency = TargetDependency.framework( - path: frameworkPath, status: .required, condition: nil) - let graphDep = try await dependency.graphDependency( - sourceDirectory: sourceDirectory, - allTargetsMap: [:] - ) - - #expect( - ({ - switch graphDep { - case let .framework(path, binaryPath, _, _, linking, archs, status): - return path == frameworkPath - && binaryPath == frameworkPath.appending(component: "MyFramework") - && linking == .dynamic && archs.isEmpty && status == .required - default: - return false - } - })() != false) - } - - @Test func testTargetGraphDependency_XCFramework() async throws { - let xcframeworkPath = sourceDirectory.appending(component: "MyXCFramework.xcframework") - let dependency = TargetDependency.xcframework( - path: xcframeworkPath, status: .required, condition: nil) - let graphDep = try await dependency.graphDependency( - sourceDirectory: sourceDirectory, - allTargetsMap: [:] - ) - - #expect( - ({ - switch graphDep { - case let .xcframework(info): - return info.path == xcframeworkPath && info.linking == .dynamic - && info.status == .required - default: - return false - } - })() != false) - } - - @Test func testTargetGraphDependency_Library() async throws { - let libPath = sourceDirectory.appending(component: "libMyLib.a") - let headersPath = sourceDirectory.appending(component: "include") - let dependency = TargetDependency.library( - path: libPath, - publicHeaders: headersPath, - swiftModuleMap: nil, - condition: nil - ) - let graphDep = try await dependency.graphDependency( - sourceDirectory: sourceDirectory, - allTargetsMap: [:] - ) - - #expect( - ({ - switch graphDep { - case let .library(path, publicHeaders, linking, archs, swiftModuleMap): - return path == libPath && publicHeaders == headersPath && linking == .static - && archs.isEmpty && swiftModuleMap == nil - default: - return false - } - })() != false) - } - - @Test func testTargetGraphDependency_Package() async throws { - let dependency = TargetDependency.package( - product: "MyPackageProduct", type: .runtime, condition: nil) - let graphDep = try await dependency.graphDependency( - sourceDirectory: sourceDirectory, - allTargetsMap: [:] - ) - - #expect( - graphDep - == .packageProduct(path: sourceDirectory, product: "MyPackageProduct", type: .runtime)) - } - - @Test func testTargetGraphDependency_SDK() async throws { - let dependency = TargetDependency.sdk(name: "MySDK", status: .optional, condition: nil) - let graphDep = try await dependency.graphDependency( - sourceDirectory: sourceDirectory, - allTargetsMap: [:] - ) - - #expect( - ({ + + @Test func testTargetGraphDependencyFramework_Project() async throws { + let dependency = TargetDependency.project( + target: "MyProjectTarget", + path: sourceDirectory, + status: .required, + condition: nil + ) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: allTargetsMap + ) + + #expect( + ({ + switch graphDep { + case let .framework(path, binaryPath, _, _, linking, archs, status): + return path == sourceDirectory + && binaryPath == sourceDirectory.appending(component: "MyProjectTarget.framework") + && linking == .dynamic && archs.isEmpty && status == .required + default: + return false + } + })() != false + ) + } + + @Test func testTargetGraphDependencyLibrary_Project() async throws { + let dependency = TargetDependency.project( + target: "MyProjectDynamicLibrary", + path: sourceDirectory, + status: .required, + condition: nil + ) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: allTargetsMap + ) + switch graphDep { - case let .sdk(name, path, status, source): - return name == "MySDK" && path == sourceDirectory && status == .optional - && source == .developer + case let .library(path, _, linking, _, _): + #expect( + path.pathString + == sourceDirectory.appending(component: "libMyProjectDynamicLibrary.dylib").pathString + ) + #expect(linking == .dynamic) default: - return false + Issue.record() } - })() != false) - } - - @Test func testTargetGraphDependency_XCTest() async throws { - let dependency = TargetDependency.xctest - let graphDep = try await dependency.graphDependency( - sourceDirectory: sourceDirectory, - allTargetsMap: [:] - ) - - #expect( - ({ - switch graphDep { - case let .xcframework(info): - return info.path == sourceDirectory && info.linking == .dynamic - && info.status == .required - default: - return false + } + + @Test func testTargetGraphDependency_Framework() async throws { + let frameworkPath = sourceDirectory.appending(component: "MyFramework.framework") + let dependency = TargetDependency.framework( + path: frameworkPath, status: .required, condition: nil + ) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: [:] + ) + + #expect( + ({ + switch graphDep { + case let .framework(path, binaryPath, _, _, linking, archs, status): + return path == frameworkPath + && binaryPath == frameworkPath.appending(component: "MyFramework") + && linking == .dynamic && archs.isEmpty && status == .required + default: + return false + } + })() != false + ) + } + + @Test func testTargetGraphDependency_XCFramework() async throws { + let xcframeworkPath = sourceDirectory.appending(component: "MyXCFramework.xcframework") + let dependency = TargetDependency.xcframework( + path: xcframeworkPath, status: .required, condition: nil + ) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: [:] + ) + + #expect( + ({ + switch graphDep { + case let .xcframework(info): + return info.path == xcframeworkPath && info.linking == .dynamic + && info.status == .required + default: + return false + } + })() != false + ) + } + + @Test func testTargetGraphDependency_Library() async throws { + let libPath = sourceDirectory.appending(component: "libMyLib.a") + let headersPath = sourceDirectory.appending(component: "include") + let dependency = TargetDependency.library( + path: libPath, + publicHeaders: headersPath, + swiftModuleMap: nil, + condition: nil + ) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: [:] + ) + + #expect( + ({ + switch graphDep { + case let .library(path, publicHeaders, linking, archs, swiftModuleMap): + return path == libPath && publicHeaders == headersPath && linking == .static + && archs.isEmpty && swiftModuleMap == nil + default: + return false + } + })() != false + ) + } + + @Test func testTargetGraphDependency_Package() async throws { + let dependency = TargetDependency.package( + product: "MyPackageProduct", type: .runtime, condition: nil + ) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: [:] + ) + + #expect( + graphDep + == .packageProduct(path: sourceDirectory, product: "MyPackageProduct", type: .runtime) + ) + } + + @Test func testTargetGraphDependency_SDK() async throws { + let dependency = TargetDependency.sdk(name: "MySDK", status: .optional, condition: nil) + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: [:] + ) + + #expect( + ({ + switch graphDep { + case let .sdk(name, path, status, source): + return name == "MySDK" && path == sourceDirectory && status == .optional + && source == .developer + default: + return false + } + })() != false + ) + } + + @Test func testTargetGraphDependency_XCTest() async throws { + let dependency = TargetDependency.xctest + let graphDep = try await dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: [:] + ) + + #expect( + ({ + switch graphDep { + case let .xcframework(info): + return info.path == sourceDirectory && info.linking == .dynamic + && info.status == .required + default: + return false + } + })() != false + ) + } + + @Test func testMapProjectGraphDependency_TargetNotFound() async throws { + let dependency = TargetDependency.project( + target: "NonExistentTarget", + path: sourceDirectory, + status: .required, + condition: nil + ) + + do { + _ = try await dependency.graphDependency(sourceDirectory: sourceDirectory, allTargetsMap: [:]) + Issue.record("Expected to throw MappingError.targetNotFound") + } catch let error as MappingError { + switch error { + case let .targetNotFound(targetName, path): + #expect(targetName == "NonExistentTarget") + #expect(path == sourceDirectory) + default: + Issue.record("Unexpected MappingError: \(error)") + } + } catch { + Issue.record("Unexpected error: \(error)") } - })() != false) - } - - @Test func testMapProjectGraphDependency_TargetNotFound() async throws { - let dependency = TargetDependency.project( - target: "NonExistentTarget", - path: sourceDirectory, - status: .required, - condition: nil - ) - - do { - _ = try await dependency.graphDependency(sourceDirectory: sourceDirectory, allTargetsMap: [:]) - Issue.record("Expected to throw MappingError.targetNotFound") - } catch let error as MappingError { - switch error { - case .targetNotFound(let targetName, let path): - #expect(targetName == "NonExistentTarget") - #expect(path == sourceDirectory) - default: - Issue.record("Unexpected MappingError: \(error)") - } - } catch { - Issue.record("Unexpected error: \(error)") } - } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift index 4f48f28f..9069d6d6 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift @@ -7,181 +7,180 @@ import XcodeProj @testable import XcodeProjToGraph struct GraphMapperTests { - - @Test func testSingleProjectGraph() async throws { - // Setup a mock provider and a single project scenario - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/SingleProject", - projectName: "SingleProject" - ) - - // Add a single target to the project - let pbxProj = mockProvider.xcodeProj.pbxproj - let target = PBXNativeTarget.mock( - name: "App", - productType: .application, - pbxProj: pbxProj - ) - if let project = pbxProj.projects.first { - project.targets.append(target) - } - - // GraphType for a single project - let projectPath = try AbsolutePath(validating: mockProvider.sourceDirectory.pathString) - let graphType = GraphType.project(projectPath) - - // Provide a closure that returns the mock provider - let mapper = GraphMapper(graphType: graphType) { path in - // We only handle this single path scenario - #expect(path == projectPath) - return mockProvider + @Test func testSingleProjectGraph() async throws { + // Setup a mock provider and a single project scenario + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/SingleProject", + projectName: "SingleProject" + ) + + // Add a single target to the project + let pbxProj = mockProvider.xcodeProj.pbxproj + let target = PBXNativeTarget.mock( + name: "App", + productType: .application, + pbxProj: pbxProj + ) + if let project = pbxProj.projects.first { + project.targets.append(target) + } + + // GraphType for a single project + let projectPath = try AbsolutePath(validating: mockProvider.sourceDirectory.pathString) + let graphType = GraphType.project(projectPath) + + // Provide a closure that returns the mock provider + let mapper = GraphMapper(graphType: graphType) { path in + // We only handle this single path scenario + #expect(path == projectPath) + return mockProvider + } + + let graph = try await mapper.xcodeGraph() + + // Validate that the returned graph matches our expectations + #expect(graph.name == "Workspace") + #expect(graph.projects.count == 1) + #expect(graph.packages == [:]) + #expect(graph.dependencies == [:]) + #expect(graph.dependencyConditions == [:]) + + // Check that the workspace is created as a wrapper around the single project + #expect(graph.workspace.projects.count == 1) + #expect(graph.workspace.projects.first == projectPath) + #expect(graph.workspace.name == "Workspace") } - let graph = try await mapper.xcodeGraph() - - // Validate that the returned graph matches our expectations - #expect(graph.name == "Workspace") - #expect(graph.projects.count == 1) - #expect(graph.packages == [:]) - #expect(graph.dependencies == [:]) - #expect(graph.dependencyConditions == [:]) - - // Check that the workspace is created as a wrapper around the single project - #expect(graph.workspace.projects.count == 1) - #expect(graph.workspace.projects.first == projectPath) - #expect(graph.workspace.name == "Workspace") - } - - @Test func testWorkspaceGraphMultipleProjects() async throws { - // Setup two mock projects - let mockProviderA = MockProjectProvider( - sourceDirectory: "/tmp/Workspace/ProjectA", - projectName: "ProjectA" - ) - let mockProviderB = MockProjectProvider( - sourceDirectory: "/tmp/Workspace/ProjectB", - projectName: "ProjectB" - ) - - // Add a target to Project A - let pbxProjA = mockProviderA.xcodeProj.pbxproj - let targetA = PBXNativeTarget.mock( - name: "ATarget", - productType: .framework, - pbxProj: pbxProjA - ) - if let projectA = pbxProjA.projects.first { - projectA.targets.append(targetA) + @Test func testWorkspaceGraphMultipleProjects() async throws { + // Setup two mock projects + let mockProviderA = MockProjectProvider( + sourceDirectory: "/tmp/Workspace/ProjectA", + projectName: "ProjectA" + ) + let mockProviderB = MockProjectProvider( + sourceDirectory: "/tmp/Workspace/ProjectB", + projectName: "ProjectB" + ) + + // Add a target to Project A + let pbxProjA = mockProviderA.xcodeProj.pbxproj + let targetA = PBXNativeTarget.mock( + name: "ATarget", + productType: .framework, + pbxProj: pbxProjA + ) + if let projectA = pbxProjA.projects.first { + projectA.targets.append(targetA) + } + + // Add a target to Project B + let pbxProjB = mockProviderB.xcodeProj.pbxproj + let targetB = PBXNativeTarget.mock( + name: "BTarget", + productType: .framework, + pbxProj: pbxProjB + ) + if let projectB = pbxProjB.projects.first { + projectB.targets.append(targetB) + } + + // Setup a workspace that references these two projects + let workspacePath = try AbsolutePath(validating: "/tmp/Workspace") + let projectAPath = try AbsolutePath(validating: "/tmp/Workspace/ProjectA.xcodeproj") + let projectBPath = try AbsolutePath(validating: "/tmp/Workspace/ProjectB.xcodeproj") + + let xcworkspace = XCWorkspace( + data: XCWorkspaceData(children: [ + .file(.init(location: .absolute(projectAPath.pathString))), + .file(.init(location: .absolute(projectBPath.pathString))), + + ]) + ) + + let provider = MockWorkspaceProvider(xcWorkspacePath: workspacePath, xcworkspace: xcworkspace) + + let graphType = GraphType.workspace(provider) + + // Provide a closure that returns the corresponding mock provider based on the project path + let mapper = GraphMapper(graphType: graphType) { path in + if path == projectAPath { + return mockProviderA + } else if path == projectBPath { + return mockProviderB + } else { + Issue.record("Unexpected project path requested: \(path)") + throw MappingError.noProjectsFound + } + } + + let graph = try await mapper.xcodeGraph() + + // Validate the graph + #expect(graph.workspace.name == "Workspace") + #expect(graph.workspace.projects.contains(projectAPath) == true) + #expect(graph.workspace.projects.contains(projectBPath) == true) + + // Check projects in the graph + #expect(graph.projects.count == 2) + let projectA = graph.projects[projectAPath] + let projectB = graph.projects[projectBPath] + try #require(projectA != nil) + try #require(projectB != nil) + #expect(projectA?.targets["ATarget"] != nil) + #expect(projectB?.targets["BTarget"] != nil) + + // Since we didn’t add packages or dependencies, these should be empty + #expect(graph.packages.isEmpty == true) + #expect(graph.dependencies.isEmpty == true) + #expect(graph.dependencyConditions.isEmpty == true) } - // Add a target to Project B - let pbxProjB = mockProviderB.xcodeProj.pbxproj - let targetB = PBXNativeTarget.mock( - name: "BTarget", - productType: .framework, - pbxProj: pbxProjB - ) - if let projectB = pbxProjB.projects.first { - projectB.targets.append(targetB) + @Test func testGraphWithDependencies() async throws { + // Example test to confirm dependency mapping works + // Setup a single project with two targets: App depends on AFramework + + let mockProvider = MockProjectProvider( + sourceDirectory: "/tmp/ProjectWithDeps", + projectName: "ProjectWithDeps" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let frameworkTarget = PBXNativeTarget.mock( + name: "AFramework", + productType: .framework, + pbxProj: pbxProj + ) + + let appTarget = PBXNativeTarget.mock( + name: "App", + productType: .application, + pbxProj: pbxProj + ) + + // Add a target dependency from App to AFramework + let dep = PBXTargetDependency.mockTargetDependency( + name: "AFramework", + pbxProj: pbxProj + ) + appTarget.dependencies.append(dep) + + if let project = pbxProj.projects.first { + project.targets.append(contentsOf: [frameworkTarget, appTarget]) + } + + let projectPath = try AbsolutePath(validating: mockProvider.xcodeProjPath.pathString) + let graphType = GraphType.project(projectPath) + + let mapper = GraphMapper(graphType: graphType) { path in + #expect(path == projectPath) + return mockProvider + } + + let graph = try await mapper.xcodeGraph() + + // Check that dependencies are mapped + let sourceDep = GraphDependency.target(name: "App", path: mockProvider.sourceDirectory) + let targetDep = GraphDependency.target(name: "AFramework", path: mockProvider.sourceDirectory) + #expect(graph.dependencies == [sourceDep: [targetDep]]) } - - // Setup a workspace that references these two projects - let workspacePath = try AbsolutePath(validating: "/tmp/Workspace") - let projectAPath = try AbsolutePath(validating: "/tmp/Workspace/ProjectA.xcodeproj") - let projectBPath = try AbsolutePath(validating: "/tmp/Workspace/ProjectB.xcodeproj") - - let xcworkspace = XCWorkspace( - data: XCWorkspaceData(children: [ - .file(.init(location: .absolute(projectAPath.pathString))), - .file(.init(location: .absolute(projectBPath.pathString))), - - ]) - ) - - let provider = MockWorkspaceProvider(xcWorkspacePath: workspacePath, xcworkspace: xcworkspace) - - let graphType = GraphType.workspace(provider) - - // Provide a closure that returns the corresponding mock provider based on the project path - let mapper = GraphMapper(graphType: graphType) { path in - if path == projectAPath { - return mockProviderA - } else if path == projectBPath { - return mockProviderB - } else { - Issue.record("Unexpected project path requested: \(path)") - throw MappingError.noProjectsFound - } - } - - let graph = try await mapper.xcodeGraph() - - // Validate the graph - #expect(graph.workspace.name == "Workspace") - #expect(graph.workspace.projects.contains(projectAPath) == true) - #expect(graph.workspace.projects.contains(projectBPath) == true) - - // Check projects in the graph - #expect(graph.projects.count == 2) - let projectA = graph.projects[projectAPath] - let projectB = graph.projects[projectBPath] - try #require(projectA != nil) - try #require(projectB != nil) - #expect(projectA?.targets["ATarget"] != nil) - #expect(projectB?.targets["BTarget"] != nil) - - // Since we didn’t add packages or dependencies, these should be empty - #expect(graph.packages.isEmpty == true) - #expect(graph.dependencies.isEmpty == true) - #expect(graph.dependencyConditions.isEmpty == true) - } - - @Test func testGraphWithDependencies() async throws { - // Example test to confirm dependency mapping works - // Setup a single project with two targets: App depends on AFramework - - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/ProjectWithDeps", - projectName: "ProjectWithDeps" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - let frameworkTarget = PBXNativeTarget.mock( - name: "AFramework", - productType: .framework, - pbxProj: pbxProj - ) - - let appTarget = PBXNativeTarget.mock( - name: "App", - productType: .application, - pbxProj: pbxProj - ) - - // Add a target dependency from App to AFramework - let dep = PBXTargetDependency.mockTargetDependency( - name: "AFramework", - pbxProj: pbxProj - ) - appTarget.dependencies.append(dep) - - if let project = pbxProj.projects.first { - project.targets.append(contentsOf: [frameworkTarget, appTarget]) - } - - let projectPath = try AbsolutePath(validating: mockProvider.xcodeProjPath.pathString) - let graphType = GraphType.project(projectPath) - - let mapper = GraphMapper(graphType: graphType) { path in - #expect(path == projectPath) - return mockProvider - } - - let graph = try await mapper.xcodeGraph() - - // Check that dependencies are mapped - let sourceDep = GraphDependency.target(name: "App", path: mockProvider.sourceDirectory) - let targetDep = GraphDependency.target(name: "AFramework", path: mockProvider.sourceDirectory) - #expect(graph.dependencies == [sourceDep: [targetDep]]) - } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift index 8aa5ebc3..4c46b9c7 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift @@ -7,127 +7,130 @@ import XcodeProj @testable import XcodeProjToGraph struct PackageMapperTests { - let mapper: PackageMapper - let projectProvider: MockProjectProvider - - init() { - let provider = MockProjectProvider() - self.projectProvider = provider - self.mapper = PackageMapper(projectProvider: provider) - } - - @Test func testMapPackageWithValidURL() async throws { - let package = XCRemoteSwiftPackageReference.mock( - repositoryURL: "https://github.com/example/package.git", - versionRequirement: .upToNextMajorVersion("1.0.0") - ) - - let result = try await mapper.map(package: package) - #expect( - result - == .remote( - url: "https://github.com/example/package.git", requirement: .upToNextMajor("1.0.0"))) - } - - @Test func testMapRequirementUpToNextMajor() async throws { - let package = XCRemoteSwiftPackageReference.mock( - repositoryURL: "https://github.com/example/package.git", - versionRequirement: .upToNextMajorVersion("1.0.0") - ) - - let requirement = await mapper.mapRequirement(package: package) - #expect(requirement == .upToNextMajor("1.0.0")) - } - - @Test func testMapRequirementUpToNextMinor() async throws { - let package = XCRemoteSwiftPackageReference.mock( - repositoryURL: "https://github.com/example/package.git", - versionRequirement: .upToNextMinorVersion("1.2.0") - ) - - let requirement = await mapper.mapRequirement(package: package) - #expect(requirement == .upToNextMinor("1.2.0")) - } - - @Test func testMapRequirementExact() async throws { - let package = XCRemoteSwiftPackageReference.mock( - repositoryURL: "https://github.com/example/package.git", - versionRequirement: .exact("1.2.3") - ) - - let requirement = await mapper.mapRequirement(package: package) - #expect(requirement == .exact("1.2.3")) - } - - @Test func testMapRequirementRange() async throws { - let package = XCRemoteSwiftPackageReference.mock( - repositoryURL: "https://github.com/example/package.git", - versionRequirement: .range(from: "1.0.0", to: "2.0.0") - ) - - let requirement = await mapper.mapRequirement(package: package) - #expect(requirement == .range(from: "1.0.0", to: "2.0.0")) - } - - @Test func testMapRequirementBranch() async throws { - let package = XCRemoteSwiftPackageReference.mock( - repositoryURL: "https://github.com/example/package.git", - versionRequirement: .branch("main") - ) - - let requirement = await mapper.mapRequirement(package: package) - #expect(requirement == .branch("main")) - } - - @Test func testMapRequirementRevision() async throws { - let package = XCRemoteSwiftPackageReference.mock( - repositoryURL: "https://github.com/example/package.git", - versionRequirement: .revision("abc123") - ) - - let requirement = await mapper.mapRequirement(package: package) - #expect(requirement == .revision("abc123")) - } - - @Test func testMapRequirementNoVersionRequirement() async throws { - let package = XCRemoteSwiftPackageReference.mock( - repositoryURL: "https://github.com/example/package.git", - versionRequirement: nil - ) - - let requirement = await mapper.mapRequirement(package: package) - #expect(requirement == .upToNextMajor("0.0.0")) - } - - @Test func testMapLocalPackage() async throws { - // Arrange - let localPackage = XCLocalSwiftPackageReference.mock(relativePath: "Packages/Example") - - // Act - let result = try await mapper.map(package: localPackage) - - // Assert - let expectedPath = projectProvider.sourceDirectory.appending( - try RelativePath(validating: "Packages/Example")) - #expect(result == .local(path: expectedPath)) - } + let mapper: PackageMapper + let projectProvider: MockProjectProvider + + init() { + let provider = MockProjectProvider() + projectProvider = provider + mapper = PackageMapper(projectProvider: provider) + } + + @Test func testMapPackageWithValidURL() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .upToNextMajorVersion("1.0.0") + ) + + let result = try await mapper.map(package: package) + #expect( + result + == .remote( + url: "https://github.com/example/package.git", requirement: .upToNextMajor("1.0.0") + ) + ) + } + + @Test func testMapRequirementUpToNextMajor() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .upToNextMajorVersion("1.0.0") + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .upToNextMajor("1.0.0")) + } + + @Test func testMapRequirementUpToNextMinor() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .upToNextMinorVersion("1.2.0") + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .upToNextMinor("1.2.0")) + } + + @Test func testMapRequirementExact() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .exact("1.2.3") + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .exact("1.2.3")) + } + + @Test func testMapRequirementRange() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .range(from: "1.0.0", to: "2.0.0") + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .range(from: "1.0.0", to: "2.0.0")) + } + + @Test func testMapRequirementBranch() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .branch("main") + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .branch("main")) + } + + @Test func testMapRequirementRevision() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .revision("abc123") + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .revision("abc123")) + } + + @Test func testMapRequirementNoVersionRequirement() async throws { + let package = XCRemoteSwiftPackageReference.mock( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: nil + ) + + let requirement = await mapper.mapRequirement(package: package) + #expect(requirement == .upToNextMajor("0.0.0")) + } + + @Test func testMapLocalPackage() async throws { + // Arrange + let localPackage = XCLocalSwiftPackageReference.mock(relativePath: "Packages/Example") + + // Act + let result = try await mapper.map(package: localPackage) + + // Assert + let expectedPath = projectProvider.sourceDirectory.appending( + try RelativePath(validating: "Packages/Example") + ) + #expect(result == .local(path: expectedPath)) + } } // Extension to support testing extension XCRemoteSwiftPackageReference { - static func mock( - repositoryURL: String, - versionRequirement: VersionRequirement? - ) -> XCRemoteSwiftPackageReference { - return XCRemoteSwiftPackageReference( - repositoryURL: repositoryURL, - versionRequirement: versionRequirement - ) - } + static func mock( + repositoryURL: String, + versionRequirement: VersionRequirement? + ) -> XCRemoteSwiftPackageReference { + return XCRemoteSwiftPackageReference( + repositoryURL: repositoryURL, + versionRequirement: versionRequirement + ) + } } extension XCLocalSwiftPackageReference { - static func mock(relativePath: String) -> XCLocalSwiftPackageReference { - return XCLocalSwiftPackageReference(relativePath: relativePath) - } + static func mock(relativePath: String) -> XCLocalSwiftPackageReference { + return XCLocalSwiftPackageReference(relativePath: relativePath) + } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift index b0b5b830..293940cd 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift @@ -7,152 +7,151 @@ import XcodeProj @testable import XcodeProjToGraph struct ProjectMapperTests { + @Test func testMapBasicProject() async throws { + let mockProvider = MockProjectProvider() + let mapper = ProjectMapper(projectProvider: mockProvider) - @Test func testMapBasicProject() async throws { - let mockProvider = MockProjectProvider() - let mapper = ProjectMapper(projectProvider: mockProvider) - - let project = try await mapper.mapProject() - - #expect(project.name == "TestProject") - #expect(project.path == mockProvider.sourceDirectory) - #expect(project.sourceRootPath == mockProvider.sourceDirectory) - #expect(project.xcodeProjPath == mockProvider.sourceDirectory) - #expect(project.type == .local) - } - - @Test func testMapProjectWithCustomAttributes() async throws { - let pbxProj = PBXProj() - let provider = MockProjectProvider( - projectName: "CustomProject", - pbxProj: pbxProj - ) - - let mapper = ProjectMapper(projectProvider: provider) - - let customAttributes: [String: Any] = [ - "ORGANIZATIONNAME": "Example Org", - "CLASSPREFIX": "EX", - "LastUpgradeCheck": "1500", - ] - - provider.pbxProj.projects.first?.attributes = customAttributes - - let project = try await mapper.mapProject() - - #expect(project.name == "CustomProject") - #expect(project.organizationName == "Example Org") - #expect(project.classPrefix == "EX") - #expect(project.lastUpgradeCheck == "1500") - } - - @Test func testMapProjectWithTargets() async throws { - - let mockProvider = MockProjectProvider() - - let configList = XCConfigurationList.mock( - configs: [("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"])], - proj: mockProvider.pbxProj) - - let mapper = ProjectMapper(projectProvider: mockProvider) - - let target = PBXNativeTarget.mock( - name: "ExampleApp", - buildConfigurationList: configList, - productType: .application, - pbxProj: mockProvider.pbxProj - ) - try mockProvider.pbxProject().targets.append(target) - - let project = try await mapper.mapProject() - print(project.targets) - #expect(project.targets.count == 1) - #expect(project.targets.first?.value.name == "ExampleApp") - #expect(project.targets.first?.value.product == .app) - } - - @Test func testMapProjectWithRemotePackages() async throws { - let mockProvider = MockProjectProvider() - let package = XCRemoteSwiftPackageReference( - repositoryURL: "https://github.com/example/package.git", - versionRequirement: .upToNextMajorVersion("1.0.0") - ) - mockProvider.pbxProj.add(object: package) - try mockProvider.pbxProject().remotePackages.append(package) - let mapper = ProjectMapper(projectProvider: mockProvider) - - let project = try await mapper.mapProject() - - #expect(project.packages.count == 1) - guard case let .remote(url, requirement) = project.packages[0] else { - Issue.record("Expected remote package") - return + let project = try await mapper.mapProject() + + #expect(project.name == "TestProject") + #expect(project.path == mockProvider.sourceDirectory) + #expect(project.sourceRootPath == mockProvider.sourceDirectory) + #expect(project.xcodeProjPath == mockProvider.sourceDirectory) + #expect(project.type == .local) + } + + @Test func testMapProjectWithCustomAttributes() async throws { + let pbxProj = PBXProj() + let provider = MockProjectProvider( + projectName: "CustomProject", + pbxProj: pbxProj + ) + + let mapper = ProjectMapper(projectProvider: provider) + + let customAttributes: [String: Any] = [ + "ORGANIZATIONNAME": "Example Org", + "CLASSPREFIX": "EX", + "LastUpgradeCheck": "1500", + ] + + provider.pbxProj.projects.first?.attributes = customAttributes + + let project = try await mapper.mapProject() + + #expect(project.name == "CustomProject") + #expect(project.organizationName == "Example Org") + #expect(project.classPrefix == "EX") + #expect(project.lastUpgradeCheck == "1500") + } + + @Test func testMapProjectWithTargets() async throws { + let mockProvider = MockProjectProvider() + + let configList = XCConfigurationList.mock( + configs: [("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"])], + proj: mockProvider.pbxProj + ) + + let mapper = ProjectMapper(projectProvider: mockProvider) + + let target = PBXNativeTarget.mock( + name: "ExampleApp", + buildConfigurationList: configList, + productType: .application, + pbxProj: mockProvider.pbxProj + ) + try mockProvider.pbxProject().targets.append(target) + + let project = try await mapper.mapProject() + print(project.targets) + #expect(project.targets.count == 1) + #expect(project.targets.first?.value.name == "ExampleApp") + #expect(project.targets.first?.value.product == .app) + } + + @Test func testMapProjectWithRemotePackages() async throws { + let mockProvider = MockProjectProvider() + let package = XCRemoteSwiftPackageReference( + repositoryURL: "https://github.com/example/package.git", + versionRequirement: .upToNextMajorVersion("1.0.0") + ) + mockProvider.pbxProj.add(object: package) + try mockProvider.pbxProject().remotePackages.append(package) + let mapper = ProjectMapper(projectProvider: mockProvider) + + let project = try await mapper.mapProject() + + #expect(project.packages.count == 1) + guard case let .remote(url, requirement) = project.packages[0] else { + Issue.record("Expected remote package") + return + } + #expect(url == "https://github.com/example/package.git") + #expect(requirement == .upToNextMajor("1.0.0")) + } + + @Test func testMapProjectWithKnownRegions() async throws { + let mockProvider = MockProjectProvider() + try mockProvider.pbxProject().knownRegions = ["en", "es", "fr"] + let mapper = ProjectMapper(projectProvider: mockProvider) + + let project = try await mapper.mapProject() + + #expect(project.defaultKnownRegions?.count == 3) + #expect(project.defaultKnownRegions?.contains("en") == true) + #expect(project.defaultKnownRegions?.contains("es") == true) + #expect(project.defaultKnownRegions?.contains("fr") == true) + } + + @Test func testMapProjectWithDevelopmentRegion() async throws { + let mockProvider = MockProjectProvider() + try mockProvider.pbxProject().developmentRegion = "fr" + let mapper = ProjectMapper(projectProvider: mockProvider) + + let project = try await mapper.mapProject() + + #expect(project.developmentRegion == "fr") + } + + @Test func testMapProjectWithResourceSynthesizers() async throws { + let mockProvider = MockProjectProvider() + let mapper = ProjectMapper(projectProvider: mockProvider) + + let project = try await mapper.mapProject() + + // Test for expected resource synthesizers + let synthesizers = project.resourceSynthesizers + + // Check for strings synthesizer + let stringsSynthesizer = synthesizers.first { $0.parser == .strings } + #expect(stringsSynthesizer != nil) + #expect(stringsSynthesizer?.extensions.contains("strings") == true) + #expect(stringsSynthesizer?.extensions.contains("stringsdict") == true) + + // Check for assets synthesizer + let assetsSynthesizer = synthesizers.first { $0.parser == .assets } + #expect(assetsSynthesizer != nil) + #expect(assetsSynthesizer?.extensions.contains("xcassets") == true) + + // Verify all expected synthesizer types are present + let expectedParsers: Set = [ + .strings, .assets, .plists, .fonts, .coreData, + .interfaceBuilder, .json, .yaml, .files, + ] + let actualParsers = Set(synthesizers.map(\.parser)) + #expect(actualParsers == expectedParsers) + } + + @Test func testMapProjectWithSchemes() async throws { + let mockProvider = MockProjectProvider() + let scheme = XCScheme.mock(name: "TestScheme") + mockProvider.xcodeProj.sharedData = XCSharedData(schemes: [scheme]) + let mapper = ProjectMapper(projectProvider: mockProvider) + + let project = try await mapper.mapProject() + + #expect(project.schemes.count == 1) + #expect(project.schemes[0].name == "TestScheme") } - #expect(url == "https://github.com/example/package.git") - #expect(requirement == .upToNextMajor("1.0.0")) - } - - @Test func testMapProjectWithKnownRegions() async throws { - let mockProvider = MockProjectProvider() - try mockProvider.pbxProject().knownRegions = ["en", "es", "fr"] - let mapper = ProjectMapper(projectProvider: mockProvider) - - let project = try await mapper.mapProject() - - #expect(project.defaultKnownRegions?.count == 3) - #expect(project.defaultKnownRegions?.contains("en") == true) - #expect(project.defaultKnownRegions?.contains("es") == true) - #expect(project.defaultKnownRegions?.contains("fr") == true) - } - - @Test func testMapProjectWithDevelopmentRegion() async throws { - let mockProvider = MockProjectProvider() - try mockProvider.pbxProject().developmentRegion = "fr" - let mapper = ProjectMapper(projectProvider: mockProvider) - - let project = try await mapper.mapProject() - - #expect(project.developmentRegion == "fr") - } - - @Test func testMapProjectWithResourceSynthesizers() async throws { - let mockProvider = MockProjectProvider() - let mapper = ProjectMapper(projectProvider: mockProvider) - - let project = try await mapper.mapProject() - - // Test for expected resource synthesizers - let synthesizers = project.resourceSynthesizers - - // Check for strings synthesizer - let stringsSynthesizer = synthesizers.first { $0.parser == .strings } - #expect(stringsSynthesizer != nil) - #expect(stringsSynthesizer?.extensions.contains("strings") == true) - #expect(stringsSynthesizer?.extensions.contains("stringsdict") == true) - - // Check for assets synthesizer - let assetsSynthesizer = synthesizers.first { $0.parser == .assets } - #expect(assetsSynthesizer != nil) - #expect(assetsSynthesizer?.extensions.contains("xcassets") == true) - - // Verify all expected synthesizer types are present - let expectedParsers: Set = [ - .strings, .assets, .plists, .fonts, .coreData, - .interfaceBuilder, .json, .yaml, .files, - ] - let actualParsers = Set(synthesizers.map(\.parser)) - #expect(actualParsers == expectedParsers) - } - - @Test func testMapProjectWithSchemes() async throws { - let mockProvider = MockProjectProvider() - let scheme = XCScheme.mock(name: "TestScheme") - mockProvider.xcodeProj.sharedData = XCSharedData(schemes: [scheme]) - let mapper = ProjectMapper(projectProvider: mockProvider) - - let project = try await mapper.mapProject() - - #expect(project.schemes.count == 1) - #expect(project.schemes[0].name == "TestScheme") - } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift index ddae7380..ebd452fb 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift @@ -7,57 +7,57 @@ import XcodeProj @testable import XcodeProjToGraph struct BuildSettingsTests { - /// Tests that a string value is correctly extracted from build settings. - @Test func testStringExtraction() async throws { - let settings: [String: Any] = ["COMPILER_FLAGS": "-ObjC"] - let value = settings.string(for: .compilerFlags) - try #require(value != nil) - #expect(value == "-ObjC") - } - - /// Tests that a boolean value is correctly extracted, and invalid types return nil. - @Test func testBoolExtraction() { - let settings: [String: Any] = ["PRUNE": true] - let boolValue = settings.bool(for: .prune) - #expect(boolValue == true) - - // Test invalid type - let invalidSettings: [String: Any] = ["PRUNE": "notABool"] - let invalidBool = invalidSettings.bool(for: .prune) - #expect(invalidBool == nil) - } - - /// Tests extracting a string array from build settings. - @Test func testStringArrayExtraction() async throws { - let settings: [String: Any] = ["LAUNCH_ARGUMENTS": ["-enableFeature", "-verbose"]] - let args = settings.stringArray(for: .launchArguments) - try #require(args != nil) - #expect(args?.count == 2) - #expect(args?.contains("-verbose") == true) - } - - /// Tests extracting a dictionary of strings (for environment variables). - @Test func testStringDictExtraction() async throws { - let settings: [String: Any] = ["ENVIRONMENT_VARIABLES": ["KEY": "VALUE"]] - let envVars = settings.stringDict(for: .environmentVariables) - try #require(envVars != nil) - #expect(envVars?["KEY"] == "VALUE") - } - - /// Tests that missing keys return nil. - @Test func testMissingKeyReturnsNil() { - let settings: [String: Any] = ["TAGS": "some,tags"] - #expect(settings.string(for: .productBundleIdentifier) == nil) - #expect(settings.bool(for: .mergeable) == nil) - } - - /// Tests that non-string array values are coerced to strings. - /// Example: If a setting is `[Any]` but some elements aren’t strings, they’re filtered out. - @Test func testCoerceAnyArrayToStringArray() async throws { - let settings: [String: Any] = ["LAUNCH_ARGUMENTS": ["-flag", 42, true]] - let args = settings.stringArray(for: .launchArguments) - try #require(args != nil) - // Non-string elements (42, true) should be discarded, leaving only ["-flag"]. - #expect(args == ["-flag"]) - } + /// Tests that a string value is correctly extracted from build settings. + @Test func testStringExtraction() async throws { + let settings: [String: Any] = ["COMPILER_FLAGS": "-ObjC"] + let value = settings.string(for: .compilerFlags) + try #require(value != nil) + #expect(value == "-ObjC") + } + + /// Tests that a boolean value is correctly extracted, and invalid types return nil. + @Test func testBoolExtraction() { + let settings: [String: Any] = ["PRUNE": true] + let boolValue = settings.bool(for: .prune) + #expect(boolValue == true) + + // Test invalid type + let invalidSettings: [String: Any] = ["PRUNE": "notABool"] + let invalidBool = invalidSettings.bool(for: .prune) + #expect(invalidBool == nil) + } + + /// Tests extracting a string array from build settings. + @Test func testStringArrayExtraction() async throws { + let settings: [String: Any] = ["LAUNCH_ARGUMENTS": ["-enableFeature", "-verbose"]] + let args = settings.stringArray(for: .launchArguments) + try #require(args != nil) + #expect(args?.count == 2) + #expect(args?.contains("-verbose") == true) + } + + /// Tests extracting a dictionary of strings (for environment variables). + @Test func testStringDictExtraction() async throws { + let settings: [String: Any] = ["ENVIRONMENT_VARIABLES": ["KEY": "VALUE"]] + let envVars = settings.stringDict(for: .environmentVariables) + try #require(envVars != nil) + #expect(envVars?["KEY"] == "VALUE") + } + + /// Tests that missing keys return nil. + @Test func testMissingKeyReturnsNil() { + let settings: [String: Any] = ["TAGS": "some,tags"] + #expect(settings.string(for: .productBundleIdentifier) == nil) + #expect(settings.bool(for: .mergeable) == nil) + } + + /// Tests that non-string array values are coerced to strings. + /// Example: If a setting is `[Any]` but some elements aren’t strings, they’re filtered out. + @Test func testCoerceAnyArrayToStringArray() async throws { + let settings: [String: Any] = ["LAUNCH_ARGUMENTS": ["-flag", 42, true]] + let args = settings.stringArray(for: .launchArguments) + try #require(args != nil) + // Non-string elements (42, true) should be discarded, leaving only ["-flag"]. + #expect(args == ["-flag"]) + } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift index 8d334b67..758f84ea 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift @@ -4,32 +4,31 @@ import XcodeGraph @testable import XcodeProjToGraph struct ConfigurationMatcherTests { + @Test func testVariantDetectionForDebug() async throws { + #expect(ConfigurationMatcher.variant(forName: "Debug") == .debug) + #expect(ConfigurationMatcher.variant(forName: "development") == .debug) + #expect(ConfigurationMatcher.variant(forName: "dev") == .debug) + } - @Test func testVariantDetectionForDebug() async throws { - #expect(ConfigurationMatcher.variant(forName: "Debug") == .debug) - #expect(ConfigurationMatcher.variant(forName: "development") == .debug) - #expect(ConfigurationMatcher.variant(forName: "dev") == .debug) - } + @Test func testVariantDetectionForRelease() async throws { + #expect(ConfigurationMatcher.variant(forName: "Release") == .release) + #expect(ConfigurationMatcher.variant(forName: "prod") == .release) + #expect(ConfigurationMatcher.variant(forName: "production") == .release) + } - @Test func testVariantDetectionForRelease() async throws { - #expect(ConfigurationMatcher.variant(forName: "Release") == .release) - #expect(ConfigurationMatcher.variant(forName: "prod") == .release) - #expect(ConfigurationMatcher.variant(forName: "production") == .release) - } + @Test func testVariantFallbackToDebug() async throws { + // Names that don't match debug/release keywords should fall back to debug + #expect(ConfigurationMatcher.variant(forName: "Staging") == .debug) + #expect(ConfigurationMatcher.variant(forName: "CustomConfig") == .debug) + } - @Test func testVariantFallbackToDebug() async throws { - // Names that don't match debug/release keywords should fall back to debug - #expect(ConfigurationMatcher.variant(forName: "Staging") == .debug) - #expect(ConfigurationMatcher.variant(forName: "CustomConfig") == .debug) - } + @Test func testValidateConfigurationName() async throws { + #expect(ConfigurationMatcher.validateConfigurationName("Debug") == true) + #expect(ConfigurationMatcher.validateConfigurationName("Release") == true) - @Test func testValidateConfigurationName() async throws { - #expect(ConfigurationMatcher.validateConfigurationName("Debug") == true) - #expect(ConfigurationMatcher.validateConfigurationName("Release") == true) - - // Invalid names: empty, whitespace, or containing spaces - #expect(ConfigurationMatcher.validateConfigurationName("") == false) - #expect(ConfigurationMatcher.validateConfigurationName("Debug Config") == false) - #expect(ConfigurationMatcher.validateConfigurationName(" ") == false) - } + // Invalid names: empty, whitespace, or containing spaces + #expect(ConfigurationMatcher.validateConfigurationName("") == false) + #expect(ConfigurationMatcher.validateConfigurationName("Debug Config") == false) + #expect(ConfigurationMatcher.validateConfigurationName(" ") == false) + } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift index b7a7d4a5..fe0f8200 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift @@ -3,160 +3,167 @@ import Testing import XcodeGraph import XcodeProj -@testable import TestSupport // For MockFactory usage +@testable import TestSupport // For MockFactory usage @testable import XcodeProjToGraph struct SettingsMapperTests { - let mapper = SettingsMapper() - - @Test func testNilConfigurationListReturnsDefault() async throws { - let mockProvider = MockProjectProvider() - let settings = try await mapper.map(projectProvider: mockProvider, configurationList: nil) - #expect(settings == Settings.default) - } - - @Test func testSingleConfigurationMapping() async throws { - let pbxProj = PBXProj() - let configList = XCConfigurationList.mock( - configs: [("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.debug"])], proj: pbxProj - ) - let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) - - let settings = try await mapper.map( - projectProvider: mockProvider, configurationList: configList) - #expect(settings.configurations.count == 1) - - let configKey = settings.configurations.keys.first - try #require(configKey != nil) - #expect(configKey?.name == "Debug") - #expect(configKey?.variant == .debug) - - let debugConfig = settings.configurations[configKey!] - try #require(debugConfig != nil) - - // Now `debugConfig` is a `Configuration?`. - let actualDebugConfig = debugConfig! - try #require(actualDebugConfig != nil) - - #expect(actualDebugConfig!.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.debug") - } - - @Test func testMultipleConfigurations() async throws { - let pbxProj = PBXProj() - let configs: [(String, [String: Sendable])] = [ - ("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.debug"]), - ("Release", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.release"]), - ] - let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) - let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) - - let settings = try await mapper.map( - projectProvider: mockProvider, configurationList: configList) - #expect(settings.configurations.count == 2) - - let debugKey = settings.configurations.keys.first { $0.name == "Debug" } - let releaseKey = settings.configurations.keys.first { $0.name == "Release" } - - try #require(debugKey != nil) - try #require(releaseKey != nil) - #expect(debugKey?.variant == .debug) - #expect(releaseKey?.variant == .release) - - let debugConfig = settings.configurations[debugKey!] - let releaseConfig = settings.configurations[releaseKey!] - - try #require(debugConfig != nil) - try #require(releaseConfig != nil) - - let actualDebugConfig = debugConfig! - let actualReleaseConfig = releaseConfig! - - #expect(actualDebugConfig?.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.debug") - #expect(actualReleaseConfig?.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.release") - } - - @Test func testCoercionOfNonStringValues() async throws { - let pbxProj = PBXProj() - let configs: [(String, [String: Sendable])] = [ - ("Debug", ["SOME_NUMBER": 42]) - ] - let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) - let mockProvider = MockProjectProvider(configurationList: configList) - - let settings = try await mapper.map( - projectProvider: mockProvider, configurationList: configList) - let debugKey = settings.configurations.keys.first { $0.name == "Debug" } - try #require(debugKey != nil) - - let debugConfig = settings.configurations[debugKey!] - try #require(debugConfig != nil) - - let actualDebugConfig = debugConfig! - try #require(actualDebugConfig != nil) - - #expect(actualDebugConfig!.settings["SOME_NUMBER"] == "42") - } - - @Test func testXCConfigPathResolution() async throws { - let pbxProj = PBXProj() - let baseConfigRef = PBXFileReference.mock( - sourceTree: .sourceRoot, path: "Config.xcconfig", pbxProj: pbxProj) - let buildConfig = XCBuildConfiguration.mock( - name: "Debug", buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example"], - pbxProj: pbxProj) - buildConfig.baseConfiguration = baseConfigRef - - let configList = XCConfigurationList( - buildConfigurations: [buildConfig], - defaultConfigurationName: "Debug", - defaultConfigurationIsVisible: false - ) - - let mockProvider = MockProjectProvider( - sourceDirectory: "/Users/test/project", configurationList: configList) - let settings = try await mapper.map( - projectProvider: mockProvider, configurationList: configList) - - let debugKey = settings.configurations.keys.first { $0.name == "Debug" } - try #require(debugKey != nil) - - let debugConfig = settings.configurations[debugKey!] - try #require(debugConfig != nil) - - let actualDebugConfig = debugConfig! - try #require(actualDebugConfig != nil) - - let expectedPath = "/Users/test/project/Config.xcconfig" - #expect(actualDebugConfig!.xcconfig?.pathString == expectedPath) - } - - @Test func testArrayValueMapping() async throws { - let pbxProj = PBXProj() - let configs: [(String, [String: Sendable])] = [ - ("Debug", ["SOME_ARRAY": ["val1", "val2"]]) - ] - let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) - let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) - - let settings = try await mapper.map( - projectProvider: mockProvider, configurationList: configList) - - // Check we have one configuration - #expect(settings.configurations.count == 1) - - // Retrieve the Debug configuration - let debugKey = settings.configurations.keys.first { $0.name == "Debug" } - try #require(debugKey != nil) - let debugConfig = settings.configurations[debugKey!] - try #require(debugConfig != nil) - - let actualDebugConfig = debugConfig! - try #require(actualDebugConfig != nil) - - // Verify the array setting - // NOTE: actualDebugConfig.settings["SOME_ARRAY"] should return a SettingValue - // which is .array(["val1", "val2"]) - #expect(actualDebugConfig!.settings["SOME_ARRAY"] == ["val1", "val2"]) - } - + let mapper = SettingsMapper() + + @Test func testNilConfigurationListReturnsDefault() async throws { + let mockProvider = MockProjectProvider() + let settings = try await mapper.map(projectProvider: mockProvider, configurationList: nil) + #expect(settings == Settings.default) + } + + @Test func testSingleConfigurationMapping() async throws { + let pbxProj = PBXProj() + let configList = XCConfigurationList.mock( + configs: [("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.debug"])], proj: pbxProj + ) + let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) + + let settings = try await mapper.map( + projectProvider: mockProvider, configurationList: configList + ) + #expect(settings.configurations.count == 1) + + let configKey = settings.configurations.keys.first + try #require(configKey != nil) + #expect(configKey?.name == "Debug") + #expect(configKey?.variant == .debug) + + let debugConfig = settings.configurations[configKey!] + try #require(debugConfig != nil) + + // Now `debugConfig` is a `Configuration?`. + let actualDebugConfig = debugConfig! + try #require(actualDebugConfig != nil) + + #expect(actualDebugConfig!.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.debug") + } + + @Test func testMultipleConfigurations() async throws { + let pbxProj = PBXProj() + let configs: [(String, [String: Sendable])] = [ + ("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.debug"]), + ("Release", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.release"]), + ] + let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) + let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) + + let settings = try await mapper.map( + projectProvider: mockProvider, configurationList: configList + ) + #expect(settings.configurations.count == 2) + + let debugKey = settings.configurations.keys.first { $0.name == "Debug" } + let releaseKey = settings.configurations.keys.first { $0.name == "Release" } + + try #require(debugKey != nil) + try #require(releaseKey != nil) + #expect(debugKey?.variant == .debug) + #expect(releaseKey?.variant == .release) + + let debugConfig = settings.configurations[debugKey!] + let releaseConfig = settings.configurations[releaseKey!] + + try #require(debugConfig != nil) + try #require(releaseConfig != nil) + + let actualDebugConfig = debugConfig! + let actualReleaseConfig = releaseConfig! + + #expect(actualDebugConfig?.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.debug") + #expect(actualReleaseConfig?.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.release") + } + + @Test func testCoercionOfNonStringValues() async throws { + let pbxProj = PBXProj() + let configs: [(String, [String: Sendable])] = [ + ("Debug", ["SOME_NUMBER": 42]), + ] + let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) + let mockProvider = MockProjectProvider(configurationList: configList) + + let settings = try await mapper.map( + projectProvider: mockProvider, configurationList: configList + ) + let debugKey = settings.configurations.keys.first { $0.name == "Debug" } + try #require(debugKey != nil) + + let debugConfig = settings.configurations[debugKey!] + try #require(debugConfig != nil) + + let actualDebugConfig = debugConfig! + try #require(actualDebugConfig != nil) + + #expect(actualDebugConfig!.settings["SOME_NUMBER"] == "42") + } + + @Test func testXCConfigPathResolution() async throws { + let pbxProj = PBXProj() + let baseConfigRef = PBXFileReference.mock( + sourceTree: .sourceRoot, path: "Config.xcconfig", pbxProj: pbxProj + ) + let buildConfig = XCBuildConfiguration.mock( + name: "Debug", buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example"], + pbxProj: pbxProj + ) + buildConfig.baseConfiguration = baseConfigRef + + let configList = XCConfigurationList( + buildConfigurations: [buildConfig], + defaultConfigurationName: "Debug", + defaultConfigurationIsVisible: false + ) + + let mockProvider = MockProjectProvider( + sourceDirectory: "/Users/test/project", configurationList: configList + ) + let settings = try await mapper.map( + projectProvider: mockProvider, configurationList: configList + ) + + let debugKey = settings.configurations.keys.first { $0.name == "Debug" } + try #require(debugKey != nil) + + let debugConfig = settings.configurations[debugKey!] + try #require(debugConfig != nil) + + let actualDebugConfig = debugConfig! + try #require(actualDebugConfig != nil) + + let expectedPath = "/Users/test/project/Config.xcconfig" + #expect(actualDebugConfig!.xcconfig?.pathString == expectedPath) + } + + @Test func testArrayValueMapping() async throws { + let pbxProj = PBXProj() + let configs: [(String, [String: Sendable])] = [ + ("Debug", ["SOME_ARRAY": ["val1", "val2"]]), + ] + let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) + let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) + + let settings = try await mapper.map( + projectProvider: mockProvider, configurationList: configList + ) + + // Check we have one configuration + #expect(settings.configurations.count == 1) + + // Retrieve the Debug configuration + let debugKey = settings.configurations.keys.first { $0.name == "Debug" } + try #require(debugKey != nil) + let debugConfig = settings.configurations[debugKey!] + try #require(debugConfig != nil) + + let actualDebugConfig = debugConfig! + try #require(actualDebugConfig != nil) + + // Verify the array setting + // NOTE: actualDebugConfig.settings["SOME_ARRAY"] should return a SettingValue + // which is .array(["val1", "val2"]) + #expect(actualDebugConfig!.settings["SOME_ARRAY"] == ["val1", "val2"]) + } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift index 8bcdce5b..ec9746f0 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift @@ -1,242 +1,242 @@ import Path import Testing -@testable import XcodeProj @testable import TestSupport +@testable import XcodeProj @testable import XcodeProjToGraph struct SchemeMapperTests { - let mockProvider: MockProjectProvider - let mapper: SchemeMapper - - init() async throws { - let mockProvider = MockProjectProvider() - self.mockProvider = mockProvider - self.mapper = try SchemeMapper(graphType: .project(mockProvider.sourceDirectory)) - } - - @Test func testMapSharedProjectSchemes() async throws { - // Setup shared scheme data - let xcscheme = XCScheme.mock(name: "SharedScheme") - - let schemes = try await mapper.mapSchemes(xcschemes: [xcscheme], shared: true) - #expect(schemes.count == 1) - #expect(schemes[0].name == "SharedScheme") - #expect(schemes[0].shared == true) - } - - @Test func testMapUserSchemes() async throws { - // Setup user scheme data - let xcscheme = XCScheme.mock(name: "UserScheme") - let schemes = try await mapper.mapSchemes(xcschemes: [xcscheme], shared: false) - - #expect(schemes.count == 1) - #expect(schemes[0].name == "UserScheme") - #expect(schemes[0].shared == false) - } - - @Test func testMapBuildAction() async throws { - let targetRef = XCScheme.BuildableReference( - referencedContainer: "container:App.xcodeproj", - blueprintIdentifier: "123", - buildableName: "App.app", - blueprintName: "App" - ) - - let buildActionEntry = XCScheme.BuildAction.Entry( - buildableReference: targetRef, - buildFor: [.running, .testing] - ) - - let buildAction = XCScheme.BuildAction( - buildActionEntries: [buildActionEntry], - parallelizeBuild: true, - buildImplicitDependencies: true, - runPostActionsOnFailure: true - ) - - let mappedAction = try await mapper.mapBuildAction(action: buildAction) - #expect(mappedAction != nil) - #expect(mappedAction?.targets.count == 1) - #expect(mappedAction?.targets[0].name == "App") - #expect(mappedAction?.runPostActionsOnFailure == true) - #expect(mappedAction?.findImplicitDependencies == true) - } - - @Test func testMapTestAction() async throws { - let targetRef = XCScheme.BuildableReference( - referencedContainer: "container:App.xcodeproj", - blueprintIdentifier: "123", - buildableName: "AppTests.xctest", - blueprintName: "AppTests" - ) - - let testableEntry = XCScheme.TestableReference.mock( - skipped: false, - buildableReference: targetRef - ) - - let envVar = XCScheme.EnvironmentVariable( - variable: "TEST_ENV", - value: "test_value", - enabled: true - ) - - let launchArg = XCScheme.CommandLineArguments.CommandLineArgument( - name: "test_arg", - enabled: true - ) - - let testAction = XCScheme.TestAction( - buildConfiguration: "Debug", - macroExpansion: nil, - testables: [testableEntry], - codeCoverageEnabled: true, - commandlineArguments: XCScheme.CommandLineArguments(arguments: [launchArg]), - environmentVariables: [envVar], - language: "en", - region: "US" - ) - - let mappedAction = try await mapper.mapTestAction(action: testAction) - #expect(mappedAction != nil) - #expect(mappedAction?.targets.count == 1) - #expect(mappedAction?.targets[0].target.name == "AppTests") - #expect(mappedAction?.configurationName == "Debug") - #expect(mappedAction?.coverage == true) - #expect(mappedAction?.arguments?.environmentVariables["TEST_ENV"]?.value == "test_value") - #expect(mappedAction?.arguments?.launchArguments.first?.name == "test_arg") - #expect(mappedAction?.language == "en") - #expect(mappedAction?.region == "US") - } - - @Test func testMapRunAction() async throws { - let targetRef = XCScheme.BuildableReference( - referencedContainer: "container:App.xcodeproj", - blueprintIdentifier: "123", - buildableName: "App.app", - blueprintName: "App" - ) - - let runnable = XCScheme.BuildableProductRunnable(buildableReference: targetRef) - - let envVar = XCScheme.EnvironmentVariable( - variable: "RUN_ENV", - value: "run_value", - enabled: true - ) - - let launchArg = XCScheme.CommandLineArguments.CommandLineArgument( - name: "run_arg", - enabled: true - ) - - let launchAction = XCScheme.LaunchAction( - pathRunnable: try XCScheme.PathRunnable(element: runnable.xmlElement()), - buildConfiguration: "Debug", - selectedDebuggerIdentifier: "", - commandlineArguments: XCScheme.CommandLineArguments(arguments: [launchArg]), - environmentVariables: [envVar] - ) - - let mappedAction = try await mapper.mapRunAction(action: launchAction) - #expect(mappedAction != nil) - #expect(mappedAction?.executable?.name == "App") - #expect(mappedAction?.configurationName == "Debug") - #expect(mappedAction?.attachDebugger == true) - #expect(mappedAction?.arguments?.environmentVariables["RUN_ENV"]?.value == "run_value") - #expect(mappedAction?.arguments?.launchArguments.first?.name == "run_arg") - } - - @Test func testMapArchiveAction() async throws { - let archiveAction = XCScheme.ArchiveAction( - buildConfiguration: "Release", - revealArchiveInOrganizer: true - ) - - let mappedAction = try await mapper.mapArchiveAction(action: archiveAction) - #expect(mappedAction != nil) - #expect(mappedAction?.configurationName == "Release") - #expect(mappedAction?.revealArchiveInOrganizer == true) - } - - @Test func testMapProfileAction() async throws { - let targetRef = XCScheme.BuildableReference( - referencedContainer: "container:App.xcodeproj", - blueprintIdentifier: "123", - buildableName: "App.app", - blueprintName: "App" - ) - - let runnable = XCScheme.BuildableProductRunnable(buildableReference: targetRef) - - let profileAction = XCScheme.ProfileAction( - runnable: runnable, - buildConfiguration: "Release" - ) - - let mappedAction = try await mapper.mapProfileAction(action: profileAction) - #expect(mappedAction != nil) - #expect(mappedAction?.executable?.name == "App") - #expect(mappedAction?.configurationName == "Release") - } - - @Test func testMapAnalyzeAction() async throws { - let analyzeAction = XCScheme.AnalyzeAction(buildConfiguration: "Debug") - - let mappedAction = try await mapper.mapAnalyzeAction(action: analyzeAction) - #expect(mappedAction != nil) - #expect(mappedAction?.configurationName == "Debug") - } - - @Test func testMapTargetReference() async throws { - let targetRef = XCScheme.BuildableReference( - referencedContainer: "container:App.xcodeproj", - blueprintIdentifier: "123", - buildableName: "App.app", - blueprintName: "App" - ) - - // Create a build action entry that uses the target reference - let buildActionEntry = XCScheme.BuildAction.Entry( - buildableReference: targetRef, - buildFor: [.running] - ) - - // Create a scheme with a build action that uses our target reference - let buildAction = XCScheme.BuildAction( - buildActionEntries: [buildActionEntry], - parallelizeBuild: true, - buildImplicitDependencies: true - ) - - let scheme = XCScheme.mock(buildAction: buildAction) - - let mapped = try await mapper.mapScheme(xcscheme: scheme, shared: true) - - // Verify the target reference was properly mapped - let mappedBuildAction = try #require(mapped.buildAction) - - #expect(mappedBuildAction.targets.count == 1) - #expect(mappedBuildAction.targets[0].name == "App") - #expect(mappedBuildAction.targets[0].projectPath == mockProvider.sourceDirectory) - } - - @Test func testNilActions() async throws { - let scheme = XCScheme.mock( - buildAction: nil, - testAction: nil, - launchAction: nil, - archiveAction: nil, - profileAction: nil, - analyzeAction: nil - ) - - let mapped = try await mapper.mapScheme(xcscheme: scheme, shared: true) - #expect(mapped.buildAction == nil) - #expect(mapped.testAction == nil) - #expect(mapped.runAction == nil) - #expect(mapped.profileAction == nil) - #expect(mapped.analyzeAction == nil) - #expect(mapped.archiveAction == nil) - } + let mockProvider: MockProjectProvider + let mapper: SchemeMapper + + init() async throws { + let mockProvider = MockProjectProvider() + self.mockProvider = mockProvider + mapper = try SchemeMapper(graphType: .project(mockProvider.sourceDirectory)) + } + + @Test func testMapSharedProjectSchemes() async throws { + // Setup shared scheme data + let xcscheme = XCScheme.mock(name: "SharedScheme") + + let schemes = try await mapper.mapSchemes(xcschemes: [xcscheme], shared: true) + #expect(schemes.count == 1) + #expect(schemes[0].name == "SharedScheme") + #expect(schemes[0].shared == true) + } + + @Test func testMapUserSchemes() async throws { + // Setup user scheme data + let xcscheme = XCScheme.mock(name: "UserScheme") + let schemes = try await mapper.mapSchemes(xcschemes: [xcscheme], shared: false) + + #expect(schemes.count == 1) + #expect(schemes[0].name == "UserScheme") + #expect(schemes[0].shared == false) + } + + @Test func testMapBuildAction() async throws { + let targetRef = XCScheme.BuildableReference( + referencedContainer: "container:App.xcodeproj", + blueprintIdentifier: "123", + buildableName: "App.app", + blueprintName: "App" + ) + + let buildActionEntry = XCScheme.BuildAction.Entry( + buildableReference: targetRef, + buildFor: [.running, .testing] + ) + + let buildAction = XCScheme.BuildAction( + buildActionEntries: [buildActionEntry], + parallelizeBuild: true, + buildImplicitDependencies: true, + runPostActionsOnFailure: true + ) + + let mappedAction = try await mapper.mapBuildAction(action: buildAction) + #expect(mappedAction != nil) + #expect(mappedAction?.targets.count == 1) + #expect(mappedAction?.targets[0].name == "App") + #expect(mappedAction?.runPostActionsOnFailure == true) + #expect(mappedAction?.findImplicitDependencies == true) + } + + @Test func testMapTestAction() async throws { + let targetRef = XCScheme.BuildableReference( + referencedContainer: "container:App.xcodeproj", + blueprintIdentifier: "123", + buildableName: "AppTests.xctest", + blueprintName: "AppTests" + ) + + let testableEntry = XCScheme.TestableReference.mock( + skipped: false, + buildableReference: targetRef + ) + + let envVar = XCScheme.EnvironmentVariable( + variable: "TEST_ENV", + value: "test_value", + enabled: true + ) + + let launchArg = XCScheme.CommandLineArguments.CommandLineArgument( + name: "test_arg", + enabled: true + ) + + let testAction = XCScheme.TestAction( + buildConfiguration: "Debug", + macroExpansion: nil, + testables: [testableEntry], + codeCoverageEnabled: true, + commandlineArguments: XCScheme.CommandLineArguments(arguments: [launchArg]), + environmentVariables: [envVar], + language: "en", + region: "US" + ) + + let mappedAction = try await mapper.mapTestAction(action: testAction) + #expect(mappedAction != nil) + #expect(mappedAction?.targets.count == 1) + #expect(mappedAction?.targets[0].target.name == "AppTests") + #expect(mappedAction?.configurationName == "Debug") + #expect(mappedAction?.coverage == true) + #expect(mappedAction?.arguments?.environmentVariables["TEST_ENV"]?.value == "test_value") + #expect(mappedAction?.arguments?.launchArguments.first?.name == "test_arg") + #expect(mappedAction?.language == "en") + #expect(mappedAction?.region == "US") + } + + @Test func testMapRunAction() async throws { + let targetRef = XCScheme.BuildableReference( + referencedContainer: "container:App.xcodeproj", + blueprintIdentifier: "123", + buildableName: "App.app", + blueprintName: "App" + ) + + let runnable = XCScheme.BuildableProductRunnable(buildableReference: targetRef) + + let envVar = XCScheme.EnvironmentVariable( + variable: "RUN_ENV", + value: "run_value", + enabled: true + ) + + let launchArg = XCScheme.CommandLineArguments.CommandLineArgument( + name: "run_arg", + enabled: true + ) + + let launchAction = XCScheme.LaunchAction( + pathRunnable: try XCScheme.PathRunnable(element: runnable.xmlElement()), + buildConfiguration: "Debug", + selectedDebuggerIdentifier: "", + commandlineArguments: XCScheme.CommandLineArguments(arguments: [launchArg]), + environmentVariables: [envVar] + ) + + let mappedAction = try await mapper.mapRunAction(action: launchAction) + #expect(mappedAction != nil) + #expect(mappedAction?.executable?.name == "App") + #expect(mappedAction?.configurationName == "Debug") + #expect(mappedAction?.attachDebugger == true) + #expect(mappedAction?.arguments?.environmentVariables["RUN_ENV"]?.value == "run_value") + #expect(mappedAction?.arguments?.launchArguments.first?.name == "run_arg") + } + + @Test func testMapArchiveAction() async throws { + let archiveAction = XCScheme.ArchiveAction( + buildConfiguration: "Release", + revealArchiveInOrganizer: true + ) + + let mappedAction = try await mapper.mapArchiveAction(action: archiveAction) + #expect(mappedAction != nil) + #expect(mappedAction?.configurationName == "Release") + #expect(mappedAction?.revealArchiveInOrganizer == true) + } + + @Test func testMapProfileAction() async throws { + let targetRef = XCScheme.BuildableReference( + referencedContainer: "container:App.xcodeproj", + blueprintIdentifier: "123", + buildableName: "App.app", + blueprintName: "App" + ) + + let runnable = XCScheme.BuildableProductRunnable(buildableReference: targetRef) + + let profileAction = XCScheme.ProfileAction( + runnable: runnable, + buildConfiguration: "Release" + ) + + let mappedAction = try await mapper.mapProfileAction(action: profileAction) + #expect(mappedAction != nil) + #expect(mappedAction?.executable?.name == "App") + #expect(mappedAction?.configurationName == "Release") + } + + @Test func testMapAnalyzeAction() async throws { + let analyzeAction = XCScheme.AnalyzeAction(buildConfiguration: "Debug") + + let mappedAction = try await mapper.mapAnalyzeAction(action: analyzeAction) + #expect(mappedAction != nil) + #expect(mappedAction?.configurationName == "Debug") + } + + @Test func testMapTargetReference() async throws { + let targetRef = XCScheme.BuildableReference( + referencedContainer: "container:App.xcodeproj", + blueprintIdentifier: "123", + buildableName: "App.app", + blueprintName: "App" + ) + + // Create a build action entry that uses the target reference + let buildActionEntry = XCScheme.BuildAction.Entry( + buildableReference: targetRef, + buildFor: [.running] + ) + + // Create a scheme with a build action that uses our target reference + let buildAction = XCScheme.BuildAction( + buildActionEntries: [buildActionEntry], + parallelizeBuild: true, + buildImplicitDependencies: true + ) + + let scheme = XCScheme.mock(buildAction: buildAction) + + let mapped = try await mapper.mapScheme(xcscheme: scheme, shared: true) + + // Verify the target reference was properly mapped + let mappedBuildAction = try #require(mapped.buildAction) + + #expect(mappedBuildAction.targets.count == 1) + #expect(mappedBuildAction.targets[0].name == "App") + #expect(mappedBuildAction.targets[0].projectPath == mockProvider.sourceDirectory) + } + + @Test func testNilActions() async throws { + let scheme = XCScheme.mock( + buildAction: nil, + testAction: nil, + launchAction: nil, + archiveAction: nil, + profileAction: nil, + analyzeAction: nil + ) + + let mapped = try await mapper.mapScheme(xcscheme: scheme, shared: true) + #expect(mapped.buildAction == nil) + #expect(mapped.testAction == nil) + #expect(mapped.runAction == nil) + #expect(mapped.profileAction == nil) + #expect(mapped.analyzeAction == nil) + #expect(mapped.archiveAction == nil) + } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift index e9dc7c01..ec8a1a98 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift @@ -7,147 +7,145 @@ import XcodeProj @testable import XcodeProjToGraph struct PBXTargetMapperTests { - let mockProvider = MockProjectProvider() - let mapper: TargetMapping - - init() { - self.mapper = TargetMapper(projectProvider: mockProvider) - } - - @Test func testMapBasicTarget() async throws { - let target = createTarget( - name: "App", - productType: .application, - buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"] - ) - - let mapped = try await mapper.map(pbxTarget: target) - #expect(mapped.name == "App") - #expect(mapped.product == .app) - #expect(mapped.productName == "App") - #expect(mapped.bundleId == "com.example.app") - - } - - @Test func testMapTargetWithMissingBundleId() async throws { - let target = createTarget( - name: "App", - productType: .application, - buildSettings: [:] - ) - - await #expect(throws: MappingError.missingBundleIdentifier(targetName: "App")) { - _ = try await mapper.map(pbxTarget: target) + let mockProvider = MockProjectProvider() + let mapper: TargetMapping + + init() { + mapper = TargetMapper(projectProvider: mockProvider) + } + + @Test func testMapBasicTarget() async throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"] + ) + + let mapped = try await mapper.map(pbxTarget: target) + #expect(mapped.name == "App") + #expect(mapped.product == .app) + #expect(mapped.productName == "App") + #expect(mapped.bundleId == "com.example.app") + } + + @Test func testMapTargetWithMissingBundleId() async throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [:] + ) + + await #expect(throws: MappingError.missingBundleIdentifier(targetName: "App")) { + _ = try await mapper.map(pbxTarget: target) + } + } + + @Test func testMapTargetWithEnvironmentVariables() async throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "ENVIRONMENT_VARIABLES": ["TEST_VAR": "test_value"], + ] + ) + + let mapped = try await mapper.map(pbxTarget: target) + #expect(mapped.environmentVariables["TEST_VAR"]?.value == "test_value") + #expect(mapped.environmentVariables["TEST_VAR"]?.isEnabled == true) + } + + @Test func testMapTargetWithLaunchArguments() async throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "LAUNCH_ARGUMENTS": ["-debug", "--verbose"], + ] + ) + + let mapped = try await mapper.map(pbxTarget: target) + let expected = [ + LaunchArgument(name: "-debug", isEnabled: true), + LaunchArgument(name: "--verbose", isEnabled: true), + ] + #expect(mapped.launchArguments == expected) + } + + @Test func testMapTargetWithSourceFiles() async throws { + let sourceFile = PBXFileReference.mock( + path: "ViewController.swift", + lastKnownFileType: "sourcecode.swift", + pbxProj: mockProvider.pbxProj + ) + let buildFile = PBXBuildFile.mock(file: sourceFile, pbxProj: mockProvider.pbxProj) + let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: mockProvider.pbxProj) + + let target = createTarget( + name: "App", + productType: .application, + buildPhases: [sourcesPhase], + buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"] + ) + + let mapped = try await mapper.map(pbxTarget: target) + #expect(mapped.sources.count == 1) + #expect(mapped.sources[0].path.basename == "ViewController.swift") + } + + @Test func testMapTargetWithMetadata() async throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "TAGS": "tag1, tag2, tag3", + ] + ) + + let mapped = try await mapper.map(pbxTarget: target) + #expect(mapped.metadata.tags == Set(["tag1", "tag2", "tag3"])) + } + + // MARK: - Helper Methods + + private func createTarget( + name: String, + productType: PBXProductType, + buildPhases: [PBXBuildPhase] = [], + buildSettings: [String: Any] = [:], + dependencies: [PBXTargetDependency] = [] + ) -> PBXNativeTarget { + let debugConfig = XCBuildConfiguration( + name: "Debug", + buildSettings: buildSettings + ) + + let releaseConfig = XCBuildConfiguration( + name: "Release", + buildSettings: buildSettings + ) + + let configurationList = XCConfigurationList( + buildConfigurations: [debugConfig, releaseConfig], + defaultConfigurationName: "Release" + ) + + mockProvider.pbxProj.add(object: debugConfig) + mockProvider.pbxProj.add(object: releaseConfig) + mockProvider.pbxProj.add(object: configurationList) + + let target = PBXNativeTarget.mock( + name: name, + buildConfigurationList: configurationList, + buildRules: [], + buildPhases: buildPhases, + dependencies: dependencies, + productType: productType, + pbxProj: mockProvider.pbxProj + ) + + return target } - } - - @Test func testMapTargetWithEnvironmentVariables() async throws { - let target = createTarget( - name: "App", - productType: .application, - buildSettings: [ - "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", - "ENVIRONMENT_VARIABLES": ["TEST_VAR": "test_value"], - ] - ) - - let mapped = try await mapper.map(pbxTarget: target) - #expect(mapped.environmentVariables["TEST_VAR"]?.value == "test_value") - #expect(mapped.environmentVariables["TEST_VAR"]?.isEnabled == true) - } - - @Test func testMapTargetWithLaunchArguments() async throws { - let target = createTarget( - name: "App", - productType: .application, - buildSettings: [ - "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", - "LAUNCH_ARGUMENTS": ["-debug", "--verbose"], - ] - ) - - let mapped = try await mapper.map(pbxTarget: target) - let expected = [ - LaunchArgument(name: "-debug", isEnabled: true), - LaunchArgument(name: "--verbose", isEnabled: true), - ] - #expect(mapped.launchArguments == expected) - - } - - @Test func testMapTargetWithSourceFiles() async throws { - let sourceFile = PBXFileReference.mock( - path: "ViewController.swift", - lastKnownFileType: "sourcecode.swift", - pbxProj: mockProvider.pbxProj - ) - let buildFile = PBXBuildFile.mock(file: sourceFile, pbxProj: mockProvider.pbxProj) - let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: mockProvider.pbxProj) - - let target = createTarget( - name: "App", - productType: .application, - buildPhases: [sourcesPhase], - buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"] - ) - - let mapped = try await mapper.map(pbxTarget: target) - #expect(mapped.sources.count == 1) - #expect(mapped.sources[0].path.basename == "ViewController.swift") - } - - @Test func testMapTargetWithMetadata() async throws { - let target = createTarget( - name: "App", - productType: .application, - buildSettings: [ - "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", - "TAGS": "tag1, tag2, tag3", - ] - ) - - let mapped = try await mapper.map(pbxTarget: target) - #expect(mapped.metadata.tags == Set(["tag1", "tag2", "tag3"])) - } - - // MARK: - Helper Methods - - private func createTarget( - name: String, - productType: PBXProductType, - buildPhases: [PBXBuildPhase] = [], - buildSettings: [String: Any] = [:], - dependencies: [PBXTargetDependency] = [] - ) -> PBXNativeTarget { - let debugConfig = XCBuildConfiguration( - name: "Debug", - buildSettings: buildSettings - ) - - let releaseConfig = XCBuildConfiguration( - name: "Release", - buildSettings: buildSettings - ) - - let configurationList = XCConfigurationList( - buildConfigurations: [debugConfig, releaseConfig], - defaultConfigurationName: "Release" - ) - - mockProvider.pbxProj.add(object: debugConfig) - mockProvider.pbxProj.add(object: releaseConfig) - mockProvider.pbxProj.add(object: configurationList) - - let target = PBXNativeTarget.mock( - name: name, - buildConfigurationList: configurationList, - buildRules: [], - buildPhases: buildPhases, - dependencies: dependencies, - productType: productType, - pbxProj: mockProvider.pbxProj - ) - - return target - } } diff --git a/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift b/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift index 1b68592e..d50beb78 100644 --- a/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift +++ b/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift @@ -8,92 +8,93 @@ import XcodeProj @Suite struct ProjectParserTests { - private func createMockDirectory(withContents contents: [String]) throws -> AbsolutePath { - let tempDirectory = FileManager.default.temporaryDirectory - let mockDirectory = tempDirectory.appendingPathComponent("MockDirectory_\(UUID().uuidString)") - .path - try FileManager.default.createDirectory( - atPath: mockDirectory, withIntermediateDirectories: true) - - for item in contents { - let itemPath = mockDirectory + "/" + item - if item.hasSuffix(".xcworkspace") || item.hasSuffix(".xcodeproj") { - try FileManager.default.createDirectory(atPath: itemPath, withIntermediateDirectories: true) - } else { - FileManager.default.createFile(atPath: itemPath, contents: nil) - } + private func createMockDirectory(withContents contents: [String]) throws -> AbsolutePath { + let tempDirectory = FileManager.default.temporaryDirectory + let mockDirectory = tempDirectory.appendingPathComponent("MockDirectory_\(UUID().uuidString)") + .path + try FileManager.default.createDirectory( + atPath: mockDirectory, withIntermediateDirectories: true + ) + + for item in contents { + let itemPath = mockDirectory + "/" + item + if item.hasSuffix(".xcworkspace") || item.hasSuffix(".xcodeproj") { + try FileManager.default.createDirectory(atPath: itemPath, withIntermediateDirectories: true) + } else { + FileManager.default.createFile(atPath: itemPath, contents: nil) + } + } + + return try AbsolutePath(validating: mockDirectory) } - return try AbsolutePath(validating: mockDirectory) - } + /// Test parsing a valid `.xcworkspace` file + @Test func testParseWorkspace() async throws { + // Arrange + let mockDirectory = try createMockDirectory(withContents: ["MyWorkspace.xcworkspace"]) + let workspacePath = mockDirectory.appending(component: "MyWorkspace.xcworkspace") - /// Test parsing a valid `.xcworkspace` file - @Test func testParseWorkspace() async throws { - // Arrange - let mockDirectory = try createMockDirectory(withContents: ["MyWorkspace.xcworkspace"]) - let workspacePath = mockDirectory.appending(component: "MyWorkspace.xcworkspace") + // Act + let graph = try await ProjectParser.parse(atPath: workspacePath.pathString) - // Act - let graph = try await ProjectParser.parse(atPath: workspacePath.pathString) - - // Assert - #expect(graph.name == "MyWorkspace") - } + // Assert + #expect(graph.name == "MyWorkspace") + } - /// Test parsing a valid `.xcodeproj` file - @Test func testParseXcodeProject() async throws { - // Arrange - let mockDirectory = try createMockDirectory(withContents: ["MyProject.xcodeproj"]) - let projectPath = mockDirectory.appending(component: "MyProject.xcodeproj") + /// Test parsing a valid `.xcodeproj` file + @Test func testParseXcodeProject() async throws { + // Arrange + let mockDirectory = try createMockDirectory(withContents: ["MyProject.xcodeproj"]) + let projectPath = mockDirectory.appending(component: "MyProject.xcodeproj") - // Act - let graph = try await ProjectParser.parse(atPath: projectPath.pathString) + // Act + let graph = try await ProjectParser.parse(atPath: projectPath.pathString) - // Assert - #expect(graph.name == "Workspace") - } + // Assert + #expect(graph.name == "Workspace") + } - /// Test parsing when directory contains both `.xcworkspace` and `.xcodeproj` - @Test func testParseDirectoryWithWorkspaceAndProject() async throws { - // Arrange - let mockDirectory = try createMockDirectory(withContents: [ - "MyWorkspace.xcworkspace", "MyProject.xcodeproj", - ]) + /// Test parsing when directory contains both `.xcworkspace` and `.xcodeproj` + @Test func testParseDirectoryWithWorkspaceAndProject() async throws { + // Arrange + let mockDirectory = try createMockDirectory(withContents: [ + "MyWorkspace.xcworkspace", "MyProject.xcodeproj", + ]) - // Act - let graph = try await ProjectParser.parse(atPath: mockDirectory.pathString) + // Act + let graph = try await ProjectParser.parse(atPath: mockDirectory.pathString) - #expect(graph.name == "MyWorkspace") - } + #expect(graph.name == "MyWorkspace") + } - /// Test parsing when the directory contains no valid project files - @Test func testParseDirectoryNoProjects() async throws { - // Arrange - let mockDirectory = try createMockDirectory(withContents: ["ReadMe.md", "file.txt"]) + /// Test parsing when the directory contains no valid project files + @Test func testParseDirectoryNoProjects() async throws { + // Arrange + let mockDirectory = try createMockDirectory(withContents: ["ReadMe.md", "file.txt"]) - // Act & Assert - await #expect(throws: MappingError.noProjectsFound) { - try await ProjectParser.parse(atPath: mockDirectory.pathString) + // Act & Assert + await #expect(throws: MappingError.noProjectsFound) { + try await ProjectParser.parse(atPath: mockDirectory.pathString) + } } - } - /// Test handling a non-existent path - @Test func testParseNonExistentPath() async throws { - // Act & Assert - await #expect(throws: MappingError.pathNotFound(path: "/non/existent/path")) { - try await ProjectParser.parse(atPath: "/non/existent/path") + /// Test handling a non-existent path + @Test func testParseNonExistentPath() async throws { + // Act & Assert + await #expect(throws: MappingError.pathNotFound(path: "/non/existent/path")) { + try await ProjectParser.parse(atPath: "/non/existent/path") + } } - } - /// Test parsing when only `.xcodeproj` exists in the directory - @Test func testParseDirectoryOnlyXcodeProj() async throws { - // Arrange - let mockDirectory = try createMockDirectory(withContents: ["MyProject.xcodeproj"]) + /// Test parsing when only `.xcodeproj` exists in the directory + @Test func testParseDirectoryOnlyXcodeProj() async throws { + // Arrange + let mockDirectory = try createMockDirectory(withContents: ["MyProject.xcodeproj"]) - // Act - let graph = try await ProjectParser.parse(atPath: mockDirectory.pathString) + // Act + let graph = try await ProjectParser.parse(atPath: mockDirectory.pathString) - // Assert - #expect(graph.name == "Workspace") - } + // Assert + #expect(graph.name == "Workspace") + } } diff --git a/Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift b/Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift index 846ff632..925c470a 100644 --- a/Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift +++ b/Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift @@ -1,88 +1,95 @@ import Foundation import Testing -import XcodeProjToGraph import TestSupport +import XcodeProjToGraph @Suite struct LipoToolTests { - /// Test that `LipoTool.archs` successfully parses valid output. - @Test func testArchs_ValidOutput() async throws { - // Arrange - let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( - withContent: """ - #!/bin/sh - echo "arm64 x86_64" - exit 0 - """) + /// Test that `LipoTool.archs` successfully parses valid output. + @Test func testArchs_ValidOutput() async throws { + // Arrange + let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo "arm64 x86_64" + exit 0 + """ + ) - // Act - let result = try await LipoTool.archs( - paths: ["/mock/path/to/file"], executablePath: mockExecutablePath) + // Act + let result = try await LipoTool.archs( + paths: ["/mock/path/to/file"], executablePath: mockExecutablePath + ) - // Assert - #expect(result.architectures == [.arm64, .x8664]) - } + // Assert + #expect(result.architectures == [.arm64, .x8664]) + } - /// Test that `LipoTool.archs` handles a single architecture output. - @Test func testArchs_SingleArchitecture() async throws { - // Arrange - let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( - withContent: """ - #!/bin/sh - echo "arm64" - exit 0 - """) + /// Test that `LipoTool.archs` handles a single architecture output. + @Test func testArchs_SingleArchitecture() async throws { + // Arrange + let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo "arm64" + exit 0 + """ + ) - // Act - let result = try await LipoTool.archs( - paths: ["/mock/path/to/file"], executablePath: mockExecutablePath) + // Act + let result = try await LipoTool.archs( + paths: ["/mock/path/to/file"], executablePath: mockExecutablePath + ) - // Assert - #expect(result.architectures == [.arm64]) - } + // Assert + #expect(result.architectures == [.arm64]) + } - /// Test that `LipoTool.archs` throws an error on non-zero exit code. - @Test func testArchs_NonZeroExitCode() async throws { - // Arrange - let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( - withContent: """ - #!/bin/sh - echo "Error: invalid usage" - exit 1 - """) + /// Test that `LipoTool.archs` throws an error on non-zero exit code. + @Test func testArchs_NonZeroExitCode() async throws { + // Arrange + let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo "Error: invalid usage" + exit 1 + """ + ) - // Act & Assert - await #expect(throws: ProcessRunnerError.failedToRunProcess("Lipo returned non-zero exit code.")) { - try await LipoTool.archs(paths: ["/mock/path/to/file"], executablePath: mockExecutablePath) + // Act & Assert + await #expect(throws: ProcessRunnerError.failedToRunProcess("Lipo returned non-zero exit code.")) { + try await LipoTool.archs(paths: ["/mock/path/to/file"], executablePath: mockExecutablePath) + } } - } - /// Test that `LipoTool.archs` handles empty output gracefully. - @Test func testArchs_EmptyOutput() async throws { - // Arrange - let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( - withContent: """ - #!/bin/sh - echo "" - exit 0 - """) + /// Test that `LipoTool.archs` handles empty output gracefully. + @Test func testArchs_EmptyOutput() async throws { + // Arrange + let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo "" + exit 0 + """ + ) - // Act - let result = try await LipoTool.archs( - paths: ["/mock/path/to/file"], executablePath: mockExecutablePath) + // Act + let result = try await LipoTool.archs( + paths: ["/mock/path/to/file"], executablePath: mockExecutablePath + ) - // Assert - #expect(result.architectures.isEmpty == true) - } + // Assert + #expect(result.architectures.isEmpty == true) + } - /// Test that `LipoTool.archs` throws an error if the executable does not exist. - @Test func testArchs_ExecutableNotFound() async throws { - // Arrange - let nonExistentExecutable = "/nonexistent/path/to/lipo" + /// Test that `LipoTool.archs` throws an error if the executable does not exist. + @Test func testArchs_ExecutableNotFound() async throws { + // Arrange + let nonExistentExecutable = "/nonexistent/path/to/lipo" - // Act & Assert - await #expect(throws: ProcessRunnerError.executableNotFound(nonExistentExecutable)) { - try await LipoTool.archs(paths: ["/mock/path/to/file"], executablePath: nonExistentExecutable) + // Act & Assert + await #expect(throws: ProcessRunnerError.executableNotFound(nonExistentExecutable)) { + try await LipoTool.archs(paths: ["/mock/path/to/file"], executablePath: nonExistentExecutable) + } } - } } diff --git a/Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift b/Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift index 2078df7b..1255e31b 100644 --- a/Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift +++ b/Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift @@ -4,184 +4,189 @@ import XcodeProjToGraph @Suite struct ProcessRunnerTests { - private func createTemporaryExecutable( - name: String = "mockExecutable_\(UUID().uuidString)", - withContent content: String - ) throws -> String { - let tempDirectory = FileManager.default.temporaryDirectory - let mockExecutablePath = tempDirectory.appendingPathComponent(name).path - - // Write the content to the temporary file - try content.write(toFile: mockExecutablePath, atomically: true, encoding: .utf8) - - // Make the file executable - try FileManager.default.setAttributes( - [.posixPermissions: 0o755], ofItemAtPath: mockExecutablePath) - - return mockExecutablePath - } - - /// Test that `ProcessRunner` runs a valid executable successfully and parses the result. - @Test func testRun_ValidExecutable_Success() async throws { - // Arrange - let mockExecutablePath = try createTemporaryExecutable( - withContent: """ - #!/bin/sh - echo "Hello, World!" - exit 0 - """ - ) - - let mockExecutable = Executable.custom( - mockExecutablePath, - [], - { result in - result.stdout.trimmingCharacters(in: .whitespacesAndNewlines) - } - ) - - // Act - let output: String = try await ProcessRunner.run( - executable: mockExecutable, - environment: nil, - workingDirectory: nil, - throwOnNonZeroExit: true - ) - - // Assert - #expect(output == "Hello, World!") - } - - /// Test that `ProcessRunner` throws an error if the executable does not exist. - @Test func testRun_ExecutableNotFound_ThrowsError() async throws { - // Arrange - let nonExistentExecutable = Executable.custom( - "/nonexistent/path", - [], - { _ in } - ) - - // Act & Assert - await #expect(throws: ProcessRunnerError.executableNotFound("/nonexistent/path")) { - try await ProcessRunner.run( - executable: nonExistentExecutable, - environment: nil, - workingDirectory: nil, - throwOnNonZeroExit: true - ) + private func createTemporaryExecutable( + name: String = "mockExecutable_\(UUID().uuidString)", + withContent content: String + ) throws -> String { + let tempDirectory = FileManager.default.temporaryDirectory + let mockExecutablePath = tempDirectory.appendingPathComponent(name).path + + // Write the content to the temporary file + try content.write(toFile: mockExecutablePath, atomically: true, encoding: .utf8) + + // Make the file executable + try FileManager.default.setAttributes( + [.posixPermissions: 0o755], ofItemAtPath: mockExecutablePath + ) + + return mockExecutablePath } - } - - /// Test that `ProcessRunner` throws an error on non-zero exit when `throwOnNonZeroExit` is enabled. - @Test func testRun_NonZeroExitCode_ThrowsError() async throws { - // Arrange - let mockExecutablePath = try createTemporaryExecutable( - withContent: """ - #!/bin/sh - exit 1 - """) - - let mockExecutable = Executable.custom( - mockExecutablePath, - [], - { _ in } - ) - - // Act & Assert - await #expect(throws: ProcessRunnerError.nonZeroExitCode(1, "")) { - try await ProcessRunner.run( - executable: mockExecutable, - environment: nil, - workingDirectory: nil, - throwOnNonZeroExit: true - ) + + /// Test that `ProcessRunner` runs a valid executable successfully and parses the result. + @Test func testRun_ValidExecutable_Success() async throws { + // Arrange + let mockExecutablePath = try createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo "Hello, World!" + exit 0 + """ + ) + + let mockExecutable = Executable.custom( + mockExecutablePath, + [], + { result in + result.stdout.trimmingCharacters(in: .whitespacesAndNewlines) + } + ) + + // Act + let output: String = try await ProcessRunner.run( + executable: mockExecutable, + environment: nil, + workingDirectory: nil, + throwOnNonZeroExit: true + ) + + // Assert + #expect(output == "Hello, World!") + } + + /// Test that `ProcessRunner` throws an error if the executable does not exist. + @Test func testRun_ExecutableNotFound_ThrowsError() async throws { + // Arrange + let nonExistentExecutable = Executable.custom( + "/nonexistent/path", + [], + { _ in } + ) + + // Act & Assert + await #expect(throws: ProcessRunnerError.executableNotFound("/nonexistent/path")) { + try await ProcessRunner.run( + executable: nonExistentExecutable, + environment: nil, + workingDirectory: nil, + throwOnNonZeroExit: true + ) + } + } + + /// Test that `ProcessRunner` throws an error on non-zero exit when `throwOnNonZeroExit` is enabled. + @Test func testRun_NonZeroExitCode_ThrowsError() async throws { + // Arrange + let mockExecutablePath = try createTemporaryExecutable( + withContent: """ + #!/bin/sh + exit 1 + """ + ) + + let mockExecutable = Executable.custom( + mockExecutablePath, + [], + { _ in } + ) + + // Act & Assert + await #expect(throws: ProcessRunnerError.nonZeroExitCode(1, "")) { + try await ProcessRunner.run( + executable: mockExecutable, + environment: nil, + workingDirectory: nil, + throwOnNonZeroExit: true + ) + } } - } - - /// Test that `ProcessRunner` does not throw on non-zero exit when `throwOnNonZeroExit` is disabled. - @Test func testRun_NonZeroExitCode_NoThrow() async throws { - // Arrange - let mockExecutablePath = try createTemporaryExecutable( - withContent: """ - #!/bin/sh - exit 1 - """) - - let mockExecutable = Executable.custom( - mockExecutablePath, - [], - { result in - result.exitCode // Simply return the exit code for validation. - } - ) - - // Act - let exitCode: Int32 = try await ProcessRunner.run( - executable: mockExecutable, - environment: nil, - workingDirectory: nil, - throwOnNonZeroExit: false - ) - - #expect(exitCode == 1) - } - - /// Test that `ProcessRunner` parses UTF-8 output correctly. - @Test func testRun_ParsesUtf8Output() async throws { - // Arrange - let mockExecutablePath = try createTemporaryExecutable( - withContent: """ - #!/bin/sh - echo "你好, 世界!" - exit 0 - """) - - let mockExecutable = Executable.custom( - mockExecutablePath, - [], - { result in - result.stdout.trimmingCharacters(in: .whitespacesAndNewlines) - } - ) - - // Act - let output: String = try await ProcessRunner.run( - executable: mockExecutable, - environment: nil, - workingDirectory: nil, - throwOnNonZeroExit: true - ) - - // Assert - #expect(output == "你好, 世界!") - } - - /// Test that `ProcessRunner` throws an error if the output is not valid UTF-8. - @Test func testRun_InvalidUtf8Output_ThrowsError() async throws { - // Arrange - let mockExecutablePath = try createTemporaryExecutable( - withContent: """ - #!/bin/sh - echo -e '\\xff' # Invalid UTF-8 sequence - - """) - - let invalidUtf8Executable = Executable.custom( - mockExecutablePath, - [], - { _ in - throw ProcessRunnerError.invalidUTF8InOutput - } - ) - - // Act & Assert - await #expect(throws: ProcessRunnerError.invalidUTF8InOutput) { - try await ProcessRunner.run( - executable: invalidUtf8Executable, - environment: nil, - workingDirectory: nil, - throwOnNonZeroExit: false - ) + + /// Test that `ProcessRunner` does not throw on non-zero exit when `throwOnNonZeroExit` is disabled. + @Test func testRun_NonZeroExitCode_NoThrow() async throws { + // Arrange + let mockExecutablePath = try createTemporaryExecutable( + withContent: """ + #!/bin/sh + exit 1 + """ + ) + + let mockExecutable = Executable.custom( + mockExecutablePath, + [], + { result in + result.exitCode // Simply return the exit code for validation. + } + ) + + // Act + let exitCode: Int32 = try await ProcessRunner.run( + executable: mockExecutable, + environment: nil, + workingDirectory: nil, + throwOnNonZeroExit: false + ) + + #expect(exitCode == 1) + } + + /// Test that `ProcessRunner` parses UTF-8 output correctly. + @Test func testRun_ParsesUtf8Output() async throws { + // Arrange + let mockExecutablePath = try createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo "你好, 世界!" + exit 0 + """ + ) + + let mockExecutable = Executable.custom( + mockExecutablePath, + [], + { result in + result.stdout.trimmingCharacters(in: .whitespacesAndNewlines) + } + ) + + // Act + let output: String = try await ProcessRunner.run( + executable: mockExecutable, + environment: nil, + workingDirectory: nil, + throwOnNonZeroExit: true + ) + + // Assert + #expect(output == "你好, 世界!") + } + + /// Test that `ProcessRunner` throws an error if the output is not valid UTF-8. + @Test func testRun_InvalidUtf8Output_ThrowsError() async throws { + // Arrange + let mockExecutablePath = try createTemporaryExecutable( + withContent: """ + #!/bin/sh + echo -e '\\xff' # Invalid UTF-8 sequence + + """ + ) + + let invalidUtf8Executable = Executable.custom( + mockExecutablePath, + [], + { _ in + throw ProcessRunnerError.invalidUTF8InOutput + } + ) + + // Act & Assert + await #expect(throws: ProcessRunnerError.invalidUTF8InOutput) { + try await ProcessRunner.run( + executable: invalidUtf8Executable, + environment: nil, + workingDirectory: nil, + throwOnNonZeroExit: false + ) + } } - } } diff --git a/Tuist/ProjectDescriptionHelpers/Module.swift b/Tuist/ProjectDescriptionHelpers/Module.swift index 9ae3f552..6d6800ca 100644 --- a/Tuist/ProjectDescriptionHelpers/Module.swift +++ b/Tuist/ProjectDescriptionHelpers/Module.swift @@ -134,10 +134,9 @@ public enum Module: String, CaseIterable { .external(name: "XcodeProj"), ] case .testSupport: - [ - .target(name: Module.xcodeProjToGraph.rawValue) - ] - + [ + .target(name: Module.xcodeProjToGraph.rawValue), + ] } return dependencies } @@ -152,8 +151,6 @@ public enum Module: String, CaseIterable { .target(name: Module.testSupport.rawValue), .external(name: "InlineSnapshotTesting"), ] - - } dependencies = dependencies + [.target(name: targetName)] return dependencies From 5b912964df30cae26f333465e298262c371b9936 Mon Sep 17 00:00:00 2001 From: Andy Kolean Date: Sun, 15 Dec 2024 17:13:05 -0500 Subject: [PATCH 03/40] [ProjectDescriptionHelpers] add fixtures to resources --- Tuist/ProjectDescriptionHelpers/Module.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Tuist/ProjectDescriptionHelpers/Module.swift b/Tuist/ProjectDescriptionHelpers/Module.swift index 6d6800ca..9a048c06 100644 --- a/Tuist/ProjectDescriptionHelpers/Module.swift +++ b/Tuist/ProjectDescriptionHelpers/Module.swift @@ -186,6 +186,12 @@ public enum Module: String, CaseIterable { default: rootFolder = "Sources" } + let resources: ResourceFileElements = switch self { + case .xcodeGraph, .xcodeProjToGraph: + [] + case .testSupport: + ["Fixtures"] + } var debugSettings: ProjectDescription.SettingsDictionary = ["SWIFT_ACTIVE_COMPILATION_CONDITIONS": "$(inherited) MOCKING"] var releaseSettings: ProjectDescription.SettingsDictionary = [:] @@ -215,7 +221,8 @@ public enum Module: String, CaseIterable { bundleId: "io.tuist.\(name)", deploymentTargets: .macOS("12.0"), infoPlist: .default, - sources: ["\(rootFolder)/\(name)/**/*.swift"], + sources: [.glob("\(rootFolder)/\(name)/**/*.swift", excluding: ["**/Fixtures/**"])], + resources: resources, dependencies: dependencies, settings: settings ) From 75bf656adcec3b5fe7f4c034f797961361f9f584 Mon Sep 17 00:00:00 2001 From: Andy Kolean Date: Sun, 15 Dec 2024 21:31:04 -0500 Subject: [PATCH 04/40] [WorkspaceMapperTests] add unit tests --- .../Sources/MessagesViewController.swift | 1 - .../Mocks/MockProjectProvider.swift | 68 +- .../Mocks/MockTargetsAndDependencies.swift | 18 + .../{ => Mocks}/WorkspaceFixture.swift | 16 +- .../XcodeGraph/Models/PlatformFilter.swift | 3 +- Sources/XcodeGraph/Models/Project.swift | 2 +- .../Extensions/AbsolutePath+Extensions.swift | 30 +- .../Extensions/PBXProject+Extensions.swift | 11 + .../XCWorkspaceDataFileRef+Extensions.swift | 26 +- .../Mappers/Build/BuildPhaseMapper.swift | 17 +- .../Mappers/Dependency/DependencyMapper.swift | 32 +- .../Dependency/PlatformConditionMapper.swift | 6 +- .../TargetDependency+GraphMapping.swift | 2 + .../Mappers/Graph/GraphMapper.swift | 82 ++- .../Mappers/Graph/MappingError.swift | 12 +- .../Mappers/Graph/ProjectParser.swift | 76 ++- .../Mappers/Project/PackageMapper.swift | 69 +- .../Mappers/Project/ProjectAttribute.swift | 8 + .../Mappers/Project/ProjectMapper.swift | 140 ++-- .../Mappers/Project/ProjectProvider.swift | 54 +- .../Settings/ConfigurationMatcher.swift | 2 +- .../Mappers/Settings/SettingsMapper.swift | 79 ++- .../PBXTarget+BuildSettings.swift | 27 + .../TargetAndSchemes/SchemeMapper.swift | 109 ++- .../TargetAndSchemes/TargetMapper.swift | 105 +-- .../Mappers/Workspace/WorkspaceMapper.swift | 80 ++- .../Mappers/Workspace/WorkspaceProvider.swift | 42 +- .../ProcessRunner/Executable.swift | 12 +- .../ProcessRunner/ProcessResult.swift | 13 +- .../ProcessRunner/ProcessRunner.swift | 11 +- .../ProcessRunner/ProcessRunnerError.swift | 1 + .../XcodeProjToGraph.docc/Documentation.md | 42 +- ...+commandLineToolWithDynamicFramework.swift | 24 +- .../IntegrationTests+iosAppLarge.swift | 2 +- ...ntegrationTests+iosAppWithExtensions.swift | 643 +++++++++++++++++- ...egrationTests+iosAppWithMultiConfigs.swift | 128 +++- ...onTests+iosAppWithRemoteSwiftPackage.swift | 24 +- ...ationTests+iosAppWithSpmDependencies.swift | 39 +- ...ationTests+iosAppWithStaticLibraries.swift | 62 +- ...icrofeatureArchitectureStaticLinking.swift | 137 +++- ...ts+ios_app_with_transitive_framework.swift | 137 +++- ...ionTests+macosAppWithSystemExtension.swift | 24 +- ...rmAppWithMacrosAndEmbeddedWatchosApp.swift | 326 ++++++++- .../Xcode/Build/BuildPhaseMapperTests.swift | 487 +++++-------- .../Xcode/Build/BuildRuleMapperTests.swift | 53 +- .../Dependency/DependencyMapperTests.swift | 71 +- .../TargetDependencyExtensionsTests.swift | 45 +- .../Xcode/GraphMapper/GraphMapperTests.swift | 56 +- .../Xcode/Project/PackageMapperTests.swift | 57 +- .../Xcode/Project/ProjectMapperTests.swift | 28 +- .../Xcode/Settings/BuildSettingsTests.swift | 30 +- .../Settings/ConfigurationMatcherTests.swift | 15 +- .../Xcode/Settings/SettingsMapperTests.swift | 122 ++-- .../Xcode/Target/SchemeMapperTests.swift | 63 +- .../Xcode/Target/TargetMapperTests.swift | 21 +- .../Workspace/WorkspaceMapperTests.swift | 153 +++++ .../ParserTests/ProjectParserTests.swift | 27 +- .../ProcessTests/LipoToolTests.swift | 20 +- .../ProcessTests/ProcessRunnerTests.swift | 33 +- 59 files changed, 2920 insertions(+), 1103 deletions(-) rename Sources/TestSupport/{ => Mocks}/WorkspaceFixture.swift (73%) create mode 100644 Sources/XcodeProjToGraph/Extensions/PBXProject+Extensions.swift create mode 100644 Sources/XcodeProjToGraph/Mappers/Project/ProjectAttribute.swift diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift index 59071594..c0164553 100644 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift +++ b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift @@ -2,7 +2,6 @@ import Messages import UIKit class MessagesViewController: MSMessagesAppViewController { - // MARK: - Conversation Handling override func willBecomeActive(with _: MSConversation) { diff --git a/Sources/TestSupport/Mocks/MockProjectProvider.swift b/Sources/TestSupport/Mocks/MockProjectProvider.swift index db566072..b1ae08c4 100644 --- a/Sources/TestSupport/Mocks/MockProjectProvider.swift +++ b/Sources/TestSupport/Mocks/MockProjectProvider.swift @@ -1,3 +1,4 @@ +import Foundation import Path import Testing import XcodeGraph @@ -5,10 +6,10 @@ import XcodeProj @testable import XcodeProjToGraph -struct MockWorkspaceProvider: WorkspaceProviding { - var workspaceDirectory: AbsolutePath - var xcWorkspacePath: AbsolutePath - var xcworkspace: XCWorkspace +public struct MockWorkspaceProvider: WorkspaceProviding { + public var workspaceDirectory: AbsolutePath + public var xcWorkspacePath: AbsolutePath + public var xcworkspace: XCWorkspace public init(xcWorkspacePath: AbsolutePath, xcworkspace: XCWorkspace) { self.xcWorkspacePath = xcWorkspacePath @@ -17,15 +18,15 @@ struct MockWorkspaceProvider: WorkspaceProviding { } } -struct MockProjectProvider: ProjectProviding { - let sourceDirectory: AbsolutePath - let xcodeProjPath: AbsolutePath - let xcodeProj: XcodeProj - var pbxProj: PBXProj { +public struct MockProjectProvider: ProjectProviding { + public let sourceDirectory: AbsolutePath + public let xcodeProjPath: AbsolutePath + public let xcodeProj: XcodeProj + public var pbxProj: PBXProj { xcodeProj.pbxproj } - init( + public init( sourceDirectory: String = "/tmp", projectName: String = "TestProject", configurationList: XCConfigurationList? = nil, @@ -45,7 +46,52 @@ struct MockProjectProvider: ProjectProviding { xcodeProj = XcodeProj(workspace: XCWorkspace(), pbxproj: pbxProj) } - func pbxProject() throws -> PBXProject { + public func pbxProject() throws -> PBXProject { return xcodeProj.pbxproj.projects.first! } } + +extension MockProjectProvider { + public static func makeBasicProjectProvider( + projectName: String = "TestProject", + sourceDirectory: String = "/tmp/\(UUID().uuidString)" + ) -> MockProjectProvider { + return MockProjectProvider( + sourceDirectory: sourceDirectory, + projectName: projectName + ) + } + + public func addTargets(_ targets: [PBXNativeTarget]) throws { + let project = try pbxProject() + project.targets.append(contentsOf: targets) + } +} + +extension ProjectMapper { + public func createMappedProject( + projectName: String = "TestProject", + targets: [PBXNativeTarget] = [] + ) async throws -> Project { + let provider = MockProjectProvider.makeBasicProjectProvider(projectName: projectName) + try provider.addTargets(targets) + + let mapper = ProjectMapper(projectProvider: provider) + return try await mapper.mapProject() + } + + public func createMappedGraph( + graphType: GraphType, + projectProviders: [AbsolutePath: MockProjectProvider] + ) async throws -> XcodeGraph.Graph { + let mapper = GraphMapper(graphType: graphType) { path in + guard let provider = projectProviders[path] else { + Issue.record("Unexpected project path requested: \(path)") + throw MappingError.noProjectsFound(path: path.pathString) + } + return provider + } + + return try await mapper.xcodeGraph() + } +} diff --git a/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift b/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift index 3a5e2b78..750b6996 100644 --- a/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift +++ b/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift @@ -170,3 +170,21 @@ extension PBXNativeTarget { return target } } + +extension XCRemoteSwiftPackageReference { + static func mock( + repositoryURL: String, + versionRequirement: VersionRequirement? + ) -> XCRemoteSwiftPackageReference { + return XCRemoteSwiftPackageReference( + repositoryURL: repositoryURL, + versionRequirement: versionRequirement + ) + } +} + +extension XCLocalSwiftPackageReference { + static func mock(relativePath: String) -> XCLocalSwiftPackageReference { + return XCLocalSwiftPackageReference(relativePath: relativePath) + } +} diff --git a/Sources/TestSupport/WorkspaceFixture.swift b/Sources/TestSupport/Mocks/WorkspaceFixture.swift similarity index 73% rename from Sources/TestSupport/WorkspaceFixture.swift rename to Sources/TestSupport/Mocks/WorkspaceFixture.swift index 9652fd92..3ff8d816 100644 --- a/Sources/TestSupport/WorkspaceFixture.swift +++ b/Sources/TestSupport/Mocks/WorkspaceFixture.swift @@ -4,6 +4,7 @@ import XcodeGraph // MARK: - Workspace Fixtures +/// Provides references to sample Xcode workspace fixtures for testing. public enum WorkspaceFixture: String, CaseIterable { case commandLineToolWithDynamicFramework = "command_line_tool_with_dynamic_framework/CommandLineTool" @@ -23,9 +24,18 @@ public enum WorkspaceFixture: String, CaseIterable { public var fileExtension: String { "xcworkspace" } + /// Returns the absolute path to the fixture workspace. Adjust the base path as needed. public func absolutePath() throws -> AbsolutePath { - return try AbsolutePath.resolvePath( - "/Users/andykolean/Developer/XcodeGraphMapper/Tests/TestSupport/Fixtures/\(rawValue).xcworkspace" - ) + print(#filePath) + + let relativePath = try RelativePath(validating: "Fixtures/\(rawValue).\(fileExtension)") + let p = try AbsolutePath.resolvePath(#filePath) + .parentDirectory + .parentDirectory + .appending(relativePath) + + print(p) + + return p } } diff --git a/Sources/XcodeGraph/Models/PlatformFilter.swift b/Sources/XcodeGraph/Models/PlatformFilter.swift index a7bff439..f62de5cc 100644 --- a/Sources/XcodeGraph/Models/PlatformFilter.swift +++ b/Sources/XcodeGraph/Models/PlatformFilter.swift @@ -3,7 +3,7 @@ import Foundation /// Convenience typealias to be used to ensure unique filters are applied public typealias PlatformFilters = Set -extension PlatformFilters: Comparable { +extension PlatformFilters: @retroactive Comparable { public static func < (lhs: Set, rhs: Set) -> Bool { lhs.map(\.xcodeprojValue).sorted().joined() < rhs.map(\.xcodeprojValue).sorted().joined() } @@ -54,7 +54,6 @@ public enum PlatformFilter: Comparable, Hashable, Codable, CaseIterable, Sendabl case .visionos: return .visionOS case .driverkit: - // TODO: Add support for it return nil } } diff --git a/Sources/XcodeGraph/Models/Project.swift b/Sources/XcodeGraph/Models/Project.swift index 85a975a9..89a67d8f 100644 --- a/Sources/XcodeGraph/Models/Project.swift +++ b/Sources/XcodeGraph/Models/Project.swift @@ -12,7 +12,7 @@ public enum ProjectType: Hashable, Equatable, Codable, CustomStringConvertible, public var description: String { switch self { case .local: "local project" - case let .external(hash): "external project" + case .external: "external project" } } } diff --git a/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift index 55ddbc86..1ab3b14c 100644 --- a/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift +++ b/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift @@ -2,6 +2,7 @@ import Foundation import Path import XcodeGraph +/// Common file extensions encountered in Xcode projects and their associated artifacts. enum FileExtension: String { case xcodeproj case xcworkspace @@ -15,25 +16,30 @@ enum FileExtension: String { } extension AbsolutePath { + /// Attempts to resolve an array of path strings into `AbsolutePath` instances. + /// + /// - Parameter paths: The string paths to resolve. + /// - Returns: An array of `AbsolutePath` if resolution succeeds. public static func resolvePaths( - _ paths: [String]?, - file _: String = #file, - line _: Int = #line, - function _: String = #function + _ paths: [String]? ) throws -> [AbsolutePath] { return try paths?.compactMap { try AbsolutePath.resolvePath($0) } ?? [] } + /// Attempts to resolve an optional path string into an `AbsolutePath`. + /// + /// - Parameter path: The path string to resolve. + /// - Returns: An `AbsolutePath` or `nil` if the path is `nil`. public static func resolveOptionalPath( - _ path: String?, - file _: String = #file, - line _: Int = #line, - function _: String = #function + _ path: String? ) throws -> AbsolutePath? { guard let path else { return nil } return try AbsolutePath.resolvePath(path) } + /// Resolves a path string into an `AbsolutePath`, optionally relative to another path. + /// + /// Throws an error if the path is invalid. public static func resolvePath( _ path: String, relativeTo: AbsolutePath? = nil, @@ -54,13 +60,15 @@ extension AbsolutePath { """ throw NSError( domain: "GraphMapperError", code: 1, - userInfo: [ - NSLocalizedDescriptionKey: message, - ] + userInfo: [NSLocalizedDescriptionKey: message] ) } } + /// Maps a path by its extension to a `TargetDependency` if applicable. + /// + /// - Parameter condition: Optional platform condition. + /// - Returns: A `TargetDependency` if the extension matches known dependency types. public func mapByExtension(condition: PlatformCondition?) -> TargetDependency? { let status: LinkingStatus = .required let absPath = self diff --git a/Sources/XcodeProjToGraph/Extensions/PBXProject+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/PBXProject+Extensions.swift new file mode 100644 index 00000000..c6cbe15e --- /dev/null +++ b/Sources/XcodeProjToGraph/Extensions/PBXProject+Extensions.swift @@ -0,0 +1,11 @@ +import XcodeProj + +extension PBXProject { + /// Retrieves the value of a specific project attribute. + /// + /// - Parameter attr: The attribute key to look up. + /// - Returns: The value of the attribute if it exists, or `nil` if not found. + func attribute(for attr: ProjectAttribute) -> String? { + attributes[attr.rawValue] as? String + } +} diff --git a/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift index 513ab45a..8d1ed26a 100644 --- a/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift +++ b/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift @@ -2,35 +2,33 @@ import Path import XcodeProj extension XCWorkspaceDataFileRef { + /// Resolves the absolute path referenced by this `XCWorkspaceDataFileRef`. + /// + /// - Parameter srcPath: The workspace source root path. + /// - Returns: The resolved `AbsolutePath` of this file reference. func absolutePath(srcPath: AbsolutePath) throws -> AbsolutePath { switch location { case let .absolute(path): - let absolutePath = try AbsolutePath.resolvePath(path) - return absolutePath + return try AbsolutePath.resolvePath(path) case let .container(subPath): let relativePath = try RelativePath(validating: subPath) - let absolutePath = srcPath.appending(relativePath) - return absolutePath + return srcPath.appending(relativePath) case let .developer(subPath): let relativePath = try RelativePath(validating: subPath) let developerPath = try AbsolutePath.resolvePath("/Applications/Xcode.app/Contents/Developer") - let absolutePath = developerPath.appending(relativePath) - return absolutePath + return developerPath.appending(relativePath) case let .group(subPath): // Group paths are relative to the workspace file itself let relativePath = try RelativePath(validating: subPath) - let absolutePath = srcPath.appending(relativePath) - return absolutePath + return srcPath.appending(relativePath) case let .current(subPath): - // Current paths are relative to the current directory (commonly workspace path) + // Current paths are relative to the current directory let relativePath = try RelativePath(validating: subPath) - let absolutePath = srcPath.appending(relativePath) - return absolutePath + return srcPath.appending(relativePath) case let .other(type, subPath): - // Handle other path types by prefixing with the type and appending the subpath + // Other path types: prefix with the type and append subpath let relativePath = try RelativePath(validating: "\(type)/\(subPath)") - let absolutePath = srcPath.appending(relativePath) - return absolutePath + return srcPath.appending(relativePath) } } } diff --git a/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift b/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift index 53e5b20e..24398f87 100644 --- a/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift @@ -158,12 +158,12 @@ public final class BuildPhaseMapper: BuildPhaseMapping { guard let pbxProject = xcodeProj.pbxproj.projects.first, let mainGroup = pbxProject.mainGroup else { - throw MappingError.noProjectsFound + throw MappingError.noProjectsFound(path: projectProvider.xcodeProjPath.pathString) } let allFiles = try await collectFiles(from: mainGroup) let filesInBuildPhases = try await getFilesInBuildPhases(target: target) - let additionalFiles = allFiles.subtracting(filesInBuildPhases) + let additionalFiles = allFiles.subtracting(filesInBuildPhases).sorted() return additionalFiles.map { FileElement.file(path: $0) } } @@ -266,13 +266,16 @@ public final class BuildPhaseMapper: BuildPhaseMapping { } private func mapResourceElement(_ buildFile: PBXBuildFile) async throws -> [ResourceFileElement] { - try await mapResourceElement(buildFile.file) + guard let file = buildFile.file else { return [] } + if let variantGroup = file as? PBXVariantGroup { + return try await mapVariantGroup(variantGroup) + } else { + return try await mapResourceElement(file) + } } - private func mapResourceElement(_ fileElement: PBXFileElement?) async throws -> [ResourceFileElement] { - if let fileRef = fileElement, - let pathString = try fileRef.fullPath(sourceRoot: projectProvider.sourcePathString) - { + private func mapResourceElement(_ fileElement: PBXFileElement) async throws -> [ResourceFileElement] { + if let pathString = try fileElement.fullPath(sourceRoot: projectProvider.sourcePathString) { let absPath = try AbsolutePath.resolvePath(pathString) return [.file(path: absPath)] } diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift index 643a50ed..5186bf4f 100644 --- a/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift @@ -31,11 +31,32 @@ protocol DependencyTypeMapper: Sendable { func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? } -/// A mapper that orchestrates the mapping of all target dependencies by leveraging multiple specialized mappers. +/// A mapper that orchestrates the mapping of all target dependencies using multiple specialized mappers. /// -/// The `DependencyMapper` tries each registered `DependencyTypeMapper` in turn, returning the first successful result. -/// This design allows for easy extension of dependency types without modifying a single large mapper. -final class DependencyMapper: DependencyMapping { +/// `DependencyMapper` tries each registered `DependencyTypeMapper` in turn until it finds one that can map a given +/// `PBXTargetDependency`. This design supports adding new dependency types without modifying a single large mapping function. +/// +/// **Example Usage:** +/// ```swift +/// // Assume you have a ProjectProvider instance for your Xcode project: +/// let projectProvider: ProjectProviding = ... +/// +/// // Create a DependencyMapper to handle dependencies in a target. +/// let dependencyMapper = DependencyMapper(projectProvider: projectProvider) +/// +/// // Retrieve a PBXTarget from your XcodeProj: +/// let pbxTarget: PBXTarget = ... +/// +/// // Map all dependencies of the PBXTarget into TargetDependency models: +/// let targetDependencies = try await dependencyMapper.mapDependencies(target: pbxTarget) +/// +/// // 'targetDependencies' now contains a uniform list of dependencies (targets, packages, frameworks, etc.) +/// // which can be analyzed, transformed, or used for code generation. +/// ``` +/// +/// This straightforward integration lets you focus on what to do with the resolved dependencies, +/// rather than the nuances of resolving them from Xcode's project structure. +public final class DependencyMapper: DependencyMapping { private let projectProvider: ProjectProviding private let typeMappers: [DependencyTypeMapper] @@ -147,11 +168,14 @@ final class ProxyDependencyMapper: DependencyTypeMapper { switch remoteGlobalID { case let .object(object): if let fileReference = object as? PBXFileReference { + // If `fileMapper.mapDependency` returns nil, it means this file type + // doesn't map to a known `TargetDependency` (e.g., unsupported extension). return try await fileMapper.mapDependency( pathString: fileReference.path, condition: condition ) } else if let referenceProxy = object as? PBXReferenceProxy { + // Similarly, nil here indicates that the referenced file isn't a supported dependency type. return try await fileMapper.mapDependency( pathString: referenceProxy.path, condition: condition diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift index f85ee5a0..4ff60d92 100644 --- a/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift @@ -3,10 +3,10 @@ import XcodeProj /// A mapper for platform-related conditions, extracting platform filters from `PBXTargetDependency`. enum PlatformConditionMapper { - /// Maps the platform filters specified on a `PBXTargetDependency` into a `PlatformCondition`. + /// Maps the platform filters on a given `PBXTargetDependency` into a `PlatformCondition`. /// - /// - Parameter dependency: The `PBXTargetDependency` to inspect. - /// - Returns: A `PlatformCondition` representing the platforms this dependency applies to, or `nil` if none. + /// Returns `nil` if no filters apply, meaning the dependency isn't restricted by platform and + /// should be considered available on all platforms. public static func mapCondition(dependency: PBXTargetDependency) -> PlatformCondition? { var filters = Set(dependency.platformFilters ?? []) if let singleFilter = dependency.platformFilter { diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift index 0404a5b8..f2b8e132 100644 --- a/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift +++ b/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift @@ -69,6 +69,8 @@ extension TargetDependency { case .dynamicLibrary, .textBasedDynamicLibrary: return .dynamic default: + // Fallback: If the extension isn't recognized, default to dynamic linking. + // Future maintainers might refine this logic if other file types appear. return .dynamic } }() diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift b/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift index c5fdb75f..8fd2a25c 100644 --- a/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift @@ -4,11 +4,12 @@ import PathKit import XcodeGraph import XcodeProj -/// Specifies the type of graph to generate. +/// Specifies the type of graph to generate for code analysis or tooling tasks. /// -/// - `.workspace(WorkspaceProviding)`: Constructs a graph from a workspace provided by a type conforming to `WorkspaceProviding`. -/// - `.project(AbsolutePath)`: Constructs a graph from a single project located at the given path, treating it as a workspace -/// with one project. +/// `GraphType` allows you to choose whether to build a graph from a single project or from an entire workspace: +/// - `.workspace(WorkspaceProviding)`: Constructs a graph from a workspace (potentially containing multiple projects). +/// - `.project(AbsolutePath)`: Constructs a graph from a single project at the given path, treating it as a workspace with one +/// project. public enum GraphType: Sendable { case workspace(WorkspaceProviding) case project(AbsolutePath) @@ -16,25 +17,49 @@ public enum GraphType: Sendable { /// A mapper that constructs a complete `XcodeGraph.Graph` from a given workspace or project. /// -/// This mapper aggregates data from projects, packages, and dependencies to produce a fully -/// formed graph. It resolves each project, maps targets, packages, and dependencies, and then -/// assembles them into a final `XcodeGraph.Graph` model. +/// `GraphMapper` orchestrates the process of aggregating data from all relevant sources: +/// - Projects (via `ProjectMapper`), +/// - Targets, Packages, and Dependencies (translated into a uniform graph model), +/// - Platform-specific conditions for dependencies (e.g., iOS-only frameworks), /// -/// The resulting graph can be used for analysis, generation of derived artifacts, or other -/// tooling tasks. +/// The resulting `XcodeGraph.Graph` model can be used for: +/// - Dependency analysis: Understand how targets and packages interrelate. +/// - Code generation: Produce derived artifacts, such as resource accessors or configuration files. +/// - Tooling integration: Serve as input to custom build tools, linters, or visualizers. /// -/// Typical usage involves creating a `GraphMapper` with a specified `GraphType` and then calling -/// `xcodeGraph()` to produce the graph. +/// **Example Usage:** +/// ```swift +/// // Suppose you have a WorkspaceProvider for a workspace: +/// let workspaceProvider: WorkspaceProviding = ... +/// let graphMapper = GraphMapper(graphType: .workspace(workspaceProvider)) +/// +/// // Or, for a single project: +/// let projectPath: AbsolutePath = ... +/// let graphMapper = GraphMapper(graphType: .project(projectPath)) +/// +/// // Construct the graph: +/// let graph = try await graphMapper.xcodeGraph() +/// +/// // 'graph' now contains a unified representation of projects, targets, packages, and dependencies. +/// // You can analyze it, generate code, or integrate it with other developer tools. +/// ``` public final class GraphMapper: Sendable { + // MARK: - Properties + private let projectProviderClosure: @Sendable (AbsolutePath) async throws -> ProjectProviding public let graphType: GraphType - /// Initializes the mapper with a specified graph type and an optional project provider closure. + // MARK: - Initialization + + /// Initializes the mapper with a specified `GraphType` and an optional project provider closure. + /// + /// The `projectProviderClosure` allows for custom logic when creating `ProjectProviding` instances. By default, + /// it initializes a `ProjectProvider` from the given path. /// /// - Parameters: - /// - graphType: The type of graph (workspace or project) to map. - /// - projectProviderClosure: A closure that, given a project path, returns a `ProjectProviding`. - /// By default, it initializes a `ProjectProvider` from the given `AbsolutePath`. + /// - graphType: The type of graph to build (workspace or project). + /// - projectProviderClosure: A closure that returns a `ProjectProviding` instance for a given project path. + /// If not provided, a default closure is used that instantiates a `ProjectProvider` from the given path. public init( graphType: GraphType, projectProviderClosure: @escaping @Sendable (AbsolutePath) async throws -> ProjectProviding = { @@ -46,11 +71,19 @@ public final class GraphMapper: Sendable { self.projectProviderClosure = projectProviderClosure } - /// Constructs an `XcodeGraph.Graph` by mapping all projects, packages, and dependencies within the specified workspace or + // MARK: - Mapping Logic + + /// Constructs an `XcodeGraph.Graph` by mapping all projects, packages, and dependencies from the specified workspace or /// project. /// - /// - Returns: A fully mapped `XcodeGraph.Graph` containing projects, packages, dependencies, and conditions. - /// - Throws: An error if project mapping or dependency resolution fails. + /// This method: + /// 1. Builds a `Workspace` model from either a workspace or a single project. + /// 2. For each project in the workspace, uses `ProjectMapper` to produce a `Project` model. + /// 3. Aggregates all projects, packages, targets, and dependencies into a single `Graph`. + /// 4. Attaches platform conditions to edges, respecting platform-specific dependencies. + /// + /// - Returns: A fully mapped `Graph` containing all discovered projects, packages, dependencies, and conditions. + /// - Throws: If mapping projects, packages, or dependencies fails (e.g., due to missing files or invalid settings). public func xcodeGraph() async throws -> XcodeGraph.Graph { var projectProviders = [AbsolutePath: ProjectProviding]() var projects: [AbsolutePath: Project] = [:] @@ -71,6 +104,7 @@ public final class GraphMapper: Sendable { ) } + // Map each project in the workspace let projectResults = try await workspace.projects.lazy.asyncCompactMap { path in do { let provider = try await self.projectProviderClosure(path) @@ -78,6 +112,7 @@ public final class GraphMapper: Sendable { let project = try await projectMapper.mapProject() return (path, provider, project) } catch { + // If one project fails to map, it's skipped. Consider logging this or throwing an error for strict usage. return nil } } @@ -87,18 +122,16 @@ public final class GraphMapper: Sendable { projects[path] = project } + // Build a map of all targets for easy target-based dependency resolution let allTargetsMap = Dictionary( projects.values.flatMap(\.targets), - uniquingKeysWith: { existing, _ in - existing - } + uniquingKeysWith: { existing, _ in existing } ) + // Process dependencies for each project and target for (path, project) in projects { if !project.packages.isEmpty { - packages[path] = Dictionary( - uniqueKeysWithValues: project.packages.map { ($0.url, $0) } - ) + packages[path] = Dictionary(uniqueKeysWithValues: project.packages.map { ($0.url, $0) }) } for (name, target) in project.targets { @@ -122,6 +155,7 @@ public final class GraphMapper: Sendable { } } + // Return the assembled graph return Graph( name: workspace.name, path: workspace.path, diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift b/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift index 0328e50a..2f89abb8 100644 --- a/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift +++ b/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift @@ -12,7 +12,7 @@ enum MappingError: Error, LocalizedError, Equatable { case unknownProjectType(path: String) /// No projects were found in the Xcode project file. - case noProjectsFound + case noProjectsFound(path: String) /// The main files group is missing for a target. case missingFilesGroup(targetName: String) @@ -44,16 +44,14 @@ enum MappingError: Error, LocalizedError, Equatable { // MARK: - Error Descriptions - /// A localized description of the error. var errorDescription: String? { switch self { - // Project Mapping Cases case let .pathNotFound(path): return "The specified path does not exist: \(path)" case let .unknownProjectType(path): return "The project type for the path '\(path)' could not be determined." - case .noProjectsFound: - return "No Xcode projects were found." + case let .noProjectsFound(path): + return "No Xcode projects were found at: \(path)" case let .missingFilesGroup(targetName): return "The files group is missing for the target '\(targetName)'." case .missingMergedBinaryType: @@ -62,14 +60,10 @@ enum MappingError: Error, LocalizedError, Equatable { return "The repository URL is missing for the package '\(packageName)'." case let .generic(message): return message - - // Target Mapping Cases case let .missingBundleIdentifier(targetName): return "The bundle identifier is missing for the target '\(targetName)'." case let .targetNotFound(targetName, path): return "The target '\(targetName)' could not be found in the project at path: \(path.pathString)." - - // Dependency Mapping Cases case let .frameworkNotFound(name, path): return "The required framework '\(name)' was not found at path: \(path.pathString)." case let .unknownDependencyType(name): diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift b/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift index 3e13d195..aedc50e6 100644 --- a/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift +++ b/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift @@ -3,7 +3,9 @@ import Path import XcodeGraph import XcodeProj -/// Specifies the type of project to parse. +/// Specifies the type of project to parse based on the discovered file structure. +/// +/// `ProjectType` is determined by examining the path or directory contents: /// - `.workspace(path)`: Indicates a `.xcworkspace` is present at the given path. /// - `.xcodeProject(path)`: Indicates a `.xcodeproj` is present at the given path. public enum ProjectType { @@ -11,21 +13,46 @@ public enum ProjectType { case xcodeProject(AbsolutePath) } -/// A parser responsible for identifying and parsing Xcode projects or workspaces into a `Graph`. +/// A parser responsible for identifying and parsing Xcode projects or workspaces into a `Graph` model. +/// +/// `ProjectParser` determines whether the given path points to: +/// - A `.xcworkspace` file +/// - A `.xcodeproj` file +/// - Or a directory containing one of these project types +/// +/// Once the project type is identified, `ProjectParser` delegates the actual mapping to `GraphMapper`, +/// resulting in a unified `Graph` model that includes targets, packages, and dependencies. +/// +/// **Example Usage:** +/// ```swift +/// // Given a file system path, which could be a directory, .xcodeproj, or .xcworkspace: +/// let path = "/path/to/MyApp" +/// +/// do { +/// // Parse the project or workspace at the given path into a Graph. +/// let graph = try await ProjectParser.parse(atPath: path) /// -/// `ProjectParser` determines whether the given path points to a workspace, a project, -/// or a directory containing one of these. It then delegates the actual mapping to `GraphMapper`. +/// // 'graph' now contains a comprehensive model of the project's structure, including targets, +/// // dependencies, and associated packages. This can be used for analysis, code generation, or tooling. +/// } catch { +/// // Handle errors such as missing projects or unreadable files. +/// print("Failed to parse project: \(error)") +/// } +/// ``` public class ProjectParser { public init() {} /// Parses the project or workspace at the given file system path into a `Graph`. /// - /// - Parameter path: The path to a `.xcworkspace`, `.xcodeproj`, or a directory containing one. - /// - Returns: A `Graph` representing the parsed project structure. + /// Attempts to locate a `.xcworkspace` or `.xcodeproj` at or within the provided path. + /// If both are absent, it throws an error indicating no projects were found. + /// + /// - Parameter path: The file system path to a `.xcworkspace`, `.xcodeproj`, or a directory containing one. + /// - Returns: A `Graph` representing the parsed project structure, including targets, dependencies, and packages. /// - Throws: /// - `MappingError.pathNotFound` if the given path does not exist. - /// - `MappingError.noProjectsFound` if no `.xcworkspace` or `.xcodeproj` can be found. - /// - Other errors thrown by `GraphMapper` during mapping. + /// - `MappingError.noProjectsFound` if no `.xcworkspace` or `.xcodeproj` is located. + /// - Other errors thrown by `GraphMapper` during graph construction. public static func parse(atPath path: String) async throws -> Graph { guard FileManager.default.fileExists(atPath: path) else { throw MappingError.pathNotFound(path: path) @@ -36,11 +63,11 @@ public class ProjectParser { return try await parse(projectType: type) } - /// Parses a given `ProjectType` into a `Graph`. + /// Parses a given `ProjectType` (workspace or project) into a `Graph`. /// - /// - Parameter projectType: The identified `ProjectType` (workspace or project). - /// - Returns: A `Graph` model. - /// - Throws: Any errors encountered during graph mapping. + /// - Parameter projectType: The identified `ProjectType`. + /// - Returns: A `Graph` model representing the parsed structure. + /// - Throws: Any errors encountered during graph mapping, including missing files or invalid configurations. public static func parse(projectType: ProjectType) async throws -> Graph { switch projectType { case let .workspace(path): @@ -52,6 +79,8 @@ public class ProjectParser { /// Maps a single `.xcodeproj` at the given path into a `Graph`. /// + /// This treats the project as a mini-workspace containing a single project, enabling consistent handling by `GraphMapper`. + /// /// - Parameter path: The absolute path to the `.xcodeproj`. /// - Returns: A `Graph` model of the project. /// - Throws: Errors from `GraphMapper` if mapping fails. @@ -62,6 +91,8 @@ public class ProjectParser { /// Maps a single `.xcworkspace` at the given path into a `Graph`. /// + /// If the workspace references multiple projects, they are all integrated into a single graph. + /// /// - Parameter path: The absolute path to the `.xcworkspace`. /// - Returns: A `Graph` model of the workspace and its contained projects. /// - Throws: Errors from `GraphMapper` if mapping fails. @@ -89,23 +120,26 @@ public class ProjectParser { /// Searches a directory for the first `.xcworkspace` or `.xcodeproj` file. /// - /// - Parameter path: A directory path. - /// - Returns: A `ProjectType` if found. - /// - Throws: - /// - `MappingError.noProjectsFound` if neither a `.xcworkspace` nor `.xcodeproj` is located in the directory. + /// If none are found, `MappingError.noProjectsFound` is thrown. This indicates that the provided directory + /// does not contain a recognizable Xcode project or workspace, and thus cannot be parsed. + /// + /// - Parameter path: The directory path to search. + /// - Returns: A `ProjectType` if a project is found. + /// - Throws: `MappingError.noProjectsFound` if no `.xcworkspace` or `.xcodeproj` is detected. private static func findProjectInDirectory(at path: AbsolutePath) throws -> ProjectType { let contents = try FileManager.default.contentsOfDirectory(atPath: path.pathString) - // Look for the first .xcworkspace - if let workspaceName = contents.first(where: { $0.hasSuffix(".xcworkspace") }) { + // Search for a .xcworkspace + if let workspaceName = contents.first(where: { $0.lowercased().hasSuffix(".xcworkspace") }) { return .workspace(path.appending(component: workspaceName)) } - // Look for the first .xcodeproj - if let projectName = contents.first(where: { $0.hasSuffix(".xcodeproj") }) { + // Search for a .xcodeproj + if let projectName = contents.first(where: { $0.lowercased().hasSuffix(".xcodeproj") }) { return .xcodeProject(path.appending(component: projectName)) } - throw MappingError.noProjectsFound + // No projects found in this directory + throw MappingError.noProjectsFound(path: path.pathString) } } diff --git a/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift b/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift index 7b07af6b..161dbf38 100644 --- a/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift @@ -3,73 +3,80 @@ import Path import XcodeGraph import XcodeProj -/// A protocol for mapping `XCSwiftPackageReference` instances to `Package` models. +/// A protocol defining how to map both remote and local Swift package references into `Package` models. +/// +/// Conforming types provide methods to translate `XCRemoteSwiftPackageReference` and `XCLocalSwiftPackageReference` +/// objects into `Package` instances, resolving URLs, version requirements, and file paths as needed. protocol PackageMapping: Sendable { /// Maps a remote Swift package reference to a `Package`. /// + /// This method inspects the repository URL and version requirement from the provided `XCRemoteSwiftPackageReference` + /// and constructs a `Package` model that can be integrated into the overall project graph. + /// /// - Parameter package: The remote Swift package reference. - /// - Returns: A `Package` representing the remote package. - /// - Throws: If required repository information is missing or invalid. + /// - Returns: A `Package` representing the remote package, including its URL and version requirement. + /// - Throws: `MappingError.missingRepositoryURL` if the remote package has no repository URL. func map(package: XCRemoteSwiftPackageReference) async throws -> Package /// Maps a local Swift package reference to a `Package`. /// + /// This method resolves the provided local package path relative to the project's source directory, + /// constructing a `.local` `Package` model that can be used in the project graph. + /// /// - Parameter package: The local Swift package reference. - /// - Returns: A `Package` representing the local package. - /// - Throws: If the package path cannot be validated. + /// - Returns: A `Package` representing the local package, including its resolved filesystem path. + /// - Throws: If the provided path is invalid or cannot be resolved relative to the project's source directory. func map(package: XCLocalSwiftPackageReference) async throws -> Package } -/// A mapper that converts remote and local Swift package references into `Package` models. +/// A mapper that converts remote and local Swift package references into domain `Package` models. /// -/// The `PackageMapper` uses the provided `ProjectProviding` to resolve local package paths relative -/// to the project's source directory. For remote packages, it uses the repository URL and version requirement -/// from the `XCRemoteSwiftPackageReference` to construct a `Package` with the appropriate `Requirement`. -final class PackageMapper: PackageMapping { +/// `PackageMapper` uses `ProjectProviding` to resolve paths and retrieves remote package information from +/// `XCRemoteSwiftPackageReference` +/// instances. By extracting repository URLs, version requirements, and local paths, `PackageMapper` produces `Package` +/// models that can be integrated into a broader Xcode project graph. +/// +/// Example usage: +/// ```swift +/// let packageMapper = PackageMapper(projectProvider: provider) +/// let remotePackage = try await packageMapper.map(package: remoteRef) +/// let localPackage = try await packageMapper.map(package: localRef) +/// ``` +public final class PackageMapper: PackageMapping { private let projectProvider: ProjectProviding - /// Creates a new `PackageMapper`. + /// Creates a new `PackageMapper` with the given project provider. /// - /// - Parameter projectProvider: A provider that offers access to the project's directory structure - /// and additional metadata. + /// - Parameter projectProvider: Provides access to the project's directory structure and metadata, + /// enabling resolution of local package paths and contextual validation. init(projectProvider: ProjectProviding) { self.projectProvider = projectProvider } - /// Maps an `XCRemoteSwiftPackageReference` to a `Package`. - /// - /// - Parameter package: The `XCRemoteSwiftPackageReference` to map. - /// - Returns: A `Package` instance representing the mapped remote package. - /// - Throws: `MappingError.missingRepositoryURL` if the repository URL is not found. public func map(package: XCRemoteSwiftPackageReference) async throws -> Package { guard let repositoryURL = package.repositoryURL else { throw MappingError.missingRepositoryURL(packageName: package.name ?? "Unknown Package") } - let requirement = await mapRequirement(package: package) + let requirement = mapRequirement(package: package) return .remote(url: repositoryURL, requirement: requirement) } - /// Maps an `XCLocalSwiftPackageReference` to a `Package`. - /// - /// - Parameter package: The `XCLocalSwiftPackageReference` to map. - /// - Returns: A `Package` instance representing the mapped local package. - /// - Throws: If the relative path is invalid. public func map(package: XCLocalSwiftPackageReference) async throws -> Package { let relativePath = try RelativePath(validating: package.relativePath) let path = projectProvider.sourceDirectory.appending(relativePath) return .local(path: path) } - /// Maps the version requirement of an `XCRemoteSwiftPackageReference` to a `Package.Requirement`. + /// Maps the version requirement of a remote Swift package to a `Package.Requirement`. /// - /// This method converts the version requirement specified in the Xcode project into a `Requirement` - /// used by the internal `Package` model. It supports all standard SwiftPM versioning schemes, - /// including major/minor constraints, exact versions, ranges, branches, and revisions. + /// By examining the `XCRemoteSwiftPackageReference`'s `versionRequirement`, this method determines the correct + /// versioning scheme (exact, range, branch, revision, or up-to-next-major/minor) and returns a `Requirement` + /// that captures this information. /// - /// - Parameter package: The `XCRemoteSwiftPackageReference` whose requirement to map. - /// - Returns: A `Package.Requirement` representing the version requirement. - public func mapRequirement(package: XCRemoteSwiftPackageReference) async -> Requirement { + /// - Parameter package: The `XCRemoteSwiftPackageReference` containing the version requirement. + /// - Returns: A `Package.Requirement` reflecting the specified versioning scheme. + public func mapRequirement(package: XCRemoteSwiftPackageReference) -> Requirement { guard let versionRequirement = package.versionRequirement else { return .upToNextMajor("0.0.0") } diff --git a/Sources/XcodeProjToGraph/Mappers/Project/ProjectAttribute.swift b/Sources/XcodeProjToGraph/Mappers/Project/ProjectAttribute.swift new file mode 100644 index 00000000..ae33a42f --- /dev/null +++ b/Sources/XcodeProjToGraph/Mappers/Project/ProjectAttribute.swift @@ -0,0 +1,8 @@ +import Foundation + +/// Attributes for project settings that can be retrieved from a `PBXProject`. +enum ProjectAttribute: String { + case classPrefix = "CLASSPREFIX" + case organization = "ORGANIZATIONNAME" + case lastUpgradeCheck = "LastUpgradeCheck" +} diff --git a/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift b/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift index f2fcd0fe..4812a81b 100644 --- a/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift @@ -4,53 +4,74 @@ import PathKit import XcodeGraph import XcodeProj -/// A type that maps a project structure into a `Project` model. +/// A protocol defining how to map a parsed Xcode project structure into a `Project` domain model. +/// +/// Conforming types should read from a project provider or XcodeProj instance, +/// translating raw build settings, targets, schemes, and packages into a fully realized `Project` model. protocol ProjectMapping: Sendable { /// Maps the current project into a `Project` model. /// - /// - Returns: A fully constructed `Project` model. - /// - Throws: An error if the mapping process fails. + /// This involves assembling project-level settings, targets, packages, schemes, and other metadata into a `Project`. + /// The resulting model can serve as a basis for code generation, analysis, or other tooling operations. + /// + /// - Returns: A fully constructed `Project` model representing the entire project. + /// - Throws: An error if any part of the mapping process fails, such as missing required data or invalid references. func mapProject() async throws -> Project } /// A mapper responsible for translating a parsed Xcode project into a `Project` model. /// -/// The `ProjectMapper` utilizes `SettingsMapper` to resolve project-level settings, -/// `TargetMapper` to map individual targets, and `PackageMapper` to resolve local and remote packages. -/// It also fetches and maps schemes using a `SchemeMapper`, integrates resource synthesizer definitions, -/// and aggregates all project-related data into a single `Project` instance. +/// `ProjectMapper` orchestrates the mapping of all major project components: +/// - Uses `SettingsMapper` to map the project's `XCConfigurationList` into domain-specific settings. +/// - Uses `TargetMapper` to convert `PBXTarget` instances into domain-level `Target` models, including sources, resources, and +/// dependencies. +/// - Uses `PackageMapper` to resolve both remote and local Swift packages. +/// - Uses `SchemeMapper` to identify and incorporate both user and shared schemes. +/// - Integrates resource synthesizers to define code generation strategies for various resource types. +/// +/// **Example Usage:** +/// ```swift +/// // Assume you have a ProjectProvider set up from your `.xcodeproj`. +/// let projectProvider: ProjectProviding = ... +/// +/// // Create a ProjectMapper with the given provider. +/// let projectMapper = ProjectMapper(projectProvider: projectProvider) +/// +/// // Perform the mapping to produce a domain-level Project model. +/// let project = try await projectMapper.mapProject() +/// +/// // 'project' now includes all targets, settings, packages, schemes, and resource synthesizers. +/// // You can use this model for code generation, analyze dependencies, or integrate with other tools. +/// ``` public final class ProjectMapper: ProjectMapping { private let projectProvider: ProjectProviding /// Initializes the mapper with a given project provider. /// - /// - Parameter projectProvider: A `ProjectProviding` instance capable of supplying access - /// to the project's files, directories, and parsed structures. + /// - Parameter projectProvider: A `ProjectProviding` instance that supplies access + /// to the project's directories, `.xcodeproj` file, and parsed data structures, + /// enabling the mapper to resolve paths, read build settings, and access targets. public init(projectProvider: ProjectProviding) { self.projectProvider = projectProvider } - /// Maps the current project into a `Project` model. - /// - /// This method fetches project-level settings, targets, packages, and schemes, then consolidates them - /// into a single `Project` instance. It also retrieves resource synthesizers to facilitate code generation - /// tasks and other downstream tooling that relies on structured resource definitions. - /// - /// - Returns: A fully constructed `Project` model containing settings, targets, packages, and schemes. - /// - Throws: An error if any portion of the mapping process (e.g., reading project files or mapping targets) fails. public func mapProject() async throws -> Project { let settingsMapper = SettingsMapper() let pbxProject = try projectProvider.pbxProject() + + // Map project-level settings let settings = try await settingsMapper.map( projectProvider: projectProvider, configurationList: pbxProject.buildConfigurationList ) + // Map targets into domain-level Target models let targetMapper = TargetMapper(projectProvider: projectProvider) let targetsArray = try await pbxProject.targets.asyncCompactMap { pbxTarget in try await targetMapper.map(pbxTarget: pbxTarget) } + // Map packages (both remote and local) let packageMapper = PackageMapper(projectProvider: projectProvider) let remotePackages = try await pbxProject.remotePackages.asyncCompactMap { package in try await packageMapper.map(package: package) @@ -59,18 +80,21 @@ public final class ProjectMapper: ProjectMapping { try await packageMapper.map(package: package) } + // Determine a files group to organize files logically let filesGroup = ProjectGroup.group(name: pbxProject.mainGroup?.name ?? "Project") + // Map schemes, both user and shared, for build and test configurations let schemeMapper = try SchemeMapper(graphType: .project(projectProvider.sourceDirectory)) let userSchemes = projectProvider.xcodeProj.userData.flatMap(\.schemes) let sharedSchemes = projectProvider.xcodeProj.sharedData?.schemes ?? [] - let schemes: [Scheme] = + let schemes = try await schemeMapper.mapSchemesAsync(xcschemes: userSchemes, shared: false) + (try await schemeMapper.mapSchemesAsync(xcschemes: sharedSchemes, shared: true)) - let lastUpgradeCheck = pbxProject.attribute(for: .lastUpgradeCheck).flatMap { - Version(string: $0) - } + // Retrieve the last known Xcode upgrade check version, if available + let lastUpgradeCheck = pbxProject.attribute(for: .lastUpgradeCheck).flatMap { Version(string: $0) } + + // Determine default known regions, if any let defaultKnownRegions = pbxProject.knownRegions.isEmpty ? nil : pbxProject.knownRegions return Project( @@ -82,12 +106,17 @@ public final class ProjectMapper: ProjectMapping { classPrefix: pbxProject.attribute(for: .classPrefix), defaultKnownRegions: defaultKnownRegions, developmentRegion: pbxProject.developmentRegion, - options: Project.Options( + options: .init( automaticSchemesOptions: .disabled, disableBundleAccessors: false, disableShowEnvironmentVarsInScriptPhases: false, disableSynthesizedResourceAccessors: false, - textSettings: .init(usesTabs: nil, indentWidth: nil, tabWidth: nil, wrapsLines: nil) + textSettings: .init( + usesTabs: nil, + indentWidth: nil, + tabWidth: nil, + wrapsLines: nil + ) ), settings: settings, filesGroup: filesGroup, @@ -104,24 +133,25 @@ public final class ProjectMapper: ProjectMapping { /// Maps known resource synthesizer definitions from the given `PBXProject`. /// - /// These synthesizers define how various resource types (e.g., strings, assets, plists) are transformed or accessed. - /// This information can be used downstream to generate code or to provide tooling support. + /// Provides a set of default resource synthesizers that cover common resource types (e.g., `.strings`, `.xcassets`, + /// `.plist`). + /// Even if the project doesn't define custom synthesizers, these defaults ensure that downstream tooling always has + /// sensible defaults. /// - /// - Parameter pbxProject: The `PBXProject` from which to derive resource synthesizer settings. - /// - Returns: An array of `ResourceSynthesizer` instances. + /// - Parameter pbxProject: The `PBXProject` from which resource synthesizer settings are derived. + /// - Returns: An array of `ResourceSynthesizer` instances representing code generation strategies for various resource types. private func mapResourceSynthesizers(from _: PBXProject) -> [ResourceSynthesizer] { - let resourceTypes: - [(parser: ResourceSynthesizer.Parser, extensions: [String], template: String)] = [ - (.strings, ["strings", "stringsdict"], "Strings"), - (.assets, ["xcassets"], "Assets"), - (.plists, ["plist"], "Plists"), - (.fonts, ["ttf", "otf", "ttc"], "Fonts"), - (.coreData, ["xcdatamodeld"], "CoreData"), - (.interfaceBuilder, ["xib", "storyboard"], "InterfaceBuilder"), - (.json, ["json"], "JSON"), - (.yaml, ["yaml", "yml"], "YAML"), - (.files, ["txt", "md"], "Files"), - ] + let resourceTypes: [(parser: ResourceSynthesizer.Parser, extensions: [String], template: String)] = [ + (.strings, ["strings", "stringsdict"], "Strings"), + (.assets, ["xcassets"], "Assets"), + (.plists, ["plist"], "Plists"), + (.fonts, ["ttf", "otf", "ttc"], "Fonts"), + (.coreData, ["xcdatamodeld"], "CoreData"), + (.interfaceBuilder, ["xib", "storyboard"], "InterfaceBuilder"), + (.json, ["json"], "JSON"), + (.yaml, ["yaml", "yml"], "YAML"), + (.files, ["txt", "md"], "Files"), + ] return resourceTypes.map { resourceType in ResourceSynthesizer( @@ -133,35 +163,3 @@ public final class ProjectMapper: ProjectMapping { } } } - -/// Attributes for project settings that can be retrieved from a `PBXProject`. -enum ProjectAttribute: String { - case classPrefix = "CLASSPREFIX" - case organization = "ORGANIZATIONNAME" - case lastUpgradeCheck = "LastUpgradeCheck" -} - -extension PBXProject { - /// Retrieves the value of a specific project attribute. - /// - /// - Parameter attr: The attribute key to look up. - /// - Returns: The value of the attribute if it exists, or `nil` if not found. - func attribute(for attr: ProjectAttribute) -> String? { - attributes[attr.rawValue] as? String - } -} - -extension SchemeMapper { - /// Maps the given Xcode schemes asynchronously. - /// - /// - Parameters: - /// - xcschemes: An array of `XCScheme` instances to map. - /// - shared: A Boolean indicating whether the schemes are shared. - /// - Returns: An array of mapped `Scheme` instances. - /// - Throws: If mapping any scheme fails. - func mapSchemesAsync(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] { - try await xcschemes.asyncCompactMap { scheme in - try await self.mapScheme(xcscheme: scheme, shared: shared) - } - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift b/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift index 128e326e..9c2e17e2 100644 --- a/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift +++ b/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift @@ -4,23 +4,33 @@ import PathKit import XcodeGraph @preconcurrency import XcodeProj -/// A protocol defining how to provide access to an Xcode project and its underlying components. +/// A protocol that defines how to provide access to an Xcode project and its underlying components. /// -/// Conforming types must specify the project's source directory, the `.xcodeproj` path, -/// and a parsed `XcodeProj` instance. They also provide a convenient way to retrieve -/// the main `PBXProject` object from the project. +/// Conforming types give you a parsed `XcodeProj` instance, the `.xcodeproj` file path, and the root source directory. +/// They also simplify retrieval of the main `PBXProject`, allowing downstream mappers or analyses to easily navigate +/// and process the project structure. public protocol ProjectProviding: Sendable { /// The absolute path to the directory containing the Xcode project. + /// + /// Typically, this is the directory above the `.xcodeproj` file, serving as the project’s source root. var sourceDirectory: AbsolutePath { get } /// The absolute path to the `.xcodeproj` file. + /// + /// This path uniquely identifies the Xcode project file on disk. var xcodeProjPath: AbsolutePath { get } /// The parsed `XcodeProj` instance representing the Xcode project. + /// + /// `XcodeProj` provides structured access to projects, targets, build configurations, groups, and files, + /// enabling advanced analysis or transformation tasks. var xcodeProj: XcodeProj { get } /// Returns the main `PBXProject` object from the `.xcodeproj`. /// + /// The `PBXProject` object serves as the root for most project-related data, including build configurations, targets, + /// and references to files and groups. + /// /// - Throws: `MappingError.noProjectsFound` if no projects are found in the `.xcodeproj`. /// - Returns: A `PBXProject` representing the primary project definition. func pbxProject() throws -> PBXProject @@ -28,19 +38,23 @@ public protocol ProjectProviding: Sendable { extension ProjectProviding { /// A convenience property providing the source directory as a string. + /// + /// Useful for passing to APIs that require string paths instead of `AbsolutePath`. public var sourcePathString: String { sourceDirectory.pathString } /// The source directory is assumed to be the parent of the `.xcodeproj` directory. + /// + /// This default implementation infers the source directory from the `xcodeProjPath`, ensuring a consistent + /// project structure. public var sourceDirectory: AbsolutePath { xcodeProjPath.parentDirectory } public func pbxProject() throws -> PBXProject { guard let pbxProject = xcodeProj.pbxproj.projects.first else { - // TODO: - Add path assocaited value - throw MappingError.noProjectsFound + throw MappingError.noProjectsFound(path: xcodeProjPath.pathString) } return pbxProject } @@ -48,9 +62,27 @@ extension ProjectProviding { /// A concrete provider that supplies information about a particular Xcode project. /// -/// `ProjectProvider` wraps a given `.xcodeproj` file, providing access to its -/// `XcodeProj` representation and the associated file paths. It simplifies operations -/// that need to read or analyze the project structure. +/// `ProjectProvider` encapsulates a `.xcodeproj` file and its parsed `XcodeProj` representation, making it straightforward +/// to integrate with mappers or other tooling that requires consistent access to the project's structure. +/// +/// **Example Usage:** +/// ```swift +/// import XcodeProj +/// +/// // Assume you have an AbsolutePath to the .xcodeproj file. +/// let xcodeProjPath: AbsolutePath = ... +/// +/// // Parse the project using XcodeProj. +/// let xcodeProj = try XcodeProj(pathString: xcodeProjPath.pathString) +/// +/// // Create a ProjectProvider instance. +/// let projectProvider = ProjectProvider(xcodeProjPath: xcodeProjPath, xcodeProj: xcodeProj) +/// +/// // Access the main PBXProject for further analysis: +/// let pbxProject = try projectProvider.pbxProject() +/// +/// // From here, you can iterate targets, fetch build settings, or integrate with other mappers. +/// ``` public struct ProjectProvider: ProjectProviding { public let xcodeProj: XcodeProj public let xcodeProjPath: AbsolutePath @@ -60,6 +92,10 @@ public struct ProjectProvider: ProjectProviding { /// - Parameters: /// - xcodeProjPath: The absolute path to the `.xcodeproj` file. /// - xcodeProj: The parsed `XcodeProj` instance representing the project. + /// + /// After initialization, `ProjectProvider` can serve as a bridge between `.xcodeproj` structures + /// and higher-level mapping tools (e.g., `ProjectMapper`, `TargetMapper`), providing consistent and + /// convenient access to all project data. public init(xcodeProjPath: AbsolutePath, xcodeProj: XcodeProj) { self.xcodeProjPath = xcodeProjPath self.xcodeProj = xcodeProj diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift b/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift index 8583c06f..348cd0fa 100644 --- a/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift +++ b/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift @@ -28,7 +28,7 @@ enum ConfigurationMatcher { public static func variant(forName name: String) -> BuildConfiguration.Variant { let lowercased = name.lowercased() return patterns.first { pattern in - pattern.keywords.contains { lowercased.contains($0) } + pattern.keywords.first(where: { lowercased.contains($0) }) != nil }?.variant ?? .debug } diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift b/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift index bbf5065a..20084e95 100644 --- a/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift @@ -3,27 +3,47 @@ import Path import XcodeGraph import XcodeProj -/// A protocol defining how to map an Xcode project's configuration list into a `Settings` model. +/// A protocol that defines how to map an Xcode project's `XCConfigurationList` into a domain-specific `Settings` model. +/// +/// Conforming types provide an asynchronous mapping function that takes a `projectProvider` and an optional +/// `XCConfigurationList`, then returns a `Settings` model. If no configuration list is provided, they return default settings. protocol SettingsMapping: Sendable { - /// Maps a given `XCConfigurationList` into `Settings`. + /// Maps a given `XCConfigurationList` into a `Settings` model. + /// + /// This operation extracts build configurations and their associated build settings, translating them into a + /// domain-specific `Settings` representation. If the provided configuration list is `nil`, default settings are returned. /// /// - Parameters: - /// - projectProvider: A provider for project-related paths and files. - /// - configurationList: The `XCConfigurationList` to map. + /// - projectProvider: A provider for project-related paths and files, used to resolve paths like `.xcconfig` files. + /// - configurationList: The `XCConfigurationList` from which to derive settings. If `nil`, defaults are returned. /// - Returns: A `Settings` model derived from the configuration list, or default settings if none are found. - /// - Throws: If build settings cannot be mapped correctly. - func map(projectProvider: ProjectProviding, configurationList: XCConfigurationList?) async throws - -> Settings + /// - Throws: If any build settings cannot be properly mapped into a `Settings` model. + func map( + projectProvider: ProjectProviding, + configurationList: XCConfigurationList? + ) async throws -> Settings } /// A mapper responsible for converting an Xcode project's configuration list into a `Settings` domain model. -final class SettingsMapper: SettingsMapping { - /// Creates a new `SettingsMapper`. +/// +/// `SettingsMapper` reads through the project's `XCConfigurationList`, extracting each build configuration along with +/// its raw build settings. It then translates these settings into a structured `Settings` model, associating them with +/// corresponding `BuildConfiguration` variants (e.g., debug or release). Additionally, it attempts to resolve any +/// `.xcconfig` references into absolute paths. If no configuration list is provided, `SettingsMapper` returns default settings. +/// +/// Typical usage: +/// ```swift +/// let mapper = SettingsMapper() +/// let settings = try await mapper.map(projectProvider: provider, configurationList: configurationList) +/// ``` +public final class SettingsMapper: SettingsMapping { + /// Creates a new `SettingsMapper` instance. public init() {} - public func map(projectProvider: ProjectProviding, configurationList: XCConfigurationList?) - async throws -> Settings - { + public func map( + projectProvider: ProjectProviding, + configurationList: XCConfigurationList? + ) async throws -> Settings { guard let configurationList else { return Settings.default } @@ -58,14 +78,15 @@ final class SettingsMapper: SettingsMapping { ) } - /// Maps a dictionary of raw build settings into a `SettingsDictionary`. + /// Converts a dictionary of raw build settings (`[String: Any]`) into a structured `SettingsDictionary`. /// - /// The raw values are converted into `SettingValue` instances. String and array values are directly converted, - /// while other types are stringified as a fallback. + /// Each raw setting value is mapped to a `SettingValue`. Strings and arrays of strings are preserved as-is; + /// other types are converted into strings as a fallback. This ensures that all settings are represented in a + /// uniform and easily processed manner. /// - /// - Parameter buildSettings: A dictionary representing the raw build settings. - /// - Returns: A `SettingsDictionary` with mapped `SettingValue` instances. - /// - Throws: If a setting value cannot be mapped. + /// - Parameter buildSettings: A dictionary of raw build settings. + /// - Returns: A `SettingsDictionary` containing `SettingValue`-typed settings. + /// - Throws: If a setting value cannot be mapped (this is typically non-fatal; most values can be stringified). public func mapBuildSettings(_ buildSettings: [String: Any]) async throws -> SettingsDictionary { var settingsDict = SettingsDictionary() for (key, value) in buildSettings { @@ -74,14 +95,14 @@ final class SettingsMapper: SettingsMapping { return settingsDict } - /// Maps a raw setting value into a `SettingValue`. + /// Maps a single raw setting value into a `SettingValue`. /// - /// If the value is a string, it's mapped directly. - /// If it's an array, elements are mapped to strings if possible. - /// Otherwise, the value is stringified. + /// - If the value is a `String`, it becomes a `SettingValue.string`. + /// - If the value is an `Array`, each element is converted to a string if possible, resulting in `SettingValue.array`. + /// - Otherwise, the value is stringified using `String(describing:)` and returned as `SettingValue.string`. /// - /// - Parameter value: The raw setting value from the build settings. - /// - Returns: A `SettingValue` representing the mapped value. + /// - Parameter value: A raw setting value from the build settings dictionary. + /// - Returns: A `SettingValue` representing the processed setting. private func mapSettingValue(_ value: Any) async throws -> SettingValue { if let stringValue = value as? String { return .string(stringValue) @@ -89,18 +110,18 @@ final class SettingsMapper: SettingsMapping { let stringArray = arrayValue.compactMap { $0 as? String } return .array(stringArray) } else { - // Fallback: convert non-string/non-array values to string + // Fallback: convert unknown types to strings let stringValue = String(describing: value) return .string(stringValue) } } - /// Determines a build configuration variant (debug or release) based on its name. + /// Determines a `BuildConfiguration.Variant` (e.g., `.debug` or `.release`) from a configuration name. /// - /// Uses `ConfigurationMatcher` to determine if the configuration name suggests a debug or release variant. + /// Uses `ConfigurationMatcher` to infer the variant by analyzing the configuration name for known keywords. /// - /// - Parameter name: The name of the build configuration. - /// - Returns: The corresponding `BuildConfiguration.Variant`. + /// - Parameter name: The name of the build configuration (e.g., "Debug", "Release", "Development"). + /// - Returns: The corresponding `BuildConfiguration.Variant` inferred from the name. private func variant(forName name: String) -> BuildConfiguration.Variant { ConfigurationMatcher.variant(forName: name) } diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift index 217f9704..b49def55 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift @@ -4,6 +4,17 @@ import XcodeGraph import XcodeProj extension PBXTarget { + enum EnvironmentExtractor { + static func extract(from buildSettings: BuildSettings) -> [String: EnvironmentVariable] { + guard let envVars = buildSettings.stringDict(for: .environmentVariables) else { + return [:] + } + return envVars.reduce(into: [:]) { result, pair in + result[pair.key] = EnvironmentVariable(value: pair.value, isEnabled: true) + } + } + } + /// Retrieves the path to the Info.plist file from the target's build settings. /// /// - Returns: The `INFOPLIST_FILE` value if present, otherwise `nil`. @@ -50,4 +61,20 @@ extension PBXTarget { visionOS: targets[.visionOSDeploymentTarget] ) } + + /// Extracts environment variables from all build configurations of the target. + /// + /// If multiple configurations define the same environment variable, the last processed configuration takes precedence. + public func extractEnvironmentVariables() -> [String: EnvironmentVariable] { + buildConfigurationList?.buildConfigurations.reduce(into: [:]) { result, config in + result.merge(EnvironmentExtractor.extract(from: config.buildSettings)) { current, _ in current + } + } ?? [:] + } + + /// Returns the build settings from the "Debug" build configuration, or an empty dictionary if not present. + var debugBuildSettings: [String: Any] { + buildConfigurationList?.buildConfigurations.first(where: { $0.name == "Debug" })?.buildSettings + ?? [:] + } } diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift index 25ec2783..6a5d640b 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift @@ -3,58 +3,67 @@ import Path import XcodeGraph import XcodeProj -/// A protocol defining how to map XCScheme objects and their associated actions -/// into domain `Scheme` models. +/// A protocol defining how to map `XCScheme` objects and their associated actions into domain `Scheme` models. +/// +/// Conforming types transform raw `XCScheme` instances—along with their build, test, run, archive, profile, +/// and analyze actions—into fully-realized `Scheme` models. This enables further analysis, code generation, +/// or integration with custom tooling based on standardized scheme data. protocol SchemeMapping: Sendable { /// Maps an array of `XCScheme` instances into `Scheme` models. /// /// - Parameters: - /// - xcschemes: An array of `XCScheme` to map. - /// - shared: A Boolean indicating whether the schemes are shared. - /// - Returns: An array of mapped `Scheme` models. - /// - Throws: If any scheme cannot be mapped. + /// - xcschemes: An array of `XCScheme` instances to map. + /// - shared: A Boolean indicating whether these schemes are shared. + /// - Returns: An array of mapped `Scheme` instances representing the provided XCSchemes. + /// - Throws: If any scheme cannot be fully resolved or mapped. func mapSchemes(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] /// Maps a single `XCScheme` into a `Scheme` model. /// /// - Parameters: /// - xcscheme: The `XCScheme` to map. - /// - shared: Indicates whether the scheme is shared. - /// - Returns: A `Scheme` model. - /// - Throws: If any scheme action cannot be mapped. + /// - shared: A Boolean indicating whether the scheme is shared. + /// - Returns: A `Scheme` model corresponding to the given `XCScheme`. + /// - Throws: If any of the scheme's actions (build, test, run, etc.) cannot be resolved. func mapScheme(xcscheme: XCScheme, shared: Bool) async throws -> Scheme /// Maps an `XCScheme.BuildAction` into a `BuildAction` model. - /// - Parameter action: The optional XCScheme.BuildAction. - /// - Returns: A `BuildAction` instance or `nil` if action is `nil`. - /// - Throws: If target references cannot be mapped. + /// + /// - Parameter action: The `XCScheme.BuildAction` to map, if any. + /// - Returns: A `BuildAction` instance, or `nil` if `action` is `nil`. + /// - Throws: If any target references in the build action cannot be resolved. func mapBuildAction(action: XCScheme.BuildAction?) async throws -> BuildAction? /// Maps an `XCScheme.LaunchAction` into a `RunAction` model. - /// - Parameter action: The optional XCScheme.LaunchAction. - /// - Returns: A `RunAction` instance or `nil` if action is `nil`. - /// - Throws: If the executable reference cannot be mapped. + /// + /// - Parameter action: The `XCScheme.LaunchAction` to map, if any. + /// - Returns: A `RunAction` instance, or `nil` if `action` is `nil`. + /// - Throws: If the executable reference cannot be resolved. func mapRunAction(action: XCScheme.LaunchAction?) async throws -> RunAction? /// Maps an `XCScheme.TestAction` into a `TestAction` model. - /// - Parameter action: The optional XCScheme.TestAction. - /// - Returns: A `TestAction` instance or `nil` if action is `nil`. - /// - Throws: If test targets cannot be mapped. + /// + /// - Parameter action: The `XCScheme.TestAction` to map, if any. + /// - Returns: A `TestAction` instance, or `nil` if `action` is `nil`. + /// - Throws: If any test target references cannot be resolved. func mapTestAction(action: XCScheme.TestAction?) async throws -> TestAction? /// Maps an `XCScheme.ArchiveAction` into an `ArchiveAction` model. - /// - Parameter action: The optional `XCScheme.ArchiveAction`. - /// - Returns: An `ArchiveAction` instance or `nil` if action is `nil`. + /// + /// - Parameter action: The `XCScheme.ArchiveAction` to map, if any. + /// - Returns: An `ArchiveAction` instance, or `nil` if `action` is `nil`. func mapArchiveAction(action: XCScheme.ArchiveAction?) async throws -> ArchiveAction? /// Maps an `XCScheme.ProfileAction` into a `ProfileAction` model. - /// - Parameter action: The optional `XCScheme.ProfileAction`. - /// - Returns: A `ProfileAction` instance or `nil` if action is `nil`. + /// + /// - Parameter action: The `XCScheme.ProfileAction` to map, if any. + /// - Returns: A `ProfileAction` instance, or `nil` if `action` is `nil`. func mapProfileAction(action: XCScheme.ProfileAction?) async throws -> ProfileAction? /// Maps an `XCScheme.AnalyzeAction` into an `AnalyzeAction` model. - /// - Parameter action: The optional `XCScheme.AnalyzeAction`. - /// - Returns: An `AnalyzeAction` instance or `nil` if action is `nil`. + /// + /// - Parameter action: The `XCScheme.AnalyzeAction` to map, if any. + /// - Returns: An `AnalyzeAction` instance, or `nil` if `action` is `nil`. func mapAnalyzeAction(action: XCScheme.AnalyzeAction?) async throws -> AnalyzeAction? } @@ -69,16 +78,33 @@ enum SchemeMapperType { /// A mapper responsible for converting `XCScheme` objects (and related Xcode scheme configurations) /// into domain `Scheme` models. /// -/// `SchemeMapper` handles the mapping of build, test, run, archive, profile, and analyze actions -/// within a scheme. It resolves references to targets, environment variables, and launch arguments, -/// producing a `Scheme` model that can be used for further analysis, generation, or tooling tasks. +/// `SchemeMapper` resolves references to targets, environment variables, launch arguments, and all actions within +/// a scheme (build, test, run, archive, profile, analyze). The resulting `Scheme` models enable consumers +/// to analyze scheme configurations, generate code, or integrate with custom tooling pipelines. +/// +/// **Example Usage:** +/// ```swift +/// // Assume you have determined the graphType (e.g., from a workspace or a single project) +/// let graphType: GraphType = ... +/// +/// // Create a SchemeMapper +/// let schemeMapper = try SchemeMapper(graphType: graphType) +/// +/// // Obtain an array of XCScheme instances (perhaps from XcodeProj's shared or user schemes) +/// let xcschemes: [XCScheme] = ... +/// +/// // Map the schemes into Scheme models +/// let schemes = try await schemeMapper.mapSchemes(xcschemes: xcschemes, shared: true) +/// +/// // 'schemes' now contains a list of domain Scheme models ready for further use. +/// ``` final class SchemeMapper: SchemeMapping { private let graphType: GraphType /// Initializes the mapper with the given graph type. /// - /// - Parameter graphType: The graph type (workspace or project) influencing how target references are resolved. - /// - Throws: `MappingError.noProjectsFound` if the required project information is missing. + /// - Parameter graphType: The graph type (workspace or project) that influences how target references are resolved. + /// - Throws: `MappingError.noProjectsFound` if required project information is missing. public init(graphType: GraphType) throws { self.graphType = graphType } @@ -241,12 +267,11 @@ final class SchemeMapper: SchemeMapping { /// Maps a `XCScheme.BuildableReference` to a `TargetReference`. /// - /// This involves resolving the container path and the target name. - /// Depending on whether we're dealing with a workspace or a standalone project, - /// the logic may differ. + /// This step involves resolving the container path and the target name, which differ depending on whether + /// the scheme originates from a workspace or a standalone project. /// /// - Parameter buildableReference: The `XCScheme.BuildableReference` to map. - /// - Returns: A `TargetReference` representing the target in the given container. + /// - Returns: A `TargetReference` representing the target in the resolved container. /// - Throws: If the referenced container cannot be resolved. private func mapTargetReference(buildableReference: XCScheme.BuildableReference) async throws -> TargetReference @@ -270,3 +295,21 @@ final class SchemeMapper: SchemeMapping { ) } } + +extension SchemeMapper { + /// Maps the given Xcode schemes asynchronously. + /// + /// This is a convenience method similar to `mapSchemes(xcschemes:shared:)`, + /// but specifically defined for asynchronous mapping flows. + /// + /// - Parameters: + /// - xcschemes: An array of `XCScheme` instances to map. + /// - shared: A Boolean indicating whether the schemes are shared. + /// - Returns: An array of mapped `Scheme` instances. + /// - Throws: If mapping any scheme fails. + func mapSchemesAsync(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] { + try await xcschemes.asyncCompactMap { scheme in + try await self.mapScheme(xcscheme: scheme, shared: shared) + } + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift index 64d45825..fbbdca76 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift @@ -3,37 +3,63 @@ import Path import XcodeGraph import XcodeProj -/// A type that maps a `PBXTarget` into a domain `Target` model, extracting platform, product, settings, sources, -/// resources, scripts, dependencies, and other configuration details. +/// A protocol defining how to map a `PBXTarget` into a domain `Target` model. +/// +/// Conforming types transform a raw `PBXTarget` from the Xcode project model into a fully-realized `Target` +/// that includes product information, build settings, source files, resources, scripts, dependencies, +/// build rules, and other essential configuration details. protocol TargetMapping: Sendable { - /// Maps the given PBX target into a `Target` domain model. + /// Maps the given `PBXTarget` into a `Target` domain model. + /// + /// By inspecting the target’s build settings, build phases, and dependencies, implementers produce a `Target` + /// that can be used for code generation, analysis, and other downstream operations. /// /// - Parameter pbxTarget: The `PBXTarget` to map. - /// - Returns: A fully mapped `Target` model. - /// - Throws: A `MappingError` if required information is missing or invalid. + /// - Returns: A fully mapped `Target` model containing all relevant information extracted from the `PBXTarget`. + /// - Throws: A `MappingError` if required information (e.g., a bundle identifier) is missing or invalid. func map(pbxTarget: PBXTarget) async throws -> Target } /// A mapper that converts a `PBXTarget` into a domain `Target` model. /// -/// The `TargetMapper` relies on: -/// - `SettingsMapper` to map build settings and configurations. -/// - `BuildPhaseMapper` to map source files, resources, scripts, copy files, headers, and related build phases. -/// - `DependencyMapper` to map target dependencies. -/// - `BuildRuleMapper` to map custom build rules. +/// `TargetMapper` orchestrates a multi-step process to produce a rich `Target` model: +/// - Uses `SettingsMapper` to translate `XCConfigurationList` into domain-specific build settings. +/// - Uses `BuildPhaseMapper` to enumerate and map sources, resources, headers, scripts, copy files, frameworks, core data models, +/// and raw script phases. +/// - Uses `BuildPhaseMapper` as well to identify additional files that are not tied to any build phase, ensuring a complete +/// picture of the project's file structure. +/// - Uses `DependencyMapper` to resolve target dependencies (e.g., other targets, packages). +/// - Uses `BuildRuleMapper` to incorporate custom build rules. +/// +/// The final `Target` includes data about the platform, product type, build settings, files, dependencies, and more. +/// This comprehensive model is crucial for downstream tasks like code generation, dependency analysis, and tooling integration. +/// +/// **Example Usage:** +/// ```swift +/// // Assume you have a ProjectProvider instance and a PBXTarget obtained from an Xcode project. +/// let projectProvider: ProjectProviding = ... +/// let pbxTarget: PBXTarget = ... +/// +/// // Create a TargetMapper to handle the mapping of PBXTarget to Target. +/// let targetMapper = TargetMapper(projectProvider: projectProvider) +/// +/// // Perform the mapping +/// let target = try await targetMapper.map(pbxTarget: pbxTarget) /// -/// The resulting `Target` object contains comprehensive information needed for further graph operations -/// such as code generation, analysis, or integration with other tooling. +/// // 'target' now contains a fully resolved Target model, including settings, sources, resources, dependencies, and more. +/// // This model can be used for code generation, analysis, or integration with custom development workflows. +/// ``` public final class TargetMapper: TargetMapping { private let projectProvider: ProjectProviding private let settingsMapper: SettingsMapping private let buildPhaseMapper: BuildPhaseMapping private let dependencyMapper: DependencyMapping - private let buildRuleMapper: BuildRuleMapper + private let buildRuleMapper: BuildRuleMapping /// Creates a new `TargetMapper` instance. /// - /// - Parameter projectProvider: Provides access to the project’s paths, `XcodeProj`, and related information. + /// - Parameter projectProvider: A provider granting access to project paths, the `XcodeProj`, and related data needed for + /// resolution. public init(projectProvider: ProjectProviding) { self.projectProvider = projectProvider settingsMapper = SettingsMapper() @@ -43,14 +69,18 @@ public final class TargetMapper: TargetMapping { } public func map(pbxTarget: PBXTarget) async throws -> Target { + // Extract platform, product, and deployment targets let platform = try pbxTarget.platform() let deploymentTargets = try pbxTarget.deploymentTargets() let product = pbxTarget.productType() + // Map build settings let settings = try await settingsMapper.map( projectProvider: projectProvider, configurationList: pbxTarget.buildConfigurationList ) + + // Map various build phases let sources = try await buildPhaseMapper.mapSources(target: pbxTarget) let resources = try await buildPhaseMapper.mapResources(target: pbxTarget) let headers = try await buildPhaseMapper.mapHeaders(target: pbxTarget) @@ -58,13 +88,20 @@ public final class TargetMapper: TargetMapping { let copyFiles = try await buildPhaseMapper.mapCopyFiles(target: pbxTarget) let coreDataModels = try await buildPhaseMapper.mapCoreDataModels(target: pbxTarget) let rawScriptBuildPhases = try await buildPhaseMapper.mapRawScriptBuildPhases(target: pbxTarget) - let additionalFiles: [FileElement] = [] // Currently no extra files + // Map any additional files not included in the known build phases + let additionalFiles = try await buildPhaseMapper.mapAdditionalFiles(target: pbxTarget) + + // Convert resource files to domain-specific `ResourceFileElements` let resourceFileElements = ResourceFileElements(resources) + + // Map build rules let buildRules = try await buildRuleMapper.mapBuildRules(target: pbxTarget) + // Extract environment variables let environmentVariables = pbxTarget.extractEnvironmentVariables() + // Extract various target-level metadata and settings let launchArguments = try extractLaunchArguments(from: pbxTarget) let filesGroup = try extractFilesGroup(from: pbxTarget) let playgrounds = try await extractPlaygrounds(from: pbxTarget) @@ -74,10 +111,12 @@ public final class TargetMapper: TargetMapping { let onDemandResourcesTags = try extractOnDemandResourcesTags(from: pbxTarget) let metadata = try extractMetadata(from: pbxTarget) + // Resolve dependencies (targets, packages, frameworks) let targetDependencies = try await dependencyMapper.mapDependencies(target: pbxTarget) let frameworkDependencies = try await buildPhaseMapper.mapFrameworks(target: pbxTarget) let allDependencies = targetDependencies + frameworkDependencies + // Construct the final `Target` model return Target( name: pbxTarget.name, destinations: platform, @@ -136,9 +175,7 @@ public final class TargetMapper: TargetMapping { from: data, options: .mutableContainersAndLeaves, format: &format - ) as? [String: Any] - else { - // TODO: - Better Error Message + ) as? [String: Any] else { throw MappingError.generic("Failed to cast plist contents to a dictionary.") } @@ -229,7 +266,7 @@ public final class TargetMapper: TargetMapping { } private func extractOnDemandResourcesTags(from _: PBXTarget) throws -> OnDemandResourcesTags? { - // TODO: - implement if needed + // TODO: implement if needed return nil } @@ -246,33 +283,3 @@ public final class TargetMapper: TargetMapping { return TargetMetadata(tags: tags) } } - -extension PBXTarget { - enum EnvironmentExtractor { - static func extract(from buildSettings: BuildSettings) -> [String: EnvironmentVariable] { - guard let envVars = buildSettings.stringDict(for: .environmentVariables) else { - return [:] - } - return envVars.reduce(into: [:]) { result, pair in - result[pair.key] = EnvironmentVariable(value: pair.value, isEnabled: true) - } - } - } - - /// Extracts environment variables from all build configurations of the target. - /// - /// If multiple configurations define environment variables with the same name, the last one processed - /// takes precedence. - public func extractEnvironmentVariables() -> [String: EnvironmentVariable] { - buildConfigurationList?.buildConfigurations.reduce(into: [:]) { result, config in - result.merge(EnvironmentExtractor.extract(from: config.buildSettings)) { current, _ in current - } - } ?? [:] - } - - /// Returns the build settings from the "Debug" build configuration, or an empty dictionary if not present. - var debugBuildSettings: [String: Any] { - buildConfigurationList?.buildConfigurations.first(where: { $0.name == "Debug" })?.buildSettings - ?? [:] - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift index 1c911360..3f390c1e 100644 --- a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift @@ -2,40 +2,56 @@ import Foundation import Path import PathKit import XcodeGraph -import XcodeProj +@preconcurrency import XcodeProj -/// A type that maps an `.xcworkspace` structure into a `Workspace` model. +/// A protocol defining how to map an `.xcworkspace` structure into a `Workspace` domain model. +/// +/// Conforming types parse a given `XCWorkspace` and extract all referenced projects, schemes, and other relevant information, +/// resulting in a coherent `Workspace` model that can be used for code generation, analysis, or further tooling. protocol WorkspaceMapping: Sendable { /// Maps the current workspace into a `Workspace` model. /// + /// This process gathers `.xcodeproj` references, shared schemes, and configuration options from the `.xcworkspace`, + /// consolidating them into a domain-level `Workspace` object. + /// /// - Returns: A `Workspace` instance representing the mapped workspace. - /// - Throws: If any portion of the mapping process fails. + /// - Throws: If any portion of the mapping process fails (e.g., due to invalid paths or unreadable scheme files). func map() async throws -> Workspace } -/// A mapper that translates a provided workspace into a `Workspace` model. +/// A mapper that converts a provided `.xcworkspace` into a `Workspace` model, extracting project paths, schemes, +/// and related data. +/// +/// `WorkspaceMapper` focuses on: +/// - Identifying `.xcodeproj` files referenced by the workspace. +/// - Mapping shared schemes defined within the workspace. +/// - Constructing a `Workspace` model with default generation options and placeholders for additional files or IDE templates. +/// +/// **Example Usage:** +/// ```swift +/// // Assume you have a WorkspaceProvider initialized for a given `.xcworkspace`. +/// let workspaceProvider: WorkspaceProviding = ... +/// +/// // Create a WorkspaceMapper instance +/// let workspaceMapper = WorkspaceMapper(workspaceProvider: workspaceProvider) +/// +/// // Map the workspace into a domain-level Workspace model +/// let workspace = try await workspaceMapper.map() /// -/// The `WorkspaceMapper` extracts project paths, maps schemes, and sets up generation options and -/// additional files. The resulting `Workspace` can then be used as an input to other processes, -/// such as code generation, analysis, or further transformations. +/// // 'workspace' now contains references to all identified projects and schemes, enabling further analysis +/// // or code generation tasks. +/// ``` public final class WorkspaceMapper: WorkspaceMapping { - private let workspaceProvider: WorkspaceProviding + public let workspaceProvider: WorkspaceProviding /// Creates a new `WorkspaceMapper`. /// - /// - Parameter workspaceProvider: A provider capable of supplying a parsed `XCWorkspace` and its file paths. + /// - Parameter workspaceProvider: A provider capable of supplying a parsed `XCWorkspace` and its associated paths. + /// This allows the mapper to discover referenced projects and shared schemes. public init(workspaceProvider: WorkspaceProviding) { self.workspaceProvider = workspaceProvider } - /// Maps the current workspace into a `Workspace` model. - /// - /// This method identifies all `.xcodeproj` files in the workspace, maps any detected schemes, - /// and constructs a fully-populated `Workspace` instance. It sets default generation options, - /// and includes hooks for adding additional files or IDE template macros if needed. - /// - /// - Returns: A fully constructed `Workspace` instance. - /// - Throws: If extracting projects or mapping schemes fails. public func map() async throws -> Workspace { let xcworkspace = workspaceProvider.xcworkspace let xcWorkspacePath = workspaceProvider.xcWorkspacePath @@ -44,7 +60,7 @@ public final class WorkspaceMapper: WorkspaceMapping { let projectAbsolutePaths = projectPaths.map { $0 } let workspaceName = xcWorkspacePath.basenameWithoutExt - let schemes = try await mapSchemes(from: srcPath) + let schemes = try await mapSchemes(from: xcWorkspacePath) let ideTemplateMacros: IDETemplateMacros? = nil let additionalFiles: [FileElement] = [] @@ -69,27 +85,26 @@ public final class WorkspaceMapper: WorkspaceMapping { /// Recursively extracts all `.xcodeproj` paths from the workspace’s file and group references. /// + /// This traversal ensures that all projects included in nested groups are discovered, + /// providing a complete picture of the workspace’s project set. + /// /// - Parameters: /// - elements: The array of `XCWorkspaceDataElement` representing files or groups in the workspace. /// - srcPath: The source directory path used as a base for resolving relative references. /// - Returns: An array of absolute paths to `.xcodeproj` directories. - /// - Throws: If resolving any referenced path fails. - private func extractProjectPaths(from elements: [XCWorkspaceDataElement], srcPath: AbsolutePath) - throws -> [AbsolutePath] - { + /// - Throws: If resolving any referenced path fails (e.g., invalid relative paths). + private func extractProjectPaths( + from elements: [XCWorkspaceDataElement], + srcPath: AbsolutePath + ) throws -> [AbsolutePath] { var paths = [AbsolutePath]() for element in elements { switch element { case let .file(ref): - let refPath = Path(ref.location.path) - if refPath.extension?.lowercased() == "xcodeproj" { - do { - let absPath = try ref.absolutePath(srcPath: srcPath) - paths.append(absPath) - } catch { - print("⚠️ Could not resolve absolute path for \(ref.location.path): \(error)") - } + let refPath = try ref.absolutePath(srcPath: srcPath) + if refPath.fileExtension == .xcodeproj { + paths.append(refPath) } case let .group(group): let groupPaths = try extractProjectPaths( @@ -105,9 +120,12 @@ public final class WorkspaceMapper: WorkspaceMapping { /// Maps all shared schemes found within the workspace. /// + /// Shared schemes are typically located in the `xcshareddata/xcschemes` directory inside the workspace. + /// If present, they are parsed and mapped into `Scheme` models that can be integrated into the `Workspace`. + /// /// - Parameter srcPath: The source path of the workspace. /// - Returns: An array of mapped `Scheme` instances. - /// - Throws: If reading or mapping any of the schemes fails. + /// - Throws: If reading or mapping any of the schemes fails (e.g., invalid `.xcscheme` files or missing references). private func mapSchemes(from srcPath: AbsolutePath) async throws -> [Scheme] { var schemes = [Scheme]() let sharedDataPath = Path(srcPath.pathString) + "xcshareddata/xcschemes" diff --git a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift index 408a4c07..c75dfb88 100644 --- a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift +++ b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift @@ -4,17 +4,48 @@ import PathKit import XcodeGraph import XcodeProj -/// A type that provides access to a workspace and its underlying `.xcworkspace` file. +/// A protocol that defines how to provide access to a `.xcworkspace` file and its parsed representation. +/// +/// Conforming types supply: +/// - The directory containing the workspace (`workspaceDirectory`). +/// - The absolute path to the `.xcworkspace` file (`xcWorkspacePath`). +/// - A parsed `XCWorkspace` instance, enabling exploration of the workspace structure. +/// +/// By abstracting these details, tooling can easily navigate and analyze workspaces, discovering contained projects +/// and shared schemes without having to manually resolve file paths or parse the workspace file. public protocol WorkspaceProviding: Sendable { - /// The absolute path to the workspace file. + /// The absolute path to the directory containing the `.xcworkspace` file. var workspaceDirectory: AbsolutePath { get } + + /// The absolute path to the `.xcworkspace` file. var xcWorkspacePath: AbsolutePath { get } /// The parsed `XCWorkspace` instance representing the workspace. var xcworkspace: XCWorkspace { get } } -/// A concrete provider for workspaces, offering access to the `.xcworkspace` file and its parsed representation. +/// A concrete provider for workspaces, offering easy access to the `.xcworkspace` file and its parsed representation. +/// +/// `WorkspaceProvider` streamlines the process of working with Xcode workspaces by: +/// - Determining and storing the `xcWorkspacePath`. +/// - Providing the `workspaceDirectory` as the parent directory of the `.xcworkspace` file. +/// - Loading and storing the parsed `XCWorkspace` instance. +/// +/// **Example Usage:** +/// ```swift +/// import XcodeProj +/// +/// // Assume you have an AbsolutePath to the .xcworkspace file. +/// let workspacePath: AbsolutePath = ... +/// +/// // Create a WorkspaceProvider instance +/// let workspaceProvider = try WorkspaceProvider(xcWorkspacePath: workspacePath) +/// +/// // Access the parsed XCWorkspace +/// let xcworkspace = workspaceProvider.xcworkspace +/// +/// // From here, you can inspect workspace elements, discover contained projects, or integrate with other mappers. +/// ``` public struct WorkspaceProvider: WorkspaceProviding { public let workspaceDirectory: AbsolutePath public let xcWorkspacePath: AbsolutePath @@ -22,8 +53,11 @@ public struct WorkspaceProvider: WorkspaceProviding { /// Initializes a `WorkspaceProvider` with a given workspace path. /// - /// - Parameter workspacePath: The absolute path to the `.xcworkspace` file. + /// - Parameter xcWorkspacePath: The absolute path to the `.xcworkspace` file. /// - Throws: If the `.xcworkspace` file cannot be loaded or parsed. + /// + /// Once initialized, `WorkspaceProvider` can be passed to tools like `WorkspaceMapper` to produce a `Workspace` model, + /// or used directly to gather workspace-related data. public init(xcWorkspacePath: AbsolutePath) throws { self.xcWorkspacePath = xcWorkspacePath workspaceDirectory = xcWorkspacePath.parentDirectory diff --git a/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift b/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift index 2c3fb416..a98853fb 100644 --- a/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift +++ b/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift @@ -1,9 +1,11 @@ import Foundation +// MARK: - Executable + /// Represents an executable command with its arguments, executable path, and a parser for the output. /// -/// This enum is used to define commands like `lipo` or custom executables, encapsulating the logic -/// for their arguments, path, and output processing. +/// Used to define commands like `lipo` or custom executables, encapsulating the logic +/// for arguments, path, and output processing. public enum Executable: Sendable { /// A `lipo` command, used for managing universal binaries. /// @@ -22,8 +24,6 @@ public enum Executable: Sendable { case custom(String, [String], @Sendable (ProcessResult) throws -> Output) /// The path to the executable. - /// - /// - Returns: A `String` representing the absolute path to the executable. public var path: String { switch self { case let .lipo(_, _, path): @@ -34,8 +34,6 @@ public enum Executable: Sendable { } /// The arguments to pass to the executable. - /// - /// - Returns: An array of `String` arguments. public var arguments: [String] { switch self { case let .lipo(lipoArgs, _, _): @@ -46,8 +44,6 @@ public enum Executable: Sendable { } /// A parser to convert the `ProcessResult` into the desired `Output` type. - /// - /// - Returns: A closure that takes a `ProcessResult` and returns an `Output` value or throws an error. public var parser: (ProcessResult) throws -> Output { switch self { case let .lipo(_, parser, _): diff --git a/Sources/XcodeProjToGraph/ProcessRunner/ProcessResult.swift b/Sources/XcodeProjToGraph/ProcessRunner/ProcessResult.swift index c8167696..854d6fc2 100644 --- a/Sources/XcodeProjToGraph/ProcessRunner/ProcessResult.swift +++ b/Sources/XcodeProjToGraph/ProcessRunner/ProcessResult.swift @@ -1,13 +1,10 @@ import Foundation -/// Represents the result of executing a process. -/// -/// This struct encapsulates the process's exit code, standard output, and standard error streams, -/// and provides a convenience property to determine if the process succeeded. +// MARK: - ProcessResult + +/// Represents the result of executing a process, including exit code, stdout, and stderr. public struct ProcessResult: Sendable, CustomStringConvertible { - /// The exit code of the process. - /// - /// A value of `0` typically indicates success, while non-zero values represent errors. + /// The exit code of the process. `0` typically indicates success. public let exitCode: Int32 /// The standard output of the process as a `String`. @@ -17,8 +14,6 @@ public struct ProcessResult: Sendable, CustomStringConvertible { public let stderr: String /// Indicates whether the process exited successfully. - /// - /// - Returns: `true` if the exit code is `0`, otherwise `false`. public var succeeded: Bool { exitCode == 0 } diff --git a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift index fa0113ec..b5a5cb7b 100644 --- a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift +++ b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift @@ -1,5 +1,8 @@ import Foundation +// MARK: - ProcessRunner + +/// A utility for running shell commands asynchronously and parsing their results. public enum ProcessRunner { /// Runs the given executable asynchronously and processes its result using the associated parser. /// @@ -8,9 +11,10 @@ public enum ProcessRunner { /// - environment: An optional dictionary of environment variables for the process. /// - workingDirectory: An optional path for the process's working directory. /// - throwOnNonZeroExit: If `true`, throws an error for non-zero exit codes. Defaults to `true`. + /// - fileManager: A `FileManager` instance, defaulting to `.default`. /// - Returns: The structured output parsed from the process's result. /// - Throws: - /// - `ProcessRunnerError` for issues like non-zero exit codes, invalid UTF-8, or failure to run. + /// - `ProcessRunnerError` for issues like non-zero exit codes, invalid UTF-8, or a failure to run. @discardableResult public static func run( executable: Executable, @@ -30,8 +34,8 @@ public enum ProcessRunner { process.executableURL = URL(fileURLWithPath: execPath) process.arguments = executable.arguments process.environment = environment ?? ProcessInfo.processInfo.environment - if let wd = workingDirectory { - process.currentDirectoryURL = URL(fileURLWithPath: wd) + if let workingDirectory { + process.currentDirectoryURL = URL(fileURLWithPath: workingDirectory) } let stdoutPipe = Pipe() @@ -46,6 +50,7 @@ public enum ProcessRunner { guard let stdoutString = String(data: stdoutData, encoding: .utf8), let stderrString = String(data: stderrData, encoding: .utf8) else { + // More descriptive error message on UTF-8 failure continuation.resume(throwing: ProcessRunnerError.invalidUTF8InOutput) return } diff --git a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift index 7262ee8a..a5c50eae 100644 --- a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift +++ b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift @@ -1,5 +1,6 @@ import Foundation +/// Errors that can occur when running processes with `ProcessRunner`. public enum ProcessRunnerError: Error, LocalizedError, Equatable { case executableNotFound(String) case failedToRunProcess(String) diff --git a/Sources/XcodeProjToGraph/XcodeProjToGraph.docc/Documentation.md b/Sources/XcodeProjToGraph/XcodeProjToGraph.docc/Documentation.md index 99d62059..7b7359f1 100644 --- a/Sources/XcodeProjToGraph/XcodeProjToGraph.docc/Documentation.md +++ b/Sources/XcodeProjToGraph/XcodeProjToGraph.docc/Documentation.md @@ -1,13 +1,45 @@ -# ``XcodeGraphMapper`` +# XcodeProjToGraph -Summary +A tool that maps Xcode projects (`.xcodeproj` and `.xcworkspace`) into a structured, analyzable graph of projects, targets, dependencies, and build settings. This enables downstream tasks such as code generation, dependency analysis, and integration with custom tooling pipelines. ## Overview -Text +`XcodeProjToGraph` takes advantage of `XcodeProj` to parse and navigate Xcode project files, then translates them into a domain-specific graph model (`XcodeGraph.Graph`). This model captures all essential components—projects, targets, packages, dependencies, build settings, schemes, and more—providing a high-level, language-agnostic structure for further processing. + +By using this graph-based representation, developers can easily analyze project configurations, visualize complex dependency graphs, or integrate advanced workflows into their build pipelines. For example, teams can leverage `XcodeProjToGraph` to: +- Generate code based on discovered resources and targets. +- Validate project configurations and detect missing bundle identifiers or invalid references. +- Explore dependencies between multiple projects and packages within a workspace. +- Automate repetitive tasks like scheme generation, resource synthesis, or compliance checks. ## Topics -### Group +### Project and Workspace Mapping + +- ``ProjectParser`` +- ``GraphMapper`` +- ``WorkspaceMapper`` +- ``ProjectMapper`` +- ``TargetMapper`` +- ``DependencyMapper`` +- ``SettingsMapper`` +- ``SchemeMapper`` +- ``PackageMapper`` +- ``BuildPhaseMapper`` +- ``PlatformConditionMapper`` + +### Utilities and Supporting Structures + +- ``WorkspaceProvider`` +- ``ProjectProvider`` + +### Errors and Diagnostics + +- ``MappingError`` +- ``ProcessRunnerError`` + +### Advanced Usage -- ``Symbol`` \ No newline at end of file +- ``LipoTool`` +- ``ProcessRunner`` +- ``Executable`` diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift index 8d1c1ea4..a533654c 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift @@ -9,7 +9,7 @@ import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test + @Test("Maps a command-line tool with a dynamic framework dependency into the correct graph") func commandLineToolWithDynamicFramework() async throws { try await assertGraph { .commandLineToolWithDynamicFramework @@ -103,7 +103,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "CommandLineTool" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/command_line_tool_with_dynamic_framework/Derived/InfoPlists/CommandLineTool-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/command_line_tool_with_dynamic_framework/Derived/InfoPlists/DynamicFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift - buildRules: 0 elements - bundleId: "com.example.commandlinetool" ▿ copyFiles: 1 element @@ -160,7 +169,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "DynamicFramework" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/command_line_tool_with_dynamic_framework/Derived/InfoPlists/CommandLineTool-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/command_line_tool_with_dynamic_framework/Derived/InfoPlists/DynamicFramework-Info.plist - buildRules: 0 elements - bundleId: "com.example.dynamicframework" ▿ copyFiles: 1 element diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift index ff3da7c4..ba81f5f0 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift @@ -9,7 +9,7 @@ import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test + @Test("Maps a large iOS app project into the correct graph") func iosAppLarge() async throws { let path = try WorkspaceFixture.iosAppLarge.absolutePath() diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift index 61439aea..1e345a07 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift @@ -9,7 +9,7 @@ import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test + @Test("Maps an iOS app with extensions into the correct graph") func iosAppWithExtensions() async throws { try await assertGraph { .iosAppWithExtensions @@ -152,7 +152,76 @@ extension IntegrationTests { ▿ (2 elements) - key: "App" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 23 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - buildRules: 0 elements - bundleId: "io.tuist.App" ▿ copyFiles: 3 elements @@ -241,7 +310,76 @@ extension IntegrationTests { ▿ (2 elements) - key: "AppIntentExtension" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 23 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - buildRules: 0 elements - bundleId: "io.tuist.App.AppIntentExtension" ▿ copyFiles: 1 element @@ -299,7 +437,76 @@ extension IntegrationTests { ▿ (2 elements) - key: "AppWithMessagesExtension" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 23 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - buildRules: 0 elements - bundleId: "io.tuist.App2" ▿ copyFiles: 2 elements @@ -372,7 +579,79 @@ extension IntegrationTests { ▿ (2 elements) - key: "Bundle" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 24 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - buildRules: 0 elements - bundleId: "io.tuist.App.Bundle" ▿ copyFiles: 1 element @@ -423,7 +702,70 @@ extension IntegrationTests { ▿ (2 elements) - key: "MessageExtension" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 21 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - buildRules: 0 elements - bundleId: "io.tuist.App2.MessageExtension" ▿ copyFiles: 1 element @@ -470,7 +812,7 @@ extension IntegrationTests { - inclusionCondition: Optional.none ▿ ResourceFileElement ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard - tags: 0 elements - inclusionCondition: Optional.none - scripts: 0 elements @@ -497,7 +839,79 @@ extension IntegrationTests { ▿ (2 elements) - key: "NotificationServiceExtension" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 24 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - buildRules: 0 elements - bundleId: "io.tuist.App.NotificationServiceExtension" ▿ copyFiles: 1 element @@ -549,7 +963,79 @@ extension IntegrationTests { ▿ (2 elements) - key: "StaticFramework" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 24 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - buildRules: 0 elements - bundleId: "io.tuist.App.StaticFramework" ▿ copyFiles: 1 element @@ -601,7 +1087,79 @@ extension IntegrationTests { ▿ (2 elements) - key: "StickersPackExtension" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 24 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - buildRules: 0 elements - bundleId: "io.tuist.App.StickersPackExtension" ▿ copyFiles: 1 element @@ -652,7 +1210,70 @@ extension IntegrationTests { ▿ (2 elements) - key: "WidgetExtension" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 21 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets - buildRules: 0 elements - bundleId: "io.tuist.App.WidgetExtension" ▿ copyFiles: 2 elements diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift index 8559e611..bc040ab7 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift @@ -9,7 +9,7 @@ import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test + @Test("Maps an iOS app with multiple configurations into the correct graph") func iosAppWithMultiConfigs() async throws { try await assertGraph { .iosAppWithMultiConfigs @@ -129,7 +129,25 @@ extension IntegrationTests { ▿ (2 elements) - key: "App" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 6 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig - buildRules: 0 elements - bundleId: "io.tuist.App" ▿ copyFiles: 1 element @@ -181,7 +199,25 @@ extension IntegrationTests { ▿ (2 elements) - key: "AppTests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 6 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig - buildRules: 0 elements - bundleId: "io.tuist.AppTests" ▿ copyFiles: 1 element @@ -281,7 +317,25 @@ extension IntegrationTests { ▿ (2 elements) - key: "Framework1" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 6 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift - buildRules: 0 elements - bundleId: "io.tuist.Framework1" ▿ copyFiles: 1 element @@ -333,7 +387,25 @@ extension IntegrationTests { ▿ (2 elements) - key: "Framework1Tests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 6 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist - buildRules: 0 elements - bundleId: "io.tuist.Framework1Tests" ▿ copyFiles: 1 element @@ -433,7 +505,28 @@ extension IntegrationTests { ▿ (2 elements) - key: "Framework2" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 7 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift - buildRules: 0 elements - bundleId: "io.tuist.Framework2" ▿ copyFiles: 1 element @@ -485,7 +578,28 @@ extension IntegrationTests { ▿ (2 elements) - key: "Framework2Tests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 7 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist - buildRules: 0 elements - bundleId: "io.tuist.Framework2Tests" ▿ copyFiles: 1 element diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift index 974a8e26..449e5da7 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift @@ -17,7 +17,7 @@ extension IntegrationTests { try #require(graph != nil) } - @Test + @Test("Maps an iOS app with a remote Swift package into the correct graph") func iosAppWithRemoteSwiftPackage() async throws { try await assertGraph { .iosAppWithRemoteSwiftPackage @@ -121,7 +121,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "App" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_remote_swift_package/Support/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift - buildRules: 0 elements - bundleId: "io.tuist.App" ▿ copyFiles: 1 element @@ -173,7 +182,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "AppTests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_remote_swift_package/Support/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist - buildRules: 0 elements - bundleId: "io.tuist.AppTests" ▿ copyFiles: 1 element diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift index 204c04f4..fdbe4473 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift @@ -9,7 +9,7 @@ import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test + @Test("Maps an iOS app with SPM dependencies into the correct graph") func iosAppWithSpmDependencies() async throws { try await assertGraph { .iosAppWithSpmDependencies @@ -110,7 +110,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "App" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_spm_dependencies/Derived/InfoPlists/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_spm_dependencies/Derived/InfoPlists/AppTests-Info.plist - buildRules: 0 elements - bundleId: "io.tuist.app" ▿ copyFiles: 2 elements @@ -196,7 +205,31 @@ extension IntegrationTests { ▿ (2 elements) - key: "AppTests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 8 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_spm_dependencies/Derived/InfoPlists/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_spm_dependencies/Derived/InfoPlists/AppTests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_spm_dependencies/Derived/Sources/TuistAssets+App.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_spm_dependencies/Derived/Sources/TuistBundle+App.swift - buildRules: 0 elements - bundleId: "io.tuist.app.tests" ▿ copyFiles: 1 element diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift index 5a3acfcb..527666f6 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift @@ -9,7 +9,7 @@ import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test + @Test("Maps an iOS app with transitive static libraries into the correct graph") func iosAppWithStaticLibraries() async throws { try await assertGraph { .iosAppWithStaticLibraries @@ -154,7 +154,13 @@ extension IntegrationTests { ▿ (2 elements) - key: "A" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 2 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a - buildRules: 0 elements - bundleId: "io.tuist.A" ▿ copyFiles: 2 elements @@ -211,7 +217,10 @@ extension IntegrationTests { ▿ (2 elements) - key: "ATests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 1 element + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift - buildRules: 0 elements - bundleId: "io.tuist.ATests" ▿ copyFiles: 1 element @@ -317,7 +326,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "B" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift - buildRules: 0 elements - bundleId: "io.tuist.B" ▿ copyFiles: 1 element @@ -369,7 +387,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "BTests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist - buildRules: 0 elements - bundleId: "io.tuist.BTests" ▿ copyFiles: 1 element @@ -469,7 +496,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "App" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift - buildRules: 0 elements - bundleId: "io.tuist.App" ▿ copyFiles: 1 element @@ -527,7 +563,19 @@ extension IntegrationTests { ▿ (2 elements) - key: "AppTests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 4 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Tests.plist - buildRules: 0 elements - bundleId: "io.tuist.AppTests" ▿ copyFiles: 1 element diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift index 9e26a527..30835a7d 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift @@ -9,7 +9,7 @@ import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test + @Test("Maps an iOS workspace using microfeature architecture with static linking into the correct graph") func iosWorkspaceWithMicrofeatureArchitectureStaticLinking() async throws { try await assertGraph { .iosWorkspaceWithMicrofeatureArchitectureStaticLinking @@ -168,7 +168,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "Core" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift - buildRules: 0 elements - bundleId: "io.tuist.Core" ▿ copyFiles: 1 element @@ -220,7 +229,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "CoreTests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist - buildRules: 0 elements - bundleId: "io.tuist.CoreTests" ▿ copyFiles: 1 element @@ -320,7 +338,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "Data" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift - buildRules: 0 elements - bundleId: "io.tuist.Data" ▿ copyFiles: 2 elements @@ -377,7 +404,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "DataTests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist - buildRules: 0 elements - bundleId: "io.tuist.DataFrameworkTests" ▿ copyFiles: 1 element @@ -477,7 +513,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "FrameworkA" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift - buildRules: 0 elements - bundleId: "io.tuist.FrameworkA" ▿ copyFiles: 2 elements @@ -534,7 +579,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "FrameworkATests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist - buildRules: 0 elements - bundleId: "io.tuist.FrameworkATests" ▿ copyFiles: 1 element @@ -634,7 +688,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "FeatureContracts" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift - buildRules: 0 elements - bundleId: "io.tuist.FeatureContracts" ▿ copyFiles: 2 elements @@ -697,7 +760,19 @@ extension IntegrationTests { ▿ (2 elements) - key: "FeatureContractsTests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 4 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist - buildRules: 0 elements - bundleId: "io.tuist.FeatureContractsTests" ▿ copyFiles: 1 element @@ -797,7 +872,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "UIComponents" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift - buildRules: 0 elements - bundleId: "io.tuist.UIComponents" ▿ copyFiles: 2 elements @@ -854,7 +938,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "UIComponentsTests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist - buildRules: 0 elements - bundleId: "io.tuist.UIComponentsTests" ▿ copyFiles: 1 element @@ -954,7 +1047,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "StaticApp" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift - buildRules: 0 elements - bundleId: "io.tuist.StaticApp" ▿ copyFiles: 1 element @@ -1006,7 +1108,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "StaticAppTests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist - buildRules: 0 elements - bundleId: "io.tuist.StaticAppTests" ▿ copyFiles: 1 element diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift index fb04f120..99734fff 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift @@ -8,7 +8,7 @@ import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test + @Test("Maps an iOS app with a transitive framework dependency into the correct graph") func ios_app_with_transitive_framework() async throws { try await assertGraph { .ios_app_with_transitive_framework @@ -216,7 +216,22 @@ extension IntegrationTests { ▿ (2 elements) - key: "App" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 5 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - buildRules: 0 elements - bundleId: "io.tuist.App" ▿ copyFiles: 1 element @@ -268,7 +283,22 @@ extension IntegrationTests { ▿ (2 elements) - key: "AppTests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 5 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - buildRules: 0 elements - bundleId: "io.tuist.AppTests" ▿ copyFiles: 1 element @@ -325,7 +355,22 @@ extension IntegrationTests { ▿ (2 elements) - key: "AppUITests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 5 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - buildRules: 0 elements - bundleId: "io.tuist.AppUITests" ▿ copyFiles: 1 element @@ -425,7 +470,19 @@ extension IntegrationTests { ▿ (2 elements) - key: "Framework1-iOS" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 4 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework - buildRules: 0 elements - bundleId: "io.tuist.Framework1" ▿ copyFiles: 1 element @@ -482,7 +539,19 @@ extension IntegrationTests { ▿ (2 elements) - key: "Framework1-macOS" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 4 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - buildRules: 0 elements - bundleId: "io.tuist.Framework1" ▿ copyFiles: 1 element @@ -539,7 +608,22 @@ extension IntegrationTests { ▿ (2 elements) - key: "Framework1Tests-iOS" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 5 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - buildRules: 0 elements - bundleId: "io.tuist.Framework1Tests" ▿ copyFiles: 1 element @@ -596,7 +680,22 @@ extension IntegrationTests { ▿ (2 elements) - key: "Framework1Tests-macOS" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 5 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - buildRules: 0 elements - bundleId: "io.tuist.Framework1Tests" ▿ copyFiles: 1 element @@ -696,7 +795,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "StaticFramework1" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Derived/InfoPlists/StaticFramework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Derived/InfoPlists/StaticFramework1Tests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift - buildRules: 0 elements - bundleId: "io.tuist.StaticFramework1" ▿ copyFiles: 1 element @@ -753,7 +861,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "StaticFramework1Tests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Derived/InfoPlists/StaticFramework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Derived/InfoPlists/StaticFramework1Tests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift - buildRules: 0 elements - bundleId: "io.tuist.StaticFramework1Tests" ▿ copyFiles: 1 element diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift index f089f6ac..76bffd76 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift @@ -9,7 +9,7 @@ import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test + @Test("Maps a macOS app with a system extension into the correct graph") func macosAppWithSystemExtension() async throws { try await assertGraph { .macosAppWithSystemExtension @@ -103,7 +103,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "MainApp" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/macos_app_with_system_extension/Derived/InfoPlists/SystemExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/macos_app_with_system_extension/MainApp/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift - buildRules: 0 elements - bundleId: "io.tuist.MainApp" ▿ copyFiles: 2 elements @@ -166,7 +175,16 @@ extension IntegrationTests { ▿ (2 elements) - key: "SystemExtension" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/macos_app_with_system_extension/Derived/InfoPlists/SystemExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/macos_app_with_system_extension/MainApp/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift - buildRules: 0 elements - bundleId: "io.tuist.SystemExtension" ▿ copyFiles: 1 element diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift index 63b88282..466abfc3 100644 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift +++ b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift @@ -9,7 +9,7 @@ import XcodeProjToGraph @testable import TestSupport extension IntegrationTests { - @Test + @Test("Maps a multiplatform app with macros and an embedded watchOS app into the correct graph") func multiplatformAppWithMacrosAndEmbeddedWatchosApp() async throws { try await assertGraph { .multiplatformAppWithMacrosAndEmbeddedWatchosApp @@ -167,7 +167,52 @@ extension IntegrationTests { ▿ (2 elements) - key: "App" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 15 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleA-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros_Testable-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleATests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift - buildRules: 0 elements - bundleId: "io.tuist.App" ▿ copyFiles: 2 elements @@ -261,7 +306,61 @@ extension IntegrationTests { ▿ (2 elements) - key: "ModuleA" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 18 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleA-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros_Testable-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleATests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift - buildRules: 0 elements - bundleId: "io.tuist.modulea" ▿ copyFiles: 1 element @@ -324,7 +423,64 @@ extension IntegrationTests { ▿ (2 elements) - key: "ModuleAMacros" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 19 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleA-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros_Testable-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleATests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift - buildRules: 0 elements - bundleId: "io.tuist.moduleamacros" ▿ copyFiles: 1 element @@ -377,7 +533,64 @@ extension IntegrationTests { ▿ (2 elements) - key: "ModuleAMacros_Testable" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 19 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleA-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros_Testable-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleATests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift - buildRules: 0 elements - bundleId: "io.tuist.moduleamacros.testable" ▿ copyFiles: 1 element @@ -429,7 +642,64 @@ extension IntegrationTests { ▿ (2 elements) - key: "ModuleATests" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 19 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleA-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros_Testable-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleATests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift - buildRules: 0 elements - bundleId: "io.tuist.moduleatests" ▿ copyFiles: 1 element @@ -491,7 +761,49 @@ extension IntegrationTests { ▿ (2 elements) - key: "WatchApp" ▿ value: Target - - additionalFiles: 0 elements + ▿ additionalFiles: 14 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleA-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros_Testable-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleATests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift - buildRules: 0 elements - bundleId: "io.tuist.App.watchkitapp" ▿ copyFiles: 1 element diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift index 72017d11..ca6f0bda 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift @@ -1,17 +1,15 @@ import Testing +import TestSupport import XcodeGraph import XcodeProj - -@testable import TestSupport @testable import XcodeProjToGraph +@Suite struct BuildPhaseMapperTests { - @Test func testMapSources() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj + @Test("Maps swift source files with compiler flags from sources phase") + func testMapSources() async throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj let fileRef = PBXFileReference.mock( sourceTree: .group, @@ -19,7 +17,6 @@ struct BuildPhaseMapperTests { path: "main.swift", pbxProj: pbxProj ) - let buildFile = PBXBuildFile.mock( file: fileRef, settings: ["COMPILER_FLAGS": "-DDEBUG"], pbxProj: pbxProj ) @@ -27,34 +24,25 @@ struct BuildPhaseMapperTests { let target = PBXNativeTarget.mock( name: "App", - buildConfigurationList: nil, - buildRules: [], buildPhases: [sourcesPhase], - dependencies: [], productType: .application, pbxProj: pbxProj ) + try provider.addTargets([target]) - if let project = pbxProj.projects.first { - project.targets.append(target) - } - - let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let mapper = BuildPhaseMapper(projectProvider: provider) let sources = try await mapper.mapSources(target: target) #expect(sources.count == 1) - let sourceFile = sources.first - try #require(sourceFile != nil) - #expect(sourceFile?.path.basename == "main.swift") - #expect(sourceFile?.compilerFlags == "-DDEBUG") + let sourceFile = try #require(sources.first) + #expect(sourceFile.path.basename == "main.swift") + #expect(sourceFile.compilerFlags == "-DDEBUG") } - @Test func testMapResources() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj + @Test("Maps resources (like xcassets) from resources phase") + func testMapResources() async throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj let assetRef = PBXFileReference.mock( sourceTree: .group, @@ -62,30 +50,23 @@ struct BuildPhaseMapperTests { path: "Assets.xcassets", pbxProj: pbxProj ) - let buildFile = PBXBuildFile.mock(file: assetRef, pbxProj: pbxProj) let resourcesPhase = PBXResourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) let target = PBXNativeTarget.mock( name: "App", - buildConfigurationList: nil, - buildRules: [], buildPhases: [resourcesPhase], - dependencies: [], productType: .application, pbxProj: pbxProj ) + try provider.addTargets([target]) - if let project = pbxProj.projects.first { - project.targets.append(target) - } - - let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let mapper = BuildPhaseMapper(projectProvider: provider) let resources = try await mapper.mapResources(target: target) + #expect(resources.count == 1) - let resource = resources.first - try #require(resource != nil) - switch resource! { + let resource = try #require(resources.first) + switch resource { case let .file(path, _, _): #expect(path.basename == "Assets.xcassets") default: @@ -93,80 +74,57 @@ struct BuildPhaseMapperTests { } } - @Test func testMapFrameworks() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj + @Test("Maps frameworks from frameworks phase") + func testMapFrameworks() async throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj - // Create a framework file reference let frameworkRef = PBXFileReference.mock( sourceTree: .group, name: "MyFramework.framework", path: "Frameworks/MyFramework.framework", pbxProj: pbxProj ) - let frameworkBuildFile = PBXBuildFile.mock(file: frameworkRef, pbxProj: pbxProj) - let frameworksPhase = PBXFrameworksBuildPhase.mock( - files: [frameworkBuildFile], pbxProj: pbxProj - ) + let frameworksPhase = PBXFrameworksBuildPhase.mock(files: [frameworkBuildFile], pbxProj: pbxProj) let target = PBXNativeTarget.mock( name: "App", - buildConfigurationList: nil, - buildRules: [], buildPhases: [frameworksPhase], - dependencies: [], productType: .application, pbxProj: pbxProj ) + try provider.addTargets([target]) - if let project = pbxProj.projects.first { - project.targets.append(target) - } - - let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let mapper = BuildPhaseMapper(projectProvider: provider) let frameworks = try await mapper.mapFrameworks(target: target) + #expect(frameworks.count == 1) - let dependency = frameworks.first - try #require(dependency != nil) - #expect(dependency?.name == "MyFramework") + let dependency = try #require(frameworks.first) + #expect(dependency.name == "MyFramework") } - @Test func testMapHeaders() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj + @Test("Maps public, private, and project headers from headers phase") + func testMapHeaders() async throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj - // Public header let publicHeaderRef = PBXFileReference.mock( - name: "PublicHeader.h", - path: "Include/PublicHeader.h", - pbxProj: pbxProj + name: "PublicHeader.h", path: "Include/PublicHeader.h", pbxProj: pbxProj ) let publicBuildFile = PBXBuildFile.mock( file: publicHeaderRef, settings: ["ATTRIBUTES": ["Public"]], pbxProj: pbxProj ) - // Private header let privateHeaderRef = PBXFileReference.mock( - name: "PrivateHeader.h", - path: "Include/PrivateHeader.h", - pbxProj: pbxProj + name: "PrivateHeader.h", path: "Include/PrivateHeader.h", pbxProj: pbxProj ) let privateBuildFile = PBXBuildFile.mock( file: privateHeaderRef, settings: ["ATTRIBUTES": ["Private"]], pbxProj: pbxProj ) - // Project header (no attributes) let projectHeaderRef = PBXFileReference.mock( - name: "ProjectHeader.h", - path: "Include/ProjectHeader.h", - pbxProj: pbxProj + name: "ProjectHeader.h", path: "Include/ProjectHeader.h", pbxProj: pbxProj ) let projectBuildFile = PBXBuildFile.mock(file: projectHeaderRef, pbxProj: pbxProj) @@ -179,32 +137,25 @@ struct BuildPhaseMapperTests { let target = PBXNativeTarget.mock( name: "App", - buildConfigurationList: nil, - buildRules: [], buildPhases: [headersPhase], - dependencies: [], productType: .application, pbxProj: pbxProj ) + try provider.addTargets([target]) - if let project = pbxProj.projects.first { - project.targets.append(target) - } - - let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let mapper = BuildPhaseMapper(projectProvider: provider) let headers = try await mapper.mapHeaders(target: target) try #require(headers != nil) + #expect(headers?.public.map(\.basename).contains("PublicHeader.h") == true) #expect(headers?.private.map(\.basename).contains("PrivateHeader.h") == true) #expect(headers?.project.map(\.basename).contains("ProjectHeader.h") == true) } - @Test func testMapScripts() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj + @Test("Maps embedded run scripts with specified input/output paths") + func testMapScripts() async throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj let scriptPhase = PBXShellScriptBuildPhase.mock( name: "Run Script", @@ -216,47 +167,34 @@ struct BuildPhaseMapperTests { let target = PBXNativeTarget.mock( name: "App", - buildConfigurationList: nil, - buildRules: [], buildPhases: [scriptPhase], - dependencies: [], productType: .application, pbxProj: pbxProj ) + try provider.addTargets([target]) - if let project = pbxProj.projects.first { - project.targets.append(target) - } - - let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let mapper = BuildPhaseMapper(projectProvider: provider) let scripts = try await mapper.mapScripts(target: target) + #expect(scripts.count == 1) - let script = scripts.first - try #require(script != nil) - #expect(script?.name == "Run Script") - #expect(script?.script == .embedded("echo Hello")) - #expect(script?.inputPaths == ["$(SRCROOT)/input.txt"]) - #expect(script?.outputPaths == ["$(DERIVED_FILE_DIR)/output.txt"]) + let script = try #require(scripts.first) + #expect(script.name == "Run Script") + #expect(script.script == .embedded("echo Hello")) + #expect(script.inputPaths == ["$(SRCROOT)/input.txt"]) + #expect(script.outputPaths == ["$(DERIVED_FILE_DIR)/output.txt"]) } - @Test func testMapCopyFiles() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj + @Test("Maps copy files actions, verifying code-sign-on-copy attributes") + func testMapCopyFiles() async throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj let fileRef = PBXFileReference.mock( - sourceTree: .group, - name: "MyLibrary.dylib", - path: "MyLibrary.dylib", - pbxProj: pbxProj + sourceTree: .group, name: "MyLibrary.dylib", path: "MyLibrary.dylib", pbxProj: pbxProj ) - // Setting an attribute for code sign on copy let buildFile = PBXBuildFile.mock( file: fileRef, settings: ["ATTRIBUTES": ["CodeSignOnCopy"]], pbxProj: pbxProj ) - let copyFilesPhase = PBXCopyFilesBuildPhase.mock( name: "Embed Libraries", dstPath: "Libraries", @@ -267,44 +205,36 @@ struct BuildPhaseMapperTests { let target = PBXNativeTarget.mock( name: "App", - buildConfigurationList: nil, - buildRules: [], buildPhases: [copyFilesPhase], - dependencies: [], productType: .application, pbxProj: pbxProj ) - if let project = pbxProj.projects.first { - project.targets.append(target) - } + try provider.addTargets([target]) - let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let mapper = BuildPhaseMapper(projectProvider: provider) let copyActions = try await mapper.mapCopyFiles(target: target) + #expect(copyActions.count == 1) - let action = copyActions.first - try #require(action != nil) - #expect(action?.name == "Embed Libraries") - #expect(action?.destination == .frameworks) - #expect(action?.subpath == "Libraries") - #expect(action?.files.count == 1) - let fileAction = action?.files.first - try #require(fileAction != nil) - #expect(fileAction?.codeSignOnCopy == true) - #expect(fileAction?.path.basename == "MyLibrary.dylib") + let action = try #require(copyActions.first) + #expect(action.name == "Embed Libraries") + #expect(action.destination == .frameworks) + #expect(action.subpath == "Libraries") + #expect(action.files.count == 1) + let fileAction = try #require(action.files.first) + #expect(fileAction.codeSignOnCopy == true) + #expect(fileAction.path.basename == "MyLibrary.dylib") } - @Test func testMapCoreDataModels() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj + @Test("Maps CoreData models from version groups within resources phase") + func testMapCoreDataModels() async throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj - // Create a core data model version group let versionChildRef = PBXFileReference.mock( - name: "Model.xcdatamodel", path: "Model.xcdatamodel", pbxProj: pbxProj + name: "Model.xcdatamodel", + path: "Model.xcdatamodel", + pbxProj: pbxProj ) - let versionGroup = XCVersionGroup.mock( currentVersion: versionChildRef, children: [versionChildRef], @@ -320,129 +250,93 @@ struct BuildPhaseMapperTests { let target = PBXNativeTarget.mock( name: "App", - buildConfigurationList: nil, - buildRules: [], buildPhases: [resourcesPhase], - dependencies: [], productType: .application, pbxProj: pbxProj ) + try provider.addTargets([target]) - if let project = pbxProj.projects.first { - project.targets.append(target) - } - - let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let mapper = BuildPhaseMapper(projectProvider: provider) let models = try await mapper.mapCoreDataModels(target: target) + #expect(models.count == 1) - let model = models.first - try #require(model != nil) - #expect(model?.path.basename == "Model.xcdatamodeld") - #expect(model?.versions.count == 1) - #expect(model?.currentVersion.contains("Model.xcdatamodel") == true) + let model = try #require(models.first) + #expect(model.path.basename == "Model.xcdatamodeld") + #expect(model.versions.count == 1) + #expect(model.currentVersion.contains("Model.xcdatamodel") == true) } - @Test func testMapRawScriptBuildPhases() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - let frameworksPhase = PBXShellScriptBuildPhase.mock(name: "Test Script", pbxProj: pbxProj) + @Test("Maps raw script build phases not covered by other categories") + func testMapRawScriptBuildPhases() async throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj + let scriptPhase = PBXShellScriptBuildPhase.mock(name: "Test Script", pbxProj: pbxProj) let target = PBXNativeTarget.mock( name: "App", - buildConfigurationList: nil, - buildRules: [], - buildPhases: [frameworksPhase], - dependencies: [], + buildPhases: [scriptPhase], productType: .application, pbxProj: pbxProj ) + try provider.addTargets([target]) - if let project = pbxProj.projects.first { - project.targets.append(target) - } - - let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let mapper = BuildPhaseMapper(projectProvider: provider) let rawPhases = try await mapper.mapRawScriptBuildPhases(target: target) + #expect(rawPhases.count == 1) - let rawPhase = rawPhases.first - try #require(rawPhase != nil) - #expect(rawPhase?.name == "Test Script") + let rawPhase = try #require(rawPhases.first) + #expect(rawPhase.name == "Test Script") } - @Test func testMapAdditionalFiles() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj + @Test("Identifies additional files not included in any build phase") + func testMapAdditionalFiles() async throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj - // Add files to main group that are not referenced by any build phase - if let project = pbxProj.projects.first, - let mainGroup = project.mainGroup - { + // Add two extra files at the root of the main group + if let project = pbxProj.projects.first, let mainGroup = project.mainGroup { let fileRef1 = PBXFileReference.mock(name: "Extra1.txt", path: "Extra1.txt", pbxProj: pbxProj) - let fileRef2 = PBXFileReference.mock( - name: "Extra2.json", path: "Extra2.json", pbxProj: pbxProj - ) - mainGroup.children.append(fileRef1) - mainGroup.children.append(fileRef2) + let fileRef2 = PBXFileReference.mock(name: "Extra2.json", path: "Extra2.json", pbxProj: pbxProj) + mainGroup.children.append(contentsOf: [fileRef1, fileRef2]) } - // Create a target that doesn't reference these files in build phases let target = PBXNativeTarget.mock( name: "App", - buildConfigurationList: nil, - buildRules: [], buildPhases: [], - dependencies: [], productType: .application, pbxProj: pbxProj ) + try provider.addTargets([target]) - if let project = pbxProj.projects.first { - project.targets.append(target) - } - - let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let mapper = BuildPhaseMapper(projectProvider: provider) let additionalFiles = try await mapper.mapAdditionalFiles(target: target) + #expect(additionalFiles.count == 2) let names = additionalFiles.map(\.path.basename) #expect(names.contains("Extra1.txt") == true) #expect(names.contains("Extra2.json") == true) } - @Test func testMapSourceFile_missingFileRef() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj + @Test("Handles source files without file references gracefully") + func testMapSourceFile_missingFileRef() async throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj - // Create a build file with no file reference + // Build file without a file ref let buildFile = PBXBuildFile() - // E.g. don't set `file` property, or fileRef is nil by default in your mock initializer. - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - _ = try await mapper.mapSources( - target: PBXNativeTarget.mock(buildPhases: [], pbxProj: pbxProj) - ) - // Since no sources phase or buildFile with a fileRef is provided, add one manually: - // Actually, let's simulate calling mapSourceFile directly if possible: - // If it's private, we can create a scenario where mapSources includes that buildFile. - // Create a sources phase to include this buildFile let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) let target = PBXNativeTarget.mock(buildPhases: [sourcesPhase], pbxProj: pbxProj) + try provider.addTargets([target]) + let mapper = BuildPhaseMapper(projectProvider: provider) let sources = try await mapper.mapSources(target: target) - // Expect no crash and empty array since fileRef is nil - #expect(sources.isEmpty == true) + #expect(sources.isEmpty == true) // Gracefully handled } - @Test func testMapSourceFile_unresolvableFullPath() async throws { + @Test("Gracefully handles non-existent file paths for source files") + func testMapSourceFile_unresolvableFullPath() async throws { + // Special case: use a provider with invalid sourceDirectory to simulate missing files let mockProvider = MockProjectProvider( sourceDirectory: "/invalid/Path", projectName: "TestProject" @@ -452,7 +346,6 @@ struct BuildPhaseMapperTests { let fileRef = PBXFileReference( name: "NonExistent.swift", path: "NonExistent.swift" - // This path won't exist relative to /invalid/Path ) let buildFile = PBXBuildFile.mock(file: fileRef, pbxProj: pbxProj) let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) @@ -460,82 +353,62 @@ struct BuildPhaseMapperTests { let mapper = BuildPhaseMapper(projectProvider: mockProvider) let sources = try await mapper.mapSources(target: target) - // Expect empty because fullPath could not be resolved #expect(sources.isEmpty == true) } - // @Test func testMapVariantGroup() async throws { -// let mockProvider = MockProjectProvider( -// sourceDirectory: "/tmp/TestProject", -// projectName: "TestProject" -// ) -// let pbxProj = mockProvider.xcodeProj.pbxproj -// -// // Create file references for localized resources, but don't auto-add them to main group -// let fileRef1 = PBXFileReference.mock( -// name: "Localizable.strings", -// path: "en.lproj/Localizable.strings", -// pbxProj: pbxProj, -// addToMainGroup: false -// ) -// let fileRef2 = PBXFileReference.mock( -// name: "Localizable.strings", -// path: "fr.lproj/Localizable.strings", -// pbxProj: pbxProj, -// addToMainGroup: false -// ) -// -// // Create variant group without auto-adding it to the main group -// let variantGroup = PBXVariantGroup.mockVariant( -// children: [fileRef1, fileRef2], -// pbxProj: pbxProj, -// addToMainGroup: false -// ) -// -// // Manually add the variant group to the main group for proper path resolution -// if let project = pbxProj.projects.first, let mainGroup = project.mainGroup { -// mainGroup.children.append(variantGroup) -// } -// -// let buildFile = PBXBuildFile.mock(file: variantGroup, pbxProj: pbxProj) -// let resourcesPhase = PBXResourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) -// let target = PBXNativeTarget.mock( -// buildPhases: [resourcesPhase], -// pbxProj: pbxProj -// ) -// -// let mapper = BuildPhaseMapper(projectProvider: mockProvider) -// let resources = try await mapper.mapResources(target: target) -// -// #expect(resources.count == 2) -// #expect(resources.first?.path.basename == "Localizable.strings") - // } - - @Test func testCollectFiles_withNestedGroups() async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj + @Test("Maps localized variant groups from resources") + func testMapVariantGroup() async throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj - // Create file references at various levels let fileRef1 = PBXFileReference.mock( - name: "RootFile.txt", path: "RootFile.txt", pbxProj: pbxProj, addToMainGroup: false + name: "Localizable.strings", + path: "en.lproj/Localizable.strings", + pbxProj: pbxProj, + addToMainGroup: false ) - - let subfileRef = PBXFileReference.mock( - name: "Subfile.txt", - path: "Subfile.txt", + let fileRef2 = PBXFileReference.mock( + name: "Localizable.strings", + path: "fr.lproj/Localizable.strings", pbxProj: pbxProj, addToMainGroup: false ) - let subgroup = PBXGroup.mock( - children: [subfileRef], name: "Subgroup", path: "Subgroup", pbxProj: pbxProj + let variantGroup = PBXVariantGroup.mockVariant( + children: [fileRef1, fileRef2], + pbxProj: pbxProj, + addToMainGroup: false ) - // Variant group inside subgroup + // Add variant group to main group for correct path resolution + if let project = pbxProj.projects.first, let mainGroup = project.mainGroup { + mainGroup.children.append(variantGroup) + } + + let buildFile = PBXBuildFile.mock(file: variantGroup, pbxProj: pbxProj) + let resourcesPhase = PBXResourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) + let target = PBXNativeTarget.mock(buildPhases: [resourcesPhase], pbxProj: pbxProj) + try provider.addTargets([target]) + + let mapper = BuildPhaseMapper(projectProvider: provider) + let resources = try await mapper.mapResources(target: target) + + #expect(resources.count == 2) + #expect(resources.first?.path.basename == "Localizable.strings") + } + + @Test("Recursively collects files from nested groups and variant groups") + func testCollectFiles_withNestedGroups() async throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj + + let fileRef1 = PBXFileReference.mock(name: "RootFile.txt", path: "RootFile.txt", pbxProj: pbxProj, addToMainGroup: false) + let subfileRef = PBXFileReference.mock(name: "Subfile.txt", path: "Subfile.txt", pbxProj: pbxProj, addToMainGroup: false) + let subgroup = PBXGroup.mock(children: [subfileRef], name: "Subgroup", path: "Subgroup", pbxProj: pbxProj) + let vfileRef = PBXFileReference.mock( - name: "VariantFile.strings", path: "en.lproj/VariantFile.strings", pbxProj: pbxProj, + name: "VariantFile.strings", + path: "en.lproj/VariantFile.strings", + pbxProj: pbxProj, addToMainGroup: false ) let variantGroup = PBXVariantGroup.mock(children: [vfileRef], pbxProj: pbxProj) @@ -548,44 +421,36 @@ struct BuildPhaseMapperTests { mainGroup.children.append(subgroup) } - let mapper = BuildPhaseMapper(projectProvider: mockProvider) - let target = PBXNativeTarget.mock(buildPhases: [], pbxProj: pbxProj) - if let project = pbxProj.projects.first { - project.targets.append(target) - } + try provider.addTargets([target]) + let mapper = BuildPhaseMapper(projectProvider: provider) let additionalFiles = try await mapper.mapAdditionalFiles(target: target) - // Expect 3 files: RootFile.txt, Subfile.txt, VariantFile.strings + #expect(additionalFiles.count == 3) - let names = additionalFiles.map(\.path.basename) - #expect(names.sorted() == ["RootFile.txt", "Subfile.txt", "VariantFile.strings"].sorted()) + let names = additionalFiles.map(\.path.basename).sorted() + #expect(names == ["RootFile.txt", "Subfile.txt", "VariantFile.strings"].sorted()) } - /// Validates all workspace fixtures. - @Test(arguments: [FileCodeGen.public, .private, .project, .disabled]) + @Test( + "Correctly identifies code generation attributes for source files", + arguments: [FileCodeGen.public, .private, .project, .disabled] + ) func testCodeGenAttributes(_ fileCodeGen: FileCodeGen) async throws { - let mockProvider = MockProjectProvider( - sourceDirectory: "/tmp/TestProject", - projectName: "TestProject" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj let fileRef = PBXFileReference.mock(name: "File.swift", path: "File.swift", pbxProj: pbxProj) - let buildFile = PBXBuildFile.mock( - file: fileRef, settings: ["ATTRIBUTES": [fileCodeGen.rawValue]], pbxProj: pbxProj - ) + let buildFile = PBXBuildFile.mock(file: fileRef, settings: ["ATTRIBUTES": [fileCodeGen.rawValue]], pbxProj: pbxProj) let sourcesPhase = PBXSourcesBuildPhase.mock(files: [buildFile], pbxProj: pbxProj) let target = PBXNativeTarget.mock(buildPhases: [sourcesPhase], pbxProj: pbxProj) - if let project = pbxProj.projects.first { - project.targets.append(target) - } + try provider.addTargets([target]) - let mapper = BuildPhaseMapper(projectProvider: mockProvider) + let mapper = BuildPhaseMapper(projectProvider: provider) let sources = try await mapper.mapSources(target: target) + #expect(sources.count == 1) - let sourceFile = sources.first - try #require(sourceFile != nil) - #expect(sourceFile?.codeGen == fileCodeGen) + let sourceFile = try #require(sources.first) + #expect(sourceFile.codeGen == fileCodeGen) } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift index ea9d2bc8..a6b1fd56 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift @@ -3,16 +3,17 @@ import XcodeGraph import XcodeProj @testable import TestSupport -@testable import XcodeProjToGraph // Adjust to access BuildRuleMapper, BuildRule, etc. +@testable import XcodeProjToGraph +@Suite struct BuildRuleMapperTests { let mapper = BuildRuleMapper() - @Test func testMapBuildRulesWithKnownCompilerSpecAndFileType() async throws { - // Using a known compiler spec from the enum, e.g. .appleClang + @Test("Maps build rules with known compiler spec and file type successfully") + func testMapBuildRulesWithKnownCompilerSpecAndFileType() async throws { + let projectProvider = MockProjectProvider() let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue let knownFileType = BuildRule.FileType.cSource.rawValue - let projectProvider = MockProjectProvider() let buildRule = PBXBuildRule.mock( compilerSpec: knownCompilerSpec, @@ -27,24 +28,28 @@ struct BuildRuleMapperTests { pbxProj: projectProvider.pbxProj ) - let target = PBXNativeTarget.mock(buildRules: [buildRule], pbxProj: projectProvider.pbxProj) + let target = PBXNativeTarget.mock( + buildRules: [buildRule], + pbxProj: projectProvider.pbxProj + ) + let rules = try await mapper.mapBuildRules(target: target) #expect(rules.count == 1) - let rule = rules.first - try #require(rule != nil) - #expect(rule?.compilerSpec.rawValue == knownCompilerSpec) - #expect(rule?.fileType.rawValue == knownFileType) - #expect(rule?.filePatterns == "*.c") - #expect(rule?.name == "C Rule") - #expect(rule?.outputFiles == ["$(DERIVED_FILE_DIR)/output.c.o"]) - #expect(rule?.inputFiles == ["$(SRCROOT)/main.c"]) - #expect(rule?.outputFilesCompilerFlags == ["-O2"]) - #expect(rule?.script == "echo Building C sources") - #expect(rule?.runOncePerArchitecture == false) + let rule = try #require(rules.first) + #expect(rule.compilerSpec.rawValue == knownCompilerSpec) + #expect(rule.fileType.rawValue == knownFileType) + #expect(rule.filePatterns == "*.c") + #expect(rule.name == "C Rule") + #expect(rule.outputFiles == ["$(DERIVED_FILE_DIR)/output.c.o"]) + #expect(rule.inputFiles == ["$(SRCROOT)/main.c"]) + #expect(rule.outputFilesCompilerFlags == ["-O2"]) + #expect(rule.script == "echo Building C sources") + #expect(rule.runOncePerArchitecture == false) } - @Test func testMapBuildRulesWithUnknownCompilerSpec() async throws { + @Test("Skips build rules when compiler spec is unknown") + func testMapBuildRulesWithUnknownCompilerSpec() async throws { let projectProvider = MockProjectProvider() let unknownCompilerSpec = "com.apple.compilers.unknown" let knownFileType = "sourcecode.c.c" @@ -61,11 +66,12 @@ struct BuildRuleMapperTests { ) let rules = try await mapper.mapBuildRules(target: target) - // Unknown compiler spec means the rule should be skipped - #expect(rules.count == 0) + // Unknown compiler spec -> rule is skipped + #expect(rules.isEmpty == true) } - @Test func testMapBuildRulesWithUnknownFileType() async throws { + @Test("Skips build rules when file type is unknown") + func testMapBuildRulesWithUnknownFileType() async throws { let projectProvider = MockProjectProvider() let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue let unknownFileType = "sourcecode.unknown" @@ -82,11 +88,12 @@ struct BuildRuleMapperTests { ) let rules = try await mapper.mapBuildRules(target: target) - // Unknown file type means the rule should be skipped - #expect(rules.count == 0) + // Unknown file type -> rule is skipped + #expect(rules.isEmpty == true) } - @Test func testMapBuildRulesWithMixedValidAndInvalid() async throws { + @Test("Includes only valid build rules when mixed with invalid ones") + func testMapBuildRulesWithMixedValidAndInvalid() async throws { let projectProvider = MockProjectProvider() let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue let knownFileType = BuildRule.FileType.cSource.rawValue diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift index 0f190395..ab5828a3 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift @@ -6,6 +6,7 @@ import XcodeProj @testable import TestSupport @testable import XcodeProjToGraph +@Suite struct DependencyMapperTests { let mockProvider = MockProjectProvider() let mapper: DependencyMapping @@ -14,7 +15,8 @@ struct DependencyMapperTests { mapper = DependencyMapper(projectProvider: mockProvider) } - @Test func testDirectTargetMapping() async throws { + @Test("Maps direct target dependencies correctly") + func testDirectTargetMapping() async throws { let pbxProj = mockProvider.xcodeProj.pbxproj let dep = PBXTargetDependency.mockTargetDependency( name: "DirectTarget", @@ -32,7 +34,8 @@ struct DependencyMapperTests { #expect(mapped.first == .target(name: "DirectTarget", status: .required, condition: nil)) } - @Test func testPackageProductMapping() async throws { + @Test("Maps package product dependencies to runtime package targets") + func testPackageProductMapping() async throws { let pbxProj = mockProvider.xcodeProj.pbxproj let dep = PBXTargetDependency.mockPackageProductDependency( productName: "MyPackageProduct", @@ -50,10 +53,10 @@ struct DependencyMapperTests { #expect(mapped.first == .package(product: "MyPackageProduct", type: .runtime, condition: nil)) } - @Test func testProxyNativeTarget() async throws { + @Test("Maps native target proxies referencing targets in the same project") + func testProxyNativeTarget() async throws { let pbxProj = mockProvider.xcodeProj.pbxproj - // Native target proxy referencing a target in the same project - let project = pbxProj.projects.first! + let project = try #require(pbxProj.projects.first) let dep = PBXTargetDependency.mockProxyDependency( remoteInfo: "NativeTarget", proxyType: .nativeTarget, @@ -72,7 +75,8 @@ struct DependencyMapperTests { #expect(mapped.first == .target(name: "NativeTarget", status: .required, condition: nil)) } - @Test func testProxyProjectReference() async throws { + @Test("Maps proxy dependencies to projects referenced by file references") + func testProxyProjectReference() async throws { let pbxProj = mockProvider.xcodeProj.pbxproj let fileRef = PBXFileReference.mock( path: "OtherProject.xcodeproj", @@ -94,17 +98,15 @@ struct DependencyMapperTests { let mapped = try await mapper.mapDependencies(target: target) #expect(mapped.count == 1) - let result = mapped.first! + let result = try #require(mapped.first) let expectedPath = try AbsolutePath.resolvePath( mockProvider.sourceDirectory.pathString + "OtherProject.xcodeproj" ) - #expect( - result - == .project(target: "OtherTarget", path: expectedPath, status: .required, condition: nil) - ) + #expect(result == .project(target: "OtherTarget", path: expectedPath, status: .required, condition: nil)) } - @Test func testProxyReferenceProxyLibrary() async throws { + @Test("Maps reference proxies to libraries when file type is a dylib") + func testProxyReferenceProxyLibrary() async throws { let pbxProj = mockProvider.xcodeProj.pbxproj let referenceProxy = PBXReferenceProxy( fileType: "compiled.mach-o.dylib", @@ -131,18 +133,18 @@ struct DependencyMapperTests { let mapped = try await mapper.mapDependencies(target: target) #expect(mapped.count == 1) - let result: TargetDependency = mapped.first! + let result = try #require(mapped.first) let expectedPath = mockProvider.sourceDirectory.appending(component: "libTest.dylib") let publicHeaders = try AbsolutePath(validating: "/tmp") #expect( - result - == TargetDependency.library( - path: expectedPath, publicHeaders: publicHeaders, swiftModuleMap: nil, condition: nil - ) + result == .library( + path: expectedPath, publicHeaders: publicHeaders, swiftModuleMap: nil, condition: nil + ) ) } - @Test func testProxyReferenceFileFramework() async throws { + @Test("Maps framework references correctly when encountered as proxy references") + func testProxyReferenceFileFramework() async throws { let pbxProj = mockProvider.xcodeProj.pbxproj let fileRef = PBXFileReference.mock( path: "MyLib.framework", @@ -166,14 +168,13 @@ struct DependencyMapperTests { let mapped = try await mapper.mapDependencies(target: target) #expect(mapped.count == 1) - let result = mapped.first! + let result = try #require(mapped.first) let expectedPath = mockProvider.sourceDirectory.appending(component: "MyLib.framework") - #expect( - result == TargetDependency.framework(path: expectedPath, status: .required, condition: nil) - ) + #expect(result == .framework(path: expectedPath, status: .required, condition: nil)) } - @Test func testPlatformConditions() async throws { + @Test("Maps dependencies with platform filters to conditions") + func testPlatformConditions() async throws { let pbxProj = mockProvider.xcodeProj.pbxproj let dep = PBXTargetDependency.mockTargetDependency( name: "ConditionalTarget", @@ -189,12 +190,13 @@ struct DependencyMapperTests { let mapped = try await mapper.mapDependencies(target: target) #expect(mapped.count == 1) - let result = mapped.first! + let result = try #require(mapped.first) let condition = PlatformCondition.when([.ios, .macos]) #expect(result == .target(name: "ConditionalTarget", status: .required, condition: condition)) } - @Test func testNoMatches() async throws { + @Test("Ignores dependencies that cannot be matched to targets, products, or proxies") + func testNoMatches() async throws { let pbxProj = mockProvider.xcodeProj.pbxproj // A dependency with no target, no product, no proxy - unhandled let dep = PBXTargetDependency.mock(name: nil, pbxProj: pbxProj) @@ -206,24 +208,24 @@ struct DependencyMapperTests { ) let mapped = try await mapper.mapDependencies(target: target) - #expect(mapped.count == 0) + #expect(mapped.isEmpty == true) } - @Test func testFileDependencyMapper() async throws { - // Test a known path extension scenario + @Test("Maps known file dependencies (like static libraries) correctly") + func testFileDependencyMapper() async throws { let fdm = FileDependencyMapper(projectProvider: mockProvider) let dependency = try await fdm.mapDependency(pathString: "libStatic.a", condition: nil) let expectedPath = mockProvider.sourceDirectory.appending(component: "libStatic.a") let publicHeaders = try AbsolutePath(validating: "/tmp") #expect( - dependency - == TargetDependency.library( - path: expectedPath, publicHeaders: publicHeaders, swiftModuleMap: nil, condition: nil - ) + dependency == .library( + path: expectedPath, publicHeaders: publicHeaders, swiftModuleMap: nil, condition: nil + ) ) } - @Test func testSinglePlatformFilter() async throws { + @Test("Maps single-platform filter dependencies correctly") + func testSinglePlatformFilter() async throws { let pbxProj = mockProvider.xcodeProj.pbxproj let dep = PBXTargetDependency.mockTargetDependency( name: "SinglePlatform", @@ -244,7 +246,8 @@ struct DependencyMapperTests { ) } - @Test func testInvalidPlatformFilter() async throws { + @Test("Ignores invalid platform filters and maps dependency without conditions") + func testInvalidPlatformFilter() async throws { let pbxProj = mockProvider.xcodeProj.pbxproj let dep = PBXTargetDependency.mockTargetDependency( name: "UnknownPlatform", diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift index d376164b..5bed6ffe 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift @@ -6,6 +6,7 @@ import XcodeProj @testable import TestSupport @testable import XcodeProjToGraph +@Suite struct TargetDependencyExtensionsTests { let sourceDirectory = try! AbsolutePath.resolvePath("/tmp/TestProject") @@ -21,7 +22,8 @@ struct TargetDependencyExtensionsTests { ), ] - @Test func testTargetGraphDependency_Target() async throws { + @Test("Resolves a target dependency into a target graph dependency") + func testTargetGraphDependency_Target() async throws { let dependency = TargetDependency.target(name: "App", status: .required, condition: nil) let graphDep = try await dependency.graphDependency( sourceDirectory: sourceDirectory, @@ -30,7 +32,8 @@ struct TargetDependencyExtensionsTests { #expect(graphDep == .target(name: "App", path: sourceDirectory, status: .required)) } - @Test func testTargetGraphDependencyFramework_Project() async throws { + @Test("Resolves a project-based framework dependency to a dynamic framework in the graph") + func testTargetGraphDependencyFramework_Project() async throws { let dependency = TargetDependency.project( target: "MyProjectTarget", path: sourceDirectory, @@ -52,11 +55,12 @@ struct TargetDependencyExtensionsTests { default: return false } - })() != false + })() == true ) } - @Test func testTargetGraphDependencyLibrary_Project() async throws { + @Test("Resolves a project-based dynamic library dependency correctly") + func testTargetGraphDependencyLibrary_Project() async throws { let dependency = TargetDependency.project( target: "MyProjectDynamicLibrary", path: sourceDirectory, @@ -76,11 +80,12 @@ struct TargetDependencyExtensionsTests { ) #expect(linking == .dynamic) default: - Issue.record() + Issue.record("Expected a library graph dependency.") } } - @Test func testTargetGraphDependency_Framework() async throws { + @Test("Resolves a framework file dependency into a dynamic framework graph dependency") + func testTargetGraphDependency_Framework() async throws { let frameworkPath = sourceDirectory.appending(component: "MyFramework.framework") let dependency = TargetDependency.framework( path: frameworkPath, status: .required, condition: nil @@ -100,11 +105,12 @@ struct TargetDependencyExtensionsTests { default: return false } - })() != false + })() == true ) } - @Test func testTargetGraphDependency_XCFramework() async throws { + @Test("Resolves an XCFramework dependency to the correct .xcframework graph dependency") + func testTargetGraphDependency_XCFramework() async throws { let xcframeworkPath = sourceDirectory.appending(component: "MyXCFramework.xcframework") let dependency = TargetDependency.xcframework( path: xcframeworkPath, status: .required, condition: nil @@ -123,11 +129,12 @@ struct TargetDependencyExtensionsTests { default: return false } - })() != false + })() == true ) } - @Test func testTargetGraphDependency_Library() async throws { + @Test("Resolves a static library dependency to a static library graph dependency") + func testTargetGraphDependency_Library() async throws { let libPath = sourceDirectory.appending(component: "libMyLib.a") let headersPath = sourceDirectory.appending(component: "include") let dependency = TargetDependency.library( @@ -150,11 +157,12 @@ struct TargetDependencyExtensionsTests { default: return false } - })() != false + })() == true ) } - @Test func testTargetGraphDependency_Package() async throws { + @Test("Resolves a package product dependency to a package product graph dependency") + func testTargetGraphDependency_Package() async throws { let dependency = TargetDependency.package( product: "MyPackageProduct", type: .runtime, condition: nil ) @@ -169,7 +177,8 @@ struct TargetDependencyExtensionsTests { ) } - @Test func testTargetGraphDependency_SDK() async throws { + @Test("Resolves an SDK dependency to the correct SDK graph dependency") + func testTargetGraphDependency_SDK() async throws { let dependency = TargetDependency.sdk(name: "MySDK", status: .optional, condition: nil) let graphDep = try await dependency.graphDependency( sourceDirectory: sourceDirectory, @@ -185,11 +194,12 @@ struct TargetDependencyExtensionsTests { default: return false } - })() != false + })() == true ) } - @Test func testTargetGraphDependency_XCTest() async throws { + @Test("Resolves an XCTest dependency to an XCFramework graph dependency") + func testTargetGraphDependency_XCTest() async throws { let dependency = TargetDependency.xctest let graphDep = try await dependency.graphDependency( sourceDirectory: sourceDirectory, @@ -205,11 +215,12 @@ struct TargetDependencyExtensionsTests { default: return false } - })() != false + })() == true ) } - @Test func testMapProjectGraphDependency_TargetNotFound() async throws { + @Test("Throws a MappingError when a project target does not exist in allTargetsMap") + func testMapProjectGraphDependency_TargetNotFound() async throws { let dependency = TargetDependency.project( target: "NonExistentTarget", path: sourceDirectory, diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift index 9069d6d6..d9992dde 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift @@ -6,9 +6,10 @@ import XcodeProj @testable import TestSupport @testable import XcodeProjToGraph +@Suite struct GraphMapperTests { - @Test func testSingleProjectGraph() async throws { - // Setup a mock provider and a single project scenario + @Test("Maps a single project into a workspace graph") + func testSingleProjectGraph() async throws { let mockProvider = MockProjectProvider( sourceDirectory: "/tmp/SingleProject", projectName: "SingleProject" @@ -25,33 +26,33 @@ struct GraphMapperTests { project.targets.append(target) } - // GraphType for a single project + // Create a GraphType for a single project let projectPath = try AbsolutePath(validating: mockProvider.sourceDirectory.pathString) let graphType = GraphType.project(projectPath) - // Provide a closure that returns the mock provider + // Mapper returns the mock provider for the given path let mapper = GraphMapper(graphType: graphType) { path in - // We only handle this single path scenario #expect(path == projectPath) return mockProvider } let graph = try await mapper.xcodeGraph() - // Validate that the returned graph matches our expectations + // Validate the graph #expect(graph.name == "Workspace") #expect(graph.projects.count == 1) - #expect(graph.packages == [:]) - #expect(graph.dependencies == [:]) - #expect(graph.dependencyConditions == [:]) + #expect(graph.packages.isEmpty == true) + #expect(graph.dependencies.isEmpty == true) + #expect(graph.dependencyConditions.isEmpty == true) - // Check that the workspace is created as a wrapper around the single project + // Workspace should wrap the single project #expect(graph.workspace.projects.count == 1) #expect(graph.workspace.projects.first == projectPath) #expect(graph.workspace.name == "Workspace") } - @Test func testWorkspaceGraphMultipleProjects() async throws { + @Test("Maps a workspace with multiple projects into a single graph") + func testWorkspaceGraphMultipleProjects() async throws { // Setup two mock projects let mockProviderA = MockProjectProvider( sourceDirectory: "/tmp/Workspace/ProjectA", @@ -84,7 +85,7 @@ struct GraphMapperTests { projectB.targets.append(targetB) } - // Setup a workspace that references these two projects + // Set up a workspace referencing the two projects let workspacePath = try AbsolutePath(validating: "/tmp/Workspace") let projectAPath = try AbsolutePath(validating: "/tmp/Workspace/ProjectA.xcodeproj") let projectBPath = try AbsolutePath(validating: "/tmp/Workspace/ProjectB.xcodeproj") @@ -93,15 +94,13 @@ struct GraphMapperTests { data: XCWorkspaceData(children: [ .file(.init(location: .absolute(projectAPath.pathString))), .file(.init(location: .absolute(projectBPath.pathString))), - ]) ) let provider = MockWorkspaceProvider(xcWorkspacePath: workspacePath, xcworkspace: xcworkspace) - let graphType = GraphType.workspace(provider) - // Provide a closure that returns the corresponding mock provider based on the project path + // Mapper picks the correct provider based on path let mapper = GraphMapper(graphType: graphType) { path in if path == projectAPath { return mockProviderA @@ -109,7 +108,7 @@ struct GraphMapperTests { return mockProviderB } else { Issue.record("Unexpected project path requested: \(path)") - throw MappingError.noProjectsFound + throw MappingError.noProjectsFound(path: path.pathString) } } @@ -120,25 +119,22 @@ struct GraphMapperTests { #expect(graph.workspace.projects.contains(projectAPath) == true) #expect(graph.workspace.projects.contains(projectBPath) == true) - // Check projects in the graph + // Check that both projects appear in the graph #expect(graph.projects.count == 2) - let projectA = graph.projects[projectAPath] - let projectB = graph.projects[projectBPath] - try #require(projectA != nil) - try #require(projectB != nil) - #expect(projectA?.targets["ATarget"] != nil) - #expect(projectB?.targets["BTarget"] != nil) - - // Since we didn’t add packages or dependencies, these should be empty + let projectA = try #require(graph.projects[projectAPath]) + let projectB = try #require(graph.projects[projectBPath]) + #expect(projectA.targets["ATarget"] != nil) + #expect(projectB.targets["BTarget"] != nil) + + // No packages or dependencies were added #expect(graph.packages.isEmpty == true) #expect(graph.dependencies.isEmpty == true) #expect(graph.dependencyConditions.isEmpty == true) } - @Test func testGraphWithDependencies() async throws { - // Example test to confirm dependency mapping works + @Test("Maps a project graph with dependencies between targets") + func testGraphWithDependencies() async throws { // Setup a single project with two targets: App depends on AFramework - let mockProvider = MockProjectProvider( sourceDirectory: "/tmp/ProjectWithDeps", projectName: "ProjectWithDeps" @@ -157,7 +153,7 @@ struct GraphMapperTests { pbxProj: pbxProj ) - // Add a target dependency from App to AFramework + // App -> AFramework dependency let dep = PBXTargetDependency.mockTargetDependency( name: "AFramework", pbxProj: pbxProj @@ -178,7 +174,7 @@ struct GraphMapperTests { let graph = try await mapper.xcodeGraph() - // Check that dependencies are mapped + // Verify dependencies are mapped let sourceDep = GraphDependency.target(name: "App", path: mockProvider.sourceDirectory) let targetDep = GraphDependency.target(name: "AFramework", path: mockProvider.sourceDirectory) #expect(graph.dependencies == [sourceDep: [targetDep]]) diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift index 4c46b9c7..a92e572a 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift @@ -6,6 +6,7 @@ import XcodeProj @testable import TestSupport @testable import XcodeProjToGraph +@Suite struct PackageMapperTests { let mapper: PackageMapper let projectProvider: MockProjectProvider @@ -16,7 +17,8 @@ struct PackageMapperTests { mapper = PackageMapper(projectProvider: provider) } - @Test func testMapPackageWithValidURL() async throws { + @Test("Maps a remote package with a valid URL and up-to-next-major requirement") + func testMapPackageWithValidURL() async throws { let package = XCRemoteSwiftPackageReference.mock( repositoryURL: "https://github.com/example/package.git", versionRequirement: .upToNextMajorVersion("1.0.0") @@ -24,14 +26,14 @@ struct PackageMapperTests { let result = try await mapper.map(package: package) #expect( - result - == .remote( - url: "https://github.com/example/package.git", requirement: .upToNextMajor("1.0.0") - ) + result == .remote( + url: "https://github.com/example/package.git", requirement: .upToNextMajor("1.0.0") + ) ) } - @Test func testMapRequirementUpToNextMajor() async throws { + @Test("Maps an up-to-next-major version requirement correctly") + func testMapRequirementUpToNextMajor() async throws { let package = XCRemoteSwiftPackageReference.mock( repositoryURL: "https://github.com/example/package.git", versionRequirement: .upToNextMajorVersion("1.0.0") @@ -41,7 +43,8 @@ struct PackageMapperTests { #expect(requirement == .upToNextMajor("1.0.0")) } - @Test func testMapRequirementUpToNextMinor() async throws { + @Test("Maps an up-to-next-minor version requirement correctly") + func testMapRequirementUpToNextMinor() async throws { let package = XCRemoteSwiftPackageReference.mock( repositoryURL: "https://github.com/example/package.git", versionRequirement: .upToNextMinorVersion("1.2.0") @@ -51,7 +54,8 @@ struct PackageMapperTests { #expect(requirement == .upToNextMinor("1.2.0")) } - @Test func testMapRequirementExact() async throws { + @Test("Maps an exact version requirement correctly") + func testMapRequirementExact() async throws { let package = XCRemoteSwiftPackageReference.mock( repositoryURL: "https://github.com/example/package.git", versionRequirement: .exact("1.2.3") @@ -61,7 +65,8 @@ struct PackageMapperTests { #expect(requirement == .exact("1.2.3")) } - @Test func testMapRequirementRange() async throws { + @Test("Maps a range version requirement correctly") + func testMapRequirementRange() async throws { let package = XCRemoteSwiftPackageReference.mock( repositoryURL: "https://github.com/example/package.git", versionRequirement: .range(from: "1.0.0", to: "2.0.0") @@ -71,7 +76,8 @@ struct PackageMapperTests { #expect(requirement == .range(from: "1.0.0", to: "2.0.0")) } - @Test func testMapRequirementBranch() async throws { + @Test("Maps a branch-based version requirement correctly") + func testMapRequirementBranch() async throws { let package = XCRemoteSwiftPackageReference.mock( repositoryURL: "https://github.com/example/package.git", versionRequirement: .branch("main") @@ -81,7 +87,8 @@ struct PackageMapperTests { #expect(requirement == .branch("main")) } - @Test func testMapRequirementRevision() async throws { + @Test("Maps a revision-based version requirement correctly") + func testMapRequirementRevision() async throws { let package = XCRemoteSwiftPackageReference.mock( repositoryURL: "https://github.com/example/package.git", versionRequirement: .revision("abc123") @@ -91,7 +98,8 @@ struct PackageMapperTests { #expect(requirement == .revision("abc123")) } - @Test func testMapRequirementNoVersionRequirement() async throws { + @Test("Maps a missing version requirement to up-to-next-major(0.0.0)") + func testMapRequirementNoVersionRequirement() async throws { let package = XCRemoteSwiftPackageReference.mock( repositoryURL: "https://github.com/example/package.git", versionRequirement: nil @@ -101,36 +109,15 @@ struct PackageMapperTests { #expect(requirement == .upToNextMajor("0.0.0")) } - @Test func testMapLocalPackage() async throws { - // Arrange + @Test("Maps a local package reference correctly") + func testMapLocalPackage() async throws { let localPackage = XCLocalSwiftPackageReference.mock(relativePath: "Packages/Example") - // Act let result = try await mapper.map(package: localPackage) - // Assert let expectedPath = projectProvider.sourceDirectory.appending( try RelativePath(validating: "Packages/Example") ) #expect(result == .local(path: expectedPath)) } } - -// Extension to support testing -extension XCRemoteSwiftPackageReference { - static func mock( - repositoryURL: String, - versionRequirement: VersionRequirement? - ) -> XCRemoteSwiftPackageReference { - return XCRemoteSwiftPackageReference( - repositoryURL: repositoryURL, - versionRequirement: versionRequirement - ) - } -} - -extension XCLocalSwiftPackageReference { - static func mock(relativePath: String) -> XCLocalSwiftPackageReference { - return XCLocalSwiftPackageReference(relativePath: relativePath) - } -} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift index 293940cd..c07ccaa6 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift @@ -6,8 +6,10 @@ import XcodeProj @testable import TestSupport @testable import XcodeProjToGraph +@Suite struct ProjectMapperTests { - @Test func testMapBasicProject() async throws { + @Test("Maps a basic project with default attributes") + func testMapBasicProject() async throws { let mockProvider = MockProjectProvider() let mapper = ProjectMapper(projectProvider: mockProvider) @@ -20,7 +22,8 @@ struct ProjectMapperTests { #expect(project.type == .local) } - @Test func testMapProjectWithCustomAttributes() async throws { + @Test("Maps a project with custom attributes (org name, class prefix, upgrade check)") + func testMapProjectWithCustomAttributes() async throws { let pbxProj = PBXProj() let provider = MockProjectProvider( projectName: "CustomProject", @@ -45,9 +48,9 @@ struct ProjectMapperTests { #expect(project.lastUpgradeCheck == "1500") } - @Test func testMapProjectWithTargets() async throws { + @Test("Maps a project that contains targets") + func testMapProjectWithTargets() async throws { let mockProvider = MockProjectProvider() - let configList = XCConfigurationList.mock( configs: [("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"])], proj: mockProvider.pbxProj @@ -64,13 +67,14 @@ struct ProjectMapperTests { try mockProvider.pbxProject().targets.append(target) let project = try await mapper.mapProject() - print(project.targets) + #expect(project.targets.count == 1) #expect(project.targets.first?.value.name == "ExampleApp") #expect(project.targets.first?.value.product == .app) } - @Test func testMapProjectWithRemotePackages() async throws { + @Test("Maps a project with remote package dependencies") + func testMapProjectWithRemotePackages() async throws { let mockProvider = MockProjectProvider() let package = XCRemoteSwiftPackageReference( repositoryURL: "https://github.com/example/package.git", @@ -91,7 +95,8 @@ struct ProjectMapperTests { #expect(requirement == .upToNextMajor("1.0.0")) } - @Test func testMapProjectWithKnownRegions() async throws { + @Test("Maps a project with known regions") + func testMapProjectWithKnownRegions() async throws { let mockProvider = MockProjectProvider() try mockProvider.pbxProject().knownRegions = ["en", "es", "fr"] let mapper = ProjectMapper(projectProvider: mockProvider) @@ -104,7 +109,8 @@ struct ProjectMapperTests { #expect(project.defaultKnownRegions?.contains("fr") == true) } - @Test func testMapProjectWithDevelopmentRegion() async throws { + @Test("Maps a project with a custom development region") + func testMapProjectWithDevelopmentRegion() async throws { let mockProvider = MockProjectProvider() try mockProvider.pbxProject().developmentRegion = "fr" let mapper = ProjectMapper(projectProvider: mockProvider) @@ -114,7 +120,8 @@ struct ProjectMapperTests { #expect(project.developmentRegion == "fr") } - @Test func testMapProjectWithResourceSynthesizers() async throws { + @Test("Maps a project with default resource synthesizers") + func testMapProjectWithResourceSynthesizers() async throws { let mockProvider = MockProjectProvider() let mapper = ProjectMapper(projectProvider: mockProvider) @@ -143,7 +150,8 @@ struct ProjectMapperTests { #expect(actualParsers == expectedParsers) } - @Test func testMapProjectWithSchemes() async throws { + @Test("Maps a project with associated schemes") + func testMapProjectWithSchemes() async throws { let mockProvider = MockProjectProvider() let scheme = XCScheme.mock(name: "TestScheme") mockProvider.xcodeProj.sharedData = XCSharedData(schemes: [scheme]) diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift index ebd452fb..bf8f7724 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift @@ -6,29 +6,30 @@ import XcodeProj @testable import TestSupport @testable import XcodeProjToGraph +@Suite struct BuildSettingsTests { - /// Tests that a string value is correctly extracted from build settings. - @Test func testStringExtraction() async throws { + @Test("Extracts a string value from build settings") + func testStringExtraction() async throws { let settings: [String: Any] = ["COMPILER_FLAGS": "-ObjC"] let value = settings.string(for: .compilerFlags) try #require(value != nil) #expect(value == "-ObjC") } - /// Tests that a boolean value is correctly extracted, and invalid types return nil. - @Test func testBoolExtraction() { + @Test("Extracts a boolean value from build settings and returns nil for invalid types") + func testBoolExtraction() { let settings: [String: Any] = ["PRUNE": true] let boolValue = settings.bool(for: .prune) #expect(boolValue == true) - // Test invalid type + // Invalid type for boolean let invalidSettings: [String: Any] = ["PRUNE": "notABool"] let invalidBool = invalidSettings.bool(for: .prune) #expect(invalidBool == nil) } - /// Tests extracting a string array from build settings. - @Test func testStringArrayExtraction() async throws { + @Test("Extracts a string array from build settings") + func testStringArrayExtraction() async throws { let settings: [String: Any] = ["LAUNCH_ARGUMENTS": ["-enableFeature", "-verbose"]] let args = settings.stringArray(for: .launchArguments) try #require(args != nil) @@ -36,28 +37,27 @@ struct BuildSettingsTests { #expect(args?.contains("-verbose") == true) } - /// Tests extracting a dictionary of strings (for environment variables). - @Test func testStringDictExtraction() async throws { + @Test("Extracts a dictionary of strings (e.g., environment variables) from build settings") + func testStringDictExtraction() async throws { let settings: [String: Any] = ["ENVIRONMENT_VARIABLES": ["KEY": "VALUE"]] let envVars = settings.stringDict(for: .environmentVariables) try #require(envVars != nil) #expect(envVars?["KEY"] == "VALUE") } - /// Tests that missing keys return nil. - @Test func testMissingKeyReturnsNil() { + @Test("Returns nil when keys are missing in build settings") + func testMissingKeyReturnsNil() { let settings: [String: Any] = ["TAGS": "some,tags"] #expect(settings.string(for: .productBundleIdentifier) == nil) #expect(settings.bool(for: .mergeable) == nil) } - /// Tests that non-string array values are coerced to strings. - /// Example: If a setting is `[Any]` but some elements aren’t strings, they’re filtered out. - @Test func testCoerceAnyArrayToStringArray() async throws { + @Test("Coerces any array elements to strings, discarding non-string values") + func testCoerceAnyArrayToStringArray() async throws { let settings: [String: Any] = ["LAUNCH_ARGUMENTS": ["-flag", 42, true]] let args = settings.stringArray(for: .launchArguments) try #require(args != nil) - // Non-string elements (42, true) should be discarded, leaving only ["-flag"]. + // Non-string elements are discarded, leaving only ["-flag"] #expect(args == ["-flag"]) } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift index 758f84ea..2d87535d 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift @@ -3,26 +3,31 @@ import XcodeGraph @testable import XcodeProjToGraph +@Suite struct ConfigurationMatcherTests { - @Test func testVariantDetectionForDebug() async throws { + @Test("Detects 'Debug' variants from configuration names") + func testVariantDetectionForDebug() async throws { #expect(ConfigurationMatcher.variant(forName: "Debug") == .debug) #expect(ConfigurationMatcher.variant(forName: "development") == .debug) #expect(ConfigurationMatcher.variant(forName: "dev") == .debug) } - @Test func testVariantDetectionForRelease() async throws { + @Test("Detects 'Release' variants from configuration names") + func testVariantDetectionForRelease() async throws { #expect(ConfigurationMatcher.variant(forName: "Release") == .release) #expect(ConfigurationMatcher.variant(forName: "prod") == .release) #expect(ConfigurationMatcher.variant(forName: "production") == .release) } - @Test func testVariantFallbackToDebug() async throws { - // Names that don't match debug/release keywords should fall back to debug + @Test("Falls back to 'Debug' variant for unrecognized configuration names") + func testVariantFallbackToDebug() async throws { + // Names without debug/release keywords default to .debug #expect(ConfigurationMatcher.variant(forName: "Staging") == .debug) #expect(ConfigurationMatcher.variant(forName: "CustomConfig") == .debug) } - @Test func testValidateConfigurationName() async throws { + @Test("Validates configuration names based on allowed patterns") + func testValidateConfigurationName() async throws { #expect(ConfigurationMatcher.validateConfigurationName("Debug") == true) #expect(ConfigurationMatcher.validateConfigurationName("Release") == true) diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift index fe0f8200..b9d20622 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift @@ -3,28 +3,30 @@ import Testing import XcodeGraph import XcodeProj -@testable import TestSupport // For MockFactory usage +@testable import TestSupport @testable import XcodeProjToGraph +@Suite struct SettingsMapperTests { let mapper = SettingsMapper() - @Test func testNilConfigurationListReturnsDefault() async throws { + @Test("Returns default settings when configuration list is nil") + func testNilConfigurationListReturnsDefault() async throws { let mockProvider = MockProjectProvider() let settings = try await mapper.map(projectProvider: mockProvider, configurationList: nil) #expect(settings == Settings.default) } - @Test func testSingleConfigurationMapping() async throws { + @Test("Maps a single build configuration correctly") + func testSingleConfigurationMapping() async throws { let pbxProj = PBXProj() let configList = XCConfigurationList.mock( - configs: [("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.debug"])], proj: pbxProj + configs: [("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.debug"])], + proj: pbxProj ) let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) - let settings = try await mapper.map( - projectProvider: mockProvider, configurationList: configList - ) + let settings = try await mapper.map(projectProvider: mockProvider, configurationList: configList) #expect(settings.configurations.count == 1) let configKey = settings.configurations.keys.first @@ -32,17 +34,12 @@ struct SettingsMapperTests { #expect(configKey?.name == "Debug") #expect(configKey?.variant == .debug) - let debugConfig = settings.configurations[configKey!] - try #require(debugConfig != nil) - - // Now `debugConfig` is a `Configuration?`. - let actualDebugConfig = debugConfig! - try #require(actualDebugConfig != nil) - - #expect(actualDebugConfig!.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.debug") + let debugConfig = try #require(settings.configurations[configKey!]) + #expect(debugConfig?.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.debug") } - @Test func testMultipleConfigurations() async throws { + @Test("Maps multiple build configurations correctly") + func testMultipleConfigurations() async throws { let pbxProj = PBXProj() let configs: [(String, [String: Sendable])] = [ ("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.debug"]), @@ -51,33 +48,24 @@ struct SettingsMapperTests { let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) - let settings = try await mapper.map( - projectProvider: mockProvider, configurationList: configList - ) + let settings = try await mapper.map(projectProvider: mockProvider, configurationList: configList) #expect(settings.configurations.count == 2) - let debugKey = settings.configurations.keys.first { $0.name == "Debug" } - let releaseKey = settings.configurations.keys.first { $0.name == "Release" } + let debugKey = try #require(settings.configurations.keys.first { $0.name == "Debug" }) + let releaseKey = try #require(settings.configurations.keys.first { $0.name == "Release" }) - try #require(debugKey != nil) - try #require(releaseKey != nil) - #expect(debugKey?.variant == .debug) - #expect(releaseKey?.variant == .release) + #expect(debugKey.variant == .debug) + #expect(releaseKey.variant == .release) - let debugConfig = settings.configurations[debugKey!] - let releaseConfig = settings.configurations[releaseKey!] + let debugConfig = try #require(settings.configurations[debugKey]) + let releaseConfig = try #require(settings.configurations[releaseKey]) - try #require(debugConfig != nil) - try #require(releaseConfig != nil) - - let actualDebugConfig = debugConfig! - let actualReleaseConfig = releaseConfig! - - #expect(actualDebugConfig?.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.debug") - #expect(actualReleaseConfig?.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.release") + #expect(debugConfig?.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.debug") + #expect(releaseConfig?.settings["PRODUCT_BUNDLE_IDENTIFIER"] == "com.example.release") } - @Test func testCoercionOfNonStringValues() async throws { + @Test("Coerces non-string values to strings in build settings") + func testCoercionOfNonStringValues() async throws { let pbxProj = PBXProj() let configs: [(String, [String: Sendable])] = [ ("Debug", ["SOME_NUMBER": 42]), @@ -85,28 +73,22 @@ struct SettingsMapperTests { let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) let mockProvider = MockProjectProvider(configurationList: configList) - let settings = try await mapper.map( - projectProvider: mockProvider, configurationList: configList - ) - let debugKey = settings.configurations.keys.first { $0.name == "Debug" } - try #require(debugKey != nil) - - let debugConfig = settings.configurations[debugKey!] - try #require(debugConfig != nil) + let settings = try await mapper.map(projectProvider: mockProvider, configurationList: configList) + let debugKey = try #require(settings.configurations.keys.first { $0.name == "Debug" }) + let debugConfig = try #require(settings.configurations[debugKey]) - let actualDebugConfig = debugConfig! - try #require(actualDebugConfig != nil) - - #expect(actualDebugConfig!.settings["SOME_NUMBER"] == "42") + #expect(debugConfig?.settings["SOME_NUMBER"] == "42") } - @Test func testXCConfigPathResolution() async throws { + @Test("Resolves XCConfig file paths correctly") + func testXCConfigPathResolution() async throws { let pbxProj = PBXProj() let baseConfigRef = PBXFileReference.mock( sourceTree: .sourceRoot, path: "Config.xcconfig", pbxProj: pbxProj ) let buildConfig = XCBuildConfiguration.mock( - name: "Debug", buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example"], + name: "Debug", + buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example"], pbxProj: pbxProj ) buildConfig.baseConfiguration = baseConfigRef @@ -120,24 +102,17 @@ struct SettingsMapperTests { let mockProvider = MockProjectProvider( sourceDirectory: "/Users/test/project", configurationList: configList ) - let settings = try await mapper.map( - projectProvider: mockProvider, configurationList: configList - ) - - let debugKey = settings.configurations.keys.first { $0.name == "Debug" } - try #require(debugKey != nil) - - let debugConfig = settings.configurations[debugKey!] - try #require(debugConfig != nil) + let settings = try await mapper.map(projectProvider: mockProvider, configurationList: configList) - let actualDebugConfig = debugConfig! - try #require(actualDebugConfig != nil) + let debugKey = try #require(settings.configurations.keys.first { $0.name == "Debug" }) + let debugConfig = try #require(settings.configurations[debugKey]) let expectedPath = "/Users/test/project/Config.xcconfig" - #expect(actualDebugConfig!.xcconfig?.pathString == expectedPath) + #expect(debugConfig?.xcconfig?.pathString == expectedPath) } - @Test func testArrayValueMapping() async throws { + @Test("Maps array values correctly in build settings") + func testArrayValueMapping() async throws { let pbxProj = PBXProj() let configs: [(String, [String: Sendable])] = [ ("Debug", ["SOME_ARRAY": ["val1", "val2"]]), @@ -145,25 +120,12 @@ struct SettingsMapperTests { let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) - let settings = try await mapper.map( - projectProvider: mockProvider, configurationList: configList - ) + let settings = try await mapper.map(projectProvider: mockProvider, configurationList: configList) - // Check we have one configuration #expect(settings.configurations.count == 1) + let debugKey = try #require(settings.configurations.keys.first { $0.name == "Debug" }) + let debugConfig = try #require(settings.configurations[debugKey]) - // Retrieve the Debug configuration - let debugKey = settings.configurations.keys.first { $0.name == "Debug" } - try #require(debugKey != nil) - let debugConfig = settings.configurations[debugKey!] - try #require(debugConfig != nil) - - let actualDebugConfig = debugConfig! - try #require(actualDebugConfig != nil) - - // Verify the array setting - // NOTE: actualDebugConfig.settings["SOME_ARRAY"] should return a SettingValue - // which is .array(["val1", "val2"]) - #expect(actualDebugConfig!.settings["SOME_ARRAY"] == ["val1", "val2"]) + #expect(debugConfig?.settings["SOME_ARRAY"] == ["val1", "val2"]) } } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift index ec9746f0..a3a0dcf6 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift @@ -4,6 +4,7 @@ import Testing @testable import XcodeProj @testable import XcodeProjToGraph +@Suite struct SchemeMapperTests { let mockProvider: MockProjectProvider let mapper: SchemeMapper @@ -14,8 +15,9 @@ struct SchemeMapperTests { mapper = try SchemeMapper(graphType: .project(mockProvider.sourceDirectory)) } - @Test func testMapSharedProjectSchemes() async throws { - // Setup shared scheme data + @Test("Maps shared project schemes correctly") + func testMapSharedProjectSchemes() async throws { + // Setup a shared scheme let xcscheme = XCScheme.mock(name: "SharedScheme") let schemes = try await mapper.mapSchemes(xcschemes: [xcscheme], shared: true) @@ -24,8 +26,9 @@ struct SchemeMapperTests { #expect(schemes[0].shared == true) } - @Test func testMapUserSchemes() async throws { - // Setup user scheme data + @Test("Maps user (non-shared) project schemes correctly") + func testMapUserSchemes() async throws { + // Setup a user scheme let xcscheme = XCScheme.mock(name: "UserScheme") let schemes = try await mapper.mapSchemes(xcschemes: [xcscheme], shared: false) @@ -34,7 +37,8 @@ struct SchemeMapperTests { #expect(schemes[0].shared == false) } - @Test func testMapBuildAction() async throws { + @Test("Maps a build action within a scheme") + func testMapBuildAction() async throws { let targetRef = XCScheme.BuildableReference( referencedContainer: "container:App.xcodeproj", blueprintIdentifier: "123", @@ -62,7 +66,8 @@ struct SchemeMapperTests { #expect(mappedAction?.findImplicitDependencies == true) } - @Test func testMapTestAction() async throws { + @Test("Maps a test action with testable references, coverage, and environment") + func testMapTestAction() async throws { let targetRef = XCScheme.BuildableReference( referencedContainer: "container:App.xcodeproj", blueprintIdentifier: "123", @@ -75,16 +80,8 @@ struct SchemeMapperTests { buildableReference: targetRef ) - let envVar = XCScheme.EnvironmentVariable( - variable: "TEST_ENV", - value: "test_value", - enabled: true - ) - - let launchArg = XCScheme.CommandLineArguments.CommandLineArgument( - name: "test_arg", - enabled: true - ) + let envVar = XCScheme.EnvironmentVariable(variable: "TEST_ENV", value: "test_value", enabled: true) + let launchArg = XCScheme.CommandLineArguments.CommandLineArgument(name: "test_arg", enabled: true) let testAction = XCScheme.TestAction( buildConfiguration: "Debug", @@ -109,7 +106,8 @@ struct SchemeMapperTests { #expect(mappedAction?.region == "US") } - @Test func testMapRunAction() async throws { + @Test("Maps a run action with environment variables and launch arguments") + func testMapRunAction() async throws { let targetRef = XCScheme.BuildableReference( referencedContainer: "container:App.xcodeproj", blueprintIdentifier: "123", @@ -119,16 +117,8 @@ struct SchemeMapperTests { let runnable = XCScheme.BuildableProductRunnable(buildableReference: targetRef) - let envVar = XCScheme.EnvironmentVariable( - variable: "RUN_ENV", - value: "run_value", - enabled: true - ) - - let launchArg = XCScheme.CommandLineArguments.CommandLineArgument( - name: "run_arg", - enabled: true - ) + let envVar = XCScheme.EnvironmentVariable(variable: "RUN_ENV", value: "run_value", enabled: true) + let launchArg = XCScheme.CommandLineArguments.CommandLineArgument(name: "run_arg", enabled: true) let launchAction = XCScheme.LaunchAction( pathRunnable: try XCScheme.PathRunnable(element: runnable.xmlElement()), @@ -147,7 +137,8 @@ struct SchemeMapperTests { #expect(mappedAction?.arguments?.launchArguments.first?.name == "run_arg") } - @Test func testMapArchiveAction() async throws { + @Test("Maps an archive action with organizer reveal enabled") + func testMapArchiveAction() async throws { let archiveAction = XCScheme.ArchiveAction( buildConfiguration: "Release", revealArchiveInOrganizer: true @@ -159,7 +150,8 @@ struct SchemeMapperTests { #expect(mappedAction?.revealArchiveInOrganizer == true) } - @Test func testMapProfileAction() async throws { + @Test("Maps a profile action to a runnable and configuration") + func testMapProfileAction() async throws { let targetRef = XCScheme.BuildableReference( referencedContainer: "container:App.xcodeproj", blueprintIdentifier: "123", @@ -180,7 +172,8 @@ struct SchemeMapperTests { #expect(mappedAction?.configurationName == "Release") } - @Test func testMapAnalyzeAction() async throws { + @Test("Maps an analyze action to the appropriate configuration") + func testMapAnalyzeAction() async throws { let analyzeAction = XCScheme.AnalyzeAction(buildConfiguration: "Debug") let mappedAction = try await mapper.mapAnalyzeAction(action: analyzeAction) @@ -188,7 +181,8 @@ struct SchemeMapperTests { #expect(mappedAction?.configurationName == "Debug") } - @Test func testMapTargetReference() async throws { + @Test("Maps target references in a scheme's build action") + func testMapTargetReference() async throws { let targetRef = XCScheme.BuildableReference( referencedContainer: "container:App.xcodeproj", blueprintIdentifier: "123", @@ -196,13 +190,11 @@ struct SchemeMapperTests { blueprintName: "App" ) - // Create a build action entry that uses the target reference let buildActionEntry = XCScheme.BuildAction.Entry( buildableReference: targetRef, buildFor: [.running] ) - // Create a scheme with a build action that uses our target reference let buildAction = XCScheme.BuildAction( buildActionEntries: [buildActionEntry], parallelizeBuild: true, @@ -213,15 +205,14 @@ struct SchemeMapperTests { let mapped = try await mapper.mapScheme(xcscheme: scheme, shared: true) - // Verify the target reference was properly mapped let mappedBuildAction = try #require(mapped.buildAction) - #expect(mappedBuildAction.targets.count == 1) #expect(mappedBuildAction.targets[0].name == "App") #expect(mappedBuildAction.targets[0].projectPath == mockProvider.sourceDirectory) } - @Test func testNilActions() async throws { + @Test("Handles schemes without any actions gracefully") + func testNilActions() async throws { let scheme = XCScheme.mock( buildAction: nil, testAction: nil, diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift index ec8a1a98..7e00176a 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift @@ -6,7 +6,8 @@ import XcodeProj @testable import TestSupport @testable import XcodeProjToGraph -struct PBXTargetMapperTests { +@Suite +struct TargetMapperTests { let mockProvider = MockProjectProvider() let mapper: TargetMapping @@ -14,7 +15,8 @@ struct PBXTargetMapperTests { mapper = TargetMapper(projectProvider: mockProvider) } - @Test func testMapBasicTarget() async throws { + @Test("Maps a basic target with a product bundle identifier") + func testMapBasicTarget() async throws { let target = createTarget( name: "App", productType: .application, @@ -28,7 +30,8 @@ struct PBXTargetMapperTests { #expect(mapped.bundleId == "com.example.app") } - @Test func testMapTargetWithMissingBundleId() async throws { + @Test("Throws an error if the target is missing a bundle identifier") + func testMapTargetWithMissingBundleId() async throws { let target = createTarget( name: "App", productType: .application, @@ -40,7 +43,8 @@ struct PBXTargetMapperTests { } } - @Test func testMapTargetWithEnvironmentVariables() async throws { + @Test("Maps a target with environment variables") + func testMapTargetWithEnvironmentVariables() async throws { let target = createTarget( name: "App", productType: .application, @@ -55,7 +59,8 @@ struct PBXTargetMapperTests { #expect(mapped.environmentVariables["TEST_VAR"]?.isEnabled == true) } - @Test func testMapTargetWithLaunchArguments() async throws { + @Test("Maps a target with launch arguments") + func testMapTargetWithLaunchArguments() async throws { let target = createTarget( name: "App", productType: .application, @@ -73,7 +78,8 @@ struct PBXTargetMapperTests { #expect(mapped.launchArguments == expected) } - @Test func testMapTargetWithSourceFiles() async throws { + @Test("Maps a target with source files") + func testMapTargetWithSourceFiles() async throws { let sourceFile = PBXFileReference.mock( path: "ViewController.swift", lastKnownFileType: "sourcecode.swift", @@ -94,7 +100,8 @@ struct PBXTargetMapperTests { #expect(mapped.sources[0].path.basename == "ViewController.swift") } - @Test func testMapTargetWithMetadata() async throws { + @Test("Maps a target with metadata tags") + func testMapTargetWithMetadata() async throws { let target = createTarget( name: "App", productType: .application, diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Workspace/WorkspaceMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Workspace/WorkspaceMapperTests.swift index e69de29b..21a8e399 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Workspace/WorkspaceMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Workspace/WorkspaceMapperTests.swift @@ -0,0 +1,153 @@ +import AEXML +import Foundation +import Path +import PathKit +import Testing +import TestSupport +import XcodeGraph +import XcodeProj +@testable import XcodeProjToGraph + +@Suite +struct WorkspaceMapperTests { + /// Creates a basic `.xcworkspace` object with given children. + private func makeWorkspace(withElements elements: [XCWorkspaceDataElement]) -> XCWorkspace { + let data = XCWorkspaceData(children: elements) + return XCWorkspace(data: data) + } + + /// Creates a file reference element pointing to a given relative path. + private func fileElement(relativePath: String) -> XCWorkspaceDataElement { + .file(XCWorkspaceDataFileRef(location: .group(relativePath))) + } + + /// Creates a group element with nested children. + private func groupElement(name: String, children: [XCWorkspaceDataElement]) -> XCWorkspaceDataElement { + .group(XCWorkspaceDataGroup(location: .group(name), name: name, children: children)) + } + + @Test("Maps workspace without any projects or schemes") + func testMap_NoProjectsOrSchemes() async throws { + // Arrange: A workspace with no .xcodeproj references + let workspacePath = try AbsolutePath(validating: "/tmp/MyWorkspace.xcworkspace") + let xcworkspace: XCWorkspace = .mock(files: ["ReadMe.md"]) + + let provider = MockWorkspaceProvider( + xcWorkspacePath: workspacePath, + xcworkspace: xcworkspace + ) + let mapper = WorkspaceMapper(workspaceProvider: provider) + + // Act + let workspace = try await mapper.map() + + // Assert: No projects, no schemes + #expect(workspace.name == "MyWorkspace") + #expect(workspace.projects.isEmpty == true) + #expect(workspace.schemes.isEmpty == true) + } + + @Test("Maps workspace with multiple projects") + func testMap_MultipleProjects() async throws { + // Arrange: A workspace with multiple xcodeproj references + let workspacePath = try AbsolutePath(validating: "/tmp/MyWorkspace.xcworkspace") + let workspaceDir = workspacePath.parentDirectory + let xcworkspace = makeWorkspace(withElements: [ + fileElement(relativePath: "ProjectA.xcodeproj"), + groupElement(name: "NestedGroup", children: [ + fileElement(relativePath: "ProjectB.xcodeproj"), + fileElement(relativePath: "Notes.txt"), + ]), + ]) + let provider = MockWorkspaceProvider( + xcWorkspacePath: workspacePath, + xcworkspace: xcworkspace + ) + let mapper = WorkspaceMapper(workspaceProvider: provider) + + // For this test, we assume no `xcshareddata/xcschemes` directory exists. + + // Act + let workspace = try await mapper.map() + + // Assert: Two projects discovered + #expect(workspace.name == "MyWorkspace") + #expect(workspace.projects.count == 2) + #expect(workspace.projects.contains(workspaceDir.appending(component: "ProjectA.xcodeproj")) == true) + #expect(workspace.projects.contains(workspaceDir.appending(components: ["NestedGroup", "ProjectB.xcodeproj"])) == true) + #expect(workspace.schemes.isEmpty == true) + } + + @Test("Maps workspace with shared schemes") + func testMap_WithSchemes() async throws { + let tempDirectory = FileManager.default.temporaryDirectory + let path = tempDirectory.appendingPathComponent("MyWorkspace.xcworkspace") + // Arrange: A workspace with one project and a schemes directory + let workspacePath = try AbsolutePath(validating: path.path()) + + // Create a mock `.xcscheme` file in `xcshareddata/xcschemes` + let sharedDataDir = workspacePath.pathString + "/xcshareddata/xcschemes" + try FileManager.default.createDirectory( + atPath: sharedDataDir, + withIntermediateDirectories: true + ) + let schemeFile = sharedDataDir + "/MyScheme.xcscheme" + try "dummy scheme content".write(toFile: schemeFile, atomically: true, encoding: .utf8) + + // A workspace with a single project reference + let xcworkspace = makeWorkspace(withElements: [ + fileElement(relativePath: "App.xcodeproj"), + ]) + let provider = MockWorkspaceProvider( + xcWorkspacePath: workspacePath, + xcworkspace: xcworkspace + ) + + let mapper = WorkspaceMapper(workspaceProvider: provider) + + do { + _ = try await mapper.map() + } catch { + #expect(error.localizedDescription == "The operation couldn’t be completed. (NSXMLParserErrorDomain error 4.)") + } + } + + @Test("No schemes directory results in no schemes mapped") + func testMap_NoSchemesDirectory() async throws { + // Arrange: A workspace with a project, but no `xcshareddata/xcschemes` directory + let workspacePath = try AbsolutePath(validating: "/tmp/MyWorkspace.xcworkspace") + + let xcworkspace = makeWorkspace(withElements: [ + fileElement(relativePath: "App.xcodeproj"), + ]) + let provider = MockWorkspaceProvider( + xcWorkspacePath: workspacePath, + xcworkspace: xcworkspace + ) + let mapper = WorkspaceMapper(workspaceProvider: provider) + + // Act + let workspace = try await mapper.map() + + // Assert: No schemes found + #expect(workspace.schemes.isEmpty == true) + } + + @Test("Workspace name is derived from the .xcworkspace file name") + func testMap_NameDerivation() async throws { + // Arrange + let workspacePath = try AbsolutePath(validating: "/tmp/AnotherWorkspace.xcworkspace") + let xcworkspace = makeWorkspace(withElements: []) + let provider = MockWorkspaceProvider( + xcWorkspacePath: workspacePath, + xcworkspace: xcworkspace + ) + let mapper = WorkspaceMapper(workspaceProvider: provider) + + // Act + let workspace = try await mapper.map() + + // Assert + #expect(workspace.name == "AnotherWorkspace") + } +} diff --git a/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift b/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift index d50beb78..b7191b60 100644 --- a/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift +++ b/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift @@ -28,8 +28,8 @@ struct ProjectParserTests { return try AbsolutePath(validating: mockDirectory) } - /// Test parsing a valid `.xcworkspace` file - @Test func testParseWorkspace() async throws { + @Test("Parses a directory containing a valid .xcworkspace file") + func testParseWorkspace() async throws { // Arrange let mockDirectory = try createMockDirectory(withContents: ["MyWorkspace.xcworkspace"]) let workspacePath = mockDirectory.appending(component: "MyWorkspace.xcworkspace") @@ -41,8 +41,8 @@ struct ProjectParserTests { #expect(graph.name == "MyWorkspace") } - /// Test parsing a valid `.xcodeproj` file - @Test func testParseXcodeProject() async throws { + @Test("Parses a directory containing a valid .xcodeproj file") + func testParseXcodeProject() async throws { // Arrange let mockDirectory = try createMockDirectory(withContents: ["MyProject.xcodeproj"]) let projectPath = mockDirectory.appending(component: "MyProject.xcodeproj") @@ -54,8 +54,8 @@ struct ProjectParserTests { #expect(graph.name == "Workspace") } - /// Test parsing when directory contains both `.xcworkspace` and `.xcodeproj` - @Test func testParseDirectoryWithWorkspaceAndProject() async throws { + @Test("Parses a directory with both .xcworkspace and .xcodeproj, preferring the workspace") + func testParseDirectoryWithWorkspaceAndProject() async throws { // Arrange let mockDirectory = try createMockDirectory(withContents: [ "MyWorkspace.xcworkspace", "MyProject.xcodeproj", @@ -64,30 +64,31 @@ struct ProjectParserTests { // Act let graph = try await ProjectParser.parse(atPath: mockDirectory.pathString) + // Assert #expect(graph.name == "MyWorkspace") } - /// Test parsing when the directory contains no valid project files - @Test func testParseDirectoryNoProjects() async throws { + @Test("Throws an error when no valid project files are found") + func testParseDirectoryNoProjects() async throws { // Arrange let mockDirectory = try createMockDirectory(withContents: ["ReadMe.md", "file.txt"]) // Act & Assert - await #expect(throws: MappingError.noProjectsFound) { + await #expect(throws: MappingError.noProjectsFound(path: mockDirectory.pathString)) { try await ProjectParser.parse(atPath: mockDirectory.pathString) } } - /// Test handling a non-existent path - @Test func testParseNonExistentPath() async throws { + @Test("Throws an error for a non-existent directory path") + func testParseNonExistentPath() async throws { // Act & Assert await #expect(throws: MappingError.pathNotFound(path: "/non/existent/path")) { try await ProjectParser.parse(atPath: "/non/existent/path") } } - /// Test parsing when only `.xcodeproj` exists in the directory - @Test func testParseDirectoryOnlyXcodeProj() async throws { + @Test("Parses a directory with only an .xcodeproj file") + func testParseDirectoryOnlyXcodeProj() async throws { // Arrange let mockDirectory = try createMockDirectory(withContents: ["MyProject.xcodeproj"]) diff --git a/Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift b/Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift index 925c470a..d594cd12 100644 --- a/Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift +++ b/Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift @@ -5,8 +5,8 @@ import XcodeProjToGraph @Suite struct LipoToolTests { - /// Test that `LipoTool.archs` successfully parses valid output. - @Test func testArchs_ValidOutput() async throws { + @Test("Parses multiple architectures correctly from Lipo output") + func testArchs_ValidOutput() async throws { // Arrange let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( withContent: """ @@ -25,8 +25,8 @@ struct LipoToolTests { #expect(result.architectures == [.arm64, .x8664]) } - /// Test that `LipoTool.archs` handles a single architecture output. - @Test func testArchs_SingleArchitecture() async throws { + @Test("Handles a single architecture output") + func testArchs_SingleArchitecture() async throws { // Arrange let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( withContent: """ @@ -45,8 +45,8 @@ struct LipoToolTests { #expect(result.architectures == [.arm64]) } - /// Test that `LipoTool.archs` throws an error on non-zero exit code. - @Test func testArchs_NonZeroExitCode() async throws { + @Test("Throws an error when Lipo returns a non-zero exit code") + func testArchs_NonZeroExitCode() async throws { // Arrange let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( withContent: """ @@ -62,8 +62,8 @@ struct LipoToolTests { } } - /// Test that `LipoTool.archs` handles empty output gracefully. - @Test func testArchs_EmptyOutput() async throws { + @Test("Handles empty output gracefully") + func testArchs_EmptyOutput() async throws { // Arrange let mockExecutablePath = try MockFileCreator.createTemporaryExecutable( withContent: """ @@ -82,8 +82,8 @@ struct LipoToolTests { #expect(result.architectures.isEmpty == true) } - /// Test that `LipoTool.archs` throws an error if the executable does not exist. - @Test func testArchs_ExecutableNotFound() async throws { + @Test("Throws an error if the Lipo executable is not found") + func testArchs_ExecutableNotFound() async throws { // Arrange let nonExistentExecutable = "/nonexistent/path/to/lipo" diff --git a/Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift b/Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift index 1255e31b..e299de0e 100644 --- a/Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift +++ b/Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift @@ -1,5 +1,6 @@ import Foundation import Testing +import TestSupport import XcodeProjToGraph @Suite @@ -16,14 +17,15 @@ struct ProcessRunnerTests { // Make the file executable try FileManager.default.setAttributes( - [.posixPermissions: 0o755], ofItemAtPath: mockExecutablePath + [.posixPermissions: 0o755], + ofItemAtPath: mockExecutablePath ) return mockExecutablePath } - /// Test that `ProcessRunner` runs a valid executable successfully and parses the result. - @Test func testRun_ValidExecutable_Success() async throws { + @Test("Runs a valid executable and returns expected output") + func testRun_ValidExecutable_Success() async throws { // Arrange let mockExecutablePath = try createTemporaryExecutable( withContent: """ @@ -53,8 +55,8 @@ struct ProcessRunnerTests { #expect(output == "Hello, World!") } - /// Test that `ProcessRunner` throws an error if the executable does not exist. - @Test func testRun_ExecutableNotFound_ThrowsError() async throws { + @Test("Throws an error if the executable does not exist") + func testRun_ExecutableNotFound_ThrowsError() async throws { // Arrange let nonExistentExecutable = Executable.custom( "/nonexistent/path", @@ -73,8 +75,8 @@ struct ProcessRunnerTests { } } - /// Test that `ProcessRunner` throws an error on non-zero exit when `throwOnNonZeroExit` is enabled. - @Test func testRun_NonZeroExitCode_ThrowsError() async throws { + @Test("Throws an error on non-zero exit code when throwOnNonZeroExit is enabled") + func testRun_NonZeroExitCode_ThrowsError() async throws { // Arrange let mockExecutablePath = try createTemporaryExecutable( withContent: """ @@ -100,8 +102,8 @@ struct ProcessRunnerTests { } } - /// Test that `ProcessRunner` does not throw on non-zero exit when `throwOnNonZeroExit` is disabled. - @Test func testRun_NonZeroExitCode_NoThrow() async throws { + @Test("Does not throw on non-zero exit code when throwOnNonZeroExit is disabled") + func testRun_NonZeroExitCode_NoThrow() async throws { // Arrange let mockExecutablePath = try createTemporaryExecutable( withContent: """ @@ -114,7 +116,7 @@ struct ProcessRunnerTests { mockExecutablePath, [], { result in - result.exitCode // Simply return the exit code for validation. + result.exitCode // Return the exit code for validation } ) @@ -126,11 +128,12 @@ struct ProcessRunnerTests { throwOnNonZeroExit: false ) + // Assert #expect(exitCode == 1) } - /// Test that `ProcessRunner` parses UTF-8 output correctly. - @Test func testRun_ParsesUtf8Output() async throws { + @Test("Parses UTF-8 output correctly") + func testRun_ParsesUtf8Output() async throws { // Arrange let mockExecutablePath = try createTemporaryExecutable( withContent: """ @@ -160,14 +163,14 @@ struct ProcessRunnerTests { #expect(output == "你好, 世界!") } - /// Test that `ProcessRunner` throws an error if the output is not valid UTF-8. - @Test func testRun_InvalidUtf8Output_ThrowsError() async throws { + @Test("Throws an error if the output is not valid UTF-8") + func testRun_InvalidUtf8Output_ThrowsError() async throws { // Arrange let mockExecutablePath = try createTemporaryExecutable( withContent: """ #!/bin/sh echo -e '\\xff' # Invalid UTF-8 sequence - + exit 0 """ ) From 5e57dc7be6edd996a26c76b4088a30725ba0973c Mon Sep 17 00:00:00 2001 From: Andy Kolean Date: Sun, 15 Dec 2024 21:49:06 -0500 Subject: [PATCH 05/40] [Integration Tests] remove --- Package.resolved | 20 +- Package.swift | 14 +- .../App/Sources/ContentView.swift | 16 - .../App/Sources/MyApp.swift | 36 - .../Project.swift | 25 - .../README.md | 3 - .../App/Sources/App.swift | 10 - .../App/Sources/ContentView.swift | 13 - .../LocalSwiftPackage/Package.swift | 15 - .../LocalSwiftPackage/LocalSwiftPackage.swift | 3 - .../Project.swift | 29 - .../README.md | 7 - .../.package.resolved | 15 - .../App/Sources/App.swift | 10 - .../App/Sources/ContentView.swift | 13 - .../LocalSwiftPackage/Package.swift | 21 - .../LocalSwiftPackage/LocalSwiftPackage.swift | 6 - .../Project.swift | 29 - .../README.md | 8 - .../CommandLineTool/main.swift | 4 - .../DynamicFramework/DynamicFramework.swift | 5 - .../Project.swift | 26 - .../Tuist/Config.swift | 3 - .../Fixtures/ios_app_large/Info.plist | 43 - .../Fixtures/ios_app_large/Project.swift | 18 - .../ios_app_large/Sources/AppDelegate.swift | 21 - .../Fixtures/ios_app_large/Tests.plist | 24 - .../Fixtures/ios_app_large/Tuist/Config.swift | 3 - .../Sources/AppIntentExtension.swift | 9 - .../Sources/AppIntentExtensionExtension.swift | 6 - .../ios_app_with_extensions/Bundle/dummy.jpg | 0 .../ios_app_with_extensions/Info.plist | 43 - .../Resources/Assets.xcassets/Contents.json | 6 - .../Contents.json | 78 - .../Base.lproj/MainInterface.storyboard | 37 - .../Sources/MessagesViewController.swift | 52 - .../NotificationService.swift | 30 - .../ios_app_with_extensions/Project.swift | 128 -- .../ios_app_with_extensions/README.md | 3 - .../Sources/AppDelegate.swift | 18 - .../Documentation.docc/Documentation.md | 13 - .../Sources/StaticFramework.swift | 5 - .../Stickers.xcassets/Contents.json | 6 - .../Sticker Pack.stickerpack/Contents.json | 9 - .../Contents.json | 78 - .../Tuist/Config.swift | 3 - .../AccentColor.colorset/Contents.json | 11 - .../AppIcon.appiconset/Contents.json | 98 -- .../Resources/Assets.xcassets/Contents.json | 6 - .../WidgetBackground.colorset/Contents.json | 11 - .../WidgetExtension/Sources/Widget.swift | 69 - .../App/Project.swift | 62 - .../App/Sources/AppDelegate.swift | 23 - .../App/Support/App-Info.plist | 43 - .../App/Support/AppTests-Info.plist | 22 - .../App/Tests/AppDelegateTests.swift | 11 - .../ConfigurationFiles/Beta.xcconfig | 2 - .../ConfigurationFiles/Debug.xcconfig | 2 - .../ConfigurationFiles/Release.xcconfig | 2 - .../ConfigurationFiles/Target.Beta.xcconfig | 2 - .../ConfigurationFiles/Target.Debug.xcconfig | 2 - .../Target.Release.xcconfig | 2 - .../Framework1/Project.swift | 43 - .../Framework1/Sources/Framework1File.swift | 16 - .../Framework1/Support/Framework1-Info.plist | 24 - .../Support/Framework1Tests-Info.plist | 22 - .../Tests/Framework1FileTests.swift | 17 - .../Framework2/Project.swift | 47 - .../Framework2/Sources/Framework2File.swift | 9 - .../Framework2/Support/Framework2-Info.plist | 24 - .../Support/Framework2Tests-Info.plist | 22 - .../Tests/Framework2FileTests.swift | 11 - .../ios_app_with_multi_configs/README.md | 3 - .../Tuist/Config.swift | 3 - .../Workspace.swift | 6 - .../.package.resolved | 16 - .../Package.resolved | 16 - .../Project.swift | 37 - .../README.md | 3 - .../Sources/AppDelegate.swift | 25 - .../Support/Info.plist | 43 - .../Support/Tests.plist | 24 - .../Tests/AppTests.swift | 6 - .../Tuist/Config.swift | 3 - .../AccentColor.colorset/Contents.json | 11 - .../AppIcon.appiconset/Contents.json | 13 - .../Resources/Assets.xcassets/Contents.json | 6 - .../Preview Assets.xcassets/Contents.json | 6 - .../App/Sources/AppApp.swift | 10 - .../App/Sources/ContentView.swift | 30 - .../AppTests/AppTests.swift | 21 - .../Project.swift | 34 - .../ios_app_with_spm_dependencies/README.md | 3 - .../Tuist/Package.resolved | 69 - .../Tuist/Package.swift | 14 - .../ios_app_with_static_libraries/Info.plist | 43 - .../Modules/A/CustomHeaders/CustomHeader.h | 0 .../A/Playgrounds/A.playground/Contents.swift | 1 - .../A.playground/contents.xcplayground | 4 - .../Modules/A/Project.swift | 36 - .../Modules/A/Sources/A.swift | 12 - .../Modules/A/Tests/ATests.swift | 10 - .../Modules/B/Info.plist | 26 - .../B/Playgrounds/B.playground/Contents.swift | 1 - .../B.playground/contents.xcplayground | 4 - .../Modules/B/Project.swift | 30 - .../Modules/B/Sources/B.swift | 9 - .../Modules/B/Tests.plist | 24 - .../Modules/B/Tests/BTests.swift | 10 - .../Modules/C/Info.plist | 26 - .../Modules/C/Project.swift | 31 - .../Modules/C/Sources/C.swift | 9 - .../Modules/C/Tests.plist | 24 - .../Modules/C/Tests/CTests.swift | 10 - .../Modules/C/build.sh | 23 - .../arm64-apple-ios-simulator.swiftsourceinfo | Bin 1084 -> 0 bytes ...x86_64-apple-ios-simulator.swiftsourceinfo | Bin 1084 -> 0 bytes .../arm64-apple-ios-simulator.abi.json | 108 -- ...apple-ios-simulator.private.swiftinterface | 12 - .../arm64-apple-ios-simulator.swiftdoc | Bin 400 -> 0 bytes .../arm64-apple-ios-simulator.swiftinterface | 12 - .../arm64-apple-ios-simulator.swiftmodule | Bin 16304 -> 0 bytes .../x86_64-apple-ios-simulator.abi.json | 108 -- ...apple-ios-simulator.private.swiftinterface | 12 - .../x86_64-apple-ios-simulator.swiftdoc | Bin 400 -> 0 bytes .../x86_64-apple-ios-simulator.swiftinterface | 12 - .../x86_64-apple-ios-simulator.swiftmodule | Bin 16308 -> 0 bytes .../Modules/C/prebuilt/C/libC.a | Bin 22696 -> 0 bytes .../Contents.swift | 1 - .../contents.xcplayground | 4 - .../Project.swift | 29 - .../ios_app_with_static_libraries/README.md | 33 - .../Sources/AppDelegate.swift | 25 - .../ios_app_with_static_libraries/Tests.plist | 24 - .../Tests/AppTests.swift | 10 - .../Tuist/Config.swift | 3 - .../App/Config/App-Info.plist | 43 - .../App/Config/AppTests-Info.plist | 22 - .../App/Project.swift | 40 - .../App/Sources/AppDelegate.swift | 19 - .../App/Tests/AppDelegateTests.swift | 11 - .../App/UITests/AppUITest.swift | 26 - .../Framework1/Config/Framework1-Info.plist | 24 - .../Config/Framework1Tests-Info.plist | 22 - .../Framework1/Project.swift | 53 - .../Framework1/Sources/Framework1File.swift | 16 - .../Tests/Framework1FileTests.swift | 19 - .../Framework1/Tests/Info.plist | 22 - .../Framework2/Config/Framework2-Info.plist | 24 - .../Framework2/Project.swift | 29 - .../Framework2/Sources/Framework2File.swift | 9 - .../Framework2/build.sh | 62 - .../Mac/Framework2.framework/Framework2 | Bin 54712 -> 0 bytes .../Headers/Framework2-Swift.h | 311 ---- .../Mac/Framework2.framework/Info.plist | 48 - .../Project/arm64-apple-macos.swiftsourceinfo | Bin 1140 -> 0 bytes .../x86_64-apple-macos.swiftsourceinfo | Bin 1144 -> 0 bytes .../Project/x86_64.swiftsourceinfo | Bin 832 -> 0 bytes .../arm64-apple-macos.abi.json | 76 - .../arm64-apple-macos.private.swiftinterface | 14 - .../arm64-apple-macos.swiftdoc | Bin 400 -> 0 bytes .../arm64-apple-macos.swiftinterface | 14 - .../arm64-apple-macos.swiftmodule | Bin 20380 -> 0 bytes .../x86_64-apple-macos.abi.json | 76 - .../x86_64-apple-macos.private.swiftinterface | 13 - .../x86_64-apple-macos.swiftdoc | Bin 400 -> 0 bytes .../x86_64-apple-macos.swiftinterface | 13 - .../x86_64-apple-macos.swiftmodule | Bin 17056 -> 0 bytes .../Framework2.swiftmodule/x86_64.swiftdoc | Bin 384 -> 0 bytes .../x86_64.swiftinterface | 10 - .../Framework2.swiftmodule/x86_64.swiftmodule | Bin 15580 -> 0 bytes .../Modules/module.modulemap | 4 - .../iOS/Framework2.framework/Framework2 | Bin 170976 -> 0 bytes .../Headers/Framework2-Swift.h | 618 -------- .../iOS/Framework2.framework/Info.plist | Bin 837 -> 0 bytes .../arm64-apple-ios-simulator.swiftsourceinfo | Bin 1148 -> 0 bytes .../Project/arm64-apple-ios.swiftsourceinfo | Bin 828 -> 0 bytes .../Project/arm64.swiftsourceinfo | Bin 828 -> 0 bytes ...x86_64-apple-ios-simulator.swiftsourceinfo | Bin 1148 -> 0 bytes .../Project/x86_64.swiftsourceinfo | Bin 840 -> 0 bytes .../arm64-apple-ios-simulator.abi.json | 76 - ...apple-ios-simulator.private.swiftinterface | 14 - .../arm64-apple-ios-simulator.swiftdoc | Bin 408 -> 0 bytes .../arm64-apple-ios-simulator.swiftinterface | 14 - .../arm64-apple-ios-simulator.swiftmodule | Bin 20676 -> 0 bytes .../arm64-apple-ios.swiftdoc | Bin 380 -> 0 bytes .../arm64-apple-ios.swiftinterface | 10 - .../arm64-apple-ios.swiftmodule | Bin 15664 -> 0 bytes .../Framework2.swiftmodule/arm64.swiftdoc | Bin 380 -> 0 bytes .../arm64.swiftinterface | 10 - .../Framework2.swiftmodule/arm64.swiftmodule | Bin 15664 -> 0 bytes .../x86_64-apple-ios-simulator.abi.json | 76 - ...apple-ios-simulator.private.swiftinterface | 14 - .../x86_64-apple-ios-simulator.swiftdoc | Bin 408 -> 0 bytes .../x86_64-apple-ios-simulator.swiftinterface | 14 - .../x86_64-apple-ios-simulator.swiftmodule | Bin 20676 -> 0 bytes .../Framework2.swiftmodule/x86_64.swiftdoc | Bin 392 -> 0 bytes .../x86_64.swiftinterface | 10 - .../Framework2.swiftmodule/x86_64.swiftmodule | Bin 15784 -> 0 bytes .../Modules/module.modulemap | 4 - .../README.md | 25 - .../StaticFramework1/Project.swift | 29 - .../Sources/Framework1File.swift | 16 - .../Tests/Framework1FileTests.swift | 19 - .../Tuist/Config.swift | 3 - .../Workspace.swift | 6 - .../Frameworks/CoreFramework/Info.plist | 26 - .../Frameworks/CoreFramework/Project.swift | 30 - .../CoreFramework/Sources/CoreClass.swift | 5 - .../Frameworks/CoreFramework/Tests.plist | 24 - .../CoreFramework/Tests/CoreClassTests.swift | 6 - .../Frameworks/DataFramework/Info.plist | 26 - .../Frameworks/DataFramework/Project.swift | 35 - .../DataFramework/Sources/DataClass.swift | 8 - .../Frameworks/DataFramework/Tests.plist | 24 - .../DataFramework/Tests/FrameworkATests.swift | 6 - .../Frameworks/FeatureAFramework/Info.plist | 26 - .../FeatureAFramework/Project.swift | 38 - .../Sources/FrameworkA.swift | 10 - .../Frameworks/FeatureAFramework/Tests.plist | 24 - .../Tests/FrameworkATests.swift | 6 - .../Frameworks/FeatureContracts/Info.plist | 26 - .../Frameworks/FeatureContracts/Project.swift | 36 - .../Sources/FeatureAContract.swift | 5 - .../Sources/FeatureBContract.swift | 7 - .../Frameworks/FeatureContracts/Tests.plist | 24 - .../Tests/FrameworkAContractTests.swift | 6 - .../UIComponentsFramework/Info.plist | 26 - .../UIComponentsFramework/Project.swift | 35 - .../Sources/UIComponentA.swift | 7 - .../UIComponentsFramework/Tests.plist | 24 - .../Tests/UIComponentATests.swift | 6 - .../StaticApp/Info.plist | 43 - .../StaticApp/Project.swift | 35 - .../StaticApp/Sources/AppDelegate.swift | 18 - .../StaticApp/Tests.plist | 24 - .../StaticApp/Tests/AppTests.swift | 6 - .../Tuist/Config.swift | 3 - .../Workspace.swift | 9 - .../MainApp/Info.plist | 28 - .../MainApp/Sources/main.swift | 3 - .../Project.swift | 25 - .../SystemExtension/Sources/main.swift | 3 - .../Tuist/Config.swift | 3 - .../AccentColor.colorset/Contents.json | 11 - .../AppIcon.appiconset/Contents.json | 13 - .../Resources/Assets.xcassets/Contents.json | 6 - .../App/Sources/ContentView.swift | 20 - .../App/Sources/TestApp.swift | 15 - .../ModuleA/Macros/Sources/Macros.swift | 23 - .../Modules/ModuleA/Sources/Macros.swift | 3 - .../Modules/ModuleA/Sources/ModuleA.swift | 12 - .../Modules/ModuleA/Tests/ModuleATests.swift | 23 - .../Project.swift | 107 -- .../Tuist/Package.resolved | 32 - .../Tuist/Package.swift | 23 - .../AccentColor.colorset/Contents.json | 11 - .../AppIcon.appiconset/Contents.json | 13 - .../Resources/Assets.xcassets/Contents.json | 6 - .../WatchApp/Sources/ContentView.swift | 18 - .../WatchApp/Sources/WatchApp.swift | 21 - .../WatchApp/Sources/WatchConfig.swift | 5 - .../ProjectA/Project.swift | 28 - .../Targets/App/Sources/AppDelegate.swift | 19 - .../ProjectA/Targets/App/Tests/AppTests.swift | 8 - .../ProjectB/.gitignore | 67 - .../ProjectB/Project.swift | 28 - .../Targets/App/Sources/AppDelegate.swift | 19 - .../ProjectB/Targets/App/Tests/AppTests.swift | 8 - .../Workspace.swift | 9 - .../TestSupport/Mocks/WorkspaceFixture.swift | 41 - .../IntegrationTests/IntegrationTests.swift | 197 --- ...+commandLineToolWithDynamicFramework.swift | 251 --- .../IntegrationTests+iosAppLarge.swift | 20 - ...ntegrationTests+iosAppWithExtensions.swift | 1378 ----------------- ...egrationTests+iosAppWithMultiConfigs.swift | 677 -------- ...onTests+iosAppWithRemoteSwiftPackage.swift | 274 ---- ...ationTests+iosAppWithSpmDependencies.swift | 308 ---- ...ationTests+iosAppWithStaticLibraries.swift | 653 -------- ...icrofeatureArchitectureStaticLinking.swift | 1195 -------------- ...ts+ios_app_with_transitive_framework.swift | 953 ------------ ...ionTests+macosAppWithSystemExtension.swift | 257 --- ...rmAppWithMacrosAndEmbeddedWatchosApp.swift | 910 ----------- .../Xcode/Project/PackageMapperTests.swift | 14 +- .../Workspace/WorkspaceMapperTests.swift | 3 +- Tuist/ProjectDescriptionHelpers/Module.swift | 6 +- 286 files changed, 14 insertions(+), 13040 deletions(-) delete mode 100644 Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/ContentView.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/MyApp.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_composable_architecture/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_composable_architecture/README.md delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/App.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/ContentView.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Package.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/README.md delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/.package.resolved delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/App.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/ContentView.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Package.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/README.md delete mode 100644 Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift delete mode 100644 Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift delete mode 100644 Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Tuist/Config.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_large/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_large/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_large/Sources/AppDelegate.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_large/Tests.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_large/Tuist/Config.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/Bundle/dummy.jpg delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/iMessage App Icon.stickersiconset/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/README.md delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/Documentation.docc/Documentation.md delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Sticker Pack.stickerpack/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/iMessage App Icon.stickersiconset/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/Tuist/Config.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AccentColor.colorset/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/WidgetBackground.colorset/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Debug.xcconfig delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Release.xcconfig delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/README.md delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Tuist/Config.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Workspace.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/.package.resolved delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Package.resolved delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/README.md delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tuist/Config.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/README.md delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.resolved delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/CustomHeaders/CustomHeader.h delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/Contents.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/contents.xcplayground delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Project.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/Contents.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/contents.xcplayground delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Project.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Info.plist delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Project.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Sources/C.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests.plist delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests/CTests.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/build.sh delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.abi.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.swiftdoc delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.swiftmodule delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.abi.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.swiftdoc delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.swiftmodule delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Playgrounds/application_with_transistive_static_dependency.playground/Contents.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Playgrounds/application_with_transistive_static_dependency.playground/contents.xcplayground delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/README.md delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests.plist delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tuist/Config.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1Tests-Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Config/Framework2-Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Sources/Framework2File.swift delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/build.sh delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Framework2 delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Headers/Framework2-Swift.h delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64-apple-macos.swiftsourceinfo delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64.swiftsourceinfo delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.abi.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.private.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftdoc delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftmodule delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.abi.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.private.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftdoc delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftmodule delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftdoc delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftmodule delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/module.modulemap delete mode 100755 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Headers/Framework2-Swift.h delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64.swiftsourceinfo delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64.swiftsourceinfo delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.abi.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftdoc delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftmodule delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftdoc delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftmodule delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftdoc delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftmodule delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.abi.json delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftdoc delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftmodule delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftdoc delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftinterface delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftmodule delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/module.modulemap delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/README.md delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Tuist/Config.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Workspace.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Tuist/Config.swift delete mode 100644 Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.swift delete mode 100644 Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Info.plist delete mode 100644 Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift delete mode 100644 Sources/TestSupport/Fixtures/macos_app_with_system_extension/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift delete mode 100644 Sources/TestSupport/Fixtures/macos_app_with_system_extension/Tuist/Config.swift delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.resolved delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.swift delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AccentColor.colorset/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/Contents.json delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift delete mode 100644 Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift delete mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Sources/AppDelegate.swift delete mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Tests/AppTests.swift delete mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/.gitignore delete mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Project.swift delete mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Sources/AppDelegate.swift delete mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Tests/AppTests.swift delete mode 100644 Sources/TestSupport/Fixtures/workspace_with_multiple_projects/Workspace.swift delete mode 100644 Sources/TestSupport/Mocks/WorkspaceFixture.swift delete mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/IntegrationTests.swift delete mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift delete mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift delete mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift delete mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift delete mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift delete mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift delete mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift delete mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift delete mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift delete mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift delete mode 100644 Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift diff --git a/Package.resolved b/Package.resolved index 5f910926..c9deaf9e 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "447185ac44bc164bd512707df26360069b79dc9ae8a26ab75a2aa5630c884a42", + "originHash" : "8dbcb87b4017f43ae481601d31f59f0ef12855a9874be06d0de98a190628d771", "pins" : [ { "identity" : "aexml", @@ -46,24 +46,6 @@ "version" : "0.10.1" } }, - { - "identity" : "swift-snapshot-testing", - "kind" : "remoteSourceControl", - "location" : "https://github.com/pointfreeco/swift-snapshot-testing", - "state" : { - "revision" : "42a086182681cf661f5c47c9b7dc3931de18c6d7", - "version" : "1.17.6" - } - }, - { - "identity" : "swift-syntax", - "kind" : "remoteSourceControl", - "location" : "https://github.com/swiftlang/swift-syntax", - "state" : { - "revision" : "0687f71944021d616d34d922343dcef086855920", - "version" : "600.0.1" - } - }, { "identity" : "xcodeproj", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index 68f34628..4fdac409 100644 --- a/Package.swift +++ b/Package.swift @@ -27,10 +27,7 @@ let targets: [Target] = [ dependencies: [ "XcodeProjToGraph", ], - path: "Sources/TestSupport", - resources: [ - .copy("Fixtures"), - ] + path: "Sources/TestSupport" ), .testTarget( name: "XcodeGraphTests", @@ -43,8 +40,7 @@ let targets: [Target] = [ name: "XcodeProjToGraphTests", dependencies: [ "XcodeProjToGraph", - "TestSupport", - .product(name: "InlineSnapshotTesting", package: "swift-snapshot-testing"), + "TestSupport" ], path: "Tests/XcodeProjToGraphTests" ), @@ -63,11 +59,7 @@ let package = Package( dependencies: [ .package(url: "https://github.com/Flight-School/AnyCodable", .upToNextMajor(from: "0.6.7")), .package(url: "https://github.com/tuist/Path.git", .upToNextMajor(from: "0.3.8")), - .package(url: "https://github.com/tuist/XcodeProj", from: "8.25.0"), - .package( - url: "https://github.com/pointfreeco/swift-snapshot-testing", - from: "1.17.0" - ), + .package(url: "https://github.com/tuist/XcodeProj", .upToNextMajor(from: "8.25.0")) ], targets: targets diff --git a/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/ContentView.swift deleted file mode 100644 index 48f62ebe..00000000 --- a/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/ContentView.swift +++ /dev/null @@ -1,16 +0,0 @@ -import SwiftUI - -public struct ContentView: View { - public init() {} - - public var body: some View { - Text("Hello, World!") - .padding() - } -} - -struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } -} diff --git a/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/MyApp.swift b/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/MyApp.swift deleted file mode 100644 index 99a17a49..00000000 --- a/Sources/TestSupport/Fixtures/app_with_composable_architecture/App/Sources/MyApp.swift +++ /dev/null @@ -1,36 +0,0 @@ -import ComposableArchitecture -import SwiftUI - -@main -struct MyApp: App { - var body: some Scene { - WindowGroup { - ContentView() - } - } -} - -@Reducer -struct Counter { - struct State: Equatable { - var count = 0 - } - - enum Action { - case decrementButtonTapped - case incrementButtonTapped - } - - var body: some Reducer { - Reduce { state, action in - switch action { - case .decrementButtonTapped: - state.count -= 1 - return .none - case .incrementButtonTapped: - state.count += 1 - return .none - } - } - } -} diff --git a/Sources/TestSupport/Fixtures/app_with_composable_architecture/Project.swift b/Sources/TestSupport/Fixtures/app_with_composable_architecture/Project.swift deleted file mode 100644 index f8edd26b..00000000 --- a/Sources/TestSupport/Fixtures/app_with_composable_architecture/Project.swift +++ /dev/null @@ -1,25 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "App", - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: .extendingDefault( - with: [ - "UILaunchScreen": [ - "UIColorName": "", - "UIImageName": "", - ], - ] - ), - sources: ["App/Sources/**"], - dependencies: [ - .external(name: "ComposableArchitecture"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/app_with_composable_architecture/README.md b/Sources/TestSupport/Fixtures/app_with_composable_architecture/README.md deleted file mode 100644 index 5f772ab8..00000000 --- a/Sources/TestSupport/Fixtures/app_with_composable_architecture/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Application with the Composable Architecture (TCA) - -This example contains an example that uses the Composable Architecture. diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/App.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/App.swift deleted file mode 100644 index 7cb2ea61..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/App.swift +++ /dev/null @@ -1,10 +0,0 @@ -import SwiftUI - -@main -struct MyApp: App { - var body: some Scene { - WindowGroup { - ContentView() - } - } -} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/ContentView.swift deleted file mode 100644 index bcdf9eae..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/App/Sources/ContentView.swift +++ /dev/null @@ -1,13 +0,0 @@ -import LocalSwiftPackage -import SwiftUI - -public struct ContentView: View { - public init() { - _ = LocalSwiftPackage() - } - - public var body: some View { - Text("Hello, World!") - .padding() - } -} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Package.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Package.swift deleted file mode 100644 index 31c72917..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Package.swift +++ /dev/null @@ -1,15 +0,0 @@ -// swift-tools-version: 5.10 - -import PackageDescription - -let package = Package( - name: "LocalSwiftPackage", - products: [ - .library(name: "LocalSwiftPackage", targets: ["LocalSwiftPackage"]), - ], - targets: [ - .target( - name: "LocalSwiftPackage" - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift deleted file mode 100644 index e4719258..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift +++ /dev/null @@ -1,3 +0,0 @@ -public final class LocalSwiftPackage { - public init() {} -} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/Project.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/Project.swift deleted file mode 100644 index 082f7ec9..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/Project.swift +++ /dev/null @@ -1,29 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "App", - packages: [ - .package(path: "LocalSwiftPackage"), - ], - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: .extendingDefault( - with: [ - "UILaunchScreen": [ - "UIColorName": "", - "UIImageName": "", - ], - ] - ), - sources: ["App/Sources/**"], - resources: [], - dependencies: [ - .package(product: "LocalSwiftPackage", type: .runtimeEmbedded), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/README.md b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/README.md deleted file mode 100644 index dbac75e0..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_embed_frameworks/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Application with Embedded Local SPM Module - -This example project demonstrates an application that includes a local Swift Package Manager (SPM) module (`LocalSwiftPackage`) configured as an embedded framework. - -The project leverages a local SPM module added to the Embed Frameworks section, showing that local SPM packages can now be embedded within the application. - -This demo project exists to validate and showcase the capability to embed local SPM modules as frameworks, allowing seamless integration into the main app. diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/.package.resolved b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/.package.resolved deleted file mode 100644 index 2d2b66fd..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/.package.resolved +++ /dev/null @@ -1,15 +0,0 @@ -{ - "originHash" : "ed38116a7ef6168e6f489a0ecc15390da3832a222e20155164ff72474d6b4615", - "pins" : [ - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections", - "state" : { - "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", - "version" : "1.1.4" - } - } - ], - "version" : 3 -} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/App.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/App.swift deleted file mode 100644 index 7cb2ea61..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/App.swift +++ /dev/null @@ -1,10 +0,0 @@ -import SwiftUI - -@main -struct MyApp: App { - var body: some Scene { - WindowGroup { - ContentView() - } - } -} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/ContentView.swift deleted file mode 100644 index bcdf9eae..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/App/Sources/ContentView.swift +++ /dev/null @@ -1,13 +0,0 @@ -import LocalSwiftPackage -import SwiftUI - -public struct ContentView: View { - public init() { - _ = LocalSwiftPackage() - } - - public var body: some View { - Text("Hello, World!") - .padding() - } -} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Package.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Package.swift deleted file mode 100644 index 16ec68c6..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Package.swift +++ /dev/null @@ -1,21 +0,0 @@ -// swift-tools-version: 5.10 - -import PackageDescription - -let package = Package( - name: "LocalSwiftPackage", - products: [ - .library(name: "LocalSwiftPackage", targets: ["LocalSwiftPackage"]), - ], - dependencies: [ - .package(url: "https://github.com/apple/swift-collections", from: "1.0.0"), - ], - targets: [ - .target( - name: "LocalSwiftPackage", - dependencies: [ - .product(name: "Collections", package: "swift-collections"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift deleted file mode 100644 index 3d455074..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/LocalSwiftPackage/Sources/LocalSwiftPackage/LocalSwiftPackage.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Collections - -public final class LocalSwiftPackage { - public init() {} - public var deque: Deque = [] -} diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/Project.swift b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/Project.swift deleted file mode 100644 index 96abc5b9..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/Project.swift +++ /dev/null @@ -1,29 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "App", - packages: [ - .package(path: "LocalSwiftPackage"), - ], - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: .extendingDefault( - with: [ - "UILaunchScreen": [ - "UIColorName": "", - "UIImageName": "", - ], - ] - ), - sources: ["App/Sources/**"], - resources: [], - dependencies: [ - .package(product: "LocalSwiftPackage"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/README.md b/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/README.md deleted file mode 100644 index a5b09eb1..00000000 --- a/Sources/TestSupport/Fixtures/app_with_local_spm_module_with_remote_dependencies/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Application wih Local SPM Module with Remote Dependencies - -This example contains a project that depends upon a local SPM module (`LocalSwiftPackage`) colocated within this directory. - -This project does NOT contain any direct remote dependencies. -However, `LocalSwiftPackage` DOES have remote dependencies. - -This example application exists to ensure that package resolution occurs even in the case of solely transitive remote dependencies. \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift deleted file mode 100644 index 81c349d7..00000000 --- a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift +++ /dev/null @@ -1,4 +0,0 @@ -import DynamicFramework -import Foundation - -let dynamicClass = DynamicFramework() diff --git a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift deleted file mode 100644 index 85f562cc..00000000 --- a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -public struct DynamicFramework { - public init() {} -} diff --git a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Project.swift b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Project.swift deleted file mode 100644 index 137199a9..00000000 --- a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Project.swift +++ /dev/null @@ -1,26 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "CommandLineTool", - targets: [ - .target( - name: "CommandLineTool", - destinations: [.mac], - product: .commandLineTool, - bundleId: "com.example.commandlinetool", - infoPlist: .default, - sources: "CommandLineTool/**", - dependencies: [ - .target(name: "DynamicFramework"), - ] - ), - .target( - name: "DynamicFramework", - destinations: [.mac], - product: .framework, - bundleId: "com.example.dynamicframework", - infoPlist: .default, - sources: "DynamicFramework/**" - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Tuist/Config.swift b/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Tuist/Config.swift deleted file mode 100644 index ff8e64fa..00000000 --- a/Sources/TestSupport/Fixtures/command_line_tool_with_dynamic_framework/Tuist/Config.swift +++ /dev/null @@ -1,3 +0,0 @@ -import ProjectDescription - -let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_large/Info.plist b/Sources/TestSupport/Fixtures/ios_app_large/Info.plist deleted file mode 100644 index c407fafb..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_large/Info.plist +++ /dev/null @@ -1,43 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - NSHumanReadableCopyright - Copyright ©. All rights reserved. - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Sources/TestSupport/Fixtures/ios_app_large/Project.swift b/Sources/TestSupport/Fixtures/ios_app_large/Project.swift deleted file mode 100644 index 225feb0e..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_large/Project.swift +++ /dev/null @@ -1,18 +0,0 @@ -import ProjectDescription - -func target(name: String) -> Target { - .target( - name: name, - destinations: .iOS, - product: .app, - bundleId: "io.tuist.\(name)", - infoPlist: .file(path: .relativeToManifest("Info.plist")), - sources: .paths([.relativeToManifest("Sources/**")]), - settings: .settings(base: ["CODE_SIGN_IDENTITY": "", "CODE_SIGNING_REQUIRED": "NO"]) - ) -} - -let project = Project( - name: "App", - targets: (1 ... 300).map { target(name: "App\($0)") } -) diff --git a/Sources/TestSupport/Fixtures/ios_app_large/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_large/Sources/AppDelegate.swift deleted file mode 100644 index c20f5076..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_large/Sources/AppDelegate.swift +++ /dev/null @@ -1,21 +0,0 @@ -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? - - func application( - _: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() - return true - } - - func hello() -> String { - "AppDelegate.hello()" - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_large/Tests.plist b/Sources/TestSupport/Fixtures/ios_app_large/Tests.plist deleted file mode 100644 index f1d34193..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_large/Tests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright ©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_app_large/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_app_large/Tuist/Config.swift deleted file mode 100644 index ff8e64fa..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_large/Tuist/Config.swift +++ /dev/null @@ -1,3 +0,0 @@ -import ProjectDescription - -let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift deleted file mode 100644 index ff50fc5f..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift +++ /dev/null @@ -1,9 +0,0 @@ -import AppIntents - -struct AppIntentExtension: AppIntent { - static var title: LocalizedStringResource = "AppIntentExtension" - - func perform() async throws -> some IntentResult { - .result() - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift deleted file mode 100644 index 1fbdaa9a..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift +++ /dev/null @@ -1,6 +0,0 @@ -import AppIntents - -@main -struct AppIntentExtensionExtension: AppIntentsExtension { - // No implementation -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Bundle/dummy.jpg b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Bundle/dummy.jpg deleted file mode 100644 index e69de29b..00000000 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Info.plist deleted file mode 100644 index c407fafb..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Info.plist +++ /dev/null @@ -1,43 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - NSHumanReadableCopyright - Copyright ©. All rights reserved. - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/iMessage App Icon.stickersiconset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/iMessage App Icon.stickersiconset/Contents.json deleted file mode 100644 index bc3c4eea..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets/iMessage App Icon.stickersiconset/Contents.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x45" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x45" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "67x50" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "74x55" - }, - { - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - }, - { - "idiom" : "universal", - "platform" : "ios", - "scale" : "2x", - "size" : "27x20" - }, - { - "idiom" : "universal", - "platform" : "ios", - "scale" : "3x", - "size" : "27x20" - }, - { - "idiom" : "universal", - "platform" : "ios", - "scale" : "2x", - "size" : "32x24" - }, - { - "idiom" : "universal", - "platform" : "ios", - "scale" : "3x", - "size" : "32x24" - }, - { - "idiom" : "ios-marketing", - "platform" : "ios", - "scale" : "1x", - "size" : "1024x768" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard deleted file mode 100644 index 36e2d491..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift deleted file mode 100644 index c0164553..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift +++ /dev/null @@ -1,52 +0,0 @@ -import Messages -import UIKit - -class MessagesViewController: MSMessagesAppViewController { - // MARK: - Conversation Handling - - override func willBecomeActive(with _: MSConversation) { - // Called when the extension is about to move from the inactive to active state. - // This will happen when the extension is about to present UI. - - // Use this method to configure the extension and restore previously stored state. - } - - override func didResignActive(with _: MSConversation) { - // Called when the extension is about to move from the active to inactive state. - // This will happen when the user dismisses the extension, changes to a different - // conversation or quits Messages. - - // Use this method to release shared resources, save user data, invalidate timers, - // and store enough state information to restore your extension to its current state - // in case it is terminated later. - } - - override func didReceive(_: MSMessage, conversation _: MSConversation) { - // Called when a message arrives that was generated by another instance of this - // extension on a remote device. - - // Use this method to trigger UI updates in response to the message. - } - - override func didStartSending(_: MSMessage, conversation _: MSConversation) { - // Called when the user taps the send button. - } - - override func didCancelSending(_: MSMessage, conversation _: MSConversation) { - // Called when the user deletes the message without sending it. - - // Use this to clean up state related to the deleted message. - } - - override func willTransition(to _: MSMessagesAppPresentationStyle) { - // Called before the extension transitions to a new presentation style. - - // Use this method to prepare for the change in presentation style. - } - - override func didTransition(to _: MSMessagesAppPresentationStyle) { - // Called after the extension transitions to a new presentation style. - - // Use this method to finalize any behaviors associated with the change in presentation style. - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift deleted file mode 100644 index b6b54e84..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift +++ /dev/null @@ -1,30 +0,0 @@ -import UserNotifications - -class NotificationService: UNNotificationServiceExtension { - var contentHandler: ((UNNotificationContent) -> Void)? - var bestAttemptContent: UNMutableNotificationContent? - - override func didReceive( - _ request: UNNotificationRequest, - withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void - ) { - self.contentHandler = contentHandler - bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) - - if let bestAttemptContent { - // Modify the notification content here... - bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" - - contentHandler(bestAttemptContent) - } - } - - override func serviceExtensionTimeWillExpire() { - // Called just before the extension will be terminated by the system. - // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will - // be used. - if let contentHandler, let bestAttemptContent { - contentHandler(bestAttemptContent) - } - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Project.swift deleted file mode 100644 index 194d9ba5..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Project.swift +++ /dev/null @@ -1,128 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "App", - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: "Info.plist", - sources: ["Sources/**"], - dependencies: [ - .target(name: "StickersPackExtension"), - .target(name: "NotificationServiceExtension"), - .target(name: "WidgetExtension"), - .target(name: "AppIntentExtension"), - ] - ), - // We need a separate app to test out Message Extensions - // as having both stickers pack and message extensions in one app - // doesn't seem to be supported. - .target( - name: "AppWithMessagesExtension", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App2", - infoPlist: "Info.plist", - sources: ["Sources/**"], - dependencies: [ - .target(name: "MessageExtension"), - .target(name: "NotificationServiceExtension"), - ] - ), - .target( - name: "StickersPackExtension", - destinations: .iOS, - product: .stickerPackExtension, - bundleId: "io.tuist.App.StickersPackExtension", - infoPlist: .extendingDefault(with: [ - "CFBundleDisplayName": "$(PRODUCT_NAME)", - "NSExtension": [ - "NSExtensionPointIdentifier": "com.apple.message-payload-provider", - "NSExtensionPrincipalClass": "StickerBrowserViewController", - ], - ]), - sources: [], - resources: ["StickersPackExtension/**"], - dependencies: [] - ), - .target( - name: "NotificationServiceExtension", - destinations: .iOS, - product: .appExtension, - bundleId: "io.tuist.App.NotificationServiceExtension", - infoPlist: .extendingDefault(with: [ - "CFBundleDisplayName": "$(PRODUCT_NAME)", - "NSExtension": [ - "NSExtensionPointIdentifier": "com.apple.usernotifications.service", - "NSExtensionPrincipalClass": "$(PRODUCT_MODULE_NAME).NotificationService", - ], - ]), - sources: "NotificationServiceExtension/**", - dependencies: [] - ), - .target( - name: "MessageExtension", - destinations: .iOS, - product: .messagesExtension, - bundleId: "io.tuist.App2.MessageExtension", - infoPlist: .extendingDefault(with: [ - "CFBundleDisplayName": "$(PRODUCT_NAME)", - "NSExtension": [ - "NSExtensionMainStoryboard": "MainInterface", - "NSExtensionPointIdentifier": "com.apple.message-payload-provider", - ], - ]), - sources: "MessageExtension/Sources/**", - resources: "MessageExtension/Resources/**", - dependencies: [] - ), - .target( - name: "WidgetExtension", - destinations: .iOS, - product: .appExtension, - bundleId: "io.tuist.App.WidgetExtension", - infoPlist: .extendingDefault(with: [ - "CFBundleDisplayName": "$(PRODUCT_NAME)", - "NSExtension": [ - "NSExtensionPointIdentifier": "com.apple.widgetkit-extension", - ], - ]), - sources: "WidgetExtension/Sources/**", - resources: "WidgetExtension/Resources/**", - dependencies: [ - .target(name: "Bundle"), - .target(name: "StaticFramework"), - ] - ), - .target( - name: "StaticFramework", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.App.StaticFramework", - infoPlist: .default, - sources: "StaticFramework/Sources/**" - ), - .target( - name: "AppIntentExtension", - destinations: .iOS, - product: .extensionKitExtension, - bundleId: "io.tuist.App.AppIntentExtension", - infoPlist: .extendingDefault(with: [ - "EXAppExtensionAttributes": [ - "EXExtensionPointIdentifier": "com.apple.appintents-extension", - ], - ]), - sources: "AppIntentExtension/Sources/**" - ), - .target( - name: "Bundle", - destinations: .iOS, - product: .bundle, - bundleId: "io.tuist.App.Bundle", - resources: "Bundle/**" - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/README.md b/Sources/TestSupport/Fixtures/ios_app_with_extensions/README.md deleted file mode 100644 index ec28324e..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# iOS app with extensions - -Sample iOS application with extension targets. \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift deleted file mode 100644 index 19603be9..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift +++ /dev/null @@ -1,18 +0,0 @@ -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? - - func application( - _: UIApplication, - didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() - return true - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/Documentation.docc/Documentation.md b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/Documentation.docc/Documentation.md deleted file mode 100644 index e7a804b3..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Sources/Documentation.docc/Documentation.md +++ /dev/null @@ -1,13 +0,0 @@ -# ``App`` - -Summary - -## Overview - -Text - -## Topics - -### Group - -- ``Symbol`` \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift deleted file mode 100644 index 60900e58..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -public struct StaticFramework { - public init() {} -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Contents.json deleted file mode 100644 index da4a164c..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Sticker Pack.stickerpack/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Sticker Pack.stickerpack/Contents.json deleted file mode 100644 index 1b6728ea..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/Sticker Pack.stickerpack/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "grid-size" : "regular" - } -} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/iMessage App Icon.stickersiconset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/iMessage App Icon.stickersiconset/Contents.json deleted file mode 100644 index 28c5ac36..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets/iMessage App Icon.stickersiconset/Contents.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x45", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x45", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "67x50", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "74x55", - "scale" : "2x" - }, - { - "idiom" : "ios-marketing", - "size" : "1024x1024", - "scale" : "1x" - }, - { - "size" : "27x20", - "idiom" : "universal", - "scale" : "2x", - "platform" : "ios" - }, - { - "size" : "27x20", - "idiom" : "universal", - "scale" : "3x", - "platform" : "ios" - }, - { - "size" : "32x24", - "idiom" : "universal", - "scale" : "2x", - "platform" : "ios" - }, - { - "size" : "32x24", - "idiom" : "universal", - "scale" : "3x", - "platform" : "ios" - }, - { - "size" : "1024x768", - "idiom" : "ios-marketing", - "scale" : "1x", - "platform" : "ios" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/Tuist/Config.swift deleted file mode 100644 index ff8e64fa..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/Tuist/Config.swift +++ /dev/null @@ -1,3 +0,0 @@ -import ProjectDescription - -let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AccentColor.colorset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb878970..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 9221b9bb..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/WidgetBackground.colorset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/WidgetBackground.colorset/Contents.json deleted file mode 100644 index eb878970..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets/WidgetBackground.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift b/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift deleted file mode 100644 index eac88f57..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift +++ /dev/null @@ -1,69 +0,0 @@ -#if canImport(WidgetKit) - - import SwiftUI - import WidgetKit - - struct Provider: TimelineProvider { - public typealias Entry = SimpleEntry - - func placeholder(in _: Context) -> SimpleEntry { - SimpleEntry(date: Date()) - } - - func getSnapshot(in _: Context, completion _: @escaping (SimpleEntry) -> Void) {} - - func getTimeline(in _: Context, completion _: @escaping (Timeline) -> Void) {} - - public func snapshot(with _: Context, completion: @escaping (SimpleEntry) -> Void) { - let entry = SimpleEntry(date: Date()) - completion(entry) - } - - public func timeline(with _: Context, completion: @escaping (Timeline) -> Void) { - var entries: [SimpleEntry] = [] - - // Generate a timeline consisting of five entries an hour apart, starting from the current date. - let currentDate = Date() - for hourOffset in 0 ..< 5 { - let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! - let entry = SimpleEntry(date: entryDate) - entries.append(entry) - } - - let timeline = Timeline(entries: entries, policy: .atEnd) - completion(timeline) - } - } - - struct SimpleEntry: TimelineEntry { - public let date: Date - } - - struct PlaceholderView: View { - var body: some View { - Text("Placeholder View") - } - } - - struct MyWidgetEntryView: View { - var entry: Provider.Entry - - var body: some View { - Text(entry.date, style: .time) - } - } - - @main - struct MyWidget: Widget { - private let kind: String = "MyWidget" - - public var body: some WidgetConfiguration { - StaticConfiguration(kind: kind, provider: Provider()) { entry in - MyWidgetEntryView(entry: entry) - } - .configurationDisplayName("MyWidget") - .description("This is an example widget.") - } - } - -#endif diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Project.swift deleted file mode 100644 index fe92251b..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Project.swift +++ /dev/null @@ -1,62 +0,0 @@ -import ProjectDescription - -let settings: Settings = .settings( - base: [ - "PROJECT_BASE": "PROJECT_BASE", - ], - configurations: [ - .debug(name: "Debug", xcconfig: "../ConfigurationFiles/Debug.xcconfig"), - .release(name: "Beta", xcconfig: "../ConfigurationFiles/Beta.xcconfig"), - .release(name: "Release", xcconfig: "../ConfigurationFiles/Release.xcconfig"), - ] -) - -let betaScheme: Scheme = .scheme( - name: "App-Beta", - shared: true, - buildAction: .buildAction(targets: ["App"]), - runAction: .runAction(configuration: "Beta", executable: "App"), - archiveAction: .archiveAction(configuration: "Beta"), - profileAction: .profileAction(configuration: "Release", executable: "App"), - analyzeAction: .analyzeAction(configuration: "Debug") -) - -let betaArchiveOnlyScheme: Scheme = .scheme( - name: "App-Beta-ArchiveOnly", - shared: true, - archiveAction: .archiveAction(configuration: "Beta") -) - -let project = Project( - name: "MainApp", - settings: settings, - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: "Support/App-Info.plist", - sources: "Sources/**", - dependencies: [ - .project(target: "Framework1", path: "../Framework1"), - .project(target: "Framework2", path: "../Framework2"), - ] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.AppTests", - infoPlist: "Support/AppTests-Info.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "App"), - ] - ), - ], - schemes: [ - betaScheme, - betaArchiveOnlyScheme, - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift deleted file mode 100644 index 7c643d2c..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Framework1 -import Framework2 -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? - - func applicationDidFinishLaunching(_: UIApplication) { - let framework1 = Framework1File() - let framework2 = Framework2File() - - print(hello()) - - print("AppDelegate -> \(framework1.hello())") - print("AppDelegate -> \(framework1.helloFromFramework2())") - print("AppDelegate -> \(framework2.hello())") - } - - func hello() -> String { - "AppDelegate.hello()" - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist deleted file mode 100644 index 314db985..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist +++ /dev/null @@ -1,43 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - NSHumanReadableCopyright - Copyright Tuist©. All rights reserved. - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist deleted file mode 100644 index 6c40a6cd..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift deleted file mode 100644 index 27fb5d7e..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift +++ /dev/null @@ -1,11 +0,0 @@ -import XCTest - -@testable import App - -class AppDelegateTests: XCTestCase { - func testHello() { - let sut = AppDelegate() - - XCTAssertEqual("AppDelegate.hello()", sut.hello()) - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig deleted file mode 100644 index 1251f45d..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ - -CUSTOM_FLAG = "Beta" \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig deleted file mode 100644 index 12491216..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ - -CUSTOM_FLAG = "Debug" \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig deleted file mode 100644 index 5f758db5..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ - -CUSTOM_FLAG = "Release" \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig deleted file mode 100644 index 85a46af1..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ - -CUSTOM_FLAG = "Target.Beta" \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Debug.xcconfig b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Debug.xcconfig deleted file mode 100644 index 0171c5c6..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ - -CUSTOM_FLAG = "Target.Debug" \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Release.xcconfig b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Release.xcconfig deleted file mode 100644 index fc53c985..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ - -CUSTOM_FLAG = "Target.Release" \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Project.swift deleted file mode 100644 index f275b144..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Project.swift +++ /dev/null @@ -1,43 +0,0 @@ -import ProjectDescription - -let settings: Settings = .settings( - base: [ - "PROJECT_BASE": "PROJECT_BASE", - ], - configurations: [ - .debug(name: "Debug", xcconfig: "../ConfigurationFiles/Debug.xcconfig"), - .release(name: "Beta", xcconfig: "../ConfigurationFiles/Beta.xcconfig"), - .release(name: "Release", xcconfig: "../ConfigurationFiles/Release.xcconfig"), - ] -) - -let project = Project( - name: "Framework1", - settings: settings, - targets: [ - .target( - name: "Framework1", - destinations: .iOS, - product: .framework, - productName: "Framework1", - bundleId: "io.tuist.Framework1", - infoPlist: "Support/Framework1-Info.plist", - sources: "Sources/**", - dependencies: [ - .project(target: "Framework2", path: "../Framework2"), - ] - ), - .target( - name: "Framework1Tests", - destinations: .iOS, - product: .unitTests, - productName: "Framework1Tests", - bundleId: "io.tuist.Framework1Tests", - infoPlist: "Support/Framework1Tests-Info.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "Framework1"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift deleted file mode 100644 index 6a448706..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation -import Framework2 - -public class Framework1File { - private let framework2File = Framework2File() - - public init() {} - - public func hello() -> String { - "Framework1File.hello()" - } - - public func helloFromFramework2() -> String { - "Framework1File -> \(framework2File.hello())" - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist deleted file mode 100644 index 3c29058d..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright Tuist©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist deleted file mode 100644 index 6c40a6cd..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift deleted file mode 100644 index 8086614a..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift +++ /dev/null @@ -1,17 +0,0 @@ -import XCTest - -@testable import Framework1 - -class Framework1Tests: XCTestCase { - func testHello() { - let sut = Framework1File() - - XCTAssertEqual("Framework1File.hello()", sut.hello()) - } - - func testHelloFromFramework2() { - let sut = Framework1File() - - XCTAssertEqual("Framework1File -> Framework2File.hello()", sut.helloFromFramework2()) - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Project.swift deleted file mode 100644 index bbec1c7f..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Project.swift +++ /dev/null @@ -1,47 +0,0 @@ -import ProjectDescription - -let settings: Settings = .settings( - configurations: [ - .debug(name: "Debug", xcconfig: "../ConfigurationFiles/Debug.xcconfig"), - .release(name: "Beta", xcconfig: "../ConfigurationFiles/Beta.xcconfig"), - .release(name: "Release", xcconfig: "../ConfigurationFiles/Release.xcconfig"), - ] -) - -// Targets can override select configurations if needed -let targetSettings: Settings = .settings( - base: [ - "TARGET_BASE": "TARGET_BASE", - ], - configurations: [ - .release(name: "Beta", xcconfig: "../ConfigurationFiles/Target.Beta.xcconfig"), - ] -) - -let project = Project( - name: "Framework2", - settings: settings, - targets: [ - .target( - name: "Framework2", - destinations: .iOS, - product: .framework, - bundleId: "io.tuist.Framework2", - infoPlist: "Support/Framework2-Info.plist", - sources: "Sources/**", - dependencies: [], - settings: targetSettings - ), - .target( - name: "Framework2Tests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.Framework2Tests", - infoPlist: "Support/Framework2Tests-Info.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "Framework2"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift deleted file mode 100644 index 62754f40..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation - -public class Framework2File { - public init() {} - - public func hello() -> String { - "Framework2File.hello()" - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist deleted file mode 100644 index 3c29058d..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright Tuist©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist deleted file mode 100644 index 6c40a6cd..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift deleted file mode 100644 index c5f88aba..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift +++ /dev/null @@ -1,11 +0,0 @@ -import XCTest - -@testable import Framework2 - -class Framework2Tests: XCTestCase { - func testHello() { - let sut = Framework2File() - - XCTAssertEqual("Framework2File.hello()", sut.hello()) - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/README.md b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/README.md deleted file mode 100644 index f2f40c42..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# iOS app with multiple configurations and an xcconfig - -A workspace that contains an application and frameworks that leverage multiple configurations (Debug, Beta and Release) each of which also has an associated xcconfig file within `ConfigurationFiles`. \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Tuist/Config.swift deleted file mode 100644 index ff8e64fa..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Tuist/Config.swift +++ /dev/null @@ -1,3 +0,0 @@ -import ProjectDescription - -let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Workspace.swift b/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Workspace.swift deleted file mode 100644 index 929bf3b5..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_multi_configs/Workspace.swift +++ /dev/null @@ -1,6 +0,0 @@ -import ProjectDescription - -let workspace = Workspace( - name: "Workspace", - projects: ["App", "Framework1", "Framework2"] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/.package.resolved b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/.package.resolved deleted file mode 100644 index 6e3d7b59..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/.package.resolved +++ /dev/null @@ -1,16 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "RxSwift", - "repositoryURL": "https://github.com/ReactiveX/RxSwift", - "state": { - "branch": null, - "revision": "b3e888b4972d9bc76495dd74d30a8c7fad4b9395", - "version": "5.0.1" - } - } - ] - }, - "version": 1 -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Package.resolved b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Package.resolved deleted file mode 100644 index 6e3d7b59..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Package.resolved +++ /dev/null @@ -1,16 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "RxSwift", - "repositoryURL": "https://github.com/ReactiveX/RxSwift", - "state": { - "branch": null, - "revision": "b3e888b4972d9bc76495dd74d30a8c7fad4b9395", - "version": "5.0.1" - } - } - ] - }, - "version": 1 -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Project.swift deleted file mode 100644 index 68086b05..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Project.swift +++ /dev/null @@ -1,37 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "App", - packages: [ - .package(url: "https://github.com/ReactiveX/RxSwift", .upToNextMajor(from: "5.0.0")), - ], - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: "Support/Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ], - dependencies: [ - .package(product: "RxSwift"), - .package(product: "RxBlocking"), - ] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.AppTests", - infoPlist: "Support/Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "App"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/README.md b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/README.md deleted file mode 100644 index 14993460..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# iOS App with a remote Swift package - -An iOS application with a remote Swift package. \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift deleted file mode 100644 index 034e8222..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift +++ /dev/null @@ -1,25 +0,0 @@ -import RxBlocking -import RxSwift -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? - - func application( - _: UIApplication, - didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - // To make sure RxSwift is available - let observable = RxSwift.Observable.just("Test") - - let result = RxBlocking.MaterializedSequenceResult.completed(elements: [1, 2]) - - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() - return true - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Info.plist deleted file mode 100644 index c407fafb..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Info.plist +++ /dev/null @@ -1,43 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - NSHumanReadableCopyright - Copyright ©. All rights reserved. - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist deleted file mode 100644 index f1d34193..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright ©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift deleted file mode 100644 index 12be2987..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation -import XCTest - -@testable import App - -final class AppTests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tuist/Config.swift deleted file mode 100644 index ff8e64fa..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_remote_swift_package/Tuist/Config.swift +++ /dev/null @@ -1,3 +0,0 @@ -import ProjectDescription - -let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb878970..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 13613e3e..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets/Contents.json b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift deleted file mode 100644 index 1295f66a..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift +++ /dev/null @@ -1,10 +0,0 @@ -import SwiftUI - -@main -struct AppApp: App { - var body: some Scene { - WindowGroup { - ContentView() - } - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift deleted file mode 100644 index 8641548a..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift +++ /dev/null @@ -1,30 +0,0 @@ -import Buy -import JWTKit -import KSCrashInstallations -import Pay -import SwiftUI - -struct ContentView: View { - init() { - // Use Mobile Buy SDK - _ = Card.CreditCard(firstName: "", lastName: "", number: "", expiryMonth: "", expiryYear: "") - _ = PayAddress() - // Use KSCrash - _ = CrashInstallationStandard() - // Use JWTKit - _ = JWTKit.ES256PrivateKey() - } - - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - Text("Hello, world!") - } - .padding() - } -} - -#Preview { - ContentView() -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift deleted file mode 100644 index 3413db38..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift +++ /dev/null @@ -1,21 +0,0 @@ -import XCTest - -@testable import App - -final class AppTests: XCTestCase { - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Project.swift deleted file mode 100644 index d23b92ff..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Project.swift +++ /dev/null @@ -1,34 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "App", - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.app", - deploymentTargets: .iOS("16.0"), - infoPlist: .default, - sources: "App/Sources/**", - resources: "App/Resources/**", - dependencies: [ - .external(name: "Buy"), - .external(name: "Pay"), - .external(name: "Installations"), - .external(name: "JWTKit"), - .sdk(name: "c++", type: .library, status: .required), - ] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.app.tests", - deploymentTargets: .iOS("16.0"), - infoPlist: .default, - sources: "AppTests/**", - dependencies: [.target(name: "App")] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/README.md b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/README.md deleted file mode 100644 index 2b052bf2..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# iOS app with SPM dependencies - -An iOS application project with various SPM dependencies. \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.resolved b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.resolved deleted file mode 100644 index a875c203..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.resolved +++ /dev/null @@ -1,69 +0,0 @@ -{ - "originHash" : "57e8e560522d98da034eecf136da2a0571e102267ae8fa09d2264359afbe28cd", - "pins" : [ - { - "identity" : "bigint", - "kind" : "remoteSourceControl", - "location" : "https://github.com/attaswift/BigInt.git", - "state" : { - "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", - "version" : "5.3.0" - } - }, - { - "identity" : "jwt-kit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/vapor/jwt-kit.git", - "state" : { - "revision" : "6f512cb5a531e684f2e5238924be81db0b3303b4", - "version" : "5.0.0-beta.3" - } - }, - { - "identity" : "kscrash", - "kind" : "remoteSourceControl", - "location" : "https://github.com/kstenerud/KSCrash", - "state" : { - "revision" : "353a7ea8f32e34b9008dd7aa6dc0b6466b7daf37", - "version" : "2.0.0-rc.3" - } - }, - { - "identity" : "mobile-buy-sdk-ios", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Shopify/mobile-buy-sdk-ios", - "state" : { - "revision" : "6bd23c2f6243f73ef6ec135723d4909bc068409e", - "version" : "12.0.0" - } - }, - { - "identity" : "swift-asn1", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-asn1.git", - "state" : { - "revision" : "c7e239b5c1492ffc3ebd7fbcc7a92548ce4e78f0", - "version" : "1.1.0" - } - }, - { - "identity" : "swift-certificates", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-certificates.git", - "state" : { - "revision" : "83640c8097acaec17c9835a083e89678cb0f2b66", - "version" : "1.3.0" - } - }, - { - "identity" : "swift-crypto", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-crypto.git", - "state" : { - "revision" : "bc1c29221f6dfeb0ebbfbc98eb95cd3d4967868e", - "version" : "3.4.0" - } - } - ], - "version" : 3 -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.swift b/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.swift deleted file mode 100644 index fc630526..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_spm_dependencies/Tuist/Package.swift +++ /dev/null @@ -1,14 +0,0 @@ -// swift-tools-version: 5.10 -@preconcurrency import PackageDescription - -let package = Package( - name: "PackageName", - dependencies: [ - // Has space symbols in package name - .package(url: "https://github.com/Shopify/mobile-buy-sdk-ios", exact: "12.0.0"), - // Has targets with slash symbols in their names - .package(url: "https://github.com/kstenerud/KSCrash", exact: "2.0.0-rc.3"), - // Has custom `swiftSettings` and uses the package access level - .package(url: "https://github.com/vapor/jwt-kit.git", .upToNextMajor(from: "5.0.0-beta.2.1")), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Info.plist deleted file mode 100755 index c407fafb..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Info.plist +++ /dev/null @@ -1,43 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - NSHumanReadableCopyright - Copyright ©. All rights reserved. - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/CustomHeaders/CustomHeader.h b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/CustomHeaders/CustomHeader.h deleted file mode 100644 index e69de29b..00000000 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/Contents.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/Contents.swift deleted file mode 100755 index fecc4ab4..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/Contents.swift +++ /dev/null @@ -1 +0,0 @@ -import Foundation diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/contents.xcplayground b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/contents.xcplayground deleted file mode 100755 index 4e6c0b72..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Playgrounds/A.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Project.swift deleted file mode 100755 index 9dfa3e4a..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Project.swift +++ /dev/null @@ -1,36 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "A", - targets: [ - .target( - name: "A", - destinations: .iOS, - product: .staticLibrary, - bundleId: "io.tuist.A", - infoPlist: nil, - sources: "Sources/**", - dependencies: [ - .project(target: "B", path: "../B"), - .library( - path: "../C/prebuilt/C/libC.a", - publicHeaders: "../C/prebuilt/C", - swiftModuleMap: "../C/prebuilt/C/C.swiftmodule" - ), - ], - - settings: .settings(base: ["HEADER_SEARCH_PATHS": "$(SRCROOT)/CustomHeaders"]) - ), - .target( - name: "ATests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.ATests", - infoPlist: nil, - sources: "Tests/**", - dependencies: [ - .target(name: "A"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift deleted file mode 100755 index a9cd1519..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift +++ /dev/null @@ -1,12 +0,0 @@ -import B -import C - -public enum A { - public static let value: String = "aValue" - - public static func printFromA() { - print("print from A") - B.printFromB() - C.printFromC() - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift deleted file mode 100755 index 974713b4..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift +++ /dev/null @@ -1,10 +0,0 @@ -import Foundation -import XCTest - -@testable import A - -final class ATests: XCTestCase { - func test_value() { - XCTAssertEqual(A.value, "aValue") - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist deleted file mode 100755 index a11b3ce7..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright ©. All rights reserved. - NSPrincipalClass - - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/Contents.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/Contents.swift deleted file mode 100755 index fecc4ab4..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/Contents.swift +++ /dev/null @@ -1 +0,0 @@ -import Foundation diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/contents.xcplayground b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/contents.xcplayground deleted file mode 100755 index 4e6c0b72..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Playgrounds/B.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Project.swift deleted file mode 100755 index 50e3d978..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Project.swift +++ /dev/null @@ -1,30 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "B", - targets: [ - .target( - name: "B", - destinations: .iOS, - product: .staticLibrary, - bundleId: "io.tuist.B", - infoPlist: "Info.plist", - sources: "Sources/**", - dependencies: [ - /* Target dependencies can be defined here */ - /* .framework(path: "framework") */ - ] - ), - .target( - name: "BTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.BTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "B"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift deleted file mode 100755 index 92fcf9d6..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation - -public enum B { - public static let value: String = "bValue" - - public static func printFromB() { - print("print from B") - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist deleted file mode 100755 index f1d34193..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright ©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift deleted file mode 100755 index 718b056f..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift +++ /dev/null @@ -1,10 +0,0 @@ -import Foundation -import XCTest - -@testable import B - -final class BTests: XCTestCase { - func test_value() { - XCTAssertEqual(B.value, "bValue") - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Info.plist deleted file mode 100755 index a11b3ce7..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright ©. All rights reserved. - NSPrincipalClass - - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Project.swift deleted file mode 100755 index c78a1249..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Project.swift +++ /dev/null @@ -1,31 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "C", - targets: [ - .target( - name: "C", - destinations: .iOS, - product: .staticLibrary, - bundleId: "io.tuist.C", - infoPlist: "Info.plist", - sources: "Sources/**", - dependencies: [ - /* Target dependencies can be defined here */ - /* .framework(path: "framework") */ - ], - settings: .settings(base: ["BUILD_LIBRARY_FOR_DISTRIBUTION": "YES"]) - ), - .target( - name: "CTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.BTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "C"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Sources/C.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Sources/C.swift deleted file mode 100755 index 7d7ac4ce..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Sources/C.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation - -public enum C { - public static let value: String = "cValue" - - public static func printFromC() { - print("print from C") - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests.plist b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests.plist deleted file mode 100755 index f1d34193..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright ©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests/CTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests/CTests.swift deleted file mode 100755 index 0e81b037..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/Tests/CTests.swift +++ /dev/null @@ -1,10 +0,0 @@ -import Foundation -import XCTest - -@testable import C - -final class BTests: XCTestCase { - func test_value() { - XCTAssertEqual(C.value, "cValue") - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/build.sh b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/build.sh deleted file mode 100755 index e038b4bc..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/build.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -rm -rf prebuilt -tuist generate --no-open - -TEMP_DIR="/tmp/tuist-lib-c-fixture" -IPHONE_SIM_DIR="$TEMP_DIR/Build/Products/Debug-iphonesimulator" - -rm -rf $TEMP_DIR -mkdir -p $TEMP_DIR - -xcrun xcodebuild build -scheme C -workspace C.xcworkspace -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone 14 Pro,OS=latest" -derivedDataPath $TEMP_DIR ONLY_ACTIVE_ARCH=NO - -mkdir -p prebuilt/C -lipo -create \ - "$IPHONE_SIM_DIR/libC.a" \ - -output "$(pwd)/prebuilt/C/libC.a" - -mkdir -p prebuilt/C/C.swiftmodule -cp -r \ - "$IPHONE_SIM_DIR/C.swiftmodule/"* \ - "$(pwd)/prebuilt/C/C.swiftmodule/" - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo deleted file mode 100644 index a4b1292a8854a772a656dfb447ecf620369443bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1084 zcmbVK&rcIk5Z-RV;ucNQs2HNLsi?c`@9p-N>4CO{o3ROaA;h}0yRuE8&F;2HqKP&= zcp%zCZ%9xACqdBQjYP7>ghMru@JDzu{R4V%UQ3}~o#fm3-hA_B-g`UEwYP5^0~i*= zFwEtcV`jFS#74@!l_I_g?wyqTi$HAFh)++5ou+&JfY=d;k44Xj`zN_yp^qxeK2EnP zo+z?k1>Kg{~&(y8T@|N|1*(1z9)xK74N064Wvj z!0COPY}owkHrcY1Qw^IwsW8iEC$)jYPJTBr+Q8Y^*ekMXGaEM9!l}9qjrn$OCPsGG zCpL3v!`jK#aqh_GYY7sX#+W_|nzSlRwL-s3Pz@aJ>u?QVzrf!a#ISqdz5P?Umj^z< z;~y7OgIAnC-g{kpP7uy*i~t@l7W1laa#7bTUs*Lwy|Ca5a$!#LktPb}m4&BlJHUy7 zAQ$vy+7VF}1Ww?jC>IndXo)2Oe*lUxACg%GRb};pDTX+SHTC&YUa<-W=*aqA9&8=F z{~CFW&WjSy@&h89@@FvKEmu zK`j!<$Z~Z0?$Yqp6KQCzQx5ZAm^+41II~;8(Dg5!MLHx0ZWw^H-h8AYZ5414-~jX* z(z+G}(gzso22MT7`CqMD3e~s(xZVw%dK7;QKpJ}gUPIan0Ntm*R{)MQiSP{OX0Va& zogCQI>hlshy?I|u#^Vn~p=js})`U@*PcAJ@OrxKKV_$PGs^0UYU|GqR)XB+maT*o6 zxw*3CI#+?U`~N#~DB5`|szcjf|K;D?D35<+!UXbJjUQLbYQ9iZ4c;p0ro|VHLQc(C z=IK(?pIIeCHF=n@G|XChQMcyOrlnYVCY{%34aLwweNf1j^5B#FWT9ka5aZfI4ZZwc J59_y@ diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo deleted file mode 100644 index 23022a2a99268f068c20a4ff4200b2c4dcbc0c03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1084 zcmbVK&rcIk5Z-Qq;ucNQs2HNLsi?bb_h+}iOb>KRxEY%iFN9c^b}QQy+U#x%B${Z` zg9oBL^o9f_a1sO!-bf^COgK~n34esgo;>y7yp}?}I?1>5z4_+Ny!UpR>u=xK1~Dv( zVVJ`<=bPDS5}OIXFJ{Dc0&Y$E#g+8wM4sg0v zA@?kL#Ttu_#^^fERB@^bU(0@H-=b?WvnNxn3SE`yy7gT+mdPWFf~=c;A3is0GPME) zaQeU^8y5GvO}4H0RKucAE4~%9liI{#C$}e$HEV`61hZ+yFNPu!kr%RjBopMb{*0=sd{7D~yf~W?LwrV(lyI6C`G}Ma zOX)y1>`zNlWcuFn$hA{(c)e2&^A60Nz$l#CZD8p7m(L>|k^?saKw57;QjxX>xCF2P zdJSn^ivZ~Z40i)(9_9S6)-8o<3;=F)17{w^p8$}C-oMw7whBP^>F*VQBTXb+L%A7j zw0kETHnsM=gidcf5aO}eBY`jK+JZT$7v|&3%ahaSC*j!F+>5IFA}LT-@+CEyEElIy zp<7$4+l~trSiAqfBZs1$x1u_<{qn73Do!eg=7U{(R diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.abi.json b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.abi.json deleted file mode 100644 index 318b6c33..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.abi.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "ABIRoot": { - "kind": "Root", - "name": "TopLevel", - "printedName": "TopLevel", - "children": [ - { - "kind": "Import", - "name": "Foundation", - "printedName": "Foundation", - "declKind": "Import", - "moduleName": "C" - }, - { - "kind": "TypeDecl", - "name": "C", - "printedName": "C", - "children": [ - { - "kind": "Var", - "name": "value", - "printedName": "value", - "children": [ - { - "kind": "TypeNominal", - "name": "String", - "printedName": "Swift.String", - "usr": "s:SS" - } - ], - "declKind": "Var", - "usr": "s:1CAAO5valueSSvpZ", - "mangledName": "$s1CAAO5valueSSvpZ", - "moduleName": "C", - "static": true, - "declAttributes": [ - "HasInitialValue", - "HasStorage", - "AccessControl" - ], - "isLet": true, - "hasStorage": true, - "accessors": [ - { - "kind": "Accessor", - "name": "Get", - "printedName": "Get()", - "children": [ - { - "kind": "TypeNominal", - "name": "String", - "printedName": "Swift.String", - "usr": "s:SS" - } - ], - "declKind": "Accessor", - "usr": "s:1CAAO5valueSSvgZ", - "mangledName": "$s1CAAO5valueSSvgZ", - "moduleName": "C", - "static": true, - "implicit": true, - "accessorKind": "get" - } - ] - }, - { - "kind": "Function", - "name": "printFromC", - "printedName": "printFromC()", - "children": [ - { - "kind": "TypeNominal", - "name": "Void", - "printedName": "()" - } - ], - "declKind": "Func", - "usr": "s:1CAAO10printFromCyyFZ", - "mangledName": "$s1CAAO10printFromCyyFZ", - "moduleName": "C", - "static": true, - "declAttributes": [ - "AccessControl" - ], - "funcSelfKind": "NonMutating" - } - ], - "declKind": "Enum", - "usr": "s:1CAAO", - "mangledName": "$s1CAAO", - "moduleName": "C", - "declAttributes": [ - "AccessControl" - ] - } - ], - "json_format_version": 8 - }, - "ConstValues": [ - { - "filePath": "\/Users\/df\/Developer\/tuist\/projects\/tuist\/fixtures\/ios_app_with_static_libraries\/Modules\/C\/Sources\/C.swift", - "kind": "StringLiteral", - "offset": 73, - "length": 8, - "value": "\"cValue\"" - } - ] -} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface deleted file mode 100644 index 9ca576a8..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +++ /dev/null @@ -1,12 +0,0 @@ -// swift-interface-format-version: 1.0 -// swift-compiler-version: Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51) -// swift-module-flags: -target arm64-apple-ios16.2-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name C -// swift-module-flags-ignorable: -enable-bare-slash-regex -import Foundation -import Swift -import _Concurrency -import _StringProcessing -public enum C { - public static let value: Swift.String - public static func printFromC() -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/arm64-apple-ios-simulator.swiftdoc deleted file mode 100644 index caeb1b3bbf84dd061b575686f70b5b8ecdfe7062..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 400 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 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.abi.json b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.abi.json deleted file mode 100644 index 318b6c33..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.abi.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "ABIRoot": { - "kind": "Root", - "name": "TopLevel", - "printedName": "TopLevel", - "children": [ - { - "kind": "Import", - "name": "Foundation", - "printedName": "Foundation", - "declKind": "Import", - "moduleName": "C" - }, - { - "kind": "TypeDecl", - "name": "C", - "printedName": "C", - "children": [ - { - "kind": "Var", - "name": "value", - "printedName": "value", - "children": [ - { - "kind": "TypeNominal", - "name": "String", - "printedName": "Swift.String", - "usr": "s:SS" - } - ], - "declKind": "Var", - "usr": "s:1CAAO5valueSSvpZ", - "mangledName": "$s1CAAO5valueSSvpZ", - "moduleName": "C", - "static": true, - "declAttributes": [ - "HasInitialValue", - "HasStorage", - "AccessControl" - ], - "isLet": true, - "hasStorage": true, - "accessors": [ - { - "kind": "Accessor", - "name": "Get", - "printedName": "Get()", - "children": [ - { - "kind": "TypeNominal", - "name": "String", - "printedName": "Swift.String", - "usr": "s:SS" - } - ], - "declKind": "Accessor", - "usr": "s:1CAAO5valueSSvgZ", - "mangledName": "$s1CAAO5valueSSvgZ", - "moduleName": "C", - "static": true, - "implicit": true, - "accessorKind": "get" - } - ] - }, - { - "kind": "Function", - "name": "printFromC", - "printedName": "printFromC()", - "children": [ - { - "kind": "TypeNominal", - "name": "Void", - "printedName": "()" - } - ], - "declKind": "Func", - "usr": "s:1CAAO10printFromCyyFZ", - "mangledName": "$s1CAAO10printFromCyyFZ", - "moduleName": "C", - "static": true, - "declAttributes": [ - "AccessControl" - ], - "funcSelfKind": "NonMutating" - } - ], - "declKind": "Enum", - "usr": "s:1CAAO", - "mangledName": "$s1CAAO", - "moduleName": "C", - "declAttributes": [ - "AccessControl" - ] - } - ], - "json_format_version": 8 - }, - "ConstValues": [ - { - "filePath": "\/Users\/df\/Developer\/tuist\/projects\/tuist\/fixtures\/ios_app_with_static_libraries\/Modules\/C\/Sources\/C.swift", - "kind": "StringLiteral", - "offset": 73, - "length": 8, - "value": "\"cValue\"" - } - ] -} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface deleted file mode 100644 index 498702a3..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +++ /dev/null @@ -1,12 +0,0 @@ -// swift-interface-format-version: 1.0 -// swift-compiler-version: Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51) -// swift-module-flags: -target x86_64-apple-ios16.2-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name C -// swift-module-flags-ignorable: -enable-bare-slash-regex -import Foundation -import Swift -import _Concurrency -import _StringProcessing -public enum C { - public static let value: Swift.String - public static func printFromC() -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/C.swiftmodule/x86_64-apple-ios-simulator.swiftdoc deleted file mode 100644 index 7d830f74f7ca665328c074fa5197598e03420cbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 400 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 - - - \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Project.swift deleted file mode 100755 index fb70657a..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Project.swift +++ /dev/null @@ -1,29 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "iOSAppWithTransistiveStaticLibraries", - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: "Info.plist", - sources: "Sources/**", - dependencies: [ - .project(target: "A", path: "Modules/A"), - ] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.AppTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "App"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/README.md b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/README.md deleted file mode 100644 index 98320247..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# iOS app with static libraries - - -This application provides a top level application with two static library dependencies. The first static library dependency has another static library dependency so that we are able to test how Tuist handles the transitiveness of the static libraries in the linked frameworks of the main app. - -``` -Workspace: - - App: - - MainApp (iOS app) - - MainAppTests (iOS unit tests) - - A: - - A (static library iOS) - - ATests (iOS unit tests) - - B: - - B (static library iOS) - - BTests (iOS unit tests) -``` - -A standalone C project is used to generate a prebuilt static library: - -``` - - C: - - C (static library iOS) - - CTests (iOS unit tests) -``` - -Dependencies: - -- App -> A -- A -> B -- A -> prebuild C (libC.a) - -Note: to re-create `libC.a` run `ios_app_with_static_libraries/Modules/C/build.sh` \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift deleted file mode 100755 index 8b7921af..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift +++ /dev/null @@ -1,25 +0,0 @@ -import A -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? - - func application( - _: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() - - A.printFromA() - - return true - } -} - -public enum AClassInThisBundle { - public static let value: String = "aValue" -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests.plist b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests.plist deleted file mode 100755 index f1d34193..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright ©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift deleted file mode 100755 index c21d831c..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift +++ /dev/null @@ -1,10 +0,0 @@ -import Foundation -import XCTest - -@testable import App - -final class AppTests: XCTestCase { - func test_application() { - XCTAssertEqual(App.AClassInThisBundle.value, "aValue") - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tuist/Config.swift deleted file mode 100644 index ff8e64fa..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_static_libraries/Tuist/Config.swift +++ /dev/null @@ -1,3 +0,0 @@ -import ProjectDescription - -let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist deleted file mode 100644 index 314db985..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist +++ /dev/null @@ -1,43 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - NSHumanReadableCopyright - Copyright Tuist©. All rights reserved. - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist deleted file mode 100644 index 6c40a6cd..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Project.swift deleted file mode 100644 index 7cdc60c8..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Project.swift +++ /dev/null @@ -1,40 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "MainApp", - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.App", - infoPlist: "Config/App-Info.plist", - sources: "Sources/**", - dependencies: [ - .project(target: "Framework1-iOS", path: "../Framework1"), - ] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.AppTests", - infoPlist: "Config/AppTests-Info.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "App"), - ] - ), - .target( - name: "AppUITests", - destinations: .iOS, - product: .uiTests, - bundleId: "io.tuist.AppUITests", - infoPlist: "Config/AppTests-Info.plist", - sources: "UITests/**", - dependencies: [ - .target(name: "App"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift deleted file mode 100644 index b6e56621..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Framework1 -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? - - func applicationDidFinishLaunching(_: UIApplication) { - let framework1 = Framework1File() - - print(hello()) - print("AppDelegate -> \(framework1.hello())") - print("AppDelegate -> \(framework1.helloFromFramework2())") - } - - func hello() -> String { - "AppDelegate.hello()" - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift deleted file mode 100644 index 27fb5d7e..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift +++ /dev/null @@ -1,11 +0,0 @@ -import XCTest - -@testable import App - -class AppDelegateTests: XCTestCase { - func testHello() { - let sut = AppDelegate() - - XCTAssertEqual("AppDelegate.hello()", sut.hello()) - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift deleted file mode 100644 index 85fb9d5f..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift +++ /dev/null @@ -1,26 +0,0 @@ -import XCTest - -class AppUITest: XCTestCase { - override func setUp() { - // Put setup code here. This method is called before the invocation of each test method in the class. - - // In UI tests it is usually best to stop immediately when a failure occurs. - continueAfterFailure = false - - // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test - // method. - XCUIApplication().launch() - - // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before - // they run. The setUp method is a good place to do this. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() { - // Use recording to get started writing UI tests. - // Use XCTAssert and related functions to verify your tests produce the correct results. - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist deleted file mode 100644 index 3c29058d..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright Tuist©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1Tests-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1Tests-Info.plist deleted file mode 100644 index 6c40a6cd..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1Tests-Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Project.swift deleted file mode 100644 index 9628d4d5..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Project.swift +++ /dev/null @@ -1,53 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "Framework1", - targets: [ - .target( - name: "Framework1-iOS", - destinations: .iOS, - product: .framework, - productName: "Framework1", - bundleId: "io.tuist.Framework1", - infoPlist: "Config/Framework1-Info.plist", - sources: "Sources/**", - dependencies: [ - .framework(path: "../Framework2/prebuilt/iOS/Framework2.framework"), - ] - ), - .target( - name: "Framework1-macOS", - destinations: [.mac], - product: .framework, - productName: "Framework1", - bundleId: "io.tuist.Framework1", - infoPlist: "Config/Framework1-Info.plist", - sources: "Sources/**", - dependencies: [ - .framework(path: "../Framework2/prebuilt/Mac/Framework2.framework"), - ] - ), - .target( - name: "Framework1Tests-iOS", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.Framework1Tests", - infoPlist: "Tests/Info.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "Framework1-iOS"), - ] - ), - .target( - name: "Framework1Tests-macOS", - destinations: [.mac], - product: .unitTests, - bundleId: "io.tuist.Framework1Tests", - infoPlist: "Tests/Info.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "Framework1-macOS"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift deleted file mode 100644 index 6a448706..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation -import Framework2 - -public class Framework1File { - private let framework2File = Framework2File() - - public init() {} - - public func hello() -> String { - "Framework1File.hello()" - } - - public func helloFromFramework2() -> String { - "Framework1File -> \(framework2File.hello())" - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift deleted file mode 100644 index dc794524..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift +++ /dev/null @@ -1,19 +0,0 @@ -import XCTest - -@testable import Framework1 - -class Framework1Tests: XCTestCase { - func testHello() { - let sut = Framework1File() - - XCTAssertEqual("Framework1File.hello()", sut.hello()) - } - - #if canImport(Framework2) - func testHelloFromFramework2() { - let sut = Framework1File() - - XCTAssertEqual("Framework1File -> Framework2File.hello()", sut.helloFromFramework2()) - } - #endif -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist deleted file mode 100644 index 6c40a6cd..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Config/Framework2-Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Config/Framework2-Info.plist deleted file mode 100644 index 3c29058d..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Config/Framework2-Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright Tuist©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Project.swift deleted file mode 100644 index 93ebb56d..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Project.swift +++ /dev/null @@ -1,29 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "Framework2", - targets: [ - .target( - name: "Framework2-iOS", - destinations: .iOS, - product: .framework, - productName: "Framework2", - bundleId: "io.tuist.Framework2", - infoPlist: "Config/Framework2-Info.plist", - sources: "Sources/**", - dependencies: [], - settings: .settings(base: ["BUILD_LIBRARY_FOR_DISTRIBUTION": "YES"]) - ), - .target( - name: "Framework2-macOS", - destinations: [.mac], - product: .framework, - productName: "Framework2", - bundleId: "io.tuist.Framework2", - infoPlist: "Config/Framework2-Info.plist", - sources: "Sources/**", - dependencies: [], - settings: .settings(base: ["BUILD_LIBRARY_FOR_DISTRIBUTION": "YES"]) - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Sources/Framework2File.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Sources/Framework2File.swift deleted file mode 100644 index 62754f40..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/Sources/Framework2File.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation - -public class Framework2File { - public init() {} - - public func hello() -> String { - "Framework2File.hello()" - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/build.sh b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/build.sh deleted file mode 100755 index a12e6fca..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/build.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/sh - -rm -rf prebuild -tuist generate --no-open - -TEMP_DIR=/private$(mktemp -d) -IPHONE_SIM_DIR="$TEMP_DIR/Build/Products/Debug-iphonesimulator" -MAC_OS_DIR="$TEMP_DIR/Build/Products/Debug" - -echo $TEMP_DIR -trap "rm -rf $TEMP_DIR" EXIT # Ensures it gets deleted - -xcrun xcodebuild build -scheme Framework2-iOS -workspace Framework2.xcworkspace -destination generic/platform=iOS -destination generic/platform=iOS\ Simulator -derivedDataPath $TEMP_DIR ONLY_ACTIVE_ARCH=NO -xcrun xcodebuild build -scheme Framework2-macOS -workspace Framework2.xcworkspace -derivedDataPath $TEMP_DIR - -mkdir -p prebuilt/iOS/Framework2.framework -lipo -create \ - "$IPHONE_SIM_DIR/Framework2.framework/Framework2" \ - -output "$(pwd)/prebuilt/iOS/Framework2.framework/Framework2" - -cp \ - "$IPHONE_SIM_DIR/Framework2.framework/Info.plist" \ - "$(pwd)/prebuilt/iOS/Framework2.framework/Info.plist" - -mkdir -p prebuilt/iOS/Framework2.framework/Headers -cp -r \ - "$IPHONE_SIM_DIR/Framework2.framework/Headers/"* \ - "$(pwd)/prebuilt/iOS/Framework2.framework/Headers/" - -mkdir -p prebuilt/iOS/Framework2.framework/Modules -cp \ - "$IPHONE_SIM_DIR/Framework2.framework/Modules/module.modulemap" \ - "$(pwd)/prebuilt/iOS/Framework2.framework/Modules/module.modulemap" - -mkdir -p prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule -cp -r \ - "$IPHONE_SIM_DIR/Framework2.framework/Modules/Framework2.swiftmodule/"* \ - "$(pwd)/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/" - -mkdir -p prebuilt/Mac/Framework2.framework -cp \ - "$MAC_OS_DIR/Framework2.framework/Framework2" \ - "$(pwd)/prebuilt/Mac/Framework2.framework/Framework2" - -cp \ - "$MAC_OS_DIR/Framework2.framework/Resources/Info.plist" \ - "$(pwd)/prebuilt/Mac/Framework2.framework/Info.plist" - -mkdir -p prebuilt/Mac/Framework2.framework/Headers -cp -r \ - "$MAC_OS_DIR/Framework2.framework/Headers/"* \ - "$(pwd)/prebuilt/Mac/Framework2.framework/Headers/" - -mkdir -p prebuilt/Mac/Framework2.framework/Modules -cp \ - "$MAC_OS_DIR/Framework2.framework/Modules/module.modulemap" \ - "$(pwd)/prebuilt/Mac/Framework2.framework/Modules/module.modulemap" - -mkdir -p prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule -cp -r \ - "$MAC_OS_DIR/Framework2.framework/Modules/Framework2.swiftmodule/"* \ - "$(pwd)/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/" diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Framework2 b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Framework2 deleted file mode 100755 index 0189f66a91a0260769f79ebd3cc85c2b1ec922e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54712 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 -# include -#endif - -#pragma clang diagnostic ignored "-Wauto-import" -#if defined(__OBJC__) -#include -#endif -#if defined(__cplusplus) -#include -#include -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#endif -#if defined(__cplusplus) -#if defined(__arm64e__) && __has_include() -# include -#else -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wreserved-macro-identifier" -# ifndef __ptrauth_swift_value_witness_function_pointer -# define __ptrauth_swift_value_witness_function_pointer(x) -# endif -# ifndef __ptrauth_swift_class_method_pointer -# define __ptrauth_swift_class_method_pointer(x) -# endif -#pragma clang diagnostic pop -#endif -#endif - -#if !defined(SWIFT_TYPEDEFS) -# define SWIFT_TYPEDEFS 1 -# if __has_include() -# include -# elif !defined(__cplusplus) -typedef uint_least16_t char16_t; -typedef uint_least32_t char32_t; -# endif -typedef float swift_float2 __attribute__((__ext_vector_type__(2))); -typedef float swift_float3 __attribute__((__ext_vector_type__(3))); -typedef float swift_float4 __attribute__((__ext_vector_type__(4))); -typedef double swift_double2 __attribute__((__ext_vector_type__(2))); -typedef double swift_double3 __attribute__((__ext_vector_type__(3))); -typedef double swift_double4 __attribute__((__ext_vector_type__(4))); -typedef int swift_int2 __attribute__((__ext_vector_type__(2))); -typedef int swift_int3 __attribute__((__ext_vector_type__(3))); -typedef int swift_int4 __attribute__((__ext_vector_type__(4))); -typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); -typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); -typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); -#endif - -#if !defined(SWIFT_PASTE) -# define SWIFT_PASTE_HELPER(x, y) x##y -# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) -#endif -#if !defined(SWIFT_METATYPE) -# define SWIFT_METATYPE(X) Class -#endif -#if !defined(SWIFT_CLASS_PROPERTY) -# if __has_feature(objc_class_property) -# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ -# else -# define SWIFT_CLASS_PROPERTY(...) -# endif -#endif -#if !defined(SWIFT_RUNTIME_NAME) -# if __has_attribute(objc_runtime_name) -# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) -# else -# define SWIFT_RUNTIME_NAME(X) -# endif -#endif -#if !defined(SWIFT_COMPILE_NAME) -# if __has_attribute(swift_name) -# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) -# else -# define SWIFT_COMPILE_NAME(X) -# endif -#endif -#if !defined(SWIFT_METHOD_FAMILY) -# if __has_attribute(objc_method_family) -# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) -# else -# define SWIFT_METHOD_FAMILY(X) -# endif -#endif -#if !defined(SWIFT_NOESCAPE) -# if __has_attribute(noescape) -# define SWIFT_NOESCAPE __attribute__((noescape)) -# else -# define SWIFT_NOESCAPE -# endif -#endif -#if !defined(SWIFT_RELEASES_ARGUMENT) -# if __has_attribute(ns_consumed) -# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) -# else -# define SWIFT_RELEASES_ARGUMENT -# endif -#endif -#if !defined(SWIFT_WARN_UNUSED_RESULT) -# if __has_attribute(warn_unused_result) -# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -# else -# define SWIFT_WARN_UNUSED_RESULT -# endif -#endif -#if !defined(SWIFT_NORETURN) -# if __has_attribute(noreturn) -# define SWIFT_NORETURN __attribute__((noreturn)) -# else -# define SWIFT_NORETURN -# endif -#endif -#if !defined(SWIFT_CLASS_EXTRA) -# define SWIFT_CLASS_EXTRA -#endif -#if !defined(SWIFT_PROTOCOL_EXTRA) -# define SWIFT_PROTOCOL_EXTRA -#endif -#if !defined(SWIFT_ENUM_EXTRA) -# define SWIFT_ENUM_EXTRA -#endif -#if !defined(SWIFT_CLASS) -# if __has_attribute(objc_subclassing_restricted) -# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA -# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# else -# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# endif -#endif -#if !defined(SWIFT_RESILIENT_CLASS) -# if __has_attribute(objc_class_stub) -# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) -# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) -# else -# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) -# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) -# endif -#endif -#if !defined(SWIFT_PROTOCOL) -# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA -# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA -#endif -#if !defined(SWIFT_EXTENSION) -# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) -#endif -#if !defined(OBJC_DESIGNATED_INITIALIZER) -# if __has_attribute(objc_designated_initializer) -# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) -# else -# define OBJC_DESIGNATED_INITIALIZER -# endif -#endif -#if !defined(SWIFT_ENUM_ATTR) -# if __has_attribute(enum_extensibility) -# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) -# else -# define SWIFT_ENUM_ATTR(_extensibility) -# endif -#endif -#if !defined(SWIFT_ENUM) -# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type -# if __has_feature(generalized_swift_name) -# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type -# else -# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) -# endif -#endif -#if !defined(SWIFT_UNAVAILABLE) -# define SWIFT_UNAVAILABLE __attribute__((unavailable)) -#endif -#if !defined(SWIFT_UNAVAILABLE_MSG) -# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) -#endif -#if !defined(SWIFT_AVAILABILITY) -# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) -#endif -#if !defined(SWIFT_WEAK_IMPORT) -# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) -#endif -#if !defined(SWIFT_DEPRECATED) -# define SWIFT_DEPRECATED __attribute__((deprecated)) -#endif -#if !defined(SWIFT_DEPRECATED_MSG) -# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) -#endif -#if !defined(SWIFT_DEPRECATED_OBJC) -# if __has_feature(attribute_diagnose_if_objc) -# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) -# else -# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) -# endif -#endif -#if defined(__OBJC__) -#if !defined(IBSegueAction) -# define IBSegueAction -#endif -#endif -#if !defined(SWIFT_EXTERN) -# if defined(__cplusplus) -# define SWIFT_EXTERN extern "C" -# else -# define SWIFT_EXTERN extern -# endif -#endif -#if !defined(SWIFT_CALL) -# define SWIFT_CALL __attribute__((swiftcall)) -#endif -#if !defined(SWIFT_INDIRECT_RESULT) -# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) -#endif -#if !defined(SWIFT_CONTEXT) -# define SWIFT_CONTEXT __attribute__((swift_context)) -#endif -#if !defined(SWIFT_ERROR_RESULT) -# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) -#endif -#if defined(__cplusplus) -# define SWIFT_NOEXCEPT noexcept -#else -# define SWIFT_NOEXCEPT -#endif -#if !defined(SWIFT_C_INLINE_THUNK) -# if __has_attribute(always_inline) -# if __has_attribute(nodebug) -# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) -# else -# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) -# endif -# else -# define SWIFT_C_INLINE_THUNK inline -# endif -#endif -#if defined(_WIN32) -#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) -# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) -#endif -#else -#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) -# define SWIFT_IMPORT_STDLIB_SYMBOL -#endif -#endif -#if defined(__OBJC__) -#if __has_feature(objc_modules) -#if __has_warning("-Watimport-in-framework-header") -#pragma clang diagnostic ignored "-Watimport-in-framework-header" -#endif -#endif - -#endif -#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" -#pragma clang diagnostic ignored "-Wduplicate-method-arg" -#if __has_warning("-Wpragma-clang-attribute") -# pragma clang diagnostic ignored "-Wpragma-clang-attribute" -#endif -#pragma clang diagnostic ignored "-Wunknown-pragmas" -#pragma clang diagnostic ignored "-Wnullability" -#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" - -#if __has_attribute(external_source_symbol) -# pragma push_macro("any") -# undef any -# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="Framework2",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) -# pragma pop_macro("any") -#endif - -#if defined(__OBJC__) -#endif -#if __has_attribute(external_source_symbol) -# pragma clang attribute pop -#endif -#if defined(__cplusplus) -#endif -#pragma clang diagnostic pop -#endif - -#else -#error unsupported Swift architecture -#endif diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Info.plist deleted file mode 100644 index 08d45571..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Info.plist +++ /dev/null @@ -1,48 +0,0 @@ - - - - - BuildMachineOSBuild - 23C71 - CFBundleDevelopmentRegion - en - CFBundleExecutable - Framework2 - CFBundleIdentifier - io.tuist.Framework2 - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - Framework2 - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSupportedPlatforms - - MacOSX - - CFBundleVersion - 1 - DTCompiler - com.apple.compilers.llvm.clang.1_0 - DTPlatformBuild - - DTPlatformName - macosx - DTPlatformVersion - 14.2 - DTSDKBuild - 23C53 - DTSDKName - macosx14.2 - DTXcode - 1520 - DTXcodeBuild - 15C500b - LSMinimumSystemVersion - 14.2 - NSHumanReadableCopyright - Copyright Tuist©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo deleted file mode 100644 index 9674059f0c081efcbbe707b98b7d826b82aa7e99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1140 zcmaJ=%}*0S6rXN^;+Bv~2quQZrefS>xBErgP}74ggo~HPqFzkucDqX#TH5TkAQyv8 z55^E_OuZ2lgC`NH!5fKWjR^-#AmQM_KY(NZfSUNGPzpwT$=iAJ`@N5OGjHo}mR~x$ z5eg%OT#hvN=wqE+kGVHuuw?y(o-ZSL>LGP5umr+OvI zEI|T--LdI?TX^0yHteyo(mWn5qqhg=TFo zOtP1q}DHt6>$IJ+;as5wjW^FTGF)8#=m zu)G8GAwD~nfUN4876?jyMNLUTzao!HNiCHem4do1$|F)pR#MW44rnlt45a*{qT&yZ zgfux6l2k<*c(8i+_{-~S)su9{+m$|qQ8*I{EZlzY8FFGgh2=UZ=FaSg6FLR6t4b)V4weSdArDeh$qH0At;j#P&;y5&wjd(Z+DR1HCxX6N8ufM8+0WUBww4Xqj4F zp)U0dq_s>Y7mqJY;J3$TY>g$p3mWuq!F_srkAGu7;l2e^D&)1ip_+O@uuN5$G79Np zl2>zCp-?oe!s%Bxo)n6vW(h{lO28y0=D{yfFqK)$C>V2ELT}Bi(C%4?=ZdBZL2U@% Q0pI)?@HzTueC22I2NOF1+yDRo diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64-apple-macos.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64-apple-macos.swiftsourceinfo deleted file mode 100644 index c71d696f0777a5a703e4b0cdef3097048eee1285..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1144 zcmaJ=KTH#06u(}9;+2p}2!mm`RE&3Ad;i+2t?57yLL3{5aWSda>m5BPZPRP{vtiT0 z7?j3zBq|0cQNR!fLn1k2!cY@P7+BmK92`2E4!*CY6pZ+iU*G%Q@BR7ScdzxAtIuq` z7#7Ab%wbD;9=xj)8&T(Gl=#d$x1!DuJn^PNynje+)t#^Ri7lRZn{$mgzfpT7=CI`1 z!QfnLUfDS={5Mv1yG@)hyhn;=9;}d zVXA#Twmb(GobBE!&K_D^MW&!>*waNrlSau?E-`B|UBh8so1+)|4*EtPhTQ}`&^I#|@UcRx zdAGxb?SSbXqK?qrkw~JdYnl`g{EC_s0)9md3JEQl2nqpR=S80o5|yOj)4>~%5>nD1 z559j6-Az6(Iyzxr0dkLKwH zoEMZQ60W|PWh~X6$%d_;jLZ%JW8N0{&X?pP{z)UPjiY=U_T*TP4__J+8DCO$6;-rh ztK^F{^3q5trKQu^SZrw$hZuCn_FAI1pa6dhn$z9?^C{xFdnRltH>;SOsbrFg>>@X9 z6jH?mS11~0fy?EyGn!g3Pmj8>SSaQ-lQXhr9F{S@0KxG>Udfn7!I;5PvMC)TL>VG@g3cP)wFC`-LpA#tU1+nMl1D6U5C@)&fg*m(qHwltW{P zJKL^t-CCqgas3*5 zgt-P@xE)GxyA)ri!gV;Yd;S=6O_e`V!~GgpSGiq$DtA@(42L0VZes6Kuc?L`kbvUa znC)P3dvH0#?%8dX?WhY4EdCp@6&%_s->F49cq`gf!@nrLKP-8wHc2PqnaX~JDma3W z%R7Z$!fe;45t;`b@GR#xPZ-G`JP3G?DPR!V2PDeng3hF?M$Tc@bjvo(5~Bz)hP4S* z$d*=kIVvfFBt+xFBBNboQ&QPjUw~~?Dd=ROgzSCNqWAR)l6HK zg&W`i@p%2H1Ufj$K6MY6^Ml-H07S#npeq0uU?dZ8fpO49Jv(xOo&;PSY7$3scmPq_ zKYf1_%H*RPmM zBbB^fD46N=Mv`ou^fa28%)tWwm%Bg&XWqRae(|0SuOjMCtgLv))G9^2 Swift.String - @objc deinit -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftdoc deleted file mode 100644 index 5618c6a78e561277e1a467c455aed399602cd7bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 400 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mBGjnH89XK)H48yX)=TW&2cMA%uOxNFUmGzU|0v_Cl=+Jndl~hOxMj#OwKPh kG|>Y}fkCSv0|UrzBQ^mZFBS#?kRY Swift.String - @objc deinit -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-macos.swiftmodule deleted file mode 100644 index bd82756068676a1d4531918513882635dec4ab2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20380 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 Swift.String - @objc deinit -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftdoc deleted file mode 100644 index 006c579058f72e867d04f51476f8de755de08ec5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 400 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mBb;Y0c5ukn*fg&3xfbi6xm@)Tp5bUe2_c Swift.String - @objc deinit -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-macos.swiftmodule deleted file mode 100644 index 846b58c90a976ce0069c5140ce9f2fd0c3a8cebe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17056 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 F{{#M!iO2u| diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftdoc deleted file mode 100644 index a3de0be94c12e80046e03bb2f6f80ebbda56e65e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 384 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mBX(b9}sYS(^`FRSadL{}Q#UP=a#JqG}Ln8xIJp(->Gd)X%WMmOT zOFdIlV1R@G&2cMA%uOxNFUkg5x(&#$urP}^Gto^18Lyk0n4Dj1XsBlllmLQOK?Vjc bAZ^4Zz~jZjAOI2rxd#T6xH1%x`5^ diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftinterface b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftinterface deleted file mode 100644 index 13898be8..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftinterface +++ /dev/null @@ -1,10 +0,0 @@ -// swift-interface-format-version: 1.0 -// swift-compiler-version: Apple Swift version 5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55) -// swift-module-flags: -target x86_64-apple-macos11.3 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name Framework2 -import Foundation -import Swift -public class Framework2File { - public init() - public func hello() -> Swift.String - @objc deinit -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftmodule deleted file mode 100644 index 1deeaaf48f09a81f66dd7eab993ad8e2e60a3354..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15580 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 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/module.modulemap b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/module.modulemap deleted file mode 100644 index 0e5447de..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Modules/module.modulemap +++ /dev/null @@ -1,4 +0,0 @@ -framework module Framework2 { - header "Framework2-Swift.h" - requires objc -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 deleted file mode 100755 index 9f4e3eb8933e94bbca01ccddef955ecd39eeec0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 170976 zcmeI53v?XSdB^XrBx46+i-hnf1aGNu1;tv)7O_lu>}n+;JC@{n1yKrQyxN_WM%vw3 z@66hgWnd^a2M5z*pOVzL36UETFi8`il%9kTKp})zQZO_Lgr?L@$f-kKZcAF*jjev) z%$?oYu~t^|IES?V3wQ4Q?)R8GzqxmH$LGx4=TCh3aUn!7AjD}@)(8<1B5?j;sxPFr zGpHol;VRd zKi&=*&ly!husrAf(QWp}`Kmo)>o# z5Jl;T_D7XiUvJ!*9T6FzO3Cw#GxwWWD9Vst9(C2@HIl8JB96b5>^aMG%}pndhd~o#e9gj8Nf5*swbXW^M zc-1m$3sL5e*@)nocIGRz*#=J3TuODj|E#A(F{}Znl;dm<4ZX_(;rO^=s@d=wZLp9i zjF%Z0;V!+HqnoSgIWMD9qaD`%a86rA+&4%Hh;Y#;gfrS8XP#M2(WcZm)g3SAgF9Zo zz}0Ouy(|5kt~IrLJ^4dD5z2Hu_H_go@UMc$&;GgRv)YxIUQoU6HU}PGuD?i)oyy*g$JAueObljJrE+!{qQWktCsJzRBpbf+C6sx*?R?THFOf3O4^Ho;%=!Z_ z)3{y5El3~$0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd& z00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY0&^vBUHA4MMz34DX8X?{=ht+;%l4NrLUyY(LcfOy?06ySH~9x#?@^bkm~6TUoaC z-M9aw-ZfaWJ$t14?yFRa`1skR|1!UFMt6&v<%#cPU`n zPL=(+`>L2)-Cf75Y_ob*`O0zz8Dt^^q*P?}`j? z+w{eI$aVVSkJ-oj?Bk?;{A)VWJ8O-9aLL+reb=sw_FPeZ`7jisw$+`neox!dmhyXm zhp#EyigL9}%cvZb5?>1^e(#Up<#OMxtTb*KRx=sBkzdM^N$EFZEzM=Cmez9J6W+Go zLYV11)?q3qC_j8+diqKk$31UQ%G`I(Ec1mwczk-A2h?FI1CNq3)sHv@>AA;3+)pyw z(z|AM@|GNj-;s|{$=Q9so$KD@^dl(Fvd>KKV$$hrM1aHE{2kkR%Mt1=j!SQ(Sq`sy ztJap+TXr#r!vT+F>C_WlcrD_jCg!m zi!xZ$GNzV`n*}X5v_>=4LL$?$qG+buVtPuwE~l9>y_hpsXht+1TeT`4Z_g|3o7%M& z#Z0DSZsd%vk6xFLWfF$bqng8d%2lLP`=qvJRn9OIxuhzTzV_8IrKht$8e0>M$CU;} z={I9W%Q7X-{d9ZiT!fm{0$;hBPKTo`o+a$yP3>lVrf!bUL&k6qE_s@El9>wx6t9$o9QsQ zMTokDXwQmkbD~EV>x$w7wc>zdHNgfG6rw{IDKRGME+1Bjd^|qh)i2&1jg2SM;))(| zW3R}j#mzNhKS#7~CWqc)c2F&d`vcDH5c}xXHW)3^uaqNFenraNQa+77RIzZO zkl&>cVx^S3Eo!5bV0n=cU$SgbOpv_HsoF=r?v#7+ROcy`^5_rwCyT1)A_xkkgzgGG`DE(d8 z^$$@yC)eMrXMgwp&!-&p$zR_IG91KV+Z1e15N<{imdVLi)S1 z>mTv?d-d!u)BsUx01hC&;DzrKmCl`{;pij-_@T*1|jls6VKm}D^SVv*DD{RHm`iAPhR4a zdA@t?dA=|4&3CUpT3cz)^WCf8>yvrDd-Xium-yy8%kF$XC@SrF{x9*&|L#Dgp2Ujz z$$S@4qsx!4cTt@PZjrxVJpWi9lH-x@C(G{rVqR=-O8W<;-knc8{@7l~`+1OM>Ywx7 z93hxL`OEL%2*LMn5ixyL+Vfbj&o5=Z9`X+!u*i`T&kxqS%>OrZ3t-i(7l~9n%YH7p#&- zL}8OQtAS?Z6J~OFmKbw7k+aO!Hqv5p4v!1Y6U5BRc}F+HGr-K#qCENN5+sL$n$FN; z387Io%GIoIQuPe<&_l&|c2Lh~$q+dzN@%93U2Wv`bj=AE-LLZaoW-L|Z>}EBjh(A? z<#?H^SBD%Me*5yXR!6iyYCmpy*|oHmubCe&=(^`H05+Hmr}>V<<2(o<7+D1p$-;@mTLK7J*OI4wwOtndckA1RO^dNQ|G=J zOLKZ5o5+O6+TN$UuhnDPWDn-7o+=WCx9df8s0Et0skmM&Bvm6U%0TSd)07n9JXsL5 zx9b(0>NYsnp^NZ!1`nXTn%9zrv>7%E$?%Y74i^WTl6p357B$0^$Fw$P77K(!(+wq& z&nuhAPB9CKoS~V7OG&#=(Vp8Ko`E6H0B0Ed&SSJMrRraH&kr#zpgif=>t{^SKSw-8 zO| zZ(iJPeD`NJEx+hbfBe}$yYc5Q{Ka{x6K8(m=9U*v)O9`mslR=C{T<)^_PHJ5PyEfT zpZ&ss{`8O1Q?;+W^wMasZ=h~^%fnkXZ+q>rySleu_Q0w1?^(I|mOY6_4)6HK$i3~G zZrprk?=PorU;X@zr=9rhCr)e){OGJd8TsgoxBsE>@9~CDKd^Y-c>Lblv5`pq##^u4 zaoZ)@!SJc#|GN6C;s?Js@pte1R^N%`!E-+N__tp@EB->uiWT2@@4F{f|JUKSe*Wvm zKb8MK|Nbv(zu2)kzfO7V@6WyapFZ}~%F~v-?^FNq=%x28*nP&!Tfebu!LmKY|NP~* zKXlKl_k87yO&dFELlcomfic{#+Lmm{RmWxw^N4WUnAdjx*EGw6xuF1QEu|b+e!YM zCheoM|N3n4c)WE}R+KfXdf(sKvC0{3w9&c@V98R-2XAm>p0nP0`%aQ0l+P`-I~I`w z?aVyv*dXJV@|>1W-QBpa|Jon_;IU=Y7NTr#=pHX5Kuh9kziNbgpj1ewxQSD_^ z-XPnK%YRqeD&oFDQb2@@Mj@Qh208Q0YKk_c#;I;Q(ZTN*xVnv|ccq`xwWfBjC;LSx zGZVfC!3F%Q;PJCJ2j;Wd72c!S>uz)4@#Xr9)Yz%~JsirHK>k+58;9z%^uyU%+S3!i ze^6XBtH0bex)j0h@BETf<=|}Q%R7n72p3TQ8|jQTPjyU97R|(9MpY_jhaoELGJ1kG zi$2MQuY3t*9&bCJbjnMl%=3fOdnvPi>SZB9tGERT1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1pe<4c&qR6ea9yP`;N!Nu7fpaJv2XPt^1dn`41fu*1GRgdA$(#yj3F}qW3QEIX)5H z_g3GN4^Gu6-+61Z3?Ne9oqIU_YkCnPRFO3`(for~VQhP9RbpFyx9lfu#znhNZ zEz{G}bRO$4l@pY=o|v9?-!FI1ON{Nredo+FzhSxl`1CZf5)V@uc$A!}e#9wA&pj66 zev;Xi-Yv8J8n}@Xmv)?xUDWcs@%*kHXZJmKu6vWypE`OMk|T;>8y#+>uI#4rD^yY| zO$9gATeg*`x19dhTMoZ^%Q0GSxt6CY4|psir`azdp2`J!5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009vAe^1~xB0%4cDD4Mc0zx0M;7?r4HCbfH-#6e~ zk?c6@E1G5#c-LZzV!5TW|9r@@oB3eZLR_=c)~mRvclLWGKWAUe7W0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5CDPS0)Y_49Hz`~`!ApzpzNkvS+U=ZcN?i>Sw!gV`UqE? z#D1lAOEyvwpw?heh}sb4F3R7cJTD+>uMUXdhpF68c}kvD(FaG8ik>$WL(QaxVrZxuG?hsTLBMmK8-a-4@eR>UBBIjOoRk zxk59d@z|Ez`rP?R8HLG%lnaCwo zq4c${jwwBz{n6N(XgsboC`!K>Gg_7@aqg$vL+2vYY~CDKl8NLnIW`#W`UkF;0cLZS z+yaVtl9AMi-COAJlUsxcj)(;t#KIb3amyP{%lR8bs75?H9_SYrlV&rS#l+I2xV%P8 zO^8~t^R^%v@4tl(&)!UjHztIrONjQYxHczxbg`}|K2R$T*j8I7$lxG{=nzJVzKKwG z`LIglD&^7tt4}^ka@sRP8C=L?{}G?ep}p~^h=n))rSmK0Ye@FSXa6QTIN!k#Vl~MP z9+~wGl-nqCV!79+XMZ8TpYb47+2579%Kn@=vCRHnJ^Q=&zm9&O*x!}elzr{bbWq7M z`+N25zh0hyf^{C5sxzM7wP!v1Z)@%XFdDB zA^o||{;te=_Pu~ICzgACdiD`=zVPon`@1q%*-?Rma0@y&OyK3ZF8&-2}@-|LfkzI*jN z-V8{rJlr!`N@12QKQR`uXjYlJ*a}de8V{dv|;tWIgrI`EHI7%%A+_cW{K@`?rXgJ}d7(j|KL3#~)u0`3DbJ z=F=TK4^h)~xpObGFsvuf9N)EA6hnb+Jxm zO<%Nw7Pt1|JEj-ZE?P;a5+*Ozl&XduiNYprRs+q*C(PvVEHUPEB4?ScZKTEI93B^( zCy1Gs^NwzYXMmZfMS1ekB}fhhHJzcy5<;VFl&e|ar0N;yp@)j`?4X{}k|A>6#NTx?kn-Ig3Y`-dsJL8#`C)%JDK+uMRmj{PyK%t&V7a)PCIZvTJEAUo$^m z&~?wzZst4OlNRBPi9$H7XHs-G!)Ya)Y|9K~FK=GCta(Gr(3moq9c?z24;gLEl!kKQ z{;-+NH}$pVyN0^jve&N(x6^ZJD!eL352RT&r6o+&Xv*nYE~Soz%bjiF$JbQ2Lmey* zE!FbFdQLU8Y%!BC^@7K2sn!>lrp|pcmge+AHjxP@3fcFydMumlv7FUYMWXO_y@n38 zK+`rA*NcUuYJ^3Zhdp_kk|LZZ3u5+my@FHR1?Mt!5x&mg;geVMTC$Kf!$u()9@5O= z;$Tx!&xXySW|;Dr*2c_YfoN#Dp(OHoWfR#cW+9O?G?Qp4Y4;i0bGO4YAms7yjDp{F ziuRRM{j=`*6&A-{KVypi`Qa&AM$t;kP7QRVRa|gCFBGZ#3fZu{Lj>(*8r8)&DGyL) zA6mV?JQWIxGpIg?6e-zgdXs%0o64hDT+#R1iPL}jgFP>_ZM*g351!Y#cft0p10Pwi z`28DeA9-lS=;Gbup`E>-Q5P1+cGRt&+`q1O#CqbH-}~g!BQLM`^f|Gkcf9uI=by6D z$0tt=k8WNv73_TOzI~f-INJH}n-{km-~HK5%YQPk%lP>x4t%dMH@I!(&hLMC$HS9- zx79wk^Onn29$4_h(8vGg*3W)nK!5s2>8aXRUV3RX*f&r&z2)I8o4398*j?S*FMHrr z`upy$eKfo7n-@KC?*)^+yY5|)zbdf$o&ULeNpSwIzj%J?ypgm1WaOhS-u{QizsDOs z{lMaRb~p0esJ-3_bEHSwS4{a zzxbp5%l7Af{LTBm_~*ZF{8RZa-!gp1wtu+r*!bX!-}&h4>;GxxGv_`Z{+Rf;AHI3l z6O&gAf4KhI`H%dh^^UWjOa0{ot>5cA`}(>|6Cc0fuK)Pk^RB$@(nntT42?w|mG)RW z_WJ2uFFjk71{NwH00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY z0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4ea RAOHd&00JNY0>ASF{s+HZcbWhI diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Headers/Framework2-Swift.h b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Headers/Framework2-Swift.h deleted file mode 100644 index d4d6c9db..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Headers/Framework2-Swift.h +++ /dev/null @@ -1,618 +0,0 @@ -#if 0 -#elif defined(__arm64__) && __arm64__ -// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) -#ifndef FRAMEWORK2_SWIFT_H -#define FRAMEWORK2_SWIFT_H -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wgcc-compat" - -#if !defined(__has_include) -# define __has_include(x) 0 -#endif -#if !defined(__has_attribute) -# define __has_attribute(x) 0 -#endif -#if !defined(__has_feature) -# define __has_feature(x) 0 -#endif -#if !defined(__has_warning) -# define __has_warning(x) 0 -#endif - -#if __has_include() -# include -#endif - -#pragma clang diagnostic ignored "-Wauto-import" -#if defined(__OBJC__) -#include -#endif -#if defined(__cplusplus) -#include -#include -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#endif -#if defined(__cplusplus) -#if defined(__arm64e__) && __has_include() -# include -#else -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wreserved-macro-identifier" -# ifndef __ptrauth_swift_value_witness_function_pointer -# define __ptrauth_swift_value_witness_function_pointer(x) -# endif -# ifndef __ptrauth_swift_class_method_pointer -# define __ptrauth_swift_class_method_pointer(x) -# endif -#pragma clang diagnostic pop -#endif -#endif - -#if !defined(SWIFT_TYPEDEFS) -# define SWIFT_TYPEDEFS 1 -# if __has_include() -# include -# elif !defined(__cplusplus) -typedef uint_least16_t char16_t; -typedef uint_least32_t char32_t; -# endif -typedef float swift_float2 __attribute__((__ext_vector_type__(2))); -typedef float swift_float3 __attribute__((__ext_vector_type__(3))); -typedef float swift_float4 __attribute__((__ext_vector_type__(4))); -typedef double swift_double2 __attribute__((__ext_vector_type__(2))); -typedef double swift_double3 __attribute__((__ext_vector_type__(3))); -typedef double swift_double4 __attribute__((__ext_vector_type__(4))); -typedef int swift_int2 __attribute__((__ext_vector_type__(2))); -typedef int swift_int3 __attribute__((__ext_vector_type__(3))); -typedef int swift_int4 __attribute__((__ext_vector_type__(4))); -typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); -typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); -typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); -#endif - -#if !defined(SWIFT_PASTE) -# define SWIFT_PASTE_HELPER(x, y) x##y -# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) -#endif -#if !defined(SWIFT_METATYPE) -# define SWIFT_METATYPE(X) Class -#endif -#if !defined(SWIFT_CLASS_PROPERTY) -# if __has_feature(objc_class_property) -# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ -# else -# define SWIFT_CLASS_PROPERTY(...) -# endif -#endif -#if !defined(SWIFT_RUNTIME_NAME) -# if __has_attribute(objc_runtime_name) -# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) -# else -# define SWIFT_RUNTIME_NAME(X) -# endif -#endif -#if !defined(SWIFT_COMPILE_NAME) -# if __has_attribute(swift_name) -# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) -# else -# define SWIFT_COMPILE_NAME(X) -# endif -#endif -#if !defined(SWIFT_METHOD_FAMILY) -# if __has_attribute(objc_method_family) -# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) -# else -# define SWIFT_METHOD_FAMILY(X) -# endif -#endif -#if !defined(SWIFT_NOESCAPE) -# if __has_attribute(noescape) -# define SWIFT_NOESCAPE __attribute__((noescape)) -# else -# define SWIFT_NOESCAPE -# endif -#endif -#if !defined(SWIFT_RELEASES_ARGUMENT) -# if __has_attribute(ns_consumed) -# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) -# else -# define SWIFT_RELEASES_ARGUMENT -# endif -#endif -#if !defined(SWIFT_WARN_UNUSED_RESULT) -# if __has_attribute(warn_unused_result) -# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -# else -# define SWIFT_WARN_UNUSED_RESULT -# endif -#endif -#if !defined(SWIFT_NORETURN) -# if __has_attribute(noreturn) -# define SWIFT_NORETURN __attribute__((noreturn)) -# else -# define SWIFT_NORETURN -# endif -#endif -#if !defined(SWIFT_CLASS_EXTRA) -# define SWIFT_CLASS_EXTRA -#endif -#if !defined(SWIFT_PROTOCOL_EXTRA) -# define SWIFT_PROTOCOL_EXTRA -#endif -#if !defined(SWIFT_ENUM_EXTRA) -# define SWIFT_ENUM_EXTRA -#endif -#if !defined(SWIFT_CLASS) -# if __has_attribute(objc_subclassing_restricted) -# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA -# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# else -# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# endif -#endif -#if !defined(SWIFT_RESILIENT_CLASS) -# if __has_attribute(objc_class_stub) -# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) -# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) -# else -# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) -# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) -# endif -#endif -#if !defined(SWIFT_PROTOCOL) -# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA -# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA -#endif -#if !defined(SWIFT_EXTENSION) -# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) -#endif -#if !defined(OBJC_DESIGNATED_INITIALIZER) -# if __has_attribute(objc_designated_initializer) -# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) -# else -# define OBJC_DESIGNATED_INITIALIZER -# endif -#endif -#if !defined(SWIFT_ENUM_ATTR) -# if __has_attribute(enum_extensibility) -# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) -# else -# define SWIFT_ENUM_ATTR(_extensibility) -# endif -#endif -#if !defined(SWIFT_ENUM) -# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type -# if __has_feature(generalized_swift_name) -# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type -# else -# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) -# endif -#endif -#if !defined(SWIFT_UNAVAILABLE) -# define SWIFT_UNAVAILABLE __attribute__((unavailable)) -#endif -#if !defined(SWIFT_UNAVAILABLE_MSG) -# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) -#endif -#if !defined(SWIFT_AVAILABILITY) -# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) -#endif -#if !defined(SWIFT_WEAK_IMPORT) -# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) -#endif -#if !defined(SWIFT_DEPRECATED) -# define SWIFT_DEPRECATED __attribute__((deprecated)) -#endif -#if !defined(SWIFT_DEPRECATED_MSG) -# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) -#endif -#if !defined(SWIFT_DEPRECATED_OBJC) -# if __has_feature(attribute_diagnose_if_objc) -# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) -# else -# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) -# endif -#endif -#if defined(__OBJC__) -#if !defined(IBSegueAction) -# define IBSegueAction -#endif -#endif -#if !defined(SWIFT_EXTERN) -# if defined(__cplusplus) -# define SWIFT_EXTERN extern "C" -# else -# define SWIFT_EXTERN extern -# endif -#endif -#if !defined(SWIFT_CALL) -# define SWIFT_CALL __attribute__((swiftcall)) -#endif -#if !defined(SWIFT_INDIRECT_RESULT) -# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) -#endif -#if !defined(SWIFT_CONTEXT) -# define SWIFT_CONTEXT __attribute__((swift_context)) -#endif -#if !defined(SWIFT_ERROR_RESULT) -# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) -#endif -#if defined(__cplusplus) -# define SWIFT_NOEXCEPT noexcept -#else -# define SWIFT_NOEXCEPT -#endif -#if !defined(SWIFT_C_INLINE_THUNK) -# if __has_attribute(always_inline) -# if __has_attribute(nodebug) -# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) -# else -# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) -# endif -# else -# define SWIFT_C_INLINE_THUNK inline -# endif -#endif -#if defined(_WIN32) -#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) -# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) -#endif -#else -#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) -# define SWIFT_IMPORT_STDLIB_SYMBOL -#endif -#endif -#if defined(__OBJC__) -#if __has_feature(objc_modules) -#if __has_warning("-Watimport-in-framework-header") -#pragma clang diagnostic ignored "-Watimport-in-framework-header" -#endif -#endif - -#endif -#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" -#pragma clang diagnostic ignored "-Wduplicate-method-arg" -#if __has_warning("-Wpragma-clang-attribute") -# pragma clang diagnostic ignored "-Wpragma-clang-attribute" -#endif -#pragma clang diagnostic ignored "-Wunknown-pragmas" -#pragma clang diagnostic ignored "-Wnullability" -#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" - -#if __has_attribute(external_source_symbol) -# pragma push_macro("any") -# undef any -# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="Framework2",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) -# pragma pop_macro("any") -#endif - -#if defined(__OBJC__) -#endif -#if __has_attribute(external_source_symbol) -# pragma clang attribute pop -#endif -#if defined(__cplusplus) -#endif -#pragma clang diagnostic pop -#endif - -#elif defined(__x86_64__) && __x86_64__ -// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) -#ifndef FRAMEWORK2_SWIFT_H -#define FRAMEWORK2_SWIFT_H -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wgcc-compat" - -#if !defined(__has_include) -# define __has_include(x) 0 -#endif -#if !defined(__has_attribute) -# define __has_attribute(x) 0 -#endif -#if !defined(__has_feature) -# define __has_feature(x) 0 -#endif -#if !defined(__has_warning) -# define __has_warning(x) 0 -#endif - -#if __has_include() -# include -#endif - -#pragma clang diagnostic ignored "-Wauto-import" -#if defined(__OBJC__) -#include -#endif -#if defined(__cplusplus) -#include -#include -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#endif -#if defined(__cplusplus) -#if defined(__arm64e__) && __has_include() -# include -#else -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wreserved-macro-identifier" -# ifndef __ptrauth_swift_value_witness_function_pointer -# define __ptrauth_swift_value_witness_function_pointer(x) -# endif -# ifndef __ptrauth_swift_class_method_pointer -# define __ptrauth_swift_class_method_pointer(x) -# endif -#pragma clang diagnostic pop -#endif -#endif - -#if !defined(SWIFT_TYPEDEFS) -# define SWIFT_TYPEDEFS 1 -# if __has_include() -# include -# elif !defined(__cplusplus) -typedef uint_least16_t char16_t; -typedef uint_least32_t char32_t; -# endif -typedef float swift_float2 __attribute__((__ext_vector_type__(2))); -typedef float swift_float3 __attribute__((__ext_vector_type__(3))); -typedef float swift_float4 __attribute__((__ext_vector_type__(4))); -typedef double swift_double2 __attribute__((__ext_vector_type__(2))); -typedef double swift_double3 __attribute__((__ext_vector_type__(3))); -typedef double swift_double4 __attribute__((__ext_vector_type__(4))); -typedef int swift_int2 __attribute__((__ext_vector_type__(2))); -typedef int swift_int3 __attribute__((__ext_vector_type__(3))); -typedef int swift_int4 __attribute__((__ext_vector_type__(4))); -typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); -typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); -typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); -#endif - -#if !defined(SWIFT_PASTE) -# define SWIFT_PASTE_HELPER(x, y) x##y -# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) -#endif -#if !defined(SWIFT_METATYPE) -# define SWIFT_METATYPE(X) Class -#endif -#if !defined(SWIFT_CLASS_PROPERTY) -# if __has_feature(objc_class_property) -# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ -# else -# define SWIFT_CLASS_PROPERTY(...) -# endif -#endif -#if !defined(SWIFT_RUNTIME_NAME) -# if __has_attribute(objc_runtime_name) -# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) -# else -# define SWIFT_RUNTIME_NAME(X) -# endif -#endif -#if !defined(SWIFT_COMPILE_NAME) -# if __has_attribute(swift_name) -# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) -# else -# define SWIFT_COMPILE_NAME(X) -# endif -#endif -#if !defined(SWIFT_METHOD_FAMILY) -# if __has_attribute(objc_method_family) -# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) -# else -# define SWIFT_METHOD_FAMILY(X) -# endif -#endif -#if !defined(SWIFT_NOESCAPE) -# if __has_attribute(noescape) -# define SWIFT_NOESCAPE __attribute__((noescape)) -# else -# define SWIFT_NOESCAPE -# endif -#endif -#if !defined(SWIFT_RELEASES_ARGUMENT) -# if __has_attribute(ns_consumed) -# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) -# else -# define SWIFT_RELEASES_ARGUMENT -# endif -#endif -#if !defined(SWIFT_WARN_UNUSED_RESULT) -# if __has_attribute(warn_unused_result) -# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -# else -# define SWIFT_WARN_UNUSED_RESULT -# endif -#endif -#if !defined(SWIFT_NORETURN) -# if __has_attribute(noreturn) -# define SWIFT_NORETURN __attribute__((noreturn)) -# else -# define SWIFT_NORETURN -# endif -#endif -#if !defined(SWIFT_CLASS_EXTRA) -# define SWIFT_CLASS_EXTRA -#endif -#if !defined(SWIFT_PROTOCOL_EXTRA) -# define SWIFT_PROTOCOL_EXTRA -#endif -#if !defined(SWIFT_ENUM_EXTRA) -# define SWIFT_ENUM_EXTRA -#endif -#if !defined(SWIFT_CLASS) -# if __has_attribute(objc_subclassing_restricted) -# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA -# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# else -# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# endif -#endif -#if !defined(SWIFT_RESILIENT_CLASS) -# if __has_attribute(objc_class_stub) -# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) -# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) -# else -# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) -# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) -# endif -#endif -#if !defined(SWIFT_PROTOCOL) -# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA -# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA -#endif -#if !defined(SWIFT_EXTENSION) -# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) -#endif -#if !defined(OBJC_DESIGNATED_INITIALIZER) -# if __has_attribute(objc_designated_initializer) -# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) -# else -# define OBJC_DESIGNATED_INITIALIZER -# endif -#endif -#if !defined(SWIFT_ENUM_ATTR) -# if __has_attribute(enum_extensibility) -# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) -# else -# define SWIFT_ENUM_ATTR(_extensibility) -# endif -#endif -#if !defined(SWIFT_ENUM) -# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type -# if __has_feature(generalized_swift_name) -# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type -# else -# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) -# endif -#endif -#if !defined(SWIFT_UNAVAILABLE) -# define SWIFT_UNAVAILABLE __attribute__((unavailable)) -#endif -#if !defined(SWIFT_UNAVAILABLE_MSG) -# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) -#endif -#if !defined(SWIFT_AVAILABILITY) -# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) -#endif -#if !defined(SWIFT_WEAK_IMPORT) -# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) -#endif -#if !defined(SWIFT_DEPRECATED) -# define SWIFT_DEPRECATED __attribute__((deprecated)) -#endif -#if !defined(SWIFT_DEPRECATED_MSG) -# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) -#endif -#if !defined(SWIFT_DEPRECATED_OBJC) -# if __has_feature(attribute_diagnose_if_objc) -# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) -# else -# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) -# endif -#endif -#if defined(__OBJC__) -#if !defined(IBSegueAction) -# define IBSegueAction -#endif -#endif -#if !defined(SWIFT_EXTERN) -# if defined(__cplusplus) -# define SWIFT_EXTERN extern "C" -# else -# define SWIFT_EXTERN extern -# endif -#endif -#if !defined(SWIFT_CALL) -# define SWIFT_CALL __attribute__((swiftcall)) -#endif -#if !defined(SWIFT_INDIRECT_RESULT) -# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) -#endif -#if !defined(SWIFT_CONTEXT) -# define SWIFT_CONTEXT __attribute__((swift_context)) -#endif -#if !defined(SWIFT_ERROR_RESULT) -# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) -#endif -#if defined(__cplusplus) -# define SWIFT_NOEXCEPT noexcept -#else -# define SWIFT_NOEXCEPT -#endif -#if !defined(SWIFT_C_INLINE_THUNK) -# if __has_attribute(always_inline) -# if __has_attribute(nodebug) -# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) -# else -# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) -# endif -# else -# define SWIFT_C_INLINE_THUNK inline -# endif -#endif -#if defined(_WIN32) -#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) -# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) -#endif -#else -#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) -# define SWIFT_IMPORT_STDLIB_SYMBOL -#endif -#endif -#if defined(__OBJC__) -#if __has_feature(objc_modules) -#if __has_warning("-Watimport-in-framework-header") -#pragma clang diagnostic ignored "-Watimport-in-framework-header" -#endif -#endif - -#endif -#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" -#pragma clang diagnostic ignored "-Wduplicate-method-arg" -#if __has_warning("-Wpragma-clang-attribute") -# pragma clang diagnostic ignored "-Wpragma-clang-attribute" -#endif -#pragma clang diagnostic ignored "-Wunknown-pragmas" -#pragma clang diagnostic ignored "-Wnullability" -#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" - -#if __has_attribute(external_source_symbol) -# pragma push_macro("any") -# undef any -# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="Framework2",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) -# pragma pop_macro("any") -#endif - -#if defined(__OBJC__) -#endif -#if __has_attribute(external_source_symbol) -# pragma clang attribute pop -#endif -#if defined(__cplusplus) -#endif -#pragma clang diagnostic pop -#endif - -#else -#error unsupported Swift architecture -#endif diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Info.plist b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Info.plist deleted file mode 100644 index 440a48af5e596156653fe4560822e450f2094153..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 837 zcmY*WOHb5L6h8O*!WVOSDWK>8iVu>e9WxRa#z^Z#g2Sr?ln`oZFEcmX_SQboN%Rl6 z^9Q)lolAGF+-hQoF5J2BH?Uyi!g!~&8EliD^L^+0?z!i5Gvq8zRP{F*K={bfW5-W) zoji5=%-QY|>FMq3A2@e@aA9y%J@HjQ-4&@^BX^UyzCL@J%CfE`Na}()z zqSgwHVwtTM)j7wPC-fC?!Ev{p2DMtDWQPmZY>Ft!on{iTpmDgEhM_D|Z-G0>mWce= zCZ)oeo7N0V7kDx}%O8y$Rbo1PBQ@tekMrhZ~rGHnZ24ePNhJi4C8e0`+O z0_LawyqTMAGB{^GOnoO8xfE4TD1ZHWeJwMaI2 zE~4#a3|L>bpyFD7MfP0X1c3xdss}YBm{jg|9ea$f+W; zZ2DN?e8*Q@?gR}*v(@E_rdMT;5)0e*xUgH=l#;dnpKi03R;{S3T2-&A>ZTwQpo4%A zS`Yz)1~egoGFXsG6wCYrC=%ZXF5mJYO`IVrHB_=Y^6P=}{>Dv$2!<}G!mK>(CA@); z@ELx>9_mJAG>Pt_N9ZZqMk#uQUZc0@6Z(R7(GTdvQO$gYV%*yn;D? XhFkb6{)TrUdoVhPFqy|Z;P3wc8> z6h;WS9BJ=^_jPh3=H85vUj+A7%>79q-Dauytui}1`-m@9-8tPd8ST9GJ zWk^7DKw{P?1C=Er!-VO$eG>YC*kzI{4H3Ir|xVq6#Sg-dW#K79$IW@Di zO9_3R2{G0);QaQw-?i-oLmL7KdL*CEs8oDG*DPvYHB3D>M+LYLCsDMC$&5TV?Q0U8 z#07$s(j>%yAaEilV2(jkkZ016v+6?5n3WLv1$)`Z2K_!6XZPtjQ@p`RK2y&YGP0F3 zPR`Kj>O)n~J%jWC?g1kpDVnMVf}&qmQex0AOJibEO(n;~pr#4Zs2GyulsKvZ8w?}^ zDgT%t`-7t)RSJbfMV1Het=&HQ{PIfWI34nIr4L{vPCebv&P5&9ZBh3@=>oajB2HGE`wj@U{i|*n zc-&7X$XVbxiR|l{SwiVnPY$&HV|aEDEapv7Xuqfs@lWa*bsWb#(6d7=F?69%WPDN4 z6r9n4R;aaA>O#*zTFqo~@%Z8-etUez)_CH(ph5ly?$gtI^c(x}cTJd9KCk9=#n3F? zG!%YXx6*|qr{uD{RnSfAjh{4 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo deleted file mode 100644 index 56650b2fc2b9781ead87aacbf2a33591fdd82c26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 828 zcmZ`%&ui0g6#ph&*O`t{%kZ>Ah!v8h`O(r0CSICJ&&AG*2sMUejcc2dq^t8ZyB>xV z*TZ&`$;Jf1X{YSqq2S0aJ5=bwgGY}Z`v>gc`*y9J!oKkNzVG|Im-jRMx7)9YDTEY+ zP>3kRAAjsqhuQE^mii`#+u86JnR?fvK0Tq@{qVsl)t0Fbl}If7o$b{5UOnC+`HMPx z?DI{3{$4E2?~p=++yZ&afr*gkY;bNHbOl{#xq;r-13R(O( zLPTf^?Lu#NrV(O5MuW@d#wjgFn8Rr3gaihm13z(X5N9 zqE=oJ5=mJRWih!RF4Fo{Cb1|g3Wv}##K|~X$*9@RY7(J6&^4#DkPlr+8T+^s$+y@Kz|2zPKnR&m9?b1URHX<1>98J1!>(!D`_FQSj@(R_bl2^4{ zPpUZfGeZaVQZ=pTUez&N2}YiW;pc1MocA29>{_0+X5`J$nxt{-QqHbAI(#&y@F>K= OAAsv)qQCJd|DHd~oY-#w diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/arm64.swiftsourceinfo deleted file mode 100644 index 56650b2fc2b9781ead87aacbf2a33591fdd82c26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 828 zcmZ`%&ui0g6#ph&*O`t{%kZ>Ah!v8h`O(r0CSICJ&&AG*2sMUejcc2dq^t8ZyB>xV z*TZ&`$;Jf1X{YSqq2S0aJ5=bwgGY}Z`v>gc`*y9J!oKkNzVG|Im-jRMx7)9YDTEY+ zP>3kRAAjsqhuQE^mii`#+u86JnR?fvK0Tq@{qVsl)t0Fbl}If7o$b{5UOnC+`HMPx z?DI{3{$4E2?~p=++yZ&afr*gkY;bNHbOl{#xq;r-13R(O( zLPTf^?Lu#NrV(O5MuW@d#wjgFn8Rr3gaihm13z(X5N9 zqE=oJ5=mJRWih!RF4Fo{Cb1|g3Wv}##K|~X$*9@RY7(J6&^4#DkPlr+8T+^s$+y@Kz|2zPKnR&m9?b1URHX<1>98J1!>(!D`_FQSj@(R_bl2^4{ zPpUZfGeZaVQZ=pTUez&N2}YiW;pc1MocA29>{_0+X5`J$nxt{-QqHbAI(#&y@F>K= OAAsv)qQCJd|DHd~oY-#w diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo deleted file mode 100644 index 0f4eaa674e70ac5ca93c5f70b462ebc939fe0f4b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1148 zcmaJ=PfXKL7=P>dXGh2+1QWxdK}=e@^&e|xW(QXY7cYxLy_n3dw5%}L(sum07+iKR zhR9;(ji4AjiGl`iB$65v512s0!INi>oIGLT_cq4Bh`;3P``+*S_rCYO9=%+8=4(SJ zh7fA?WkL_$9g%B^zv{dqbnU9(zy>E#gRKjetmgQ|;d+!m(SA>5>;(^XOxOsd!MBuhtI5 z==%P^3w`ro?+;f9ZqMV(Dh)+rp(X~392Y~SBD<_Iy9D&>Yi&b6VZGjt5Cdyx^XSCF z4kZM8hs8vDm;dXl&eknI7#a{r(Bt`h)}WHJmg!P6hV59nX-ejzoJ7$MCbQb~c(_V% z5+^H^UL{0X5IB(&Fvp-#$TMPVQ^su0o|F*!1^c-{C8b2d8crX!a*lX|lfsTQRmf^? z&aNGzxiyG3LGA6P_i+yxvZR}aAuD1;)5k<5qDg~d+89d@ii&9p(tsG1v@vnO1XhvL z@>pb0&?3q})R3Z4QP;HYdn>mOKfSn8sii}`Et!27iBnLZ;cMtPWopVJSgwL#+gX2X z#kS`lmq2_VXMt^X;JIr8fhRZz?DId{FxYWi*SV-#-8yw2lopW7b>d{jx$l5r+rR3T zfyezcgPaA9lgMEE!~)9Hd-9>xAAOVEU~z7WLgPh+cx1%N8bdhVhn^mosh$gc;zRSg zspE`3v_!2eQx|&586%s`C6n_b`0eo->*I;!{6ACzw5xX@_8d~>9*^Nqm#y0eu_Vn&;@k> diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64.swiftsourceinfo b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/Project/x86_64.swiftsourceinfo deleted file mode 100644 index 281445fec92e279c91832b22179a72f82c13e738..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 840 zcmZ`%F>KR76g?+RQ=F;_QN`533PEz}*yluXL=j6|lsO`0K}aE3c4O+sk?k}sQ%N&a zD54pP#DGApiiAWV1$AJEMCC3Wf|P-Qk&!VIQwIK}2`NbZ(z}26{`0^4|GW2Q=Q%Zn zkc1HOQ^nYW4?X%I8#v6;U&TNx8~7~JZ=3YThjgnK*gv6LBK^J`j0C>1?Hbpu#o8XO zUt^D4uHnw#j-#(}s>&GtFl=&k$+OKhSncHJFk&!#5b_^;fI(;=EmC03g&0*G5%ht^jBMC`{ zwFzYuO3QpaAxeTMBvQfxqg-U-3xXs?5n6&g8LP0WR!wUqfzWR_uis4NQ%Sx+((}4$ z$CHA@+xlw7C^)7C0x+LHh)UqYlk8LPfH_~teg;51j0jx;P=Jw5zy``f7yaxg2!0Z9 zb?AwX|1ehT!ENQW^_YcgaF+8?7NnqyHt~2+)y-y zWTemz^ZFHYsZuJchGFJ%8yV7l@}^PEqz)GFzug5QJoD}aiQ{`VOb4q^tOCAcDwS2W zMKWh5AQ?XPVL-+GAhkO;pdB-Z0Y~9h<)Vwwt86KC8 ab7sX-;G;1`S|JSn2J*ge=oe|_U;6{75ZvDY diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.abi.json b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.abi.json deleted file mode 100644 index 5bbfed86..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.abi.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "ABIRoot": { - "kind": "Root", - "name": "TopLevel", - "printedName": "TopLevel", - "children": [ - { - "kind": "Import", - "name": "Foundation", - "printedName": "Foundation", - "declKind": "Import", - "moduleName": "Framework2" - }, - { - "kind": "TypeDecl", - "name": "Framework2File", - "printedName": "Framework2File", - "children": [ - { - "kind": "Constructor", - "name": "init", - "printedName": "init()", - "children": [ - { - "kind": "TypeNominal", - "name": "Framework2File", - "printedName": "Framework2.Framework2File", - "usr": "s:10Framework20A4FileC" - } - ], - "declKind": "Constructor", - "usr": "s:10Framework20A4FileCACycfc", - "mangledName": "$s10Framework20A4FileCACycfc", - "moduleName": "Framework2", - "declAttributes": [ - "AccessControl" - ], - "init_kind": "Designated" - }, - { - "kind": "Function", - "name": "hello", - "printedName": "hello()", - "children": [ - { - "kind": "TypeNominal", - "name": "String", - "printedName": "Swift.String", - "usr": "s:SS" - } - ], - "declKind": "Func", - "usr": "s:10Framework20A4FileC5helloSSyF", - "mangledName": "$s10Framework20A4FileC5helloSSyF", - "moduleName": "Framework2", - "isOpen": true, - "declAttributes": [ - "AccessControl" - ], - "funcSelfKind": "NonMutating" - } - ], - "declKind": "Class", - "usr": "s:10Framework20A4FileC", - "mangledName": "$s10Framework20A4FileC", - "moduleName": "Framework2", - "isOpen": true, - "declAttributes": [ - "AccessControl" - ] - } - ], - "json_format_version": 8 - }, - "ConstValues": [] -} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface deleted file mode 100644 index df83246e..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +++ /dev/null @@ -1,14 +0,0 @@ -// swift-interface-format-version: 1.0 -// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) -// swift-module-flags: -target arm64-apple-ios17.2-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name Framework2 -// swift-module-flags-ignorable: -enable-bare-slash-regex -import Foundation -import Swift -import _Concurrency -import _StringProcessing -import _SwiftConcurrencyShims -public class Framework2File { - public init() - public func hello() -> Swift.String - @objc deinit -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftdoc deleted file mode 100644 index 1ed091506ac68c02e6ceacb3165882e68f3f8698..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 408 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mB_?V5L}*_R-#arT2!2wpQm7|XQ^kTpivAG%t_2k*98mc8R?mt zDI|jh3{4FT^bGY3Kw_E#F->_8>13`Jx Swift.String - @objc deinit -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios-simulator.swiftmodule deleted file mode 100644 index 4b07dfa8e084e8bea3cecb4c1f097f3773c79078..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20676 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 Y0Yw`6r)i>3|7B?|`;s(aPVx2s0KtU_!~g&Q diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftdoc deleted file mode 100644 index 4a89e35cfb4572e553fbf382c9fe931f5a465e8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 380 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mBX(b9}sYS(^`FRSadL{}Q#UP=a#JqG}Ln8xIJp(->Gd)X%WMmOT zOFdIlV1R@G&2cMA%uOxNFUmGzV3-HwCl=+Jndl~hOxMlKFE%vMGX;t=FtiFXFmM5B aBQ^mZFBS#?kQm4 Swift.String - @objc deinit -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64-apple-ios.swiftmodule deleted file mode 100644 index ec7884d89a4132a6bf07396b1de702eca9c7bb3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15664 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 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftdoc deleted file mode 100644 index 4a89e35cfb4572e553fbf382c9fe931f5a465e8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 380 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mBX(b9}sYS(^`FRSadL{}Q#UP=a#JqG}Ln8xIJp(->Gd)X%WMmOT zOFdIlV1R@G&2cMA%uOxNFUmGzV3-HwCl=+Jndl~hOxMlKFE%vMGX;t=FtiFXFmM5B aBQ^mZFBS#?kQm4 Swift.String - @objc deinit -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/arm64.swiftmodule deleted file mode 100644 index ec7884d89a4132a6bf07396b1de702eca9c7bb3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15664 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 diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.abi.json b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.abi.json deleted file mode 100644 index 5bbfed86..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.abi.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "ABIRoot": { - "kind": "Root", - "name": "TopLevel", - "printedName": "TopLevel", - "children": [ - { - "kind": "Import", - "name": "Foundation", - "printedName": "Foundation", - "declKind": "Import", - "moduleName": "Framework2" - }, - { - "kind": "TypeDecl", - "name": "Framework2File", - "printedName": "Framework2File", - "children": [ - { - "kind": "Constructor", - "name": "init", - "printedName": "init()", - "children": [ - { - "kind": "TypeNominal", - "name": "Framework2File", - "printedName": "Framework2.Framework2File", - "usr": "s:10Framework20A4FileC" - } - ], - "declKind": "Constructor", - "usr": "s:10Framework20A4FileCACycfc", - "mangledName": "$s10Framework20A4FileCACycfc", - "moduleName": "Framework2", - "declAttributes": [ - "AccessControl" - ], - "init_kind": "Designated" - }, - { - "kind": "Function", - "name": "hello", - "printedName": "hello()", - "children": [ - { - "kind": "TypeNominal", - "name": "String", - "printedName": "Swift.String", - "usr": "s:SS" - } - ], - "declKind": "Func", - "usr": "s:10Framework20A4FileC5helloSSyF", - "mangledName": "$s10Framework20A4FileC5helloSSyF", - "moduleName": "Framework2", - "isOpen": true, - "declAttributes": [ - "AccessControl" - ], - "funcSelfKind": "NonMutating" - } - ], - "declKind": "Class", - "usr": "s:10Framework20A4FileC", - "mangledName": "$s10Framework20A4FileC", - "moduleName": "Framework2", - "isOpen": true, - "declAttributes": [ - "AccessControl" - ] - } - ], - "json_format_version": 8 - }, - "ConstValues": [] -} \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface deleted file mode 100644 index 7c4d9572..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +++ /dev/null @@ -1,14 +0,0 @@ -// swift-interface-format-version: 1.0 -// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) -// swift-module-flags: -target x86_64-apple-ios17.2-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name Framework2 -// swift-module-flags-ignorable: -enable-bare-slash-regex -import Foundation -import Swift -import _Concurrency -import _StringProcessing -import _SwiftConcurrencyShims -public class Framework2File { - public init() - public func hello() -> Swift.String - @objc deinit -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftdoc deleted file mode 100644 index 8a6e1edfa88dde5bcd04b38c022383c9af2934a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 408 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mB_?V5L}*_R-#arT2!2wpQm7|XQ^kTpivAG%t_2k*98mc8R?mt zDI|jh3{4FT^bGY3Kw_Epcl diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftinterface b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftinterface deleted file mode 100644 index 7c4d9572..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +++ /dev/null @@ -1,14 +0,0 @@ -// swift-interface-format-version: 1.0 -// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) -// swift-module-flags: -target x86_64-apple-ios17.2-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name Framework2 -// swift-module-flags-ignorable: -enable-bare-slash-regex -import Foundation -import Swift -import _Concurrency -import _StringProcessing -import _SwiftConcurrencyShims -public class Framework2File { - public init() - public func hello() -> Swift.String - @objc deinit -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64-apple-ios-simulator.swiftmodule deleted file mode 100644 index 642d1d19cc01fc05a61bfb2d7424a6f00a7ac295..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20676 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 XDALeBP7{6lFH3XTm!t`Eim(3%Cfo@F diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftdoc b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftdoc deleted file mode 100644 index dcf344bd4942babbb549fc122ed41ebd44e567c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 392 zcmaDfX9YVW2Lpp90|Ns)qlJ#c+7Dby0=U-%aP4>CT5rI$Ux91Q2d>2%xY!*xUFbQa zy@N^j#3Ahshx9v`wD%m+SaZl(Xp58P1t*OOP8vYc#=uE?50mB63R);OV>3tGBDLM&@(dAvs6e%7BRHc zGc^SUNC?mzx1z+{)bjkIY$FDSZ$N&9g;~6riEbjuc-_qWVnY)>Q{Cds+|r!HlKdi| j0w8D=WMJR|(nf3oJYFme0w6JvyI??xD?<^P4-y9eY Swift.String - @objc deinit -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftmodule b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Modules/Framework2.swiftmodule/x86_64.swiftmodule deleted file mode 100644 index f3bfa36d0f3cbd3eaf380b9d928f9d59166708b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15784 zcmd6Ndw5glndi|3Y>u3xV+XQ^q;O1}R59ZO&;g=2Nn2*z zefIaBBgwL4NdB1TN%dIrxqRRIy_es6Iq!GgK6s2%6*J6QmSKuiBhk^ADI{4Ul5y5= zh{Q~Nv8wyDuSq5Ju9%sQ|yrltA8ZH4vD%$B6|qGsc7+u6dQKwj=R{i zN%j!#rMxAhJUim0QAMiJ#JJj=kgCT0rpcJKS8W=P8IH#sWs_>-@t8F#84~I$JFl+p ziy7?qIjS&bQmX2WX&m90c~))dk72R_)B0nY9YMdjA9MWXu-_7-d)BaIipES6Y76G| z`%OVGFBwBI&65+75p*I_6|VL{DvSNE^*i#8M5@I3MNJ=*(=tffP2&TB$lRSGEBSp5TXCxB#o1&5>F(;R1X_ljY zwQ*K5jjN59hF1qoD1KW zjTxXvj2M_G$R=eVNjbY-!8j_4rnu|4{lxll(v9Vum z#tCkW#SGIlq6(VpQ(M5)bS&`wxdp&IH10PKNCwiUnv^*ha}3=^UhAaV3=7_;{h!jq z?2wH;F6;ZG$etB-uQIwJoMr*FMPScB)uL`V$&yh*>>=D%#-)5qUV+kKh7fxsr5g?D zA^;krJ0$3Uwag&*U11lC8=yY~z@~I3TUJDwq8Z+jS2JAd|I7bUJVus0 zyZSHHItXAI)Gt#h!*M%oESnbU4MHNwVRTuFxj>FL#sfq4HrHd)7_kj=-WR_GDJz z154Qvm<`g}bTIM}u$-2Yc`S@`Ww@e`^bPM5BQEx+i^VUr4gZ87r$7V2B}?|nCv_(U z_7v;^E#XF%i8PJmR;Wmk#DBfKU>V`oX68f@e zX7&V-Ec$!Pj*PD5g8;XnJ-b;u}mXiWydxT0sJDVc_c|HLI44fPI_T2 zg_Gof+B^|6B`BkrBH4LcU%`DhdkAR@TzhrHqK=$Ijyi`Bmt3rVSrzh3zaNpadNzhA zZv>MdGciYFn1RRWM&0Z%43nbpGXndja)j%zLV_5Os**7)L_qLF%tT<#=psHsDnP6| zot2d}AsSzjOqn5pON8e$2^N_LT*2hPQ%1PdSj>FM5A#5QRZ+DiGb#Q73-}TCY-tBf zE1NeX&@W__z%m^|0Kzna1lA+Z^g<36p)a#o67u)O49LfmxmsxcTdWafUvY6alkDXL zcO@eVqR}XDkrHo6hABsFSkn*;)J7b2878gJ1yZtI9Cx$VlHBDemsv@+sG!q7ZXNg6 z9*Z0DXKendpu58BKMHX(E^a!1J=-5(Elp!M-Z18w^dCYWqCVdo&GmrWs8kEN z4m#>W1$-Rgj`Q5VgbL>U-};E!6!IHFQeCg3@nF2JKVTn_8pnu_`td+RzInaZT@*1> zjQ%=o#B(2pxc8FW37&&)@_A}YaA%U-2R!#{7k4tnof5d;*brs8cfF8+i==4Ihc0d= zU#0x3j;b+DLpV^V1cnn{Mu! zuRse2>`}kHKTsFeY{;Lq=>taho=yMZg7fZaO!)1=09h^=0D*=?zTyMRF9po~4*MlX z{e+`#GHy=98*mWPm?z>5Q377$G^BOZC*t;krGKAfp!gfN+unR z@TReNLHyW!|3&sAQGXfMTEKVQ2ZAQd9+esadf;sV0$U%bAsze{5iG=ANpkNLy3h9> z8TU5=wiAx}P+faOemw~)|$oLL94Sn(2{Bd_Hj)C?w>N& z=-_q)SDt;x#$B-$D#JG%Gza62p;$v7C^;HN9d%=x#(b-Gn<{iy+@wuKoKs%?O;EMz zuZFl(K6Ap~IE@2=ItmMg_}FTBpM86fJ0h?%A#PfBs(h3jd=z0JsJ2I8;dpH@9eL&0 znU7RQ`S^KLZ=k-?4Bm&cvqfW_C69{Jz+|keHw@;V07}N?7j{Mpn1??w|17Op;>R`!4-u zu!vXyNpFjT!OQ2(gYky9$gdH|2%7_r+P*?;igh)V8{R3*u7CB#OEH8LO34F$JFtZG z5P^df((pDkvDa*RgyI=7onJ;^443|Tp(y2#AB>^sxpSg%ym|Lt9uu>)vzcjZhAQqF(nrWf<7O@qV5(`INA06*DU>x z+T$8iIDkr_FvmLD?l~&x-^03vsnFxS=O~sFxN9OMF!(FsXi$!dsF!lWLB0pC_{yME zJDH=tDG8`(EDYA)zXv(?W{O3qoDuX`r$GF~@S?fo2-ikX2qN&2V-zN?_~<={iDUhH z-i3;&@~G9j^>uD8+T#A@c!Xp!=z&aN@;lTn5Hg5s>)NfM!N#s0Kx?titOJ= z4;64Ls5=DskkNs+LQf4mu;LW}R-lk_8)C^nzc9bla~PA9mmu0gdKbf`><7r}wgMG% zUy~aG=tnBeVd^=K#RA`3k?qVyaLJeqp9dpfCA)&~HMkQ*J${ssFwIV-(Rg|xkPMD7_mr%MBHatk$DUdJu{ze155)b~t7}_aTJerSF6N7p>{pxD8T(T|hBup4;>dY~d zwU?UEM)Xt;qVw-Jh1C``rO?&73bQN9MvGcqorpP>|9&x8HwLk#fxZa!!;R>wkRd*1 zrsj9|qJCkQYF?ud3JeZ?`$~Khf6fGE1eaiNOpDm~#6B^%%SfG1lZhsApzE`k6 zBI?e-CMoey?o^0R?Ja7(kIKD$`{rxsSTst})I>8Ii1`~l6Js7wN9}F*iJzI#(Vu6Y z7>r~bLz_cF)6HmiUa!GQgiZ9e&fphpqb<%uH1SLkZNdaW0LqM+`(R%QyAmd)J7wQ` zQ$>wwwCT`7LIgw~^N64uPEdCZ`~yDvH@}6h7Q7DYf#F%dQSNG)(T18L4vhBaQl;!+ zG{?}YwSi&kF3oE&C*cF^NP;~iH=FcNy)Z`Z0}cpYxeYtngNXd7WWW{$Hd4wber85H zt`E&jHMp*(eU^`z6Mt|Oct>{~VnHVI@;meMnQucK5Cz!6z6?+~j>a8IL()0zz{t*y z-6q;vvYS7ukvp_#<)tl_`p55@6qeC)yz}f?S|RZ4syj1u)~AFGU-I*&e#z8JcsJXZ z-bzOT@!IF%7_tfd;FDwX20w;2;Fd~r*xuXoXCW||#sg46Ah`s6!DSH>(~*(FC43*alP@+!&CSDd z19CLP9z{e%01=g4MqQ>u&MaDZgqL5ddz7LB{6D*eXJ9aXrB9j>t7h&YRAk~2f&MB_IavqmH%1c6Bv0+X@8m&Vm|ZQaRO zd>cg{&>?4plxBPITn&4impjYw-2{6W7(|!Z%~B8+*;nCF@GBd878?L5_D3#VB*jp@!+4&2hThj&bzX)YF_If%3l0xHfF@~opK(H%@^fpiB+WP zaf!BTbCwTOo}=tzKp25a;LnJv2tcSRVBfW`O4KixLrmWC0q22qXF2PU)-gF8VqSCl z9>4^z0G<$_D0cyVn(cq*Hv>Qj(jmCZ!oX_cEpDY}Pxe<}gPK9vdIo;7Tc?ku_c;g= z%7*7@FJG&BT^866TblY}Rra;#l=EB<)Kt>`c+85@B1@>$f1#WAg{D z8&qy5Vu;3>EfwO$Y_C;BR$GFyRMp_W6JF*P=gK;;+;R2>G&;)^t%Z3vVrVAfp?U#2cbPb>BZU(0$c1W6CIR3!TWl7(XsuE-=z*VuO z5z7H-^nO9dKNPG2YsCMdR{jK8G^tdNN;$-$#-IX2 z-shwONsezQHcr}5(+>UzWf}l|l&9A$P!HsiNW&VD?3XgTuFo&PMFi0W=I)?mlELW*`hJCD-^$=+%CW))ub?Ukf3A1f!+I03X7JvVw6Bohaji| z-}L%P-q2&JZ{wk=Pt$;>Uu?IG$7_!VR$gtY!UF*nF6xi3T2@4h>hOpk!PBoFzv%ha zU+q~5lmJRtwhzeqn8L@g;`~A+K5?-XUw(a|`AC`(|HtwlxOZZ~$@6UhNZ+|avPaIn zu&^T4c)17WP{Q+_t47VeQw#C(i4|dmz3d0iEo4#EomaLdkzV{pyRYZ@1*ABalS$Rt z2Q1|Q!cjiB5YI>_h!{vGa7`qU^Ac(nJU=K8H=6SBLUSS#UhY9oL#)ex)VNRki`bvY z^=k+ZHned(mt7v0_jc1SbEI_eZ={*iDSnCK(8{Y5c)C35X7Q55C@PeT=^2?^H8;st zs!aN^h<9#iFMHm+W~GGo(mQ5{5k}nfVov&fGLZd?1#jmrJe3}?z*hbonH6hfLA?tN z$|dFwDd8JwdO$MZ{Vn8<+&G)f0%MtkUvBthF-~{N%^tPkT^u}lyDZ8as>$Vw4?T!^ zN@ zLl>mKq^ONYPM8`Gy7W>DfRPF4AVcpvW$TYeRAS5EP6KdG_Ajg+ey4Nz>YBVtVu65B&nVqN<~U(2CWUG>ExHI=v57jPA8cx z4c7r8g{i~14N93COa9V>&a(idju07Uv*Urw}o-LVGs=etuIfJ)2A1xS1yjAaM z`?>-ASV%AJ5VEbk%hL*0pNA|QczSXVlwtLJv#Z7G>}&;l#KeyF?wxzLS-bbP@9DOB zyE?yyDSOhV+uNV(-rEH!ApO%|{poLD@YCI0ExY%$ceg+5d3t-s4AvZj{4ww_RR%pg zV(s4LRYb95Ikl{@q{XsId)qtOtdGDNUAsJO?JeD&J=MEA+jqBlp39M^dYe4V>Djh- zho#+1=E;H}XPBk^@h$10GR!QUfL>R78))v_)#4>Q;cIDsW^ZS=huL{I?D6SvH)ko! z4$p2+7sPIZN;!h>?)cZxaW_9zm|>;%kIwI zInY{&TZWmC?f&fcJ%oskmgj#DY<^0%Czj#kZF^hibozYDu8u!KY^FoeeA6>ic-Q?C zV$-F_Nnv&&&u!n`+OfCI1KVu98uP2fSVVG~?KO z-m*+R_s7E%GeExObUrLS`T52g9A`d8o?#ks@}>|c%1tg~Q6*oZ4ZOH% zP+GAmG}yJ0&a_K{%}(vInx@lFd_upxGqRZ14gWTDw7~kt&b_bZ^Ut87Oy9xU6&k7Gs z=w|}2>thD@Ou)+(msQ}x>gl3Gm3*bNkFOY5^FH3W7tg=(5hhZ z<^8VR6Z$fY*;;a|saFd=z%akMZ6+YZiYD~x6|01YikCJYbJbwl?=+a#uP6DM4&tBo z;s$XaKk=`OEVQ<)QH0taD)xNSS8}VzEjSrfxk}C0(k9FN^KAoe83sRE{40s!$A>Q? zG>Q0);>)1GV?=xfd}**B7krm~h9e*9WabIRtwrrjhxwmI42SD7Yl3`9m817{{ZfJH zNDopoH%}bcR)jO6&z(H5Z882UROkvF5lauKpWnemm#)PjV{tP~2shQOJ`!!L!2jlD1>612XjXVVc+v`&@wGG13T_t6TTWyxlVs@bv=ey(?z|(WzDL zHf{4tEFv>D6DYwt8&$V@dZV?3LG?fX*IB_OBTA6YPZ#x+tCuV-BU!K>8NH%Oy$n;H zEw2Ph(l-c1#mm>UO@vlePU!Jpzq%LLjIghh)+(fZG@D;Gb~z+g5ZkNMkS!y5)XSFR z{}TAwCD#`QF*2wvEd!aEfEFsA6`bGE(#=7qn#55Y%)wa743(Ssrnr{vd2`b~9w(T& zxD=dSxF0`XsDy;1%FQpqRJgGD0a;|gUOWP+q@cD8M8_T_{+j%X7X*rF{?^aZNP(QX zjjz}So&BFmQV5*uR?mwt`GeiGHZfX4GAoRJr=+xbx@a|M9($ZDi5aVUdAQJEP#z5> zUt>UBnr3=x>O_PWp^Ciioh}(=y>F<>w9a3{t;7xvW_136SyujY4cIOJ1^o&aHBMSd z{J~1Wu}>&3Uefo^DlFE2T{WX2dwlUX%<{5Ip3uIw6eHwN=1y@wu3E6yYU87)vW#d8yMr)ma13305*LW zh~q`es+z%(92$C_KsW%q=Wk&g!Y9w)z>2CF`6@UW!GX}G-tU`QDN15D1(5TJ$CkQX&_C?%o$L)2v{X^V-%f#KIMd@qLEm#DYBtW`bnxL^F+&&e4@#(-}EW0#hM1c6(; ziRYJSFnm9mEY5&_i%;9b*NDRA625quMjLyLQ5~oegW^=VAk@?NRTv)(snpxrF!G5t zqPjx$%o@=j-MSn&<9Q2_`%5A>339F5ecEOGI=c2(bnOjXYuVuwuP%q+pjOcg`S{U!QWhKV1xTYMoQK zv8}@gY1f07+IwYQ+CgF9jEX!E>KY}=zXIj*XEeB?-nJV8G(RY&t#ep?4Hp0r9^Xg! z^5+Swwr|nUnE zirE7crn4WNR)fTFpYTBDib&Bs{SnMKNQUr(ih)^*ZP|8xT%O~JEUR$^rDKn^c#lR|8{ddldyk=iTrntNx6!c^M9>jf~svyqpw=z2a6Ln z()db9^BH_8uR=06O0-bLes^MZCF9MkrDBF&-r&}wPnE~tqlzu)m%gOsy|qkYZr%@U zFXdPa2*W5N%g4Ga=%N#?+15ii?<4IBxUcv9GfgPt6QU4(2u* z%%l5dzT`z4gHD$6Q8B;z_xl&q$`7tzyT-GA+xj)@*Q1BlvaZe3YV*{rTmRtN+S>K4 zww63PReZ@0wQ`{%^PQnr+9d0aS+kfg`NC2eD)KF59j!bT$ekyvQzZi&*N7Ko45=hn z9}A5knRCa`LTkRnm;AMj8KYzRs2D}pil%+ Framework1 -- Framework1 -> Framework2 (prebuilt) - -Note: to re-create `Framework2.framework` run `ios_app_with_transitive_framework/Framework2/build.sh` \ No newline at end of file diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Project.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Project.swift deleted file mode 100644 index ab1af823..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Project.swift +++ /dev/null @@ -1,29 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "StaticFramework1", - targets: [ - .target( - name: "StaticFramework1", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.StaticFramework1", - infoPlist: .default, - sources: "Sources/**", - dependencies: [ - .framework(path: "../Framework2/prebuilt/iOS/Framework2.framework"), - ] - ), - .target( - name: "StaticFramework1Tests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.StaticFramework1Tests", - infoPlist: .default, - sources: "Tests/**", - dependencies: [ - .target(name: "StaticFramework1"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift deleted file mode 100644 index 6a448706..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation -import Framework2 - -public class Framework1File { - private let framework2File = Framework2File() - - public init() {} - - public func hello() -> String { - "Framework1File.hello()" - } - - public func helloFromFramework2() -> String { - "Framework1File -> \(framework2File.hello())" - } -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift deleted file mode 100644 index 609faf2b..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift +++ /dev/null @@ -1,19 +0,0 @@ -import XCTest - -@testable import StaticFramework1 - -class Framework1Tests: XCTestCase { - func testHello() { - let sut = Framework1File() - - XCTAssertEqual("Framework1File.hello()", sut.hello()) - } - - #if canImport(Framework2) - func testHelloFromFramework2() { - let sut = Framework1File() - - XCTAssertEqual("Framework1File -> Framework2File.hello()", sut.helloFromFramework2()) - } - #endif -} diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Tuist/Config.swift deleted file mode 100644 index ff8e64fa..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Tuist/Config.swift +++ /dev/null @@ -1,3 +0,0 @@ -import ProjectDescription - -let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Workspace.swift b/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Workspace.swift deleted file mode 100644 index d63c5df6..00000000 --- a/Sources/TestSupport/Fixtures/ios_app_with_transitive_framework/Workspace.swift +++ /dev/null @@ -1,6 +0,0 @@ -import ProjectDescription - -let workspace = Workspace( - name: "Workspace", - projects: ["App", "Framework1", "StaticFramework1"] -) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist deleted file mode 100644 index a11b3ce7..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright ©. All rights reserved. - NSPrincipalClass - - - diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Project.swift deleted file mode 100644 index f5d10ede..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Project.swift +++ /dev/null @@ -1,30 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "Core", - targets: [ - .target( - name: "Core", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.Core", - infoPlist: "Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ] - ), - .target( - name: "CoreTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.CoreTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "Core"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift deleted file mode 100644 index 4fa1dac1..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -public class CoreClass { - public init() {} -} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist deleted file mode 100644 index f1d34193..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright ©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift deleted file mode 100644 index 0f871eaa..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation -import XCTest - -@testable import Core - -final class CoreClassTests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist deleted file mode 100644 index a11b3ce7..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright ©. All rights reserved. - NSPrincipalClass - - - diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Project.swift deleted file mode 100644 index f1c3b5cb..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Project.swift +++ /dev/null @@ -1,35 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "Data", - targets: [ - .target( - name: "Data", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.Data", - infoPlist: "Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ], - dependencies: [ - /* Target dependencies can be defined here */ - // .framework(path: "Frameworks/MyFramework.framework") - .project(target: "Core", path: "../CoreFramework"), - ] - ), - .target( - name: "DataTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.DataFrameworkTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "Data"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift deleted file mode 100644 index 3f40c7cf..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Core -import Foundation - -public class DataClass { - let core = CoreClass() - - public init() {} -} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist deleted file mode 100644 index f1d34193..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright ©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift deleted file mode 100644 index ece49c68..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation -import XCTest - -@testable import Data - -final class DataClassTests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist deleted file mode 100644 index a11b3ce7..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright ©. All rights reserved. - NSPrincipalClass - - - diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Project.swift deleted file mode 100644 index 4d1c420c..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Project.swift +++ /dev/null @@ -1,38 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "FrameworkA", - targets: [ - .target( - name: "FrameworkA", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.FrameworkA", - infoPlist: "Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ], - dependencies: [ - /* Target dependencies can be defined here */ - // .framework(path: "Frameworks/MyFramework.framework") - .project(target: "FeatureContracts", path: "../FeatureContracts"), - .project(target: "Core", path: "../CoreFramework"), - .project(target: "Data", path: "../DataFramework"), - .project(target: "UIComponents", path: "../UIComponentsFramework"), - ] - ), - .target( - name: "FrameworkATests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.FrameworkATests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "FrameworkA"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift deleted file mode 100644 index 4bd4ac87..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift +++ /dev/null @@ -1,10 +0,0 @@ -import FeatureContracts -import Foundation - -class FrameworkA { - func run(featureB: FeatureBContract) { - featureB.run() - let a = featureB.expose() - print(a) - } -} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist deleted file mode 100644 index f1d34193..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright ©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift deleted file mode 100644 index ea9d8b47..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation -import XCTest - -@testable import FrameworkA - -final class FrameworkATests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist deleted file mode 100644 index a11b3ce7..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright ©. All rights reserved. - NSPrincipalClass - - - diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Project.swift deleted file mode 100644 index 77e4fc63..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Project.swift +++ /dev/null @@ -1,36 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "FeatureContracts", - targets: [ - .target( - name: "FeatureContracts", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.FeatureContracts", - infoPlist: "Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ], - dependencies: [ - /* Target dependencies can be defined here */ - // .framework(path: "Frameworks/MyFramework.framework") - .project(target: "Data", path: "../DataFramework"), - .project(target: "Core", path: "../CoreFramework"), - ] - ), - .target( - name: "FeatureContractsTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.FeatureContractsTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "FeatureContracts"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift deleted file mode 100644 index dc57816f..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -public protocol FeatureAContract { - func run() -} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift deleted file mode 100644 index f41a3561..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Core -import Foundation - -public protocol FeatureBContract { - func run() - func expose() -> CoreClass -} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist deleted file mode 100644 index f1d34193..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright ©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift deleted file mode 100644 index 2f8b4bef..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation -import XCTest - -@testable import FrameworkA - -final class FrameworkAContractTests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist deleted file mode 100644 index a11b3ce7..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright ©. All rights reserved. - NSPrincipalClass - - - diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Project.swift deleted file mode 100644 index f4b82d87..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Project.swift +++ /dev/null @@ -1,35 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "UIComponents", - targets: [ - .target( - name: "UIComponents", - destinations: .iOS, - product: .staticFramework, - bundleId: "io.tuist.UIComponents", - infoPlist: "Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ], - dependencies: [ - /* Target dependencies can be defined here */ - // .framework(path: "Frameworks/MyFramework.framework") - .project(target: "FeatureContracts", path: "../FeatureContracts"), - ] - ), - .target( - name: "UIComponentsTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.UIComponentsTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "UIComponents"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift deleted file mode 100644 index 7783b747..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Data -import Foundation -import UIKit - -class UIComponentA: UIView { - let data = DataClass() -} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist deleted file mode 100644 index f1d34193..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright ©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift deleted file mode 100644 index 0f09132d..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation -import XCTest - -@testable import UIComponents - -final class UIComponentATests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist deleted file mode 100644 index c407fafb..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist +++ /dev/null @@ -1,43 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - NSHumanReadableCopyright - Copyright ©. All rights reserved. - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Project.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Project.swift deleted file mode 100644 index b2e3abe6..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Project.swift +++ /dev/null @@ -1,35 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "StaticApp", - targets: [ - .target( - name: "StaticApp", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.StaticApp", - infoPlist: "Info.plist", - sources: ["Sources/**"], - resources: [ - /* Path to resources can be defined here */ - // "Resources/**" - ], - dependencies: [ - /* Target dependencies can be defined here */ - // .framework(path: "Frameworks/MyFramework.framework") - .project(target: "FrameworkA", path: "../Frameworks/FeatureAFramework"), - ] - ), - .target( - name: "StaticAppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.StaticAppTests", - infoPlist: "Tests.plist", - sources: "Tests/**", - dependencies: [ - .target(name: "StaticApp"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift deleted file mode 100644 index 19603be9..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift +++ /dev/null @@ -1,18 +0,0 @@ -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? - - func application( - _: UIApplication, - didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() - return true - } -} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist deleted file mode 100644 index f1d34193..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright ©. All rights reserved. - - diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift deleted file mode 100644 index c3e283c6..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation -import XCTest - -@testable import StaticApp - -final class StaticAppTests: XCTestCase {} diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Tuist/Config.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Tuist/Config.swift deleted file mode 100644 index ff8e64fa..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Tuist/Config.swift +++ /dev/null @@ -1,3 +0,0 @@ -import ProjectDescription - -let config = Config() diff --git a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.swift b/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.swift deleted file mode 100644 index a0dbefd1..00000000 --- a/Sources/TestSupport/Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.swift +++ /dev/null @@ -1,9 +0,0 @@ -import ProjectDescription - -let workspace = Workspace( - name: "Workspace", - projects: [ - "StaticApp", - "Frameworks/**", - ] -) diff --git a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Info.plist b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Info.plist deleted file mode 100644 index 82ed201d..00000000 --- a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Info.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - ATSApplicationFontsPath - Fonts - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright ©. All rights reserved. - NSPrincipalClass - NSApplication - - diff --git a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift deleted file mode 100644 index 737b4827..00000000 --- a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift +++ /dev/null @@ -1,3 +0,0 @@ -import AppKit - -_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv) diff --git a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Project.swift b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Project.swift deleted file mode 100644 index 20d324dd..00000000 --- a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Project.swift +++ /dev/null @@ -1,25 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "App with SystemExtension", - targets: [ - .target( - name: "MainApp", - destinations: [.mac], - product: .app, - bundleId: "io.tuist.MainApp", - infoPlist: "MainApp/Info.plist", - sources: ["MainApp/Sources/**"], - dependencies: [ - .target(name: "SystemExtension"), - ] - ), - .target( - name: "SystemExtension", - destinations: [.mac], - product: .systemExtension, - bundleId: "io.tuist.SystemExtension", - sources: ["SystemExtension/Sources/**"] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift deleted file mode 100644 index 06697d60..00000000 --- a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift +++ /dev/null @@ -1,3 +0,0 @@ -import Foundation - -print("System Extension") diff --git a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Tuist/Config.swift b/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Tuist/Config.swift deleted file mode 100644 index ff8e64fa..00000000 --- a/Sources/TestSupport/Fixtures/macos_app_with_system_extension/Tuist/Config.swift +++ /dev/null @@ -1,3 +0,0 @@ -import ProjectDescription - -let config = Config() diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb878970..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 13613e3e..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/Contents.json b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift deleted file mode 100644 index 6c1f47a2..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift +++ /dev/null @@ -1,20 +0,0 @@ -import ModuleA -import SwiftUI - -struct ContentView: View { - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundColor(.accentColor) - Text("Hello, world!") - Text("\(#stringify(1 + 1))") - } - } -} - -struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift deleted file mode 100644 index 78f112a8..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift +++ /dev/null @@ -1,15 +0,0 @@ -import ModuleA -import SwiftUI - -@main -struct TestApp: App { - init() { - ModuleA.test() - } - - var body: some Scene { - WindowGroup { - ContentView() - } - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift deleted file mode 100644 index 3624b5cb..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift +++ /dev/null @@ -1,23 +0,0 @@ -import SwiftCompilerPlugin -import SwiftSyntax -import SwiftSyntaxMacros - -@main -struct ModuleAMacros: CompilerPlugin { - var providingMacros: [Macro.Type] = [ - StringifyMacro.self, - ] -} - -public struct StringifyMacro: ExpressionMacro { - public static func expansion( - of node: some FreestandingMacroExpansionSyntax, - in _: some MacroExpansionContext - ) -> ExprSyntax { - guard let argument = node.arguments.first?.expression else { - fatalError("compiler bug: the macro does not have any arguments") - } - - return "(\(argument), \(literal: argument.description))" - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift deleted file mode 100644 index 2a8156b3..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift +++ /dev/null @@ -1,3 +0,0 @@ -@freestanding(expression) -public macro stringify(_ value: T) -> (T, String) = - #externalMacro(module: "ModuleAMacros", type: "StringifyMacro") diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift deleted file mode 100644 index b99b065a..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift +++ /dev/null @@ -1,12 +0,0 @@ -import CasePaths - -@CasePathable -enum AppAction { - case home -} - -public enum ModuleA { - public static func test() { - print("Module A") - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift deleted file mode 100644 index ba961a38..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift +++ /dev/null @@ -1,23 +0,0 @@ -import SwiftSyntaxMacros -import SwiftSyntaxMacrosTestSupport -import XCTest - -@testable import ModuleAMacros_Testable - -final class StringifyMacroTests: XCTestCase { - let testMacros: [String: Macro.Type] = [ - "stringify": StringifyMacro.self, - ] - - func testStringifyStruct() throws { - assertMacroExpansion( - """ - #stringify(1+1) - """, - expandedSource: """ - (1 + 1, "1+1") - """, - macros: testMacros - ) - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Project.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Project.swift deleted file mode 100644 index 82bebfd9..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Project.swift +++ /dev/null @@ -1,107 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "AppWithWatchApp", - targets: [ - .target( - name: "App", - destinations: [.iPhone, .appleVision], - product: .app, - bundleId: "io.tuist.App", - infoPlist: .default, - sources: [ - "App/Sources/**", - ], - resources: [ - "App/Resources/**", - ], - dependencies: [ - .target(name: "WatchApp", condition: .when([.ios])), - .target(name: "ModuleA"), - ] - ), - .target( - name: "WatchApp", - destinations: [.appleWatch], - product: .app, - bundleId: "io.tuist.App.watchkitapp", - infoPlist: nil, - sources: "WatchApp/Sources/**", - resources: "WatchApp/Resources/**", - dependencies: [ - .target(name: "ModuleA"), - ], - settings: .settings( - base: [ - "GENERATE_INFOPLIST_FILE": true, - "CURRENT_PROJECT_VERSION": "1.0", - "MARKETING_VERSION": "1.0", - "INFOPLIST_KEY_UISupportedInterfaceOrientations": [ - "UIInterfaceOrientationPortrait", - "UIInterfaceOrientationPortraitUpsideDown", - ], - "INFOPLIST_KEY_WKCompanionAppBundleIdentifier": "io.tuist.App", - "INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp": false, - ] - ) - ), - .target( - name: "ModuleA", - destinations: [.iPhone, .appleVision, .appleWatch], - product: .framework, - productName: "ModuleA", - bundleId: "io.tuist.modulea", - sources: [ - "Modules/ModuleA/Sources/**", - ], - dependencies: [ - .external(name: "CasePaths"), - .target(name: "ModuleAMacros"), - ] - ), - .target( - name: "ModuleATests", - destinations: [.iPhone, .appleVision, .appleWatch], - product: .unitTests, - productName: "ModuleATests", - bundleId: "io.tuist.moduleatests", - sources: [ - "Modules/ModuleA/Tests/**", - ], - dependencies: [ - .target(name: "ModuleA"), - .target(name: "ModuleAMacros_Testable"), - .external(name: "SwiftSyntaxMacrosTestSupport"), - ] - ), - .target( - name: "ModuleAMacros", - destinations: .macOS, - product: .macro, - productName: "ModuleAMacros", - bundleId: "io.tuist.moduleamacros", - deploymentTargets: .macOS("14.0"), - sources: [ - "Modules/ModuleA/Macros/Sources/**", - ], - dependencies: [ - .external(name: "SwiftSyntaxMacros"), - .external(name: "SwiftCompilerPlugin"), - ] - ), - .target( - name: "ModuleAMacros_Testable", - destinations: [.iPhone, .appleVision, .appleWatch], // Must match platform of the test target - product: .framework, // Must match be a linkable product - productName: "ModuleAMacros_Testable", - bundleId: "io.tuist.moduleamacros.testable", - sources: [ - "Modules/ModuleA/Macros/Sources/**", - ], - dependencies: [ - .external(name: "SwiftSyntaxMacros"), - .external(name: "SwiftCompilerPlugin"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.resolved b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.resolved deleted file mode 100644 index 105e045a..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.resolved +++ /dev/null @@ -1,32 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swift-case-paths", - "kind" : "remoteSourceControl", - "location" : "https://github.com/pointfreeco/swift-case-paths", - "state" : { - "revision" : "bc92c4b27f9a84bfb498cdbfdf35d5a357e9161f", - "version" : "1.5.6" - } - }, - { - "identity" : "swift-syntax", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-syntax", - "state" : { - "revision" : "2bc86522d115234d1f588efe2bcb4ce4be8f8b82", - "version" : "510.0.3" - } - }, - { - "identity" : "xctest-dynamic-overlay", - "kind" : "remoteSourceControl", - "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", - "state" : { - "revision" : "a3f634d1a409c7979cabc0a71b3f26ffa9fc8af1", - "version" : "1.4.3" - } - } - ], - "version" : 2 -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.swift deleted file mode 100644 index de8d34a9..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/Package.swift +++ /dev/null @@ -1,23 +0,0 @@ -// swift-tools-version: 5.9 -import PackageDescription - -#if TUIST - import ProjectDescription - - let packageSettings = PackageSettings( - baseSettings: .settings( - base: [ - "ENABLE_USER_SCRIPT_SANDBOXING": true, - ] - ) - ) - -#endif - -let package = Package( - name: "Dependencies", - dependencies: [ - .package(url: "https://github.com/pointfreeco/swift-case-paths", from: "1.5.6"), - .package(url: "https://github.com/apple/swift-syntax", "510.0.3" ..< "601.0.0-prerelease"), - ] -) diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AccentColor.colorset/Contents.json b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb878970..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 49c81cd8..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "platform" : "watchos", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/Contents.json b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift deleted file mode 100644 index 8b74b2b1..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift +++ /dev/null @@ -1,18 +0,0 @@ -import SwiftUI - -struct ContentView: View { - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundColor(.accentColor) - Text("Hello, world!") - } - } -} - -struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift deleted file mode 100644 index 0755c22e..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift +++ /dev/null @@ -1,21 +0,0 @@ -import CasePaths -import ModuleA -import SwiftUI - -@CasePathable -enum WatchAppAction { - case home -} - -@main -struct WatchApp: App { - init() { - ModuleA.test() - } - - var body: some Scene { - WindowGroup { - ContentView() - } - } -} diff --git a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift b/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift deleted file mode 100644 index 4485cd7c..00000000 --- a/Sources/TestSupport/Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -public enum WatchConfig { - public static let title: String = "Hello, watchOS" -} diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Project.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Project.swift deleted file mode 100644 index ca2b3dc2..00000000 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Project.swift +++ /dev/null @@ -1,28 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "ProjectA", - organizationName: "tuist.io", - targets: [ - .target( - name: "App", - destinations: .iOS, - product: .app, - bundleId: "io.tuist.app", - deploymentTargets: DeploymentTargets.iOS("13.0"), - infoPlist: .default, - sources: ["Targets/App/Sources/**"] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.AppTests", - infoPlist: .default, - sources: ["Targets/App/Tests/**"], - dependencies: [ - .target(name: "App"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Sources/AppDelegate.swift deleted file mode 100644 index 4cde399e..00000000 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Sources/AppDelegate.swift +++ /dev/null @@ -1,19 +0,0 @@ -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? - - func application( - _: UIApplication, - didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() - - return true - } -} diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Tests/AppTests.swift deleted file mode 100644 index 70c453ba..00000000 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectA/Targets/App/Tests/AppTests.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Foundation -import XCTest - -final class AppTests: XCTestCase { - func test_twoPlusTwo_isFour() { - XCTAssertEqual(2 + 2, 4) - } -} diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/.gitignore b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/.gitignore deleted file mode 100644 index c8512dae..00000000 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/.gitignore +++ /dev/null @@ -1,67 +0,0 @@ -### macOS ### -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### Xcode ### -# Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore - -## User settings -xcuserdata/ - -## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) -*.xcscmblueprint -*.xccheckout - -## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) -build/ -DerivedData/ -*.moved-aside -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 - -### Xcode Patch ### -*.xcodeproj/* -!*.xcodeproj/project.pbxproj -!*.xcodeproj/xcshareddata/ -!*.xcworkspace/contents.xcworkspacedata -/*.gcno - -### Projects ### -*.xcodeproj -*.xcworkspace - -### Tuist derived files ### -graph.dot -Derived/ diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Project.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Project.swift deleted file mode 100644 index 2eea208d..00000000 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Project.swift +++ /dev/null @@ -1,28 +0,0 @@ -import ProjectDescription - -let project = Project( - name: "ProjectB", - organizationName: "tuist.io", - targets: [ - .target( - name: "App", - destinations: [.iPhone], - product: .app, - bundleId: "io.tuist.app", - deploymentTargets: .iOS("13.0"), - infoPlist: .default, - sources: ["Targets/App/Sources/**"] - ), - .target( - name: "AppTests", - destinations: .iOS, - product: .unitTests, - bundleId: "io.tuist.AppTests", - infoPlist: .default, - sources: ["Targets/App/Tests/**"], - dependencies: [ - .target(name: "App"), - ] - ), - ] -) diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Sources/AppDelegate.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Sources/AppDelegate.swift deleted file mode 100644 index 4cde399e..00000000 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Sources/AppDelegate.swift +++ /dev/null @@ -1,19 +0,0 @@ -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? - - func application( - _: UIApplication, - didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - let viewController = UIViewController() - viewController.view.backgroundColor = .white - window?.rootViewController = viewController - window?.makeKeyAndVisible() - - return true - } -} diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Tests/AppTests.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Tests/AppTests.swift deleted file mode 100644 index 70c453ba..00000000 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/ProjectB/Targets/App/Tests/AppTests.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Foundation -import XCTest - -final class AppTests: XCTestCase { - func test_twoPlusTwo_isFour() { - XCTAssertEqual(2 + 2, 4) - } -} diff --git a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/Workspace.swift b/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/Workspace.swift deleted file mode 100644 index 09929f52..00000000 --- a/Sources/TestSupport/Fixtures/workspace_with_multiple_projects/Workspace.swift +++ /dev/null @@ -1,9 +0,0 @@ -import ProjectDescription - -let workspace = Workspace( - name: "Tuist", - projects: [ - "ProjectA", - "ProjectB", - ] -) diff --git a/Sources/TestSupport/Mocks/WorkspaceFixture.swift b/Sources/TestSupport/Mocks/WorkspaceFixture.swift deleted file mode 100644 index 3ff8d816..00000000 --- a/Sources/TestSupport/Mocks/WorkspaceFixture.swift +++ /dev/null @@ -1,41 +0,0 @@ -import Foundation -import Path -import XcodeGraph - -// MARK: - Workspace Fixtures - -/// Provides references to sample Xcode workspace fixtures for testing. -public enum WorkspaceFixture: String, CaseIterable { - case commandLineToolWithDynamicFramework = - "command_line_tool_with_dynamic_framework/CommandLineTool" - case iosAppWithRemoteSwiftPackage = "ios_app_with_remote_swift_package/App" - case iosAppWithSpmDependencies = "ios_app_with_spm_dependencies/App" - case iosAppWithExtensions = "ios_app_with_extensions/App" - case iosAppWithMultiConfigs = "ios_app_with_multi_configs/Workspace" - case iosWorkspaceWithMicrofeatureArchitectureStaticLinking = - "ios_workspace_with_microfeature_architecture_static_linking/Workspace" - case multiplatformAppWithMacrosAndEmbeddedWatchosApp = - "multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp" - case iosAppLarge = "ios_app_large/App" - case ios_app_with_transitive_framework = "ios_app_with_transitive_framework/Workspace" - case macosAppWithSystemExtension = "macos_app_with_system_extension/App with SystemExtension" - case iosAppWithStaticLibraries = - "ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries" - - public var fileExtension: String { "xcworkspace" } - - /// Returns the absolute path to the fixture workspace. Adjust the base path as needed. - public func absolutePath() throws -> AbsolutePath { - print(#filePath) - - let relativePath = try RelativePath(validating: "Fixtures/\(rawValue).\(fileExtension)") - let p = try AbsolutePath.resolvePath(#filePath) - .parentDirectory - .parentDirectory - .appending(relativePath) - - print(p) - - return p - } -} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/IntegrationTests.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/IntegrationTests.swift deleted file mode 100644 index 2178d2e0..00000000 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/IntegrationTests.swift +++ /dev/null @@ -1,197 +0,0 @@ -import Foundation -import InlineSnapshotTesting -import Path -import RegexBuilder -import Testing -import XcodeGraph -import XcodeProj -import XcodeProjToGraph - -@testable import TestSupport - -struct GraphDependencyTestableMap: Encodable, Comparable { - static func < (lhs: GraphDependencyTestableMap, rhs: GraphDependencyTestableMap) -> Bool { - lhs.key < rhs.key - } - - let key: GraphDependency - let values: [GraphDependency] - - init(key: GraphDependency, values: Set) { - self.key = key - self.values = Array(values).sorted() - } -} - -@Suite( - .snapshots( - // Change this re-recored etc - record: .failed - ) -) -struct IntegrationTests { - func assertGraph( - of fixture: () -> WorkspaceFixture, - name: (() -> String)? = nil, - dependencies: (() -> String)? = nil, - dependencyConditions: (() -> String)? = nil, - packages: (() -> String)? = nil, - workspace: (() -> String)? = nil, - projects: (() -> String)? = nil, - fileID: StaticString = #fileID, - file filePath: StaticString = #filePath, - function: StaticString = #function, - line: UInt = #line, - column: UInt = #column - ) async throws { - let path = try fixture().absolutePath() - - let fullGraph: XcodeGraph.Graph = try await ProjectParser.parse(atPath: path.pathString) - - let graph = try fullGraph.normalizeGraphPaths().minimizeGraph() - - assertInlineSnapshot( - of: graph.name, - as: .dump, - message: "Dependency Conditions did not match", - syntaxDescriptor: InlineSnapshotSyntaxDescriptor( - trailingClosureLabel: "name", - trailingClosureOffset: 1 - ), - matches: name, - fileID: fileID, - file: filePath, - function: function, - line: line, - column: column - ) - assertInlineSnapshot( - of: graph.dependencies, - as: .dump, - message: "Dependencies did not match", - syntaxDescriptor: InlineSnapshotSyntaxDescriptor( - trailingClosureLabel: "dependencies", - trailingClosureOffset: 2 - ), - matches: dependencies, - fileID: fileID, - file: filePath, - function: function, - line: line, - column: column - ) - assertInlineSnapshot( - of: graph.dependencyConditions, - as: .dump, - message: "Dependency Conditions did not match", - syntaxDescriptor: InlineSnapshotSyntaxDescriptor( - trailingClosureLabel: "dependencyConditions", - trailingClosureOffset: 3 - ), - matches: dependencyConditions, - fileID: fileID, - file: filePath, - function: function, - line: line, - column: column - ) - assertInlineSnapshot( - of: graph.packages, - as: .dump, - message: "Packages did not match", - syntaxDescriptor: InlineSnapshotSyntaxDescriptor( - trailingClosureLabel: "packages", - trailingClosureOffset: 4 - ), - matches: packages, - fileID: fileID, - file: filePath, - function: function, - line: line, - column: column - ) - assertInlineSnapshot( - of: graph.workspace, - as: .dump, - message: "Workspace did not match", - syntaxDescriptor: InlineSnapshotSyntaxDescriptor( - trailingClosureLabel: "workspace", - trailingClosureOffset: 5 - ), - matches: workspace, - fileID: fileID, - file: filePath, - function: function, - line: line, - column: column - ) - assertInlineSnapshot( - of: graph.projects, - as: .dump, - message: "Projects did not match", - syntaxDescriptor: InlineSnapshotSyntaxDescriptor( - trailingClosureLabel: "projects", - trailingClosureOffset: 6 - ), - matches: projects, - fileID: fileID, - file: filePath, - function: function, - line: line, - column: column - ) - } -} - -extension XcodeGraph.Graph { - func normalizeGraphPaths() throws -> XcodeGraph.Graph { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - - let data = try encoder.encode(self) - var jsonString = String(decoding: data, as: UTF8.self) - - // Normalize any prefix before /Fixtures. - jsonString = jsonString.replacingOccurrences( - of: #"[^"]*?/Fixtures"#, - with: "/Fixtures", - options: [.regularExpression] - ) - - let decoder = JSONDecoder() - let normalizedGraph = try decoder.decode(XcodeGraph.Graph.self, from: Data(jsonString.utf8)) - - return normalizedGraph - } - - func minimizeGraph() -> Graph { - var graph = self - graph.workspace.schemes = [] - graph.workspace.generationOptions = .test() - - for (key, project) in graph.projects { - graph.projects[key]?.schemes = [] - graph.projects[key]?.resourceSynthesizers = [] - graph.projects[key]?.settings = Settings(configurations: [:]) - - for targetKey in project.targets.keys { - graph.projects[key]?.targets[targetKey]?.scripts = [] - graph.projects[key]?.targets[targetKey]?.playgrounds = [] - graph.projects[key]?.targets[targetKey]?.rawScriptBuildPhases = [] - graph.projects[key]?.targets[targetKey]?.playgrounds = [] - graph.projects[key]?.targets[targetKey]?.buildRules = [] - graph.projects[key]?.targets[targetKey]?.settings = nil - graph.projects[key]?.targets[targetKey]?.infoPlist = nil - graph.projects[key]?.targets[targetKey]?.destinations = [] - } - } - - return graph - } -} - -extension AbsolutePath: @retroactive AnySnapshotStringConvertible { - public var snapshotDescription: String { - return pathString - } -} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift deleted file mode 100644 index a533654c..00000000 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift +++ /dev/null @@ -1,251 +0,0 @@ -import Foundation -import InlineSnapshotTesting -import Path -import Testing -import XcodeGraph -import XcodeProj -import XcodeProjToGraph - -@testable import TestSupport - -extension IntegrationTests { - @Test("Maps a command-line tool with a dynamic framework dependency into the correct graph") - func commandLineToolWithDynamicFramework() async throws { - try await assertGraph { - .commandLineToolWithDynamicFramework - } name: { - """ - - "CommandLineTool" - - """ - } dependencies: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - ▿ key: target 'CommandLineTool' - ▿ target: (3 elements) - - name: "CommandLineTool" - - path: /Fixtures/command_line_tool_with_dynamic_framework - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'DynamicFramework' - ▿ target: (3 elements) - - name: "DynamicFramework" - - path: /Fixtures/command_line_tool_with_dynamic_framework - - status: LinkingStatus.required - - """ - } dependencyConditions: { - """ - - 0 key/value pairs - - """ - } packages: { - """ - - 0 key/value pairs - - """ - } workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "CommandLineTool" - - path: /Fixtures/command_line_tool_with_dynamic_framework - ▿ projects: 1 element - - /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcworkspace - - """ - } projects: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcodeproj - ▿ value: CommandLineTool - - path: /Fixtures/command_line_tool_with_dynamic_framework - - sourceRootPath: /Fixtures/command_line_tool_with_dynamic_framework - - xcodeProjPath: /Fixtures/command_line_tool_with_dynamic_framework - - name: "CommandLineTool" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "CommandLineTool" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/command_line_tool_with_dynamic_framework/Derived/InfoPlists/CommandLineTool-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/command_line_tool_with_dynamic_framework/Derived/InfoPlists/DynamicFramework-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift - - buildRules: 0 elements - - bundleId: "com.example.commandlinetool" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "DynamicFramework" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "CommandLineTool" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: command line tool - - productName: "CommandLineTool" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift - ▿ (2 elements) - - key: "DynamicFramework" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/command_line_tool_with_dynamic_framework/Derived/InfoPlists/CommandLineTool-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/command_line_tool_with_dynamic_framework/Derived/InfoPlists/DynamicFramework-Info.plist - - buildRules: 0 elements - - bundleId: "com.example.dynamicframework" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "DynamicFramework" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "DynamicFramework" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - - """ - } - } -} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift deleted file mode 100644 index ba81f5f0..00000000 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift +++ /dev/null @@ -1,20 +0,0 @@ -import Foundation -import InlineSnapshotTesting -import Path -import Testing -import XcodeGraph -import XcodeProj -import XcodeProjToGraph - -@testable import TestSupport - -extension IntegrationTests { - @Test("Maps a large iOS app project into the correct graph") - func iosAppLarge() async throws { - let path = try WorkspaceFixture.iosAppLarge.absolutePath() - - let graph: XcodeGraph.Graph = try await ProjectParser.parse(projectType: .workspace(path)) - - #expect(graph.projects.first?.value.targets.count == 300) - } -} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift deleted file mode 100644 index 1e345a07..00000000 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift +++ /dev/null @@ -1,1378 +0,0 @@ -import Foundation -import InlineSnapshotTesting -import Path -import Testing -import XcodeGraph -import XcodeProj -import XcodeProjToGraph - -@testable import TestSupport - -extension IntegrationTests { - @Test("Maps an iOS app with extensions into the correct graph") - func iosAppWithExtensions() async throws { - try await assertGraph { - .iosAppWithExtensions - } name: { - """ - - "App" - - """ - } dependencies: { - """ - ▿ 3 key/value pairs - ▿ (2 elements) - ▿ key: target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ value: 4 members - ▿ target 'AppIntentExtension' - ▿ target: (3 elements) - - name: "AppIntentExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ target 'NotificationServiceExtension' - ▿ target: (3 elements) - - name: "NotificationServiceExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ target 'StickersPackExtension' - ▿ target: (3 elements) - - name: "StickersPackExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ target 'WidgetExtension' - ▿ target: (3 elements) - - name: "WidgetExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'AppWithMessagesExtension' - ▿ target: (3 elements) - - name: "AppWithMessagesExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ value: 2 members - ▿ target 'MessageExtension' - ▿ target: (3 elements) - - name: "MessageExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ target 'NotificationServiceExtension' - ▿ target: (3 elements) - - name: "NotificationServiceExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'WidgetExtension' - ▿ target: (3 elements) - - name: "WidgetExtension" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ value: 2 members - ▿ target 'Bundle' - ▿ target: (3 elements) - - name: "Bundle" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - ▿ target 'StaticFramework' - ▿ target: (3 elements) - - name: "StaticFramework" - - path: /Fixtures/ios_app_with_extensions - - status: LinkingStatus.required - - """ - } dependencyConditions: { - """ - - 0 key/value pairs - - """ - } packages: { - """ - - 0 key/value pairs - - """ - } workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "App" - - path: /Fixtures/ios_app_with_extensions - ▿ projects: 1 element - - /Fixtures/ios_app_with_extensions/App.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_app_with_extensions/App.xcworkspace - - """ - } projects: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/ios_app_with_extensions/App.xcodeproj - ▿ value: App - - path: /Fixtures/ios_app_with_extensions - - sourceRootPath: /Fixtures/ios_app_with_extensions - - xcodeProjPath: /Fixtures/ios_app_with_extensions - - name: "App" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 9 key/value pairs - ▿ (2 elements) - - key: "App" - ▿ value: Target - ▿ additionalFiles: 23 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - - buildRules: 0 elements - - bundleId: "io.tuist.App" - ▿ copyFiles: 3 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Embed ExtensionKit Extensions" - ▿ subpath: Optional - - some: "$(EXTENSIONS_FOLDER_PATH)" - ▿ CopyFilesAction - - destination: Destination.plugins - - files: 0 elements - - name: "Embed Foundation Extensions" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 4 elements - ▿ TargetDependency - ▿ target: (3 elements) - - name: "AppIntentExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "NotificationServiceExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "StickersPackExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "WidgetExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 2 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc - ▿ (2 elements) - - key: "AppIntentExtension" - ▿ value: Target - ▿ additionalFiles: 23 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - - buildRules: 0 elements - - bundleId: "io.tuist.App.AppIntentExtension" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppIntentExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: extensionKit extension - - productName: "AppIntentExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 2 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift - ▿ (2 elements) - - key: "AppWithMessagesExtension" - ▿ value: Target - ▿ additionalFiles: 23 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - - buildRules: 0 elements - - bundleId: "io.tuist.App2" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.plugins - - files: 0 elements - - name: "Embed Foundation Extensions" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 2 elements - ▿ TargetDependency - ▿ target: (3 elements) - - name: "MessageExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "NotificationServiceExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppWithMessagesExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "AppWithMessagesExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 2 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc - ▿ (2 elements) - - key: "Bundle" - ▿ value: Target - ▿ additionalFiles: 24 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - - buildRules: 0 elements - - bundleId: "io.tuist.App.Bundle" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Bundle" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: bundle - - productName: "Bundle" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 1 element - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - - sources: 0 elements - ▿ (2 elements) - - key: "MessageExtension" - ▿ value: Target - ▿ additionalFiles: 21 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - - buildRules: 0 elements - - bundleId: "io.tuist.App2.MessageExtension" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "MessageExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: iMessage extension - - productName: "MessageExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 2 elements - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 3 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift - ▿ (2 elements) - - key: "NotificationServiceExtension" - ▿ value: Target - ▿ additionalFiles: 24 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - - buildRules: 0 elements - - bundleId: "io.tuist.App.NotificationServiceExtension" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "NotificationServiceExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: app extension - - productName: "NotificationServiceExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift - ▿ (2 elements) - - key: "StaticFramework" - ▿ value: Target - ▿ additionalFiles: 24 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - - buildRules: 0 elements - - bundleId: "io.tuist.App.StaticFramework" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "StaticFramework" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "StaticFramework" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift - ▿ (2 elements) - - key: "StickersPackExtension" - ▿ value: Target - ▿ additionalFiles: 24 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - - buildRules: 0 elements - - bundleId: "io.tuist.App.StickersPackExtension" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "StickersPackExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: sticker pack extension - - productName: "StickersPackExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 1 element - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - - sources: 0 elements - ▿ (2 elements) - - key: "WidgetExtension" - ▿ value: Target - ▿ additionalFiles: 21 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets - - buildRules: 0 elements - - bundleId: "io.tuist.App.WidgetExtension" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 2 elements - ▿ TargetDependency - ▿ target: (3 elements) - - name: "Bundle" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "StaticFramework" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "WidgetExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: app extension - - productName: "WidgetExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 1 element - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 3 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - - """ - } - } -} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift deleted file mode 100644 index bc040ab7..00000000 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift +++ /dev/null @@ -1,677 +0,0 @@ -import Foundation -import InlineSnapshotTesting -import Path -import Testing -import XcodeGraph -import XcodeProj -import XcodeProjToGraph - -@testable import TestSupport - -extension IntegrationTests { - @Test("Maps an iOS app with multiple configurations into the correct graph") - func iosAppWithMultiConfigs() async throws { - try await assertGraph { - .iosAppWithMultiConfigs - } name: { - """ - - "Workspace" - - """ - } dependencies: { - """ - ▿ 3 key/value pairs - ▿ (2 elements) - ▿ key: target 'AppTests' - ▿ target: (3 elements) - - name: "AppTests" - - path: /Fixtures/ios_app_with_multi_configs/App - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_multi_configs/App - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'Framework1Tests' - ▿ target: (3 elements) - - name: "Framework1Tests" - - path: /Fixtures/ios_app_with_multi_configs/Framework1 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'Framework1' - ▿ target: (3 elements) - - name: "Framework1" - - path: /Fixtures/ios_app_with_multi_configs/Framework1 - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'Framework2Tests' - ▿ target: (3 elements) - - name: "Framework2Tests" - - path: /Fixtures/ios_app_with_multi_configs/Framework2 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'Framework2' - ▿ target: (3 elements) - - name: "Framework2" - - path: /Fixtures/ios_app_with_multi_configs/Framework2 - - status: LinkingStatus.required - - """ - } dependencyConditions: { - """ - - 0 key/value pairs - - """ - } packages: { - """ - - 0 key/value pairs - - """ - } workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "Workspace" - - path: /Fixtures/ios_app_with_multi_configs - ▿ projects: 3 elements - - /Fixtures/ios_app_with_multi_configs/App/MainApp.xcodeproj - - /Fixtures/ios_app_with_multi_configs/Framework1/Framework1.xcodeproj - - /Fixtures/ios_app_with_multi_configs/Framework2/Framework2.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_app_with_multi_configs/Workspace.xcworkspace - - """ - } projects: { - """ - ▿ 3 key/value pairs - ▿ (2 elements) - - key: /Fixtures/ios_app_with_multi_configs/App/MainApp.xcodeproj - ▿ value: MainApp - - path: /Fixtures/ios_app_with_multi_configs/App - - sourceRootPath: /Fixtures/ios_app_with_multi_configs/App - - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/App - - name: "MainApp" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "App" - ▿ value: Target - ▿ additionalFiles: 6 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig - - buildRules: 0 elements - - bundleId: "io.tuist.App" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift - ▿ (2 elements) - - key: "AppTests" - ▿ value: Target - ▿ additionalFiles: 6 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig - - buildRules: 0 elements - - bundleId: "io.tuist.AppTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "App" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "AppTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_app_with_multi_configs/Framework1/Framework1.xcodeproj - ▿ value: Framework1 - - path: /Fixtures/ios_app_with_multi_configs/Framework1 - - sourceRootPath: /Fixtures/ios_app_with_multi_configs/Framework1 - - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/Framework1 - - name: "Framework1" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "Framework1" - ▿ value: Target - ▿ additionalFiles: 6 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.Framework1" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework1" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "Framework1" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift - ▿ (2 elements) - - key: "Framework1Tests" - ▿ value: Target - ▿ additionalFiles: 6 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist - - buildRules: 0 elements - - bundleId: "io.tuist.Framework1Tests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "Framework1" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework1Tests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "Framework1Tests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_app_with_multi_configs/Framework2/Framework2.xcodeproj - ▿ value: Framework2 - - path: /Fixtures/ios_app_with_multi_configs/Framework2 - - sourceRootPath: /Fixtures/ios_app_with_multi_configs/Framework2 - - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/Framework2 - - name: "Framework2" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "Framework2" - ▿ value: Target - ▿ additionalFiles: 7 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.Framework2" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework2" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "Framework2" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift - ▿ (2 elements) - - key: "Framework2Tests" - ▿ value: Target - ▿ additionalFiles: 7 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist - - buildRules: 0 elements - - bundleId: "io.tuist.Framework2Tests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "Framework2" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework2Tests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "Framework2Tests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - - """ - } - } -} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift deleted file mode 100644 index 449e5da7..00000000 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift +++ /dev/null @@ -1,274 +0,0 @@ -import Foundation -import InlineSnapshotTesting -import Path -import Testing -import XcodeGraph -import XcodeProj -import XcodeProjToGraph - -@testable import TestSupport - -extension IntegrationTests { - @Test - func projectNoWorkspace() async throws { - let path = try WorkspaceFixture.iosAppWithRemoteSwiftPackage.absolutePath() - let graph: XcodeGraph.Graph = try await ProjectParser.parse(projectType: .xcodeProject(path)) - - try #require(graph != nil) - } - - @Test("Maps an iOS app with a remote Swift package into the correct graph") - func iosAppWithRemoteSwiftPackage() async throws { - try await assertGraph { - .iosAppWithRemoteSwiftPackage - } name: { - """ - - "App" - - """ - } dependencies: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - ▿ key: target 'AppTests' - ▿ target: (3 elements) - - name: "AppTests" - - path: /Fixtures/ios_app_with_remote_swift_package - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_remote_swift_package - - status: LinkingStatus.required - - """ - } dependencyConditions: { - """ - - 0 key/value pairs - - """ - } packages: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj - ▿ value: 1 key/value pair - ▿ (2 elements) - - key: "https://github.com/ReactiveX/RxSwift" - ▿ value: Package - ▿ remote: (2 elements) - - url: "https://github.com/ReactiveX/RxSwift" - ▿ requirement: Requirement - - upToNextMajor: "5.0.0" - - """ - } workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "App" - - path: /Fixtures/ios_app_with_remote_swift_package - ▿ projects: 1 element - - /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_app_with_remote_swift_package/App.xcworkspace - - """ - } projects: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj - ▿ value: App - - path: /Fixtures/ios_app_with_remote_swift_package - - sourceRootPath: /Fixtures/ios_app_with_remote_swift_package - - xcodeProjPath: /Fixtures/ios_app_with_remote_swift_package - - name: "App" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "App" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_remote_swift_package/Support/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.App" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift - ▿ (2 elements) - - key: "AppTests" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_remote_swift_package/Support/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist - - buildRules: 0 elements - - bundleId: "io.tuist.AppTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "App" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "AppTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift - ▿ packages: 1 element - ▿ Package - ▿ remote: (2 elements) - - url: "https://github.com/ReactiveX/RxSwift" - ▿ requirement: Requirement - - upToNextMajor: "5.0.0" - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - - """ - } - } -} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift deleted file mode 100644 index fdbe4473..00000000 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithSpmDependencies.swift +++ /dev/null @@ -1,308 +0,0 @@ -import Foundation -import InlineSnapshotTesting -import Path -import Testing -import XcodeGraph -import XcodeProj -import XcodeProjToGraph - -@testable import TestSupport - -extension IntegrationTests { - @Test("Maps an iOS app with SPM dependencies into the correct graph") - func iosAppWithSpmDependencies() async throws { - try await assertGraph { - .iosAppWithSpmDependencies - } name: { - """ - - "App" - - """ - } dependencies: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - ▿ key: target 'AppTests' - ▿ target: (3 elements) - - name: "AppTests" - - path: /Fixtures/ios_app_with_spm_dependencies - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_spm_dependencies - - status: LinkingStatus.required - - """ - } dependencyConditions: { - """ - - 0 key/value pairs - - """ - } packages: { - """ - - 0 key/value pairs - - """ - } workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "App" - - path: /Fixtures/ios_app_with_spm_dependencies - ▿ projects: 8 elements - - /Fixtures/ios_app_with_spm_dependencies/App.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/BigInt/BigInt.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/KSCrash/KSCrash.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/Mobile Buy SDK/Mobile Buy SDK.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/jwt-kit/jwt-kit.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/swift-asn1/swift-asn1.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/swift-certificates/swift-certificates.xcodeproj - - /Fixtures/ios_app_with_spm_dependencies/Tuist/.build/tuist-derived/swift-crypto/swift-crypto.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_app_with_spm_dependencies/App.xcworkspace - - """ - } projects: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/ios_app_with_spm_dependencies/App.xcodeproj - ▿ value: App - - path: /Fixtures/ios_app_with_spm_dependencies - - sourceRootPath: /Fixtures/ios_app_with_spm_dependencies - - xcodeProjPath: /Fixtures/ios_app_with_spm_dependencies - - name: "App" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "App" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_spm_dependencies/Derived/InfoPlists/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_spm_dependencies/Derived/InfoPlists/AppTests-Info.plist - - buildRules: 0 elements - - bundleId: "io.tuist.app" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - ▿ iOS: Optional - - some: "16.0" - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 2 elements - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 4 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_spm_dependencies/Derived/Sources/TuistAssets+App.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_spm_dependencies/Derived/Sources/TuistBundle+App.swift - ▿ (2 elements) - - key: "AppTests" - ▿ value: Target - ▿ additionalFiles: 8 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_spm_dependencies/App/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_spm_dependencies/App/Resources/Preview Content/Preview Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_spm_dependencies/App/Sources/AppApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_spm_dependencies/App/Sources/ContentView.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_spm_dependencies/Derived/InfoPlists/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_spm_dependencies/Derived/InfoPlists/AppTests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_spm_dependencies/Derived/Sources/TuistAssets+App.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_spm_dependencies/Derived/Sources/TuistBundle+App.swift - - buildRules: 0 elements - - bundleId: "io.tuist.app.tests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "App" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - ▿ iOS: Optional - - some: "16.0" - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "AppTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_spm_dependencies/AppTests/AppTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - - """ - } - } -} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift deleted file mode 100644 index 527666f6..00000000 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift +++ /dev/null @@ -1,653 +0,0 @@ -import Foundation -import InlineSnapshotTesting -import Path -import Testing -import XcodeGraph -import XcodeProj -import XcodeProjToGraph - -@testable import TestSupport - -extension IntegrationTests { - @Test("Maps an iOS app with transitive static libraries into the correct graph") - func iosAppWithStaticLibraries() async throws { - try await assertGraph { - .iosAppWithStaticLibraries - } name: { - """ - - "iOSAppWithTransistiveStaticLibraries" - - """ - } dependencies: { - """ - ▿ 4 key/value pairs - ▿ (2 elements) - ▿ key: target 'ATests' - ▿ target: (3 elements) - - name: "ATests" - - path: /Fixtures/ios_app_with_static_libraries/Modules/A - - status: LinkingStatus.required - ▿ value: 2 members - ▿ library 'libC.a' - ▿ library: (5 elements) - - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a - - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C - - linking: BinaryLinking.static - ▿ architectures: 2 elements - - BinaryArchitecture.x8664 - - BinaryArchitecture.arm64 - - swiftModuleMap: Optional.none - ▿ target 'A' - ▿ target: (3 elements) - - name: "A" - - path: /Fixtures/ios_app_with_static_libraries/Modules/A - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_static_libraries - - status: LinkingStatus.required - ▿ value: 1 member - ▿ library 'libC.a' - ▿ library: (5 elements) - - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a - - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C - - linking: BinaryLinking.static - ▿ architectures: 2 elements - - BinaryArchitecture.x8664 - - BinaryArchitecture.arm64 - - swiftModuleMap: Optional.none - ▿ (2 elements) - ▿ key: target 'AppTests' - ▿ target: (3 elements) - - name: "AppTests" - - path: /Fixtures/ios_app_with_static_libraries - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_static_libraries - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'BTests' - ▿ target: (3 elements) - - name: "BTests" - - path: /Fixtures/ios_app_with_static_libraries/Modules/B - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'B' - ▿ target: (3 elements) - - name: "B" - - path: /Fixtures/ios_app_with_static_libraries/Modules/B - - status: LinkingStatus.required - - """ - } dependencyConditions: { - """ - - 0 key/value pairs - - """ - } packages: { - """ - - 0 key/value pairs - - """ - } workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "iOSAppWithTransistiveStaticLibraries" - - path: /Fixtures/ios_app_with_static_libraries - ▿ projects: 3 elements - - /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcodeproj - - /Fixtures/ios_app_with_static_libraries/Modules/A/A.xcodeproj - - /Fixtures/ios_app_with_static_libraries/Modules/B/B.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcworkspace - - """ - } projects: { - """ - ▿ 3 key/value pairs - ▿ (2 elements) - - key: /Fixtures/ios_app_with_static_libraries/Modules/A/A.xcodeproj - ▿ value: A - - path: /Fixtures/ios_app_with_static_libraries/Modules/A - - sourceRootPath: /Fixtures/ios_app_with_static_libraries/Modules/A - - xcodeProjPath: /Fixtures/ios_app_with_static_libraries/Modules/A - - name: "A" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "A" - ▿ value: Target - ▿ additionalFiles: 2 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a - - buildRules: 0 elements - - bundleId: "io.tuist.A" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "A" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: static library - - productName: "A" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift - ▿ (2 elements) - - key: "ATests" - ▿ value: Target - ▿ additionalFiles: 1 element - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift - - buildRules: 0 elements - - bundleId: "io.tuist.ATests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 2 elements - ▿ TargetDependency - ▿ target: (3 elements) - - name: "A" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ library: (4 elements) - - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a - - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C - - swiftModuleMap: Optional.none - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "ATests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "ATests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_app_with_static_libraries/Modules/B/B.xcodeproj - ▿ value: B - - path: /Fixtures/ios_app_with_static_libraries/Modules/B - - sourceRootPath: /Fixtures/ios_app_with_static_libraries/Modules/B - - xcodeProjPath: /Fixtures/ios_app_with_static_libraries/Modules/B - - name: "B" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "B" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.B" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "B" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: static library - - productName: "B" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift - ▿ (2 elements) - - key: "BTests" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist - - buildRules: 0 elements - - bundleId: "io.tuist.BTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "B" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "BTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "BTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcodeproj - ▿ value: iOSAppWithTransistiveStaticLibraries - - path: /Fixtures/ios_app_with_static_libraries - - sourceRootPath: /Fixtures/ios_app_with_static_libraries - - xcodeProjPath: /Fixtures/ios_app_with_static_libraries - - name: "iOSAppWithTransistiveStaticLibraries" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "App" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Tests.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.App" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ library: (4 elements) - - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a - - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C - - swiftModuleMap: Optional.none - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift - ▿ (2 elements) - - key: "AppTests" - ▿ value: Target - ▿ additionalFiles: 4 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_static_libraries/Tests.plist - - buildRules: 0 elements - - bundleId: "io.tuist.AppTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "App" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "AppTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - - """ - } - } -} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift deleted file mode 100644 index 30835a7d..00000000 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift +++ /dev/null @@ -1,1195 +0,0 @@ -import Foundation -import InlineSnapshotTesting -import Path -import Testing -import XcodeGraph -import XcodeProj -import XcodeProjToGraph - -@testable import TestSupport - -extension IntegrationTests { - @Test("Maps an iOS workspace using microfeature architecture with static linking into the correct graph") - func iosWorkspaceWithMicrofeatureArchitectureStaticLinking() async throws { - try await assertGraph { - .iosWorkspaceWithMicrofeatureArchitectureStaticLinking - } name: { - """ - - "Workspace" - - """ - } dependencies: { - """ - ▿ 6 key/value pairs - ▿ (2 elements) - ▿ key: target 'CoreTests' - ▿ target: (3 elements) - - name: "CoreTests" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'Core' - ▿ target: (3 elements) - - name: "Core" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'DataTests' - ▿ target: (3 elements) - - name: "DataTests" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'Data' - ▿ target: (3 elements) - - name: "Data" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'FeatureContractsTests' - ▿ target: (3 elements) - - name: "FeatureContractsTests" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'FeatureContracts' - ▿ target: (3 elements) - - name: "FeatureContracts" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'FrameworkATests' - ▿ target: (3 elements) - - name: "FrameworkATests" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'FrameworkA' - ▿ target: (3 elements) - - name: "FrameworkA" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'StaticAppTests' - ▿ target: (3 elements) - - name: "StaticAppTests" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'StaticApp' - ▿ target: (3 elements) - - name: "StaticApp" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'UIComponentsTests' - ▿ target: (3 elements) - - name: "UIComponentsTests" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'UIComponents' - ▿ target: (3 elements) - - name: "UIComponents" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework - - status: LinkingStatus.required - - """ - } dependencyConditions: { - """ - - 0 key/value pairs - - """ - } packages: { - """ - - 0 key/value pairs - - """ - } workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "Workspace" - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking - ▿ projects: 6 elements - - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Core.xcodeproj - - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Data.xcodeproj - - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/FrameworkA.xcodeproj - - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/FeatureContracts.xcodeproj - - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/UIComponents.xcodeproj - - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/StaticApp.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.xcworkspace - - """ - } projects: { - """ - ▿ 6 key/value pairs - ▿ (2 elements) - - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Core.xcodeproj - ▿ value: Core - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework - - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework - - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework - - name: "Core" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "Core" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.Core" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Core" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "Core" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift - ▿ (2 elements) - - key: "CoreTests" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist - - buildRules: 0 elements - - bundleId: "io.tuist.CoreTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "Core" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "CoreTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "CoreTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Data.xcodeproj - ▿ value: Data - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework - - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework - - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework - - name: "Data" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "Data" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.Data" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Data" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "Data" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift - ▿ (2 elements) - - key: "DataTests" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist - - buildRules: 0 elements - - bundleId: "io.tuist.DataFrameworkTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "Data" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "DataTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "DataTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/FrameworkA.xcodeproj - ▿ value: FrameworkA - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework - - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework - - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework - - name: "FrameworkA" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "FrameworkA" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.FrameworkA" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "FrameworkA" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "FrameworkA" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift - ▿ (2 elements) - - key: "FrameworkATests" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist - - buildRules: 0 elements - - bundleId: "io.tuist.FrameworkATests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "FrameworkA" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "FrameworkATests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "FrameworkATests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/FeatureContracts.xcodeproj - ▿ value: FeatureContracts - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts - - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts - - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts - - name: "FeatureContracts" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "FeatureContracts" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.FeatureContracts" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "FeatureContracts" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "FeatureContracts" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 2 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift - ▿ (2 elements) - - key: "FeatureContractsTests" - ▿ value: Target - ▿ additionalFiles: 4 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist - - buildRules: 0 elements - - bundleId: "io.tuist.FeatureContractsTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "FeatureContracts" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "FeatureContractsTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "FeatureContractsTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/UIComponents.xcodeproj - ▿ value: UIComponents - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework - - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework - - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework - - name: "UIComponents" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "UIComponents" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.UIComponents" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Dependencies" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "UIComponents" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "UIComponents" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift - ▿ (2 elements) - - key: "UIComponentsTests" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist - - buildRules: 0 elements - - bundleId: "io.tuist.UIComponentsTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "UIComponents" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "UIComponentsTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "UIComponentsTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/StaticApp.xcodeproj - ▿ value: StaticApp - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp - - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp - - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp - - name: "StaticApp" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "StaticApp" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.StaticApp" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "StaticApp" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "StaticApp" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift - ▿ (2 elements) - - key: "StaticAppTests" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist - - buildRules: 0 elements - - bundleId: "io.tuist.StaticAppTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "StaticApp" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "StaticAppTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "StaticAppTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - - """ - } - } -} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift deleted file mode 100644 index 99734fff..00000000 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift +++ /dev/null @@ -1,953 +0,0 @@ -import Foundation -import InlineSnapshotTesting -import Path -import Testing -import XcodeGraph -import XcodeProj -import XcodeProjToGraph -@testable import TestSupport - -extension IntegrationTests { - @Test("Maps an iOS app with a transitive framework dependency into the correct graph") - func ios_app_with_transitive_framework() async throws { - try await assertGraph { - .ios_app_with_transitive_framework - } name: { - """ - - "Workspace" - - """ - } dependencies: { - """ - ▿ 8 key/value pairs - ▿ (2 elements) - ▿ key: target 'AppTests' - ▿ target: (3 elements) - - name: "AppTests" - - path: /Fixtures/ios_app_with_transitive_framework/App - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_transitive_framework/App - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'AppUITests' - ▿ target: (3 elements) - - name: "AppUITests" - - path: /Fixtures/ios_app_with_transitive_framework/App - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/ios_app_with_transitive_framework/App - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'Framework1-iOS' - ▿ target: (3 elements) - - name: "Framework1-iOS" - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ framework 'Framework2.framework' - ▿ framework: (7 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 - - dsymPath: Optional.none - - bcsymbolmapPaths: 0 elements - - linking: BinaryLinking.dynamic - ▿ architectures: 2 elements - - BinaryArchitecture.x8664 - - BinaryArchitecture.arm64 - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'Framework1-macOS' - ▿ target: (3 elements) - - name: "Framework1-macOS" - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ framework 'Framework2.framework' - ▿ framework: (7 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework - - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Framework2 - - dsymPath: Optional.none - - bcsymbolmapPaths: 0 elements - - linking: BinaryLinking.dynamic - ▿ architectures: 1 element - - BinaryArchitecture.arm64 - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'Framework1Tests-iOS' - ▿ target: (3 elements) - - name: "Framework1Tests-iOS" - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'Framework1-iOS' - ▿ target: (3 elements) - - name: "Framework1-iOS" - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'Framework1Tests-macOS' - ▿ target: (3 elements) - - name: "Framework1Tests-macOS" - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'Framework1-macOS' - ▿ target: (3 elements) - - name: "Framework1-macOS" - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'StaticFramework1' - ▿ target: (3 elements) - - name: "StaticFramework1" - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 - - status: LinkingStatus.required - ▿ value: 1 member - ▿ framework 'Framework2.framework' - ▿ framework: (7 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 - - dsymPath: Optional.none - - bcsymbolmapPaths: 0 elements - - linking: BinaryLinking.dynamic - ▿ architectures: 2 elements - - BinaryArchitecture.x8664 - - BinaryArchitecture.arm64 - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'StaticFramework1Tests' - ▿ target: (3 elements) - - name: "StaticFramework1Tests" - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 - - status: LinkingStatus.required - ▿ value: 2 members - ▿ framework 'Framework2.framework' - ▿ framework: (7 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 - - dsymPath: Optional.none - - bcsymbolmapPaths: 0 elements - - linking: BinaryLinking.dynamic - ▿ architectures: 2 elements - - BinaryArchitecture.x8664 - - BinaryArchitecture.arm64 - - status: LinkingStatus.required - ▿ target 'StaticFramework1' - ▿ target: (3 elements) - - name: "StaticFramework1" - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 - - status: LinkingStatus.required - - """ - } dependencyConditions: { - """ - - 0 key/value pairs - - """ - } packages: { - """ - - 0 key/value pairs - - """ - } workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "Workspace" - - path: /Fixtures/ios_app_with_transitive_framework - ▿ projects: 3 elements - - /Fixtures/ios_app_with_transitive_framework/App/MainApp.xcodeproj - - /Fixtures/ios_app_with_transitive_framework/Framework1/Framework1.xcodeproj - - /Fixtures/ios_app_with_transitive_framework/StaticFramework1/StaticFramework1.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/ios_app_with_transitive_framework/Workspace.xcworkspace - - """ - } projects: { - """ - ▿ 3 key/value pairs - ▿ (2 elements) - - key: /Fixtures/ios_app_with_transitive_framework/App/MainApp.xcodeproj - ▿ value: MainApp - - path: /Fixtures/ios_app_with_transitive_framework/App - - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/App - - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/App - - name: "MainApp" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 3 key/value pairs - ▿ (2 elements) - - key: "App" - ▿ value: Target - ▿ additionalFiles: 5 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - buildRules: 0 elements - - bundleId: "io.tuist.App" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift - ▿ (2 elements) - - key: "AppTests" - ▿ value: Target - ▿ additionalFiles: 5 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - buildRules: 0 elements - - bundleId: "io.tuist.AppTests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "App" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppTests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "AppTests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift - ▿ (2 elements) - - key: "AppUITests" - ▿ value: Target - ▿ additionalFiles: 5 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - buildRules: 0 elements - - bundleId: "io.tuist.AppUITests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "App" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "AppUITests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: ui tests - - productName: "AppUITests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_app_with_transitive_framework/Framework1/Framework1.xcodeproj - ▿ value: Framework1 - - path: /Fixtures/ios_app_with_transitive_framework/Framework1 - - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/Framework1 - - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/Framework1 - - name: "Framework1" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 4 key/value pairs - ▿ (2 elements) - - key: "Framework1-iOS" - ▿ value: Target - ▿ additionalFiles: 4 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework - - buildRules: 0 elements - - bundleId: "io.tuist.Framework1" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ framework: (3 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework1-iOS" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "Framework1" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift - ▿ (2 elements) - - key: "Framework1-macOS" - ▿ value: Target - ▿ additionalFiles: 4 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - buildRules: 0 elements - - bundleId: "io.tuist.Framework1" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ framework: (3 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework1-macOS" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "Framework1" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift - ▿ (2 elements) - - key: "Framework1Tests-iOS" - ▿ value: Target - ▿ additionalFiles: 5 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - buildRules: 0 elements - - bundleId: "io.tuist.Framework1Tests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "Framework1-iOS" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework1Tests-iOS" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "Framework1Tests_iOS" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift - ▿ (2 elements) - - key: "Framework1Tests-macOS" - ▿ value: Target - ▿ additionalFiles: 5 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - buildRules: 0 elements - - bundleId: "io.tuist.Framework1Tests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "Framework1-macOS" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "Framework1Tests-macOS" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "Framework1Tests_macOS" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - ▿ (2 elements) - - key: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/StaticFramework1.xcodeproj - ▿ value: StaticFramework1 - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 - - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 - - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 - - name: "StaticFramework1" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "StaticFramework1" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Derived/InfoPlists/StaticFramework1-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Derived/InfoPlists/StaticFramework1Tests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.StaticFramework1" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ framework: (3 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "StaticFramework1" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "StaticFramework1" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift - ▿ (2 elements) - - key: "StaticFramework1Tests" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Derived/InfoPlists/StaticFramework1-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Derived/InfoPlists/StaticFramework1Tests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift - - buildRules: 0 elements - - bundleId: "io.tuist.StaticFramework1Tests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 2 elements - ▿ TargetDependency - ▿ framework: (3 elements) - - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "StaticFramework1" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "StaticFramework1Tests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "StaticFramework1Tests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - - """ - } - } -} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift deleted file mode 100644 index 76bffd76..00000000 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift +++ /dev/null @@ -1,257 +0,0 @@ -import Foundation -import InlineSnapshotTesting -import Path -import Testing -import XcodeGraph -import XcodeProj -import XcodeProjToGraph - -@testable import TestSupport - -extension IntegrationTests { - @Test("Maps a macOS app with a system extension into the correct graph") - func macosAppWithSystemExtension() async throws { - try await assertGraph { - .macosAppWithSystemExtension - } name: { - """ - - "App with SystemExtension" - - """ - } dependencies: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - ▿ key: target 'MainApp' - ▿ target: (3 elements) - - name: "MainApp" - - path: /Fixtures/macos_app_with_system_extension - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'SystemExtension' - ▿ target: (3 elements) - - name: "SystemExtension" - - path: /Fixtures/macos_app_with_system_extension - - status: LinkingStatus.required - - """ - } dependencyConditions: { - """ - - 0 key/value pairs - - """ - } packages: { - """ - - 0 key/value pairs - - """ - } workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "App with SystemExtension" - - path: /Fixtures/macos_app_with_system_extension - ▿ projects: 1 element - - /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcworkspace - - """ - } projects: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcodeproj - ▿ value: App with SystemExtension - - path: /Fixtures/macos_app_with_system_extension - - sourceRootPath: /Fixtures/macos_app_with_system_extension - - xcodeProjPath: /Fixtures/macos_app_with_system_extension - - name: "App with SystemExtension" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 2 key/value pairs - ▿ (2 elements) - - key: "MainApp" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/macos_app_with_system_extension/Derived/InfoPlists/SystemExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/macos_app_with_system_extension/MainApp/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift - - buildRules: 0 elements - - bundleId: "io.tuist.MainApp" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Embed System Extensions" - ▿ subpath: Optional - - some: "$(CONTENTS_FOLDER_PATH)/Library/SystemExtensions" - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "SystemExtension" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "MainApp" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "MainApp" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift - ▿ (2 elements) - - key: "SystemExtension" - ▿ value: Target - ▿ additionalFiles: 3 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/macos_app_with_system_extension/Derived/InfoPlists/SystemExtension-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/macos_app_with_system_extension/MainApp/Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift - - buildRules: 0 elements - - bundleId: "io.tuist.SystemExtension" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "SystemExtension" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: system extension - - productName: "SystemExtension" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - - """ - } - } -} diff --git a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift b/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift deleted file mode 100644 index 466abfc3..00000000 --- a/Tests/XcodeProjToGraphTests/IntegrationTests/Projects/IntegrationTests+multiplatformAppWithMacrosAndEmbeddedWatchosApp.swift +++ /dev/null @@ -1,910 +0,0 @@ -import Foundation -import InlineSnapshotTesting -import Path -import Testing -import XcodeGraph -import XcodeProj -import XcodeProjToGraph - -@testable import TestSupport - -extension IntegrationTests { - @Test("Maps a multiplatform app with macros and an embedded watchOS app into the correct graph") - func multiplatformAppWithMacrosAndEmbeddedWatchosApp() async throws { - try await assertGraph { - .multiplatformAppWithMacrosAndEmbeddedWatchosApp - } name: { - """ - - "AppWithWatchApp" - - """ - } dependencies: { - """ - ▿ 4 key/value pairs - ▿ (2 elements) - ▿ key: target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ value: 2 members - ▿ target 'ModuleA' - ▿ target: (3 elements) - - name: "ModuleA" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ target 'WatchApp' - ▿ target: (3 elements) - - name: "WatchApp" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'ModuleA' - ▿ target: (3 elements) - - name: "ModuleA" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'ModuleAMacros' - ▿ target: (3 elements) - - name: "ModuleAMacros" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'ModuleATests' - ▿ target: (3 elements) - - name: "ModuleATests" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ value: 2 members - ▿ target 'ModuleA' - ▿ target: (3 elements) - - name: "ModuleA" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ target 'ModuleAMacros_Testable' - ▿ target: (3 elements) - - name: "ModuleAMacros_Testable" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ (2 elements) - ▿ key: target 'WatchApp' - ▿ target: (3 elements) - - name: "WatchApp" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ value: 1 member - ▿ target 'ModuleA' - ▿ target: (3 elements) - - name: "ModuleA" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - - """ - } dependencyConditions: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - ▿ key: GraphEdge - ▿ from: target 'App' - ▿ target: (3 elements) - - name: "App" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ to: target 'WatchApp' - ▿ target: (3 elements) - - name: "WatchApp" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - status: LinkingStatus.required - ▿ value: PlatformCondition - ▿ platformFilters: 1 member - - PlatformFilter.ios - - """ - } packages: { - """ - - 0 key/value pairs - - """ - } workspace: { - """ - ▿ Workspace - - additionalFiles: 0 elements - ▿ generationOptions: GenerationOptions - ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes - ▿ enabled: (5 elements) - - codeCoverageMode: CodeCoverageMode.disabled - ▿ testingOptions: TestingOptions - - rawValue: 0 - - testLanguage: Optional.none - - testRegion: Optional.none - - testScreenCaptureFormat: Optional.none - ▿ enableAutomaticXcodeSchemes: Optional - - some: false - - lastXcodeUpgradeCheck: Optional.none - - renderMarkdownReadme: false - - ideTemplateMacros: Optional.none - - name: "AppWithWatchApp" - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - ▿ projects: 4 elements - - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp.xcodeproj - - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/.build/tuist-derived/swift-case-paths/swift-case-paths.xcodeproj - - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/.build/tuist-derived/swift-syntax/swift-syntax.xcodeproj - - /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Tuist/.build/tuist-derived/xctest-dynamic-overlay/xctest-dynamic-overlay.xcodeproj - - schemes: 0 elements - - xcWorkspacePath: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp.xcworkspace - - """ - } projects: { - """ - ▿ 1 key/value pair - ▿ (2 elements) - - key: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp.xcodeproj - ▿ value: AppWithWatchApp - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - sourceRootPath: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - xcodeProjPath: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app - - name: "AppWithWatchApp" - - organizationName: Optional.none - - classPrefix: Optional.none - ▿ defaultKnownRegions: Optional> - ▿ some: 2 elements - - "Base" - - "en" - ▿ developmentRegion: Optional - - some: "en" - ▿ options: Options - - automaticSchemesOptions: AutomaticSchemesOptions.disabled - - disableBundleAccessors: false - - disableShowEnvironmentVarsInScriptPhases: false - - disableSynthesizedResourceAccessors: false - ▿ textSettings: TextSettings - - indentWidth: Optional.none - - tabWidth: Optional.none - - usesTabs: Optional.none - - wrapsLines: Optional.none - ▿ targets: 6 key/value pairs - ▿ (2 elements) - - key: "App" - ▿ value: Target - ▿ additionalFiles: 15 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleA-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros_Testable-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleATests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift - - buildRules: 0 elements - - bundleId: "io.tuist.App" - ▿ copyFiles: 2 elements - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - ▿ CopyFilesAction - - destination: Destination.productsDirectory - - files: 0 elements - - name: "Embed Watch Content" - ▿ subpath: Optional - - some: "$(CONTENTS_FOLDER_PATH)/Watch" - - coreDataModels: 0 elements - ▿ dependencies: 2 elements - ▿ TargetDependency - ▿ target: (3 elements) - - name: "ModuleA" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "WatchApp" - - status: LinkingStatus.required - ▿ condition: Optional - ▿ some: PlatformCondition - ▿ platformFilters: 1 member - - PlatformFilter.ios - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "App" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "App" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 1 element - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 4 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift - ▿ (2 elements) - - key: "ModuleA" - ▿ value: Target - ▿ additionalFiles: 18 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleA-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros_Testable-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleATests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift - - buildRules: 0 elements - - bundleId: "io.tuist.modulea" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "ModuleAMacros" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "ModuleA" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "ModuleA" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 2 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift - ▿ (2 elements) - - key: "ModuleAMacros" - ▿ value: Target - ▿ additionalFiles: 19 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleA-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros_Testable-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleATests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift - - buildRules: 0 elements - - bundleId: "io.tuist.moduleamacros" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - ▿ macOS: Optional - - some: "14.0" - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "ModuleAMacros" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: command line tool - - productName: "ModuleAMacros" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift - ▿ (2 elements) - - key: "ModuleAMacros_Testable" - ▿ value: Target - ▿ additionalFiles: 19 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleA-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros_Testable-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleATests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift - - buildRules: 0 elements - - bundleId: "io.tuist.moduleamacros.testable" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - - dependencies: 0 elements - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "ModuleAMacros_Testable" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: dynamic framework - - productName: "ModuleAMacros_Testable" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift - ▿ (2 elements) - - key: "ModuleATests" - ▿ value: Target - ▿ additionalFiles: 19 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleA-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros_Testable-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleATests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift - - buildRules: 0 elements - - bundleId: "io.tuist.moduleatests" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 2 elements - ▿ TargetDependency - ▿ target: (3 elements) - - name: "ModuleA" - - status: LinkingStatus.required - - condition: Optional.none - ▿ TargetDependency - ▿ target: (3 elements) - - name: "ModuleAMacros_Testable" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "ModuleATests" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: unit tests - - productName: "ModuleATests" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - - resources: 0 elements - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 1 element - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift - ▿ (2 elements) - - key: "WatchApp" - ▿ value: Target - ▿ additionalFiles: 14 elements - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Resources/Assets.xcassets - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/ContentView.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/App/Sources/TestApp.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/App-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleA-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleAMacros_Testable-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/InfoPlists/ModuleATests-Info.plist - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+App.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+App.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Macros/Sources/Macros.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/Macros.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Sources/ModuleA.swift - ▿ FileElement - ▿ file: (1 element) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Modules/ModuleA/Tests/ModuleATests.swift - - buildRules: 0 elements - - bundleId: "io.tuist.App.watchkitapp" - ▿ copyFiles: 1 element - ▿ CopyFilesAction - - destination: Destination.frameworks - - files: 0 elements - - name: "Embed Frameworks" - - subpath: Optional.none - - coreDataModels: 0 elements - ▿ dependencies: 1 element - ▿ TargetDependency - ▿ target: (3 elements) - - name: "ModuleA" - - status: LinkingStatus.required - - condition: Optional.none - ▿ deploymentTargets: DeploymentTargets - - iOS: Optional.none - - macOS: Optional.none - - tvOS: Optional.none - - visionOS: Optional.none - - watchOS: Optional.none - - destinations: 0 members - - entitlements: Optional.none - - environmentVariables: 0 key/value pairs - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "MainGroup" - - headers: Optional.none - - infoPlist: Optional.none - - launchArguments: 0 elements - - mergeable: false - - mergedBinaryType: MergedBinaryType.disabled - ▿ metadata: TargetMetadata - - tags: 0 members - - name: "WatchApp" - - onDemandResourcesTags: Optional.none - - playgrounds: 0 elements - - product: application - - productName: "WatchApp" - - prune: false - - rawScriptBuildPhases: 0 elements - ▿ resources: ResourceFileElements - - privacyManifest: Optional.none - ▿ resources: 1 element - ▿ ResourceFileElement - ▿ file: (3 elements) - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Resources/Assets.xcassets - - tags: 0 elements - - inclusionCondition: Optional.none - - scripts: 0 elements - - settings: Optional.none - ▿ sources: 5 elements - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistAssets+WatchApp.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/Derived/Sources/TuistBundle+WatchApp.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/ContentView.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchApp.swift - ▿ SourceFile - - codeGen: Optional.none - - compilationCondition: Optional.none - - compilerFlags: Optional.none - - contentHash: Optional.none - - path: /Fixtures/multiplatform_app_with_macros_and_embedded_watchos_app/WatchApp/Sources/WatchConfig.swift - - packages: 0 elements - - schemes: 0 elements - ▿ settings: Settings - - base: 0 key/value pairs - - baseDebug: 0 key/value pairs - - configurations: 0 key/value pairs - ▿ defaultSettings: DefaultSettings - ▿ recommended: (1 element) - - excluding: 0 members - ▿ filesGroup: ProjectGroup - ▿ group: (1 element) - - name: "Project" - - additionalFiles: 0 elements - - ideTemplateMacros: Optional.none - - resourceSynthesizers: 0 elements - - lastUpgradeCheck: Optional.none - - type: local project - - """ - } - } -} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift index a92e572a..5783553d 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift @@ -39,7 +39,7 @@ struct PackageMapperTests { versionRequirement: .upToNextMajorVersion("1.0.0") ) - let requirement = await mapper.mapRequirement(package: package) + let requirement = mapper.mapRequirement(package: package) #expect(requirement == .upToNextMajor("1.0.0")) } @@ -50,7 +50,7 @@ struct PackageMapperTests { versionRequirement: .upToNextMinorVersion("1.2.0") ) - let requirement = await mapper.mapRequirement(package: package) + let requirement = mapper.mapRequirement(package: package) #expect(requirement == .upToNextMinor("1.2.0")) } @@ -61,7 +61,7 @@ struct PackageMapperTests { versionRequirement: .exact("1.2.3") ) - let requirement = await mapper.mapRequirement(package: package) + let requirement = mapper.mapRequirement(package: package) #expect(requirement == .exact("1.2.3")) } @@ -72,7 +72,7 @@ struct PackageMapperTests { versionRequirement: .range(from: "1.0.0", to: "2.0.0") ) - let requirement = await mapper.mapRequirement(package: package) + let requirement = mapper.mapRequirement(package: package) #expect(requirement == .range(from: "1.0.0", to: "2.0.0")) } @@ -83,7 +83,7 @@ struct PackageMapperTests { versionRequirement: .branch("main") ) - let requirement = await mapper.mapRequirement(package: package) + let requirement = mapper.mapRequirement(package: package) #expect(requirement == .branch("main")) } @@ -94,7 +94,7 @@ struct PackageMapperTests { versionRequirement: .revision("abc123") ) - let requirement = await mapper.mapRequirement(package: package) + let requirement = mapper.mapRequirement(package: package) #expect(requirement == .revision("abc123")) } @@ -105,7 +105,7 @@ struct PackageMapperTests { versionRequirement: nil ) - let requirement = await mapper.mapRequirement(package: package) + let requirement = mapper.mapRequirement(package: package) #expect(requirement == .upToNextMajor("0.0.0")) } diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Workspace/WorkspaceMapperTests.swift b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Workspace/WorkspaceMapperTests.swift index 21a8e399..09dbdaa2 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Workspace/WorkspaceMapperTests.swift +++ b/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Workspace/WorkspaceMapperTests.swift @@ -1,4 +1,3 @@ -import AEXML import Foundation import Path import PathKit @@ -83,7 +82,7 @@ struct WorkspaceMapperTests { let tempDirectory = FileManager.default.temporaryDirectory let path = tempDirectory.appendingPathComponent("MyWorkspace.xcworkspace") // Arrange: A workspace with one project and a schemes directory - let workspacePath = try AbsolutePath(validating: path.path()) + let workspacePath = try AbsolutePath(validating: path.path) // Create a mock `.xcscheme` file in `xcshareddata/xcschemes` let sharedDataDir = workspacePath.pathString + "/xcshareddata/xcschemes" diff --git a/Tuist/ProjectDescriptionHelpers/Module.swift b/Tuist/ProjectDescriptionHelpers/Module.swift index 9a048c06..dabd7db7 100644 --- a/Tuist/ProjectDescriptionHelpers/Module.swift +++ b/Tuist/ProjectDescriptionHelpers/Module.swift @@ -148,8 +148,7 @@ public enum Module: String, CaseIterable { ] case .xcodeProjToGraph: [ - .target(name: Module.testSupport.rawValue), - .external(name: "InlineSnapshotTesting"), + .target(name: Module.testSupport.rawValue) ] } dependencies = dependencies + [.target(name: targetName)] @@ -190,7 +189,7 @@ public enum Module: String, CaseIterable { case .xcodeGraph, .xcodeProjToGraph: [] case .testSupport: - ["Fixtures"] + [] } var debugSettings: ProjectDescription.SettingsDictionary = ["SWIFT_ACTIVE_COMPILATION_CONDITIONS": "$(inherited) MOCKING"] var releaseSettings: ProjectDescription.SettingsDictionary = [:] @@ -222,7 +221,6 @@ public enum Module: String, CaseIterable { deploymentTargets: .macOS("12.0"), infoPlist: .default, sources: [.glob("\(rootFolder)/\(name)/**/*.swift", excluding: ["**/Fixtures/**"])], - resources: resources, dependencies: dependencies, settings: settings ) From dbd55de765cda3c74dcea5925282bccdcca5e7a9 Mon Sep 17 00:00:00 2001 From: Andy Kolean Date: Sun, 15 Dec 2024 23:48:59 -0500 Subject: [PATCH 06/40] [access modifiers] add missing access modifiers --- .../Mappers/Dependency/PlatformConditionMapper.swift | 2 +- Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift | 4 ++-- .../Mappers/TargetAndSchemes/SchemeMapper.swift | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift index 4ff60d92..8a7248d4 100644 --- a/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift @@ -2,7 +2,7 @@ import XcodeGraph import XcodeProj /// A mapper for platform-related conditions, extracting platform filters from `PBXTargetDependency`. -enum PlatformConditionMapper { +public enum PlatformConditionMapper { /// Maps the platform filters on a given `PBXTargetDependency` into a `PlatformCondition`. /// /// Returns `nil` if no filters apply, meaning the dependency isn't restricted by platform and diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift b/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift index 2f89abb8..e14231fc 100644 --- a/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift +++ b/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift @@ -2,7 +2,7 @@ import Foundation import Path /// Represents errors that may occur during project or dependency mapping processes. -enum MappingError: Error, LocalizedError, Equatable { +public enum MappingError: Error, LocalizedError, Equatable { // MARK: - Project Mapping Errors /// The provided path does not exist. @@ -44,7 +44,7 @@ enum MappingError: Error, LocalizedError, Equatable { // MARK: - Error Descriptions - var errorDescription: String? { + public var errorDescription: String? { switch self { case let .pathNotFound(path): return "The specified path does not exist: \(path)" diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift index 6a5d640b..18ff140d 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift +++ b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift @@ -98,7 +98,7 @@ enum SchemeMapperType { /// /// // 'schemes' now contains a list of domain Scheme models ready for further use. /// ``` -final class SchemeMapper: SchemeMapping { +public final class SchemeMapper: SchemeMapping { private let graphType: GraphType /// Initializes the mapper with the given graph type. From 75991004596c66e2b81609051109085bd184c766 Mon Sep 17 00:00:00 2001 From: Andy Kolean Date: Mon, 16 Dec 2024 19:32:23 -0500 Subject: [PATCH 07/40] [swift tools version] 5.9 --- Package.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index 4fdac409..d59c768e 100644 --- a/Package.swift +++ b/Package.swift @@ -1,6 +1,6 @@ -// swift-tools-version:6.0 +// swift-tools-version:5.9 -@preconcurrency import PackageDescription +import PackageDescription let targets: [Target] = [ .target( @@ -61,6 +61,5 @@ let package = Package( .package(url: "https://github.com/tuist/Path.git", .upToNextMajor(from: "0.3.8")), .package(url: "https://github.com/tuist/XcodeProj", .upToNextMajor(from: "8.25.0")) ], - targets: targets ) From 381e87d10a1a2e7fe1d44320159fc2cb1d271b5c Mon Sep 17 00:00:00 2001 From: Andy Kolean Date: Wed, 18 Dec 2024 21:54:54 -0500 Subject: [PATCH 08/40] Address code review feedback: refine mappers, clean up test data, and improve structure --- Package.resolved | 21 +- Package.swift | 37 +- .../Mocks/MockBuildFilesAndPhases.swift | 139 -- .../TestSupport/Mocks/MockBuildSettings.swift | 58 - Sources/TestSupport/Mocks/MockDefaults.swift | 23 - .../TestSupport/Mocks/MockFileCreator.swift | 19 - .../TestSupport/Mocks/MockFileStructure.swift | 144 -- .../Mocks/MockProjectAndWorkspace.swift | 138 -- .../Mocks/MockProjectProvider.swift | 97 -- .../Mocks/MockSchemesAndUserData.swift | 79 - .../Mocks/MockTargetsAndDependencies.swift | 190 --- .../DependenciesGraph/DependenciesGraph.swift | 4 +- Sources/XcodeGraph/Graph/Graph.swift | 2 +- Sources/XcodeGraph/Graph/GraphTarget.swift | 2 +- Sources/XcodeGraph/Models/AnalyzeAction.swift | 2 +- Sources/XcodeGraph/Models/ArchiveAction.swift | 2 +- Sources/XcodeGraph/Models/Arguments.swift | 2 +- Sources/XcodeGraph/Models/BuildAction.swift | 2 +- Sources/XcodeGraph/Models/Headers.swift | 2 +- .../XcodeGraph/Models/IDETemplateMacros.swift | 2 +- .../Models/Metadata/FrameworkMetadata.swift | 2 +- .../Models/Metadata/LibraryMetadata.swift | 2 +- .../Models/Metadata/TargetMetadata.swift | 2 +- .../Models/Metadata/XCFrameworkMetadata.swift | 2 +- .../XcodeGraph/Models/PlatformCondition.swift | 2 +- Sources/XcodeGraph/Models/ProfileAction.swift | 2 +- Sources/XcodeGraph/Models/Project.swift | 7 +- .../Models/RawScriptBuildPhase.swift | 2 +- .../Models/ResourceSynthesizer.swift | 4 +- Sources/XcodeGraph/Models/RunAction.swift | 2 +- Sources/XcodeGraph/Models/Scheme.swift | 2 +- Sources/XcodeGraph/Models/Settings.swift | 8 +- Sources/XcodeGraph/Models/Target.swift | 4 +- Sources/XcodeGraph/Models/TestAction.swift | 2 +- .../XcodeGraph/Models/TestableTarget.swift | 2 +- Sources/XcodeGraph/Models/Workspace.swift | 4 +- .../Models/XCFrameworkInfoPlist.swift | 4 + .../Extensions/AbsolutePath+Extensions.swift | 47 + .../Extensions/PBXProject+Extensions.swift | 0 .../Extensions/Package+Extensions.swift | 2 +- .../Extensions/Platform+Extensions.swift | 4 +- .../PlatformFilter+Extensions.swift | 0 .../TargetDependency+Extensions.swift | 3 +- .../XCWorkspaceDataFileRef+Extensions.swift | 11 +- .../Mappers/Graph/GraphMapper.swift | 143 ++ .../Mappers/Packages/XCPackageMapper.swift | 83 + .../Mappers/Phases}/BuildPhaseConstants.swift | 2 +- .../Phases/PBXCopyFilesBuildPhaseMapper.swift | 55 + .../PBXCoreDataModelsBuildPhaseMapper.swift | 36 + .../PBXFrameworksBuildPhaseMapper.swift | 30 + .../Phases/PBXHeadersBuildPhaseMapper.swift | 63 + .../Phases/PBXResourcesBuildPhaseMapper.swift | 57 + .../Phases/PBXScriptsBuildPhaseMapper.swift | 100 ++ .../Phases/PBXSourcesBuildPhaseMapper.swift | 52 + .../Mappers/Project/PBXProjectMapper.swift | 130 ++ .../Mappers/Project/ProjectAttribute.swift | 0 .../Mappers/Project/ProjectProvider.swift | 81 + .../SchemeDiagnosticsOptions+XCScheme.swift | 0 .../Mappers/Schemes/XCSchemeMapper.swift | 195 +++ .../Mappers/Settings/BuildSettings.swift | 0 .../XCConfigurationList+Helpers.swift | 0 .../Settings/XCConfigurationMapper.swift} | 31 +- .../Mappers/Targets/PBXBuildRuleMapper.swift | 55 + .../Targets}/PBXTarget+BuildHeaders.swift | 2 +- .../Targets}/PBXTarget+BuildSettings.swift | 8 +- .../Targets/PBXTarget+GraphMapping.swift | 61 + .../PBXTarget+PlatformInference.swift | 6 +- ...XTargetDependency+PlatformCondition.swift} | 8 +- .../Targets/PBXTargetDependencyMapper.swift | 129 ++ .../Mappers/Targets/PBXTargetMapper.swift | 313 ++++ .../TargetDependency+GraphMapping.swift | 225 +++ .../Mappers/Workspace/WorkspaceProvider.swift | 12 +- .../Mappers/Workspace/XCWorkspaceMapper.swift | 125 ++ .../Parser/ProjectParser.swift | 134 ++ .../Utilities/ConfigurationMatcher.swift | 54 + .../XcodeProjToGraph.docc/Documentation.md | 14 +- .../Extensions/AbsolutePath+Extensions.swift | 96 -- .../Extensions/Sendable+Retroactive.swift | 16 - .../Extensions/Sequence+Async.swift | 24 - .../Mappers/Build/BuildPhaseMapper.swift | 428 ----- .../Mappers/Build/BuildRuleMapper.swift | 63 - .../Mappers/Dependency/DependencyMapper.swift | 189 --- .../Dependency/FileDependencyMapper.swift | 23 - .../TargetDependency+GraphMapping.swift | 272 ---- .../Mappers/Graph/GraphMapper.swift | 169 -- .../Mappers/Graph/MappingError.swift | 73 - .../Mappers/Graph/ProjectParser.swift | 145 -- .../Mappers/Project/PackageMapper.swift | 99 -- .../Mappers/Project/ProjectMapper.swift | 165 -- .../Mappers/Project/ProjectProvider.swift | 103 -- .../Settings/ConfigurationMatcher.swift | 42 - .../TargetAndSchemes/SchemeMapper.swift | 315 ---- .../TargetAndSchemes/TargetMapper.swift | 285 ---- .../Mappers/Workspace/WorkspaceMapper.swift | 146 -- .../ProcessRunner/Executable.swift | 55 - .../ProcessRunner/Lipo/LipoArchsResult.swift | 38 - .../ProcessRunner/Lipo/LipoArguments.swift | 29 - .../ProcessRunner/Lipo/LipoTool.swift | 36 - .../ProcessRunner/ProcessResult.swift | 28 - .../ProcessRunner/ProcessRunner.swift | 81 - .../ProcessRunner/ProcessRunnerError.swift | 22 - .../IntegrationTests/IntegrationTests.swift | 173 +++ ...+commandLineToolWithDynamicFramework.swift | 249 +++ .../IntegrationTests+iosAppLarge.swift | 18 + ...ntegrationTests+iosAppWithExtensions.swift | 1376 +++++++++++++++++ ...egrationTests+iosAppWithMultiConfigs.swift | 675 ++++++++ ...onTests+iosAppWithRemoteSwiftPackage.swift | 275 ++++ ...ationTests+iosAppWithStaticLibraries.swift | 647 ++++++++ ...icrofeatureArchitectureStaticLinking.swift | 1193 ++++++++++++++ ...ts+ios_app_with_transitive_framework.swift | 945 +++++++++++ ...ionTests+macosAppWithSystemExtension.swift | 255 +++ .../MapperTests/Graph}/GraphMapperTests.swift | 154 +- .../Package/XCPackageMapperTests.swift} | 74 +- .../PBXCopyFilesBuildPhaseMapperTests.swift | 54 + ...XCoreDataModelsBuildPhaseMapperTests.swift | 54 + .../PBXFrameworksBuildPhaseMapperTests.swift | 39 + .../PBXHeadersBuildPhaseMapperTests.swift | 66 + .../PBXResourcesBuildPhaseMapperTests.swift | 78 + .../PBXScriptsBuildPhaseMapperTests.swift | 64 + .../PBXSourcesBuildPhaseMapperTests.swift | 120 ++ .../Project/PBXProjectMapperTests.swift} | 86 +- .../Project/ProjectProviderTests.swift | 88 ++ .../Schemes/XCSchemeMapperTests.swift} | 84 +- .../Settings/BuildSettingsTests.swift | 24 +- .../Settings/ConfigurationMatcherTests.swift | 43 + .../XCConfigurationMapperTests.swift} | 87 +- .../Target/PBXBuildRuleMapperTests.swift | 130 ++ .../Target/PBXTargetDependencyMapper.swift | 316 ++++ .../Target/PBXTargetMapperTests.swift | 335 ++++ .../TargetDependencyExtensionsTests.swift | 190 +++ .../Workspace/XCWorkspaceMapperTests.swift | 205 +++ .../Mocks/MockDefaults.swift | 22 + .../Mocks/MockProjectProvider.swift | 84 + .../Mocks/MockWorkspaceProvider.swift | 18 + .../Mocks/PBXProjectMapper+Mock.swift | 35 + .../Mocks/WorkspaceFixture.swift | 68 + .../ParserTests/ProjectParserTests.swift | 42 +- .../PerformanceTests/PerformanceTests.swift | 84 + .../Resources/Fixtures.zip | Bin 0 -> 8760289 bytes Tests/XcodeProjMapperTests/TestData/.swift | 1 + .../TestData/PBXBuildRule+TestData.swift | 32 + .../TestData/PBXFileReference+TestData.swift | 21 + .../TestData/PBXGroup+TestData.swift | 17 + .../TestData/PBXNativeTarget+TestData.swift | 36 + .../TestData/PBXProj+TestData.swift | 61 + .../TestData/PBXProject+TestData.swift | 114 ++ .../PBXShellScriptBuildPhase+TestData.swift | 35 + .../PBXTargetDependency+TestData.swift | 19 + .../TestData/PBXVariantGroup+TestData.swift | 17 + .../XCBuildConfiguration+TestData.swift | 25 + .../XCConfigurationList+TestData.swift | 17 + .../TestData/XCScheme+TestData.swift | 29 + .../XCSchemeTestableReference+TestData.swift | 28 + .../TestData/XCUserData+TestData.swift | 27 + .../TestData/XCVersionGroup+TestData.swift | 34 + .../TestData/XCWorkspace+TestData.swift | 21 + .../XCWorkspaceDataElement+TestData.swift | 7 + .../XCWorkspaceDataGroup+TestData.swift | 9 + .../TestData/XcodeProj+TestData.swift | 25 + .../Xcode/Build/BuildPhaseMapperTests.swift | 456 ------ .../Xcode/Build/BuildRuleMapperTests.swift | 134 -- .../Dependency/DependencyMapperTests.swift | 269 ---- .../TargetDependencyExtensionsTests.swift | 246 --- .../Settings/ConfigurationMatcherTests.swift | 39 - .../Xcode/Target/TargetMapperTests.swift | 158 -- .../Workspace/WorkspaceMapperTests.swift | 152 -- .../ProcessTests/LipoToolTests.swift | 95 -- .../ProcessTests/ProcessRunnerTests.swift | 195 --- Tuist/ProjectDescriptionHelpers/Module.swift | 21 +- 169 files changed, 11072 insertions(+), 5949 deletions(-) delete mode 100644 Sources/TestSupport/Mocks/MockBuildFilesAndPhases.swift delete mode 100644 Sources/TestSupport/Mocks/MockBuildSettings.swift delete mode 100644 Sources/TestSupport/Mocks/MockDefaults.swift delete mode 100644 Sources/TestSupport/Mocks/MockFileCreator.swift delete mode 100644 Sources/TestSupport/Mocks/MockFileStructure.swift delete mode 100644 Sources/TestSupport/Mocks/MockProjectAndWorkspace.swift delete mode 100644 Sources/TestSupport/Mocks/MockProjectProvider.swift delete mode 100644 Sources/TestSupport/Mocks/MockSchemesAndUserData.swift delete mode 100644 Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift create mode 100644 Sources/XcodeProjMapper/Extensions/AbsolutePath+Extensions.swift rename Sources/{XcodeProjToGraph => XcodeProjMapper}/Extensions/PBXProject+Extensions.swift (100%) rename Sources/{XcodeProjToGraph => XcodeProjMapper}/Extensions/Package+Extensions.swift (90%) rename Sources/{XcodeProjToGraph => XcodeProjMapper}/Extensions/Platform+Extensions.swift (90%) rename Sources/{XcodeProjToGraph => XcodeProjMapper}/Extensions/PlatformFilter+Extensions.swift (100%) rename Sources/{XcodeProjToGraph => XcodeProjMapper}/Extensions/TargetDependency+Extensions.swift (92%) rename Sources/{XcodeProjToGraph => XcodeProjMapper}/Extensions/XCWorkspaceDataFileRef+Extensions.swift (77%) create mode 100644 Sources/XcodeProjMapper/Mappers/Graph/GraphMapper.swift create mode 100644 Sources/XcodeProjMapper/Mappers/Packages/XCPackageMapper.swift rename Sources/{XcodeProjToGraph/Mappers/Build => XcodeProjMapper/Mappers/Phases}/BuildPhaseConstants.swift (95%) create mode 100644 Sources/XcodeProjMapper/Mappers/Phases/PBXCopyFilesBuildPhaseMapper.swift create mode 100644 Sources/XcodeProjMapper/Mappers/Phases/PBXCoreDataModelsBuildPhaseMapper.swift create mode 100644 Sources/XcodeProjMapper/Mappers/Phases/PBXFrameworksBuildPhaseMapper.swift create mode 100644 Sources/XcodeProjMapper/Mappers/Phases/PBXHeadersBuildPhaseMapper.swift create mode 100644 Sources/XcodeProjMapper/Mappers/Phases/PBXResourcesBuildPhaseMapper.swift create mode 100644 Sources/XcodeProjMapper/Mappers/Phases/PBXScriptsBuildPhaseMapper.swift create mode 100644 Sources/XcodeProjMapper/Mappers/Phases/PBXSourcesBuildPhaseMapper.swift create mode 100644 Sources/XcodeProjMapper/Mappers/Project/PBXProjectMapper.swift rename Sources/{XcodeProjToGraph => XcodeProjMapper}/Mappers/Project/ProjectAttribute.swift (100%) create mode 100644 Sources/XcodeProjMapper/Mappers/Project/ProjectProvider.swift rename Sources/{XcodeProjToGraph/Mappers/TargetAndSchemes => XcodeProjMapper/Mappers/Schemes}/SchemeDiagnosticsOptions+XCScheme.swift (100%) create mode 100644 Sources/XcodeProjMapper/Mappers/Schemes/XCSchemeMapper.swift rename Sources/{XcodeProjToGraph => XcodeProjMapper}/Mappers/Settings/BuildSettings.swift (100%) rename Sources/{XcodeProjToGraph => XcodeProjMapper}/Mappers/Settings/XCConfigurationList+Helpers.swift (100%) rename Sources/{XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift => XcodeProjMapper/Mappers/Settings/XCConfigurationMapper.swift} (86%) create mode 100644 Sources/XcodeProjMapper/Mappers/Targets/PBXBuildRuleMapper.swift rename Sources/{XcodeProjToGraph/Mappers/TargetAndSchemes => XcodeProjMapper/Mappers/Targets}/PBXTarget+BuildHeaders.swift (70%) rename Sources/{XcodeProjToGraph/Mappers/TargetAndSchemes => XcodeProjMapper/Mappers/Targets}/PBXTarget+BuildSettings.swift (92%) create mode 100644 Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+GraphMapping.swift rename Sources/{XcodeProjToGraph/Mappers/TargetAndSchemes => XcodeProjMapper/Mappers/Targets}/PBXTarget+PlatformInference.swift (94%) rename Sources/{XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift => XcodeProjMapper/Mappers/Targets/PBXTargetDependency+PlatformCondition.swift} (70%) create mode 100644 Sources/XcodeProjMapper/Mappers/Targets/PBXTargetDependencyMapper.swift create mode 100644 Sources/XcodeProjMapper/Mappers/Targets/PBXTargetMapper.swift create mode 100644 Sources/XcodeProjMapper/Mappers/Targets/TargetDependency+GraphMapping.swift rename Sources/{XcodeProjToGraph => XcodeProjMapper}/Mappers/Workspace/WorkspaceProvider.swift (89%) create mode 100644 Sources/XcodeProjMapper/Mappers/Workspace/XCWorkspaceMapper.swift create mode 100644 Sources/XcodeProjMapper/Parser/ProjectParser.swift create mode 100644 Sources/XcodeProjMapper/Utilities/ConfigurationMatcher.swift rename Sources/{XcodeProjToGraph => XcodeProjMapper}/XcodeProjToGraph.docc/Documentation.md (66%) delete mode 100644 Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift delete mode 100644 Sources/XcodeProjToGraph/Extensions/Sendable+Retroactive.swift delete mode 100644 Sources/XcodeProjToGraph/Extensions/Sequence+Async.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Build/BuildRuleMapper.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Dependency/FileDependencyMapper.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift delete mode 100644 Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift delete mode 100644 Sources/XcodeProjToGraph/ProcessRunner/Executable.swift delete mode 100644 Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArchsResult.swift delete mode 100644 Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArguments.swift delete mode 100644 Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoTool.swift delete mode 100644 Sources/XcodeProjToGraph/ProcessRunner/ProcessResult.swift delete mode 100644 Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift delete mode 100644 Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift create mode 100644 Tests/XcodeProjMapperTests/IntegrationTests/IntegrationTests.swift create mode 100644 Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift create mode 100644 Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift create mode 100644 Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift create mode 100644 Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift create mode 100644 Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift create mode 100644 Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift create mode 100644 Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift create mode 100644 Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift create mode 100644 Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift rename Tests/{XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper => XcodeProjMapperTests/MapperTests/Graph}/GraphMapperTests.swift (52%) rename Tests/{XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift => XcodeProjMapperTests/MapperTests/Package/XCPackageMapperTests.swift} (60%) create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Phases/PBXCopyFilesBuildPhaseMapperTests.swift create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Phases/PBXCoreDataModelsBuildPhaseMapperTests.swift create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Phases/PBXFrameworksBuildPhaseMapperTests.swift create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Phases/PBXHeadersBuildPhaseMapperTests.swift create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Phases/PBXResourcesBuildPhaseMapperTests.swift create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Phases/PBXScriptsBuildPhaseMapperTests.swift create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Phases/PBXSourcesBuildPhaseMapperTests.swift rename Tests/{XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift => XcodeProjMapperTests/MapperTests/Project/PBXProjectMapperTests.swift} (60%) create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Project/ProjectProviderTests.swift rename Tests/{XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift => XcodeProjMapperTests/MapperTests/Schemes/XCSchemeMapperTests.swift} (76%) rename Tests/{XcodeProjToGraphTests/MapperTests/Xcode => XcodeProjMapperTests/MapperTests}/Settings/BuildSettingsTests.swift (78%) create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Settings/ConfigurationMatcherTests.swift rename Tests/{XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift => XcodeProjMapperTests/MapperTests/Settings/XCConfigurationMapperTests.swift} (58%) create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Target/PBXBuildRuleMapperTests.swift create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Target/PBXTargetDependencyMapper.swift create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Target/PBXTargetMapperTests.swift create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Target/TargetDependencyExtensionsTests.swift create mode 100644 Tests/XcodeProjMapperTests/MapperTests/Workspace/XCWorkspaceMapperTests.swift create mode 100644 Tests/XcodeProjMapperTests/Mocks/MockDefaults.swift create mode 100644 Tests/XcodeProjMapperTests/Mocks/MockProjectProvider.swift create mode 100644 Tests/XcodeProjMapperTests/Mocks/MockWorkspaceProvider.swift create mode 100644 Tests/XcodeProjMapperTests/Mocks/PBXProjectMapper+Mock.swift create mode 100644 Tests/XcodeProjMapperTests/Mocks/WorkspaceFixture.swift rename Tests/{XcodeProjToGraphTests => XcodeProjMapperTests}/ParserTests/ProjectParserTests.swift (70%) create mode 100644 Tests/XcodeProjMapperTests/PerformanceTests/PerformanceTests.swift create mode 100644 Tests/XcodeProjMapperTests/Resources/Fixtures.zip create mode 100644 Tests/XcodeProjMapperTests/TestData/.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/PBXBuildRule+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/PBXFileReference+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/PBXGroup+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/PBXNativeTarget+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/PBXProj+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/PBXProject+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/PBXShellScriptBuildPhase+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/PBXTargetDependency+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/PBXVariantGroup+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/XCBuildConfiguration+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/XCConfigurationList+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/XCScheme+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/XCSchemeTestableReference+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/XCUserData+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/XCVersionGroup+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/XCWorkspace+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/XCWorkspaceDataElement+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/XCWorkspaceDataGroup+TestData.swift create mode 100644 Tests/XcodeProjMapperTests/TestData/XcodeProj+TestData.swift delete mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildPhaseMapperTests.swift delete mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Build/BuildRuleMapperTests.swift delete mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/DependencyMapperTests.swift delete mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Dependency/TargetDependencyExtensionsTests.swift delete mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/ConfigurationMatcherTests.swift delete mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/TargetMapperTests.swift delete mode 100644 Tests/XcodeProjToGraphTests/MapperTests/Xcode/Workspace/WorkspaceMapperTests.swift delete mode 100644 Tests/XcodeProjToGraphTests/ProcessTests/LipoToolTests.swift delete mode 100644 Tests/XcodeProjToGraphTests/ProcessTests/ProcessRunnerTests.swift diff --git a/Package.resolved b/Package.resolved index c9deaf9e..dfc56acc 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,4 @@ { - "originHash" : "8dbcb87b4017f43ae481601d31f59f0ef12855a9874be06d0de98a190628d771", "pins" : [ { "identity" : "aexml", @@ -46,6 +45,24 @@ "version" : "0.10.1" } }, + { + "identity" : "swift-snapshot-testing", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-snapshot-testing", + "state" : { + "revision" : "42a086182681cf661f5c47c9b7dc3931de18c6d7", + "version" : "1.17.6" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swiftlang/swift-syntax", + "state" : { + "revision" : "0687f71944021d616d34d922343dcef086855920", + "version" : "600.0.1" + } + }, { "identity" : "xcodeproj", "kind" : "remoteSourceControl", @@ -56,5 +73,5 @@ } } ], - "version" : 3 + "version" : 2 } diff --git a/Package.swift b/Package.swift index d59c768e..008f1f4c 100644 --- a/Package.swift +++ b/Package.swift @@ -1,5 +1,4 @@ // swift-tools-version:5.9 - import PackageDescription let targets: [Target] = [ @@ -14,20 +13,16 @@ let targets: [Target] = [ ] ), .target( - name: "XcodeProjToGraph", + name: "XcodeProjMapper", dependencies: [ "XcodeGraph", .product(name: "Path", package: "Path"), .product(name: "XcodeProj", package: "XcodeProj"), ], - path: "Sources/XcodeProjToGraph" - ), - .target( - name: "TestSupport", - dependencies: [ - "XcodeProjToGraph", - ], - path: "Sources/TestSupport" + path: "Sources/XcodeProjMapper", + swiftSettings: [ + .enableExperimentalFeature("StrictConcurrency"), + ] ), .testTarget( name: "XcodeGraphTests", @@ -37,29 +32,37 @@ let targets: [Target] = [ path: "Tests/XcodeGraphTests" ), .testTarget( - name: "XcodeProjToGraphTests", + name: "XcodeProjMapperTests", dependencies: [ - "XcodeProjToGraph", - "TestSupport" + "XcodeProjMapper", + .product(name: "InlineSnapshotTesting", package: "swift-snapshot-testing"), ], - path: "Tests/XcodeProjToGraphTests" + path: "Tests/XcodeProjMapperTests", + resources: [ + .copy("Resources"), + ] ), ] let package = Package( name: "XcodeGraph", - platforms: [.macOS(.v12)], + platforms: [.macOS(.v13)], products: [ .library( name: "XcodeGraph", targets: ["XcodeGraph"] ), - .library(name: "XcodeProjToGraph", targets: ["XcodeProjToGraph"]), + .library(name: "XcodeProjMapper", targets: ["XcodeProjMapper"]), ], dependencies: [ .package(url: "https://github.com/Flight-School/AnyCodable", .upToNextMajor(from: "0.6.7")), .package(url: "https://github.com/tuist/Path.git", .upToNextMajor(from: "0.3.8")), - .package(url: "https://github.com/tuist/XcodeProj", .upToNextMajor(from: "8.25.0")) + .package(url: "https://github.com/tuist/XcodeProj", from: "8.25.0"), + .package( + url: "https://github.com/pointfreeco/swift-snapshot-testing", + from: "1.17.0" + ), ], + targets: targets ) diff --git a/Sources/TestSupport/Mocks/MockBuildFilesAndPhases.swift b/Sources/TestSupport/Mocks/MockBuildFilesAndPhases.swift deleted file mode 100644 index 1966b6ad..00000000 --- a/Sources/TestSupport/Mocks/MockBuildFilesAndPhases.swift +++ /dev/null @@ -1,139 +0,0 @@ -import Foundation -import Path -import XcodeGraph -@testable @preconcurrency import XcodeProj - -extension PBXBuildFile { - public static func mock( - file: PBXFileElement, - settings: [String: Any]? = nil, - pbxProj: PBXProj - ) -> PBXBuildFile { - let buildFile = PBXBuildFile(file: file, settings: settings) - pbxProj.add(object: buildFile) - return buildFile - } -} - -extension PBXBuildRule { - public static func mock( - compilerSpec: String = BuildRule.CompilerSpec.appleClang.rawValue, - fileType: String = BuildRule.FileType.cSource.rawValue, - isEditable: Bool = true, - filePatterns: String? = "*.cpp;*.cxx;*.cc", - name: String = "Default Build Rule", - dependencyFile: String? = nil, - outputFiles: [String] = ["$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).o"], - inputFiles: [String] = [], - outputFilesCompilerFlags: [String]? = nil, - script: String? = nil, - runOncePerArchitecture: Bool? = nil, - pbxProj: PBXProj - ) -> PBXBuildRule { - let rule = PBXBuildRule( - compilerSpec: compilerSpec, - fileType: fileType, - isEditable: isEditable, - filePatterns: filePatterns, - name: name, - dependencyFile: dependencyFile, - outputFiles: outputFiles, - inputFiles: inputFiles, - outputFilesCompilerFlags: outputFilesCompilerFlags, - script: script, - runOncePerArchitecture: runOncePerArchitecture - ) - pbxProj.add(object: rule) - return rule - } -} - -extension PBXSourcesBuildPhase { - public static func mock( - files: [PBXBuildFile], - pbxProj: PBXProj - ) -> PBXSourcesBuildPhase { - let phase = PBXSourcesBuildPhase(files: files) - pbxProj.add(object: phase) - return phase - } -} - -extension PBXResourcesBuildPhase { - public static func mock( - files: [PBXBuildFile], - pbxProj: PBXProj - ) -> PBXResourcesBuildPhase { - let phase = PBXResourcesBuildPhase(files: files) - pbxProj.add(object: phase) - return phase - } -} - -extension PBXFrameworksBuildPhase { - public static func mock( - files: [PBXBuildFile], - pbxProj: PBXProj - ) -> PBXFrameworksBuildPhase { - let phase = PBXFrameworksBuildPhase(files: files) - pbxProj.add(object: phase) - return phase - } -} - -extension PBXShellScriptBuildPhase { - public static func mock( - name: String? = "Embed Precompiled Frameworks", - shellScript: String = "#!/bin/sh\necho 'Mock Shell Script'", - inputPaths: [String] = [], - outputPaths: [String] = [], - inputFileListPaths: [String]? = nil, - outputFileListPaths: [String]? = nil, - shellPath: String = "/bin/sh", - buildActionMask: UInt = PBXBuildPhase.defaultBuildActionMask, - runOnlyForDeploymentPostprocessing: Bool = false, - showEnvVarsInLog: Bool = true, - alwaysOutOfDate: Bool = false, - dependencyFile: String? = nil, - pbxProj: PBXProj - ) -> PBXShellScriptBuildPhase { - let script = PBXShellScriptBuildPhase( - files: [], - name: name, - inputPaths: inputPaths, - outputPaths: outputPaths, - inputFileListPaths: inputFileListPaths, - outputFileListPaths: outputFileListPaths, - shellPath: shellPath, - shellScript: shellScript, - buildActionMask: buildActionMask, - runOnlyForDeploymentPostprocessing: runOnlyForDeploymentPostprocessing, - showEnvVarsInLog: showEnvVarsInLog, - alwaysOutOfDate: alwaysOutOfDate, - dependencyFile: dependencyFile - ) - pbxProj.add(object: script) - return script - } -} - -extension PBXCopyFilesBuildPhase { - public static func mock( - name: String? = "Embed Frameworks", - dstPath: String = "", - dstSubfolderSpec: PBXCopyFilesBuildPhase.SubFolder = .frameworks, - files: [PBXBuildFile] = [], - pbxProj: PBXProj - ) -> PBXCopyFilesBuildPhase { - let phase = PBXCopyFilesBuildPhase( - dstPath: dstPath, - dstSubfolderSpec: dstSubfolderSpec, - name: name, - buildActionMask: PBXBuildPhase.defaultBuildActionMask, - files: files, - runOnlyForDeploymentPostprocessing: false - ) - pbxProj.add(object: phase) - return phase - } -} diff --git a/Sources/TestSupport/Mocks/MockBuildSettings.swift b/Sources/TestSupport/Mocks/MockBuildSettings.swift deleted file mode 100644 index 4f0a7100..00000000 --- a/Sources/TestSupport/Mocks/MockBuildSettings.swift +++ /dev/null @@ -1,58 +0,0 @@ -import Foundation -import Path -import XcodeGraph -@testable @preconcurrency import XcodeProj - -extension XCBuildConfiguration { - public static func mock( - name: String = "Debug", - buildSettings: [String: Sendable] = MockDefaults.defaultDebugSettings, - baseConfiguration: PBXFileReference? = nil, - pbxProj: PBXProj - ) -> XCBuildConfiguration { - let anySettings = buildSettings.reduce(into: [String: Any]()) { $0[$1.key] = $1.value } - let config = XCBuildConfiguration( - name: name, - baseConfiguration: baseConfiguration, - buildSettings: anySettings - ) - pbxProj.add(object: config) - return config - } -} - -extension XCConfigurationList { - public static func mock( - configs: [(name: String, settings: [String: Sendable])] = [ - ("Debug", MockDefaults.defaultDebugSettings), - ("Release", MockDefaults.defaultReleaseSettings), - ], - defaultConfigurationName: String = "Release", - defaultConfigurationIsVisible: Bool = false, - proj: PBXProj - ) -> XCConfigurationList { - let configsAny: [(String, [String: Any])] = configs.map { name, sendableSettings in - let anySettings = sendableSettings.reduce(into: [String: Any]()) { $0[$1.key] = $1.value } - return (name, anySettings) - } - - let buildConfigs: [XCBuildConfiguration] = configsAny.map { name, settings in - let config = XCBuildConfiguration( - name: name, - baseConfiguration: nil, - buildSettings: settings - ) - proj.add(object: config) - return config - } - - let configList = XCConfigurationList( - buildConfigurations: buildConfigs, - defaultConfigurationName: defaultConfigurationName, - defaultConfigurationIsVisible: defaultConfigurationIsVisible - ) - proj.add(object: configList) - - return configList - } -} diff --git a/Sources/TestSupport/Mocks/MockDefaults.swift b/Sources/TestSupport/Mocks/MockDefaults.swift deleted file mode 100644 index 3a8b01b9..00000000 --- a/Sources/TestSupport/Mocks/MockDefaults.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Foundation -import Path -import XcodeGraph -@testable @preconcurrency import XcodeProj - -public enum MockDefaults { - public static let defaultDebugSettings: [String: Sendable] = [ - "PRODUCT_NAME": "$(TARGET_NAME)", - "ENABLE_STRICT_OBJC_MSGSEND": "YES", - "SDKROOT": "iphoneos", - "PRODUCT_BUNDLE_IDENTIFIER": "com.test.app", - ] - - public static let defaultReleaseSettings: [String: Sendable] = [ - "PRODUCT_NAME": "$(TARGET_NAME)", - "VALIDATE_PRODUCT": "YES", - "SDKROOT": "iphoneos", - ] - - public static let defaultProjectAttributes: [String: Sendable] = [ - "BuildIndependentTargetsInParallel": "YES", - ] -} diff --git a/Sources/TestSupport/Mocks/MockFileCreator.swift b/Sources/TestSupport/Mocks/MockFileCreator.swift deleted file mode 100644 index b15cea44..00000000 --- a/Sources/TestSupport/Mocks/MockFileCreator.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Foundation - -public class MockFileCreator { - public static func createTemporaryExecutable( - name: String = "mockLipo_\(UUID().uuidString)", - withContent content: String - ) throws -> String { - let tempDirectory = FileManager.default.temporaryDirectory - let mockExecutablePath = tempDirectory.appendingPathComponent(name).path - - try content.write(toFile: mockExecutablePath, atomically: true, encoding: .utf8) - - try FileManager.default.setAttributes( - [.posixPermissions: 0o755], ofItemAtPath: mockExecutablePath - ) - - return mockExecutablePath - } -} diff --git a/Sources/TestSupport/Mocks/MockFileStructure.swift b/Sources/TestSupport/Mocks/MockFileStructure.swift deleted file mode 100644 index ae447fa7..00000000 --- a/Sources/TestSupport/Mocks/MockFileStructure.swift +++ /dev/null @@ -1,144 +0,0 @@ -import Foundation -import Path -import XcodeGraph -@testable @preconcurrency import XcodeProj - -extension PBXFileReference { - public static func mock( - sourceTree: PBXSourceTree = .group, - name: String? = nil, - explicitFileType: String? = nil, - path: String = "AppDelegate.swift", - lastKnownFileType: String? = "sourcecode.swift", - includeInIndex: Bool? = nil, - pbxProj: PBXProj, - addToMainGroup: Bool = true - ) -> PBXFileReference { - let file = PBXFileReference( - sourceTree: sourceTree, - name: name, - explicitFileType: explicitFileType, - lastKnownFileType: lastKnownFileType, - path: path, - includeInIndex: includeInIndex - ) - pbxProj.add(object: file) - if addToMainGroup, let project = pbxProj.projects.first, - let mainGroup = project.mainGroup - { - mainGroup.children.append(file) - } - return file - } - - public static func mockProject( - path: String = "App.xcodeproj", - name: String? = "App", - sourceTree: PBXSourceTree = .sourceRoot, - lastKnownFileType: String? = nil, - explicitFileType: String? = nil, - includeInIndex: Bool? = nil, - pbxProj: PBXProj - ) -> PBXFileReference { - let file = PBXFileReference( - sourceTree: sourceTree, - name: name, - explicitFileType: explicitFileType, - lastKnownFileType: lastKnownFileType, - path: path, - includeInIndex: includeInIndex - ) - pbxProj.add(object: file) - return file - } -} - -extension PBXVariantGroup { - public static func mockVariant( - children: [PBXFileElement] = [], - sourceTree: PBXSourceTree = .group, - name: String? = "MainGroup", - path: String? = "/tmp/TestProject", - pbxProj: PBXProj, - addToMainGroup: Bool = true - ) -> PBXVariantGroup { - let group = PBXVariantGroup( - children: children, - sourceTree: sourceTree, - name: name, - path: path - ) - pbxProj.add(objects: children) - pbxProj.add(object: group) - if addToMainGroup, let project = pbxProj.projects.first, let mainGroup = project.mainGroup { - mainGroup.children.append(group) - } - - return group - } -} - -extension PBXGroup { - public static func mock( - children: [PBXFileElement] = [], - sourceTree: PBXSourceTree = .group, - name: String? = "MainGroup", - path: String? = "/tmp/TestProject", - pbxProj: PBXProj, - addToMainGroup: Bool = true - ) -> PBXGroup { - let group = PBXGroup( - children: children, - sourceTree: sourceTree, - name: name, - path: path - ) - pbxProj.add(objects: children) - pbxProj.add(object: group) - if addToMainGroup, let project = pbxProj.projects.first, let mainGroup = project.mainGroup { - mainGroup.children.append(group) - } - - return group - } -} - -extension XCVersionGroup { - public static func mock( - currentVersion: PBXFileReference? = nil, - children: [PBXFileElement] = [], - path: String = "DefaultGroup", - sourceTree: PBXSourceTree = .group, - versionGroupType: String? = nil, - name: String? = nil, - includeInIndex: Bool? = nil, - wrapsLines: Bool? = nil, - usesTabs: Bool? = nil, - indentWidth: UInt? = nil, - tabWidth: UInt? = nil, - pbxProj: PBXProj - ) -> XCVersionGroup { - let group = XCVersionGroup( - currentVersion: currentVersion, - path: path, - name: name, - sourceTree: sourceTree, - versionGroupType: versionGroupType, - includeInIndex: includeInIndex, - wrapsLines: wrapsLines, - usesTabs: usesTabs, - indentWidth: indentWidth, - tabWidth: tabWidth - ) - if let currentVersion { - pbxProj.add(object: currentVersion) - } - if let project = pbxProj.projects.first, let mainGroup = project.mainGroup { - mainGroup.children.append(group) - } - group.children = children - pbxProj.add(object: group) - pbxProj.add(objects: children) - return group - } -} diff --git a/Sources/TestSupport/Mocks/MockProjectAndWorkspace.swift b/Sources/TestSupport/Mocks/MockProjectAndWorkspace.swift deleted file mode 100644 index c12677bc..00000000 --- a/Sources/TestSupport/Mocks/MockProjectAndWorkspace.swift +++ /dev/null @@ -1,138 +0,0 @@ -import Foundation -import Path -import XcodeGraph -@testable @preconcurrency import XcodeProj - -extension PBXProject { - public static func mock( - name: String = "MainApp", - buildConfigurationList: XCConfigurationList? = nil, - compatibilityVersion: String = "Xcode 14.0", - mainGroup: PBXGroup? = nil, - developmentRegion: String = "en", - knownRegions: [String] = ["Base", "en"], - productsGroup: PBXGroup? = nil, - targets: [PBXTarget]? = nil, - attributes: [String: Any] = MockDefaults.defaultProjectAttributes, - packageReferences: [XCRemoteSwiftPackageReference] = [], - pbxProj: PBXProj - ) -> PBXProject { - let resolvedMainGroup = - mainGroup - ?? PBXGroup.mock( - children: [], - sourceTree: .group, - name: "MainGroup", - path: "/tmp/TestProject", - pbxProj: pbxProj, - addToMainGroup: false - ) - - let resolvedBuildConfigList = buildConfigurationList ?? XCConfigurationList.mock(proj: pbxProj) - pbxProj.add(object: resolvedBuildConfigList) - - if let productsGroup { - pbxProj.add(object: productsGroup) - } - - let projectRef = PBXFileReference.mock( - name: "App", - path: "App.xcodeproj", - pbxProj: pbxProj, - addToMainGroup: false - ) - - let proj = PBXProject( - name: name, - buildConfigurationList: resolvedBuildConfigList, - compatibilityVersion: compatibilityVersion, - preferredProjectObjectVersion: nil, - minimizedProjectReferenceProxies: nil, - mainGroup: resolvedMainGroup, - developmentRegion: developmentRegion, - hasScannedForEncodings: 0, - knownRegions: knownRegions, - productsGroup: productsGroup, - projectDirPath: "", - projects: [["B900DB68213936CC004AEC3E": projectRef]], - projectRoots: [""], - targets: targets ?? [], - packages: packageReferences, - attributes: attributes, - targetAttributes: [:] - ) - - pbxProj.add(object: proj) - pbxProj.rootObject = proj - return proj - } -} - -extension XCWorkspace { - public static func mock( - files: [String] = [ - "App/MainApp.xcodeproj", - "Framework1/Framework1.xcodeproj", - "StaticFramework1/StaticFramework1.xcodeproj", - ] - ) -> XCWorkspace { - let children = files.map { path in - XCWorkspaceDataElement.file(XCWorkspaceDataFileRef(location: .group(path))) - } - return XCWorkspace(data: XCWorkspaceData(children: children)) - } -} - -extension XcodeProj { - public static func mock( - projectName: String = "MainApp", - targets: [PBXTarget] = [], - schemes _: [XCScheme] = [] - ) -> XcodeProj { - let pbxProj = PBXProj() - let target = targets.first ?? PBXNativeTarget.mock(pbxProj: pbxProj) - - _ = XCBuildConfiguration.mock( - name: "Debug", - buildSettings: MockDefaults.defaultDebugSettings, - pbxProj: pbxProj - ) - _ = XCBuildConfiguration.mock( - name: "Release", - buildSettings: MockDefaults.defaultReleaseSettings, - pbxProj: pbxProj - ) - - let configList = XCConfigurationList.mock( - configs: [ - ("Debug", MockDefaults.defaultDebugSettings), - ("Release", MockDefaults.defaultReleaseSettings), - ], - proj: pbxProj - ) - target.buildConfigurationList = configList - - let pbxProject = PBXProject.mock( - name: projectName, - buildConfigurationList: configList, - targets: [target], - pbxProj: pbxProj - ) - pbxProj.rootObject = pbxProject - - let workspace = XCWorkspace.mock(files: ["App/\(projectName).xcodeproj"]) - return XcodeProj(workspace: workspace, pbxproj: pbxProj) - } -} - -extension PBXObjectReference { - public static func mock(objects: PBXObjects) -> PBXObjectReference { - PBXObjectReference(objects: objects) - } -} - -extension PBXProj { - public func add(objects: [PBXObject]) { - objects.forEach { add(object: $0) } - } -} diff --git a/Sources/TestSupport/Mocks/MockProjectProvider.swift b/Sources/TestSupport/Mocks/MockProjectProvider.swift deleted file mode 100644 index b1ae08c4..00000000 --- a/Sources/TestSupport/Mocks/MockProjectProvider.swift +++ /dev/null @@ -1,97 +0,0 @@ -import Foundation -import Path -import Testing -import XcodeGraph -import XcodeProj - -@testable import XcodeProjToGraph - -public struct MockWorkspaceProvider: WorkspaceProviding { - public var workspaceDirectory: AbsolutePath - public var xcWorkspacePath: AbsolutePath - public var xcworkspace: XCWorkspace - - public init(xcWorkspacePath: AbsolutePath, xcworkspace: XCWorkspace) { - self.xcWorkspacePath = xcWorkspacePath - workspaceDirectory = xcWorkspacePath.parentDirectory - self.xcworkspace = xcworkspace - } -} - -public struct MockProjectProvider: ProjectProviding { - public let sourceDirectory: AbsolutePath - public let xcodeProjPath: AbsolutePath - public let xcodeProj: XcodeProj - public var pbxProj: PBXProj { - xcodeProj.pbxproj - } - - public init( - sourceDirectory: String = "/tmp", - projectName: String = "TestProject", - configurationList: XCConfigurationList? = nil, - pbxProj: PBXProj = PBXProj() - ) { - let configurationList = configurationList ?? .mock(proj: pbxProj) - self.sourceDirectory = try! AbsolutePath.resolvePath(sourceDirectory) - xcodeProjPath = self.sourceDirectory.appending(component: "TestProject.xcodproj") - // minimal project setup - let pbxProject = PBXProject.mock( - name: projectName, buildConfigurationList: configurationList, pbxProj: pbxProj - ) - pbxProj.add(object: pbxProject) - pbxProj.add(object: configurationList) - pbxProj.rootObject = pbxProject - - xcodeProj = XcodeProj(workspace: XCWorkspace(), pbxproj: pbxProj) - } - - public func pbxProject() throws -> PBXProject { - return xcodeProj.pbxproj.projects.first! - } -} - -extension MockProjectProvider { - public static func makeBasicProjectProvider( - projectName: String = "TestProject", - sourceDirectory: String = "/tmp/\(UUID().uuidString)" - ) -> MockProjectProvider { - return MockProjectProvider( - sourceDirectory: sourceDirectory, - projectName: projectName - ) - } - - public func addTargets(_ targets: [PBXNativeTarget]) throws { - let project = try pbxProject() - project.targets.append(contentsOf: targets) - } -} - -extension ProjectMapper { - public func createMappedProject( - projectName: String = "TestProject", - targets: [PBXNativeTarget] = [] - ) async throws -> Project { - let provider = MockProjectProvider.makeBasicProjectProvider(projectName: projectName) - try provider.addTargets(targets) - - let mapper = ProjectMapper(projectProvider: provider) - return try await mapper.mapProject() - } - - public func createMappedGraph( - graphType: GraphType, - projectProviders: [AbsolutePath: MockProjectProvider] - ) async throws -> XcodeGraph.Graph { - let mapper = GraphMapper(graphType: graphType) { path in - guard let provider = projectProviders[path] else { - Issue.record("Unexpected project path requested: \(path)") - throw MappingError.noProjectsFound(path: path.pathString) - } - return provider - } - - return try await mapper.xcodeGraph() - } -} diff --git a/Sources/TestSupport/Mocks/MockSchemesAndUserData.swift b/Sources/TestSupport/Mocks/MockSchemesAndUserData.swift deleted file mode 100644 index c744a4dd..00000000 --- a/Sources/TestSupport/Mocks/MockSchemesAndUserData.swift +++ /dev/null @@ -1,79 +0,0 @@ -import Foundation -import Path -import XcodeGraph -@testable @preconcurrency import XcodeProj - -extension XCScheme.TestableReference { - public static func mock( - skipped: Bool, - parallelization: XCScheme.TestParallelization = .none, - randomExecutionOrdering: Bool = false, - buildableReference: XCScheme.BuildableReference, - locationScenarioReference: XCScheme.LocationScenarioReference? = nil, - skippedTests: [XCScheme.TestItem] = [], - selectedTests: [XCScheme.TestItem] = [], - useTestSelectionWhitelist: Bool? = nil - ) -> XCScheme.TestableReference { - XCScheme.TestableReference( - skipped: skipped, - parallelization: parallelization, - randomExecutionOrdering: randomExecutionOrdering, - buildableReference: buildableReference, - locationScenarioReference: locationScenarioReference, - skippedTests: skippedTests, - selectedTests: selectedTests, - useTestSelectionWhitelist: useTestSelectionWhitelist - ) - } -} - -extension XCScheme { - public static func mock( - name: String = "DefaultScheme", - buildAction: BuildAction? = nil, - testAction: TestAction? = nil, - launchAction: LaunchAction? = nil, - archiveAction: ArchiveAction? = nil, - profileAction: ProfileAction? = nil, - analyzeAction: AnalyzeAction? = nil, - wasCreatedForAppExtension: Bool? = nil - ) -> XCScheme { - XCScheme( - name: name, - lastUpgradeVersion: "1.3", - version: "1.3", - buildAction: buildAction, - testAction: testAction, - launchAction: launchAction, - profileAction: profileAction, - analyzeAction: analyzeAction, - archiveAction: archiveAction, - wasCreatedForAppExtension: wasCreatedForAppExtension - ) - } -} - -extension XCUserData { - public static func mock( - userName: String = "user", - schemes: [XCScheme] = [], - schemeManagement: XCSchemeManagement? = XCSchemeManagement( - schemeUserState: [ - XCSchemeManagement.UserStateScheme( - name: "App.xcscheme", - shared: true, - orderHint: 0, - isShown: true - ), - ], - suppressBuildableAutocreation: nil - ) - ) -> XCUserData { - XCUserData( - userName: userName, - schemes: schemes, - breakpoints: nil, - schemeManagement: schemeManagement - ) - } -} diff --git a/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift b/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift deleted file mode 100644 index 750b6996..00000000 --- a/Sources/TestSupport/Mocks/MockTargetsAndDependencies.swift +++ /dev/null @@ -1,190 +0,0 @@ -import Foundation -import Path -import XcodeGraph -@testable @preconcurrency import XcodeProj - -extension PBXTargetDependency { - public static func mock( - name: String? = "App", - target: PBXTarget? = nil, - targetProxy: PBXContainerItemProxy? = nil, - platformFilter: String? = nil, - platformFilters: [String]? = nil, - pbxProj: PBXProj - ) -> PBXTargetDependency { - let dependency = PBXTargetDependency( - name: name, - platformFilter: platformFilter, - platformFilters: platformFilters, - target: target, - targetProxy: targetProxy - ) - pbxProj.add(object: dependency) - return dependency - } -} - -extension PBXContainerItemProxy { - public static func mock( - containerPortal: PBXContainerItemProxy.ContainerPortal, - proxyType: PBXContainerItemProxy.ProxyType = .nativeTarget, - remoteGlobalID: PBXContainerItemProxy.RemoteGlobalID = .string("TARGET_REF"), - remoteInfo: String? = "App", - pbxProj: PBXProj - ) -> PBXContainerItemProxy { - let proxy = PBXContainerItemProxy( - containerPortal: containerPortal, - remoteGlobalID: remoteGlobalID, - proxyType: proxyType, - remoteInfo: remoteInfo - ) - pbxProj.add(object: proxy) - return proxy - } -} - -extension PBXTargetDependency { - public static func mockTargetDependency( - name: String, - platformFilters: [String]? = nil, - platformFilter: String? = nil, - pbxProj: PBXProj - ) -> PBXTargetDependency { - let target = PBXNativeTarget.mock( - name: name, - productType: .application, - pbxProj: pbxProj - ) - - let dep = PBXTargetDependency( - name: nil, - target: target - ) - dep.platformFilter = platformFilter - dep.platformFilters = platformFilters - pbxProj.add(object: dep) - return dep - } - - public static func mockPackageProductDependency( - productName: String, - pbxProj: PBXProj - ) -> PBXTargetDependency { - let productRef = XCSwiftPackageProductDependency.mock( - productName: productName, - pbxProj: pbxProj - ) - let dep = PBXTargetDependency(name: nil, product: productRef) - pbxProj.add(object: dep) - return dep - } - - public static func mockProxyDependency( - remoteInfo: String, - proxyType: PBXContainerItemProxy.ProxyType, - containerPortal: PBXContainerItemProxy.ContainerPortal, - pbxProj: PBXProj, - platformFilter: String? = nil, - platformFilters: [String]? = nil, - remoteObject: PBXObject? = nil - ) -> PBXTargetDependency { - let proxy = PBXContainerItemProxy( - containerPortal: containerPortal, - remoteGlobalID: .string("GLOBAL_ID"), - proxyType: proxyType, - remoteInfo: remoteInfo - ) - pbxProj.add(object: proxy) - - if let remoteObject { - proxy.remoteGlobalID = .object(remoteObject) - } - - let dep = PBXTargetDependency(name: nil, target: nil, targetProxy: proxy) - dep.platformFilter = platformFilter - dep.platformFilters = platformFilters - pbxProj.add(object: dep) - return dep - } -} - -extension XCSwiftPackageProductDependency { - public static func mock( - productName: String, - package: XCRemoteSwiftPackageReference? = nil, - isPlugin: Bool = false, - pbxProj: PBXProj - ) -> XCSwiftPackageProductDependency { - let dep = XCSwiftPackageProductDependency( - productName: productName, package: package, isPlugin: isPlugin - ) - pbxProj.add(object: dep) - return dep - } -} - -extension PBXNativeTarget { - public static func mock( - name: String = "App", - buildConfigurationList: XCConfigurationList? = nil, - buildRules: [PBXBuildRule]? = nil, - buildPhases: [PBXBuildPhase]? = nil, - dependencies: [PBXTargetDependency] = [], - productInstallPath: String? = nil, - productType: PBXProductType = .application, - product: PBXFileReference? = nil, - pbxProj: PBXProj - ) -> PBXNativeTarget { - let resolvedProduct = - product - ?? PBXFileReference.mock( - sourceTree: .buildProductsDir, - explicitFileType: "wrapper.application", - path: "App.app", - lastKnownFileType: nil, - includeInIndex: false, - pbxProj: pbxProj - ) - - let resolvedBuildConfigList = buildConfigurationList ?? XCConfigurationList.mock(proj: pbxProj) - let resolvedBuildRules = buildRules ?? [PBXBuildRule.mock(pbxProj: pbxProj)] - let resolvedBuildPhases = - buildPhases ?? [ - PBXSourcesBuildPhase.mock(files: [], pbxProj: pbxProj), - PBXResourcesBuildPhase.mock(files: [], pbxProj: pbxProj), - PBXFrameworksBuildPhase.mock(files: [], pbxProj: pbxProj), - ] - - let target = PBXNativeTarget( - name: name, - buildConfigurationList: resolvedBuildConfigList, - buildPhases: resolvedBuildPhases, - buildRules: resolvedBuildRules, - dependencies: dependencies, - productInstallPath: productInstallPath, - productName: name, - product: resolvedProduct, - productType: productType - ) - pbxProj.add(object: target) - return target - } -} - -extension XCRemoteSwiftPackageReference { - static func mock( - repositoryURL: String, - versionRequirement: VersionRequirement? - ) -> XCRemoteSwiftPackageReference { - return XCRemoteSwiftPackageReference( - repositoryURL: repositoryURL, - versionRequirement: versionRequirement - ) - } -} - -extension XCLocalSwiftPackageReference { - static func mock(relativePath: String) -> XCLocalSwiftPackageReference { - return XCLocalSwiftPackageReference(relativePath: relativePath) - } -} diff --git a/Sources/XcodeGraph/DependenciesGraph/DependenciesGraph.swift b/Sources/XcodeGraph/DependenciesGraph/DependenciesGraph.swift index 62972a92..639bd16b 100644 --- a/Sources/XcodeGraph/DependenciesGraph/DependenciesGraph.swift +++ b/Sources/XcodeGraph/DependenciesGraph/DependenciesGraph.swift @@ -22,7 +22,7 @@ public struct DependenciesGraph: Equatable, Codable, Sendable { #if DEBUG extension DependenciesGraph { - public static func test( + static func test( externalDependencies: [String: [TargetDependency]] = [:], externalProjects: [AbsolutePath: Project] = [:] ) -> Self { @@ -43,7 +43,7 @@ public struct DependenciesGraph: Equatable, Codable, Sendable { ) } - public static func test( + static func test( packageFolder: AbsolutePath ) -> Self { let externalDependencies = [ diff --git a/Sources/XcodeGraph/Graph/Graph.swift b/Sources/XcodeGraph/Graph/Graph.swift index 8cdf72d7..5f749c82 100644 --- a/Sources/XcodeGraph/Graph/Graph.swift +++ b/Sources/XcodeGraph/Graph/Graph.swift @@ -68,7 +68,7 @@ extension [GraphEdge: PlatformCondition] { #if DEBUG extension Graph { - public static func test( + static func test( name: String = "graph", path: AbsolutePath = .root, workspace: Workspace = .test(), diff --git a/Sources/XcodeGraph/Graph/GraphTarget.swift b/Sources/XcodeGraph/Graph/GraphTarget.swift index 78f81765..fdc34f10 100644 --- a/Sources/XcodeGraph/Graph/GraphTarget.swift +++ b/Sources/XcodeGraph/Graph/GraphTarget.swift @@ -34,7 +34,7 @@ public struct GraphTarget: Equatable, Hashable, Comparable, CustomDebugStringCon #if DEBUG extension GraphTarget { - public static func test( + static func test( path: AbsolutePath = .root, target: Target = .test(), project: Project = .test(type: .local) diff --git a/Sources/XcodeGraph/Models/AnalyzeAction.swift b/Sources/XcodeGraph/Models/AnalyzeAction.swift index c0d5577c..187ce720 100644 --- a/Sources/XcodeGraph/Models/AnalyzeAction.swift +++ b/Sources/XcodeGraph/Models/AnalyzeAction.swift @@ -14,7 +14,7 @@ public struct AnalyzeAction: Equatable, Codable, Sendable { #if DEBUG extension AnalyzeAction { - public static func test(configurationName: String = "Beta Release") -> AnalyzeAction { + static func test(configurationName: String = "Beta Release") -> AnalyzeAction { AnalyzeAction(configurationName: configurationName) } } diff --git a/Sources/XcodeGraph/Models/ArchiveAction.swift b/Sources/XcodeGraph/Models/ArchiveAction.swift index 99dc55a4..fce94fdc 100644 --- a/Sources/XcodeGraph/Models/ArchiveAction.swift +++ b/Sources/XcodeGraph/Models/ArchiveAction.swift @@ -29,7 +29,7 @@ public struct ArchiveAction: Equatable, Codable, Sendable { #if DEBUG extension ArchiveAction { - public static func test( + static func test( configurationName: String = "Beta Release", revealArchiveInOrganizer: Bool = true, customArchiveName: String? = nil, diff --git a/Sources/XcodeGraph/Models/Arguments.swift b/Sources/XcodeGraph/Models/Arguments.swift index 5b939098..ae14c4d4 100644 --- a/Sources/XcodeGraph/Models/Arguments.swift +++ b/Sources/XcodeGraph/Models/Arguments.swift @@ -31,7 +31,7 @@ extension Arguments: Equatable { #if DEBUG extension Arguments { - public static func test( + static func test( environmentVariables: [String: EnvironmentVariable] = [:], launchArguments: [LaunchArgument] = [] ) -> Arguments { diff --git a/Sources/XcodeGraph/Models/BuildAction.swift b/Sources/XcodeGraph/Models/BuildAction.swift index 93f32ef2..557a6927 100644 --- a/Sources/XcodeGraph/Models/BuildAction.swift +++ b/Sources/XcodeGraph/Models/BuildAction.swift @@ -29,7 +29,7 @@ public struct BuildAction: Equatable, Codable, Sendable { #if DEBUG extension BuildAction { - public static func test( + static func test( // swiftlint:disable:next force_try targets: [TargetReference] = [TargetReference(projectPath: try! AbsolutePath(validating: "/Project"), name: "App")], preActions: [ExecutionAction] = [], diff --git a/Sources/XcodeGraph/Models/Headers.swift b/Sources/XcodeGraph/Models/Headers.swift index 98fa08d0..69345e46 100644 --- a/Sources/XcodeGraph/Models/Headers.swift +++ b/Sources/XcodeGraph/Models/Headers.swift @@ -24,7 +24,7 @@ public struct Headers: Equatable, Codable, Sendable { #if DEBUG extension Headers { - public static func test( + static func test( public: [AbsolutePath] = [], private: [AbsolutePath] = [], project: [AbsolutePath] = [] diff --git a/Sources/XcodeGraph/Models/IDETemplateMacros.swift b/Sources/XcodeGraph/Models/IDETemplateMacros.swift index 28067ffa..96e2b050 100644 --- a/Sources/XcodeGraph/Models/IDETemplateMacros.swift +++ b/Sources/XcodeGraph/Models/IDETemplateMacros.swift @@ -39,7 +39,7 @@ public struct IDETemplateMacros: Codable, Hashable, Sendable { #if DEBUG extension IDETemplateMacros { - public static func test(fileHeader: String? = "Header template") -> IDETemplateMacros { + static func test(fileHeader: String? = "Header template") -> IDETemplateMacros { IDETemplateMacros(fileHeader: fileHeader) } } diff --git a/Sources/XcodeGraph/Models/Metadata/FrameworkMetadata.swift b/Sources/XcodeGraph/Models/Metadata/FrameworkMetadata.swift index a746d099..67d3bdbe 100644 --- a/Sources/XcodeGraph/Models/Metadata/FrameworkMetadata.swift +++ b/Sources/XcodeGraph/Models/Metadata/FrameworkMetadata.swift @@ -32,7 +32,7 @@ public struct FrameworkMetadata: Equatable { #if DEBUG extension FrameworkMetadata { - public static func test( + static func test( // swiftlint:disable:next force_try path: AbsolutePath = try! AbsolutePath(validating: "/Frameworks/TestFramework.xframework"), // swiftlint:disable:next force_try diff --git a/Sources/XcodeGraph/Models/Metadata/LibraryMetadata.swift b/Sources/XcodeGraph/Models/Metadata/LibraryMetadata.swift index 5861b6b1..77660491 100644 --- a/Sources/XcodeGraph/Models/Metadata/LibraryMetadata.swift +++ b/Sources/XcodeGraph/Models/Metadata/LibraryMetadata.swift @@ -26,7 +26,7 @@ public struct LibraryMetadata: Equatable { #if DEBUG extension LibraryMetadata { - public static func test( + static func test( // swiftlint:disable:next force_try path: AbsolutePath = try! AbsolutePath(validating: "/Libraries/libTest/libTest.a"), // swiftlint:disable:next force_try diff --git a/Sources/XcodeGraph/Models/Metadata/TargetMetadata.swift b/Sources/XcodeGraph/Models/Metadata/TargetMetadata.swift index 56a184a4..a6a5a56d 100644 --- a/Sources/XcodeGraph/Models/Metadata/TargetMetadata.swift +++ b/Sources/XcodeGraph/Models/Metadata/TargetMetadata.swift @@ -11,7 +11,7 @@ public struct TargetMetadata: Codable, Equatable, Sendable { #if DEBUG extension TargetMetadata { - public static func test( + static func test( tags: Set = [] ) -> TargetMetadata { TargetMetadata( diff --git a/Sources/XcodeGraph/Models/Metadata/XCFrameworkMetadata.swift b/Sources/XcodeGraph/Models/Metadata/XCFrameworkMetadata.swift index 72e24715..5666abf9 100644 --- a/Sources/XcodeGraph/Models/Metadata/XCFrameworkMetadata.swift +++ b/Sources/XcodeGraph/Models/Metadata/XCFrameworkMetadata.swift @@ -37,7 +37,7 @@ public struct XCFrameworkMetadata: Equatable { #if DEBUG extension XCFrameworkMetadata { - public static func test( + static func test( // swiftlint:disable:next force_try path: AbsolutePath = try! AbsolutePath(validating: "/XCFrameworks/XCFramework.xcframework"), infoPlist: XCFrameworkInfoPlist = .test(), diff --git a/Sources/XcodeGraph/Models/PlatformCondition.swift b/Sources/XcodeGraph/Models/PlatformCondition.swift index 64e1847a..a7453b41 100644 --- a/Sources/XcodeGraph/Models/PlatformCondition.swift +++ b/Sources/XcodeGraph/Models/PlatformCondition.swift @@ -65,7 +65,7 @@ public struct PlatformCondition: Codable, Hashable, Equatable, Comparable, Senda #if DEBUG extension PlatformCondition { - public static func test(_ platformFilters: PlatformFilters) throws -> PlatformCondition? { + static func test(_ platformFilters: PlatformFilters) throws -> PlatformCondition? { .when(platformFilters) } } diff --git a/Sources/XcodeGraph/Models/ProfileAction.swift b/Sources/XcodeGraph/Models/ProfileAction.swift index 1699b6df..8f9aacff 100644 --- a/Sources/XcodeGraph/Models/ProfileAction.swift +++ b/Sources/XcodeGraph/Models/ProfileAction.swift @@ -29,7 +29,7 @@ public struct ProfileAction: Equatable, Codable, Sendable { #if DEBUG extension ProfileAction { - public static func test( + static func test( configurationName: String = "Beta Release", preActions: [ExecutionAction] = [], postActions: [ExecutionAction] = [], diff --git a/Sources/XcodeGraph/Models/Project.swift b/Sources/XcodeGraph/Models/Project.swift index 89a67d8f..c88703b6 100644 --- a/Sources/XcodeGraph/Models/Project.swift +++ b/Sources/XcodeGraph/Models/Project.swift @@ -173,7 +173,7 @@ public struct Project: Hashable, Equatable, CustomStringConvertible, CustomDebug #if DEBUG extension Project { - public static func test( + static func test( path: AbsolutePath = try! AbsolutePath(validating: "/Project"), // swiftlint:disable:this force_try sourceRootPath: AbsolutePath = try! AbsolutePath(validating: "/Project"), // swiftlint:disable:this force_try // swiftlint:disable:next force_try @@ -265,7 +265,8 @@ public struct Project: Hashable, Equatable, CustomStringConvertible, CustomDebug } extension Project.Options { - public static func test( + @usableFromInline + static func test( automaticSchemesOptions: AutomaticSchemesOptions = .enabled( targetSchemesGrouping: .byNameSuffix( build: ["Implementation", "Interface", "Mocks", "Testing"], @@ -291,7 +292,7 @@ public struct Project: Hashable, Equatable, CustomStringConvertible, CustomDebug } extension Project.Options.TextSettings { - public static func test( + static func test( usesTabs: Bool? = true, indentWidth: UInt? = 2, tabWidth: UInt? = 2, diff --git a/Sources/XcodeGraph/Models/RawScriptBuildPhase.swift b/Sources/XcodeGraph/Models/RawScriptBuildPhase.swift index 2555a244..ebeea9d3 100644 --- a/Sources/XcodeGraph/Models/RawScriptBuildPhase.swift +++ b/Sources/XcodeGraph/Models/RawScriptBuildPhase.swift @@ -41,7 +41,7 @@ public struct RawScriptBuildPhase: Equatable, Codable, Sendable { #if DEBUG extension RawScriptBuildPhase { - public static func test( + static func test( name: String = "Test", script: String = "", showEnvVarsInLog: Bool = false, diff --git a/Sources/XcodeGraph/Models/ResourceSynthesizer.swift b/Sources/XcodeGraph/Models/ResourceSynthesizer.swift index 9b8880e2..878e4a4f 100644 --- a/Sources/XcodeGraph/Models/ResourceSynthesizer.swift +++ b/Sources/XcodeGraph/Models/ResourceSynthesizer.swift @@ -13,7 +13,7 @@ public struct ResourceSynthesizer: Equatable, Hashable, Codable, Sendable { case defaultTemplate(String) } - public enum Parser: String, Equatable, Hashable, Codable, Sendable { + public enum Parser: String, CaseIterable, Equatable, Hashable, Codable, Sendable { case strings case stringsCatalog case assets @@ -98,7 +98,7 @@ extension ResourceSynthesizer.Parser.Option: ExpressibleByArrayLiteral { #if DEBUG extension XcodeGraph.ResourceSynthesizer { - public static func test( + static func test( parser: Parser = .assets, parserOptions: [String: Parser.Option] = [:], extensions: Set = ["xcassets"], diff --git a/Sources/XcodeGraph/Models/RunAction.swift b/Sources/XcodeGraph/Models/RunAction.swift index a0c2e092..cd94cc2f 100644 --- a/Sources/XcodeGraph/Models/RunAction.swift +++ b/Sources/XcodeGraph/Models/RunAction.swift @@ -53,7 +53,7 @@ public struct RunAction: Equatable, Codable, Sendable { #if DEBUG extension RunAction { - public static func test( + static func test( configurationName: String = BuildConfiguration.debug.name, attachDebugger: Bool = true, customLLDBInitFile: AbsolutePath? = nil, diff --git a/Sources/XcodeGraph/Models/Scheme.swift b/Sources/XcodeGraph/Models/Scheme.swift index 24b4cfe1..9546cffd 100644 --- a/Sources/XcodeGraph/Models/Scheme.swift +++ b/Sources/XcodeGraph/Models/Scheme.swift @@ -41,7 +41,7 @@ public struct Scheme: Equatable, Codable, Sendable { #if DEBUG extension Scheme { - public static func test( + static func test( name: String = "Test", shared: Bool = false, buildAction: BuildAction? = BuildAction.test(), diff --git a/Sources/XcodeGraph/Models/Settings.swift b/Sources/XcodeGraph/Models/Settings.swift index d8f182c5..a6fa9acc 100644 --- a/Sources/XcodeGraph/Models/Settings.swift +++ b/Sources/XcodeGraph/Models/Settings.swift @@ -160,7 +160,7 @@ extension [String: SettingValue] { #if DEBUG extension Configuration { - public static func test( + static func test( settings: SettingsDictionary = [:], xcconfig: AbsolutePath? = try! AbsolutePath(validating: "/Config.xcconfig") // swiftlint:disable:this force_try ) -> Configuration { @@ -169,7 +169,7 @@ extension [String: SettingValue] { } extension Settings { - public static func test( + static func test( base: SettingsDictionary, debug: Configuration, release: Configuration @@ -180,7 +180,7 @@ extension [String: SettingValue] { ) } - public static func test( + static func test( base: SettingsDictionary = [:], baseDebug: SettingsDictionary = [:], configurations: [BuildConfiguration: Configuration?] = [:] @@ -192,7 +192,7 @@ extension [String: SettingValue] { ) } - public static func test(defaultSettings: DefaultSettings) -> Settings { + static func test(defaultSettings: DefaultSettings) -> Settings { Settings( base: [:], configurations: [ diff --git a/Sources/XcodeGraph/Models/Target.swift b/Sources/XcodeGraph/Models/Target.swift index f7ac328d..82b6696b 100644 --- a/Sources/XcodeGraph/Models/Target.swift +++ b/Sources/XcodeGraph/Models/Target.swift @@ -393,7 +393,7 @@ extension Sequence { extension Target { /// Creates a Target with test data /// Note: Referenced paths may not exist - public static func test( + static func test( name: String = "Target", destinations: Destinations = [.iPhone, .iPad], product: Product = .app, @@ -453,7 +453,7 @@ extension Sequence { /// Creates a Target with test data /// Note: Referenced paths may not exist - public static func test( + static func test( name: String = "Target", platform: Platform, product: Product = .app, diff --git a/Sources/XcodeGraph/Models/TestAction.swift b/Sources/XcodeGraph/Models/TestAction.swift index 2d5e2878..adf1fb39 100644 --- a/Sources/XcodeGraph/Models/TestAction.swift +++ b/Sources/XcodeGraph/Models/TestAction.swift @@ -59,7 +59,7 @@ public struct TestAction: Equatable, Codable, Sendable { #if DEBUG extension TestAction { - public static func test( + static func test( targets: [TestableTarget] = [TestableTarget(target: TargetReference( // swiftlint:disable:next force_try projectPath: try! AbsolutePath(validating: "/Project"), diff --git a/Sources/XcodeGraph/Models/TestableTarget.swift b/Sources/XcodeGraph/Models/TestableTarget.swift index 7d800202..220785b9 100644 --- a/Sources/XcodeGraph/Models/TestableTarget.swift +++ b/Sources/XcodeGraph/Models/TestableTarget.swift @@ -31,7 +31,7 @@ public struct TestableTarget: Equatable, Hashable, Codable, Sendable { #if DEBUG extension TestableTarget { - public static func test( + static func test( // swiftlint:disable:next force_try target: TargetReference = TargetReference(projectPath: try! AbsolutePath(validating: "/Project"), name: "App"), skipped: Bool = false, diff --git a/Sources/XcodeGraph/Models/Workspace.swift b/Sources/XcodeGraph/Models/Workspace.swift index 4fc7f6fa..4bd4c7e8 100644 --- a/Sources/XcodeGraph/Models/Workspace.swift +++ b/Sources/XcodeGraph/Models/Workspace.swift @@ -150,7 +150,7 @@ extension Workspace { #if DEBUG extension Workspace { - public static func test( + static func test( path: AbsolutePath = try! AbsolutePath(validating: "/"), // swiftlint:disable:this force_try xcWorkspacePath: AbsolutePath = try! AbsolutePath(validating: "/"), // swiftlint:disable:this force_try name: String = "test", @@ -174,7 +174,7 @@ extension Workspace { } extension Workspace.GenerationOptions { - public static func test( + static func test( enableAutomaticXcodeSchemes: Bool? = false, autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes = .enabled( codeCoverageMode: .disabled, diff --git a/Sources/XcodeGraph/Models/XCFrameworkInfoPlist.swift b/Sources/XcodeGraph/Models/XCFrameworkInfoPlist.swift index 2d4fb129..5d0377b2 100644 --- a/Sources/XcodeGraph/Models/XCFrameworkInfoPlist.swift +++ b/Sources/XcodeGraph/Models/XCFrameworkInfoPlist.swift @@ -78,6 +78,10 @@ public struct XCFrameworkInfoPlist: Codable, Hashable, Equatable, Sendable { /// List of libraries that are part of the .xcframework. public let libraries: [Library] + + public init(libraries: [Library]) { + self.libraries = libraries + } } #if DEBUG diff --git a/Sources/XcodeProjMapper/Extensions/AbsolutePath+Extensions.swift b/Sources/XcodeProjMapper/Extensions/AbsolutePath+Extensions.swift new file mode 100644 index 00000000..44cb928b --- /dev/null +++ b/Sources/XcodeProjMapper/Extensions/AbsolutePath+Extensions.swift @@ -0,0 +1,47 @@ +import Foundation +import Path +import XcodeGraph + +/// Common file extensions encountered in Xcode projects and their associated artifacts. +enum FileExtension: String { + case xcodeproj + case xcworkspace + case framework + case xcframework + case staticLibrary = "a" + case dynamicLibrary = "dylib" + case textBasedDynamicLibrary = "tbd" + case coreData = "xcdatamodeld" + case playground +} + +extension AbsolutePath { + /// Maps a path by its extension to a `TargetDependency` if applicable. + /// + /// - Parameter condition: Optional platform condition. + /// - Returns: A `TargetDependency` if the extension matches known dependency types. + func mapByExtension(condition: PlatformCondition?) -> TargetDependency? { + let status: LinkingStatus = .required + let absPath = self + switch absPath.fileExtension { + case .framework: + return .framework(path: absPath, status: status, condition: condition) + case .xcframework: + return .xcframework(path: absPath, status: status, condition: condition) + case .dynamicLibrary, .textBasedDynamicLibrary, .staticLibrary: + return .library( + path: absPath, + publicHeaders: absPath.parentDirectory, + swiftModuleMap: nil, + condition: condition + ) + default: + return nil + } + } + + var fileExtension: FileExtension? { + guard let ext = self.extension?.lowercased() else { return nil } + return FileExtension(rawValue: ext) + } +} diff --git a/Sources/XcodeProjToGraph/Extensions/PBXProject+Extensions.swift b/Sources/XcodeProjMapper/Extensions/PBXProject+Extensions.swift similarity index 100% rename from Sources/XcodeProjToGraph/Extensions/PBXProject+Extensions.swift rename to Sources/XcodeProjMapper/Extensions/PBXProject+Extensions.swift diff --git a/Sources/XcodeProjToGraph/Extensions/Package+Extensions.swift b/Sources/XcodeProjMapper/Extensions/Package+Extensions.swift similarity index 90% rename from Sources/XcodeProjToGraph/Extensions/Package+Extensions.swift rename to Sources/XcodeProjMapper/Extensions/Package+Extensions.swift index 503be76f..e06e2354 100644 --- a/Sources/XcodeProjToGraph/Extensions/Package+Extensions.swift +++ b/Sources/XcodeProjMapper/Extensions/Package+Extensions.swift @@ -2,7 +2,7 @@ import XcodeGraph extension Package { /// Returns a URL or identifier for the package based on whether it's remote or local. - public var url: String { + var url: String { switch self { case let .remote(url, _): return url diff --git a/Sources/XcodeProjToGraph/Extensions/Platform+Extensions.swift b/Sources/XcodeProjMapper/Extensions/Platform+Extensions.swift similarity index 90% rename from Sources/XcodeProjToGraph/Extensions/Platform+Extensions.swift rename to Sources/XcodeProjMapper/Extensions/Platform+Extensions.swift index 1ab4d705..14ef58c3 100644 --- a/Sources/XcodeProjToGraph/Extensions/Platform+Extensions.swift +++ b/Sources/XcodeProjMapper/Extensions/Platform+Extensions.swift @@ -3,7 +3,7 @@ import XcodeGraph extension Platform { /// Initializes a `Platform` instance from an SDK root string (e.g., "iphoneos", "macosx"). /// Returns `nil` if no matching platform is found. - public init?(sdkroot: String) { + init?(sdkroot: String) { guard let platform = Platform.allCases.first(where: { $0.xcodeSdkRoot == sdkroot }) else { return nil } @@ -11,7 +11,7 @@ extension Platform { } /// Returns a set of `Destination` values supported by this platform. - public var destinations: Destinations { + var destinations: Destinations { switch self { case .iOS: return [.iPad, .iPhone, .macCatalyst, .macWithiPadDesign, .appleVisionWithiPadDesign] diff --git a/Sources/XcodeProjToGraph/Extensions/PlatformFilter+Extensions.swift b/Sources/XcodeProjMapper/Extensions/PlatformFilter+Extensions.swift similarity index 100% rename from Sources/XcodeProjToGraph/Extensions/PlatformFilter+Extensions.swift rename to Sources/XcodeProjMapper/Extensions/PlatformFilter+Extensions.swift diff --git a/Sources/XcodeProjToGraph/Extensions/TargetDependency+Extensions.swift b/Sources/XcodeProjMapper/Extensions/TargetDependency+Extensions.swift similarity index 92% rename from Sources/XcodeProjToGraph/Extensions/TargetDependency+Extensions.swift rename to Sources/XcodeProjMapper/Extensions/TargetDependency+Extensions.swift index a6d0f65a..c92c1fce 100644 --- a/Sources/XcodeProjToGraph/Extensions/TargetDependency+Extensions.swift +++ b/Sources/XcodeProjMapper/Extensions/TargetDependency+Extensions.swift @@ -1,9 +1,8 @@ -// TargetDependency+Extensions import XcodeGraph extension TargetDependency { /// Extracts the name of the dependency for relevant cases, such as target, project, SDK, package, and libraries. - public var name: String { + var name: String { switch self { case let .target(name, _, _): return name diff --git a/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift b/Sources/XcodeProjMapper/Extensions/XCWorkspaceDataFileRef+Extensions.swift similarity index 77% rename from Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift rename to Sources/XcodeProjMapper/Extensions/XCWorkspaceDataFileRef+Extensions.swift index 8d1ed26a..6bfadb5b 100644 --- a/Sources/XcodeProjToGraph/Extensions/XCWorkspaceDataFileRef+Extensions.swift +++ b/Sources/XcodeProjMapper/Extensions/XCWorkspaceDataFileRef+Extensions.swift @@ -6,17 +6,18 @@ extension XCWorkspaceDataFileRef { /// /// - Parameter srcPath: The workspace source root path. /// - Returns: The resolved `AbsolutePath` of this file reference. - func absolutePath(srcPath: AbsolutePath) throws -> AbsolutePath { + func path(srcPath: AbsolutePath) throws -> AbsolutePath { switch location { case let .absolute(path): - return try AbsolutePath.resolvePath(path) + return try AbsolutePath(validating: path) case let .container(subPath): let relativePath = try RelativePath(validating: subPath) return srcPath.appending(relativePath) case let .developer(subPath): - let relativePath = try RelativePath(validating: subPath) - let developerPath = try AbsolutePath.resolvePath("/Applications/Xcode.app/Contents/Developer") - return developerPath.appending(relativePath) + return try AbsolutePath( + validating: subPath, + relativeTo: try AbsolutePath(validating: "/Applications/Xcode.app/Contents/Developer") + ) case let .group(subPath): // Group paths are relative to the workspace file itself let relativePath = try RelativePath(validating: subPath) diff --git a/Sources/XcodeProjMapper/Mappers/Graph/GraphMapper.swift b/Sources/XcodeProjMapper/Mappers/Graph/GraphMapper.swift new file mode 100644 index 00000000..7e769024 --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Graph/GraphMapper.swift @@ -0,0 +1,143 @@ +import Foundation +import Path +import PathKit +import XcodeGraph +import XcodeProj + +/// A protocol that defines how to construct a `Graph` from either a workspace or a project. +protocol GraphMapping { + /// Constructs a `Graph` by analyzing the provided workspace or project. + /// + /// - Returns: A fully constructed `XcodeGraph.Graph`. + /// - Throws: If reading or mapping any of the projects or dependencies fails. + func map() throws -> XcodeGraph.Graph +} + +/// Specifies the type of graph to generate for analysis or tooling tasks. +/// +/// - `.workspace(WorkspaceProviding)`: Build a graph from a workspace, potentially containing multiple projects. +/// - `.project(AbsolutePath)`: Build a graph from a single `.xcodeproj` located at the given path. +enum GraphType { + case workspace(WorkspaceProviding) + case project(AbsolutePath) +} + +/// A mapper that constructs a `XcodeGraph.Graph` from a workspace or project. +/// +/// `GraphMapper` aggregates projects, packages, and targets into a unified graph model suitable for: +/// - Dependency analysis +/// - Code generation +/// - Integration with developer tools +/// +/// Example: +/// ```swift +/// let workspaceProvider: WorkspaceProviding = ... +/// let graphMapper = GraphMapper(graphType: .workspace(workspaceProvider)) +/// +/// let graph = try graphMapper.map() +/// // 'graph' now represents all projects, targets, and dependencies in the workspace. +/// ``` +struct GraphMapper: GraphMapping { + private let projectProviderClosure: (AbsolutePath) throws -> ProjectProviding + private let graphType: GraphType + + /// Initializes the mapper with a given `GraphType` and optionally a custom project provider closure. + /// + /// - Parameters: + /// - graphType: The type of graph to construct. + /// - projectProviderClosure: A closure for creating `ProjectProviding` instances from paths. + /// Defaults to creating a `ProjectProvider` directly from `XcodeProj`. + init( + graphType: GraphType, + projectProviderClosure: @escaping (AbsolutePath) throws -> ProjectProviding = { path in + let xcodeProj = try XcodeProj(pathString: path.pathString) + return ProjectProvider(xcodeProjPath: path, xcodeProj: xcodeProj) + } + ) { + self.graphType = graphType + self.projectProviderClosure = projectProviderClosure + } + + func map() throws -> XcodeGraph.Graph { + var projects: [AbsolutePath: Project] = [:] + var packages: [AbsolutePath: [String: Package]] = [:] + var dependencies: [GraphDependency: Set] = [:] + var dependencyConditions: [GraphEdge: PlatformCondition] = [:] + + let workspace: Workspace = try { + switch graphType { + case let .workspace(workspaceProvider): + return try XCWorkspaceMapper().map(workspaceProvider: workspaceProvider) + case let .project(absolutePath): + return Workspace( + path: absolutePath.parentDirectory, + xcWorkspacePath: absolutePath.parentDirectory, + name: "Workspace", + projects: [absolutePath] + ) + } + }() + + // Map each project in the workspace. Fail early if one fails. + let projectResults = try workspace.projects.map { path -> (AbsolutePath, Project) in + let provider = try projectProviderClosure(path) + let projectMapper = PBXProjectMapper() + let project = try projectMapper.map(projectProvider: provider) + return (path, project) + } + + for (path, project) in projectResults { + projects[path] = project + } + + // Build a map of all targets for target-based dependency resolution + let allTargetsMap = Dictionary( + projects.values.flatMap(\.targets), + uniquingKeysWith: { existing, _ in existing } + ) + + // Process dependencies for each project and target + for (path, project) in projects { + if !project.packages.isEmpty { + packages[path] = Dictionary(uniqueKeysWithValues: project.packages.map { ($0.url, $0) }) + } + + for (name, target) in project.targets { + let sourceDependency = GraphDependency.target(name: name, path: path.parentDirectory) + let edgesAndDependencies = try target.dependencies.compactMap { targetDep -> ( + GraphEdge, + PlatformCondition?, + GraphDependency + ) in + let graphDep = try targetDep.graphDependency( + sourceDirectory: path.parentDirectory, + allTargetsMap: allTargetsMap + ) + return (GraphEdge(from: sourceDependency, to: graphDep), targetDep.condition, graphDep) + } + + for (edge, condition, _) in edgesAndDependencies { + if let condition { + dependencyConditions[edge] = condition + } + } + + let targetDependencies = edgesAndDependencies.map(\.2) + if !targetDependencies.isEmpty { + dependencies[sourceDependency] = Set(targetDependencies) + } + } + } + + // Return the assembled graph + return Graph( + name: workspace.name, + path: workspace.path, + workspace: workspace, + projects: projects, + packages: packages, + dependencies: dependencies, + dependencyConditions: dependencyConditions + ) + } +} diff --git a/Sources/XcodeProjMapper/Mappers/Packages/XCPackageMapper.swift b/Sources/XcodeProjMapper/Mappers/Packages/XCPackageMapper.swift new file mode 100644 index 00000000..9e4dc050 --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Packages/XCPackageMapper.swift @@ -0,0 +1,83 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// Defines errors that may occur when mapping package references. +enum PackageMappingError: Error, LocalizedError, Equatable { + case missingRepositoryURL(packageName: String) + + var errorDescription: String? { + switch self { + case let .missingRepositoryURL(packageName): + return "The repository URL is missing for the package: \(packageName)." + } + } +} + +/// A protocol defining how to map remote and local Swift package references into `Package` models. +protocol PackageMapping { + /// Maps a remote Swift package reference to a `Package`. + /// + /// - Parameter package: The remote package reference. + /// - Returns: A `Package` representing the remote package. + /// - Throws: `PackageMappingError.missingRepositoryURL` if the package has no repository URL. + func map(package: XCRemoteSwiftPackageReference) throws -> Package + + /// Maps a local Swift package reference to a `Package`. + /// + /// - Parameters: + /// - package: The local Swift package reference. + /// - sourceDirectory: The project’s source directory used to resolve relative paths. + /// - Returns: A `Package` representing the local package. + /// - Throws: If the provided path is invalid and cannot be resolved. + func map(package: XCLocalSwiftPackageReference, sourceDirectory: AbsolutePath) throws -> Package +} + +/// A mapper that converts remote and local Swift package references into `Package` domain models. +/// +/// `PackageMapper` translates `XCRemoteSwiftPackageReference` and `XCLocalSwiftPackageReference` instances +/// into `Package` models by extracting repository URLs, version requirements, and resolving local paths. +struct XCPackageMapper: PackageMapping { + func map(package: XCRemoteSwiftPackageReference) throws -> Package { + guard let repositoryURL = package.repositoryURL else { + throw PackageMappingError.missingRepositoryURL(packageName: package.name ?? "Unknown Package") + } + + let requirement = mapRequirement(package: package) + return .remote(url: repositoryURL, requirement: requirement) + } + + func map(package: XCLocalSwiftPackageReference, sourceDirectory: AbsolutePath) throws -> Package { + let relativePath = try RelativePath(validating: package.relativePath) + let path = sourceDirectory.appending(relativePath) + return .local(path: path) + } + + /// Determines the version requirement for a remote Swift package. + /// + /// Converts the `XCRemoteSwiftPackageReference`'s version requirement into a `Package.Requirement`. + /// + /// - Parameter package: The remote package reference containing the version requirement. + /// - Returns: A `Package.Requirement` reflecting the specified versioning scheme. + func mapRequirement(package: XCRemoteSwiftPackageReference) -> Requirement { + guard let versionRequirement = package.versionRequirement else { + return .upToNextMajor("0.0.0") + } + + switch versionRequirement { + case let .upToNextMajorVersion(version): + return .upToNextMajor(version) + case let .upToNextMinorVersion(version): + return .upToNextMinor(version) + case let .exact(version): + return .exact(version) + case let .range(lowerBound, upperBound): + return .range(from: lowerBound, to: upperBound) + case let .branch(branch): + return .branch(branch) + case let .revision(revision): + return .revision(revision) + } + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseConstants.swift b/Sources/XcodeProjMapper/Mappers/Phases/BuildPhaseConstants.swift similarity index 95% rename from Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseConstants.swift rename to Sources/XcodeProjMapper/Mappers/Phases/BuildPhaseConstants.swift index d8468e4a..e51d16d0 100644 --- a/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseConstants.swift +++ b/Sources/XcodeProjMapper/Mappers/Phases/BuildPhaseConstants.swift @@ -15,7 +15,7 @@ enum BuildPhaseConstants { /// Attributes indicating header visibility within a build target. enum HeaderAttribute: String { - /// Indicates that a header is public and can be exposed outside the module. + /// Indicates that a header is and can be exposed outside the module. case `public` = "Public" /// Indicates that a header is private and not exposed outside the module. case `private` = "Private" diff --git a/Sources/XcodeProjMapper/Mappers/Phases/PBXCopyFilesBuildPhaseMapper.swift b/Sources/XcodeProjMapper/Mappers/Phases/PBXCopyFilesBuildPhaseMapper.swift new file mode 100644 index 00000000..f6d48c46 --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Phases/PBXCopyFilesBuildPhaseMapper.swift @@ -0,0 +1,55 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +protocol PBXCopyFilesBuildPhaseMapping { + func map(_ copyFilesPhases: [PBXCopyFilesBuildPhase], projectProvider: ProjectProviding) throws -> [CopyFilesAction] +} + +struct PBXCopyFilesBuildPhaseMapper: PBXCopyFilesBuildPhaseMapping { + func map(_ copyFilesPhases: [PBXCopyFilesBuildPhase], projectProvider: ProjectProviding) throws -> [CopyFilesAction] { + try copyFilesPhases.compactMap { try mapCopyFilesPhase($0, projectProvider: projectProvider) } + .sorted { $0.name < $1.name } + } + + private func mapCopyFilesPhase( + _ phase: PBXCopyFilesBuildPhase, + projectProvider: ProjectProviding + ) throws -> CopyFilesAction? { + let files = try phase.files?.compactMap { buildFile -> CopyFileElement? in + guard let fileRef = buildFile.file, + let pathString = try fileRef.fullPath(sourceRoot: projectProvider.sourcePathString) + else { return nil } + + let absolutePath = try AbsolutePath(validating: pathString) + let attributes: [String]? = buildFile.settings?.stringArray(for: .attributes) + let codeSignOnCopy = attributes?.contains(BuildFileAttribute.codeSignOnCopy.rawValue) ?? false + + return .file(path: absolutePath, condition: nil, codeSignOnCopy: codeSignOnCopy) + } ?? [] + + return CopyFilesAction( + name: phase.name ?? BuildPhaseConstants.copyFilesDefault, + destination: mapDstSubfolderSpec(phase.dstSubfolderSpec), + subpath: phase.dstPath.flatMap { $0.isEmpty ? nil : $0 }, + files: files.sorted { $0.path < $1.path } + ) + } + + private func mapDstSubfolderSpec(_ subfolderSpec: PBXCopyFilesBuildPhase.SubFolder?) -> CopyFilesAction.Destination { + switch subfolderSpec { + case .absolutePath: return .absolutePath + case .productsDirectory: return .productsDirectory + case .wrapper: return .wrapper + case .executables: return .executables + case .resources: return .resources + case .javaResources: return .javaResources + case .frameworks: return .frameworks + case .sharedFrameworks: return .sharedFrameworks + case .sharedSupport: return .sharedSupport + case .plugins: return .plugins + default: return .productsDirectory + } + } +} diff --git a/Sources/XcodeProjMapper/Mappers/Phases/PBXCoreDataModelsBuildPhaseMapper.swift b/Sources/XcodeProjMapper/Mappers/Phases/PBXCoreDataModelsBuildPhaseMapper.swift new file mode 100644 index 00000000..1d9b9d99 --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Phases/PBXCoreDataModelsBuildPhaseMapper.swift @@ -0,0 +1,36 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +protocol PBXCoreDataModelsBuildPhaseMapping { + func map(_ resourceFiles: [PBXBuildFile], projectProvider: ProjectProviding) throws -> [CoreDataModel] +} + +struct PBXCoreDataModelsBuildPhaseMapper: PBXCoreDataModelsBuildPhaseMapping { + func map(_ resourceFiles: [PBXBuildFile], projectProvider: ProjectProviding) throws -> [CoreDataModel] { + try resourceFiles.compactMap { try mapCoreDataModel($0, projectProvider: projectProvider) } + } + + private func mapCoreDataModel(_ buildFile: PBXBuildFile, projectProvider: ProjectProviding) throws -> CoreDataModel? { + guard let versionGroup = buildFile.file as? XCVersionGroup, + versionGroup.path?.hasSuffix(FileExtension.coreData.rawValue) == true, + let modelPathString = try versionGroup.fullPath(sourceRoot: projectProvider.sourcePathString) + else { + return nil + } + + let absModelPath = try AbsolutePath(validating: modelPathString) + let versions = versionGroup.children.compactMap(\.path) + let validatedVersions = try versions.map { + try AbsolutePath(validating: $0, relativeTo: absModelPath) + } + let currentVersion = versionGroup.currentVersion?.path ?? validatedVersions.first?.pathString ?? "" + + return CoreDataModel( + path: absModelPath, + versions: validatedVersions, + currentVersion: currentVersion + ) + } +} diff --git a/Sources/XcodeProjMapper/Mappers/Phases/PBXFrameworksBuildPhaseMapper.swift b/Sources/XcodeProjMapper/Mappers/Phases/PBXFrameworksBuildPhaseMapper.swift new file mode 100644 index 00000000..8ce647aa --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Phases/PBXFrameworksBuildPhaseMapper.swift @@ -0,0 +1,30 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +protocol PBXFrameworksBuildPhaseMapping { + func map(_ frameworksBuildPhase: PBXFrameworksBuildPhase, projectProvider: ProjectProviding) throws -> [TargetDependency] +} + +struct PBXFrameworksBuildPhaseMapper: PBXFrameworksBuildPhaseMapping { + func map(_ frameworksBuildPhase: PBXFrameworksBuildPhase, projectProvider: ProjectProviding) throws -> [TargetDependency] { + guard let files = frameworksBuildPhase.files, !files.isEmpty else { + return [] + } + + return try files.compactMap { try mapFrameworkDependency($0, projectProvider: projectProvider) } + } + + private func mapFrameworkDependency( + _ buildFile: PBXBuildFile, + projectProvider: ProjectProviding + ) throws -> TargetDependency? { + guard let fileRef = buildFile.file, + let filePath = try fileRef.fullPath(sourceRoot: projectProvider.sourceDirectory.pathString) + else { return nil } + + let absPath = try AbsolutePath(validating: filePath) + return absPath.mapByExtension(condition: nil) + } +} diff --git a/Sources/XcodeProjMapper/Mappers/Phases/PBXHeadersBuildPhaseMapper.swift b/Sources/XcodeProjMapper/Mappers/Phases/PBXHeadersBuildPhaseMapper.swift new file mode 100644 index 00000000..afddaed6 --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Phases/PBXHeadersBuildPhaseMapper.swift @@ -0,0 +1,63 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +protocol PBXHeadersBuildPhaseMapping { + func map(_ headersBuildPhase: PBXHeadersBuildPhase, projectProvider: ProjectProviding) throws -> Headers? +} + +struct PBXHeadersBuildPhaseMapper: PBXHeadersBuildPhaseMapping { + func map(_ headersBuildPhase: PBXHeadersBuildPhase, projectProvider: ProjectProviding) throws -> Headers? { + guard let files = headersBuildPhase.files, !files.isEmpty else { + return nil + } + + var publicHeaders = [AbsolutePath]() + var privateHeaders = [AbsolutePath]() + var projectHeaders = [AbsolutePath]() + + for buildFile in files { + if let headerInfo = try mapHeaderFile(buildFile, projectProvider: projectProvider) { + switch headerInfo.visibility { + case .public: publicHeaders.append(headerInfo.path) + case .private: privateHeaders.append(headerInfo.path) + case .project: projectHeaders.append(headerInfo.path) + } + } + } + + return Headers(public: publicHeaders, private: privateHeaders, project: projectHeaders) + } + + private func mapHeaderFile(_ buildFile: PBXBuildFile, projectProvider: ProjectProviding) throws -> HeaderInfo? { + guard let pbxElement = buildFile.file, + let pathString = try pbxElement.fullPath(sourceRoot: projectProvider.sourcePathString) + else { return nil } + + let attributes = buildFile.settings?.stringArray(for: .attributes) + let absolutePath = try AbsolutePath(validating: pathString) + + let visibility: HeaderInfo.HeaderVisibility + if attributes?.contains(HeaderAttribute.public.rawValue) == true { + visibility = .public + } else if attributes?.contains(HeaderAttribute.private.rawValue) == true { + visibility = .private + } else { + visibility = .project + } + + return HeaderInfo(path: absolutePath, visibility: visibility) + } +} + +private struct HeaderInfo { + let path: AbsolutePath + let visibility: HeaderVisibility + + enum HeaderVisibility { + case `public` + case `private` + case project + } +} diff --git a/Sources/XcodeProjMapper/Mappers/Phases/PBXResourcesBuildPhaseMapper.swift b/Sources/XcodeProjMapper/Mappers/Phases/PBXResourcesBuildPhaseMapper.swift new file mode 100644 index 00000000..47b7ecbf --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Phases/PBXResourcesBuildPhaseMapper.swift @@ -0,0 +1,57 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +protocol PBXResourcesBuildPhaseMapping { + func map(_ resourcesBuildPhase: PBXResourcesBuildPhase, projectProvider: ProjectProviding) throws -> [ResourceFileElement] +} + +struct PBXResourcesBuildPhaseMapper: PBXResourcesBuildPhaseMapping { + func map(_ resourcesBuildPhase: PBXResourcesBuildPhase, projectProvider: ProjectProviding) throws -> [ResourceFileElement] { + guard let files = resourcesBuildPhase.files, !files.isEmpty else { + return [] + } + + var resources = [ResourceFileElement]() + for buildFile in files { + resources.append(contentsOf: try mapResourceElement(buildFile, projectProvider: projectProvider)) + } + return resources.sorted { $0.path < $1.path } + } + + private func mapResourceElement( + _ buildFile: PBXBuildFile, + projectProvider: ProjectProviding + ) throws -> [ResourceFileElement] { + guard let file = buildFile.file else { return [] } + if let variantGroup = file as? PBXVariantGroup { + return try mapVariantGroup(variantGroup, projectProvider: projectProvider) + } else { + return try mapResourceElement(file, projectProvider: projectProvider) + } + } + + private func mapResourceElement( + _ fileElement: PBXFileElement, + projectProvider: ProjectProviding + ) throws -> [ResourceFileElement] { + if let pathString = try fileElement.fullPath(sourceRoot: projectProvider.sourcePathString) { + let absPath = try AbsolutePath(validating: pathString) + return [.file(path: absPath)] + } + return [] + } + + private func mapVariantGroup( + _ variantGroup: PBXVariantGroup, + projectProvider: ProjectProviding + ) throws -> [ResourceFileElement] { + var elements = [ResourceFileElement]() + for child in variantGroup.children { + let childFiles = try mapResourceElement(child, projectProvider: projectProvider) + elements.append(contentsOf: childFiles) + } + return elements + } +} diff --git a/Sources/XcodeProjMapper/Mappers/Phases/PBXScriptsBuildPhaseMapper.swift b/Sources/XcodeProjMapper/Mappers/Phases/PBXScriptsBuildPhaseMapper.swift new file mode 100644 index 00000000..4ff067f7 --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Phases/PBXScriptsBuildPhaseMapper.swift @@ -0,0 +1,100 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +protocol PBXScriptsBuildPhaseMapping { + /// Maps the given script phases into `TargetScript` models. + /// + /// - Parameters: + /// - scriptPhases: The array of `PBXShellScriptBuildPhase` to map. + /// - buildPhases: The complete array of the target’s `PBXBuildPhase`s, used to determine script order. + /// - projectProvider: Provides access to the project's directory structure. + /// - Returns: An array of `TargetScript` models representing each shell script build phase. + /// - Throws: If script file references or paths cannot be resolved. + func map( + _ scriptPhases: [PBXShellScriptBuildPhase], + buildPhases: [PBXBuildPhase], + projectProvider: ProjectProviding + ) throws -> [TargetScript] + + /// Maps raw script build phases into `RawScriptBuildPhase` models. + /// + /// - Parameter scriptPhases: The array of `PBXShellScriptBuildPhase` to map. + /// - Returns: An array of `RawScriptBuildPhase` instances. + func mapRawScriptBuildPhases(_ scriptPhases: [PBXShellScriptBuildPhase]) -> [RawScriptBuildPhase] +} + +struct PBXScriptsBuildPhaseMapper: PBXScriptsBuildPhaseMapping { + func map( + _ scriptPhases: [PBXShellScriptBuildPhase], + buildPhases: [PBXBuildPhase], + projectProvider: ProjectProviding + ) throws -> [TargetScript] { + try scriptPhases.compactMap { + try mapScriptPhase($0, buildPhases: buildPhases, projectProvider: projectProvider) + } + } + + func mapRawScriptBuildPhases(_ scriptPhases: [PBXShellScriptBuildPhase]) -> [RawScriptBuildPhase] { + scriptPhases.map { mapShellScriptBuildPhase($0) } + } + + // MARK: - Private Helpers + + private func mapScriptPhase( + _ scriptPhase: PBXShellScriptBuildPhase, + buildPhases: [PBXBuildPhase], + projectProvider _: ProjectProviding + ) throws -> TargetScript? { + guard let shellScript = scriptPhase.shellScript else { return nil } + + let inputFileListPaths = try scriptPhase.inputFileListPaths?.compactMap { try AbsolutePath(validating: $0) } ?? [] + + let outputFileListPaths = try scriptPhase.outputFileListPaths?.compactMap { try AbsolutePath(validating: $0) } ?? [] + + let dependencyFile = try scriptPhase.dependencyFile.map { try AbsolutePath(validating: $0) } + return TargetScript( + name: scriptPhase.name ?? BuildPhaseConstants.defaultScriptName, + order: determineScriptOrder(buildPhases: buildPhases, scriptPhase: scriptPhase), + script: .embedded(shellScript), + inputPaths: scriptPhase.inputPaths, + inputFileListPaths: inputFileListPaths, + outputPaths: scriptPhase.outputPaths, + outputFileListPaths: outputFileListPaths, + showEnvVarsInLog: scriptPhase.showEnvVarsInLog, + basedOnDependencyAnalysis: scriptPhase.alwaysOutOfDate ? false : nil, + runForInstallBuildsOnly: scriptPhase.runOnlyForDeploymentPostprocessing, + shellPath: scriptPhase.shellPath ?? BuildPhaseConstants.defaultShellPath, + dependencyFile: dependencyFile + ) + } + + private func mapShellScriptBuildPhase(_ buildPhase: PBXShellScriptBuildPhase) -> RawScriptBuildPhase { + let name = buildPhase.name() ?? BuildPhaseConstants.unnamedScriptPhase + let shellPath = buildPhase.shellPath ?? BuildPhaseConstants.defaultShellPath + let script = buildPhase.shellScript ?? "" + let showEnvVarsInLog = buildPhase.showEnvVarsInLog + + return RawScriptBuildPhase( + name: name, + script: script, + showEnvVarsInLog: showEnvVarsInLog, + hashable: false, + shellPath: shellPath + ) + } + + private func determineScriptOrder( + buildPhases: [PBXBuildPhase], + scriptPhase: PBXShellScriptBuildPhase + ) -> TargetScript.Order { + guard let scriptPhaseIndex = buildPhases.firstIndex(of: scriptPhase) else { return .pre } + + if let sourcesPhaseIndex = buildPhases.firstIndex(where: { $0.buildPhase == .sources }) { + return scriptPhaseIndex > sourcesPhaseIndex ? .post : .pre + } + + return scriptPhaseIndex == 0 ? .pre : .post + } +} diff --git a/Sources/XcodeProjMapper/Mappers/Phases/PBXSourcesBuildPhaseMapper.swift b/Sources/XcodeProjMapper/Mappers/Phases/PBXSourcesBuildPhaseMapper.swift new file mode 100644 index 00000000..4f329cef --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Phases/PBXSourcesBuildPhaseMapper.swift @@ -0,0 +1,52 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +protocol PBXSourcesBuildPhaseMapping { + func map(_ sourcesBuildPhase: PBXSourcesBuildPhase, projectProvider: ProjectProviding) throws -> [SourceFile] +} + +struct PBXSourcesBuildPhaseMapper: PBXSourcesBuildPhaseMapping { + func map(_ sourcesBuildPhase: PBXSourcesBuildPhase, projectProvider: ProjectProviding) throws -> [SourceFile] { + guard let files = sourcesBuildPhase.files, !files.isEmpty else { + return [] + } + + return try files.compactMap { buildFile in + try mapSourceFile(buildFile, projectProvider: projectProvider) + }.sorted { $0.path < $1.path } + } + + private func mapSourceFile(_ buildFile: PBXBuildFile, projectProvider: ProjectProviding) throws -> SourceFile? { + guard let fileRef = buildFile.file, + let pathString = try fileRef.fullPath(sourceRoot: projectProvider.sourcePathString) + else { return nil } + + let absPath = try AbsolutePath(validating: pathString) + let settings = buildFile.settings ?? [:] + let compilerFlags: String? = settings.string(for: .compilerFlags) + let attributes: [String]? = settings.stringArray(for: .attributes) + + return SourceFile( + path: absPath, + compilerFlags: compilerFlags, + codeGen: mapCodeGenAttribute(attributes) + ) + } + + private func mapCodeGenAttribute(_ attributes: [String]?) -> FileCodeGen? { + guard let attributes else { return nil } + + if attributes.contains(FileCodeGen.public.rawValue) { + return .public + } else if attributes.contains(FileCodeGen.private.rawValue) { + return .private + } else if attributes.contains(FileCodeGen.project.rawValue) { + return .project + } else if attributes.contains(FileCodeGen.disabled.rawValue) { + return .disabled + } + return nil + } +} diff --git a/Sources/XcodeProjMapper/Mappers/Project/PBXProjectMapper.swift b/Sources/XcodeProjMapper/Mappers/Project/PBXProjectMapper.swift new file mode 100644 index 00000000..f836bbd8 --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Project/PBXProjectMapper.swift @@ -0,0 +1,130 @@ +import Foundation +import Path +import PathKit +import XcodeGraph +import XcodeProj + +/// A mapper that transforms a `.xcodeproj` (provided via `ProjectProviding`) into a `Project` domain model. +/// +/// This process involves: +/// - Mapping project-level settings. +/// - Converting PBXTargets into `Target` models. +/// - Resolving both remote and local Swift packages. +/// - Identifying and integrating user and shared schemes. +/// - Providing resource synthesizers for code generation. +struct PBXProjectMapper { + /// Maps the given Xcode project into a `Project` model. + /// + /// - Parameter projectProvider: Supplies access to `.xcodeproj` data and related directories. + /// - Returns: A fully constructed `Project` model. + /// - Throws: If reading or transforming project data fails. + func map(projectProvider: ProjectProviding) throws -> Project { + let settingsMapper = XCConfigurationMapper() + let pbxProject = try projectProvider.pbxProject() + + let settings = try settingsMapper.map( + projectProvider: projectProvider, + configurationList: pbxProject.buildConfigurationList + ) + + let targetMapper = PBXTargetMapper() + let targets = try pbxProject.targets.compactMap { + try targetMapper.map(pbxTarget: $0, projectProvider: projectProvider) + }.sorted() + + let packageMapper = XCPackageMapper() + let remotePackages = try pbxProject.remotePackages.compactMap { + try packageMapper.map(package: $0) + } + let localPackages = try pbxProject.localPackages.compactMap { + try packageMapper.map(package: $0, sourceDirectory: projectProvider.sourceDirectory) + } + + let filesGroup = ProjectGroup.group(name: pbxProject.mainGroup?.name ?? "Project") + + let schemeMapper = XCSchemeMapper() + let graphType: GraphType = .project(projectProvider.sourceDirectory) + let userSchemes = try projectProvider.xcodeProj.userData.flatMap(\.schemes).map { + try schemeMapper.map($0, shared: false, graphType: graphType) + } + let sharedSchemes = try projectProvider.xcodeProj.sharedData?.schemes.map { + try schemeMapper.map($0, shared: true, graphType: graphType) + } ?? [] + let schemes = userSchemes + sharedSchemes + let lastUpgradeCheck = pbxProject.attribute(for: .lastUpgradeCheck).flatMap { Version(string: $0) } + let defaultKnownRegions = pbxProject.knownRegions.isEmpty ? nil : pbxProject.knownRegions + + return Project( + path: projectProvider.sourceDirectory, + sourceRootPath: projectProvider.sourceDirectory, + xcodeProjPath: projectProvider.sourceDirectory, + name: pbxProject.name, + organizationName: pbxProject.attribute(for: .organization), + classPrefix: pbxProject.attribute(for: .classPrefix), + defaultKnownRegions: defaultKnownRegions, + developmentRegion: pbxProject.developmentRegion, + options: .init( + automaticSchemesOptions: .disabled, + disableBundleAccessors: false, + disableShowEnvironmentVarsInScriptPhases: false, + disableSynthesizedResourceAccessors: false, + textSettings: .init( + usesTabs: nil, + indentWidth: nil, + tabWidth: nil, + wrapsLines: nil + ) + ), + settings: settings, + filesGroup: filesGroup, + targets: targets, + packages: remotePackages + localPackages, + schemes: schemes, + ideTemplateMacros: nil, + additionalFiles: [], + resourceSynthesizers: mapResourceSynthesizers(), + lastUpgradeCheck: lastUpgradeCheck, + type: .local + ) + } + + /// Returns a set of default resource synthesizers for common resource types. + private func mapResourceSynthesizers() -> [ResourceSynthesizer] { + ResourceSynthesizer.Parser.allCases.map { parser in + let (exts, template) = parser.resourceTypes() + return ResourceSynthesizer( + parser: parser, + parserOptions: [:], + extensions: Set(exts), + template: .defaultTemplate(template) + ) + } + } +} + +extension ResourceSynthesizer.Parser { + fileprivate func resourceTypes() -> (exts: [String], template: String) { + switch self { + case .strings: + return (["strings", "stringsdict"], "Strings") + case .stringsCatalog: + return (["strings", "stringsdict"], "Strings") + case .assets: + return (["xcassets"], "Assets") + case .plists: + return (["plist"], "Plists") + case .fonts: + return (["ttf", "otf", "ttc"], "Fonts") + case .coreData: + return (["xcdatamodeld"], "CoreData") + case .interfaceBuilder: + return (["xib", "storyboard"], "InterfaceBuilder") + case .json: + return (["json"], "JSON") + case .yaml: + return (["yaml", "yml"], "YAML") + case .files: + return (["txt", "md"], "Files") + } + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Project/ProjectAttribute.swift b/Sources/XcodeProjMapper/Mappers/Project/ProjectAttribute.swift similarity index 100% rename from Sources/XcodeProjToGraph/Mappers/Project/ProjectAttribute.swift rename to Sources/XcodeProjMapper/Mappers/Project/ProjectAttribute.swift diff --git a/Sources/XcodeProjMapper/Mappers/Project/ProjectProvider.swift b/Sources/XcodeProjMapper/Mappers/Project/ProjectProvider.swift new file mode 100644 index 00000000..de9f1f59 --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Project/ProjectProvider.swift @@ -0,0 +1,81 @@ +import Foundation +import Path +import PathKit +import XcodeGraph +import XcodeProj + +/// Errors that may occur while providing project information. +enum ProjectProvidingError: LocalizedError, Equatable { + case noProjectsFound(path: String) + + var errorDescription: String? { + switch self { + case let .noProjectsFound(path): + return "No `PBXProject` was found in the `.xcodeproj` at: \(path)." + } + } +} + +/// A protocol that defines how to provide access to an Xcode project and its underlying components. +/// +/// Conforming types must supply: +/// - A parsed `XcodeProj` instance +/// - The `.xcodeproj` file path +/// - The project’s source directory +/// - A method to retrieve the main `PBXProject` +protocol ProjectProviding { + /// The absolute path to the directory containing the Xcode project. + var sourceDirectory: AbsolutePath { get } + + /// The absolute path to the `.xcodeproj` file. + var xcodeProjPath: AbsolutePath { get } + + /// The parsed `XcodeProj` instance representing the Xcode project. + var xcodeProj: XcodeProj { get } + + /// Returns the main `PBXProject` object from the `.xcodeproj`. + /// + /// - Throws: `ProjectProvidingError.noProjectsFound` if no projects are found. + /// - Returns: A `PBXProject` representing the primary project definition. + func pbxProject() throws -> PBXProject +} + +extension ProjectProviding { + var sourcePathString: String { + sourceDirectory.pathString + } +} + +/// A concrete provider supplying information about a particular Xcode project. +/// +/// `ProjectProvider` holds a `.xcodeproj` file path and its `XcodeProj` representation, enabling integration +/// with mappers or tooling that require direct access to the project's structure. +struct ProjectProvider: ProjectProviding { + let xcodeProj: XcodeProj + let xcodeProjPath: AbsolutePath + + /// Initializes a new `ProjectProvider` with the given `.xcodeproj` path and `XcodeProj` instance. + /// + /// - Parameters: + /// - xcodeProjPath: The absolute path to the `.xcodeproj` file. + /// - xcodeProj: The parsed `XcodeProj` instance. + init(xcodeProjPath: AbsolutePath, xcodeProj: XcodeProj) { + self.xcodeProjPath = xcodeProjPath + self.xcodeProj = xcodeProj + } + + /// The source directory is assumed to be the parent of the `.xcodeproj` directory. + /// + /// This implementation infers the source directory from the `xcodeProjPath`, ensuring a consistent + /// project structure. + var sourceDirectory: AbsolutePath { + xcodeProjPath.parentDirectory + } + + func pbxProject() throws -> PBXProject { + guard let pbxProject = xcodeProj.pbxproj.projects.first else { + throw ProjectProvidingError.noProjectsFound(path: xcodeProjPath.pathString) + } + return pbxProject + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeDiagnosticsOptions+XCScheme.swift b/Sources/XcodeProjMapper/Mappers/Schemes/SchemeDiagnosticsOptions+XCScheme.swift similarity index 100% rename from Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeDiagnosticsOptions+XCScheme.swift rename to Sources/XcodeProjMapper/Mappers/Schemes/SchemeDiagnosticsOptions+XCScheme.swift diff --git a/Sources/XcodeProjMapper/Mappers/Schemes/XCSchemeMapper.swift b/Sources/XcodeProjMapper/Mappers/Schemes/XCSchemeMapper.swift new file mode 100644 index 00000000..6df6544c --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Schemes/XCSchemeMapper.swift @@ -0,0 +1,195 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// A protocol defining how to map a single `XCScheme` object (and its actions) into a domain `Scheme` model. +/// +/// Conforming types translate a raw `XCScheme` instance, including its build, test, run, archive, profile, +/// and analyze actions, into a `Scheme` model ready for analysis, code generation, or tooling integration. +protocol SchemeMapping { + /// Maps a single `XCScheme` into a `Scheme` model. + /// + /// - Parameters: + /// - xcscheme: The `XCScheme` to map. + /// - shared: Indicates whether the scheme is shared. + /// - Returns: A `Scheme` model corresponding to the given `XCScheme`. + /// - Throws: If any of the scheme's actions (build, test, run, etc.) cannot be resolved. + func map( + _ xcscheme: XCScheme, + shared: Bool, + graphType: GraphType + ) throws -> Scheme +} + +/// A mapper responsible for converting an `XCScheme` object into a `Scheme` model. +/// +/// `SchemeMapper` resolves references to targets, variables, and all scheme actions. +/// The resulting `Scheme` models enable analysis, code generation, or integration with tooling. +struct XCSchemeMapper: SchemeMapping { + func map( + _ xcscheme: XCScheme, + shared: Bool, + graphType: GraphType + ) throws -> Scheme { + Scheme( + name: xcscheme.name, + shared: shared, + hidden: false, + buildAction: try mapBuildAction(action: xcscheme.buildAction, graphType: graphType), + testAction: try mapTestAction(action: xcscheme.testAction, graphType: graphType), + runAction: try mapRunAction(action: xcscheme.launchAction, graphType: graphType), + archiveAction: try mapArchiveAction(action: xcscheme.archiveAction), + profileAction: try mapProfileAction(action: xcscheme.profileAction, graphType: graphType), + analyzeAction: try mapAnalyzeAction(action: xcscheme.analyzeAction) + ) + } + + // MARK: - Internal/Private Mappings + + func mapBuildAction(action: XCScheme.BuildAction?, graphType: GraphType) throws -> BuildAction? { + guard let action else { return nil } + + let targets = try action.buildActionEntries.compactMap { entry in + try mapTargetReference(buildableReference: entry.buildableReference, graphType: graphType) + } + + return BuildAction( + targets: targets, + preActions: [], + postActions: [], + runPostActionsOnFailure: action.runPostActionsOnFailure ?? false, + findImplicitDependencies: action.buildImplicitDependencies + ) + } + + func mapTestAction(action: XCScheme.TestAction?, graphType: GraphType) throws -> TestAction? { + guard let action else { return nil } + + let testTargets = try action.testables.compactMap { testable in + let targetReference = try mapTargetReference( + buildableReference: testable.buildableReference, + graphType: graphType + ) + return TestableTarget(target: targetReference, skipped: testable.skipped) + } + + let arguments = mapArguments( + environmentVariables: action.environmentVariables, + commandlineArguments: action.commandlineArguments + ) + let diagnosticsOptions = SchemeDiagnosticsOptions(action: action) + + return TestAction( + targets: testTargets, + arguments: arguments, + configurationName: action.buildConfiguration, + attachDebugger: true, + coverage: action.codeCoverageEnabled, + codeCoverageTargets: [], + expandVariableFromTarget: nil, + preActions: [], + postActions: [], + diagnosticsOptions: diagnosticsOptions, + language: action.language, + region: action.region + ) + } + + func mapRunAction(action: XCScheme.LaunchAction?, graphType: GraphType) throws -> RunAction? { + guard let action else { return nil } + + let executable: TargetReference? = try { + if let buildableRef = action.runnable?.buildableReference { + return try mapTargetReference(buildableReference: buildableRef, graphType: graphType) + } + return nil + }() + + let arguments = mapArguments( + environmentVariables: action.environmentVariables, + commandlineArguments: action.commandlineArguments + ) + let diagnosticsOptions = SchemeDiagnosticsOptions(action: action) + let attachDebugger = action.selectedDebuggerIdentifier.isEmpty + + return RunAction( + configurationName: action.buildConfiguration, + attachDebugger: attachDebugger, + customLLDBInitFile: nil, + preActions: [], + postActions: [], + executable: executable, + filePath: nil, + arguments: arguments, + options: RunActionOptions(), + diagnosticsOptions: diagnosticsOptions + ) + } + + func mapArchiveAction(action: XCScheme.ArchiveAction?) throws -> ArchiveAction? { + guard let action else { return nil } + return ArchiveAction( + configurationName: action.buildConfiguration, + revealArchiveInOrganizer: action.revealArchiveInOrganizer + ) + } + + func mapProfileAction(action: XCScheme.ProfileAction?, graphType: GraphType) throws -> ProfileAction? { + guard let action else { return nil } + + let executable: TargetReference? = try { + if let buildableRef = action.buildableProductRunnable?.buildableReference { + return try mapTargetReference(buildableReference: buildableRef, graphType: graphType) + } + return nil + }() + + return ProfileAction( + configurationName: action.buildConfiguration, + executable: executable + ) + } + + func mapAnalyzeAction(action: XCScheme.AnalyzeAction?) throws -> AnalyzeAction? { + guard let action else { return nil } + return AnalyzeAction(configurationName: action.buildConfiguration) + } + + // MARK: - Private Helpers + + private func mapTargetReference( + buildableReference: XCScheme.BuildableReference, + graphType: GraphType + ) throws -> TargetReference { + let targetName = buildableReference.blueprintName + let container = buildableReference.referencedContainer + + let projectPath: AbsolutePath + switch graphType { + case let .workspace(workspaceProvider): + let containerRelativePath = container.replacingOccurrences(of: "container:", with: "") + let relativePath = try RelativePath(validating: containerRelativePath) + projectPath = workspaceProvider.workspaceDirectory.appending(relativePath) + case let .project(path): + projectPath = path + } + + return TargetReference(projectPath: projectPath, name: targetName) + } + + private func mapArguments( + environmentVariables: [XCScheme.EnvironmentVariable]?, + commandlineArguments: XCScheme.CommandLineArguments? + ) -> Arguments { + let envVariables = environmentVariables?.reduce(into: [String: EnvironmentVariable]()) { dict, variable in + dict[variable.variable] = EnvironmentVariable(value: variable.value, isEnabled: variable.enabled) + } ?? [:] + + let launchArguments = commandlineArguments?.arguments.map { + LaunchArgument(name: $0.name, isEnabled: $0.enabled) + } ?? [] + + return Arguments(environmentVariables: envVariables, launchArguments: launchArguments) + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/BuildSettings.swift b/Sources/XcodeProjMapper/Mappers/Settings/BuildSettings.swift similarity index 100% rename from Sources/XcodeProjToGraph/Mappers/Settings/BuildSettings.swift rename to Sources/XcodeProjMapper/Mappers/Settings/BuildSettings.swift diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/XCConfigurationList+Helpers.swift b/Sources/XcodeProjMapper/Mappers/Settings/XCConfigurationList+Helpers.swift similarity index 100% rename from Sources/XcodeProjToGraph/Mappers/Settings/XCConfigurationList+Helpers.swift rename to Sources/XcodeProjMapper/Mappers/Settings/XCConfigurationList+Helpers.swift diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift b/Sources/XcodeProjMapper/Mappers/Settings/XCConfigurationMapper.swift similarity index 86% rename from Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift rename to Sources/XcodeProjMapper/Mappers/Settings/XCConfigurationMapper.swift index 20084e95..08c4ba05 100644 --- a/Sources/XcodeProjToGraph/Mappers/Settings/SettingsMapper.swift +++ b/Sources/XcodeProjMapper/Mappers/Settings/XCConfigurationMapper.swift @@ -21,7 +21,7 @@ protocol SettingsMapping: Sendable { func map( projectProvider: ProjectProviding, configurationList: XCConfigurationList? - ) async throws -> Settings + ) throws -> Settings } /// A mapper responsible for converting an Xcode project's configuration list into a `Settings` domain model. @@ -34,16 +34,16 @@ protocol SettingsMapping: Sendable { /// Typical usage: /// ```swift /// let mapper = SettingsMapper() -/// let settings = try await mapper.map(projectProvider: provider, configurationList: configurationList) +/// let settings = try mapper.map(projectProvider: provider, configurationList: configurationList) /// ``` -public final class SettingsMapper: SettingsMapping { +final class XCConfigurationMapper: SettingsMapping { /// Creates a new `SettingsMapper` instance. - public init() {} + init() {} - public func map( + func map( projectProvider: ProjectProviding, configurationList: XCConfigurationList? - ) async throws -> Settings { + ) throws -> Settings { guard let configurationList else { return Settings.default } @@ -51,7 +51,7 @@ public final class SettingsMapper: SettingsMapping { var configurations: [BuildConfiguration: Configuration?] = [:] for buildConfig in configurationList.buildConfigurations { let buildSettings = buildConfig.buildSettings - let settingsDict = try await mapBuildSettings(buildSettings) + let settingsDict = try mapBuildSettings(buildSettings) var xcconfigAbsolutePath: AbsolutePath? if let baseConfigRef = buildConfig.baseConfiguration, @@ -59,10 +59,10 @@ public final class SettingsMapper: SettingsMapping { sourceRoot: projectProvider.sourceDirectory.pathString ) { - xcconfigAbsolutePath = try AbsolutePath.resolvePath(xcconfigPath) + xcconfigAbsolutePath = try AbsolutePath(validating: xcconfigPath) } - let variant = variant(forName: buildConfig.name) + let variant = variant(for: buildConfig.name) let buildConfiguration = BuildConfiguration(name: buildConfig.name, variant: variant) configurations[buildConfiguration] = Configuration( settings: settingsDict, @@ -87,10 +87,10 @@ public final class SettingsMapper: SettingsMapping { /// - Parameter buildSettings: A dictionary of raw build settings. /// - Returns: A `SettingsDictionary` containing `SettingValue`-typed settings. /// - Throws: If a setting value cannot be mapped (this is typically non-fatal; most values can be stringified). - public func mapBuildSettings(_ buildSettings: [String: Any]) async throws -> SettingsDictionary { + func mapBuildSettings(_ buildSettings: [String: Any]) throws -> SettingsDictionary { var settingsDict = SettingsDictionary() for (key, value) in buildSettings { - settingsDict[key] = try await mapSettingValue(value) + settingsDict[key] = try mapSettingValue(value) } return settingsDict } @@ -103,7 +103,7 @@ public final class SettingsMapper: SettingsMapping { /// /// - Parameter value: A raw setting value from the build settings dictionary. /// - Returns: A `SettingValue` representing the processed setting. - private func mapSettingValue(_ value: Any) async throws -> SettingValue { + private func mapSettingValue(_ value: Any) throws -> SettingValue { if let stringValue = value as? String { return .string(stringValue) } else if let arrayValue = value as? [Any] { @@ -122,7 +122,10 @@ public final class SettingsMapper: SettingsMapping { /// /// - Parameter name: The name of the build configuration (e.g., "Debug", "Release", "Development"). /// - Returns: The corresponding `BuildConfiguration.Variant` inferred from the name. - private func variant(forName name: String) -> BuildConfiguration.Variant { - ConfigurationMatcher.variant(forName: name) + private func variant( + for name: String, + configurationMatcher: ConfigurationMatching = ConfigurationMatcher() + ) -> BuildConfiguration.Variant { + configurationMatcher.variant(for: name) } } diff --git a/Sources/XcodeProjMapper/Mappers/Targets/PBXBuildRuleMapper.swift b/Sources/XcodeProjMapper/Mappers/Targets/PBXBuildRuleMapper.swift new file mode 100644 index 00000000..9518ad6b --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Targets/PBXBuildRuleMapper.swift @@ -0,0 +1,55 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// A protocol defining how to map a single `PBXBuildRule` instance into a `BuildRule` domain model. +/// +/// Conforming types transform an individual build rule defined in an Xcode project into a +/// structured `BuildRule` model, enabling further analysis or code generation steps to operate on +/// well-defined representations of build rules. +protocol BuildRuleMapping { + /// Maps a single `PBXBuildRule` into a `BuildRule` model. + /// + /// - Parameter buildRule: The `PBXBuildRule` to map. + /// - Returns: A `BuildRule` model if the compiler spec and file type are recognized; otherwise, `nil`. + /// - Throws: If resolving or mapping the build rule fails. + func map(_ buildRule: PBXBuildRule) throws -> BuildRule? +} + +/// A mapper that converts a `PBXBuildRule` object into a `BuildRule` domain model. +/// +/// `BuildRuleMapper` extracts known compiler specs and file types from the provided build rule. +/// If the compiler spec or file type is unknown, the build rule is ignored (returning `nil`). +struct PBXBuildRuleMapper: BuildRuleMapping { + func map(_ buildRule: PBXBuildRule) throws -> BuildRule? { + guard let compilerSpec = mapCompilerSpec(buildRule.compilerSpec), + let fileType = mapFileType(buildRule.fileType) + else { + // Unknown compiler spec or file type encountered. Skipping this build rule. + return nil + } + + return BuildRule( + compilerSpec: compilerSpec, + fileType: fileType, + filePatterns: buildRule.filePatterns, + name: buildRule.name, + outputFiles: buildRule.outputFiles, + inputFiles: buildRule.inputFiles, + outputFilesCompilerFlags: buildRule.outputFilesCompilerFlags, + script: buildRule.script, + runOncePerArchitecture: buildRule.runOncePerArchitecture + ) + } + + // MARK: - Private Helpers + + private func mapCompilerSpec(_ compilerSpec: String) -> BuildRule.CompilerSpec? { + BuildRule.CompilerSpec(rawValue: compilerSpec) + } + + private func mapFileType(_ fileType: String) -> BuildRule.FileType? { + BuildRule.FileType(rawValue: fileType) + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildHeaders.swift b/Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+BuildHeaders.swift similarity index 70% rename from Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildHeaders.swift rename to Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+BuildHeaders.swift index cd9dceff..3708f285 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildHeaders.swift +++ b/Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+BuildHeaders.swift @@ -2,7 +2,7 @@ import XcodeProj extension PBXTarget { /// Returns the headers build phase, if any. - public func headersBuildPhase() throws -> PBXHeadersBuildPhase? { + func headersBuildPhase() throws -> PBXHeadersBuildPhase? { buildPhases.compactMap { $0 as? PBXHeadersBuildPhase }.first } } diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift b/Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+BuildSettings.swift similarity index 92% rename from Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift rename to Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+BuildSettings.swift index b49def55..41eeb27c 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+BuildSettings.swift +++ b/Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+BuildSettings.swift @@ -18,14 +18,14 @@ extension PBXTarget { /// Retrieves the path to the Info.plist file from the target's build settings. /// /// - Returns: The `INFOPLIST_FILE` value if present, otherwise `nil`. - public func infoPlistPath() throws -> String? { + func infoPlistPath() throws -> String? { buildConfigurationList?.stringSetting(for: .infoPlistFile) } /// Retrieves the path to the entitlements file from the target's build settings. /// /// - Returns: The `CODE_SIGN_ENTITLEMENTS` value if present, otherwise `nil`. - public func entitlementsPath() throws -> String? { + func entitlementsPath() throws -> String? { buildConfigurationList?.stringSetting(for: .codeSignEntitlements) } @@ -39,7 +39,7 @@ extension PBXTarget { /// - `VISIONOS_DEPLOYMENT_TARGET` /// /// - Returns: A `DeploymentTargets` instance containing any discovered versions. - public func deploymentTargets() throws -> DeploymentTargets { + func deploymentTargets() throws -> DeploymentTargets { guard let configList = buildConfigurationList else { return DeploymentTargets(iOS: nil, macOS: nil, watchOS: nil, tvOS: nil, visionOS: nil) } @@ -65,7 +65,7 @@ extension PBXTarget { /// Extracts environment variables from all build configurations of the target. /// /// If multiple configurations define the same environment variable, the last processed configuration takes precedence. - public func extractEnvironmentVariables() -> [String: EnvironmentVariable] { + func extractEnvironmentVariables() -> [String: EnvironmentVariable] { buildConfigurationList?.buildConfigurations.reduce(into: [:]) { result, config in result.merge(EnvironmentExtractor.extract(from: config.buildSettings)) { current, _ in current } diff --git a/Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+GraphMapping.swift b/Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+GraphMapping.swift new file mode 100644 index 00000000..c1b45d1d --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+GraphMapping.swift @@ -0,0 +1,61 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +extension PBXTarget { + /// Attempts to retrieve the bundle identifier from the target's debug build settings, or throws an error if missing. + func bundleIdentifier() throws -> String { + if let bundleId = debugBuildSettings.string(for: .productBundleIdentifier) { + return bundleId + } + throw TargetMappingError.missingBundleIdentifier(targetName: name) + } + + /// Returns an array of all `PBXCopyFilesBuildPhase` instances for this target. + func copyFilesBuildPhases() -> [PBXCopyFilesBuildPhase] { + buildPhases.compactMap { $0 as? PBXCopyFilesBuildPhase } + } + + func launchArguments() throws -> [LaunchArgument] { + guard let buildConfigList = buildConfigurationList else { return [] } + var launchArguments: [LaunchArgument] = [] + for buildConfig in buildConfigList.buildConfigurations { + if let args = buildConfig.buildSettings.stringArray(for: .launchArguments) { + launchArguments.append(contentsOf: args.map { LaunchArgument(name: $0, isEnabled: true) }) + } + } + return launchArguments.uniqued() + } + + func prune() throws -> Bool { + debugBuildSettings.bool(for: .prune) ?? false + } + + func mergedBinaryType() throws -> MergedBinaryType { + let mergedBinaryTypeString = debugBuildSettings.string(for: .mergedBinaryType) + return mergedBinaryTypeString == "automatic" ? .automatic : .disabled + } + + func mergeable() throws -> Bool { + debugBuildSettings.bool(for: .mergeable) ?? false + } + + func onDemandResourcesTags() throws -> OnDemandResourcesTags? { + // Currently returns nil, could be extended if needed + return nil + } + + func metadata() throws -> TargetMetadata { + var tags: Set = [] + for buildConfig in buildConfigurationList?.buildConfigurations ?? [] { + if let tagsString = buildConfig.buildSettings.string(for: .tags) { + let extractedTags = tagsString + .split(separator: ",") + .map { $0.trimmingCharacters(in: .whitespaces) } + tags.formUnion(extractedTags) + } + } + return TargetMetadata(tags: tags) + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+PlatformInference.swift b/Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+PlatformInference.swift similarity index 94% rename from Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+PlatformInference.swift rename to Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+PlatformInference.swift index 8377b043..bff98d6f 100644 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/PBXTarget+PlatformInference.swift +++ b/Sources/XcodeProjMapper/Mappers/Targets/PBXTarget+PlatformInference.swift @@ -7,7 +7,7 @@ extension PBXTarget { /// Maps the `PBXTarget.productType` to a domain `Product` model. /// /// If the product type is not explicitly handled, defaults to `.app`. - public func productType() -> Product { + func productType() -> Product { return productType?.mapProductType() ?? .app } @@ -22,7 +22,7 @@ extension PBXTarget { /// /// - Returns: A `Destinations` set representing all supported destinations. /// - Throws: If retrieving deployment targets fails. - public func platform() throws -> Destinations { + func platform() throws -> Destinations { if let sdkName = buildConfigurationList?.stringSetting(for: .sdkroot), let root = Platform(sdkroot: sdkName) { @@ -76,6 +76,8 @@ extension PBXTarget { return Platform.macOS.destinations case .tvTopShelfExtension: return Platform.tvOS.destinations + case .watch2App, .watch2Extension: + return Platform.watchOS.destinations default: return Platform.iOS.destinations } diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift b/Sources/XcodeProjMapper/Mappers/Targets/PBXTargetDependency+PlatformCondition.swift similarity index 70% rename from Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift rename to Sources/XcodeProjMapper/Mappers/Targets/PBXTargetDependency+PlatformCondition.swift index 8a7248d4..84bdfaaa 100644 --- a/Sources/XcodeProjToGraph/Mappers/Dependency/PlatformConditionMapper.swift +++ b/Sources/XcodeProjMapper/Mappers/Targets/PBXTargetDependency+PlatformCondition.swift @@ -2,14 +2,14 @@ import XcodeGraph import XcodeProj /// A mapper for platform-related conditions, extracting platform filters from `PBXTargetDependency`. -public enum PlatformConditionMapper { +extension PBXTargetDependency { /// Maps the platform filters on a given `PBXTargetDependency` into a `PlatformCondition`. /// /// Returns `nil` if no filters apply, meaning the dependency isn't restricted by platform and /// should be considered available on all platforms. - public static func mapCondition(dependency: PBXTargetDependency) -> PlatformCondition? { - var filters = Set(dependency.platformFilters ?? []) - if let singleFilter = dependency.platformFilter { + func platformCondition() -> PlatformCondition? { + var filters = Set(platformFilters ?? []) + if let singleFilter = platformFilter { filters.insert(singleFilter) } diff --git a/Sources/XcodeProjMapper/Mappers/Targets/PBXTargetDependencyMapper.swift b/Sources/XcodeProjMapper/Mappers/Targets/PBXTargetDependencyMapper.swift new file mode 100644 index 00000000..15e11a83 --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Targets/PBXTargetDependencyMapper.swift @@ -0,0 +1,129 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// A protocol that defines how to map a single `PBXTargetDependency` into a `TargetDependency` model. +/// +/// Implementations of this protocol handle all known dependency types—direct targets, package products, +/// proxy references (which may point to other targets or projects), and file-based dependencies. +protocol DependencyMapping { + /// Maps a single `PBXTargetDependency` into a `TargetDependency` model. + /// + /// - Parameters: + /// - dependency: The `PBXTargetDependency` to map. + /// - projectProvider: Provides access to the project's `.xcodeproj` and source directory. + /// - Returns: A `TargetDependency` model if the dependency can be resolved; otherwise, `nil`. + /// - Throws: If the dependency references invalid paths or targets that cannot be resolved. + func map(_ dependency: PBXTargetDependency, projectProvider: ProjectProviding) throws -> TargetDependency? +} + +/// A unified mapper that handles all types of `PBXTargetDependency` instances. +/// +/// `PBXTargetDependencyMapper` checks if the dependency references a direct target, a package product, +/// or a proxy. For proxy dependencies, it may resolve references to another target, a project, +/// or file-based dependencies (frameworks, libraries, etc.). If a dependency cannot be resolved +/// to a known domain model, it returns `nil`. +struct PBXTargetDependencyMapper: DependencyMapping { + func map(_ dependency: PBXTargetDependency, projectProvider: ProjectProviding) throws -> TargetDependency? { + let condition = dependency.platformCondition() + + // 1. Direct target dependency + if let target = dependency.target { + return .target(name: target.name, status: .required, condition: condition) + } + + // 2. Package product dependency + if let product = dependency.product { + return .package( + product: product.productName, + type: .runtime, + condition: condition + ) + } + + // 3. Proxy dependency + if let targetProxy = dependency.targetProxy, let proxyType = targetProxy.proxyType { + switch proxyType { + case .nativeTarget: + return try mapNativeTargetProxy(targetProxy, condition: condition, projectProvider: projectProvider) + case .reference: + return try mapReferenceProxy(targetProxy, condition: condition, projectProvider: projectProvider) + default: + return nil + } + } + + return nil + } + + // MARK: - Private Helpers + + private func mapNativeTargetProxy( + _ targetProxy: PBXContainerItemProxy, + condition: PlatformCondition?, + projectProvider: ProjectProviding + ) throws -> TargetDependency? { + guard let remoteInfo = targetProxy.remoteInfo else { return nil } + + switch targetProxy.containerPortal { + case .project: + // Direct reference to another target in the same project. + return .target(name: remoteInfo, status: .required, condition: condition) + case let .fileReference(fileReference): + guard let projectRelativePath = fileReference.path else { return nil } + let fullPath = projectProvider.sourceDirectory.pathString + projectRelativePath + let absPath = try AbsolutePath(validating: fullPath) + // Reference to a target in another project. + return .project(target: remoteInfo, path: absPath, status: .required, condition: condition) + case .unknownObject: + return nil + } + } + + private func mapReferenceProxy( + _ targetProxy: PBXContainerItemProxy, + condition: PlatformCondition?, + projectProvider: ProjectProviding + ) throws -> TargetDependency? { + guard let remoteGlobalID = targetProxy.remoteGlobalID else { return nil } + + switch remoteGlobalID { + case let .object(object): + if let fileReference = object as? PBXFileReference { + return try mapFileDependency( + pathString: fileReference.path, + condition: condition, + projectProvider: projectProvider + ) + } else if let referenceProxy = object as? PBXReferenceProxy { + return try mapFileDependency( + pathString: referenceProxy.path, + condition: condition, + projectProvider: projectProvider + ) + } + return nil + case .string: + return nil + } + } + + /// Maps file-based dependencies (e.g., frameworks, libraries) into `TargetDependency` models. + /// + /// - Parameters: + /// - pathString: The path string for the file-based dependency. + /// - condition: An optional platform condition. + /// - projectProvider: Provides directory structure for resolving relative paths. + /// - Returns: A `TargetDependency` if the file’s extension matches a known dependency type, or `nil` if not. + private func mapFileDependency( + pathString: String?, + condition: PlatformCondition?, + projectProvider: ProjectProviding + ) throws -> TargetDependency? { + guard let pathString else { return nil } + let validatedPath = projectProvider.sourceDirectory.appending(try RelativePath(validating: pathString)) + let absPath = try AbsolutePath(validating: validatedPath.pathString) + return absPath.mapByExtension(condition: condition) + } +} diff --git a/Sources/XcodeProjMapper/Mappers/Targets/PBXTargetMapper.swift b/Sources/XcodeProjMapper/Mappers/Targets/PBXTargetMapper.swift new file mode 100644 index 00000000..28fcea10 --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Targets/PBXTargetMapper.swift @@ -0,0 +1,313 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// Errors that may occur while mapping a `PBXTarget` into a `Target`. +enum TargetMappingError: LocalizedError, Equatable { + case noProjectsFound(path: String) + case missingFilesGroup(targetName: String) + case invalidPlist(path: String) + case missingBundleIdentifier(targetName: String) + + var errorDescription: String? { + switch self { + case let .noProjectsFound(path): + return "No project was found at: \(path)." + case let .missingFilesGroup(targetName): + return "The files group is missing for the target '\(targetName)'." + case let .invalidPlist(path): + return "Failed to read a valid plist dictionary from file at: \(path)." + case let .missingBundleIdentifier(targetName): + return "The bundle identifier is missing for the target '\(targetName)'." + } + } +} + +/// A protocol defining how to map a `PBXTarget` into a domain-level `Target` model. +/// +/// Conforming types transform raw `PBXTarget` instances—including their build phases, +/// settings, and dependencies—into fully realized `Target` models suitable for analysis, +/// code generation, or tooling integration. +protocol TargetMapping { + /// Maps a given `PBXTarget` into a `Target` model. + /// + /// This involves: + /// - Extracting platform, product, and deployment information. + /// - Mapping build phases (sources, resources, headers, scripts, copy files, frameworks, etc.) + /// - Resolving dependencies (project-based, frameworks, libraries, packages, SDKs). + /// - Reading settings, launch arguments, and metadata. + /// + /// - Parameters: + /// - pbxTarget: The `PBXTarget` to map. + /// - projectProvider: Provides access to project paths and `XcodeProj` data. + /// - Returns: A fully mapped `Target` model. + /// - Throws: `TargetMappingError` if required data (like a bundle identifier) is missing, + /// or if necessary files/groups cannot be found. + func map(pbxTarget: PBXTarget, projectProvider: ProjectProviding) throws -> Target +} + +/// A mapper that converts a `PBXTarget` into a domain `Target` model. +/// +/// `PBXTargetMapper` orchestrates various specialized mappers (e.g., sources, resources, headers) +/// and dependency resolvers to produce a comprehensive `Target` suitable for downstream tasks. +struct PBXTargetMapper: TargetMapping { + private let settingsMapper: SettingsMapping + private let sourcesMapper: PBXSourcesBuildPhaseMapping + private let resourcesMapper: PBXResourcesBuildPhaseMapping + private let headersMapper: PBXHeadersBuildPhaseMapping + private let scriptsMapper: PBXScriptsBuildPhaseMapping + private let copyFilesMapper: PBXCopyFilesBuildPhaseMapping + private let coreDataModelsMapper: PBXCoreDataModelsBuildPhaseMapping + private let frameworksMapper: PBXFrameworksBuildPhaseMapping + private let dependencyMapper: DependencyMapping + private let buildRuleMapper: BuildRuleMapping + + init( + settingsMapper: SettingsMapping = XCConfigurationMapper(), + sourcesMapper: PBXSourcesBuildPhaseMapping = PBXSourcesBuildPhaseMapper(), + resourcesMapper: PBXResourcesBuildPhaseMapping = PBXResourcesBuildPhaseMapper(), + headersMapper: PBXHeadersBuildPhaseMapping = PBXHeadersBuildPhaseMapper(), + scriptsMapper: PBXScriptsBuildPhaseMapping = PBXScriptsBuildPhaseMapper(), + copyFilesMapper: PBXCopyFilesBuildPhaseMapping = PBXCopyFilesBuildPhaseMapper(), + coreDataModelsMapper: PBXCoreDataModelsBuildPhaseMapping = PBXCoreDataModelsBuildPhaseMapper(), + frameworksMapper: PBXFrameworksBuildPhaseMapping = PBXFrameworksBuildPhaseMapper(), + dependencyMapper: DependencyMapping = PBXTargetDependencyMapper(), + buildRuleMapper: BuildRuleMapping = PBXBuildRuleMapper() + ) { + self.settingsMapper = settingsMapper + self.sourcesMapper = sourcesMapper + self.resourcesMapper = resourcesMapper + self.headersMapper = headersMapper + self.scriptsMapper = scriptsMapper + self.copyFilesMapper = copyFilesMapper + self.coreDataModelsMapper = coreDataModelsMapper + self.frameworksMapper = frameworksMapper + self.dependencyMapper = dependencyMapper + self.buildRuleMapper = buildRuleMapper + } + + func map(pbxTarget: PBXTarget, projectProvider: ProjectProviding) throws -> Target { + let platform = try pbxTarget.platform() + let deploymentTargets = try pbxTarget.deploymentTargets() + let product = pbxTarget.productType() + + let settings = try settingsMapper.map( + projectProvider: projectProvider, + configurationList: pbxTarget.buildConfigurationList + ) + + let sources = try pbxTarget.sourcesBuildPhase().map { + try sourcesMapper.map($0, projectProvider: projectProvider) + } ?? [] + + let resources = try pbxTarget.resourcesBuildPhase().map { + try resourcesMapper.map($0, projectProvider: projectProvider) + } ?? [] + + let headers = try pbxTarget.headersBuildPhase().map { + try headersMapper.map($0, projectProvider: projectProvider) + } ?? nil + + let runScriptPhases = pbxTarget.runScriptBuildPhases() + let scripts = try scriptsMapper.map( + runScriptPhases, + buildPhases: pbxTarget.buildPhases, + projectProvider: projectProvider + ) + let rawScriptBuildPhases = scriptsMapper.mapRawScriptBuildPhases(runScriptPhases) + + let copyFilesPhases = pbxTarget.copyFilesBuildPhases() + let copyFiles = try copyFilesMapper.map(copyFilesPhases, projectProvider: projectProvider) + + let resourceFiles = try pbxTarget.resourcesBuildPhase()?.files ?? [] + let coreDataModels = try coreDataModelsMapper.map(resourceFiles, projectProvider: projectProvider) + + let frameworksPhase = try pbxTarget.frameworksBuildPhase() + let frameworks = try frameworksPhase.map { + try frameworksMapper.map($0, projectProvider: projectProvider) + } ?? [] + + let additionalFiles = try mapAdditionalFiles(from: pbxTarget, projectProvider: projectProvider) + let resourceFileElements = ResourceFileElements(resources) + + let buildRules = try pbxTarget.buildRules.compactMap { + try buildRuleMapper.map($0) + } + + let environmentVariables = pbxTarget.extractEnvironmentVariables() + let launchArguments = try pbxTarget.launchArguments() + let filesGroup = try extractFilesGroup(from: pbxTarget, projectProvider: projectProvider) + let playgrounds = try extractPlaygrounds(from: pbxTarget, projectProvider: projectProvider) + let prune = try pbxTarget.prune() + let mergedBinaryType = try pbxTarget.mergedBinaryType() + let mergeable = try pbxTarget.mergeable() + let onDemandResourcesTags = try pbxTarget.onDemandResourcesTags() + let metadata = try pbxTarget.metadata() + + let targetDependencies = try pbxTarget.dependencies.compactMap { + try dependencyMapper.map($0, projectProvider: projectProvider) + } + let allDependencies = (targetDependencies + frameworks).sorted { $0.name < $1.name } + + return Target( + name: pbxTarget.name, + destinations: platform, + product: product, + productName: pbxTarget.productName ?? pbxTarget.name, + bundleId: try pbxTarget.bundleIdentifier(), + deploymentTargets: deploymentTargets, + infoPlist: try extractInfoPlist(from: pbxTarget, projectProvider: projectProvider), + entitlements: try extractEntitlements(from: pbxTarget, projectProvider: projectProvider), + settings: settings, + sources: sources, + resources: resourceFileElements, + copyFiles: copyFiles, + headers: headers, + coreDataModels: coreDataModels, + scripts: scripts, + environmentVariables: environmentVariables, + launchArguments: launchArguments, + filesGroup: filesGroup, + dependencies: allDependencies, + rawScriptBuildPhases: rawScriptBuildPhases, + playgrounds: playgrounds, + additionalFiles: additionalFiles, + buildRules: buildRules, + prune: prune, + mergedBinaryType: mergedBinaryType, + mergeable: mergeable, + onDemandResourcesTags: onDemandResourcesTags, + metadata: metadata + ) + } + + // MARK: - Helpers + + /// Identifies files not included in any build phase, returning them as `FileElement` models. + func mapAdditionalFiles(from pbxTarget: PBXTarget, projectProvider: ProjectProviding) throws -> [FileElement] { + guard let pbxProject = projectProvider.xcodeProj.pbxproj.projects.first, + let mainGroup = pbxProject.mainGroup + else { + throw TargetMappingError.noProjectsFound(path: projectProvider.xcodeProjPath.pathString) + } + + let allFiles = try collectAllFiles(from: mainGroup, projectProvider: projectProvider) + let filesInBuildPhases = try filesReferencedByBuildPhases(pbxTarget: pbxTarget, projectProvider: projectProvider) + let additionalFiles = allFiles.subtracting(filesInBuildPhases).sorted() + return additionalFiles.map { FileElement.file(path: $0) } + } + + /// Extracts the main files group for the target. + func extractFilesGroup(from target: PBXTarget, projectProvider: ProjectProviding) throws -> ProjectGroup { + guard let pbxProject = projectProvider.xcodeProj.pbxproj.projects.first, + let mainGroup = pbxProject.mainGroup + else { + throw TargetMappingError.missingFilesGroup(targetName: target.name) + } + return ProjectGroup.group(name: mainGroup.name ?? "MainGroup") + } + + /// Extracts and parses the project's Info.plist as a dictionary, or returns an empty dictionary if none is found. + func extractInfoPlist(from target: PBXTarget, projectProvider: ProjectProviding) throws -> InfoPlist { + if let plistPath = try target.infoPlistPath() { + let path = projectProvider.sourceDirectory.appending(try RelativePath(validating: plistPath)) + let plistDictionary = try readPlistAsDictionary(at: path) + return .dictionary(plistDictionary) + } + return .dictionary([:]) + } + + /// Extracts the target's entitlements file, if present. + func extractEntitlements(from target: PBXTarget, projectProvider: ProjectProviding) throws -> Entitlements? { + if let entitlementsPath = try target.entitlementsPath() { + let path = projectProvider.sourceDirectory.appending(try RelativePath(validating: entitlementsPath)) + return Entitlements.file(path: path) + } + return nil + } + + + /// Recursively collects all files from a given `PBXGroup`. + private func collectAllFiles(from group: PBXGroup, projectProvider: ProjectProviding) throws -> Set { + var files = Set() + for child in group.children { + if let file = child as? PBXFileReference, + let pathString = try file.fullPath(sourceRoot: projectProvider.sourcePathString) + { + let absPath = try AbsolutePath(validating: pathString) + files.insert(absPath) + } else if let subgroup = child as? PBXGroup { + files.formUnion(try collectAllFiles(from: subgroup, projectProvider: projectProvider)) + } + } + return files + } + + /// Identifies all files referenced by any build phase in the target. + private func filesReferencedByBuildPhases( + pbxTarget: PBXTarget, + projectProvider: ProjectProviding + ) throws -> Set { + let filePaths = try pbxTarget.buildPhases.compactMap(\.files) + .flatMap { $0 } + .compactMap { buildFile -> AbsolutePath? in + guard let fileRef = buildFile.file, + let filePath = try fileRef.fullPath(sourceRoot: projectProvider.sourceDirectory.pathString) + else { return nil } + return try AbsolutePath(validating: filePath) + } + return Set(filePaths) + } + + /// Extracts playground files from the target's sources. + private func extractPlaygrounds(from pbxTarget: PBXTarget, projectProvider: ProjectProviding) throws -> [AbsolutePath] { + let sources = try pbxTarget.sourcesBuildPhase().map { + try sourcesMapper.map($0, projectProvider: projectProvider) + } ?? [] + return sources.filter { $0.path.fileExtension == .playground }.map(\.path) + } + + /// Reads and parses a plist file into a `[String: Plist.Value]` dictionary. + private func readPlistAsDictionary(at path: AbsolutePath) throws -> [String: Plist.Value] { + let fileURL = URL(fileURLWithPath: path.pathString) + let data = try Data(contentsOf: fileURL) + var format = PropertyListSerialization.PropertyListFormat.xml + guard let plist = try? PropertyListSerialization.propertyList( + from: data, + options: .mutableContainersAndLeaves, + format: &format + ) as? [String: Any] else { + throw TargetMappingError.invalidPlist(path: path.pathString) + } + + return try plist.reduce(into: [String: Plist.Value]()) { result, item in + result[item.key] = try convertToPlistValue(item.value) + } + } + + /// Converts a raw plist value into a `Plist.Value`. + private func convertToPlistValue(_ value: Any) throws -> Plist.Value { + switch value { + case let stringValue as String: + return .string(stringValue) + case let intValue as Int: + return .integer(intValue) + case let doubleValue as Double: + return .real(doubleValue) + case let boolValue as Bool: + return .boolean(boolValue) + case let arrayValue as [Any]: + let convertedArray = try arrayValue.map { try convertToPlistValue($0) } + return .array(convertedArray) + case let dictValue as [String: Any]: + let convertedDict = try dictValue.reduce(into: [String: Plist.Value]()) { + dictResult, dictItem in + dictResult[dictItem.key] = try convertToPlistValue(dictItem.value) + } + return .dictionary(convertedDict) + default: + return .string(String(describing: value)) + } + } +} diff --git a/Sources/XcodeProjMapper/Mappers/Targets/TargetDependency+GraphMapping.swift b/Sources/XcodeProjMapper/Mappers/Targets/TargetDependency+GraphMapping.swift new file mode 100644 index 00000000..7cedda2b --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Targets/TargetDependency+GraphMapping.swift @@ -0,0 +1,225 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// Errors that may occur when mapping `TargetDependency` instances into `GraphDependency` models. +enum TargetDependencyMappingError: LocalizedError, Equatable { + case targetNotFound(targetName: String, path: AbsolutePath) + case unknownDependencyType(name: String) + + var errorDescription: String? { + switch self { + case let .targetNotFound(targetName, path): + return "The target '\(targetName)' could not be found in the project at: \(path.pathString)." + case let .unknownDependencyType(name): + return "An unknown dependency type '\(name)' was encountered." + } + } +} + +extension TargetDependency { + /// Maps this `TargetDependency` to a `GraphDependency` by resolving paths, product types, + /// and linking details. Project-based dependencies are resolved using the provided `allTargetsMap`. + /// + /// - Parameters: + /// - sourceDirectory: The root directory for resolving relative paths. + /// - allTargetsMap: A map of target names to `Target` models for resolving project-based dependencies. + /// - Returns: A corresponding `GraphDependency` model. + /// - Throws: `TargetDependencyMappingError` if a referenced target is not found or the dependency type is unknown. + func graphDependency( + sourceDirectory: AbsolutePath, + allTargetsMap: [String: Target] + ) throws -> GraphDependency { + switch self { + case let .target(name, status, _): + return .target(name: name, path: sourceDirectory, status: status) + + case let .project(targetName, projectPath, status, _): + return try mapProjectGraphDependency( + projectPath: projectPath, + targetName: targetName, + status: status, + allTargetsMap: allTargetsMap + ) + + case let .framework(path, status, _): + // TODO: - Retrieve architectures, bcsymbolmapPaths from metadata providers if needed. + return .framework( + path: path, + binaryPath: path.appending(component: "\(name)"), + dsymPath: nil, + bcsymbolmapPaths: [], + linking: .dynamic, + architectures: [], + status: status + ) + + case let .xcframework(path, status, _): + // TODO: - Retrieve architectures, bcsymbolmapPaths, infoPlist from metadata providers. + let infoPlist = XCFrameworkInfoPlist(libraries: []) + return .xcframework( + GraphDependency.XCFramework( + path: path, + infoPlist: infoPlist, + linking: .dynamic, + mergeable: false, + status: status, + macroPath: nil, + swiftModules: [], + moduleMaps: [] + ) + ) + + case let .library(path, publicHeaders, swiftModuleMap, _): + let linking: BinaryLinking = { + switch path.fileExtension { + case .staticLibrary: return .static + case .dynamicLibrary, .textBasedDynamicLibrary: return .dynamic + default: return .dynamic + } + }() + // Future: Retrieve architectures from metadata providers. + return .library( + path: path, + publicHeaders: publicHeaders, + linking: linking, + architectures: [], + swiftModuleMap: swiftModuleMap + ) + + case let .package(product, type, _): + return .packageProduct( + path: sourceDirectory, + product: product, + type: type.graphPackageType + ) + + case let .sdk(name, status, _): + return .sdk( + name: name, + path: sourceDirectory, + status: status, + source: .developer + ) + + case .xctest: + // TODO: - Retrieve infoPlist from metadata providers. + let infoPlist = XCFrameworkInfoPlist(libraries: []) + return .xcframework( + GraphDependency.XCFramework( + path: sourceDirectory, + infoPlist: infoPlist, + linking: .dynamic, + mergeable: false, + status: .required, + macroPath: nil, + swiftModules: [], + moduleMaps: [] + ) + ) + } + } + + /// Resolves a project-based target dependency into a `GraphDependency`, using the `allTargetsMap` to find + /// the appropriate target and derive its product type (e.g. framework, library, app). + /// + /// - Parameters: + /// - projectPath: The absolute path of the `.xcodeproj` directory. + /// - targetName: The name of the target within that project. + /// - status: The linking status of the dependency. + /// - allTargetsMap: A dictionary of target names to `Target` models for resolution. + /// - Returns: A `GraphDependency` representing the resolved dependency. + /// - Throws: `TargetDependencyMappingError.targetNotFound` if `targetName` isn't in `allTargetsMap`, + /// `TargetDependencyMappingError.unknownDependencyType` if the product type can't be mapped. + func mapProjectGraphDependency( + projectPath: AbsolutePath, + targetName: String, + status: LinkingStatus, + allTargetsMap: [String: Target] + ) throws -> GraphDependency { + guard let target = allTargetsMap[targetName] else { + throw TargetDependencyMappingError.targetNotFound(targetName: targetName, path: projectPath) + } + + let product = target.product + let dependency: GraphDependency + + switch product { + case .framework, .staticFramework: + let linking: BinaryLinking = (product == .staticFramework) ? .static : .dynamic + dependency = .framework( + path: projectPath, + binaryPath: projectPath.appending(component: "\(targetName).framework"), + dsymPath: nil, + bcsymbolmapPaths: [], + linking: linking, + architectures: [], + status: status + ) + + case .staticLibrary, .dynamicLibrary: + let linking: BinaryLinking = (product == .staticLibrary) ? .static : .dynamic + let libName = linking == .static ? "lib\(targetName).a" : "lib\(targetName).dylib" + let publicHeadersPath = projectPath.appending(component: "include") + dependency = .library( + path: projectPath.appending(component: libName), + publicHeaders: publicHeadersPath, + linking: linking, + architectures: [], + swiftModuleMap: nil + ) + + case .bundle: + dependency = .bundle(path: projectPath.appending(component: "\(targetName).bundle")) + + case .app, .commandLineTool: + dependency = .target(name: targetName, path: projectPath, status: status) + + default: + throw TargetDependencyMappingError.unknownDependencyType(name: product.description) + } + + return dependency + } +} + +extension TargetDependency.PackageType { + /// Translates `TargetDependency.PackageType` into `GraphDependency.PackageProductType`. + var graphPackageType: GraphDependency.PackageProductType { + switch self { + case .runtime: return .runtime + case .runtimeEmbedded: return .runtimeEmbedded + case .plugin: return .plugin + case .macro: return .macro + } + } +} + +extension PBXProductType { + /// Maps `PBXProductType` to a `Product`, or returns `nil` if unsupported. + func mapProductType() -> Product? { + switch self { + case .application, .messagesApplication, .onDemandInstallCapableApplication: return .app + case .framework, .xcFramework: return .framework + case .staticFramework: return .staticFramework + case .dynamicLibrary: return .dynamicLibrary + case .staticLibrary, .metalLibrary: return .staticLibrary + case .bundle, .ocUnitTestBundle: return .bundle + case .unitTestBundle: return .unitTests + case .uiTestBundle: return .uiTests + case .appExtension: return .appExtension + case .extensionKitExtension, .xcodeExtension: return .extensionKitExtension + case .commandLineTool: return .commandLineTool + case .messagesExtension: return .messagesExtension + case .stickerPack: return .stickerPackExtension + case .xpcService: return .xpc + case .watchApp, .watch2App, .watch2AppContainer: return .watch2App + case .watchExtension, .watch2Extension: return .watch2Extension + case .tvExtension: return .tvTopShelfExtension + case .systemExtension: return .systemExtension + case .instrumentsPackage, .intentsServiceExtension, .driverExtension, .none: + return nil + } + } +} diff --git a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift b/Sources/XcodeProjMapper/Mappers/Workspace/WorkspaceProvider.swift similarity index 89% rename from Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift rename to Sources/XcodeProjMapper/Mappers/Workspace/WorkspaceProvider.swift index c75dfb88..ccd5da7b 100644 --- a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceProvider.swift +++ b/Sources/XcodeProjMapper/Mappers/Workspace/WorkspaceProvider.swift @@ -13,7 +13,7 @@ import XcodeProj /// /// By abstracting these details, tooling can easily navigate and analyze workspaces, discovering contained projects /// and shared schemes without having to manually resolve file paths or parse the workspace file. -public protocol WorkspaceProviding: Sendable { +protocol WorkspaceProviding { /// The absolute path to the directory containing the `.xcworkspace` file. var workspaceDirectory: AbsolutePath { get } @@ -46,10 +46,10 @@ public protocol WorkspaceProviding: Sendable { /// /// // From here, you can inspect workspace elements, discover contained projects, or integrate with other mappers. /// ``` -public struct WorkspaceProvider: WorkspaceProviding { - public let workspaceDirectory: AbsolutePath - public let xcWorkspacePath: AbsolutePath - public let xcworkspace: XCWorkspace +struct WorkspaceProvider: WorkspaceProviding { + let workspaceDirectory: AbsolutePath + let xcWorkspacePath: AbsolutePath + let xcworkspace: XCWorkspace /// Initializes a `WorkspaceProvider` with a given workspace path. /// @@ -58,7 +58,7 @@ public struct WorkspaceProvider: WorkspaceProviding { /// /// Once initialized, `WorkspaceProvider` can be passed to tools like `WorkspaceMapper` to produce a `Workspace` model, /// or used directly to gather workspace-related data. - public init(xcWorkspacePath: AbsolutePath) throws { + init(xcWorkspacePath: AbsolutePath) throws { self.xcWorkspacePath = xcWorkspacePath workspaceDirectory = xcWorkspacePath.parentDirectory xcworkspace = try XCWorkspace(path: Path(xcWorkspacePath.pathString)) diff --git a/Sources/XcodeProjMapper/Mappers/Workspace/XCWorkspaceMapper.swift b/Sources/XcodeProjMapper/Mappers/Workspace/XCWorkspaceMapper.swift new file mode 100644 index 00000000..911ec91d --- /dev/null +++ b/Sources/XcodeProjMapper/Mappers/Workspace/XCWorkspaceMapper.swift @@ -0,0 +1,125 @@ +import Foundation +import Path +import PathKit +import XcodeGraph +import XcodeProj + +/// A protocol defining how to map an `.xcworkspace` into a `Workspace` model. +/// +/// Conforming types extract project references, shared schemes, and other relevant data +/// from a workspace to produce a high-level `Workspace` domain model. +protocol WorkspaceMapping { + /// Maps the `.xcworkspace` into a `Workspace` domain model. + /// + /// This includes: + /// - Identifying all `.xcodeproj` references in the workspace. + /// - Mapping any shared schemes present in the workspace. + /// + /// - Returns: A fully constructed `Workspace` representing the workspace’s structure. + /// - Throws: If reading projects or schemes fails. + func map(workspaceProvider: WorkspaceProviding) throws -> Workspace +} + +/// A mapper that converts an `.xcworkspace` into a `Workspace` model. +/// +/// `WorkspaceMapper`: +/// - Finds all referenced Xcode projects, +/// - Maps shared schemes, and +/// - Produces a `Workspace` model suitable for analysis or code generation. +struct XCWorkspaceMapper: WorkspaceMapping { + func map(workspaceProvider: WorkspaceProviding) throws -> Workspace { + let xcworkspace = workspaceProvider.xcworkspace + let xcWorkspacePath = workspaceProvider.xcWorkspacePath + let srcPath = workspaceProvider.workspaceDirectory + let projectPaths = try extractProjectPaths( + from: xcworkspace.data.children, + srcPath: srcPath, workspaceProvider: workspaceProvider + ) + let workspaceName = xcWorkspacePath.basenameWithoutExt + let schemes = try mapSchemes(from: xcWorkspacePath, workspaceProvider: workspaceProvider) + + let generationOptions = Workspace.GenerationOptions( + enableAutomaticXcodeSchemes: nil, + autogeneratedWorkspaceSchemes: .disabled, + lastXcodeUpgradeCheck: nil, + renderMarkdownReadme: false + ) + + return Workspace( + path: srcPath, + xcWorkspacePath: xcWorkspacePath, + name: workspaceName, + projects: projectPaths, + schemes: schemes, + generationOptions: generationOptions, + ideTemplateMacros: nil, + additionalFiles: [] + ) + } + + // MARK: - Private Helpers + + /// Recursively identifies all `.xcodeproj` files within the workspace structure. + /// + /// - Parameters: + /// - elements: The workspace elements (files/groups). + /// - srcPath: The source directory path used for resolving relative references. + /// - Returns: An array of absolute paths to `.xcodeproj` directories. + private func extractProjectPaths( + from elements: [XCWorkspaceDataElement], + srcPath: AbsolutePath, + workspaceProvider: WorkspaceProviding + ) throws -> [AbsolutePath] { + var paths = [AbsolutePath]() + + for element in elements { + switch element { + case let .file(ref): + let refPath = try ref.path(srcPath: srcPath) + if refPath.fileExtension == .xcodeproj { + paths.append(refPath) + } + case let .group(group): + let nestedSrcPath = srcPath.appending(component: group.location.path) + let groupPaths = try extractProjectPaths( + from: group.children, + srcPath: nestedSrcPath, + workspaceProvider: workspaceProvider + ) + paths.append(contentsOf: groupPaths) + } + } + + return paths + } + + /// Maps shared schemes defined within the workspace. + /// + /// Schemes are typically located in `xcshareddata/xcschemes`. If found, + /// this method parses them and maps them into `Scheme` models. + /// + /// - Parameter srcPath: The workspace's root path. + /// - Returns: An array of `Scheme` instances for shared schemes in the workspace. + private func mapSchemes( + from srcPath: AbsolutePath, + workspaceProvider: WorkspaceProviding + ) throws -> [Scheme] { + var schemes = [Scheme]() + let sharedDataPath = Path(srcPath.pathString) + "xcshareddata/xcschemes" + + if sharedDataPath.exists { + let schemePaths = try sharedDataPath.children().filter { $0.extension == "xcscheme" } + + // Construct graphType for schemes + let graphType = GraphType.workspace(workspaceProvider) + let schemeMapper = XCSchemeMapper() + for schemePath in schemePaths { + let xcscheme = try XCScheme(path: schemePath) + let scheme = try schemeMapper.map(xcscheme, shared: true, graphType: graphType) + schemes.append(scheme) + } + } + + return schemes + } +} diff --git a/Sources/XcodeProjMapper/Parser/ProjectParser.swift b/Sources/XcodeProjMapper/Parser/ProjectParser.swift new file mode 100644 index 00000000..1bef201b --- /dev/null +++ b/Sources/XcodeProjMapper/Parser/ProjectParser.swift @@ -0,0 +1,134 @@ +import Foundation +import Path +import XcodeGraph +import XcodeProj + +/// A protocol defining how to parse a project or workspace path into a `Graph` model. +public protocol ProjectParsing { + /// Parses the project or workspace at the given file system path into a `Graph`. + /// + /// This method analyzes the provided path to determine whether it points to: + /// - A `.xcworkspace` file + /// - A `.xcodeproj` file + /// - A directory containing either of these project types + /// + /// Once identified, it constructs a `Graph` model representing the entire project structure, + /// including targets, dependencies, and packages. This `Graph` can then be used for tasks such as + /// code generation, dependency analysis, or integration with custom developer tooling. + /// + /// **Example Usage:** + /// ```swift + /// // Suppose `/path/to/MyApp` contains either a MyApp.xcworkspace or MyApp.xcodeproj: + /// let parser: ProjectParsing = ProjectParser() + /// let graph = try parser.parse(at: "/path/to/MyApp") + /// + /// // 'graph' now represents the entire project's structure. + /// // You can analyze dependencies, generate derived code, or feed it into other build tools. + /// ``` + /// + /// If the specified path does not exist or no recognized Xcode project files are found, + /// this method will throw an error. + /// + /// - Parameter path: A file system path to a `.xcworkspace`, `.xcodeproj`, or a directory containing one. + /// - Returns: A `Graph` representing the discovered project or workspace. + /// - Throws: If no project or workspace can be found at the provided path or if other + /// internal parsing or mapping steps fail. + func parse(at path: String) throws -> Graph +} + +/// Specifies the type of project to parse: +/// - `.workspace(path)`: A `.xcworkspace` found at `path` +/// - `.xcodeProject(path)`: A `.xcodeproj` found at `path` +enum ProjectType: Equatable { + case workspace(AbsolutePath) + case xcodeProject(AbsolutePath) +} + +/// Errors that can occur when parsing a project or workspace. +enum ProjectParserError: LocalizedError, Equatable { + case pathNotFound(path: String) + case noProjectsFound(path: String) + + var errorDescription: String? { + switch self { + case let .pathNotFound(path): + return "The specified path does not exist: \(path)" + case let .noProjectsFound(path): + return "No `.xcworkspace` or `.xcodeproj` was found at: \(path)" + } + } +} + +/// A parser for identifying and parsing Xcode projects or workspaces into a `Graph` model. +/// +/// `ProjectParser` determines whether a given path points to a `.xcworkspace`, `.xcodeproj`, +/// or a directory containing one. It then uses a `GraphMapper` to build a unified `Graph` model +/// from the discovered projects. The resulting `Graph` can be employed for a wide range of tasks: +/// dependency analysis, code generation, custom tooling integration, and more. +public struct ProjectParser: ProjectParsing { + private let fileManager: FileManager + + /// Creates a new `ProjectParser`. + /// + /// - Parameter fileManager: The file manager to use for file system queries. Defaults to `.default`. + public init(fileManager: FileManager = .default) { + self.fileManager = fileManager + } + + public func parse(at path: String) throws -> Graph { + guard fileManager.fileExists(atPath: path) else { + throw ProjectParserError.pathNotFound(path: path) + } + + let absolutePath = try AbsolutePath(validating: path) + let type = try determineProjectType(at: absolutePath) + return try parse(projectType: type) + } + + // MARK: - Internal Helpers + + func parse(projectType: ProjectType) throws -> Graph { + switch projectType { + case let .workspace(path): + return try mapXCWorkspace(at: path) + case let .xcodeProject(path): + return try mapXcodeProj(at: path) + } + } + + func determineProjectType(at path: AbsolutePath) throws -> ProjectType { + switch path.fileExtension { + case .xcworkspace: + return .workspace(path) + case .xcodeproj: + return .xcodeProject(path) + default: + return try findProjectInDirectory(at: path) + } + } + + private func mapXcodeProj(at path: AbsolutePath) throws -> Graph { + let graphMapper = GraphMapper(graphType: .project(path)) + return try graphMapper.map() + } + + private func mapXCWorkspace(at path: AbsolutePath) throws -> Graph { + let workspaceProvider = try WorkspaceProvider(xcWorkspacePath: path) + let graphMapper = GraphMapper(graphType: .workspace(workspaceProvider)) + return try graphMapper.map() + } + + private func findProjectInDirectory(at path: AbsolutePath) throws -> ProjectType { + let contents = try fileManager.contentsOfDirectory(atPath: path.pathString) + + if let workspaceName = contents.first(where: { $0.lowercased().hasSuffix(".xcworkspace") }) { + return .workspace(path.appending(component: workspaceName)) + } + + if let projectName = contents.first(where: { $0.lowercased().hasSuffix(".xcodeproj") }) { + return .xcodeProject(path.appending(component: projectName)) + } + + throw ProjectParserError.noProjectsFound(path: path.pathString) + } +} diff --git a/Sources/XcodeProjMapper/Utilities/ConfigurationMatcher.swift b/Sources/XcodeProjMapper/Utilities/ConfigurationMatcher.swift new file mode 100644 index 00000000..ff325dfa --- /dev/null +++ b/Sources/XcodeProjMapper/Utilities/ConfigurationMatcher.swift @@ -0,0 +1,54 @@ +import Foundation +import XcodeGraph + +/// A protocol defining methods for determining the variant of a build configuration +/// and validating configuration names. +protocol ConfigurationMatching { + /// Returns the build configuration variant for a given configuration name. + /// + /// This method checks for keywords that identify known variants and defaults to `.debug` if none match. + /// + /// - Parameter name: The name of the build configuration. + /// - Returns: The determined `BuildConfiguration.Variant` for the given name. + func variant(for name: String) -> BuildConfiguration.Variant + + /// Validates that a configuration name is non-empty and contains no whitespace. + /// + /// - Parameter name: The configuration name to validate. + /// - Returns: `true` if the name is valid; `false` otherwise. + func validateConfigurationName(_ name: String) -> Bool +} + +/// A concrete implementation of `ConfigurationMatching` that uses predefined keyword patterns +/// to determine configuration variants. +struct ConfigurationMatcher: ConfigurationMatching { + /// Represents a pattern mapping a set of keywords to a configuration variant. + struct Pattern { + let keywords: Set + let variant: BuildConfiguration.Variant + } + + /// Common patterns for identifying build configuration variants. + let patterns: [Pattern] + + /// Initializes a new `ConfigurationMatcher` with default patterns. + /// + /// - Parameter patterns: An optional array of `Pattern` to override defaults. + init(patterns: [Pattern]? = nil) { + self.patterns = patterns ?? [ + Pattern(keywords: ["debug", "development", "dev"], variant: .debug), + Pattern(keywords: ["release", "prod", "production"], variant: .release), + ] + } + + func variant(for name: String) -> BuildConfiguration.Variant { + let lowercased = name.lowercased() + return patterns.first { pattern in + pattern.keywords.contains(where: { lowercased.contains($0) }) + }?.variant ?? .debug + } + + func validateConfigurationName(_ name: String) -> Bool { + !name.isEmpty && name.rangeOfCharacter(from: .whitespaces) == nil + } +} diff --git a/Sources/XcodeProjToGraph/XcodeProjToGraph.docc/Documentation.md b/Sources/XcodeProjMapper/XcodeProjToGraph.docc/Documentation.md similarity index 66% rename from Sources/XcodeProjToGraph/XcodeProjToGraph.docc/Documentation.md rename to Sources/XcodeProjMapper/XcodeProjToGraph.docc/Documentation.md index 7b7359f1..db8ae089 100644 --- a/Sources/XcodeProjToGraph/XcodeProjToGraph.docc/Documentation.md +++ b/Sources/XcodeProjMapper/XcodeProjToGraph.docc/Documentation.md @@ -1,12 +1,12 @@ -# XcodeProjToGraph +# XcodeProjMapper A tool that maps Xcode projects (`.xcodeproj` and `.xcworkspace`) into a structured, analyzable graph of projects, targets, dependencies, and build settings. This enables downstream tasks such as code generation, dependency analysis, and integration with custom tooling pipelines. ## Overview -`XcodeProjToGraph` takes advantage of `XcodeProj` to parse and navigate Xcode project files, then translates them into a domain-specific graph model (`XcodeGraph.Graph`). This model captures all essential components—projects, targets, packages, dependencies, build settings, schemes, and more—providing a high-level, language-agnostic structure for further processing. +`XcodeProjMapper` takes advantage of `XcodeProj` to parse and navigate Xcode project files, then translates them into a domain-specific graph model (`XcodeGraph.Graph`). This model captures all essential components—projects, targets, packages, dependencies, build settings, schemes, and more—providing a high-level, language-agnostic structure for further processing. -By using this graph-based representation, developers can easily analyze project configurations, visualize complex dependency graphs, or integrate advanced workflows into their build pipelines. For example, teams can leverage `XcodeProjToGraph` to: +By using this graph-based representation, developers can easily analyze project configurations, visualize complex dependency graphs, or integrate advanced workflows into their build pipelines. For example, teams can leverage `XcodeProjMapper` to: - Generate code based on discovered resources and targets. - Validate project configurations and detect missing bundle identifiers or invalid references. - Explore dependencies between multiple projects and packages within a workspace. @@ -33,13 +33,5 @@ By using this graph-based representation, developers can easily analyze project - ``WorkspaceProvider`` - ``ProjectProvider`` -### Errors and Diagnostics -- ``MappingError`` -- ``ProcessRunnerError`` -### Advanced Usage - -- ``LipoTool`` -- ``ProcessRunner`` -- ``Executable`` diff --git a/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift b/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift deleted file mode 100644 index 1ab3b14c..00000000 --- a/Sources/XcodeProjToGraph/Extensions/AbsolutePath+Extensions.swift +++ /dev/null @@ -1,96 +0,0 @@ -import Foundation -import Path -import XcodeGraph - -/// Common file extensions encountered in Xcode projects and their associated artifacts. -enum FileExtension: String { - case xcodeproj - case xcworkspace - case framework - case xcframework - case staticLibrary = "a" - case dynamicLibrary = "dylib" - case textBasedDynamicLibrary = "tbd" - case coreData = "xcdatamodeld" - case playground -} - -extension AbsolutePath { - /// Attempts to resolve an array of path strings into `AbsolutePath` instances. - /// - /// - Parameter paths: The string paths to resolve. - /// - Returns: An array of `AbsolutePath` if resolution succeeds. - public static func resolvePaths( - _ paths: [String]? - ) throws -> [AbsolutePath] { - return try paths?.compactMap { try AbsolutePath.resolvePath($0) } ?? [] - } - - /// Attempts to resolve an optional path string into an `AbsolutePath`. - /// - /// - Parameter path: The path string to resolve. - /// - Returns: An `AbsolutePath` or `nil` if the path is `nil`. - public static func resolveOptionalPath( - _ path: String? - ) throws -> AbsolutePath? { - guard let path else { return nil } - return try AbsolutePath.resolvePath(path) - } - - /// Resolves a path string into an `AbsolutePath`, optionally relative to another path. - /// - /// Throws an error if the path is invalid. - public static func resolvePath( - _ path: String, - relativeTo: AbsolutePath? = nil, - file: String = #file, - line: Int = #line, - function: String = #function - ) throws -> AbsolutePath { - do { - if let relativeTo { - return try AbsolutePath(validating: path, relativeTo: relativeTo) - } - return try AbsolutePath(validating: path) - } catch { - let message = """ - Invalid absolute path: '\(path)' - Thrown in \(function) at \(file):\(line) - Original error: \(error) - """ - throw NSError( - domain: "GraphMapperError", code: 1, - userInfo: [NSLocalizedDescriptionKey: message] - ) - } - } - - /// Maps a path by its extension to a `TargetDependency` if applicable. - /// - /// - Parameter condition: Optional platform condition. - /// - Returns: A `TargetDependency` if the extension matches known dependency types. - public func mapByExtension(condition: PlatformCondition?) -> TargetDependency? { - let status: LinkingStatus = .required - let absPath = self - switch absPath.fileExtension { - case .framework: - return .framework(path: absPath, status: status, condition: condition) - case .xcframework: - return .xcframework(path: absPath, status: status, condition: condition) - case .dynamicLibrary, .textBasedDynamicLibrary, .staticLibrary: - return .library( - path: absPath, - publicHeaders: absPath.parentDirectory, - swiftModuleMap: nil, - condition: condition - ) - default: - return nil - } - } - - var fileExtension: FileExtension? { - guard let ext = self.extension?.lowercased() else { return nil } - return FileExtension(rawValue: ext) - } -} diff --git a/Sources/XcodeProjToGraph/Extensions/Sendable+Retroactive.swift b/Sources/XcodeProjToGraph/Extensions/Sendable+Retroactive.swift deleted file mode 100644 index 8886ed78..00000000 --- a/Sources/XcodeProjToGraph/Extensions/Sendable+Retroactive.swift +++ /dev/null @@ -1,16 +0,0 @@ -import XcodeProj - -extension PBXTargetDependency: @unchecked @retroactive Sendable {} -extension XCWorkspace: @unchecked @retroactive Sendable {} -extension PBXBuildRule: @unchecked @retroactive Sendable {} -extension XCScheme: @unchecked @retroactive Sendable {} -extension XCScheme.BuildAction.Entry: @unchecked @retroactive Sendable {} -extension XCScheme.TestableReference: @unchecked @retroactive Sendable {} -extension PBXTarget: @unchecked @retroactive Sendable {} -extension XCRemoteSwiftPackageReference: @unchecked @retroactive Sendable {} -extension XCLocalSwiftPackageReference: @unchecked @retroactive Sendable {} -extension PBXBuildFile: @unchecked @retroactive Sendable {} -extension PBXCopyFilesBuildPhase: @unchecked @retroactive Sendable {} -extension PBXShellScriptBuildPhase: @unchecked @retroactive Sendable {} -extension XcodeProj: @unchecked @retroactive Sendable {} -extension PBXBuildPhase: @unchecked @retroactive Sendable {} diff --git a/Sources/XcodeProjToGraph/Extensions/Sequence+Async.swift b/Sources/XcodeProjToGraph/Extensions/Sequence+Async.swift deleted file mode 100644 index 13cea053..00000000 --- a/Sources/XcodeProjToGraph/Extensions/Sequence+Async.swift +++ /dev/null @@ -1,24 +0,0 @@ -import Foundation - -extension Sequence where Element: Sendable { - func asyncCompactMap(_ transform: @escaping @Sendable (Element) async throws -> T?) - async throws -> [T] - { - var results = [T]() - try await withThrowingTaskGroup(of: T?.self) { group in - for element in self { - group.addTask { - try await transform(element) - } - } - - for try await value in group { - if let value { - results.append(value) - } - } - } - - return results - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift b/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift deleted file mode 100644 index 24398f87..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Build/BuildPhaseMapper.swift +++ /dev/null @@ -1,428 +0,0 @@ -import Foundation -import Path -import XcodeGraph -import XcodeProj - -/// A protocol defining how to map various build phases of a target into domain models. -/// -/// Conformers transform raw Xcode build phase data (from `PBXTarget` and associated `XcodeProj` structures) -/// into typed domain models like `SourceFile`, `ResourceFileElement`, `Headers`, `TargetScript`, and more. -/// -/// This allows downstream tools or processes to work with a structured, semantic representation of the build -/// steps involved in an Xcode target. -protocol BuildPhaseMapping: Sendable { - /// Maps source files from the target's Sources build phase. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `SourceFile` instances representing the target’s source files. - /// - Throws: If file references cannot be resolved or paths are invalid. - func mapSources(target: PBXTarget) async throws -> [SourceFile] - - /// Maps resource files from the target's Resources build phase. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `ResourceFileElement` instances representing the target’s resources. - /// - Throws: If resource references cannot be resolved or paths are invalid. - func mapResources(target: PBXTarget) async throws -> [ResourceFileElement] - - /// Maps headers from the target’s Headers build phase. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: A `Headers` instance if headers are present, or `nil` if none found. - /// - Throws: If header file references cannot be resolved. - func mapHeaders(target: PBXTarget) async throws -> Headers? - - /// Maps scripts from shell script build phases. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `TargetScript` instances representing each shell script build phase. - /// - Throws: If script file references or paths cannot be resolved. - func mapScripts(target: PBXTarget) async throws -> [TargetScript] - - /// Maps copy files build phases. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `CopyFilesAction` instances describing how files are copied at build time. - /// - Throws: If file references or paths cannot be resolved. - func mapCopyFiles(target: PBXTarget) async throws -> [CopyFilesAction] - - /// Maps Core Data models from the target’s resource phases. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `CoreDataModel` instances describing the target’s Core Data models. - /// - Throws: If model paths cannot be resolved. - func mapCoreDataModels(target: PBXTarget) async throws -> [CoreDataModel] - - /// Maps raw script build phases for debugging or analysis. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `RawScriptBuildPhase` instances representing the raw script phases. - func mapRawScriptBuildPhases(target: PBXTarget) async throws -> [RawScriptBuildPhase] - - /// Maps additional files that are not included in any build phase. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `FileElement` for files that are part of the project but not in build phases. - /// - Throws: If file references or paths cannot be resolved. - func mapAdditionalFiles(target: PBXTarget) async throws -> [FileElement] - - /// Maps frameworks referenced by the target’s frameworks build phase. - /// - /// - Parameter target: The Xcode target to map. - /// - Returns: An array of `TargetDependency` instances representing frameworks. - /// - Throws: If framework references or paths cannot be resolved. - func mapFrameworks(target: PBXTarget) async throws -> [TargetDependency] -} - -/// A mapper responsible for converting the build phases of a `PBXTarget` into corresponding domain models. -/// -/// The `BuildPhaseMapper` leverages `ProjectProviding` to resolve file paths and uses XcodeProj’s APIs to -/// navigate build phases (sources, resources, headers, scripts, copy files, and frameworks). -/// -/// By producing strongly-typed domain models (`SourceFile`, `ResourceFileElement`, `Headers`, `TargetScript`, -/// etc.), it enables subsequent steps (like code generation, analysis, or custom tooling) to operate on a well-structured, -/// semantic representation of the target’s build phases. -public final class BuildPhaseMapper: BuildPhaseMapping { - private let projectProvider: ProjectProviding - - /// Creates a new `BuildPhaseMapper`. - /// - /// - Parameter projectProvider: Provides access to the project’s paths, files, and parsed structures. - public init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - } - - public func mapSources(target: PBXTarget) async throws -> [SourceFile] { - guard let sourcesPhase = try target.sourcesBuildPhase() else { return [] } - return try await sourcesPhase.files?.asyncCompactMap { try await self.mapSourceFile($0) } - .sorted { $0.path < $1.path } ?? [] - } - - public func mapResources(target: PBXTarget) async throws -> [ResourceFileElement] { - guard let resourcesPhase = try target.resourcesBuildPhase() else { return [] } - var resources = [ResourceFileElement]() - for buildFile in resourcesPhase.files ?? [] { - let resourceElements = try await mapResourceElement(buildFile) - resources.append(contentsOf: resourceElements) - } - return resources.sorted { $0.path < $1.path } - } - - public func mapHeaders(target: PBXTarget) async throws -> Headers? { - guard let headersPhase = try target.headersBuildPhase() else { return nil } - - var publicHeaders = [AbsolutePath]() - var privateHeaders = [AbsolutePath]() - var projectHeaders = [AbsolutePath]() - - for buildFile in headersPhase.files ?? [] { - if let headerInfo = try await mapHeaderFile(buildFile) { - switch headerInfo.visibility { - case .public: publicHeaders.append(headerInfo.path) - case .private: privateHeaders.append(headerInfo.path) - case .project: projectHeaders.append(headerInfo.path) - } - } - } - - return Headers( - public: publicHeaders, - private: privateHeaders, - project: projectHeaders - ) - } - - public func mapScripts(target: PBXTarget) async throws -> [TargetScript] { - let scriptPhases = target.buildPhases.compactMap { $0 as? PBXShellScriptBuildPhase } - return try await scriptPhases.asyncCompactMap { try await self.mapScriptPhase($0, in: target) } - } - - public func mapCopyFiles(target: PBXTarget) async throws -> [CopyFilesAction] { - let copyFilesPhases = target.buildPhases.compactMap { $0 as? PBXCopyFilesBuildPhase } - return try await copyFilesPhases.asyncCompactMap { try await self.mapCopyFilesPhase($0) }.sorted { $0.name < $1.name } - } - - public func mapCoreDataModels(target: PBXTarget) async throws -> [CoreDataModel] { - guard let resourcesPhase = try target.resourcesBuildPhase() else { return [] } - return try resourcesPhase.files?.compactMap { try self.mapCoreDataModel($0) } - ?? [] - } - - public func mapRawScriptBuildPhases(target: PBXTarget) async throws -> [RawScriptBuildPhase] { - let scriptPhases = target.runScriptBuildPhases() - return scriptPhases.compactMap { mapShellScriptBuildPhase($0) } - } - - public func mapAdditionalFiles(target: PBXTarget) async throws -> [FileElement] { - let xcodeProj = projectProvider.xcodeProj - guard let pbxProject = xcodeProj.pbxproj.projects.first, - let mainGroup = pbxProject.mainGroup - else { - throw MappingError.noProjectsFound(path: projectProvider.xcodeProjPath.pathString) - } - - let allFiles = try await collectFiles(from: mainGroup) - let filesInBuildPhases = try await getFilesInBuildPhases(target: target) - let additionalFiles = allFiles.subtracting(filesInBuildPhases).sorted() - - return additionalFiles.map { FileElement.file(path: $0) } - } - - public func mapFrameworks(target: PBXTarget) async throws -> [TargetDependency] { - let frameworksPhases = target.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase } - let allFrameworkFiles = frameworksPhases.flatMap { $0.files ?? [] } - return try await allFrameworkFiles.asyncCompactMap { try await self.mapFrameworkDependency($0) } - } - - // MARK: - Private Helpers - - private func mapDstSubfolderSpec(_ subfolderSpec: PBXCopyFilesBuildPhase.SubFolder?) - -> CopyFilesAction.Destination - { - switch subfolderSpec { - case .absolutePath: return .absolutePath - case .productsDirectory: return .productsDirectory - case .wrapper: return .wrapper - case .executables: return .executables - case .resources: return .resources - case .javaResources: return .javaResources - case .frameworks: return .frameworks - case .sharedFrameworks: return .sharedFrameworks - case .sharedSupport: return .sharedSupport - case .plugins: return .plugins - default: return .productsDirectory - } - } - - private func determineScriptOrder(target: PBXTarget, scriptPhase: PBXShellScriptBuildPhase) - -> TargetScript.Order - { - guard let scriptPhaseIndex = target.buildPhases.firstIndex(of: scriptPhase) else { - return .pre - } - if let sourcesPhaseIndex = target.buildPhases.firstIndex(where: { $0.buildPhase == .sources }) { - return scriptPhaseIndex > sourcesPhaseIndex ? .post : .pre - } - return scriptPhaseIndex == 0 ? .pre : .post - } - - private func mapSourceFile(_ buildFile: PBXBuildFile) async throws -> SourceFile? { - guard let fileRef = buildFile.file, - let pathString = try fileRef.fullPath(sourceRoot: projectProvider.sourcePathString) - else { return nil } - - let absPath = try AbsolutePath.resolvePath(pathString) - let settings = buildFile.settings ?? [:] - let compilerFlags: String? = settings.string(for: .compilerFlags) - let attributes: [String]? = settings.stringArray(for: .attributes) - - return SourceFile( - path: absPath, - compilerFlags: compilerFlags, - codeGen: mapCodeGenAttribute(attributes) - ) - } - - private func mapCopyFilesPhase(_ phase: PBXCopyFilesBuildPhase) async throws -> CopyFilesAction? { - let files = - try await phase.files?.asyncCompactMap { buildFile -> CopyFileElement? in - guard let fileRef = buildFile.file, - let pathString = try fileRef.fullPath( - sourceRoot: self.projectProvider.sourcePathString - ) - else { return nil } - - let absolutePath = try AbsolutePath.resolvePath(pathString) - let attributes: [String]? = buildFile.settings?.stringArray(for: .attributes) - let codeSignOnCopy = - attributes?.contains(BuildFileAttribute.codeSignOnCopy.rawValue) ?? false - - return .file(path: absolutePath, condition: nil, codeSignOnCopy: codeSignOnCopy) - } ?? [] - - return CopyFilesAction( - name: phase.name ?? BuildPhaseConstants.copyFilesDefault, - destination: mapDstSubfolderSpec(phase.dstSubfolderSpec), - subpath: phase.dstPath.flatMap { $0.isEmpty ? nil : $0 }, - files: files.sorted { $0.path < $1.path } - ) - } - - private func getFilesInBuildPhases(target: PBXTarget) async throws -> Set { - return Set( - try await target.buildPhases.asyncCompactMap { $0.files } - .flatMap { $0 } - .asyncCompactMap { buildFile -> AbsolutePath? in - guard let fileRef = buildFile.file, - let filePath = try fileRef.fullPath( - sourceRoot: self.projectProvider.sourcePathString - ) - else { - return nil - } - return try AbsolutePath.resolvePath(filePath) - } - ) - } - - private func mapResourceElement(_ buildFile: PBXBuildFile) async throws -> [ResourceFileElement] { - guard let file = buildFile.file else { return [] } - if let variantGroup = file as? PBXVariantGroup { - return try await mapVariantGroup(variantGroup) - } else { - return try await mapResourceElement(file) - } - } - - private func mapResourceElement(_ fileElement: PBXFileElement) async throws -> [ResourceFileElement] { - if let pathString = try fileElement.fullPath(sourceRoot: projectProvider.sourcePathString) { - let absPath = try AbsolutePath.resolvePath(pathString) - return [.file(path: absPath)] - } - return [] - } - - private func mapVariantGroup(_ variantGroup: PBXVariantGroup) async throws - -> [ResourceFileElement] - { - var elements = [ResourceFileElement]() - for child in variantGroup.children { - let childFiles = try await mapResourceElement(child) - elements.append(contentsOf: childFiles) - } - return elements - } - - private func collectFiles(from group: PBXGroup) async throws -> Set { - var files = Set() - for child in group.children { - if let file = child as? PBXFileReference, - let pathString = try file.fullPath(sourceRoot: projectProvider.sourcePathString), - let absPath = try? AbsolutePath.resolvePath(pathString) - { - files.insert(absPath) - } else if let subgroup = child as? PBXGroup { - files.formUnion(try await collectFiles(from: subgroup)) - } - } - return files - } - - private func mapFrameworkDependency(_ buildFile: PBXBuildFile) async throws -> TargetDependency? { - guard let fileRef = buildFile.file, - let filePath = try fileRef.fullPath( - sourceRoot: projectProvider.sourceDirectory.pathString - ) - else { return nil } - - let absPath = try AbsolutePath.resolvePath(filePath) - return absPath.mapByExtension(condition: nil) - } - - private func mapHeaderFile(_ buildFile: PBXBuildFile) async throws -> HeaderInfo? { - guard let pbxElement = buildFile.file, - let pathString = try pbxElement.fullPath(sourceRoot: projectProvider.sourcePathString) - else { return nil } - - let attributes: [String]? = buildFile.settings?.stringArray(for: .attributes) - let absolutePath = try AbsolutePath.resolvePath(pathString) - - let visibility: HeaderInfo.HeaderVisibility - if attributes?.contains(HeaderAttribute.public.rawValue) == true { - visibility = .public - } else if attributes?.contains(HeaderAttribute.private.rawValue) == true { - visibility = .private - } else { - visibility = .project - } - - return HeaderInfo(path: absolutePath, visibility: visibility) - } - - private func mapScriptPhase(_ scriptPhase: PBXShellScriptBuildPhase, in target: PBXTarget) - async throws -> TargetScript? - { - guard let shellScript = scriptPhase.shellScript else { return nil } - - return TargetScript( - name: scriptPhase.name ?? BuildPhaseConstants.defaultScriptName, - order: determineScriptOrder(target: target, scriptPhase: scriptPhase), - script: .embedded(shellScript), - inputPaths: scriptPhase.inputPaths, - inputFileListPaths: try AbsolutePath.resolvePaths(scriptPhase.inputFileListPaths), - outputPaths: scriptPhase.outputPaths, - outputFileListPaths: try AbsolutePath.resolvePaths(scriptPhase.outputFileListPaths), - showEnvVarsInLog: scriptPhase.showEnvVarsInLog, - basedOnDependencyAnalysis: scriptPhase.alwaysOutOfDate ? false : nil, - runForInstallBuildsOnly: scriptPhase.runOnlyForDeploymentPostprocessing, - shellPath: scriptPhase.shellPath ?? BuildPhaseConstants.defaultShellPath, - dependencyFile: try AbsolutePath.resolveOptionalPath(scriptPhase.dependencyFile) - ) - } - - private func mapShellScriptBuildPhase(_ buildPhase: PBXShellScriptBuildPhase) - -> RawScriptBuildPhase - { - let name = buildPhase.name() ?? BuildPhaseConstants.unnamedScriptPhase - let shellPath = buildPhase.shellPath ?? BuildPhaseConstants.defaultShellPath - let script = buildPhase.shellScript ?? "" - let showEnvVarsInLog = buildPhase.showEnvVarsInLog - - return RawScriptBuildPhase( - name: name, - script: script, - showEnvVarsInLog: showEnvVarsInLog, - hashable: false, - shellPath: shellPath - ) - } - - private func mapCoreDataModel(_ buildFile: PBXBuildFile) throws -> CoreDataModel? { - guard let versionGroup = buildFile.file as? XCVersionGroup, - versionGroup.path?.hasSuffix(FileExtension.coreData.rawValue) == true, - let modelPathString = try versionGroup.fullPath(sourceRoot: projectProvider.sourcePathString) - else { - return nil - } - - let absModelPath = try AbsolutePath.resolvePath(modelPathString) - let versions = versionGroup.children.compactMap(\.path) - let validatedVersions = try versions.map { - try AbsolutePath.resolvePath($0, relativeTo: absModelPath) - } - let currentVersion = - versionGroup.currentVersion?.path ?? validatedVersions.first?.pathString ?? "" - - return CoreDataModel( - path: absModelPath, - versions: validatedVersions, - currentVersion: currentVersion - ) - } - - private func mapCodeGenAttribute(_ attributes: [String]?) -> FileCodeGen? { - guard let attributes else { return nil } - - if attributes.contains(FileCodeGen.public.rawValue) { - return .public - } else if attributes.contains(FileCodeGen.private.rawValue) { - return .private - } else if attributes.contains(FileCodeGen.project.rawValue) { - return .project - } else if attributes.contains(FileCodeGen.disabled.rawValue) { - return .disabled - } - return nil - } -} - -private struct HeaderInfo { - let path: AbsolutePath - let visibility: HeaderVisibility - - enum HeaderVisibility { - case `public` - case `private` - case project - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Build/BuildRuleMapper.swift b/Sources/XcodeProjToGraph/Mappers/Build/BuildRuleMapper.swift deleted file mode 100644 index 377761f6..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Build/BuildRuleMapper.swift +++ /dev/null @@ -1,63 +0,0 @@ -import Foundation -import Path -import XcodeGraph -@preconcurrency import XcodeProj - -/// A protocol defining how to map `PBXBuildRule` instances into `BuildRule` domain models. -/// -/// Conforming types transform build rules defined in Xcode projects into a structured `BuildRule` model, -/// enabling further analysis or code generation steps to operate on a well-defined representation of these rules. -protocol BuildRuleMapping: Sendable { - /// Maps the build rules of a given `PBXTarget` into an array of `BuildRule` models. - /// - /// - Parameter target: The `PBXTarget` whose build rules are to be mapped. - /// - Returns: An array of `BuildRule` models representing the target’s build rules. - /// - Throws: If resolving or mapping any of the build rules fails. - func mapBuildRules(target: PBXTarget) async throws -> [BuildRule] -} - -/// A mapper that converts `PBXBuildRule` objects into `BuildRule` domain models. -/// -/// `BuildRuleMapper` attempts to translate each `PBXBuildRule` into a `BuildRule` by resolving -/// the compiler specification and file type. If a rule references an unknown compiler spec or -/// file type, that particular rule is skipped. -final class BuildRuleMapper: BuildRuleMapping { - public func mapBuildRules(target: PBXTarget) async throws -> [BuildRule] { - return try await target.buildRules.asyncCompactMap { pbxBuildRule in - guard let compilerSpec = self.mapCompilerSpec(pbxBuildRule.compilerSpec), - let fileType = self.mapFileType(pbxBuildRule.fileType) - else { - // Unknown compiler spec or file type encountered. Skipping this build rule. - return nil - } - - return BuildRule( - compilerSpec: compilerSpec, - fileType: fileType, - filePatterns: pbxBuildRule.filePatterns, - name: pbxBuildRule.name, - outputFiles: pbxBuildRule.outputFiles, - inputFiles: pbxBuildRule.inputFiles, - outputFilesCompilerFlags: pbxBuildRule.outputFilesCompilerFlags, - script: pbxBuildRule.script, - runOncePerArchitecture: pbxBuildRule.runOncePerArchitecture - ) - } - } - - /// Maps a compiler specification string to a `BuildRule.CompilerSpec`. - /// - /// - Parameter compilerSpec: The compiler specification string from the `PBXBuildRule`. - /// - Returns: A `BuildRule.CompilerSpec` instance if recognized; otherwise, `nil`. - public func mapCompilerSpec(_ compilerSpec: String) -> BuildRule.CompilerSpec? { - BuildRule.CompilerSpec(rawValue: compilerSpec) - } - - /// Maps a file type string to a `BuildRule.FileType`. - /// - /// - Parameter fileType: The file type string from the `PBXBuildRule`. - /// - Returns: A `BuildRule.FileType` instance if recognized; otherwise, `nil`. - public func mapFileType(_ fileType: String) -> BuildRule.FileType? { - BuildRule.FileType(rawValue: fileType) - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift deleted file mode 100644 index 5186bf4f..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Dependency/DependencyMapper.swift +++ /dev/null @@ -1,189 +0,0 @@ -import Foundation -import Path -import XcodeGraph -@preconcurrency import XcodeProj - -/// A protocol that defines how to map `PBXTargetDependency` instances into `TargetDependency` domain models. -/// -/// Conforming types resolve various dependency references—such as direct targets, packages, or proxy references— -/// and translate them into a consistent `TargetDependency` representation. This enables downstream operations -/// like graph analysis, code generation, or dependency visualization to work from a uniform model of dependencies. -protocol DependencyMapping: Sendable { - /// Maps all dependencies of a given `PBXTarget` into an array of `TargetDependency` models. - /// - /// - Parameter target: The `PBXTarget` whose dependencies are to be mapped. - /// - Returns: An array of `TargetDependency` models representing the target's dependencies. - /// - Throws: If any dependency cannot be resolved or mapped correctly. - func mapDependencies(target: PBXTarget) async throws -> [TargetDependency] -} - -/// A protocol that defines how to map a single `PBXTargetDependency` into a `TargetDependency` model. -/// -/// Different implementations may specialize in certain types of dependencies (e.g., direct targets, package products, -/// or proxy references). The `DependencyMapper` uses multiple `DependencyTypeMapper` instances in sequence to attempt -/// resolving each dependency. -protocol DependencyTypeMapper: Sendable { - /// Maps a single `PBXTargetDependency` into a `TargetDependency` model. - /// - /// - Parameter dependency: The `PBXTargetDependency` to map. - /// - Returns: A `TargetDependency` model if the dependency can be resolved by this mapper, or `nil` if not. - /// - Throws: If mapping fails due to issues like invalid paths or missing targets. - func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? -} - -/// A mapper that orchestrates the mapping of all target dependencies using multiple specialized mappers. -/// -/// `DependencyMapper` tries each registered `DependencyTypeMapper` in turn until it finds one that can map a given -/// `PBXTargetDependency`. This design supports adding new dependency types without modifying a single large mapping function. -/// -/// **Example Usage:** -/// ```swift -/// // Assume you have a ProjectProvider instance for your Xcode project: -/// let projectProvider: ProjectProviding = ... -/// -/// // Create a DependencyMapper to handle dependencies in a target. -/// let dependencyMapper = DependencyMapper(projectProvider: projectProvider) -/// -/// // Retrieve a PBXTarget from your XcodeProj: -/// let pbxTarget: PBXTarget = ... -/// -/// // Map all dependencies of the PBXTarget into TargetDependency models: -/// let targetDependencies = try await dependencyMapper.mapDependencies(target: pbxTarget) -/// -/// // 'targetDependencies' now contains a uniform list of dependencies (targets, packages, frameworks, etc.) -/// // which can be analyzed, transformed, or used for code generation. -/// ``` -/// -/// This straightforward integration lets you focus on what to do with the resolved dependencies, -/// rather than the nuances of resolving them from Xcode's project structure. -public final class DependencyMapper: DependencyMapping { - private let projectProvider: ProjectProviding - private let typeMappers: [DependencyTypeMapper] - - /// Creates a new `DependencyMapper` with a given project provider. - /// - /// - Parameter projectProvider: Provides access to the project's directories, files, and parsed structures. - init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - typeMappers = [ - DirectTargetMapper(), - PackageProductMapper(), - ProxyDependencyMapper(projectProvider: projectProvider), - ] - } - - public func mapDependencies(target: PBXTarget) async throws -> [TargetDependency] { - return try await target.dependencies.asyncCompactMap { [typeMappers] dependency in - for mapper in typeMappers { - if let mapped = try await mapper.mapDependency(dependency) { - return mapped - } - } - return nil - } - } -} - -/// A mapper that handles direct target dependencies, translating them into `.target` `TargetDependency` models. -final class DirectTargetMapper: DependencyTypeMapper { - public func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? { - guard let target = dependency.target else { return nil } - let condition = PlatformConditionMapper.mapCondition(dependency: dependency) - return .target(name: target.name, status: .required, condition: condition) - } -} - -/// A mapper that handles package product dependencies, converting them into `.package` `TargetDependency` models. -final class PackageProductMapper: DependencyTypeMapper { - public func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? { - guard let product = dependency.product else { return nil } - let condition = PlatformConditionMapper.mapCondition(dependency: dependency) - return .package( - product: product.productName, - type: .runtime, - condition: condition - ) - } -} - -/// A mapper that resolves proxy dependencies, which may point to native targets in other projects or file references. -/// -/// Depending on the proxy type, this mapper may return a `.target` or `.project` dependency, or file-based dependencies. -final class ProxyDependencyMapper: DependencyTypeMapper { - private let projectProvider: ProjectProviding - private let fileMapper: FileDependencyMapper - - init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - fileMapper = FileDependencyMapper(projectProvider: projectProvider) - } - - public func mapDependency(_ dependency: PBXTargetDependency) async throws -> TargetDependency? { - guard let targetProxy = dependency.targetProxy, - let proxyType = targetProxy.proxyType - else { return nil } - - let condition = PlatformConditionMapper.mapCondition(dependency: dependency) - - switch proxyType { - case .nativeTarget: - return try await mapNativeTargetProxy(targetProxy, condition: condition) - case .reference: - return try await mapReferenceProxy(targetProxy, condition: condition) - default: - return nil - } - } - - private func mapNativeTargetProxy( - _ targetProxy: PBXContainerItemProxy, - condition: PlatformCondition? - ) async throws -> TargetDependency? { - guard let remoteInfo = targetProxy.remoteInfo else { return nil } - - switch targetProxy.containerPortal { - case .project: - return .target(name: remoteInfo, status: .required, condition: condition) - case let .fileReference(fileReference): - guard let projectRelativePath = fileReference.path else { return nil } - let fullPath = projectProvider.sourceDirectory.pathString + projectRelativePath - let absPath = try AbsolutePath.resolvePath(fullPath) - return .project( - target: remoteInfo, - path: absPath, - status: .required, - condition: condition - ) - case .unknownObject: - return nil - } - } - - private func mapReferenceProxy( - _ targetProxy: PBXContainerItemProxy, - condition: PlatformCondition? - ) async throws -> TargetDependency? { - guard let remoteGlobalID = targetProxy.remoteGlobalID else { return nil } - - switch remoteGlobalID { - case let .object(object): - if let fileReference = object as? PBXFileReference { - // If `fileMapper.mapDependency` returns nil, it means this file type - // doesn't map to a known `TargetDependency` (e.g., unsupported extension). - return try await fileMapper.mapDependency( - pathString: fileReference.path, - condition: condition - ) - } else if let referenceProxy = object as? PBXReferenceProxy { - // Similarly, nil here indicates that the referenced file isn't a supported dependency type. - return try await fileMapper.mapDependency( - pathString: referenceProxy.path, - condition: condition - ) - } - return nil - case .string: - return nil - } - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/FileDependencyMapper.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/FileDependencyMapper.swift deleted file mode 100644 index 7deb2c7d..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Dependency/FileDependencyMapper.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Path -import XcodeGraph -import XcodeProj - -/// A helper responsible for mapping file-based dependencies (like frameworks or libraries) into `TargetDependency` models. -final class FileDependencyMapper: Sendable { - private let projectProvider: ProjectProviding - - init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - } - - public func mapDependency(pathString: String?, condition: PlatformCondition?) async throws - -> TargetDependency? - { - guard let pathString else { return nil } - let validatedPath = projectProvider.sourceDirectory.appending( - try RelativePath(validating: pathString) - ) - let absPath = try AbsolutePath.resolvePath(validatedPath.pathString) - return absPath.mapByExtension(condition: condition) - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift b/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift deleted file mode 100644 index f2b8e132..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Dependency/TargetDependency+GraphMapping.swift +++ /dev/null @@ -1,272 +0,0 @@ -import Foundation -import Path -import XcodeGraph -import XcodeProj - -extension TargetDependency { - /// Converts a `TargetDependency` into a corresponding `GraphDependency` model, - /// resolving any additional details (like linking types, binary paths, or architectures) - /// based on the dependency type. - /// - /// This method leverages information like the source directory and an all-targets map to - /// resolve project-based target dependencies and to construct the correct `GraphDependency` - /// variant (e.g., frameworks, libraries, SDKs, packages, etc.). - /// - /// - Parameters: - /// - sourceDirectory: The root directory from which to resolve relative paths. - /// - allTargetsMap: A dictionary mapping target names to `Target` models, used to - /// resolve project-based dependencies. - /// - Returns: A `GraphDependency` model representing this dependency. - /// - Throws: If a project-based dependency cannot be resolved (e.g., target not found). - public func graphDependency( - sourceDirectory: AbsolutePath, - allTargetsMap: [String: Target] - ) async throws -> GraphDependency { - switch self { - case let .target(name, status, _): - return .target(name: name, path: sourceDirectory, status: status) - - case let .project(targetName, projectPath, status, _): - return try mapProjectGraphDependency( - projectPath: projectPath, - targetName: targetName, - status: status, - allTargetsMap: allTargetsMap - ) - - case let .framework(path, status, _): - let binaryPath = path.appending(component: "\(name)") - let architectures = (try? await LipoTool.archs(paths: [binaryPath.pathString]).architectures) ?? [] - return .framework( - path: path, - binaryPath: binaryPath, - dsymPath: nil, - bcsymbolmapPaths: [], - linking: .dynamic, - architectures: architectures, - status: status - ) - - case let .xcframework(path, status, _): - return .xcframework( - GraphDependency.XCFramework( - path: path, - infoPlist: .test(), - linking: .dynamic, - mergeable: false, - status: status, - macroPath: nil, - swiftModules: [], - moduleMaps: [] - ) - ) - - case let .library(path, publicHeaders, swiftModuleMap, _): - let linking: BinaryLinking = { - switch path.fileExtension { - case .staticLibrary: - return .static - case .dynamicLibrary, .textBasedDynamicLibrary: - return .dynamic - default: - // Fallback: If the extension isn't recognized, default to dynamic linking. - // Future maintainers might refine this logic if other file types appear. - return .dynamic - } - }() - let architectures = (try? await LipoTool.archs(paths: [path.pathString]).architectures) ?? [] - - return .library( - path: path, - publicHeaders: publicHeaders, - linking: linking, - architectures: architectures, - swiftModuleMap: swiftModuleMap - ) - - case let .package(product, type, _): - return .packageProduct( - path: sourceDirectory, - product: product, - type: type.graphPackageType - ) - - case let .sdk(name, status, _): - return .sdk( - name: name, - path: sourceDirectory, - status: status, - source: .developer - ) - - case .xctest: - return .xcframework( - GraphDependency.XCFramework( - path: sourceDirectory, - infoPlist: XCFrameworkInfoPlist.test(), - linking: .dynamic, - mergeable: false, - status: .required, - macroPath: nil, - swiftModules: [], - moduleMaps: [] - ) - ) - } - } - - /// Maps a project-based target dependency into a `GraphDependency` by resolving the target - /// and determining the appropriate dependency type (e.g., framework, library, bundle, app). - /// - /// - Parameters: - /// - projectPath: The absolute path of the project containing the target. - /// - targetName: The name of the target dependency. - /// - status: The linking status of the dependency. - /// - allTargetsMap: A dictionary mapping target names to `Target` models. - /// - Returns: A `GraphDependency` model representing the resolved project target dependency. - /// - Throws: If the target specified by `targetName` is not found in `allTargetsMap`. - public func mapProjectGraphDependency( - projectPath: AbsolutePath, - targetName: String, - status: LinkingStatus, - allTargetsMap: [String: Target] - ) throws -> GraphDependency { - guard let target = allTargetsMap[targetName] else { - throw MappingError.targetNotFound(targetName: targetName, path: projectPath) - } - - let product = target.product - let dependency: GraphDependency - - switch product { - case .framework, .staticFramework: - let linking: BinaryLinking = (product == .staticFramework) ? .static : .dynamic - dependency = .framework( - path: projectPath, - binaryPath: projectPath.appending(component: "\(targetName).framework"), - dsymPath: nil, - bcsymbolmapPaths: [], - linking: linking, - architectures: [], - status: status - ) - - case .staticLibrary, .dynamicLibrary: - let linking: BinaryLinking = (product == .staticLibrary) ? .static : .dynamic - let publicHeadersPath = projectPath.appending(component: "include") - dependency = .library( - path: projectPath.appending( - component: linking == .static - ? "lib\(targetName).a" - : "lib\(targetName).dylib" - ), - publicHeaders: publicHeadersPath, - linking: linking, - architectures: [], - swiftModuleMap: nil - ) - - case .bundle: - dependency = .bundle( - path: projectPath.appending(component: "\(targetName).bundle") - ) - - case .app, .commandLineTool: - dependency = .target( - name: targetName, - path: projectPath, - status: status - ) - - default: - - throw MappingError.unknownDependencyType(name: product.description) - } - - return dependency - } -} - -extension TargetDependency.PackageType { - /// Converts a `TargetDependency.PackageType` into a `GraphDependency.PackageProductType`. - var graphPackageType: GraphDependency.PackageProductType { - switch self { - case .runtime: - return .runtime - case .runtimeEmbedded: - return .runtimeEmbedded - case .plugin: - return .plugin - case .macro: - return .macro - } - } -} - -extension PBXProductType { - /// Maps a `PBXProductType` into a `Product` domain model. - /// - /// - Parameter pbxProductType: The `PBXProductType` to map. - /// - Returns: A `Product` model if known, or `nil` if the product type is unsupported. - func mapProductType() -> Product? { - switch self { - case .application, .messagesApplication, .onDemandInstallCapableApplication: - return .app - - case .framework, .xcFramework: - return .framework - - case .staticFramework: - return .staticFramework - - case .dynamicLibrary: - return .dynamicLibrary - - case .staticLibrary, .metalLibrary: - return .staticLibrary - - case .bundle, .ocUnitTestBundle: - return .bundle - - case .unitTestBundle: - return .unitTests - - case .uiTestBundle: - return .uiTests - - case .appExtension: - return .appExtension - - case .extensionKitExtension, .xcodeExtension: - return .extensionKitExtension - - case .commandLineTool: - return .commandLineTool - - case .messagesExtension: - return .messagesExtension - - case .stickerPack: - return .stickerPackExtension - - case .xpcService: - return .xpc - - case .watchApp, .watch2App, .watch2AppContainer: - return .watch2App - - case .watchExtension, .watch2Extension: - return .watch2Extension - - case .tvExtension: - return .tvTopShelfExtension - - case .systemExtension: - return .systemExtension - - // Unsupported or unknown cases - case .instrumentsPackage, .intentsServiceExtension, .driverExtension, .none: - return nil - } - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift b/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift deleted file mode 100644 index 8fd2a25c..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Graph/GraphMapper.swift +++ /dev/null @@ -1,169 +0,0 @@ -import Foundation -import Path -import PathKit -import XcodeGraph -import XcodeProj - -/// Specifies the type of graph to generate for code analysis or tooling tasks. -/// -/// `GraphType` allows you to choose whether to build a graph from a single project or from an entire workspace: -/// - `.workspace(WorkspaceProviding)`: Constructs a graph from a workspace (potentially containing multiple projects). -/// - `.project(AbsolutePath)`: Constructs a graph from a single project at the given path, treating it as a workspace with one -/// project. -public enum GraphType: Sendable { - case workspace(WorkspaceProviding) - case project(AbsolutePath) -} - -/// A mapper that constructs a complete `XcodeGraph.Graph` from a given workspace or project. -/// -/// `GraphMapper` orchestrates the process of aggregating data from all relevant sources: -/// - Projects (via `ProjectMapper`), -/// - Targets, Packages, and Dependencies (translated into a uniform graph model), -/// - Platform-specific conditions for dependencies (e.g., iOS-only frameworks), -/// -/// The resulting `XcodeGraph.Graph` model can be used for: -/// - Dependency analysis: Understand how targets and packages interrelate. -/// - Code generation: Produce derived artifacts, such as resource accessors or configuration files. -/// - Tooling integration: Serve as input to custom build tools, linters, or visualizers. -/// -/// **Example Usage:** -/// ```swift -/// // Suppose you have a WorkspaceProvider for a workspace: -/// let workspaceProvider: WorkspaceProviding = ... -/// let graphMapper = GraphMapper(graphType: .workspace(workspaceProvider)) -/// -/// // Or, for a single project: -/// let projectPath: AbsolutePath = ... -/// let graphMapper = GraphMapper(graphType: .project(projectPath)) -/// -/// // Construct the graph: -/// let graph = try await graphMapper.xcodeGraph() -/// -/// // 'graph' now contains a unified representation of projects, targets, packages, and dependencies. -/// // You can analyze it, generate code, or integrate it with other developer tools. -/// ``` -public final class GraphMapper: Sendable { - // MARK: - Properties - - private let projectProviderClosure: @Sendable (AbsolutePath) async throws -> ProjectProviding - public let graphType: GraphType - - // MARK: - Initialization - - /// Initializes the mapper with a specified `GraphType` and an optional project provider closure. - /// - /// The `projectProviderClosure` allows for custom logic when creating `ProjectProviding` instances. By default, - /// it initializes a `ProjectProvider` from the given path. - /// - /// - Parameters: - /// - graphType: The type of graph to build (workspace or project). - /// - projectProviderClosure: A closure that returns a `ProjectProviding` instance for a given project path. - /// If not provided, a default closure is used that instantiates a `ProjectProvider` from the given path. - public init( - graphType: GraphType, - projectProviderClosure: @escaping @Sendable (AbsolutePath) async throws -> ProjectProviding = { - let xcodeProj = try XcodeProj(pathString: $0.pathString) - return ProjectProvider(xcodeProjPath: $0, xcodeProj: xcodeProj) - } - ) { - self.graphType = graphType - self.projectProviderClosure = projectProviderClosure - } - - // MARK: - Mapping Logic - - /// Constructs an `XcodeGraph.Graph` by mapping all projects, packages, and dependencies from the specified workspace or - /// project. - /// - /// This method: - /// 1. Builds a `Workspace` model from either a workspace or a single project. - /// 2. For each project in the workspace, uses `ProjectMapper` to produce a `Project` model. - /// 3. Aggregates all projects, packages, targets, and dependencies into a single `Graph`. - /// 4. Attaches platform conditions to edges, respecting platform-specific dependencies. - /// - /// - Returns: A fully mapped `Graph` containing all discovered projects, packages, dependencies, and conditions. - /// - Throws: If mapping projects, packages, or dependencies fails (e.g., due to missing files or invalid settings). - public func xcodeGraph() async throws -> XcodeGraph.Graph { - var projectProviders = [AbsolutePath: ProjectProviding]() - var projects: [AbsolutePath: Project] = [:] - var packages: [AbsolutePath: [String: Package]] = [:] - var dependencies: [GraphDependency: Set] = [:] - var dependencyConditions: [GraphEdge: PlatformCondition] = [:] - - let workspace = - switch graphType { - case let .workspace(workspaceProvider): - try await WorkspaceMapper(workspaceProvider: workspaceProvider).map() - case let .project(absolutePath): - Workspace( - path: absolutePath.parentDirectory, - xcWorkspacePath: absolutePath.parentDirectory, - name: "Workspace", - projects: [absolutePath] - ) - } - - // Map each project in the workspace - let projectResults = try await workspace.projects.lazy.asyncCompactMap { path in - do { - let provider = try await self.projectProviderClosure(path) - let projectMapper = ProjectMapper(projectProvider: provider) - let project = try await projectMapper.mapProject() - return (path, provider, project) - } catch { - // If one project fails to map, it's skipped. Consider logging this or throwing an error for strict usage. - return nil - } - } - - for (path, provider, project) in projectResults { - projectProviders[path] = provider - projects[path] = project - } - - // Build a map of all targets for easy target-based dependency resolution - let allTargetsMap = Dictionary( - projects.values.flatMap(\.targets), - uniquingKeysWith: { existing, _ in existing } - ) - - // Process dependencies for each project and target - for (path, project) in projects { - if !project.packages.isEmpty { - packages[path] = Dictionary(uniqueKeysWithValues: project.packages.map { ($0.url, $0) }) - } - - for (name, target) in project.targets { - let sourceDependency = GraphDependency.target(name: name, path: path.parentDirectory) - let edgesAndDependencies = try await target.dependencies.asyncCompactMap { targetDep in - let graphDep = try await targetDep.graphDependency( - sourceDirectory: path.parentDirectory, - allTargetsMap: allTargetsMap - ) - let edge = GraphEdge(from: sourceDependency, to: graphDep) - return (edge, targetDep.condition, graphDep) - } - - for (edge, condition, _) in edgesAndDependencies { - dependencyConditions[edge] = condition - } - - let targetDependencies = edgesAndDependencies.compactMap(\.2) - guard !targetDependencies.isEmpty else { continue } - dependencies[sourceDependency] = Set(targetDependencies) - } - } - - // Return the assembled graph - return Graph( - name: workspace.name, - path: workspace.path, - workspace: workspace, - projects: projects, - packages: packages, - dependencies: dependencies, - dependencyConditions: dependencyConditions - ) - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift b/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift deleted file mode 100644 index e14231fc..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Graph/MappingError.swift +++ /dev/null @@ -1,73 +0,0 @@ -import Foundation -import Path - -/// Represents errors that may occur during project or dependency mapping processes. -public enum MappingError: Error, LocalizedError, Equatable { - // MARK: - Project Mapping Errors - - /// The provided path does not exist. - case pathNotFound(path: String) - - /// The provided project type is unknown. - case unknownProjectType(path: String) - - /// No projects were found in the Xcode project file. - case noProjectsFound(path: String) - - /// The main files group is missing for a target. - case missingFilesGroup(targetName: String) - - /// The merged binary type for a target is missing. - case missingMergedBinaryType - - /// The repository URL is missing from the package reference. - case missingRepositoryURL(packageName: String) - - /// A generic mapping error with a message. - case generic(String) - - // MARK: - Target Mapping Errors - - /// The bundle identifier is missing from the build settings of a target. - case missingBundleIdentifier(targetName: String) - - /// The specified target could not be found. - case targetNotFound(targetName: String, path: AbsolutePath) - - // MARK: - Dependency Mapping Errors - - /// A required framework dependency was not found. - case frameworkNotFound(name: String, path: AbsolutePath) - - /// An unknown dependency type was encountered. - case unknownDependencyType(name: String) - - // MARK: - Error Descriptions - - public var errorDescription: String? { - switch self { - case let .pathNotFound(path): - return "The specified path does not exist: \(path)" - case let .unknownProjectType(path): - return "The project type for the path '\(path)' could not be determined." - case let .noProjectsFound(path): - return "No Xcode projects were found at: \(path)" - case let .missingFilesGroup(targetName): - return "The files group is missing for the target '\(targetName)'." - case .missingMergedBinaryType: - return "The merged binary type is missing for the target." - case let .missingRepositoryURL(packageName): - return "The repository URL is missing for the package '\(packageName)'." - case let .generic(message): - return message - case let .missingBundleIdentifier(targetName): - return "The bundle identifier is missing for the target '\(targetName)'." - case let .targetNotFound(targetName, path): - return "The target '\(targetName)' could not be found in the project at path: \(path.pathString)." - case let .frameworkNotFound(name, path): - return "The required framework '\(name)' was not found at path: \(path.pathString)." - case let .unknownDependencyType(name): - return "An unknown dependency type '\(name)' was encountered." - } - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift b/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift deleted file mode 100644 index aedc50e6..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Graph/ProjectParser.swift +++ /dev/null @@ -1,145 +0,0 @@ -import Foundation -import Path -import XcodeGraph -import XcodeProj - -/// Specifies the type of project to parse based on the discovered file structure. -/// -/// `ProjectType` is determined by examining the path or directory contents: -/// - `.workspace(path)`: Indicates a `.xcworkspace` is present at the given path. -/// - `.xcodeProject(path)`: Indicates a `.xcodeproj` is present at the given path. -public enum ProjectType { - case workspace(AbsolutePath) - case xcodeProject(AbsolutePath) -} - -/// A parser responsible for identifying and parsing Xcode projects or workspaces into a `Graph` model. -/// -/// `ProjectParser` determines whether the given path points to: -/// - A `.xcworkspace` file -/// - A `.xcodeproj` file -/// - Or a directory containing one of these project types -/// -/// Once the project type is identified, `ProjectParser` delegates the actual mapping to `GraphMapper`, -/// resulting in a unified `Graph` model that includes targets, packages, and dependencies. -/// -/// **Example Usage:** -/// ```swift -/// // Given a file system path, which could be a directory, .xcodeproj, or .xcworkspace: -/// let path = "/path/to/MyApp" -/// -/// do { -/// // Parse the project or workspace at the given path into a Graph. -/// let graph = try await ProjectParser.parse(atPath: path) -/// -/// // 'graph' now contains a comprehensive model of the project's structure, including targets, -/// // dependencies, and associated packages. This can be used for analysis, code generation, or tooling. -/// } catch { -/// // Handle errors such as missing projects or unreadable files. -/// print("Failed to parse project: \(error)") -/// } -/// ``` -public class ProjectParser { - public init() {} - - /// Parses the project or workspace at the given file system path into a `Graph`. - /// - /// Attempts to locate a `.xcworkspace` or `.xcodeproj` at or within the provided path. - /// If both are absent, it throws an error indicating no projects were found. - /// - /// - Parameter path: The file system path to a `.xcworkspace`, `.xcodeproj`, or a directory containing one. - /// - Returns: A `Graph` representing the parsed project structure, including targets, dependencies, and packages. - /// - Throws: - /// - `MappingError.pathNotFound` if the given path does not exist. - /// - `MappingError.noProjectsFound` if no `.xcworkspace` or `.xcodeproj` is located. - /// - Other errors thrown by `GraphMapper` during graph construction. - public static func parse(atPath path: String) async throws -> Graph { - guard FileManager.default.fileExists(atPath: path) else { - throw MappingError.pathNotFound(path: path) - } - - let absolutePath = try AbsolutePath(validating: path) - let type = try determineProjectType(at: absolutePath) - return try await parse(projectType: type) - } - - /// Parses a given `ProjectType` (workspace or project) into a `Graph`. - /// - /// - Parameter projectType: The identified `ProjectType`. - /// - Returns: A `Graph` model representing the parsed structure. - /// - Throws: Any errors encountered during graph mapping, including missing files or invalid configurations. - public static func parse(projectType: ProjectType) async throws -> Graph { - switch projectType { - case let .workspace(path): - return try await mapXCWorkspace(at: path) - case let .xcodeProject(path): - return try await mapXcodeProj(at: path) - } - } - - /// Maps a single `.xcodeproj` at the given path into a `Graph`. - /// - /// This treats the project as a mini-workspace containing a single project, enabling consistent handling by `GraphMapper`. - /// - /// - Parameter path: The absolute path to the `.xcodeproj`. - /// - Returns: A `Graph` model of the project. - /// - Throws: Errors from `GraphMapper` if mapping fails. - public static func mapXcodeProj(at path: AbsolutePath) async throws -> Graph { - let graphMapper = GraphMapper(graphType: .project(path)) - return try await graphMapper.xcodeGraph() - } - - /// Maps a single `.xcworkspace` at the given path into a `Graph`. - /// - /// If the workspace references multiple projects, they are all integrated into a single graph. - /// - /// - Parameter path: The absolute path to the `.xcworkspace`. - /// - Returns: A `Graph` model of the workspace and its contained projects. - /// - Throws: Errors from `GraphMapper` if mapping fails. - public static func mapXCWorkspace(at path: AbsolutePath) async throws -> Graph { - let workspaceProvider = try WorkspaceProvider(xcWorkspacePath: path) - let graphMapper = GraphMapper(graphType: .workspace(workspaceProvider)) - return try await graphMapper.xcodeGraph() - } - - /// Determines the type of project at a given path by inspecting file extensions or directory contents. - /// - /// - Parameter path: The absolute path to check. - /// - Returns: A `ProjectType` representing either a `.workspace` or `.xcodeproj`. - /// - Throws: `MappingError.noProjectsFound` if no recognizable project files are found. - private static func determineProjectType(at path: AbsolutePath) throws -> ProjectType { - switch path.fileExtension { - case .xcworkspace: - return .workspace(path) - case .xcodeproj: - return .xcodeProject(path) - default: - return try findProjectInDirectory(at: path) - } - } - - /// Searches a directory for the first `.xcworkspace` or `.xcodeproj` file. - /// - /// If none are found, `MappingError.noProjectsFound` is thrown. This indicates that the provided directory - /// does not contain a recognizable Xcode project or workspace, and thus cannot be parsed. - /// - /// - Parameter path: The directory path to search. - /// - Returns: A `ProjectType` if a project is found. - /// - Throws: `MappingError.noProjectsFound` if no `.xcworkspace` or `.xcodeproj` is detected. - private static func findProjectInDirectory(at path: AbsolutePath) throws -> ProjectType { - let contents = try FileManager.default.contentsOfDirectory(atPath: path.pathString) - - // Search for a .xcworkspace - if let workspaceName = contents.first(where: { $0.lowercased().hasSuffix(".xcworkspace") }) { - return .workspace(path.appending(component: workspaceName)) - } - - // Search for a .xcodeproj - if let projectName = contents.first(where: { $0.lowercased().hasSuffix(".xcodeproj") }) { - return .xcodeProject(path.appending(component: projectName)) - } - - // No projects found in this directory - throw MappingError.noProjectsFound(path: path.pathString) - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift b/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift deleted file mode 100644 index 161dbf38..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Project/PackageMapper.swift +++ /dev/null @@ -1,99 +0,0 @@ -import Foundation -import Path -import XcodeGraph -import XcodeProj - -/// A protocol defining how to map both remote and local Swift package references into `Package` models. -/// -/// Conforming types provide methods to translate `XCRemoteSwiftPackageReference` and `XCLocalSwiftPackageReference` -/// objects into `Package` instances, resolving URLs, version requirements, and file paths as needed. -protocol PackageMapping: Sendable { - /// Maps a remote Swift package reference to a `Package`. - /// - /// This method inspects the repository URL and version requirement from the provided `XCRemoteSwiftPackageReference` - /// and constructs a `Package` model that can be integrated into the overall project graph. - /// - /// - Parameter package: The remote Swift package reference. - /// - Returns: A `Package` representing the remote package, including its URL and version requirement. - /// - Throws: `MappingError.missingRepositoryURL` if the remote package has no repository URL. - func map(package: XCRemoteSwiftPackageReference) async throws -> Package - - /// Maps a local Swift package reference to a `Package`. - /// - /// This method resolves the provided local package path relative to the project's source directory, - /// constructing a `.local` `Package` model that can be used in the project graph. - /// - /// - Parameter package: The local Swift package reference. - /// - Returns: A `Package` representing the local package, including its resolved filesystem path. - /// - Throws: If the provided path is invalid or cannot be resolved relative to the project's source directory. - func map(package: XCLocalSwiftPackageReference) async throws -> Package -} - -/// A mapper that converts remote and local Swift package references into domain `Package` models. -/// -/// `PackageMapper` uses `ProjectProviding` to resolve paths and retrieves remote package information from -/// `XCRemoteSwiftPackageReference` -/// instances. By extracting repository URLs, version requirements, and local paths, `PackageMapper` produces `Package` -/// models that can be integrated into a broader Xcode project graph. -/// -/// Example usage: -/// ```swift -/// let packageMapper = PackageMapper(projectProvider: provider) -/// let remotePackage = try await packageMapper.map(package: remoteRef) -/// let localPackage = try await packageMapper.map(package: localRef) -/// ``` -public final class PackageMapper: PackageMapping { - private let projectProvider: ProjectProviding - - /// Creates a new `PackageMapper` with the given project provider. - /// - /// - Parameter projectProvider: Provides access to the project's directory structure and metadata, - /// enabling resolution of local package paths and contextual validation. - init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - } - - public func map(package: XCRemoteSwiftPackageReference) async throws -> Package { - guard let repositoryURL = package.repositoryURL else { - throw MappingError.missingRepositoryURL(packageName: package.name ?? "Unknown Package") - } - - let requirement = mapRequirement(package: package) - return .remote(url: repositoryURL, requirement: requirement) - } - - public func map(package: XCLocalSwiftPackageReference) async throws -> Package { - let relativePath = try RelativePath(validating: package.relativePath) - let path = projectProvider.sourceDirectory.appending(relativePath) - return .local(path: path) - } - - /// Maps the version requirement of a remote Swift package to a `Package.Requirement`. - /// - /// By examining the `XCRemoteSwiftPackageReference`'s `versionRequirement`, this method determines the correct - /// versioning scheme (exact, range, branch, revision, or up-to-next-major/minor) and returns a `Requirement` - /// that captures this information. - /// - /// - Parameter package: The `XCRemoteSwiftPackageReference` containing the version requirement. - /// - Returns: A `Package.Requirement` reflecting the specified versioning scheme. - public func mapRequirement(package: XCRemoteSwiftPackageReference) -> Requirement { - guard let versionRequirement = package.versionRequirement else { - return .upToNextMajor("0.0.0") - } - - switch versionRequirement { - case let .upToNextMajorVersion(version): - return .upToNextMajor(version) - case let .upToNextMinorVersion(version): - return .upToNextMinor(version) - case let .exact(version): - return .exact(version) - case let .range(lowerBound, upperBound): - return .range(from: lowerBound, to: upperBound) - case let .branch(branch): - return .branch(branch) - case let .revision(revision): - return .revision(revision) - } - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift b/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift deleted file mode 100644 index 4812a81b..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Project/ProjectMapper.swift +++ /dev/null @@ -1,165 +0,0 @@ -import Foundation -import Path -import PathKit -import XcodeGraph -import XcodeProj - -/// A protocol defining how to map a parsed Xcode project structure into a `Project` domain model. -/// -/// Conforming types should read from a project provider or XcodeProj instance, -/// translating raw build settings, targets, schemes, and packages into a fully realized `Project` model. -protocol ProjectMapping: Sendable { - /// Maps the current project into a `Project` model. - /// - /// This involves assembling project-level settings, targets, packages, schemes, and other metadata into a `Project`. - /// The resulting model can serve as a basis for code generation, analysis, or other tooling operations. - /// - /// - Returns: A fully constructed `Project` model representing the entire project. - /// - Throws: An error if any part of the mapping process fails, such as missing required data or invalid references. - func mapProject() async throws -> Project -} - -/// A mapper responsible for translating a parsed Xcode project into a `Project` model. -/// -/// `ProjectMapper` orchestrates the mapping of all major project components: -/// - Uses `SettingsMapper` to map the project's `XCConfigurationList` into domain-specific settings. -/// - Uses `TargetMapper` to convert `PBXTarget` instances into domain-level `Target` models, including sources, resources, and -/// dependencies. -/// - Uses `PackageMapper` to resolve both remote and local Swift packages. -/// - Uses `SchemeMapper` to identify and incorporate both user and shared schemes. -/// - Integrates resource synthesizers to define code generation strategies for various resource types. -/// -/// **Example Usage:** -/// ```swift -/// // Assume you have a ProjectProvider set up from your `.xcodeproj`. -/// let projectProvider: ProjectProviding = ... -/// -/// // Create a ProjectMapper with the given provider. -/// let projectMapper = ProjectMapper(projectProvider: projectProvider) -/// -/// // Perform the mapping to produce a domain-level Project model. -/// let project = try await projectMapper.mapProject() -/// -/// // 'project' now includes all targets, settings, packages, schemes, and resource synthesizers. -/// // You can use this model for code generation, analyze dependencies, or integrate with other tools. -/// ``` -public final class ProjectMapper: ProjectMapping { - private let projectProvider: ProjectProviding - - /// Initializes the mapper with a given project provider. - /// - /// - Parameter projectProvider: A `ProjectProviding` instance that supplies access - /// to the project's directories, `.xcodeproj` file, and parsed data structures, - /// enabling the mapper to resolve paths, read build settings, and access targets. - public init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - } - - public func mapProject() async throws -> Project { - let settingsMapper = SettingsMapper() - let pbxProject = try projectProvider.pbxProject() - - // Map project-level settings - let settings = try await settingsMapper.map( - projectProvider: projectProvider, - configurationList: pbxProject.buildConfigurationList - ) - - // Map targets into domain-level Target models - let targetMapper = TargetMapper(projectProvider: projectProvider) - let targetsArray = try await pbxProject.targets.asyncCompactMap { pbxTarget in - try await targetMapper.map(pbxTarget: pbxTarget) - } - - // Map packages (both remote and local) - let packageMapper = PackageMapper(projectProvider: projectProvider) - let remotePackages = try await pbxProject.remotePackages.asyncCompactMap { package in - try await packageMapper.map(package: package) - } - let localPackages = try await pbxProject.localPackages.asyncCompactMap { package in - try await packageMapper.map(package: package) - } - - // Determine a files group to organize files logically - let filesGroup = ProjectGroup.group(name: pbxProject.mainGroup?.name ?? "Project") - - // Map schemes, both user and shared, for build and test configurations - let schemeMapper = try SchemeMapper(graphType: .project(projectProvider.sourceDirectory)) - let userSchemes = projectProvider.xcodeProj.userData.flatMap(\.schemes) - let sharedSchemes = projectProvider.xcodeProj.sharedData?.schemes ?? [] - let schemes = - try await schemeMapper.mapSchemesAsync(xcschemes: userSchemes, shared: false) - + (try await schemeMapper.mapSchemesAsync(xcschemes: sharedSchemes, shared: true)) - - // Retrieve the last known Xcode upgrade check version, if available - let lastUpgradeCheck = pbxProject.attribute(for: .lastUpgradeCheck).flatMap { Version(string: $0) } - - // Determine default known regions, if any - let defaultKnownRegions = pbxProject.knownRegions.isEmpty ? nil : pbxProject.knownRegions - - return Project( - path: projectProvider.sourceDirectory, - sourceRootPath: projectProvider.sourceDirectory, - xcodeProjPath: projectProvider.sourceDirectory, - name: pbxProject.name, - organizationName: pbxProject.attribute(for: .organization), - classPrefix: pbxProject.attribute(for: .classPrefix), - defaultKnownRegions: defaultKnownRegions, - developmentRegion: pbxProject.developmentRegion, - options: .init( - automaticSchemesOptions: .disabled, - disableBundleAccessors: false, - disableShowEnvironmentVarsInScriptPhases: false, - disableSynthesizedResourceAccessors: false, - textSettings: .init( - usesTabs: nil, - indentWidth: nil, - tabWidth: nil, - wrapsLines: nil - ) - ), - settings: settings, - filesGroup: filesGroup, - targets: targetsArray.sorted(), - packages: remotePackages + localPackages, - schemes: schemes, - ideTemplateMacros: nil, - additionalFiles: [], - resourceSynthesizers: mapResourceSynthesizers(from: pbxProject), - lastUpgradeCheck: lastUpgradeCheck, - type: .local - ) - } - - /// Maps known resource synthesizer definitions from the given `PBXProject`. - /// - /// Provides a set of default resource synthesizers that cover common resource types (e.g., `.strings`, `.xcassets`, - /// `.plist`). - /// Even if the project doesn't define custom synthesizers, these defaults ensure that downstream tooling always has - /// sensible defaults. - /// - /// - Parameter pbxProject: The `PBXProject` from which resource synthesizer settings are derived. - /// - Returns: An array of `ResourceSynthesizer` instances representing code generation strategies for various resource types. - private func mapResourceSynthesizers(from _: PBXProject) -> [ResourceSynthesizer] { - let resourceTypes: [(parser: ResourceSynthesizer.Parser, extensions: [String], template: String)] = [ - (.strings, ["strings", "stringsdict"], "Strings"), - (.assets, ["xcassets"], "Assets"), - (.plists, ["plist"], "Plists"), - (.fonts, ["ttf", "otf", "ttc"], "Fonts"), - (.coreData, ["xcdatamodeld"], "CoreData"), - (.interfaceBuilder, ["xib", "storyboard"], "InterfaceBuilder"), - (.json, ["json"], "JSON"), - (.yaml, ["yaml", "yml"], "YAML"), - (.files, ["txt", "md"], "Files"), - ] - - return resourceTypes.map { resourceType in - ResourceSynthesizer( - parser: resourceType.parser, - parserOptions: [:], - extensions: Set(resourceType.extensions), - template: .defaultTemplate(resourceType.template) - ) - } - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift b/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift deleted file mode 100644 index 9c2e17e2..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Project/ProjectProvider.swift +++ /dev/null @@ -1,103 +0,0 @@ -import Foundation -import Path -import PathKit -import XcodeGraph -@preconcurrency import XcodeProj - -/// A protocol that defines how to provide access to an Xcode project and its underlying components. -/// -/// Conforming types give you a parsed `XcodeProj` instance, the `.xcodeproj` file path, and the root source directory. -/// They also simplify retrieval of the main `PBXProject`, allowing downstream mappers or analyses to easily navigate -/// and process the project structure. -public protocol ProjectProviding: Sendable { - /// The absolute path to the directory containing the Xcode project. - /// - /// Typically, this is the directory above the `.xcodeproj` file, serving as the project’s source root. - var sourceDirectory: AbsolutePath { get } - - /// The absolute path to the `.xcodeproj` file. - /// - /// This path uniquely identifies the Xcode project file on disk. - var xcodeProjPath: AbsolutePath { get } - - /// The parsed `XcodeProj` instance representing the Xcode project. - /// - /// `XcodeProj` provides structured access to projects, targets, build configurations, groups, and files, - /// enabling advanced analysis or transformation tasks. - var xcodeProj: XcodeProj { get } - - /// Returns the main `PBXProject` object from the `.xcodeproj`. - /// - /// The `PBXProject` object serves as the root for most project-related data, including build configurations, targets, - /// and references to files and groups. - /// - /// - Throws: `MappingError.noProjectsFound` if no projects are found in the `.xcodeproj`. - /// - Returns: A `PBXProject` representing the primary project definition. - func pbxProject() throws -> PBXProject -} - -extension ProjectProviding { - /// A convenience property providing the source directory as a string. - /// - /// Useful for passing to APIs that require string paths instead of `AbsolutePath`. - public var sourcePathString: String { - sourceDirectory.pathString - } - - /// The source directory is assumed to be the parent of the `.xcodeproj` directory. - /// - /// This default implementation infers the source directory from the `xcodeProjPath`, ensuring a consistent - /// project structure. - public var sourceDirectory: AbsolutePath { - xcodeProjPath.parentDirectory - } - - public func pbxProject() throws -> PBXProject { - guard let pbxProject = xcodeProj.pbxproj.projects.first else { - throw MappingError.noProjectsFound(path: xcodeProjPath.pathString) - } - return pbxProject - } -} - -/// A concrete provider that supplies information about a particular Xcode project. -/// -/// `ProjectProvider` encapsulates a `.xcodeproj` file and its parsed `XcodeProj` representation, making it straightforward -/// to integrate with mappers or other tooling that requires consistent access to the project's structure. -/// -/// **Example Usage:** -/// ```swift -/// import XcodeProj -/// -/// // Assume you have an AbsolutePath to the .xcodeproj file. -/// let xcodeProjPath: AbsolutePath = ... -/// -/// // Parse the project using XcodeProj. -/// let xcodeProj = try XcodeProj(pathString: xcodeProjPath.pathString) -/// -/// // Create a ProjectProvider instance. -/// let projectProvider = ProjectProvider(xcodeProjPath: xcodeProjPath, xcodeProj: xcodeProj) -/// -/// // Access the main PBXProject for further analysis: -/// let pbxProject = try projectProvider.pbxProject() -/// -/// // From here, you can iterate targets, fetch build settings, or integrate with other mappers. -/// ``` -public struct ProjectProvider: ProjectProviding { - public let xcodeProj: XcodeProj - public let xcodeProjPath: AbsolutePath - - /// Initializes a new `ProjectProvider` with the given project path and `XcodeProj` instance. - /// - /// - Parameters: - /// - xcodeProjPath: The absolute path to the `.xcodeproj` file. - /// - xcodeProj: The parsed `XcodeProj` instance representing the project. - /// - /// After initialization, `ProjectProvider` can serve as a bridge between `.xcodeproj` structures - /// and higher-level mapping tools (e.g., `ProjectMapper`, `TargetMapper`), providing consistent and - /// convenient access to all project data. - public init(xcodeProjPath: AbsolutePath, xcodeProj: XcodeProj) { - self.xcodeProjPath = xcodeProjPath - self.xcodeProj = xcodeProj - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift b/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift deleted file mode 100644 index 348cd0fa..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Settings/ConfigurationMatcher.swift +++ /dev/null @@ -1,42 +0,0 @@ -import Foundation -import Path -import XcodeGraph -import XcodeProj - -/// A utility that determines the variant of a build configuration (e.g., debug or release) -/// based on naming conventions and validates configuration names. -enum ConfigurationMatcher { - /// Represents a pattern mapping a set of keywords to a configuration variant. - private struct Pattern { - let keywords: Set - let variant: BuildConfiguration.Variant - } - - /// Common patterns for identifying build configuration variants. - private static let patterns: [Pattern] = [ - Pattern(keywords: ["debug", "development", "dev"], variant: .debug), - Pattern(keywords: ["release", "prod", "production"], variant: .release), - ] - - /// Returns the build configuration variant for a given configuration name. - /// - /// This method lowercases the name and checks if it contains any keywords for known variants. - /// If none match, it defaults to `.debug`. - /// - /// - Parameter name: The name of the build configuration. - /// - Returns: The determined `BuildConfiguration.Variant` for the given name. - public static func variant(forName name: String) -> BuildConfiguration.Variant { - let lowercased = name.lowercased() - return patterns.first { pattern in - pattern.keywords.first(where: { lowercased.contains($0) }) != nil - }?.variant ?? .debug - } - - /// Validates that a configuration name is non-empty and contains no whitespace. - /// - /// - Parameter name: The configuration name to validate. - /// - Returns: `true` if the name is valid; `false` otherwise. - public static func validateConfigurationName(_ name: String) -> Bool { - !name.isEmpty && name.rangeOfCharacter(from: .whitespaces) == nil - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift deleted file mode 100644 index 18ff140d..00000000 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/SchemeMapper.swift +++ /dev/null @@ -1,315 +0,0 @@ -import Foundation -import Path -import XcodeGraph -import XcodeProj - -/// A protocol defining how to map `XCScheme` objects and their associated actions into domain `Scheme` models. -/// -/// Conforming types transform raw `XCScheme` instances—along with their build, test, run, archive, profile, -/// and analyze actions—into fully-realized `Scheme` models. This enables further analysis, code generation, -/// or integration with custom tooling based on standardized scheme data. -protocol SchemeMapping: Sendable { - /// Maps an array of `XCScheme` instances into `Scheme` models. - /// - /// - Parameters: - /// - xcschemes: An array of `XCScheme` instances to map. - /// - shared: A Boolean indicating whether these schemes are shared. - /// - Returns: An array of mapped `Scheme` instances representing the provided XCSchemes. - /// - Throws: If any scheme cannot be fully resolved or mapped. - func mapSchemes(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] - - /// Maps a single `XCScheme` into a `Scheme` model. - /// - /// - Parameters: - /// - xcscheme: The `XCScheme` to map. - /// - shared: A Boolean indicating whether the scheme is shared. - /// - Returns: A `Scheme` model corresponding to the given `XCScheme`. - /// - Throws: If any of the scheme's actions (build, test, run, etc.) cannot be resolved. - func mapScheme(xcscheme: XCScheme, shared: Bool) async throws -> Scheme - - /// Maps an `XCScheme.BuildAction` into a `BuildAction` model. - /// - /// - Parameter action: The `XCScheme.BuildAction` to map, if any. - /// - Returns: A `BuildAction` instance, or `nil` if `action` is `nil`. - /// - Throws: If any target references in the build action cannot be resolved. - func mapBuildAction(action: XCScheme.BuildAction?) async throws -> BuildAction? - - /// Maps an `XCScheme.LaunchAction` into a `RunAction` model. - /// - /// - Parameter action: The `XCScheme.LaunchAction` to map, if any. - /// - Returns: A `RunAction` instance, or `nil` if `action` is `nil`. - /// - Throws: If the executable reference cannot be resolved. - func mapRunAction(action: XCScheme.LaunchAction?) async throws -> RunAction? - - /// Maps an `XCScheme.TestAction` into a `TestAction` model. - /// - /// - Parameter action: The `XCScheme.TestAction` to map, if any. - /// - Returns: A `TestAction` instance, or `nil` if `action` is `nil`. - /// - Throws: If any test target references cannot be resolved. - func mapTestAction(action: XCScheme.TestAction?) async throws -> TestAction? - - /// Maps an `XCScheme.ArchiveAction` into an `ArchiveAction` model. - /// - /// - Parameter action: The `XCScheme.ArchiveAction` to map, if any. - /// - Returns: An `ArchiveAction` instance, or `nil` if `action` is `nil`. - func mapArchiveAction(action: XCScheme.ArchiveAction?) async throws -> ArchiveAction? - - /// Maps an `XCScheme.ProfileAction` into a `ProfileAction` model. - /// - /// - Parameter action: The `XCScheme.ProfileAction` to map, if any. - /// - Returns: A `ProfileAction` instance, or `nil` if `action` is `nil`. - func mapProfileAction(action: XCScheme.ProfileAction?) async throws -> ProfileAction? - - /// Maps an `XCScheme.AnalyzeAction` into an `AnalyzeAction` model. - /// - /// - Parameter action: The `XCScheme.AnalyzeAction` to map, if any. - /// - Returns: An `AnalyzeAction` instance, or `nil` if `action` is `nil`. - func mapAnalyzeAction(action: XCScheme.AnalyzeAction?) async throws -> AnalyzeAction? -} - -/// Defines the type of scheme mapper based on the source of the graph. -enum SchemeMapperType { - /// A workspace-based scheme mapper that may have multiple projects. - case workspace(workspacePath: AbsolutePath, pathProviders: [AbsolutePath: ProjectProviding]) - /// A project-based scheme mapper dealing with a single project. - case project(provider: ProjectProviding) -} - -/// A mapper responsible for converting `XCScheme` objects (and related Xcode scheme configurations) -/// into domain `Scheme` models. -/// -/// `SchemeMapper` resolves references to targets, environment variables, launch arguments, and all actions within -/// a scheme (build, test, run, archive, profile, analyze). The resulting `Scheme` models enable consumers -/// to analyze scheme configurations, generate code, or integrate with custom tooling pipelines. -/// -/// **Example Usage:** -/// ```swift -/// // Assume you have determined the graphType (e.g., from a workspace or a single project) -/// let graphType: GraphType = ... -/// -/// // Create a SchemeMapper -/// let schemeMapper = try SchemeMapper(graphType: graphType) -/// -/// // Obtain an array of XCScheme instances (perhaps from XcodeProj's shared or user schemes) -/// let xcschemes: [XCScheme] = ... -/// -/// // Map the schemes into Scheme models -/// let schemes = try await schemeMapper.mapSchemes(xcschemes: xcschemes, shared: true) -/// -/// // 'schemes' now contains a list of domain Scheme models ready for further use. -/// ``` -public final class SchemeMapper: SchemeMapping { - private let graphType: GraphType - - /// Initializes the mapper with the given graph type. - /// - /// - Parameter graphType: The graph type (workspace or project) that influences how target references are resolved. - /// - Throws: `MappingError.noProjectsFound` if required project information is missing. - public init(graphType: GraphType) throws { - self.graphType = graphType - } - - public func mapSchemes(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] { - try await xcschemes.asyncCompactMap { xcscheme in - try await self.mapScheme(xcscheme: xcscheme, shared: shared) - } - } - - public func mapScheme(xcscheme: XCScheme, shared: Bool) async throws -> Scheme { - Scheme( - name: xcscheme.name, - shared: shared, - hidden: false, - buildAction: try await mapBuildAction(action: xcscheme.buildAction), - testAction: try await mapTestAction(action: xcscheme.testAction), - runAction: try await mapRunAction(action: xcscheme.launchAction), - archiveAction: try await mapArchiveAction(action: xcscheme.archiveAction), - profileAction: try await mapProfileAction(action: xcscheme.profileAction), - analyzeAction: try await mapAnalyzeAction(action: xcscheme.analyzeAction) - ) - } - - public func mapBuildAction(action: XCScheme.BuildAction?) async throws -> BuildAction? { - guard let action else { return nil } - - let targets = try await action.buildActionEntries.asyncCompactMap { entry in - let buildableReference = entry.buildableReference - return try await self.mapTargetReference(buildableReference: buildableReference) - } - - return BuildAction( - targets: targets, - preActions: [], - postActions: [], - runPostActionsOnFailure: action.runPostActionsOnFailure ?? false, - findImplicitDependencies: action.buildImplicitDependencies - ) - } - - public func mapTestAction(action: XCScheme.TestAction?) async throws -> TestAction? { - guard let action else { return nil } - - let testTargets = try await action.testables.asyncCompactMap { testable in - let targetReference = try await self.mapTargetReference( - buildableReference: testable.buildableReference - ) - return TestableTarget(target: targetReference, skipped: testable.skipped) - } - - let environmentVariables = - action.environmentVariables?.reduce(into: [String: EnvironmentVariable]()) { dict, variable in - dict[variable.variable] = EnvironmentVariable( - value: variable.value, isEnabled: variable.enabled - ) - } ?? [:] - - let launchArguments = - action.commandlineArguments?.arguments.map { - LaunchArgument(name: $0.name, isEnabled: $0.enabled) - } ?? [] - - let arguments = Arguments( - environmentVariables: environmentVariables, - launchArguments: launchArguments - ) - let diagnosticsOptions = SchemeDiagnosticsOptions(action: action) - - return TestAction( - targets: testTargets, - arguments: arguments, - configurationName: action.buildConfiguration, - attachDebugger: true, - coverage: action.codeCoverageEnabled, - codeCoverageTargets: [], - expandVariableFromTarget: nil, - preActions: [], - postActions: [], - diagnosticsOptions: diagnosticsOptions, - language: action.language, - region: action.region - ) - } - - public func mapRunAction(action: XCScheme.LaunchAction?) async throws -> RunAction? { - guard let action else { return nil } - - let executable: TargetReference? = try await { - if let buildableRef = action.runnable?.buildableReference { - return try await mapTargetReference(buildableReference: buildableRef) - } else { - return nil - } - }() - - let environmentVariables = - action.environmentVariables?.reduce(into: [String: EnvironmentVariable]()) { dict, variable in - dict[variable.variable] = EnvironmentVariable( - value: variable.value, isEnabled: variable.enabled - ) - } ?? [:] - - let launchArguments = - action.commandlineArguments?.arguments.map { - LaunchArgument(name: $0.name, isEnabled: $0.enabled) - } ?? [] - - let arguments = Arguments( - environmentVariables: environmentVariables, - launchArguments: launchArguments - ) - let diagnosticsOptions = SchemeDiagnosticsOptions(action: action) - let attachDebugger = action.selectedDebuggerIdentifier.isEmpty - - return RunAction( - configurationName: action.buildConfiguration, - attachDebugger: attachDebugger, - customLLDBInitFile: nil, - preActions: [], - postActions: [], - executable: executable, - filePath: nil, - arguments: arguments, - options: RunActionOptions(), - diagnosticsOptions: diagnosticsOptions - ) - } - - public func mapArchiveAction(action: XCScheme.ArchiveAction?) async throws -> ArchiveAction? { - guard let action else { return nil } - - return ArchiveAction( - configurationName: action.buildConfiguration, - revealArchiveInOrganizer: action.revealArchiveInOrganizer - ) - } - - public func mapProfileAction(action: XCScheme.ProfileAction?) async throws -> ProfileAction? { - guard let action else { return nil } - - let executable: TargetReference? = try await { - if let buildableRef = action.buildableProductRunnable?.buildableReference { - return try await mapTargetReference(buildableReference: buildableRef) - } else { - return nil - } - }() - - return ProfileAction( - configurationName: action.buildConfiguration, - executable: executable - ) - } - - public func mapAnalyzeAction(action: XCScheme.AnalyzeAction?) async throws -> AnalyzeAction? { - guard let action else { return nil } - return AnalyzeAction(configurationName: action.buildConfiguration) - } - - /// Maps a `XCScheme.BuildableReference` to a `TargetReference`. - /// - /// This step involves resolving the container path and the target name, which differ depending on whether - /// the scheme originates from a workspace or a standalone project. - /// - /// - Parameter buildableReference: The `XCScheme.BuildableReference` to map. - /// - Returns: A `TargetReference` representing the target in the resolved container. - /// - Throws: If the referenced container cannot be resolved. - private func mapTargetReference(buildableReference: XCScheme.BuildableReference) async throws - -> TargetReference - { - let targetName = buildableReference.blueprintName - let container = buildableReference.referencedContainer - - let projectPath: AbsolutePath - switch graphType { - case let .workspace(workspaceProvider): - let containerRelativePath = container.replacingOccurrences(of: "container:", with: "") - let relativePath = try RelativePath(validating: containerRelativePath) - projectPath = workspaceProvider.workspaceDirectory.appending(relativePath) - case let .project(path): - projectPath = path - } - - return TargetReference( - projectPath: projectPath, - name: targetName - ) - } -} - -extension SchemeMapper { - /// Maps the given Xcode schemes asynchronously. - /// - /// This is a convenience method similar to `mapSchemes(xcschemes:shared:)`, - /// but specifically defined for asynchronous mapping flows. - /// - /// - Parameters: - /// - xcschemes: An array of `XCScheme` instances to map. - /// - shared: A Boolean indicating whether the schemes are shared. - /// - Returns: An array of mapped `Scheme` instances. - /// - Throws: If mapping any scheme fails. - func mapSchemesAsync(xcschemes: [XCScheme], shared: Bool) async throws -> [Scheme] { - try await xcschemes.asyncCompactMap { scheme in - try await self.mapScheme(xcscheme: scheme, shared: shared) - } - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift b/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift deleted file mode 100644 index fbbdca76..00000000 --- a/Sources/XcodeProjToGraph/Mappers/TargetAndSchemes/TargetMapper.swift +++ /dev/null @@ -1,285 +0,0 @@ -import Foundation -import Path -import XcodeGraph -import XcodeProj - -/// A protocol defining how to map a `PBXTarget` into a domain `Target` model. -/// -/// Conforming types transform a raw `PBXTarget` from the Xcode project model into a fully-realized `Target` -/// that includes product information, build settings, source files, resources, scripts, dependencies, -/// build rules, and other essential configuration details. -protocol TargetMapping: Sendable { - /// Maps the given `PBXTarget` into a `Target` domain model. - /// - /// By inspecting the target’s build settings, build phases, and dependencies, implementers produce a `Target` - /// that can be used for code generation, analysis, and other downstream operations. - /// - /// - Parameter pbxTarget: The `PBXTarget` to map. - /// - Returns: A fully mapped `Target` model containing all relevant information extracted from the `PBXTarget`. - /// - Throws: A `MappingError` if required information (e.g., a bundle identifier) is missing or invalid. - func map(pbxTarget: PBXTarget) async throws -> Target -} - -/// A mapper that converts a `PBXTarget` into a domain `Target` model. -/// -/// `TargetMapper` orchestrates a multi-step process to produce a rich `Target` model: -/// - Uses `SettingsMapper` to translate `XCConfigurationList` into domain-specific build settings. -/// - Uses `BuildPhaseMapper` to enumerate and map sources, resources, headers, scripts, copy files, frameworks, core data models, -/// and raw script phases. -/// - Uses `BuildPhaseMapper` as well to identify additional files that are not tied to any build phase, ensuring a complete -/// picture of the project's file structure. -/// - Uses `DependencyMapper` to resolve target dependencies (e.g., other targets, packages). -/// - Uses `BuildRuleMapper` to incorporate custom build rules. -/// -/// The final `Target` includes data about the platform, product type, build settings, files, dependencies, and more. -/// This comprehensive model is crucial for downstream tasks like code generation, dependency analysis, and tooling integration. -/// -/// **Example Usage:** -/// ```swift -/// // Assume you have a ProjectProvider instance and a PBXTarget obtained from an Xcode project. -/// let projectProvider: ProjectProviding = ... -/// let pbxTarget: PBXTarget = ... -/// -/// // Create a TargetMapper to handle the mapping of PBXTarget to Target. -/// let targetMapper = TargetMapper(projectProvider: projectProvider) -/// -/// // Perform the mapping -/// let target = try await targetMapper.map(pbxTarget: pbxTarget) -/// -/// // 'target' now contains a fully resolved Target model, including settings, sources, resources, dependencies, and more. -/// // This model can be used for code generation, analysis, or integration with custom development workflows. -/// ``` -public final class TargetMapper: TargetMapping { - private let projectProvider: ProjectProviding - private let settingsMapper: SettingsMapping - private let buildPhaseMapper: BuildPhaseMapping - private let dependencyMapper: DependencyMapping - private let buildRuleMapper: BuildRuleMapping - - /// Creates a new `TargetMapper` instance. - /// - /// - Parameter projectProvider: A provider granting access to project paths, the `XcodeProj`, and related data needed for - /// resolution. - public init(projectProvider: ProjectProviding) { - self.projectProvider = projectProvider - settingsMapper = SettingsMapper() - buildPhaseMapper = BuildPhaseMapper(projectProvider: projectProvider) - dependencyMapper = DependencyMapper(projectProvider: projectProvider) - buildRuleMapper = BuildRuleMapper() - } - - public func map(pbxTarget: PBXTarget) async throws -> Target { - // Extract platform, product, and deployment targets - let platform = try pbxTarget.platform() - let deploymentTargets = try pbxTarget.deploymentTargets() - let product = pbxTarget.productType() - - // Map build settings - let settings = try await settingsMapper.map( - projectProvider: projectProvider, - configurationList: pbxTarget.buildConfigurationList - ) - - // Map various build phases - let sources = try await buildPhaseMapper.mapSources(target: pbxTarget) - let resources = try await buildPhaseMapper.mapResources(target: pbxTarget) - let headers = try await buildPhaseMapper.mapHeaders(target: pbxTarget) - let scripts = try await buildPhaseMapper.mapScripts(target: pbxTarget) - let copyFiles = try await buildPhaseMapper.mapCopyFiles(target: pbxTarget) - let coreDataModels = try await buildPhaseMapper.mapCoreDataModels(target: pbxTarget) - let rawScriptBuildPhases = try await buildPhaseMapper.mapRawScriptBuildPhases(target: pbxTarget) - - // Map any additional files not included in the known build phases - let additionalFiles = try await buildPhaseMapper.mapAdditionalFiles(target: pbxTarget) - - // Convert resource files to domain-specific `ResourceFileElements` - let resourceFileElements = ResourceFileElements(resources) - - // Map build rules - let buildRules = try await buildRuleMapper.mapBuildRules(target: pbxTarget) - - // Extract environment variables - let environmentVariables = pbxTarget.extractEnvironmentVariables() - - // Extract various target-level metadata and settings - let launchArguments = try extractLaunchArguments(from: pbxTarget) - let filesGroup = try extractFilesGroup(from: pbxTarget) - let playgrounds = try await extractPlaygrounds(from: pbxTarget) - let prune = try extractPrune(from: pbxTarget) - let mergedBinaryType = try extractMergedBinaryType(from: pbxTarget) - let mergeable = try extractMergeable(from: pbxTarget) - let onDemandResourcesTags = try extractOnDemandResourcesTags(from: pbxTarget) - let metadata = try extractMetadata(from: pbxTarget) - - // Resolve dependencies (targets, packages, frameworks) - let targetDependencies = try await dependencyMapper.mapDependencies(target: pbxTarget) - let frameworkDependencies = try await buildPhaseMapper.mapFrameworks(target: pbxTarget) - let allDependencies = targetDependencies + frameworkDependencies - - // Construct the final `Target` model - return Target( - name: pbxTarget.name, - destinations: platform, - product: product, - productName: pbxTarget.productName ?? pbxTarget.name, - bundleId: try extractBundleIdentifier(from: pbxTarget), - deploymentTargets: deploymentTargets, - infoPlist: try extractInfoPlist(from: pbxTarget), - entitlements: try extractEntitlements(from: pbxTarget), - settings: settings, - sources: sources, - resources: resourceFileElements, - copyFiles: copyFiles, - headers: headers, - coreDataModels: coreDataModels, - scripts: scripts, - environmentVariables: environmentVariables, - launchArguments: launchArguments, - filesGroup: filesGroup, - dependencies: allDependencies.sorted { $0.name < $1.name }, - rawScriptBuildPhases: rawScriptBuildPhases, - playgrounds: playgrounds, - additionalFiles: additionalFiles, - buildRules: buildRules, - prune: prune, - mergedBinaryType: mergedBinaryType, - mergeable: mergeable, - onDemandResourcesTags: onDemandResourcesTags, - metadata: metadata - ) - } - - // MARK: - Helper Methods - - private func extractBundleIdentifier(from target: PBXTarget) throws -> String { - if let bundleId = target.debugBuildSettings.string(for: .productBundleIdentifier) { - return bundleId - } - throw MappingError.missingBundleIdentifier(targetName: target.name) - } - - private func extractInfoPlist(from target: PBXTarget) throws -> InfoPlist { - if let plistPath = try target.infoPlistPath() { - let path = try resolvePath(plistPath) - let plistDictionary = try readPlistAsDictionary(at: path) - return .dictionary(plistDictionary) - } - return .dictionary([:]) - } - - private func readPlistAsDictionary(at path: AbsolutePath) throws -> [String: Plist.Value] { - let fileURL = URL(fileURLWithPath: path.pathString) - let data = try Data(contentsOf: fileURL) - var format = PropertyListSerialization.PropertyListFormat.xml - guard let plist = try PropertyListSerialization.propertyList( - from: data, - options: .mutableContainersAndLeaves, - format: &format - ) as? [String: Any] else { - throw MappingError.generic("Failed to cast plist contents to a dictionary.") - } - - return try plist.reduce(into: [String: Plist.Value]()) { result, item in - result[item.key] = try convertToPlistValue(item.value) - } - } - - private func convertToPlistValue(_ value: Any) throws -> Plist.Value { - switch value { - case let stringValue as String: - return .string(stringValue) - case let intValue as Int: - return .integer(intValue) - case let doubleValue as Double: - return .real(doubleValue) - case let boolValue as Bool: - return .boolean(boolValue) - case let arrayValue as [Any]: - let convertedArray = try arrayValue.map { try convertToPlistValue($0) } - return .array(convertedArray) - case let dictValue as [String: Any]: - let convertedDict = try dictValue.reduce(into: [String: Plist.Value]()) { - dictResult, dictItem in - dictResult[dictItem.key] = try convertToPlistValue(dictItem.value) - } - return .dictionary(convertedDict) - default: - return .string(String(describing: value)) - } - } - - private func extractEntitlements(from target: PBXTarget) throws -> Entitlements? { - if let entitlementsPath = try target.entitlementsPath() { - let resolvedPath = try resolvePath(entitlementsPath) - return Entitlements.file(path: resolvedPath) - } - return nil - } - - private func resolvePath(_ pathString: String) throws -> AbsolutePath { - let processedPath: String - if pathString.hasPrefix("$(SRCROOT)/") { - let relative = String(pathString.dropFirst("$(SRCROOT)/".count)) - processedPath = relative - } else if pathString == "$(SRCROOT)" { - processedPath = "" - } else { - processedPath = pathString - } - return projectProvider.sourceDirectory.appending(try RelativePath(validating: processedPath)) - } - - private func extractLaunchArguments(from target: PBXTarget) throws -> [LaunchArgument] { - guard let buildConfigList = target.buildConfigurationList else { return [] } - var launchArguments: [LaunchArgument] = [] - for buildConfig in buildConfigList.buildConfigurations { - if let args = buildConfig.buildSettings.stringArray(for: .launchArguments) { - launchArguments.append(contentsOf: args.map { LaunchArgument(name: $0, isEnabled: true) }) - } - } - return launchArguments.uniqued() - } - - private func extractFilesGroup(from target: PBXTarget) throws -> ProjectGroup { - guard let mainGroup = try projectProvider.pbxProject().mainGroup else { - throw MappingError.missingFilesGroup(targetName: target.name) - } - return ProjectGroup.group(name: mainGroup.name ?? "MainGroup") - } - - private func extractPlaygrounds(from target: PBXTarget) async throws -> [AbsolutePath] { - let sourceFiles = try await buildPhaseMapper.mapSources(target: target) - return sourceFiles.filter { $0.path.fileExtension == .playground }.map(\.path) - } - - private func extractPrune(from target: PBXTarget) throws -> Bool { - target.debugBuildSettings.bool(for: .prune) ?? false - } - - private func extractMergedBinaryType(from target: PBXTarget) throws -> MergedBinaryType { - let mergedBinaryTypeString = target.debugBuildSettings.string(for: .mergedBinaryType) - return mergedBinaryTypeString == "automatic" ? .automatic : .disabled - } - - private func extractMergeable(from target: PBXTarget) throws -> Bool { - target.debugBuildSettings.bool(for: .mergeable) ?? false - } - - private func extractOnDemandResourcesTags(from _: PBXTarget) throws -> OnDemandResourcesTags? { - // TODO: implement if needed - return nil - } - - private func extractMetadata(from target: PBXTarget) throws -> TargetMetadata { - var tags: Set = [] - for buildConfig in target.buildConfigurationList?.buildConfigurations ?? [] { - if let tagsString = buildConfig.buildSettings.string(for: .tags) { - let extractedTags = tagsString.split(separator: ",").map { - $0.trimmingCharacters(in: .whitespaces) - } - tags.formUnion(extractedTags) - } - } - return TargetMetadata(tags: tags) - } -} diff --git a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift b/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift deleted file mode 100644 index 3f390c1e..00000000 --- a/Sources/XcodeProjToGraph/Mappers/Workspace/WorkspaceMapper.swift +++ /dev/null @@ -1,146 +0,0 @@ -import Foundation -import Path -import PathKit -import XcodeGraph -@preconcurrency import XcodeProj - -/// A protocol defining how to map an `.xcworkspace` structure into a `Workspace` domain model. -/// -/// Conforming types parse a given `XCWorkspace` and extract all referenced projects, schemes, and other relevant information, -/// resulting in a coherent `Workspace` model that can be used for code generation, analysis, or further tooling. -protocol WorkspaceMapping: Sendable { - /// Maps the current workspace into a `Workspace` model. - /// - /// This process gathers `.xcodeproj` references, shared schemes, and configuration options from the `.xcworkspace`, - /// consolidating them into a domain-level `Workspace` object. - /// - /// - Returns: A `Workspace` instance representing the mapped workspace. - /// - Throws: If any portion of the mapping process fails (e.g., due to invalid paths or unreadable scheme files). - func map() async throws -> Workspace -} - -/// A mapper that converts a provided `.xcworkspace` into a `Workspace` model, extracting project paths, schemes, -/// and related data. -/// -/// `WorkspaceMapper` focuses on: -/// - Identifying `.xcodeproj` files referenced by the workspace. -/// - Mapping shared schemes defined within the workspace. -/// - Constructing a `Workspace` model with default generation options and placeholders for additional files or IDE templates. -/// -/// **Example Usage:** -/// ```swift -/// // Assume you have a WorkspaceProvider initialized for a given `.xcworkspace`. -/// let workspaceProvider: WorkspaceProviding = ... -/// -/// // Create a WorkspaceMapper instance -/// let workspaceMapper = WorkspaceMapper(workspaceProvider: workspaceProvider) -/// -/// // Map the workspace into a domain-level Workspace model -/// let workspace = try await workspaceMapper.map() -/// -/// // 'workspace' now contains references to all identified projects and schemes, enabling further analysis -/// // or code generation tasks. -/// ``` -public final class WorkspaceMapper: WorkspaceMapping { - public let workspaceProvider: WorkspaceProviding - - /// Creates a new `WorkspaceMapper`. - /// - /// - Parameter workspaceProvider: A provider capable of supplying a parsed `XCWorkspace` and its associated paths. - /// This allows the mapper to discover referenced projects and shared schemes. - public init(workspaceProvider: WorkspaceProviding) { - self.workspaceProvider = workspaceProvider - } - - public func map() async throws -> Workspace { - let xcworkspace = workspaceProvider.xcworkspace - let xcWorkspacePath = workspaceProvider.xcWorkspacePath - let srcPath = workspaceProvider.workspaceDirectory - let projectPaths = try extractProjectPaths(from: xcworkspace.data.children, srcPath: srcPath) - let projectAbsolutePaths = projectPaths.map { $0 } - - let workspaceName = xcWorkspacePath.basenameWithoutExt - let schemes = try await mapSchemes(from: xcWorkspacePath) - - let ideTemplateMacros: IDETemplateMacros? = nil - let additionalFiles: [FileElement] = [] - let generationOptions = Workspace.GenerationOptions( - enableAutomaticXcodeSchemes: nil, - autogeneratedWorkspaceSchemes: .disabled, - lastXcodeUpgradeCheck: nil, - renderMarkdownReadme: false - ) - - return Workspace( - path: srcPath, - xcWorkspacePath: xcWorkspacePath, - name: workspaceName, - projects: projectAbsolutePaths, - schemes: schemes, - generationOptions: generationOptions, - ideTemplateMacros: ideTemplateMacros, - additionalFiles: additionalFiles - ) - } - - /// Recursively extracts all `.xcodeproj` paths from the workspace’s file and group references. - /// - /// This traversal ensures that all projects included in nested groups are discovered, - /// providing a complete picture of the workspace’s project set. - /// - /// - Parameters: - /// - elements: The array of `XCWorkspaceDataElement` representing files or groups in the workspace. - /// - srcPath: The source directory path used as a base for resolving relative references. - /// - Returns: An array of absolute paths to `.xcodeproj` directories. - /// - Throws: If resolving any referenced path fails (e.g., invalid relative paths). - private func extractProjectPaths( - from elements: [XCWorkspaceDataElement], - srcPath: AbsolutePath - ) throws -> [AbsolutePath] { - var paths = [AbsolutePath]() - - for element in elements { - switch element { - case let .file(ref): - let refPath = try ref.absolutePath(srcPath: srcPath) - if refPath.fileExtension == .xcodeproj { - paths.append(refPath) - } - case let .group(group): - let groupPaths = try extractProjectPaths( - from: group.children, - srcPath: srcPath.appending(component: group.location.path) - ) - paths.append(contentsOf: groupPaths) - } - } - - return paths - } - - /// Maps all shared schemes found within the workspace. - /// - /// Shared schemes are typically located in the `xcshareddata/xcschemes` directory inside the workspace. - /// If present, they are parsed and mapped into `Scheme` models that can be integrated into the `Workspace`. - /// - /// - Parameter srcPath: The source path of the workspace. - /// - Returns: An array of mapped `Scheme` instances. - /// - Throws: If reading or mapping any of the schemes fails (e.g., invalid `.xcscheme` files or missing references). - private func mapSchemes(from srcPath: AbsolutePath) async throws -> [Scheme] { - var schemes = [Scheme]() - let sharedDataPath = Path(srcPath.pathString) + "xcshareddata/xcschemes" - - if sharedDataPath.exists { - let schemePaths = try sharedDataPath.children().filter { $0.extension == "xcscheme" } - - for schemePath in schemePaths { - let xcscheme = try XCScheme(path: schemePath) - let schemeMapper = try SchemeMapper(graphType: .workspace(workspaceProvider)) - let scheme = try await schemeMapper.mapScheme(xcscheme: xcscheme, shared: true) - schemes.append(scheme) - } - } - - return schemes - } -} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift b/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift deleted file mode 100644 index a98853fb..00000000 --- a/Sources/XcodeProjToGraph/ProcessRunner/Executable.swift +++ /dev/null @@ -1,55 +0,0 @@ -import Foundation - -// MARK: - Executable - -/// Represents an executable command with its arguments, executable path, and a parser for the output. -/// -/// Used to define commands like `lipo` or custom executables, encapsulating the logic -/// for arguments, path, and output processing. -public enum Executable: Sendable { - /// A `lipo` command, used for managing universal binaries. - /// - /// - Parameters: - /// - arguments: The arguments to pass to `lipo`. - /// - parser: A closure to parse the `ProcessResult` into an `Output`. - /// - executablePath: The path to the `lipo` binary (default: `/usr/bin/lipo`). - case lipo(LipoArguments, @Sendable (ProcessResult) throws -> Output, executablePath: String = "/usr/bin/lipo") - - /// A custom executable command. - /// - /// - Parameters: - /// - executablePath: The path to the custom executable. - /// - arguments: The arguments to pass to the executable. - /// - parser: A closure to parse the `ProcessResult` into an `Output`. - case custom(String, [String], @Sendable (ProcessResult) throws -> Output) - - /// The path to the executable. - public var path: String { - switch self { - case let .lipo(_, _, path): - return path - case let .custom(executablePath, _, _): - return executablePath - } - } - - /// The arguments to pass to the executable. - public var arguments: [String] { - switch self { - case let .lipo(lipoArgs, _, _): - return lipoArgs.toArguments() - case let .custom(_, args, _): - return args - } - } - - /// A parser to convert the `ProcessResult` into the desired `Output` type. - public var parser: (ProcessResult) throws -> Output { - switch self { - case let .lipo(_, parser, _): - return parser - case let .custom(_, _, parser): - return parser - } - } -} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArchsResult.swift b/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArchsResult.swift deleted file mode 100644 index 6dbd1230..00000000 --- a/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArchsResult.swift +++ /dev/null @@ -1,38 +0,0 @@ -import Foundation -@preconcurrency import XcodeGraph - -/// Represents the architectures extracted from running `lipo -archs`. -/// -/// `LipoArchsResult` provides a structured result indicating which architectures -/// are contained in a given binary. It uses `XcodeGraph.BinaryArchitecture` to -/// represent each architecture (e.g., arm64, x86_64). -public struct LipoArchsResult: Sendable { - /// The list of architectures reported by `lipo -archs`. - public let architectures: [XcodeGraph.BinaryArchitecture] -} - -/// Parses the output of a `ProcessResult` from a `lipo -archs` invocation into a `LipoArchsResult`. -/// -/// `lipo -archs` typically returns a single line of whitespace-separated architectures, -/// for example: `"arm64"` or `"arm64 x86_64"`. -/// -/// - Parameter result: The `ProcessResult` obtained from running the `lipo -archs` command. -/// - Returns: A `LipoArchsResult` containing all detected architectures. -/// - Throws: -/// - `ProcessRunnerError.failedToRunProcess` if `lipo` exits with a non-zero code. -/// - Any errors related to decoding or interpreting the output as architectures. -public func parseLipoArchsResult(_ result: ProcessResult) throws -> LipoArchsResult { - // Ensure that the process succeeded. If not, throw an error indicating lipo failed. - guard result.succeeded else { - throw ProcessRunnerError.failedToRunProcess("Lipo returned non-zero exit code.") - } - - // Trim whitespace and split by space to extract architecture identifiers. - let output = result.stdout.trimmingCharacters(in: .whitespacesAndNewlines) - let archs = output.split(separator: " ") - .map(String.init) - .compactMap(BinaryArchitecture.init) - - // Return the parsed architectures encapsulated in a LipoArchsResult. - return LipoArchsResult(architectures: archs) -} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArguments.swift b/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArguments.swift deleted file mode 100644 index f79704aa..00000000 --- a/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoArguments.swift +++ /dev/null @@ -1,29 +0,0 @@ -import Foundation - -public struct LipoArguments: Sendable { - public enum Operation: Sendable { - case archs - - public var command: String { - switch self { - case .archs: - "-archs" - } - } - } - - public let operation: Operation - public let paths: [String] - - public init(operation: Operation, paths: [String]) { - self.operation = operation - self.paths = paths - } - - func toArguments() -> [String] { - var args: [String] = [] - args.append(operation.command) - args.append(contentsOf: paths) - return args - } -} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoTool.swift b/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoTool.swift deleted file mode 100644 index e8e2315d..00000000 --- a/Sources/XcodeProjToGraph/ProcessRunner/Lipo/LipoTool.swift +++ /dev/null @@ -1,36 +0,0 @@ -import Foundation - -/// A utility class for invoking `lipo` commands and parsing their results. -/// -/// `LipoTool` provides a high-level interface for running `lipo -archs` on given paths -/// to determine which architectures a binary contains. -public enum LipoTool { - /// Runs `lipo -archs` on the given paths and returns a `LipoArchsResult`. - /// - /// This method asynchronously executes `lipo -archs` using `ProcessRunner.run`, - /// then parses the output into a `LipoArchsResult`. The result includes all architectures - /// detected in the provided binary(ies). - /// - /// - Parameters: - /// - paths: An array of file paths to the binary files you want to inspect for architectures. - /// Typically, passing one path is common, but multiple paths can also be provided. - /// - executablePath: The path to the `lipo` executable. Defaults to `/usr/bin/lipo`. - /// - /// - Returns: A `LipoArchsResult` representing the architectures found. - /// - /// - Throws: - /// - `ProcessRunnerError` if there are issues running the `lipo` command or decoding its output. - /// - Any errors thrown by `parseLipoArchsResult` if the output is malformed. - /// - /// - Note: This method is `async` and may suspend. Ensure you're calling it from an asynchronous - /// context or within a `Task`. - @discardableResult - public static func archs( - paths: [String], - executablePath: String = "/usr/bin/lipo" - ) async throws -> LipoArchsResult { - let args = LipoArguments(operation: .archs, paths: paths) - let executable = Executable.lipo(args, parseLipoArchsResult, executablePath: executablePath) - return try await ProcessRunner.run(executable: executable, throwOnNonZeroExit: false) - } -} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/ProcessResult.swift b/Sources/XcodeProjToGraph/ProcessRunner/ProcessResult.swift deleted file mode 100644 index 854d6fc2..00000000 --- a/Sources/XcodeProjToGraph/ProcessRunner/ProcessResult.swift +++ /dev/null @@ -1,28 +0,0 @@ -import Foundation - -// MARK: - ProcessResult - -/// Represents the result of executing a process, including exit code, stdout, and stderr. -public struct ProcessResult: Sendable, CustomStringConvertible { - /// The exit code of the process. `0` typically indicates success. - public let exitCode: Int32 - - /// The standard output of the process as a `String`. - public let stdout: String - - /// The standard error output of the process as a `String`. - public let stderr: String - - /// Indicates whether the process exited successfully. - public var succeeded: Bool { - exitCode == 0 - } - - public var description: String { - """ - Exit Code: \(exitCode) - Stdout: \(stdout) - Stderr: \(stderr) - """ - } -} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift deleted file mode 100644 index b5a5cb7b..00000000 --- a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunner.swift +++ /dev/null @@ -1,81 +0,0 @@ -import Foundation - -// MARK: - ProcessRunner - -/// A utility for running shell commands asynchronously and parsing their results. -public enum ProcessRunner { - /// Runs the given executable asynchronously and processes its result using the associated parser. - /// - /// - Parameters: - /// - executable: An `Executable` that defines the command, arguments, and output parser. - /// - environment: An optional dictionary of environment variables for the process. - /// - workingDirectory: An optional path for the process's working directory. - /// - throwOnNonZeroExit: If `true`, throws an error for non-zero exit codes. Defaults to `true`. - /// - fileManager: A `FileManager` instance, defaulting to `.default`. - /// - Returns: The structured output parsed from the process's result. - /// - Throws: - /// - `ProcessRunnerError` for issues like non-zero exit codes, invalid UTF-8, or a failure to run. - @discardableResult - public static func run( - executable: Executable, - environment: [String: String]? = nil, - workingDirectory: String? = nil, - throwOnNonZeroExit: Bool = true, - fileManager: FileManager = FileManager.default - ) async throws -> T { - let execPath = executable.path - - guard fileManager.isExecutableFile(atPath: execPath) else { - throw ProcessRunnerError.executableNotFound(execPath) - } - - return try await withCheckedThrowingContinuation { continuation in - let process = Process() - process.executableURL = URL(fileURLWithPath: execPath) - process.arguments = executable.arguments - process.environment = environment ?? ProcessInfo.processInfo.environment - if let workingDirectory { - process.currentDirectoryURL = URL(fileURLWithPath: workingDirectory) - } - - let stdoutPipe = Pipe() - let stderrPipe = Pipe() - process.standardOutput = stdoutPipe - process.standardError = stderrPipe - - process.terminationHandler = { process in - let stdoutData = stdoutPipe.fileHandleForReading.readDataToEndOfFile() - let stderrData = stderrPipe.fileHandleForReading.readDataToEndOfFile() - - guard let stdoutString = String(data: stdoutData, encoding: .utf8), - let stderrString = String(data: stderrData, encoding: .utf8) - else { - // More descriptive error message on UTF-8 failure - continuation.resume(throwing: ProcessRunnerError.invalidUTF8InOutput) - return - } - - let exitCode = process.terminationStatus - let result = ProcessResult(exitCode: exitCode, stdout: stdoutString, stderr: stderrString) - - if throwOnNonZeroExit, !result.succeeded { - continuation.resume(throwing: ProcessRunnerError.nonZeroExitCode(exitCode, result.stderr)) - return - } - - do { - let output = try executable.parser(result) - continuation.resume(returning: output) - } catch { - continuation.resume(throwing: error) - } - } - - do { - try process.run() - } catch { - continuation.resume(throwing: ProcessRunnerError.failedToRunProcess(error.localizedDescription)) - } - } - } -} diff --git a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift b/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift deleted file mode 100644 index a5c50eae..00000000 --- a/Sources/XcodeProjToGraph/ProcessRunner/ProcessRunnerError.swift +++ /dev/null @@ -1,22 +0,0 @@ -import Foundation - -/// Errors that can occur when running processes with `ProcessRunner`. -public enum ProcessRunnerError: Error, LocalizedError, Equatable { - case executableNotFound(String) - case failedToRunProcess(String) - case invalidUTF8InOutput - case nonZeroExitCode(Int32, String) - - public var errorDescription: String? { - switch self { - case let .executableNotFound(cmd): - return "The executable '\(cmd)' was not found or is not executable." - case let .failedToRunProcess(reason): - return "Failed to run process: \(reason)" - case .invalidUTF8InOutput: - return "Could not decode output as UTF-8." - case let .nonZeroExitCode(code, stderr): - return "Command exited with code \(code). Stderr: \(stderr)" - } - } -} diff --git a/Tests/XcodeProjMapperTests/IntegrationTests/IntegrationTests.swift b/Tests/XcodeProjMapperTests/IntegrationTests/IntegrationTests.swift new file mode 100644 index 00000000..76b0208e --- /dev/null +++ b/Tests/XcodeProjMapperTests/IntegrationTests/IntegrationTests.swift @@ -0,0 +1,173 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeProj +import XcodeProjMapper +@testable import XcodeGraph + +// The IntegrationTests suite is serialized and uses inline snapshot testing. +// If a test fails, its snapshot can be re-recorded as needed by changing `record: .failed`. +@Suite( + // TODO: - Remove this when no longer lazy unzipping fixtures + .serialized, + .snapshots( + record: .failed + ) +) +struct IntegrationTests { + /// Asserts that the given graph parsed from a workspace fixture matches the provided inline snapshots. + /// + /// - Parameters: + /// - fixture: A closure that returns a `WorkspaceFixture` used to generate the graph. + func assertGraph( + of fixture: () -> WorkspaceFixture, + name: (() -> String)? = nil, + dependencies: (() -> String)? = nil, + dependencyConditions: (() -> String)? = nil, + packages: (() -> String)? = nil, + workspace: (() -> String)? = nil, + projects: (() -> String)? = nil, + fileID: StaticString = #fileID, + file filePath: StaticString = #filePath, + function: StaticString = #function, + line: UInt = #line, + column: UInt = #column + ) throws { + let path = try fixture().absolutePath() + + let parser = ProjectParser() + let fullGraph: XcodeGraph.Graph = try parser.parse(at: path.pathString) + let graph = try fullGraph.normalizeGraphPaths().minimizeGraph() + + // A helper for making assertions more concise. + func assertSnapshot( + of value: some Any, + label: String, + trailingClosureOffset: Int, + matches expected: (() -> String)?, + message: String + ) { + assertInlineSnapshot( + of: value, + as: .dump, + message: message, + syntaxDescriptor: InlineSnapshotSyntaxDescriptor( + trailingClosureLabel: label, + trailingClosureOffset: trailingClosureOffset + ), + matches: expected, + fileID: fileID, + file: filePath, + function: function, + line: line, + column: column + ) + } + + // Assertions for each portion of the graph. + assertSnapshot( + of: graph.name, + label: "name", + trailingClosureOffset: 1, + matches: name, + message: "Graph name did not match" + ) + + assertSnapshot( + of: graph.dependencies, + label: "dependencies", + trailingClosureOffset: 2, + matches: dependencies, + message: "Dependencies did not match" + ) + + assertSnapshot( + of: graph.dependencyConditions, + label: "dependencyConditions", + trailingClosureOffset: 3, + matches: dependencyConditions, + message: "Dependency Conditions did not match" + ) + + assertSnapshot( + of: graph.packages, + label: "packages", + trailingClosureOffset: 4, + matches: packages, + message: "Packages did not match" + ) + + assertSnapshot( + of: graph.workspace, + label: "workspace", + trailingClosureOffset: 5, + matches: workspace, + message: "Workspace did not match" + ) + + assertSnapshot( + of: graph.projects, + label: "projects", + trailingClosureOffset: 6, + matches: projects, + message: "Projects did not match" + ) + } +} + +// MARK: - Graph Normalization & Minimization + +extension XcodeGraph.Graph { + /// Normalizes file paths in the graph's JSON representation to a consistent relative form. + func normalizeGraphPaths() throws -> XcodeGraph.Graph { + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] + + let data = try encoder.encode(self) + var jsonString = String(decoding: data, as: UTF8.self) + + // Replace any path prefix before /Fixtures with a unified placeholder. + jsonString = jsonString.replacingOccurrences( + of: #"[^"]*?/Fixtures"#, + with: "/Fixtures", + options: [.regularExpression] + ) + + let decoder = JSONDecoder() + return try decoder.decode(XcodeGraph.Graph.self, from: Data(jsonString.utf8)) + } + + /// Minimizes the graph's data by removing unnecessary details (e.g., schemes, resource synthesizers). + func minimizeGraph() -> Graph { + var graph = self + + // Remove workspace schemes and standardize generation options. + graph.workspace.schemes = [] + graph.workspace.generationOptions = .test() + + for (key, project) in graph.projects { + graph.projects[key]?.schemes = [] + graph.projects[key]?.resourceSynthesizers = [] + graph.projects[key]?.settings = Settings(configurations: [:]) + + for targetKey in project.targets.keys { + // Remove unneeded properties from targets. + graph.projects[key]?.targets[targetKey]?.scripts = [] + graph.projects[key]?.targets[targetKey]?.playgrounds = [] + graph.projects[key]?.targets[targetKey]?.rawScriptBuildPhases = [] + graph.projects[key]?.targets[targetKey]?.buildRules = [] + graph.projects[key]?.targets[targetKey]?.settings = nil + graph.projects[key]?.targets[targetKey]?.infoPlist = nil + graph.projects[key]?.targets[targetKey]?.destinations = [] + } + } + + return graph + } +} + +// Allows AbsolutePath to be displayed in snapshots in a readable form. +extension AbsolutePath: @retroactive AnySnapshotStringConvertible { + public var snapshotDescription: String { pathString } +} diff --git a/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift new file mode 100644 index 00000000..e2aa768d --- /dev/null +++ b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+commandLineToolWithDynamicFramework.swift @@ -0,0 +1,249 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProj +import XcodeProjMapper + +extension IntegrationTests { + @Test("Maps a command-line tool with a dynamic framework dependency into the correct graph") + func commandLineToolWithDynamicFramework() throws { + try assertGraph { + .commandLineToolWithDynamicFramework + } name: { + """ + - "CommandLineTool" + + """ + } dependencies: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: target 'CommandLineTool' + ▿ target: (3 elements) + - name: "CommandLineTool" + - path: /Fixtures/command_line_tool_with_dynamic_framework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'DynamicFramework' + ▿ target: (3 elements) + - name: "DynamicFramework" + - path: /Fixtures/command_line_tool_with_dynamic_framework + - status: LinkingStatus.required + + """ + } dependencyConditions: { + """ + - 0 key/value pairs + + """ + } packages: { + """ + - 0 key/value pairs + + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "CommandLineTool" + - path: /Fixtures/command_line_tool_with_dynamic_framework + ▿ projects: 1 element + - /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcworkspace + + """ + } projects: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool.xcodeproj + ▿ value: CommandLineTool + - path: /Fixtures/command_line_tool_with_dynamic_framework + - sourceRootPath: /Fixtures/command_line_tool_with_dynamic_framework + - xcodeProjPath: /Fixtures/command_line_tool_with_dynamic_framework + - name: "CommandLineTool" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "CommandLineTool" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/command_line_tool_with_dynamic_framework/Derived/InfoPlists/CommandLineTool-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/command_line_tool_with_dynamic_framework/Derived/InfoPlists/DynamicFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift + - buildRules: 0 elements + - bundleId: "com.example.commandlinetool" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "DynamicFramework" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "CommandLineTool" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: command line tool + - productName: "CommandLineTool" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift + ▿ (2 elements) + - key: "DynamicFramework" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/command_line_tool_with_dynamic_framework/CommandLineTool/main.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/command_line_tool_with_dynamic_framework/Derived/InfoPlists/CommandLineTool-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/command_line_tool_with_dynamic_framework/Derived/InfoPlists/DynamicFramework-Info.plist + - buildRules: 0 elements + - bundleId: "com.example.dynamicframework" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "DynamicFramework" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "DynamicFramework" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/command_line_tool_with_dynamic_framework/DynamicFramework/DynamicFramework.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift new file mode 100644 index 00000000..0e236e79 --- /dev/null +++ b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppLarge.swift @@ -0,0 +1,18 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProj +import XcodeProjMapper + +extension IntegrationTests { + @Test("Maps a large iOS app project into the correct graph") + func iosAppLarge() throws { + let path = try WorkspaceFixture.iosAppLarge.absolutePath() + + let parser = ProjectParser() + let graph: XcodeGraph.Graph = try parser.parse(at: path.pathString) + #expect(graph.projects.first?.value.targets.count == 300) + } +} diff --git a/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift new file mode 100644 index 00000000..5119d73e --- /dev/null +++ b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithExtensions.swift @@ -0,0 +1,1376 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProj +import XcodeProjMapper + +extension IntegrationTests { + @Test("Maps an iOS app with extensions into the correct graph") + func iosAppWithExtensions() throws { + try assertGraph { + .iosAppWithExtensions + } name: { + """ + - "App" + + """ + } dependencies: { + """ + ▿ 3 key/value pairs + ▿ (2 elements) + ▿ key: target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ value: 4 members + ▿ target 'AppIntentExtension' + ▿ target: (3 elements) + - name: "AppIntentExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'NotificationServiceExtension' + ▿ target: (3 elements) + - name: "NotificationServiceExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'StickersPackExtension' + ▿ target: (3 elements) + - name: "StickersPackExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'WidgetExtension' + ▿ target: (3 elements) + - name: "WidgetExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'AppWithMessagesExtension' + ▿ target: (3 elements) + - name: "AppWithMessagesExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ value: 2 members + ▿ target 'MessageExtension' + ▿ target: (3 elements) + - name: "MessageExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'NotificationServiceExtension' + ▿ target: (3 elements) + - name: "NotificationServiceExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'WidgetExtension' + ▿ target: (3 elements) + - name: "WidgetExtension" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ value: 2 members + ▿ target 'Bundle' + ▿ target: (3 elements) + - name: "Bundle" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + ▿ target 'StaticFramework' + ▿ target: (3 elements) + - name: "StaticFramework" + - path: /Fixtures/ios_app_with_extensions + - status: LinkingStatus.required + + """ + } dependencyConditions: { + """ + - 0 key/value pairs + + """ + } packages: { + """ + - 0 key/value pairs + + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "App" + - path: /Fixtures/ios_app_with_extensions + ▿ projects: 1 element + - /Fixtures/ios_app_with_extensions/App.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_extensions/App.xcworkspace + + """ + } projects: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/ios_app_with_extensions/App.xcodeproj + ▿ value: App + - path: /Fixtures/ios_app_with_extensions + - sourceRootPath: /Fixtures/ios_app_with_extensions + - xcodeProjPath: /Fixtures/ios_app_with_extensions + - name: "App" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 9 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + ▿ additionalFiles: 23 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 3 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Embed ExtensionKit Extensions" + ▿ subpath: Optional + - some: "$(EXTENSIONS_FOLDER_PATH)" + ▿ CopyFilesAction + - destination: Destination.plugins + - files: 0 elements + - name: "Embed Foundation Extensions" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 4 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "AppIntentExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "NotificationServiceExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "StickersPackExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "WidgetExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ (2 elements) + - key: "AppIntentExtension" + ▿ value: Target + ▿ additionalFiles: 23 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift + - buildRules: 0 elements + - bundleId: "io.tuist.App.AppIntentExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppIntentExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: extensionKit extension + - productName: "AppIntentExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ (2 elements) + - key: "AppWithMessagesExtension" + ▿ value: Target + ▿ additionalFiles: 23 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift + - buildRules: 0 elements + - bundleId: "io.tuist.App2" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.plugins + - files: 0 elements + - name: "Embed Foundation Extensions" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "MessageExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "NotificationServiceExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppWithMessagesExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "AppWithMessagesExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ (2 elements) + - key: "Bundle" + ▿ value: Target + ▿ additionalFiles: 24 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift + - buildRules: 0 elements + - bundleId: "io.tuist.App.Bundle" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Bundle" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: bundle + - productName: "Bundle" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + - sources: 0 elements + ▿ (2 elements) + - key: "MessageExtension" + ▿ value: Target + ▿ additionalFiles: 21 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift + - buildRules: 0 elements + - bundleId: "io.tuist.App2.MessageExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "MessageExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: iMessage extension + - productName: "MessageExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 2 elements + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 3 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ (2 elements) + - key: "NotificationServiceExtension" + ▿ value: Target + ▿ additionalFiles: 24 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift + - buildRules: 0 elements + - bundleId: "io.tuist.App.NotificationServiceExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "NotificationServiceExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: app extension + - productName: "NotificationServiceExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ (2 elements) + - key: "StaticFramework" + ▿ value: Target + ▿ additionalFiles: 24 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift + - buildRules: 0 elements + - bundleId: "io.tuist.App.StaticFramework" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticFramework" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "StaticFramework" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ (2 elements) + - key: "StickersPackExtension" + ▿ value: Target + ▿ additionalFiles: 24 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift + - buildRules: 0 elements + - bundleId: "io.tuist.App.StickersPackExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StickersPackExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: sticker pack extension + - productName: "StickersPackExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + - sources: 0 elements + ▿ (2 elements) + - key: "WidgetExtension" + ▿ value: Target + ▿ additionalFiles: 21 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/AppIntentExtension/Sources/AppIntentExtensionExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Bundle/dummy.jpg + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/AppIntentExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/Bundle-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/MessageExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/NotificationServiceExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StaticFramework-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/StickersPackExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/InfoPlists/WidgetExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+MessageExtension.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Assets.xcassets + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Resources/Base.lproj/MainInterface.storyboard/Base.lproj/MainInterface.storyboard + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/MessageExtension/Sources/MessagesViewController.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/NotificationServiceExtension/NotificationService.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/Sources/Documentation.docc + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StaticFramework/Sources/StaticFramework.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_extensions/StickersPackExtension/Stickers.xcassets + - buildRules: 0 elements + - bundleId: "io.tuist.App.WidgetExtension" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Bundle" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "StaticFramework" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "WidgetExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: app extension + - productName: "WidgetExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + ▿ resources: 1 element + ▿ ResourceFileElement + ▿ file: (3 elements) + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Resources/Assets.xcassets + - tags: 0 elements + - inclusionCondition: Optional.none + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 3 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistAssets+WidgetExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/Derived/Sources/TuistBundle+WidgetExtension.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_extensions/WidgetExtension/Sources/Widget.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift new file mode 100644 index 00000000..193d97d6 --- /dev/null +++ b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithMultiConfigs.swift @@ -0,0 +1,675 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProj +import XcodeProjMapper + +extension IntegrationTests { + @Test("Maps an iOS app with multiple configurations into the correct graph") + func iosAppWithMultiConfigs() throws { + try assertGraph { + .iosAppWithMultiConfigs + } name: { + """ + - "Workspace" + + """ + } dependencies: { + """ + ▿ 3 key/value pairs + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_multi_configs/App + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_multi_configs/App + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1Tests' + ▿ target: (3 elements) + - name: "Framework1Tests" + - path: /Fixtures/ios_app_with_multi_configs/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Framework1' + ▿ target: (3 elements) + - name: "Framework1" + - path: /Fixtures/ios_app_with_multi_configs/Framework1 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework2Tests' + ▿ target: (3 elements) + - name: "Framework2Tests" + - path: /Fixtures/ios_app_with_multi_configs/Framework2 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Framework2' + ▿ target: (3 elements) + - name: "Framework2" + - path: /Fixtures/ios_app_with_multi_configs/Framework2 + - status: LinkingStatus.required + + """ + } dependencyConditions: { + """ + - 0 key/value pairs + + """ + } packages: { + """ + - 0 key/value pairs + + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "Workspace" + - path: /Fixtures/ios_app_with_multi_configs + ▿ projects: 3 elements + - /Fixtures/ios_app_with_multi_configs/App/MainApp.xcodeproj + - /Fixtures/ios_app_with_multi_configs/Framework1/Framework1.xcodeproj + - /Fixtures/ios_app_with_multi_configs/Framework2/Framework2.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_multi_configs/Workspace.xcworkspace + + """ + } projects: { + """ + ▿ 3 key/value pairs + ▿ (2 elements) + - key: /Fixtures/ios_app_with_multi_configs/App/MainApp.xcodeproj + ▿ value: MainApp + - path: /Fixtures/ios_app_with_multi_configs/App + - sourceRootPath: /Fixtures/ios_app_with_multi_configs/App + - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/App + - name: "MainApp" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + ▿ additionalFiles: 6 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + ▿ additionalFiles: 6 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/App/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/App/Support/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/App/Support/AppTests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig + - buildRules: 0 elements + - bundleId: "io.tuist.AppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/App/Tests/AppDelegateTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_app_with_multi_configs/Framework1/Framework1.xcodeproj + ▿ value: Framework1 + - path: /Fixtures/ios_app_with_multi_configs/Framework1 + - sourceRootPath: /Fixtures/ios_app_with_multi_configs/Framework1 + - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/Framework1 + - name: "Framework1" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "Framework1" + ▿ value: Target + ▿ additionalFiles: 6 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Framework1" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift + ▿ (2 elements) + - key: "Framework1Tests" + ▿ value: Target + ▿ additionalFiles: 6 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Sources/Framework1File.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Support/Framework1Tests-Info.plist + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Framework1" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1Tests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "Framework1Tests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/Framework1/Tests/Framework1FileTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_app_with_multi_configs/Framework2/Framework2.xcodeproj + ▿ value: Framework2 + - path: /Fixtures/ios_app_with_multi_configs/Framework2 + - sourceRootPath: /Fixtures/ios_app_with_multi_configs/Framework2 + - xcodeProjPath: /Fixtures/ios_app_with_multi_configs/Framework2 + - name: "Framework2" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "Framework2" + ▿ value: Target + ▿ additionalFiles: 7 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift + - buildRules: 0 elements + - bundleId: "io.tuist.Framework2" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework2" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Framework2" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift + ▿ (2 elements) + - key: "Framework2Tests" + ▿ value: Target + ▿ additionalFiles: 7 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Debug.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Release.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/ConfigurationFiles/Target.Beta.xcconfig + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Sources/Framework2File.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Support/Framework2Tests-Info.plist + - buildRules: 0 elements + - bundleId: "io.tuist.Framework2Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Framework2" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework2Tests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "Framework2Tests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_multi_configs/Framework2/Tests/Framework2FileTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift new file mode 100644 index 00000000..3db9e1b5 --- /dev/null +++ b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithRemoteSwiftPackage.swift @@ -0,0 +1,275 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProj +import XcodeProjMapper + +extension IntegrationTests { + @Test + func projectNoWorkspace() throws { + let path = try WorkspaceFixture.iosAppWithRemoteSwiftPackage.absolutePath().parentDirectory + .appending(component: "App.xcodeproj") + + let parser = ProjectParser() + let graph: XcodeGraph.Graph = try parser.parse(at: path.pathString) + + try #require(graph != nil) + } + + @Test("Maps an iOS app with a remote Swift package into the correct graph") + func iosAppWithRemoteSwiftPackage() throws { + try assertGraph { + .iosAppWithRemoteSwiftPackage + } name: { + """ + - "App" + + """ + } dependencies: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_remote_swift_package + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_remote_swift_package + - status: LinkingStatus.required + + """ + } dependencyConditions: { + """ + - 0 key/value pairs + + """ + } packages: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj + ▿ value: 1 key/value pair + ▿ (2 elements) + - key: "https://github.com/ReactiveX/RxSwift" + ▿ value: Package + ▿ remote: (2 elements) + - url: "https://github.com/ReactiveX/RxSwift" + ▿ requirement: Requirement + - upToNextMajor: "5.0.0" + + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "App" + - path: /Fixtures/ios_app_with_remote_swift_package + ▿ projects: 1 element + - /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_remote_swift_package/App.xcworkspace + + """ + } projects: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/ios_app_with_remote_swift_package/App.xcodeproj + ▿ value: App + - path: /Fixtures/ios_app_with_remote_swift_package + - sourceRootPath: /Fixtures/ios_app_with_remote_swift_package + - xcodeProjPath: /Fixtures/ios_app_with_remote_swift_package + - name: "App" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_remote_swift_package/Support/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_remote_swift_package/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_remote_swift_package/Support/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_remote_swift_package/Support/Tests.plist + - buildRules: 0 elements + - bundleId: "io.tuist.AppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_remote_swift_package/Tests/AppTests.swift + ▿ packages: 1 element + ▿ Package + ▿ remote: (2 elements) + - url: "https://github.com/ReactiveX/RxSwift" + ▿ requirement: Requirement + - upToNextMajor: "5.0.0" + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift new file mode 100644 index 00000000..eb42e686 --- /dev/null +++ b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosAppWithStaticLibraries.swift @@ -0,0 +1,647 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProj +import XcodeProjMapper + +extension IntegrationTests { + @Test("Maps an iOS app with transitive static libraries into the correct graph") + func iosAppWithStaticLibraries() throws { + try assertGraph { + .iosAppWithStaticLibraries + } name: { + """ + - "iOSAppWithTransistiveStaticLibraries" + + """ + } dependencies: { + """ + ▿ 4 key/value pairs + ▿ (2 elements) + ▿ key: target 'ATests' + ▿ target: (3 elements) + - name: "ATests" + - path: /Fixtures/ios_app_with_static_libraries/Modules/A + - status: LinkingStatus.required + ▿ value: 2 members + ▿ library 'libC.a' + ▿ library: (5 elements) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C + - linking: BinaryLinking.static + - architectures: 0 elements + - swiftModuleMap: Optional.none + ▿ target 'A' + ▿ target: (3 elements) + - name: "A" + - path: /Fixtures/ios_app_with_static_libraries/Modules/A + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_static_libraries + - status: LinkingStatus.required + ▿ value: 1 member + ▿ library 'libC.a' + ▿ library: (5 elements) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C + - linking: BinaryLinking.static + - architectures: 0 elements + - swiftModuleMap: Optional.none + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_static_libraries + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_static_libraries + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'BTests' + ▿ target: (3 elements) + - name: "BTests" + - path: /Fixtures/ios_app_with_static_libraries/Modules/B + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'B' + ▿ target: (3 elements) + - name: "B" + - path: /Fixtures/ios_app_with_static_libraries/Modules/B + - status: LinkingStatus.required + + """ + } dependencyConditions: { + """ + - 0 key/value pairs + + """ + } packages: { + """ + - 0 key/value pairs + + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "iOSAppWithTransistiveStaticLibraries" + - path: /Fixtures/ios_app_with_static_libraries + ▿ projects: 3 elements + - /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcodeproj + - /Fixtures/ios_app_with_static_libraries/Modules/A/A.xcodeproj + - /Fixtures/ios_app_with_static_libraries/Modules/B/B.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcworkspace + + """ + } projects: { + """ + ▿ 3 key/value pairs + ▿ (2 elements) + - key: /Fixtures/ios_app_with_static_libraries/Modules/A/A.xcodeproj + ▿ value: A + - path: /Fixtures/ios_app_with_static_libraries/Modules/A + - sourceRootPath: /Fixtures/ios_app_with_static_libraries/Modules/A + - xcodeProjPath: /Fixtures/ios_app_with_static_libraries/Modules/A + - name: "A" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "A" + ▿ value: Target + ▿ additionalFiles: 2 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - buildRules: 0 elements + - bundleId: "io.tuist.A" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "A" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: static library + - productName: "A" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift + ▿ (2 elements) + - key: "ATests" + ▿ value: Target + ▿ additionalFiles: 1 element + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Sources/A.swift + - buildRules: 0 elements + - bundleId: "io.tuist.ATests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ target: (3 elements) + - name: "A" + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ library: (4 elements) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C + - swiftModuleMap: Optional.none + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "ATests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "ATests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Modules/A/Tests/ATests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_app_with_static_libraries/Modules/B/B.xcodeproj + ▿ value: B + - path: /Fixtures/ios_app_with_static_libraries/Modules/B + - sourceRootPath: /Fixtures/ios_app_with_static_libraries/Modules/B + - xcodeProjPath: /Fixtures/ios_app_with_static_libraries/Modules/B + - name: "B" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "B" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift + - buildRules: 0 elements + - bundleId: "io.tuist.B" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "B" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: static library + - productName: "B" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift + ▿ (2 elements) + - key: "BTests" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Sources/B.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests.plist + - buildRules: 0 elements + - bundleId: "io.tuist.BTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "B" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "BTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "BTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Modules/B/Tests/BTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries.xcodeproj + ▿ value: iOSAppWithTransistiveStaticLibraries + - path: /Fixtures/ios_app_with_static_libraries + - sourceRootPath: /Fixtures/ios_app_with_static_libraries + - xcodeProjPath: /Fixtures/ios_app_with_static_libraries + - name: "iOSAppWithTransistiveStaticLibraries" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ library: (4 elements) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + - publicHeaders: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C + - swiftModuleMap: Optional.none + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + ▿ additionalFiles: 4 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Modules/C/prebuilt/C/libC.a + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_static_libraries/Tests.plist + - buildRules: 0 elements + - bundleId: "io.tuist.AppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_static_libraries/Tests/AppTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift new file mode 100644 index 00000000..c0578cba --- /dev/null +++ b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+iosWorkspaceWithMicrofeatureArchitectureStaticLinking.swift @@ -0,0 +1,1193 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProj +import XcodeProjMapper + +extension IntegrationTests { + @Test("Maps an iOS workspace using microfeature architecture with static linking into the correct graph") + func iosWorkspaceWithMicrofeatureArchitectureStaticLinking() throws { + try assertGraph { + .iosWorkspaceWithMicrofeatureArchitectureStaticLinking + } name: { + """ + - "Workspace" + + """ + } dependencies: { + """ + ▿ 6 key/value pairs + ▿ (2 elements) + ▿ key: target 'CoreTests' + ▿ target: (3 elements) + - name: "CoreTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Core' + ▿ target: (3 elements) + - name: "Core" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'DataTests' + ▿ target: (3 elements) + - name: "DataTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Data' + ▿ target: (3 elements) + - name: "Data" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'FeatureContractsTests' + ▿ target: (3 elements) + - name: "FeatureContractsTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'FeatureContracts' + ▿ target: (3 elements) + - name: "FeatureContracts" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'FrameworkATests' + ▿ target: (3 elements) + - name: "FrameworkATests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'FrameworkA' + ▿ target: (3 elements) + - name: "FrameworkA" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'StaticAppTests' + ▿ target: (3 elements) + - name: "StaticAppTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'StaticApp' + ▿ target: (3 elements) + - name: "StaticApp" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'UIComponentsTests' + ▿ target: (3 elements) + - name: "UIComponentsTests" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'UIComponents' + ▿ target: (3 elements) + - name: "UIComponents" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - status: LinkingStatus.required + + """ + } dependencyConditions: { + """ + - 0 key/value pairs + + """ + } packages: { + """ + - 0 key/value pairs + + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "Workspace" + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking + ▿ projects: 6 elements + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Core.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Data.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/FrameworkA.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/FeatureContracts.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/UIComponents.xcodeproj + - /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/StaticApp.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Workspace.xcworkspace + + """ + } projects: { + """ + ▿ 6 key/value pairs + ▿ (2 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Core.xcodeproj + ▿ value: Core + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework + - name: "Core" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "Core" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift + - buildRules: 0 elements + - bundleId: "io.tuist.Core" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Core" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Core" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift + ▿ (2 elements) + - key: "CoreTests" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Sources/CoreClass.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests.plist + - buildRules: 0 elements + - bundleId: "io.tuist.CoreTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Core" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "CoreTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "CoreTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/CoreFramework/Tests/CoreClassTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Data.xcodeproj + ▿ value: Data + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework + - name: "Data" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "Data" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift + - buildRules: 0 elements + - bundleId: "io.tuist.Data" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Data" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Data" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift + ▿ (2 elements) + - key: "DataTests" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Sources/DataClass.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests.plist + - buildRules: 0 elements + - bundleId: "io.tuist.DataFrameworkTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Data" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "DataTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "DataTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/DataFramework/Tests/FrameworkATests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/FrameworkA.xcodeproj + ▿ value: FrameworkA + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework + - name: "FrameworkA" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "FrameworkA" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift + - buildRules: 0 elements + - bundleId: "io.tuist.FrameworkA" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "FrameworkA" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "FrameworkA" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift + ▿ (2 elements) + - key: "FrameworkATests" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Sources/FrameworkA.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests.plist + - buildRules: 0 elements + - bundleId: "io.tuist.FrameworkATests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "FrameworkA" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "FrameworkATests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "FrameworkATests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureAFramework/Tests/FrameworkATests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/FeatureContracts.xcodeproj + ▿ value: FeatureContracts + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts + - name: "FeatureContracts" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "FeatureContracts" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift + - buildRules: 0 elements + - bundleId: "io.tuist.FeatureContracts" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "FeatureContracts" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "FeatureContracts" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 2 elements + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift + ▿ (2 elements) + - key: "FeatureContractsTests" + ▿ value: Target + ▿ additionalFiles: 4 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureAContract.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Sources/FeatureBContract.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests.plist + - buildRules: 0 elements + - bundleId: "io.tuist.FeatureContractsTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "FeatureContracts" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "FeatureContractsTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "FeatureContractsTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/FeatureContracts/Tests/FrameworkAContractTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/UIComponents.xcodeproj + ▿ value: UIComponents + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework + - name: "UIComponents" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "UIComponents" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift + - buildRules: 0 elements + - bundleId: "io.tuist.UIComponents" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Dependencies" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "UIComponents" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "UIComponents" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift + ▿ (2 elements) + - key: "UIComponentsTests" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Sources/UIComponentA.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests.plist + - buildRules: 0 elements + - bundleId: "io.tuist.UIComponentsTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "UIComponents" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "UIComponentsTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "UIComponentsTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/Frameworks/UIComponentsFramework/Tests/UIComponentATests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/StaticApp.xcodeproj + ▿ value: StaticApp + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - sourceRootPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - xcodeProjPath: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp + - name: "StaticApp" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "StaticApp" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift + - buildRules: 0 elements + - bundleId: "io.tuist.StaticApp" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticApp" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "StaticApp" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "StaticAppTests" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests.plist + - buildRules: 0 elements + - bundleId: "io.tuist.StaticAppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "StaticApp" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticAppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "StaticAppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_workspace_with_microfeature_architecture_static_linking/StaticApp/Tests/AppTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift new file mode 100644 index 00000000..da3f0e2b --- /dev/null +++ b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+ios_app_with_transitive_framework.swift @@ -0,0 +1,945 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProj +import XcodeProjMapper + +extension IntegrationTests { + @Test("Maps an iOS app with a transitive framework dependency into the correct graph") + func ios_app_with_transitive_framework() throws { + try assertGraph { + .ios_app_with_transitive_framework + } name: { + """ + - "Workspace" + + """ + } dependencies: { + """ + ▿ 8 key/value pairs + ▿ (2 elements) + ▿ key: target 'AppTests' + ▿ target: (3 elements) + - name: "AppTests" + - path: /Fixtures/ios_app_with_transitive_framework/App + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_transitive_framework/App + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'AppUITests' + ▿ target: (3 elements) + - name: "AppUITests" + - path: /Fixtures/ios_app_with_transitive_framework/App + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'App' + ▿ target: (3 elements) + - name: "App" + - path: /Fixtures/ios_app_with_transitive_framework/App + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1-iOS' + ▿ target: (3 elements) + - name: "Framework1-iOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ framework 'Framework2.framework' + ▿ framework: (7 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 + - dsymPath: Optional.none + - bcsymbolmapPaths: 0 elements + - linking: BinaryLinking.dynamic + - architectures: 0 elements + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1-macOS' + ▿ target: (3 elements) + - name: "Framework1-macOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ framework 'Framework2.framework' + ▿ framework: (7 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework + - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework/Framework2 + - dsymPath: Optional.none + - bcsymbolmapPaths: 0 elements + - linking: BinaryLinking.dynamic + - architectures: 0 elements + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1Tests-iOS' + ▿ target: (3 elements) + - name: "Framework1Tests-iOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Framework1-iOS' + ▿ target: (3 elements) + - name: "Framework1-iOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'Framework1Tests-macOS' + ▿ target: (3 elements) + - name: "Framework1Tests-macOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'Framework1-macOS' + ▿ target: (3 elements) + - name: "Framework1-macOS" + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'StaticFramework1' + ▿ target: (3 elements) + - name: "StaticFramework1" + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - status: LinkingStatus.required + ▿ value: 1 member + ▿ framework 'Framework2.framework' + ▿ framework: (7 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 + - dsymPath: Optional.none + - bcsymbolmapPaths: 0 elements + - linking: BinaryLinking.dynamic + - architectures: 0 elements + - status: LinkingStatus.required + ▿ (2 elements) + ▿ key: target 'StaticFramework1Tests' + ▿ target: (3 elements) + - name: "StaticFramework1Tests" + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - status: LinkingStatus.required + ▿ value: 2 members + ▿ framework 'Framework2.framework' + ▿ framework: (7 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - binaryPath: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework/Framework2 + - dsymPath: Optional.none + - bcsymbolmapPaths: 0 elements + - linking: BinaryLinking.dynamic + - architectures: 0 elements + - status: LinkingStatus.required + ▿ target 'StaticFramework1' + ▿ target: (3 elements) + - name: "StaticFramework1" + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - status: LinkingStatus.required + + """ + } dependencyConditions: { + """ + - 0 key/value pairs + + """ + } packages: { + """ + - 0 key/value pairs + + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "Workspace" + - path: /Fixtures/ios_app_with_transitive_framework + ▿ projects: 3 elements + - /Fixtures/ios_app_with_transitive_framework/App/MainApp.xcodeproj + - /Fixtures/ios_app_with_transitive_framework/Framework1/Framework1.xcodeproj + - /Fixtures/ios_app_with_transitive_framework/StaticFramework1/StaticFramework1.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/ios_app_with_transitive_framework/Workspace.xcworkspace + + """ + } projects: { + """ + ▿ 3 key/value pairs + ▿ (2 elements) + - key: /Fixtures/ios_app_with_transitive_framework/App/MainApp.xcodeproj + ▿ value: MainApp + - path: /Fixtures/ios_app_with_transitive_framework/App + - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/App + - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/App + - name: "MainApp" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 3 key/value pairs + ▿ (2 elements) + - key: "App" + ▿ value: Target + ▿ additionalFiles: 5 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - buildRules: 0 elements + - bundleId: "io.tuist.App" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "App" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "App" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift + ▿ (2 elements) + - key: "AppTests" + ▿ value: Target + ▿ additionalFiles: 5 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - buildRules: 0 elements + - bundleId: "io.tuist.AppTests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppTests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "AppTests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift + ▿ (2 elements) + - key: "AppUITests" + ▿ value: Target + ▿ additionalFiles: 5 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Config/App-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Config/AppTests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Sources/AppDelegate.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/App/Tests/AppDelegateTests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - buildRules: 0 elements + - bundleId: "io.tuist.AppUITests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "App" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "AppUITests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: ui tests + - productName: "AppUITests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/App/UITests/AppUITest.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_app_with_transitive_framework/Framework1/Framework1.xcodeproj + ▿ value: Framework1 + - path: /Fixtures/ios_app_with_transitive_framework/Framework1 + - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/Framework1 + - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/Framework1 + - name: "Framework1" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 4 key/value pairs + ▿ (2 elements) + - key: "Framework1-iOS" + ▿ value: Target + ▿ additionalFiles: 4 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ framework: (3 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1-iOS" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Framework1" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift + ▿ (2 elements) + - key: "Framework1-macOS" + ▿ value: Target + ▿ additionalFiles: 4 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ framework: (3 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1-macOS" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "Framework1" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift + ▿ (2 elements) + - key: "Framework1Tests-iOS" + ▿ value: Target + ▿ additionalFiles: 5 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Framework1-iOS" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1Tests-iOS" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "Framework1Tests_iOS" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift + ▿ (2 elements) + - key: "Framework1Tests-macOS" + ▿ value: Target + ▿ additionalFiles: 5 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Config/Framework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Sources/Framework1File.swift + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/Mac/Framework2.framework + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - buildRules: 0 elements + - bundleId: "io.tuist.Framework1Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "Framework1-macOS" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "Framework1Tests-macOS" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "Framework1Tests_macOS" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/Framework1/Tests/Framework1FileTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + ▿ (2 elements) + - key: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/StaticFramework1.xcodeproj + ▿ value: StaticFramework1 + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - sourceRootPath: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - xcodeProjPath: /Fixtures/ios_app_with_transitive_framework/StaticFramework1 + - name: "StaticFramework1" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "StaticFramework1" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Derived/InfoPlists/StaticFramework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Derived/InfoPlists/StaticFramework1Tests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift + - buildRules: 0 elements + - bundleId: "io.tuist.StaticFramework1" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ framework: (3 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticFramework1" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: dynamic framework + - productName: "StaticFramework1" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift + ▿ (2 elements) + - key: "StaticFramework1Tests" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Derived/InfoPlists/StaticFramework1-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Derived/InfoPlists/StaticFramework1Tests-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Sources/Framework1File.swift + - buildRules: 0 elements + - bundleId: "io.tuist.StaticFramework1Tests" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + ▿ dependencies: 2 elements + ▿ TargetDependency + ▿ framework: (3 elements) + - path: /Fixtures/ios_app_with_transitive_framework/Framework2/prebuilt/iOS/Framework2.framework + - status: LinkingStatus.required + - condition: Optional.none + ▿ TargetDependency + ▿ target: (3 elements) + - name: "StaticFramework1" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "StaticFramework1Tests" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: unit tests + - productName: "StaticFramework1Tests" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/ios_app_with_transitive_framework/StaticFramework1/Tests/Framework1FileTests.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift new file mode 100644 index 00000000..f8f3c8d0 --- /dev/null +++ b/Tests/XcodeProjMapperTests/IntegrationTests/Projects/IntegrationTests+macosAppWithSystemExtension.swift @@ -0,0 +1,255 @@ +import Foundation +import InlineSnapshotTesting +import Path +import Testing +import XcodeGraph +import XcodeProj +import XcodeProjMapper + +extension IntegrationTests { + @Test("Maps a macOS app with a system extension into the correct graph") + func macosAppWithSystemExtension() throws { + try assertGraph { + .macosAppWithSystemExtension + } name: { + """ + - "App with SystemExtension" + + """ + } dependencies: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + ▿ key: target 'MainApp' + ▿ target: (3 elements) + - name: "MainApp" + - path: /Fixtures/macos_app_with_system_extension + - status: LinkingStatus.required + ▿ value: 1 member + ▿ target 'SystemExtension' + ▿ target: (3 elements) + - name: "SystemExtension" + - path: /Fixtures/macos_app_with_system_extension + - status: LinkingStatus.required + + """ + } dependencyConditions: { + """ + - 0 key/value pairs + + """ + } packages: { + """ + - 0 key/value pairs + + """ + } workspace: { + """ + ▿ Workspace + - additionalFiles: 0 elements + ▿ generationOptions: GenerationOptions + ▿ autogeneratedWorkspaceSchemes: AutogeneratedWorkspaceSchemes + ▿ enabled: (5 elements) + - codeCoverageMode: CodeCoverageMode.disabled + ▿ testingOptions: TestingOptions + - rawValue: 0 + - testLanguage: Optional.none + - testRegion: Optional.none + - testScreenCaptureFormat: Optional.none + ▿ enableAutomaticXcodeSchemes: Optional + - some: false + - lastXcodeUpgradeCheck: Optional.none + - renderMarkdownReadme: false + - ideTemplateMacros: Optional.none + - name: "App with SystemExtension" + - path: /Fixtures/macos_app_with_system_extension + ▿ projects: 1 element + - /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcodeproj + - schemes: 0 elements + - xcWorkspacePath: /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcworkspace + + """ + } projects: { + """ + ▿ 1 key/value pair + ▿ (2 elements) + - key: /Fixtures/macos_app_with_system_extension/App with SystemExtension.xcodeproj + ▿ value: App with SystemExtension + - path: /Fixtures/macos_app_with_system_extension + - sourceRootPath: /Fixtures/macos_app_with_system_extension + - xcodeProjPath: /Fixtures/macos_app_with_system_extension + - name: "App with SystemExtension" + - organizationName: Optional.none + - classPrefix: Optional.none + ▿ defaultKnownRegions: Optional> + ▿ some: 2 elements + - "Base" + - "en" + ▿ developmentRegion: Optional + - some: "en" + ▿ options: Options + - automaticSchemesOptions: AutomaticSchemesOptions.disabled + - disableBundleAccessors: false + - disableShowEnvironmentVarsInScriptPhases: false + - disableSynthesizedResourceAccessors: false + ▿ textSettings: TextSettings + - indentWidth: Optional.none + - tabWidth: Optional.none + - usesTabs: Optional.none + - wrapsLines: Optional.none + ▿ targets: 2 key/value pairs + ▿ (2 elements) + - key: "MainApp" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/macos_app_with_system_extension/Derived/InfoPlists/SystemExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/macos_app_with_system_extension/MainApp/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift + - buildRules: 0 elements + - bundleId: "io.tuist.MainApp" + ▿ copyFiles: 2 elements + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + ▿ CopyFilesAction + - destination: Destination.productsDirectory + - files: 0 elements + - name: "Embed System Extensions" + ▿ subpath: Optional + - some: "$(CONTENTS_FOLDER_PATH)/Library/SystemExtensions" + - coreDataModels: 0 elements + ▿ dependencies: 1 element + ▿ TargetDependency + ▿ target: (3 elements) + - name: "SystemExtension" + - status: LinkingStatus.required + - condition: Optional.none + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "MainApp" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: application + - productName: "MainApp" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift + ▿ (2 elements) + - key: "SystemExtension" + ▿ value: Target + ▿ additionalFiles: 3 elements + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/macos_app_with_system_extension/Derived/InfoPlists/SystemExtension-Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/macos_app_with_system_extension/MainApp/Info.plist + ▿ FileElement + ▿ file: (1 element) + - path: /Fixtures/macos_app_with_system_extension/MainApp/Sources/main.swift + - buildRules: 0 elements + - bundleId: "io.tuist.SystemExtension" + ▿ copyFiles: 1 element + ▿ CopyFilesAction + - destination: Destination.frameworks + - files: 0 elements + - name: "Embed Frameworks" + - subpath: Optional.none + - coreDataModels: 0 elements + - dependencies: 0 elements + ▿ deploymentTargets: DeploymentTargets + - iOS: Optional.none + - macOS: Optional.none + - tvOS: Optional.none + - visionOS: Optional.none + - watchOS: Optional.none + - destinations: 0 members + - entitlements: Optional.none + - environmentVariables: 0 key/value pairs + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "MainGroup" + - headers: Optional.none + - infoPlist: Optional.none + - launchArguments: 0 elements + - mergeable: false + - mergedBinaryType: MergedBinaryType.disabled + ▿ metadata: TargetMetadata + - tags: 0 members + - name: "SystemExtension" + - onDemandResourcesTags: Optional.none + - playgrounds: 0 elements + - product: system extension + - productName: "SystemExtension" + - prune: false + - rawScriptBuildPhases: 0 elements + ▿ resources: ResourceFileElements + - privacyManifest: Optional.none + - resources: 0 elements + - scripts: 0 elements + - settings: Optional.none + ▿ sources: 1 element + ▿ SourceFile + - codeGen: Optional.none + - compilationCondition: Optional.none + - compilerFlags: Optional.none + - contentHash: Optional.none + - path: /Fixtures/macos_app_with_system_extension/SystemExtension/Sources/main.swift + - packages: 0 elements + - schemes: 0 elements + ▿ settings: Settings + - base: 0 key/value pairs + - baseDebug: 0 key/value pairs + - configurations: 0 key/value pairs + ▿ defaultSettings: DefaultSettings + ▿ recommended: (1 element) + - excluding: 0 members + ▿ filesGroup: ProjectGroup + ▿ group: (1 element) + - name: "Project" + - additionalFiles: 0 elements + - ideTemplateMacros: Optional.none + - resourceSynthesizers: 0 elements + - lastUpgradeCheck: Optional.none + - type: local project + + """ + } + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Graph/GraphMapperTests.swift similarity index 52% rename from Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift rename to Tests/XcodeProjMapperTests/MapperTests/Graph/GraphMapperTests.swift index d9992dde..8a89e988 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/GraphMapper/GraphMapperTests.swift +++ b/Tests/XcodeProjMapperTests/MapperTests/Graph/GraphMapperTests.swift @@ -2,29 +2,40 @@ import Path import Testing import XcodeGraph import XcodeProj - -@testable import TestSupport -@testable import XcodeProjToGraph +@testable import XcodeProjMapper @Suite struct GraphMapperTests { @Test("Maps a single project into a workspace graph") - func testSingleProjectGraph() async throws { + func testSingleProjectGraph() throws { + let pbxProj = PBXProj() + let debug: XCBuildConfiguration = .testDebug().add(to: pbxProj) + let releaseConfig: XCBuildConfiguration = .testRelease().add(to: pbxProj) + let configurationList: XCConfigurationList = .test(buildConfigurations: [debug, releaseConfig]).add(to: pbxProj) let mockProvider = MockProjectProvider( sourceDirectory: "/tmp/SingleProject", - projectName: "SingleProject" + projectName: "SingleProject", + configurationList: configurationList, + pbxProj: pbxProj ) + let sourceFile = try PBXFileReference.test( + path: "ViewController.swift", + lastKnownFileType: "sourcecode.swift" + ).add(to: pbxProj).addToMainGroup(in: pbxProj) + + let buildFile = PBXBuildFile(file: sourceFile).add(to: pbxProj) + let sourcesPhase = PBXSourcesBuildPhase(files: [buildFile]).add(to: pbxProj) + // Add a single target to the project - let pbxProj = mockProvider.xcodeProj.pbxproj - let target = PBXNativeTarget.mock( + try PBXNativeTarget.test( name: "App", - productType: .application, - pbxProj: pbxProj + buildConfigurationList: configurationList, + buildPhases: [sourcesPhase], + productType: .application ) - if let project = pbxProj.projects.first { - project.targets.append(target) - } + .add(to: pbxProj) + .add(to: pbxProj.rootObject) // Create a GraphType for a single project let projectPath = try AbsolutePath(validating: mockProvider.sourceDirectory.pathString) @@ -36,7 +47,7 @@ struct GraphMapperTests { return mockProvider } - let graph = try await mapper.xcodeGraph() + let graph = try mapper.map() // Validate the graph #expect(graph.name == "Workspace") @@ -52,38 +63,57 @@ struct GraphMapperTests { } @Test("Maps a workspace with multiple projects into a single graph") - func testWorkspaceGraphMultipleProjects() async throws { + func testWorkspaceGraphMultipleProjects() throws { + let pbxProjA = PBXProj() + let pbxProjB = PBXProj() + + let debug: XCBuildConfiguration = .testDebug().add(to: pbxProjA).add(to: pbxProjB) + let releaseConfig: XCBuildConfiguration = .testRelease().add(to: pbxProjA).add(to: pbxProjB) + let configurationList: XCConfigurationList = .test(buildConfigurations: [debug, releaseConfig]).add(to: pbxProjA) + .add(to: pbxProjB) + // Setup two mock projects + let mockProviderA = MockProjectProvider( sourceDirectory: "/tmp/Workspace/ProjectA", - projectName: "ProjectA" + projectName: "ProjectA", + configurationList: configurationList, + pbxProj: pbxProjA ) + let mockProviderB = MockProjectProvider( sourceDirectory: "/tmp/Workspace/ProjectB", - projectName: "ProjectB" + projectName: "ProjectB", + configurationList: configurationList, + pbxProj: pbxProjB ) - // Add a target to Project A - let pbxProjA = mockProviderA.xcodeProj.pbxproj - let targetA = PBXNativeTarget.mock( + let sourceFile = try PBXFileReference.test( + path: "ViewController.swift", + lastKnownFileType: "sourcecode.swift" + ).add(to: pbxProjA).addToMainGroup(in: pbxProjA) + + let buildFile = PBXBuildFile(file: sourceFile).add(to: pbxProjB) + let sourcesPhase = PBXSourcesBuildPhase(files: [buildFile]).add(to: pbxProjB) + + // Add targets to each project + try PBXNativeTarget.test( name: "ATarget", - productType: .framework, - pbxProj: pbxProjA + buildConfigurationList: configurationList, + buildPhases: [sourcesPhase], + productType: .framework ) - if let projectA = pbxProjA.projects.first { - projectA.targets.append(targetA) - } + .add(to: pbxProjA) + .add(to: pbxProjA.rootObject) - // Add a target to Project B - let pbxProjB = mockProviderB.xcodeProj.pbxproj - let targetB = PBXNativeTarget.mock( + try PBXNativeTarget.test( name: "BTarget", - productType: .framework, - pbxProj: pbxProjB + buildConfigurationList: configurationList, + buildPhases: [sourcesPhase], + productType: .framework ) - if let projectB = pbxProjB.projects.first { - projectB.targets.append(targetB) - } + .add(to: pbxProjB) + .add(to: pbxProjB.rootObject) // Set up a workspace referencing the two projects let workspacePath = try AbsolutePath(validating: "/tmp/Workspace") @@ -108,61 +138,75 @@ struct GraphMapperTests { return mockProviderB } else { Issue.record("Unexpected project path requested: \(path)") - throw MappingError.noProjectsFound(path: path.pathString) + return MockProjectProvider() } } - let graph = try await mapper.xcodeGraph() + let graph = try mapper.map() // Validate the graph #expect(graph.workspace.name == "Workspace") #expect(graph.workspace.projects.contains(projectAPath) == true) #expect(graph.workspace.projects.contains(projectBPath) == true) - - // Check that both projects appear in the graph #expect(graph.projects.count == 2) + let projectA = try #require(graph.projects[projectAPath]) let projectB = try #require(graph.projects[projectBPath]) #expect(projectA.targets["ATarget"] != nil) #expect(projectB.targets["BTarget"] != nil) - // No packages or dependencies were added + // No packages or dependencies #expect(graph.packages.isEmpty == true) #expect(graph.dependencies.isEmpty == true) #expect(graph.dependencyConditions.isEmpty == true) } @Test("Maps a project graph with dependencies between targets") - func testGraphWithDependencies() async throws { + func testGraphWithDependencies() throws { + let pbxProj = PBXProj() + let debug: XCBuildConfiguration = .testDebug().add(to: pbxProj) + let releaseConfig: XCBuildConfiguration = .testRelease().add(to: pbxProj) + let configurationList: XCConfigurationList = .test(buildConfigurations: [debug, releaseConfig]).add(to: pbxProj) // Setup a single project with two targets: App depends on AFramework let mockProvider = MockProjectProvider( sourceDirectory: "/tmp/ProjectWithDeps", - projectName: "ProjectWithDeps" - ) - let pbxProj = mockProvider.xcodeProj.pbxproj - - let frameworkTarget = PBXNativeTarget.mock( - name: "AFramework", - productType: .framework, + projectName: "ProjectWithDeps", + configurationList: configurationList, pbxProj: pbxProj ) - let appTarget = PBXNativeTarget.mock( + let sourceFile = try PBXFileReference.test( + path: "ViewController.swift", + lastKnownFileType: "sourcecode.swift" + ).add(to: pbxProj).addToMainGroup(in: pbxProj) + + let buildFile = PBXBuildFile(file: sourceFile).add(to: pbxProj) + let sourcesPhase = PBXSourcesBuildPhase(files: [buildFile]).add(to: pbxProj) + + // Add a single target to the project + let appTarget = try PBXNativeTarget.test( name: "App", - productType: .application, - pbxProj: pbxProj + buildConfigurationList: configurationList, + buildPhases: [sourcesPhase], + productType: .application ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) // App -> AFramework dependency - let dep = PBXTargetDependency.mockTargetDependency( + let target = try PBXNativeTarget.test( name: "AFramework", - pbxProj: pbxProj + buildConfigurationList: configurationList, + buildPhases: [sourcesPhase], + productType: .framework + ).add(to: pbxProj).add(to: pbxProj.rootObject) + + let dep = PBXTargetDependency( + name: "AFramework", + target: target ) - appTarget.dependencies.append(dep) - if let project = pbxProj.projects.first { - project.targets.append(contentsOf: [frameworkTarget, appTarget]) - } + appTarget.dependencies.append(dep) let projectPath = try AbsolutePath(validating: mockProvider.xcodeProjPath.pathString) let graphType = GraphType.project(projectPath) @@ -172,7 +216,7 @@ struct GraphMapperTests { return mockProvider } - let graph = try await mapper.xcodeGraph() + let graph = try mapper.map() // Verify dependencies are mapped let sourceDep = GraphDependency.target(name: "App", path: mockProvider.sourceDirectory) diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Package/XCPackageMapperTests.swift similarity index 60% rename from Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift rename to Tests/XcodeProjMapperTests/MapperTests/Package/XCPackageMapperTests.swift index 5783553d..45f32267 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/PackageMapperTests.swift +++ b/Tests/XcodeProjMapperTests/MapperTests/Package/XCPackageMapperTests.swift @@ -2,39 +2,39 @@ import Path import Testing import XcodeGraph import XcodeProj - -@testable import TestSupport -@testable import XcodeProjToGraph +@testable import XcodeProjMapper @Suite -struct PackageMapperTests { - let mapper: PackageMapper +struct XCPackageMapperTests { + let mapper: XCPackageMapper let projectProvider: MockProjectProvider init() { let provider = MockProjectProvider() projectProvider = provider - mapper = PackageMapper(projectProvider: provider) + mapper = XCPackageMapper() } @Test("Maps a remote package with a valid URL and up-to-next-major requirement") - func testMapPackageWithValidURL() async throws { - let package = XCRemoteSwiftPackageReference.mock( + func testMapPackageWithValidURL() throws { + let package = XCRemoteSwiftPackageReference( repositoryURL: "https://github.com/example/package.git", versionRequirement: .upToNextMajorVersion("1.0.0") ) - let result = try await mapper.map(package: package) + let result = try mapper.map(package: package) #expect( - result == .remote( - url: "https://github.com/example/package.git", requirement: .upToNextMajor("1.0.0") - ) + result + == .remote( + url: "https://github.com/example/package.git", + requirement: .upToNextMajor("1.0.0") + ) ) } @Test("Maps an up-to-next-major version requirement correctly") - func testMapRequirementUpToNextMajor() async throws { - let package = XCRemoteSwiftPackageReference.mock( + func testMapRequirementUpToNextMajor() throws { + let package = XCRemoteSwiftPackageReference( repositoryURL: "https://github.com/example/package.git", versionRequirement: .upToNextMajorVersion("1.0.0") ) @@ -44,8 +44,8 @@ struct PackageMapperTests { } @Test("Maps an up-to-next-minor version requirement correctly") - func testMapRequirementUpToNextMinor() async throws { - let package = XCRemoteSwiftPackageReference.mock( + func testMapRequirementUpToNextMinor() throws { + let package = XCRemoteSwiftPackageReference( repositoryURL: "https://github.com/example/package.git", versionRequirement: .upToNextMinorVersion("1.2.0") ) @@ -55,8 +55,8 @@ struct PackageMapperTests { } @Test("Maps an exact version requirement correctly") - func testMapRequirementExact() async throws { - let package = XCRemoteSwiftPackageReference.mock( + func testMapRequirementExact() throws { + let package = XCRemoteSwiftPackageReference( repositoryURL: "https://github.com/example/package.git", versionRequirement: .exact("1.2.3") ) @@ -66,8 +66,8 @@ struct PackageMapperTests { } @Test("Maps a range version requirement correctly") - func testMapRequirementRange() async throws { - let package = XCRemoteSwiftPackageReference.mock( + func testMapRequirementRange() throws { + let package = XCRemoteSwiftPackageReference( repositoryURL: "https://github.com/example/package.git", versionRequirement: .range(from: "1.0.0", to: "2.0.0") ) @@ -77,8 +77,8 @@ struct PackageMapperTests { } @Test("Maps a branch-based version requirement correctly") - func testMapRequirementBranch() async throws { - let package = XCRemoteSwiftPackageReference.mock( + func testMapRequirementBranch() throws { + let package = XCRemoteSwiftPackageReference( repositoryURL: "https://github.com/example/package.git", versionRequirement: .branch("main") ) @@ -88,8 +88,8 @@ struct PackageMapperTests { } @Test("Maps a revision-based version requirement correctly") - func testMapRequirementRevision() async throws { - let package = XCRemoteSwiftPackageReference.mock( + func testMapRequirementRevision() throws { + let package = XCRemoteSwiftPackageReference( repositoryURL: "https://github.com/example/package.git", versionRequirement: .revision("abc123") ) @@ -99,8 +99,8 @@ struct PackageMapperTests { } @Test("Maps a missing version requirement to up-to-next-major(0.0.0)") - func testMapRequirementNoVersionRequirement() async throws { - let package = XCRemoteSwiftPackageReference.mock( + func testMapRequirementNoVersionRequirement() throws { + let package = XCRemoteSwiftPackageReference( repositoryURL: "https://github.com/example/package.git", versionRequirement: nil ) @@ -110,14 +110,28 @@ struct PackageMapperTests { } @Test("Maps a local package reference correctly") - func testMapLocalPackage() async throws { - let localPackage = XCLocalSwiftPackageReference.mock(relativePath: "Packages/Example") - - let result = try await mapper.map(package: localPackage) + func testMapLocalPackage() throws { + let localPackage = XCLocalSwiftPackageReference(relativePath: "Packages/Example") + let result = try mapper.map(package: localPackage, sourceDirectory: projectProvider.sourceDirectory) let expectedPath = projectProvider.sourceDirectory.appending( try RelativePath(validating: "Packages/Example") ) #expect(result == .local(path: expectedPath)) } + + @Test("Throws an error if remote package has no repository URL") + func testMapPackageWithoutURL() async throws { + let package = XCRemoteSwiftPackageReference( + repositoryURL: "", + versionRequirement: .exact("1.2.3") + ) + package.repositoryURL = nil + + #expect { + try mapper.map(package: package) + } throws: { error in + return error.localizedDescription == "The repository URL is missing for the package: Unknown Package." + } + } } diff --git a/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXCopyFilesBuildPhaseMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXCopyFilesBuildPhaseMapperTests.swift new file mode 100644 index 00000000..30bdba91 --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXCopyFilesBuildPhaseMapperTests.swift @@ -0,0 +1,54 @@ +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +@Suite +struct PBXCopyFilesBuildPhaseMapperTests { + @Test("Maps copy files actions, verifying code-sign-on-copy attributes") + func testMapCopyFiles() throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj + + let fileRef = try PBXFileReference.test( + sourceTree: .group, + name: "MyLibrary.dylib", + path: "MyLibrary.dylib" + ) + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + + let buildFile = PBXBuildFile( + file: fileRef, + settings: ["ATTRIBUTES": ["CodeSignOnCopy"]] + ).add(to: pbxProj) + + let copyFilesPhase = PBXCopyFilesBuildPhase( + dstPath: "Libraries", + dstSubfolderSpec: .frameworks, + name: "Embed Libraries", + files: [buildFile] + ).add(to: pbxProj) + + try PBXNativeTarget.test( + name: "App", + buildPhases: [copyFilesPhase], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapper = PBXCopyFilesBuildPhaseMapper() + let copyActions = try mapper.map([copyFilesPhase], projectProvider: provider) + + #expect(copyActions.count == 1) + let action = try #require(copyActions.first) + #expect(action.name == "Embed Libraries") + #expect(action.destination == .frameworks) + #expect(action.subpath == "Libraries") + #expect(action.files.count == 1) + let fileAction = try #require(action.files.first) + #expect(fileAction.codeSignOnCopy == true) + #expect(fileAction.path.basename == "MyLibrary.dylib") + } +} diff --git a/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXCoreDataModelsBuildPhaseMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXCoreDataModelsBuildPhaseMapperTests.swift new file mode 100644 index 00000000..d3ee931f --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXCoreDataModelsBuildPhaseMapperTests.swift @@ -0,0 +1,54 @@ +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +@Suite +struct PBXCoreDataModelsBuildPhaseMapperTests { + @Test("Maps CoreData models from version groups within resources phase") + func testMapCoreDataModels() throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj + + let versionChildRef = try PBXFileReference.test( + name: "Model.xcdatamodel", + path: "Model.xcdatamodel" + ) + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + + let versionGroup = try XCVersionGroup.test( + currentVersion: versionChildRef, + children: [versionChildRef], + path: "Model.xcdatamodeld", + sourceTree: .group, + versionGroupType: "wrapper.xcdatamodel", + name: "Model.xcdatamodeld", + pbxProj: pbxProj + ) + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + + versionGroup.currentVersion?.add(to: pbxProj) + + let buildFile = PBXBuildFile(file: versionGroup).add(to: pbxProj) + let resourcesPhase = PBXResourcesBuildPhase(files: [buildFile]).add(to: pbxProj) + + try PBXNativeTarget.test( + name: "App", + buildPhases: [resourcesPhase], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapper = PBXCoreDataModelsBuildPhaseMapper() + let models = try mapper.map([buildFile], projectProvider: provider) + + #expect(models.count == 1) + let model = try #require(models.first) + #expect(model.path.basename == "Model.xcdatamodeld") + #expect(model.versions.count == 1) + #expect(model.currentVersion.contains("Model.xcdatamodel") == true) + } +} diff --git a/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXFrameworksBuildPhaseMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXFrameworksBuildPhaseMapperTests.swift new file mode 100644 index 00000000..35b99b8b --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXFrameworksBuildPhaseMapperTests.swift @@ -0,0 +1,39 @@ +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +@Suite +struct PBXFrameworksBuildPhaseMapperTests { + @Test("Maps frameworks from frameworks phase") + func testMapFrameworks() throws { + let mockProvider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = mockProvider.xcodeProj.pbxproj + + let frameworkRef = try PBXFileReference( + sourceTree: .group, + name: "MyFramework.framework", + path: "Frameworks/MyFramework.framework" + ) + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + + let frameworkBuildFile = PBXBuildFile(file: frameworkRef).add(to: pbxProj) + let frameworksPhase = PBXFrameworksBuildPhase(files: [frameworkBuildFile]).add(to: pbxProj) + + try PBXNativeTarget( + name: "App", + buildPhases: [frameworksPhase], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapper = PBXFrameworksBuildPhaseMapper() + let frameworks = try mapper.map(frameworksPhase, projectProvider: mockProvider) + + #expect(frameworks.count == 1) + let dependency = try #require(frameworks.first) + #expect(dependency.name == "MyFramework") + } +} diff --git a/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXHeadersBuildPhaseMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXHeadersBuildPhaseMapperTests.swift new file mode 100644 index 00000000..3fc4fc8d --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXHeadersBuildPhaseMapperTests.swift @@ -0,0 +1,66 @@ +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +@Suite +struct PBXHeadersBuildPhaseMapperTests { + @Test("Maps public, private, and project headers from headers phase") + func testMapHeaders() throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj + + let publicHeaderRef = try PBXFileReference.test( + name: "PublicHeader.h", + path: "Include/PublicHeader.h" + ) + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + + let publicBuildFile = PBXBuildFile( + file: publicHeaderRef, + settings: ["ATTRIBUTES": ["Public"]] + ).add(to: pbxProj) + + let privateHeaderRef = try PBXFileReference.test( + name: "PrivateHeader.h", + path: "Include/PrivateHeader.h" + ) + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + + let privateBuildFile = PBXBuildFile( + file: privateHeaderRef, + settings: ["ATTRIBUTES": ["Private"]] + ).add(to: pbxProj) + + let projectHeaderRef = try PBXFileReference.test( + name: "ProjectHeader.h", + path: "Include/ProjectHeader.h" + ) + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + + let projectBuildFile = PBXBuildFile(file: projectHeaderRef).add(to: pbxProj) + + let headersPhase = PBXHeadersBuildPhase( + files: [publicBuildFile, privateBuildFile, projectBuildFile] + ).add(to: pbxProj) + + try PBXNativeTarget( + name: "App", + buildPhases: [headersPhase], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapper = PBXHeadersBuildPhaseMapper() + let headers = try mapper.map(headersPhase, projectProvider: provider) + try #require(headers != nil) + + #expect(headers?.public.map(\.basename).contains("PublicHeader.h") == true) + #expect(headers?.private.map(\.basename).contains("PrivateHeader.h") == true) + #expect(headers?.project.map(\.basename).contains("ProjectHeader.h") == true) + } +} diff --git a/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXResourcesBuildPhaseMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXResourcesBuildPhaseMapperTests.swift new file mode 100644 index 00000000..ca159580 --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXResourcesBuildPhaseMapperTests.swift @@ -0,0 +1,78 @@ +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +@Suite +struct PBXResourcesBuildPhaseMapperTests { + @Test("Maps resources (like xcassets) from resources phase") + func testMapResources() throws { + let mockProvider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = mockProvider.xcodeProj.pbxproj + + let assetRef = try PBXFileReference( + sourceTree: .group, + name: "Assets.xcassets", + path: "Assets.xcassets" + ) + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + .add(to: pbxProj) + + let buildFile = PBXBuildFile(file: assetRef).add(to: pbxProj) + let resourcesPhase = PBXResourcesBuildPhase(files: [buildFile]).add(to: pbxProj) + + try PBXNativeTarget( + name: "App", + buildPhases: [resourcesPhase], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapper = PBXResourcesBuildPhaseMapper() + let resources = try mapper.map(resourcesPhase, projectProvider: mockProvider) + + #expect(resources.count == 1) + let resource = try #require(resources.first) + switch resource { + case let .file(path, _, _): + #expect(path.basename == "Assets.xcassets") + default: + Issue.record("Expected a file resource.") + } + } + + @Test("Maps localized variant groups from resources") + func testMapVariantGroup() throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj + + let fileRef1 = PBXFileReference.test( + name: "Localizable.strings", + path: "en.lproj/Localizable.strings" + ).add(to: pbxProj) + let fileRef2 = PBXFileReference.test( + name: "Localizable.strings", + path: "fr.lproj/Localizable.strings" + ).add(to: pbxProj) + + let variantGroup = try PBXVariantGroup.mockVariant( + children: [fileRef1, fileRef2] + ).add(to: pbxProj) + .addToMainGroup(in: pbxProj) + + let buildFile = PBXBuildFile(file: variantGroup).add(to: pbxProj) + let resourcesPhase = PBXResourcesBuildPhase(files: [buildFile]).add(to: pbxProj) + + try PBXNativeTarget.test(buildPhases: [resourcesPhase]) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapper = PBXResourcesBuildPhaseMapper() + let resources = try mapper.map(resourcesPhase, projectProvider: provider) + + #expect(resources.count == 2) + #expect(resources.first?.path.basename == "Localizable.strings") + } +} diff --git a/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXScriptsBuildPhaseMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXScriptsBuildPhaseMapperTests.swift new file mode 100644 index 00000000..caea6dc7 --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXScriptsBuildPhaseMapperTests.swift @@ -0,0 +1,64 @@ +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +@Suite +struct PBXScriptsBuildPhaseMapperTests { + @Test("Maps embedded run scripts with specified input/output paths") + func testMapScripts() throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj + + let scriptPhase = PBXShellScriptBuildPhase.test( + name: "Run Script", + shellScript: "echo Hello", + inputPaths: ["$(SRCROOT)/input.txt"], + outputPaths: ["$(DERIVED_FILE_DIR)/output.txt"] + ).add(to: pbxProj) + + try PBXNativeTarget.test( + name: "App", + buildPhases: [scriptPhase], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapper = PBXScriptsBuildPhaseMapper() + let scripts = try mapper.map([scriptPhase], buildPhases: [scriptPhase], projectProvider: provider) + + #expect(scripts.count == 1) + let script = try #require(scripts.first) + #expect(script.name == "Run Script") + #expect(script.script == .embedded("echo Hello")) + #expect(script.inputPaths == ["$(SRCROOT)/input.txt"]) + #expect(script.outputPaths == ["$(DERIVED_FILE_DIR)/output.txt"]) + } + + @Test("Maps raw script build phases not covered by other categories") + func testMapRawScriptBuildPhases() throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj + + let scriptPhase = PBXShellScriptBuildPhase.test( + name: "Test Script" + ) + .add(to: pbxProj) + + try PBXNativeTarget.test( + name: "App", + buildPhases: [scriptPhase], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapper = PBXScriptsBuildPhaseMapper() + let rawPhases = try mapper.map([scriptPhase], buildPhases: [scriptPhase], projectProvider: provider) + + #expect(rawPhases.count == 1) + let rawPhase = try #require(rawPhases.first) + #expect(rawPhase.name == "Test Script") + } +} diff --git a/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXSourcesBuildPhaseMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXSourcesBuildPhaseMapperTests.swift new file mode 100644 index 00000000..ce3379a0 --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Phases/PBXSourcesBuildPhaseMapperTests.swift @@ -0,0 +1,120 @@ +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +@Suite +struct PBXSourcesBuildPhaseMapperTests { + @Test("Maps Swift source files with compiler flags from sources phase") + func testMapSources() throws { + let mockProvider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = mockProvider.xcodeProj.pbxproj + + // Create a file reference for a Swift source and add it to the main group. + let fileRef = try PBXFileReference( + sourceTree: .group, + name: "main.swift", + path: "main.swift" + ) + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + + // Add a build file with compiler flags. + let buildFile = PBXBuildFile( + file: fileRef, + settings: ["COMPILER_FLAGS": "-DDEBUG"] + ) + .add(to: pbxProj) + + // Create a sources build phase with the file. + let sourcesPhase = PBXSourcesBuildPhase(files: [buildFile]) + .add(to: pbxProj) + + // Add a native target that includes the sources phase. + try PBXNativeTarget( + name: "App", + buildPhases: [sourcesPhase], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapper = PBXSourcesBuildPhaseMapper() + let sources = try mapper.map(sourcesPhase, projectProvider: mockProvider) + + #expect(sources.count == 1) + let sourceFile = try #require(sources.first) + #expect(sourceFile.path.basename == "main.swift") + #expect(sourceFile.compilerFlags == "-DDEBUG") + } + + @Test("Handles source files without file references gracefully") + func testMapSourceFile_missingFileRef() throws { + let mockProvider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = mockProvider.xcodeProj.pbxproj + + // A build file with no file reference. + let buildFile = PBXBuildFile() + let sourcesPhase = PBXSourcesBuildPhase(files: [buildFile]).add(to: pbxProj) + let target = try PBXNativeTarget.test(buildPhases: [sourcesPhase]) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + try mockProvider.addTargets([target]) + + let mapper = PBXSourcesBuildPhaseMapper() + let sources = try mapper.map(sourcesPhase, projectProvider: mockProvider) + #expect(sources.isEmpty == true) // Gracefully handled empty result. + } + + @Test("Gracefully handles non-existent file paths for source files") + func testMapSourceFile_unresolvableFullPath() throws { + // Use a provider with an invalid source directory to simulate missing files. + let mockProvider = MockProjectProvider( + sourceDirectory: "/invalid/Path", + projectName: "TestProject" + ) + let pbxProj = mockProvider.xcodeProj.pbxproj + + let fileRef = PBXFileReference( + name: "NonExistent.swift", + path: "NonExistent.swift" + ) + let buildFile = PBXBuildFile(file: fileRef).add(to: pbxProj) + let sourcesPhase = PBXSourcesBuildPhase(files: [buildFile]).add(to: pbxProj) + try PBXNativeTarget.test(buildPhases: [sourcesPhase]) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapper = PBXSourcesBuildPhaseMapper() + let sources = try mapper.map(sourcesPhase, projectProvider: mockProvider) + #expect(sources.isEmpty == true) + } + + @Test( + "Correctly identifies code generation attributes for source files", + arguments: [FileCodeGen.public, .private, .project, .disabled] + ) + func testCodeGenAttributes(_ fileCodeGen: FileCodeGen) throws { + let provider: MockProjectProvider = .makeBasicProjectProvider() + let pbxProj = provider.xcodeProj.pbxproj + + let fileRef = try PBXFileReference.test(name: "File.swift", path: "File.swift") + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + + let buildFile = PBXBuildFile( + file: fileRef, + settings: ["ATTRIBUTES": [fileCodeGen.rawValue]] + ).add(to: pbxProj) + + let sourcesPhase = PBXSourcesBuildPhase(files: [buildFile]).add(to: pbxProj) + try PBXNativeTarget.test(buildPhases: [sourcesPhase]).add(to: pbxProj).add(to: pbxProj.rootObject) + + let mapper = PBXSourcesBuildPhaseMapper() + let sources = try mapper.map(sourcesPhase, projectProvider: provider) + + #expect(sources.count == 1) + let sourceFile = try #require(sources.first) + #expect(sourceFile.codeGen == fileCodeGen) + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Project/PBXProjectMapperTests.swift similarity index 60% rename from Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift rename to Tests/XcodeProjMapperTests/MapperTests/Project/PBXProjectMapperTests.swift index c07ccaa6..f8df7f9c 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Project/ProjectMapperTests.swift +++ b/Tests/XcodeProjMapperTests/MapperTests/Project/PBXProjectMapperTests.swift @@ -2,18 +2,16 @@ import Path import Testing import XcodeGraph import XcodeProj - -@testable import TestSupport -@testable import XcodeProjToGraph +@testable import XcodeProjMapper @Suite -struct ProjectMapperTests { +struct PBXProjectMapperTests { @Test("Maps a basic project with default attributes") - func testMapBasicProject() async throws { + func testMapBasicProject() throws { let mockProvider = MockProjectProvider() - let mapper = ProjectMapper(projectProvider: mockProvider) + let mapper = PBXProjectMapper() - let project = try await mapper.mapProject() + let project = try mapper.map(projectProvider: mockProvider) #expect(project.name == "TestProject") #expect(project.path == mockProvider.sourceDirectory) @@ -23,24 +21,22 @@ struct ProjectMapperTests { } @Test("Maps a project with custom attributes (org name, class prefix, upgrade check)") - func testMapProjectWithCustomAttributes() async throws { + func testMapProjectWithCustomAttributes() throws { let pbxProj = PBXProj() - let provider = MockProjectProvider( + let mockProvider = MockProjectProvider( projectName: "CustomProject", pbxProj: pbxProj ) - - let mapper = ProjectMapper(projectProvider: provider) + let mapper = PBXProjectMapper() let customAttributes: [String: Any] = [ "ORGANIZATIONNAME": "Example Org", "CLASSPREFIX": "EX", "LastUpgradeCheck": "1500", ] + mockProvider.pbxProj.projects.first?.attributes = customAttributes - provider.pbxProj.projects.first?.attributes = customAttributes - - let project = try await mapper.mapProject() + let project = try mapper.map(projectProvider: mockProvider) #expect(project.name == "CustomProject") #expect(project.organizationName == "Example Org") @@ -48,33 +44,8 @@ struct ProjectMapperTests { #expect(project.lastUpgradeCheck == "1500") } - @Test("Maps a project that contains targets") - func testMapProjectWithTargets() async throws { - let mockProvider = MockProjectProvider() - let configList = XCConfigurationList.mock( - configs: [("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"])], - proj: mockProvider.pbxProj - ) - - let mapper = ProjectMapper(projectProvider: mockProvider) - - let target = PBXNativeTarget.mock( - name: "ExampleApp", - buildConfigurationList: configList, - productType: .application, - pbxProj: mockProvider.pbxProj - ) - try mockProvider.pbxProject().targets.append(target) - - let project = try await mapper.mapProject() - - #expect(project.targets.count == 1) - #expect(project.targets.first?.value.name == "ExampleApp") - #expect(project.targets.first?.value.product == .app) - } - @Test("Maps a project with remote package dependencies") - func testMapProjectWithRemotePackages() async throws { + func testMapProjectWithRemotePackages() throws { let mockProvider = MockProjectProvider() let package = XCRemoteSwiftPackageReference( repositoryURL: "https://github.com/example/package.git", @@ -82,9 +53,9 @@ struct ProjectMapperTests { ) mockProvider.pbxProj.add(object: package) try mockProvider.pbxProject().remotePackages.append(package) - let mapper = ProjectMapper(projectProvider: mockProvider) + let mapper = PBXProjectMapper() - let project = try await mapper.mapProject() + let project = try mapper.map(projectProvider: mockProvider) #expect(project.packages.count == 1) guard case let .remote(url, requirement) = project.packages[0] else { @@ -96,12 +67,12 @@ struct ProjectMapperTests { } @Test("Maps a project with known regions") - func testMapProjectWithKnownRegions() async throws { + func testMapProjectWithKnownRegions() throws { let mockProvider = MockProjectProvider() try mockProvider.pbxProject().knownRegions = ["en", "es", "fr"] - let mapper = ProjectMapper(projectProvider: mockProvider) + let mapper = PBXProjectMapper() - let project = try await mapper.mapProject() + let project = try mapper.map(projectProvider: mockProvider) #expect(project.defaultKnownRegions?.count == 3) #expect(project.defaultKnownRegions?.contains("en") == true) @@ -110,24 +81,21 @@ struct ProjectMapperTests { } @Test("Maps a project with a custom development region") - func testMapProjectWithDevelopmentRegion() async throws { + func testMapProjectWithDevelopmentRegion() throws { let mockProvider = MockProjectProvider() try mockProvider.pbxProject().developmentRegion = "fr" - let mapper = ProjectMapper(projectProvider: mockProvider) - - let project = try await mapper.mapProject() + let mapper = PBXProjectMapper() + let project = try mapper.map(projectProvider: mockProvider) #expect(project.developmentRegion == "fr") } @Test("Maps a project with default resource synthesizers") - func testMapProjectWithResourceSynthesizers() async throws { + func testMapProjectWithResourceSynthesizers() throws { let mockProvider = MockProjectProvider() - let mapper = ProjectMapper(projectProvider: mockProvider) - - let project = try await mapper.mapProject() + let mapper = PBXProjectMapper() - // Test for expected resource synthesizers + let project = try mapper.map(projectProvider: mockProvider) let synthesizers = project.resourceSynthesizers // Check for strings synthesizer @@ -144,20 +112,20 @@ struct ProjectMapperTests { // Verify all expected synthesizer types are present let expectedParsers: Set = [ .strings, .assets, .plists, .fonts, .coreData, - .interfaceBuilder, .json, .yaml, .files, + .interfaceBuilder, .json, .yaml, .files, .stringsCatalog, ] let actualParsers = Set(synthesizers.map(\.parser)) #expect(actualParsers == expectedParsers) } @Test("Maps a project with associated schemes") - func testMapProjectWithSchemes() async throws { + func testMapProjectWithSchemes() throws { let mockProvider = MockProjectProvider() - let scheme = XCScheme.mock(name: "TestScheme") + let scheme = XCScheme.test(name: "TestScheme") mockProvider.xcodeProj.sharedData = XCSharedData(schemes: [scheme]) - let mapper = ProjectMapper(projectProvider: mockProvider) + let mapper = PBXProjectMapper() - let project = try await mapper.mapProject() + let project = try mapper.map(projectProvider: mockProvider) #expect(project.schemes.count == 1) #expect(project.schemes[0].name == "TestScheme") diff --git a/Tests/XcodeProjMapperTests/MapperTests/Project/ProjectProviderTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Project/ProjectProviderTests.swift new file mode 100644 index 00000000..176f134c --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Project/ProjectProviderTests.swift @@ -0,0 +1,88 @@ +import Testing +import XcodeGraph +import XcodeProj +import Path +@testable import XcodeProjMapper + +@Suite +struct ProjectProviderTests { + @Test("Returns pbxProject successfully when project exists") + func testPBXProjectSuccess() throws { + // Create a dummy PBXProject + let proj = PBXProj() + let pbxProject = PBXProject.test( + name: "TestProject", + buildConfigurationList: .test(), + mainGroup: .test(), + projects: [] + ) + + proj.add(object: pbxProject) + proj.rootObject = pbxProject + + let xcodeProj = XcodeProj( + workspace: XCWorkspace(data: XCWorkspaceData(children: [])), + pbxproj: proj + ) + + let provider = ProjectProvider( + xcodeProjPath: try AbsolutePath(validating: "/tmp/TestProject.xcodeproj"), + xcodeProj: xcodeProj + ) + + let project = try provider.pbxProject() + #expect(project.name == "TestProject") + } + + @Test("Throws noProjectsFound error when no projects are present") + func testNoProjectsFoundError() throws { + let proj = PBXProj() + // No PBXProject added to 'proj', so this should trigger the error + let xcodeProj = XcodeProj( + workspace: XCWorkspace(data: XCWorkspaceData(children: [])), + pbxproj: proj + ) + + let provider = ProjectProvider( + xcodeProjPath: try AbsolutePath(validating: "/tmp/EmptyProject.xcodeproj"), + xcodeProj: xcodeProj + ) + + #expect(throws: ProjectProvidingError.noProjectsFound(path: "/tmp/EmptyProject.xcodeproj")) { + _ = try provider.pbxProject() + } + + #expect { + _ = try provider.pbxProject() + } throws: { error in + return error.localizedDescription == "No `PBXProject` was found in the `.xcodeproj` at: /tmp/EmptyProject.xcodeproj." + } + + } + + @Test("Verifies sourceDirectory is parent of xcodeProjPath") + func testSourceDirectoryComputation() throws { + let proj = PBXProj() + let pbxProject = PBXProject.test( + name: "TestProject", + buildConfigurationList: .test(), + mainGroup: .test(), + projects: [] + ) + + proj.add(object: pbxProject) + proj.rootObject = pbxProject + + let xcodeProj = XcodeProj( + workspace: XCWorkspace(data: XCWorkspaceData(children: [])), + pbxproj: proj + ) + + let provider = ProjectProvider( + xcodeProjPath: try AbsolutePath(validating: "/tmp/Projects/TestProject.xcodeproj"), + xcodeProj: xcodeProj + ) + + #expect(provider.sourceDirectory.pathString == "/tmp/Projects") + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Schemes/XCSchemeMapperTests.swift similarity index 76% rename from Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift rename to Tests/XcodeProjMapperTests/MapperTests/Schemes/XCSchemeMapperTests.swift index a3a0dcf6..85f2fb58 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Target/SchemeMapperTests.swift +++ b/Tests/XcodeProjMapperTests/MapperTests/Schemes/XCSchemeMapperTests.swift @@ -1,44 +1,40 @@ import Path import Testing -@testable import TestSupport +import XcodeGraph @testable import XcodeProj -@testable import XcodeProjToGraph +@testable import XcodeProjMapper @Suite -struct SchemeMapperTests { +struct XCSchemeMapperTests { let mockProvider: MockProjectProvider - let mapper: SchemeMapper + let mapper: XCSchemeMapper + let graphType: GraphType - init() async throws { + init() throws { let mockProvider = MockProjectProvider() self.mockProvider = mockProvider - mapper = try SchemeMapper(graphType: .project(mockProvider.sourceDirectory)) + mapper = XCSchemeMapper() + graphType = .project(mockProvider.sourceDirectory) } @Test("Maps shared project schemes correctly") - func testMapSharedProjectSchemes() async throws { - // Setup a shared scheme - let xcscheme = XCScheme.mock(name: "SharedScheme") - - let schemes = try await mapper.mapSchemes(xcschemes: [xcscheme], shared: true) - #expect(schemes.count == 1) - #expect(schemes[0].name == "SharedScheme") - #expect(schemes[0].shared == true) + func testMapSharedProjectSchemes() throws { + let xcscheme = XCScheme.test(name: "SharedScheme") + let scheme = try mapper.map(xcscheme, shared: true, graphType: graphType) + #expect(scheme.name == "SharedScheme") + #expect(scheme.shared == true) } @Test("Maps user (non-shared) project schemes correctly") - func testMapUserSchemes() async throws { - // Setup a user scheme - let xcscheme = XCScheme.mock(name: "UserScheme") - let schemes = try await mapper.mapSchemes(xcschemes: [xcscheme], shared: false) - - #expect(schemes.count == 1) - #expect(schemes[0].name == "UserScheme") - #expect(schemes[0].shared == false) + func testMapUserSchemes() throws { + let xcscheme = XCScheme.test(name: "UserScheme") + let scheme = try mapper.map(xcscheme, shared: false, graphType: graphType) + #expect(scheme.name == "UserScheme") + #expect(scheme.shared == false) } @Test("Maps a build action within a scheme") - func testMapBuildAction() async throws { + func testMapBuildAction() throws { let targetRef = XCScheme.BuildableReference( referencedContainer: "container:App.xcodeproj", blueprintIdentifier: "123", @@ -58,7 +54,7 @@ struct SchemeMapperTests { runPostActionsOnFailure: true ) - let mappedAction = try await mapper.mapBuildAction(action: buildAction) + let mappedAction = try mapper.mapBuildAction(action: buildAction, graphType: graphType) #expect(mappedAction != nil) #expect(mappedAction?.targets.count == 1) #expect(mappedAction?.targets[0].name == "App") @@ -67,7 +63,7 @@ struct SchemeMapperTests { } @Test("Maps a test action with testable references, coverage, and environment") - func testMapTestAction() async throws { + func testMapTestAction() throws { let targetRef = XCScheme.BuildableReference( referencedContainer: "container:App.xcodeproj", blueprintIdentifier: "123", @@ -75,7 +71,7 @@ struct SchemeMapperTests { blueprintName: "AppTests" ) - let testableEntry = XCScheme.TestableReference.mock( + let testableEntry = XCScheme.TestableReference.test( skipped: false, buildableReference: targetRef ) @@ -94,7 +90,7 @@ struct SchemeMapperTests { region: "US" ) - let mappedAction = try await mapper.mapTestAction(action: testAction) + let mappedAction = try mapper.mapTestAction(action: testAction, graphType: graphType) #expect(mappedAction != nil) #expect(mappedAction?.targets.count == 1) #expect(mappedAction?.targets[0].target.name == "AppTests") @@ -107,7 +103,7 @@ struct SchemeMapperTests { } @Test("Maps a run action with environment variables and launch arguments") - func testMapRunAction() async throws { + func testMapRunAction() throws { let targetRef = XCScheme.BuildableReference( referencedContainer: "container:App.xcodeproj", blueprintIdentifier: "123", @@ -116,7 +112,6 @@ struct SchemeMapperTests { ) let runnable = XCScheme.BuildableProductRunnable(buildableReference: targetRef) - let envVar = XCScheme.EnvironmentVariable(variable: "RUN_ENV", value: "run_value", enabled: true) let launchArg = XCScheme.CommandLineArguments.CommandLineArgument(name: "run_arg", enabled: true) @@ -128,7 +123,7 @@ struct SchemeMapperTests { environmentVariables: [envVar] ) - let mappedAction = try await mapper.mapRunAction(action: launchAction) + let mappedAction = try mapper.mapRunAction(action: launchAction, graphType: graphType) #expect(mappedAction != nil) #expect(mappedAction?.executable?.name == "App") #expect(mappedAction?.configurationName == "Debug") @@ -138,27 +133,26 @@ struct SchemeMapperTests { } @Test("Maps an archive action with organizer reveal enabled") - func testMapArchiveAction() async throws { + func testMapArchiveAction() throws { let archiveAction = XCScheme.ArchiveAction( buildConfiguration: "Release", revealArchiveInOrganizer: true ) - let mappedAction = try await mapper.mapArchiveAction(action: archiveAction) + let mappedAction = try mapper.mapArchiveAction(action: archiveAction) #expect(mappedAction != nil) #expect(mappedAction?.configurationName == "Release") #expect(mappedAction?.revealArchiveInOrganizer == true) } @Test("Maps a profile action to a runnable and configuration") - func testMapProfileAction() async throws { + func testMapProfileAction() throws { let targetRef = XCScheme.BuildableReference( referencedContainer: "container:App.xcodeproj", blueprintIdentifier: "123", buildableName: "App.app", blueprintName: "App" ) - let runnable = XCScheme.BuildableProductRunnable(buildableReference: targetRef) let profileAction = XCScheme.ProfileAction( @@ -166,23 +160,22 @@ struct SchemeMapperTests { buildConfiguration: "Release" ) - let mappedAction = try await mapper.mapProfileAction(action: profileAction) + let mappedAction = try mapper.mapProfileAction(action: profileAction, graphType: graphType) #expect(mappedAction != nil) #expect(mappedAction?.executable?.name == "App") #expect(mappedAction?.configurationName == "Release") } @Test("Maps an analyze action to the appropriate configuration") - func testMapAnalyzeAction() async throws { + func testMapAnalyzeAction() throws { let analyzeAction = XCScheme.AnalyzeAction(buildConfiguration: "Debug") - - let mappedAction = try await mapper.mapAnalyzeAction(action: analyzeAction) + let mappedAction = try mapper.mapAnalyzeAction(action: analyzeAction) #expect(mappedAction != nil) #expect(mappedAction?.configurationName == "Debug") } @Test("Maps target references in a scheme's build action") - func testMapTargetReference() async throws { + func testMapTargetReference() throws { let targetRef = XCScheme.BuildableReference( referencedContainer: "container:App.xcodeproj", blueprintIdentifier: "123", @@ -201,19 +194,18 @@ struct SchemeMapperTests { buildImplicitDependencies: true ) - let scheme = XCScheme.mock(buildAction: buildAction) - - let mapped = try await mapper.mapScheme(xcscheme: scheme, shared: true) - + let scheme = XCScheme.test(buildAction: buildAction) + let mapped = try mapper.map(scheme, shared: true, graphType: graphType) let mappedBuildAction = try #require(mapped.buildAction) + #expect(mappedBuildAction.targets.count == 1) #expect(mappedBuildAction.targets[0].name == "App") #expect(mappedBuildAction.targets[0].projectPath == mockProvider.sourceDirectory) } @Test("Handles schemes without any actions gracefully") - func testNilActions() async throws { - let scheme = XCScheme.mock( + func testNilActions() throws { + let scheme = XCScheme.test( buildAction: nil, testAction: nil, launchAction: nil, @@ -222,7 +214,7 @@ struct SchemeMapperTests { analyzeAction: nil ) - let mapped = try await mapper.mapScheme(xcscheme: scheme, shared: true) + let mapped = try mapper.map(scheme, shared: true, graphType: graphType) #expect(mapped.buildAction == nil) #expect(mapped.testAction == nil) #expect(mapped.runAction == nil) diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Settings/BuildSettingsTests.swift similarity index 78% rename from Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift rename to Tests/XcodeProjMapperTests/MapperTests/Settings/BuildSettingsTests.swift index bf8f7724..9bdc2292 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/BuildSettingsTests.swift +++ b/Tests/XcodeProjMapperTests/MapperTests/Settings/BuildSettingsTests.swift @@ -2,14 +2,12 @@ import Path import Testing import XcodeGraph import XcodeProj - -@testable import TestSupport -@testable import XcodeProjToGraph +@testable import XcodeProjMapper @Suite struct BuildSettingsTests { @Test("Extracts a string value from build settings") - func testStringExtraction() async throws { + func testStringExtraction() throws { let settings: [String: Any] = ["COMPILER_FLAGS": "-ObjC"] let value = settings.string(for: .compilerFlags) try #require(value != nil) @@ -29,7 +27,7 @@ struct BuildSettingsTests { } @Test("Extracts a string array from build settings") - func testStringArrayExtraction() async throws { + func testStringArrayExtraction() throws { let settings: [String: Any] = ["LAUNCH_ARGUMENTS": ["-enableFeature", "-verbose"]] let args = settings.stringArray(for: .launchArguments) try #require(args != nil) @@ -38,7 +36,7 @@ struct BuildSettingsTests { } @Test("Extracts a dictionary of strings (e.g., environment variables) from build settings") - func testStringDictExtraction() async throws { + func testStringDictExtraction() throws { let settings: [String: Any] = ["ENVIRONMENT_VARIABLES": ["KEY": "VALUE"]] let envVars = settings.stringDict(for: .environmentVariables) try #require(envVars != nil) @@ -53,11 +51,23 @@ struct BuildSettingsTests { } @Test("Coerces any array elements to strings, discarding non-string values") - func testCoerceAnyArrayToStringArray() async throws { + func testCoerceAnyArrayToStringArray() throws { let settings: [String: Any] = ["LAUNCH_ARGUMENTS": ["-flag", 42, true]] let args = settings.stringArray(for: .launchArguments) try #require(args != nil) // Non-string elements are discarded, leaving only ["-flag"] #expect(args == ["-flag"]) } + + @Test( + "Extracts the SDKROOT build setting as a string", + arguments: Platform.allCases + ) + func testExtractSDKROOT(platform: Platform) throws { + let settings: [String: Any] = ["SDKROOT": platform.xcodeSdkRoot] + + let sdkroot = settings.string(for: .sdkroot) + try #require(sdkroot != nil) + #expect(sdkroot == platform.xcodeSdkRoot) + } } diff --git a/Tests/XcodeProjMapperTests/MapperTests/Settings/ConfigurationMatcherTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Settings/ConfigurationMatcherTests.swift new file mode 100644 index 00000000..f51beaae --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Settings/ConfigurationMatcherTests.swift @@ -0,0 +1,43 @@ +import Testing +import XcodeGraph +@testable import XcodeProjMapper + +@Suite +struct ConfigurationMatcherTests { + let configurationMatcher: ConfigurationMatching + + init(configurationMatcher: ConfigurationMatching = ConfigurationMatcher()) { + self.configurationMatcher = configurationMatcher + } + + @Test("Detects 'Debug' variants from configuration names") + func testVariantDetectionForDebug() throws { + #expect(configurationMatcher.variant(for: "Debug") == .debug) + #expect(configurationMatcher.variant(for: "development") == .debug) + #expect(configurationMatcher.variant(for: "dev") == .debug) + } + + @Test("Detects 'Release' variants from configuration names") + func testVariantDetectionForRelease() throws { + #expect(configurationMatcher.variant(for: "Release") == .release) + #expect(configurationMatcher.variant(for: "prod") == .release) + #expect(configurationMatcher.variant(for: "production") == .release) + } + + @Test("Falls back to 'Debug' variant for unrecognized configuration names") + func testVariantFallbackToDebug() throws { + #expect(configurationMatcher.variant(for: "Staging") == .debug) + #expect(configurationMatcher.variant(for: "CustomConfig") == .debug) + } + + @Test("Validates configuration names based on allowed patterns") + func testValidateConfigurationName() throws { + #expect(configurationMatcher.validateConfigurationName("Debug") == true) + #expect(configurationMatcher.validateConfigurationName("Release") == true) + + // Invalid names: empty, whitespace, or containing spaces + #expect(configurationMatcher.validateConfigurationName("") == false) + #expect(configurationMatcher.validateConfigurationName("Debug Config") == false) + #expect(configurationMatcher.validateConfigurationName(" ") == false) + } +} diff --git a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Settings/XCConfigurationMapperTests.swift similarity index 58% rename from Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift rename to Tests/XcodeProjMapperTests/MapperTests/Settings/XCConfigurationMapperTests.swift index b9d20622..2cddc90c 100644 --- a/Tests/XcodeProjToGraphTests/MapperTests/Xcode/Settings/SettingsMapperTests.swift +++ b/Tests/XcodeProjMapperTests/MapperTests/Settings/XCConfigurationMapperTests.swift @@ -2,31 +2,30 @@ import Path import Testing import XcodeGraph import XcodeProj - -@testable import TestSupport -@testable import XcodeProjToGraph +@testable import XcodeProjMapper @Suite -struct SettingsMapperTests { - let mapper = SettingsMapper() +struct XCConfigurationMapperTests { + let mapper = XCConfigurationMapper() @Test("Returns default settings when configuration list is nil") - func testNilConfigurationListReturnsDefault() async throws { + func testNilConfigurationListReturnsDefault() throws { let mockProvider = MockProjectProvider() - let settings = try await mapper.map(projectProvider: mockProvider, configurationList: nil) + let settings = try mapper.map(projectProvider: mockProvider, configurationList: nil) #expect(settings == Settings.default) } @Test("Maps a single build configuration correctly") - func testSingleConfigurationMapping() async throws { + func testSingleConfigurationMapping() throws { let pbxProj = PBXProj() - let configList = XCConfigurationList.mock( - configs: [("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.debug"])], - proj: pbxProj - ) + let config: XCBuildConfiguration = .testDebug().add(to: pbxProj) + let configList = XCConfigurationList.test( + buildConfigurations: [config], + defaultConfigurationName: "Debug" + ).add(to: pbxProj) let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) - let settings = try await mapper.map(projectProvider: mockProvider, configurationList: configList) + let settings = try mapper.map(projectProvider: mockProvider, configurationList: configList) #expect(settings.configurations.count == 1) let configKey = settings.configurations.keys.first @@ -39,16 +38,16 @@ struct SettingsMapperTests { } @Test("Maps multiple build configurations correctly") - func testMultipleConfigurations() async throws { + func testMultipleConfigurations() throws { let pbxProj = PBXProj() - let configs: [(String, [String: Sendable])] = [ - ("Debug", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.debug"]), - ("Release", ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.release"]), - ] - let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) + + let debugConfiguration: XCBuildConfiguration = .testDebug().add(to: pbxProj) + let releaseConfiguration: XCBuildConfiguration = .testRelease().add(to: pbxProj) + let configs = [debugConfiguration, releaseConfiguration] + let configList = XCConfigurationList.test(buildConfigurations: configs).add(to: pbxProj) let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) - let settings = try await mapper.map(projectProvider: mockProvider, configurationList: configList) + let settings = try mapper.map(projectProvider: mockProvider, configurationList: configList) #expect(settings.configurations.count == 2) let debugKey = try #require(settings.configurations.keys.first { $0.name == "Debug" }) @@ -65,15 +64,15 @@ struct SettingsMapperTests { } @Test("Coerces non-string values to strings in build settings") - func testCoercionOfNonStringValues() async throws { + func testCoercionOfNonStringValues() throws { let pbxProj = PBXProj() - let configs: [(String, [String: Sendable])] = [ - ("Debug", ["SOME_NUMBER": 42]), - ] - let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) + + let config: XCBuildConfiguration = .testDebug(buildSettings: ["SOME_NUMBER": 42, "A_BOOL": true]).add(to: pbxProj) + + let configList = XCConfigurationList.test(buildConfigurations: [config]).add(to: pbxProj) let mockProvider = MockProjectProvider(configurationList: configList) - let settings = try await mapper.map(projectProvider: mockProvider, configurationList: configList) + let settings = try mapper.map(projectProvider: mockProvider, configurationList: configList) let debugKey = try #require(settings.configurations.keys.first { $0.name == "Debug" }) let debugConfig = try #require(settings.configurations[debugKey]) @@ -81,16 +80,15 @@ struct SettingsMapperTests { } @Test("Resolves XCConfig file paths correctly") - func testXCConfigPathResolution() async throws { - let pbxProj = PBXProj() - let baseConfigRef = PBXFileReference.mock( - sourceTree: .sourceRoot, path: "Config.xcconfig", pbxProj: pbxProj - ) - let buildConfig = XCBuildConfiguration.mock( - name: "Debug", - buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example"], - pbxProj: pbxProj - ) + func testXCConfigPathResolution() throws { + let pbxProj = MockProjectProvider().pbxProj + let baseConfigRef = try PBXFileReference.test( + sourceTree: .sourceRoot, path: "Config.xcconfig" + ).add(to: pbxProj).addToMainGroup(in: pbxProj) + + let buildConfig = XCBuildConfiguration.testDebug( + buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example"] + ).add(to: pbxProj) buildConfig.baseConfiguration = baseConfigRef let configList = XCConfigurationList( @@ -100,9 +98,10 @@ struct SettingsMapperTests { ) let mockProvider = MockProjectProvider( - sourceDirectory: "/Users/test/project", configurationList: configList + sourceDirectory: "/Users/test/project", + configurationList: configList ) - let settings = try await mapper.map(projectProvider: mockProvider, configurationList: configList) + let settings = try mapper.map(projectProvider: mockProvider, configurationList: configList) let debugKey = try #require(settings.configurations.keys.first { $0.name == "Debug" }) let debugConfig = try #require(settings.configurations[debugKey]) @@ -112,15 +111,15 @@ struct SettingsMapperTests { } @Test("Maps array values correctly in build settings") - func testArrayValueMapping() async throws { + func testArrayValueMapping() throws { let pbxProj = PBXProj() - let configs: [(String, [String: Sendable])] = [ - ("Debug", ["SOME_ARRAY": ["val1", "val2"]]), - ] - let configList = XCConfigurationList.mock(configs: configs, proj: pbxProj) + + let config: XCBuildConfiguration = .testDebug(buildSettings: ["SOME_ARRAY": ["val1", "val2"]]).add(to: pbxProj) + + let configList = XCConfigurationList.test(buildConfigurations: [config]).add(to: pbxProj) let mockProvider = MockProjectProvider(configurationList: configList, pbxProj: pbxProj) - let settings = try await mapper.map(projectProvider: mockProvider, configurationList: configList) + let settings = try mapper.map(projectProvider: mockProvider, configurationList: configList) #expect(settings.configurations.count == 1) let debugKey = try #require(settings.configurations.keys.first { $0.name == "Debug" }) diff --git a/Tests/XcodeProjMapperTests/MapperTests/Target/PBXBuildRuleMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Target/PBXBuildRuleMapperTests.swift new file mode 100644 index 00000000..0290cc68 --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Target/PBXBuildRuleMapperTests.swift @@ -0,0 +1,130 @@ +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +@Suite +struct PBXBuildRuleMapperTests { + let mapper = PBXBuildRuleMapper() + + @Test("Maps build rules with known compiler spec and file type successfully") + func testMapBuildRulesWithKnownCompilerSpecAndFileType() throws { + let projectProvider = MockProjectProvider() + let pbxProj = projectProvider.pbxProj + let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue + let knownFileType = BuildRule.FileType.cSource.rawValue + + let buildRule = PBXBuildRule.test( + compilerSpec: knownCompilerSpec, + fileType: knownFileType, + filePatterns: "*.c", + name: "C Rule", + outputFiles: ["$(DERIVED_FILE_DIR)/output.c.o"], + inputFiles: ["$(SRCROOT)/main.c"], + outputFilesCompilerFlags: ["-O2"], + script: "echo Building C sources", + runOncePerArchitecture: false + ).add(to: pbxProj) + + try PBXNativeTarget.test(buildRules: [buildRule]) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let optionalRule = try mapper.map(buildRule) + let rule = try #require(optionalRule) + + #expect(rule.compilerSpec.rawValue == knownCompilerSpec) + #expect(rule.fileType.rawValue == knownFileType) + #expect(rule.filePatterns == "*.c") + #expect(rule.name == "C Rule") + #expect(rule.outputFiles == ["$(DERIVED_FILE_DIR)/output.c.o"]) + #expect(rule.inputFiles == ["$(SRCROOT)/main.c"]) + #expect(rule.outputFilesCompilerFlags == ["-O2"]) + #expect(rule.script == "echo Building C sources") + #expect(rule.runOncePerArchitecture == false) + } + + @Test("Skips build rules when compiler spec is unknown") + func testMapBuildRulesWithUnknownCompilerSpec() throws { + let projectProvider = MockProjectProvider() + let pbxProj = projectProvider.pbxProj + let unknownCompilerSpec = "com.apple.compilers.unknown" + let knownFileType = "sourcecode.c.c" + + let buildRule = PBXBuildRule.test( + compilerSpec: unknownCompilerSpec, + fileType: knownFileType + ).add(to: pbxProj) + + try PBXNativeTarget.test(buildRules: [buildRule]) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let rule = try mapper.map(buildRule) + #expect(rule == nil) // Unknown compiler spec -> rule skipped + } + + @Test("Skips build rules when file type is unknown") + func testMapBuildRulesWithUnknownFileType() throws { + let projectProvider = MockProjectProvider() + let pbxProj = projectProvider.pbxProj + let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue + let unknownFileType = "sourcecode.unknown" + + let buildRule = PBXBuildRule.test( + compilerSpec: knownCompilerSpec, + fileType: unknownFileType + ).add(to: pbxProj) + + try PBXNativeTarget.test(buildRules: [buildRule]) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let rule = try mapper.map(buildRule) + #expect(rule == nil) // Unknown file type -> rule skipped + } + + @Test("Individually handles valid and invalid rules, returning nil for invalid ones") + func testMapIndividualValidAndInvalidRules() throws { + let projectProvider = MockProjectProvider() + let pbxProj = projectProvider.pbxProj + let knownCompilerSpec = BuildRule.CompilerSpec.appleClang.rawValue + let knownFileType = BuildRule.FileType.cSource.rawValue + let unknownCompilerSpec = "com.apple.compilers.unknown" + let unknownFileType = "sourcecode.unknown" + + let validRule = PBXBuildRule.test( + compilerSpec: knownCompilerSpec, + fileType: knownFileType, + name: "Valid Rule" + ).add(to: pbxProj) + + let invalidRuleUnknownCompiler = PBXBuildRule.test( + compilerSpec: unknownCompilerSpec, + fileType: knownFileType, + name: "Invalid Compiler" + ).add(to: pbxProj) + + let invalidRuleUnknownFileType = PBXBuildRule.test( + compilerSpec: knownCompilerSpec, + fileType: unknownFileType, + name: "Invalid FileType" + ).add(to: pbxProj) + + try PBXNativeTarget.test( + buildRules: [validRule, invalidRuleUnknownCompiler, invalidRuleUnknownFileType] + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + // Since the mapper maps one rule at a time now, we test them individually. + let validResult = try mapper.map(validRule) + #expect(validResult?.name == "Valid Rule") + + let invalidCompilerResult = try mapper.map(invalidRuleUnknownCompiler) + #expect(invalidCompilerResult == nil) + + let invalidFileTypeResult = try mapper.map(invalidRuleUnknownFileType) + #expect(invalidFileTypeResult == nil) + } +} diff --git a/Tests/XcodeProjMapperTests/MapperTests/Target/PBXTargetDependencyMapper.swift b/Tests/XcodeProjMapperTests/MapperTests/Target/PBXTargetDependencyMapper.swift new file mode 100644 index 00000000..dca08a11 --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Target/PBXTargetDependencyMapper.swift @@ -0,0 +1,316 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +@Suite +struct DependencyMapperTests { + let mockProvider = MockProjectProvider() + let mapper: DependencyMapping + + init() { + mapper = PBXTargetDependencyMapper() + } + + @Test("Maps direct target dependencies correctly") + func testDirectTargetMapping() throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + + let target = try PBXNativeTarget.test( + name: "DirectTarget", + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let dep = PBXTargetDependency( + name: "DirectTarget", + target: target + ).add(to: pbxProj) + + try PBXNativeTarget.test( + name: "App", + dependencies: [dep], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapped = try mapper.map(dep, projectProvider: mockProvider) + #expect(mapped == .target(name: "DirectTarget", status: .required, condition: nil)) + } + + @Test("Maps package product dependencies to runtime package targets") + func testPackageProductMapping() throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + + let productRef = XCSwiftPackageProductDependency(productName: "MyPackageProduct") + let dep = PBXTargetDependency(name: nil, product: productRef).add(to: pbxProj) + + try PBXNativeTarget.test( + name: "App", + dependencies: [dep], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapped = try mapper.map(dep, projectProvider: mockProvider) + #expect(mapped == .package(product: "MyPackageProduct", type: .runtime, condition: nil)) + } + + @Test("Maps native target proxies referencing targets in the same project") + func testProxyNativeTarget() throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + let project = try #require(pbxProj.rootObject) + + let proxy = PBXContainerItemProxy( + containerPortal: .project(project), + remoteGlobalID: .string("GLOBAL_ID"), + proxyType: .nativeTarget, + remoteInfo: "NativeTarget" + ) + .add(to: pbxProj) + + let dep = PBXTargetDependency(name: nil, target: nil, targetProxy: proxy).add(to: pbxProj) + + try PBXNativeTarget.test( + name: "App", + dependencies: [dep], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapped = try mapper.map(dep, projectProvider: mockProvider) + #expect(mapped == .target(name: "NativeTarget", status: .required, condition: nil)) + } + + @Test("Maps proxy dependencies referencing other projects via file references") + func testProxyProjectReference() throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + + let fileRef = try PBXFileReference.test(path: "OtherProject.xcodeproj") + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + + let proxy = PBXContainerItemProxy( + containerPortal: .fileReference(fileRef), + remoteGlobalID: .string("GLOBAL_ID"), + proxyType: .nativeTarget, + remoteInfo: "OtherTarget" + ).add(to: pbxProj) + + let dep = PBXTargetDependency(name: nil, target: nil, targetProxy: proxy).add(to: pbxProj) + + try PBXNativeTarget.test( + name: "App", + dependencies: [dep], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapped = try mapper.map(dep, projectProvider: mockProvider) + let result = try #require(mapped) + let expectedPath = try AbsolutePath(validating: mockProvider.sourceDirectory.pathString + "OtherProject.xcodeproj") + #expect(result == .project(target: "OtherTarget", path: expectedPath, status: .required, condition: nil)) + } + + @Test("Maps reference proxies to libraries when file type is a dylib") + func testProxyReferenceProxyLibrary() throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + + let referenceProxy = try PBXReferenceProxy( + fileType: "compiled.mach-o.dylib", + path: "libTest.dylib", + remote: nil, + sourceTree: .group + ) + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + let mainGroup = try #require(pbxProj.projects.first?.mainGroup) + let projectRef = PBXProject.test( + name: "RemoteProject", + buildConfigurationList: .test(), + mainGroup: mainGroup + ).add(to: pbxProj) + + let proxy = PBXContainerItemProxy( + containerPortal: .project(projectRef), + remoteGlobalID: .string("GLOBAL_ID"), + proxyType: .reference, + remoteInfo: "SomeRemoteInfo" + ) + proxy.remoteGlobalID = .object(referenceProxy) + + let dep = PBXTargetDependency(name: nil, target: nil, targetProxy: proxy).add(to: pbxProj) + + try PBXNativeTarget.test( + name: "App", + dependencies: [dep], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapped = try mapper.map(dep, projectProvider: mockProvider) + let result = try #require(mapped) + + let expectedPath = mockProvider.sourceDirectory.appending(component: "libTest.dylib") + let publicHeaders = try AbsolutePath(validating: "/tmp") + #expect( + result == .library( + path: expectedPath, + publicHeaders: publicHeaders, + swiftModuleMap: nil, + condition: nil + ) + ) + } + + @Test("Maps frameworks when encountered as proxy references") + func testProxyReferenceFileFramework() throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + + let fileRef = try PBXFileReference.test(path: "MyLib.framework") + .add(to: pbxProj) + .addToMainGroup(in: pbxProj) + let mainGroup = try #require(pbxProj.projects.first?.mainGroup) + + let projectRef = PBXProject.test( + name: "RemoteProject", + buildConfigurationList: .test(), + mainGroup: mainGroup + ) + .add(to: pbxProj) + + let proxy = PBXContainerItemProxy( + containerPortal: .project(projectRef), + remoteGlobalID: .object(fileRef), + proxyType: .reference, + remoteInfo: "SomeFramework" + ) + pbxProj.add(object: proxy) + + let dep = PBXTargetDependency(name: nil, target: nil, targetProxy: proxy).add(to: pbxProj) + + try PBXNativeTarget.test( + name: "App", + dependencies: [dep], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + try PBXNativeTarget.test( + name: "App", + dependencies: [dep], + productType: .application + ).add(to: pbxProj).add(to: pbxProj.rootObject) + + let mapped = try mapper.map(dep, projectProvider: mockProvider) + let result = try #require(mapped) + let expectedPath = mockProvider.sourceDirectory.appending(component: "MyLib.framework") + #expect(result == .framework(path: expectedPath, status: .required, condition: nil)) + } + + @Test("Maps dependencies with platform filters to conditions") + func testPlatformConditions() throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + + let target = try PBXNativeTarget.test( + name: "ConditionalTarget", + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let dep = PBXTargetDependency(name: "ConditionalTarget", target: target).add(to: pbxProj) + dep.platformFilters = ["macos", "ios"] + + try PBXNativeTarget.test( + name: "App", + dependencies: [dep], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapped = try mapper.map(dep, projectProvider: mockProvider) + let result = try #require(mapped) + #expect(result == .target(name: "ConditionalTarget", status: .required, condition: .when([.ios, .macos]))) + } + + @Test("Ignores dependencies that cannot be matched to targets, products, or proxies") + func testNoMatches() throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + + // A dependency with no target, no product, no proxy. + let dep = PBXTargetDependency.test(name: nil).add(to: pbxProj) + + try PBXNativeTarget.test( + name: "App", + dependencies: [dep], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapped = try mapper.map(dep, projectProvider: mockProvider) + #expect(mapped == nil) + } + + @Test("Maps single-platform filter dependencies correctly") + func testSinglePlatformFilter() throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + + let target = try PBXNativeTarget.test( + name: "SinglePlatform", + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let dep = PBXTargetDependency(name: "SinglePlatform", target: target).add(to: pbxProj) + dep.platformFilter = "tvos" + + try PBXNativeTarget.test( + name: "App", + dependencies: [dep], + productType: .application + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapped = try mapper.map(dep, projectProvider: mockProvider) + #expect(mapped == .target(name: "SinglePlatform", status: .required, condition: .when([.tvos]))) + } + + @Test("Ignores invalid platform filters, mapping dependency without conditions") + func testInvalidPlatformFilter() throws { + let pbxProj = mockProvider.xcodeProj.pbxproj + + let target = try PBXNativeTarget.test( + name: "UnknownPlatform", + productType: .framework + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let dep = PBXTargetDependency(name: "UnknownPlatform", target: target).add(to: pbxProj) + dep.platformFilter = "weirdos" + + try PBXNativeTarget.test( + name: "App", + dependencies: [dep], + productType: .commandLineTool + ) + .add(to: pbxProj) + .add(to: pbxProj.rootObject) + + let mapped = try mapper.map(dep, projectProvider: mockProvider) + #expect(mapped == .target(name: "UnknownPlatform", status: .required, condition: nil)) + } +} diff --git a/Tests/XcodeProjMapperTests/MapperTests/Target/PBXTargetMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Target/PBXTargetMapperTests.swift new file mode 100644 index 00000000..de73d646 --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Target/PBXTargetMapperTests.swift @@ -0,0 +1,335 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper +import Foundation + +@Suite +struct PBXTargetMapperTests { + let mockProvider = MockProjectProvider() + let mapper: TargetMapping + + init() { + mapper = PBXTargetMapper() + } + + @Test("Maps a basic target with a product bundle identifier") + func testMapBasicTarget() throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"] + ) + + let mapped = try mapper.map(pbxTarget: target, projectProvider: mockProvider) + #expect(mapped.name == "App") + #expect(mapped.product == .app) + #expect(mapped.productName == "App") + #expect(mapped.bundleId == "com.example.app") + } + + @Test("Throws an error if the target is missing a bundle identifier") + func testMapTargetWithMissingBundleId() throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [:] + ) + + #expect(throws: TargetMappingError.missingBundleIdentifier(targetName: "App")) { + _ = try mapper.map(pbxTarget: target, projectProvider: mockProvider) + } + } + + @Test("Maps a target with environment variables") + func testMapTargetWithEnvironmentVariables() throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "ENVIRONMENT_VARIABLES": ["TEST_VAR": "test_value"], + ] + ) + + let mapped = try mapper.map(pbxTarget: target, projectProvider: mockProvider) + #expect(mapped.environmentVariables["TEST_VAR"]?.value == "test_value") + #expect(mapped.environmentVariables["TEST_VAR"]?.isEnabled == true) + } + + @Test("Maps a target with launch arguments") + func testMapTargetWithLaunchArguments() throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "LAUNCH_ARGUMENTS": ["-debug", "--verbose"], + ] + ) + + let mapped = try mapper.map(pbxTarget: target, projectProvider: mockProvider) + let expected = [ + LaunchArgument(name: "-debug", isEnabled: true), + LaunchArgument(name: "--verbose", isEnabled: true), + ] + #expect(mapped.launchArguments == expected) + } + + @Test("Maps a target with source files") + func testMapTargetWithSourceFiles() throws { + let pbxProj = mockProvider.pbxProj + let sourceFile = try PBXFileReference.test( + path: "ViewController.swift", + lastKnownFileType: "sourcecode.swift" + ).add(to: pbxProj).addToMainGroup(in: pbxProj) + + let buildFile = PBXBuildFile(file: sourceFile).add(to: pbxProj) + let sourcesPhase = PBXSourcesBuildPhase(files: [buildFile]).add(to: pbxProj) + + let target = createTarget( + name: "App", + productType: .application, + buildPhases: [sourcesPhase], + buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"] + ) + + let mapped = try mapper.map(pbxTarget: target, projectProvider: mockProvider) + #expect(mapped.sources.count == 1) + #expect(mapped.sources[0].path.basename == "ViewController.swift") + } + + @Test("Maps a target with metadata tags") + func testMapTargetWithMetadata() throws { + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "TAGS": "tag1, tag2, tag3", + ] + ) + + let mapped = try mapper.map(pbxTarget: target, projectProvider: mockProvider) + #expect(mapped.metadata.tags == Set(["tag1", "tag2", "tag3"])) + } + + @Test("Maps entitlements when CODE_SIGN_ENTITLEMENTS is set") + func testMapEntitlements() async throws { + // Create a temporary directory for the test. + let tempDir = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) + try FileManager.default.createDirectory(at: tempDir, withIntermediateDirectories: true) + + defer { + // Cleanup the temporary directory after the test. + try? FileManager.default.removeItem(at: tempDir) + } + + // Update the mockProvider to reflect the temporary directory as the source directory. + let sourceDirectory = try AbsolutePath(validating: tempDir.path) + let provider = MockProjectProvider( + sourceDirectory: sourceDirectory.pathString, + pbxProj: mockProvider.pbxProj + ) + + // Create a mock entitlements file. + let entitlementsPath = sourceDirectory.appending(component: "App.entitlements") + try "{}".write(toFile: entitlementsPath.pathString, atomically: true, encoding: .utf8) + + // Create build configurations with CODE_SIGN_ENTITLEMENTS set. + let debugConfig = XCBuildConfiguration( + name: "Debug", + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "CODE_SIGN_ENTITLEMENTS": "App.entitlements" + ] + ) + let releaseConfig = XCBuildConfiguration( + name: "Release", + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "CODE_SIGN_ENTITLEMENTS": "App.entitlements" + ] + ) + + let configList = XCConfigurationList( + buildConfigurations: [debugConfig, releaseConfig], + defaultConfigurationName: "Release" + ) + + provider.pbxProj.add(object: debugConfig) + provider.pbxProj.add(object: releaseConfig) + provider.pbxProj.add(object: configList) + + let target = PBXNativeTarget.test( + name: "App", + buildConfigurationList: configList, + buildPhases: [], + productType: .application + ) + + let mapped = try mapper.map(pbxTarget: target, projectProvider: provider) + #expect(mapped.entitlements == .file(path: entitlementsPath)) + } + + + @Test("Throws noProjectsFound when pbxProj has no projects") + func testMapTarget_noProjectsFound() throws { + // Remove all projects from pbxProj + var mockProvider = MockProjectProvider(pbxProj: PBXProj()) + let mapper = PBXTargetMapper() + let target = PBXNativeTarget.test() + mockProvider.xcodeProj = XcodeProj(workspace: XCWorkspace(), pbxproj: PBXProj()) + + #expect(throws: TargetMappingError.noProjectsFound(path: mockProvider.xcodeProjPath.pathString)) { + _ = try mapper.mapAdditionalFiles(from: target, projectProvider: mockProvider) + } + + #expect { + _ = try mapper.mapAdditionalFiles(from: target, projectProvider: mockProvider) + } throws: { error in + return error.localizedDescription == "No project was found at: /tmp/TestProject.xcodproj." + } + } + + @Test("Throws missingFilesGroup when mainGroup is nil") + func testMapTarget_missingFilesGroup() throws { + let mapper = PBXTargetMapper() + + var mockProvider = MockProjectProvider(pbxProj: PBXProj()) + let target = createTarget( + name: "App", + productType: .application, + buildSettings: ["PRODUCT_BUNDLE_IDENTIFIER": "com.example.app"] + ) + mockProvider.xcodeProj = XcodeProj(workspace: XCWorkspace(), pbxproj: PBXProj()) + + #expect(throws: TargetMappingError.missingFilesGroup(targetName: "App")) { + _ = try mapper.extractFilesGroup(from: target, projectProvider: mockProvider) + } + + #expect { + _ = try mapper.extractFilesGroup(from: target, projectProvider: mockProvider) + } throws: { error in + return error.localizedDescription == "The files group is missing for the target 'App'." + } + } + + @Test("Parses a valid Info.plist successfully") + func testMapTarget_validPlist() throws { + let tempDirectory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) + try FileManager.default.createDirectory(at: tempDirectory, withIntermediateDirectories: true) + let srcPath = try AbsolutePath(validating: tempDirectory.path) + + let relativePath = try RelativePath(validating: "Info.plist") + let plistPath = srcPath.appending(relativePath) + + let plistContent: [String: Any] = [ + "CFBundleIdentifier": "com.example.app", + "CFBundleName": "ExampleApp", + "CFVersion": 1.4 + ] + let data = try PropertyListSerialization.data(fromPropertyList: plistContent, format: .xml, options: 0) + try data.write(to: URL(fileURLWithPath: plistPath.pathString)) + + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "INFOPLIST_FILE": relativePath.pathString + ] + ) + var mockProvider = MockProjectProvider(pbxProj: PBXProj()) + mockProvider.sourceDirectory = srcPath + mockProvider.xcodeProj = XcodeProj(workspace: XCWorkspace(), pbxproj: PBXProj()) + + let mapper = PBXTargetMapper() + + let infoPlist = try mapper.extractInfoPlist(from: target, projectProvider: mockProvider) + + #expect({ + switch infoPlist { + case let .dictionary(dict): + return dict["CFBundleIdentifier"] == .string("com.example.app") + && dict["CFBundleName"] == .string("ExampleApp") + default: + return false + } + }() == true) + } + + @Test("Throws invalidPlist when Info.plist cannot be parsed") + func testMapTarget_invalidPlist() throws { + // Create a fake plist that is not actually a plist + let tempDirectory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) + try FileManager.default.createDirectory(at: tempDirectory, withIntermediateDirectories: true) + let srcPath = try AbsolutePath(validating: tempDirectory.path) + + let relativePath = try RelativePath(validating: "Invalid.plist") + let invalidPlistPath = srcPath.appending(relativePath) + + try "Not a plist".write(toFile: invalidPlistPath.pathString, atomically: true, encoding: .utf8) + + let target = createTarget( + name: "App", + productType: .application, + buildSettings: [ + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.app", + "INFOPLIST_FILE": relativePath.pathString + ] + ) + var mockProvider = MockProjectProvider(pbxProj: PBXProj()) + mockProvider.sourceDirectory = srcPath + mockProvider.xcodeProj = XcodeProj(workspace: XCWorkspace(), pbxproj: PBXProj()) + + let mapper = PBXTargetMapper() + + #expect { + _ = try mapper.extractInfoPlist(from: target, projectProvider: mockProvider) + } throws: { error in + return error.localizedDescription == "Failed to read a valid plist dictionary from file at: \(invalidPlistPath.pathString)." + } + } + + // MARK: - Helper Methods + + private func createTarget( + name: String, + productType: PBXProductType, + buildPhases: [PBXBuildPhase] = [], + buildSettings: [String: Any] = [:], + dependencies: [PBXTargetDependency] = [] + ) -> PBXNativeTarget { + let debugConfig = XCBuildConfiguration( + name: "Debug", + buildSettings: buildSettings + ) + + let releaseConfig = XCBuildConfiguration( + name: "Release", + buildSettings: buildSettings + ) + + let configurationList = XCConfigurationList( + buildConfigurations: [debugConfig, releaseConfig], + defaultConfigurationName: "Release" + ) + + mockProvider.pbxProj.add(object: debugConfig) + mockProvider.pbxProj.add(object: releaseConfig) + mockProvider.pbxProj.add(object: configurationList) + + let target = PBXNativeTarget.test( + name: name, + buildConfigurationList: configurationList, + buildRules: [], + buildPhases: buildPhases, + dependencies: dependencies, + productType: productType + ) + + return target + } +} diff --git a/Tests/XcodeProjMapperTests/MapperTests/Target/TargetDependencyExtensionsTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Target/TargetDependencyExtensionsTests.swift new file mode 100644 index 00000000..6d190ea7 --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Target/TargetDependencyExtensionsTests.swift @@ -0,0 +1,190 @@ +import Path +import Testing +import XcodeProj +@testable import XcodeGraph +@testable import XcodeProjMapper + +@Suite +struct TargetDependencyExtensionsTests { + let sourceDirectory = try! AbsolutePath(validating: "/tmp/TestProject") + + // A dummy global target map for .project dependencies + let allTargetsMap: [String: Target] = [ + "MyProjectTarget": Target.test(name: "MyProjectTarget", product: .framework), + "MyProjectDynamicLibrary": Target.test(name: "MyProjectDynamicLibrary", product: .dynamicLibrary), + ] + + @Test("Resolves a target dependency into a target graph dependency") + func testTargetGraphDependency_Target() throws { + let dependency = TargetDependency.target(name: "App", status: .required, condition: nil) + let graphDep = try dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: allTargetsMap + ) + #expect(graphDep == .target(name: "App", path: sourceDirectory, status: .required)) + } + + @Test("Resolves a project-based framework dependency to a dynamic framework in the graph") + func testTargetGraphDependencyFramework_Project() throws { + let dependency = TargetDependency.project( + target: "MyProjectTarget", + path: sourceDirectory, + status: .required, + condition: nil + ) + + let graphDep = try dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: allTargetsMap + ) + + #expect({ + switch graphDep { + case let .framework(path, binaryPath, _, _, linking, archs, status): + return path == sourceDirectory + && binaryPath == sourceDirectory.appending(component: "MyProjectTarget.framework") + && linking == .dynamic && archs.isEmpty && status == .required + default: + return false + } + }() == true) + } + + @Test("Resolves a project-based dynamic library dependency correctly") + func testTargetGraphDependencyLibrary_Project() throws { + let dependency = TargetDependency.project( + target: "MyProjectDynamicLibrary", + path: sourceDirectory, + status: .required, + condition: nil + ) + let graphDep = try dependency.graphDependency( + sourceDirectory: sourceDirectory, + allTargetsMap: allTargetsMap + ) + + switch graphDep { + case let .library(path, _, linking, archs, _): + #expect(path == sourceDirectory.appending(component: "libMyProjectDynamicLibrary.dylib")) + #expect(linking == .dynamic) + #expect(archs.isEmpty == true) + default: + Issue.record("Expected a library graph dependency.") + } + } + + @Test("Resolves a framework file dependency into a dynamic framework graph dependency") + func testTargetGraphDependency_Framework() throws { + let frameworkPath = sourceDirectory.appending(component: "MyFramework.framework") + let dependency = TargetDependency.framework(path: frameworkPath, status: .required, condition: nil) + let graphDep = try dependency.graphDependency(sourceDirectory: sourceDirectory, allTargetsMap: [:]) + + #expect({ + switch graphDep { + case let .framework(path, binaryPath, _, _, linking, archs, status): + return path == frameworkPath + && binaryPath == frameworkPath.appending(component: "MyFramework") + && linking == .dynamic && archs.isEmpty && status == .required + default: + return false + } + }() == true) + } + + @Test("Resolves an XCFramework dependency to the correct .xcframework graph dependency") + func testTargetGraphDependency_XCFramework() throws { + let xcframeworkPath = sourceDirectory.appending(component: "MyXCFramework.xcframework") + let dependency = TargetDependency.xcframework(path: xcframeworkPath, status: .required, condition: nil) + let graphDep = try dependency.graphDependency(sourceDirectory: sourceDirectory, allTargetsMap: [:]) + + #expect({ + switch graphDep { + case let .xcframework(info): + return info.path == xcframeworkPath && info.linking == .dynamic && info.status == .required + default: + return false + } + }() == true) + } + + @Test("Resolves a static library dependency to a static library graph dependency") + func testTargetGraphDependency_Library() throws { + let libPath = sourceDirectory.appending(component: "libMyLib.a") + let headersPath = sourceDirectory.appending(component: "include") + let dependency = TargetDependency.library(path: libPath, publicHeaders: headersPath, swiftModuleMap: nil, condition: nil) + + let graphDep = try dependency.graphDependency(sourceDirectory: sourceDirectory, allTargetsMap: [:]) + + #expect({ + switch graphDep { + case let .library(path, publicHeaders, linking, archs, swiftModuleMap): + return path == libPath && publicHeaders == headersPath && linking == .static + && archs.isEmpty && swiftModuleMap == nil + default: + return false + } + }() == true) + } + + @Test("Resolves a package product dependency to a package product graph dependency") + func testTargetGraphDependency_Package() throws { + let dependency = TargetDependency.package(product: "MyPackageProduct", type: .runtime, condition: nil) + let graphDep = try dependency.graphDependency(sourceDirectory: sourceDirectory, allTargetsMap: [:]) + #expect(graphDep == .packageProduct(path: sourceDirectory, product: "MyPackageProduct", type: .runtime)) + } + + @Test("Resolves an SDK dependency to the correct SDK graph dependency") + func testTargetGraphDependency_SDK() throws { + let dependency = TargetDependency.sdk(name: "MySDK", status: .optional, condition: nil) + let graphDep = try dependency.graphDependency(sourceDirectory: sourceDirectory, allTargetsMap: [:]) + + #expect({ + switch graphDep { + case let .sdk(name, path, status, source): + return name == "MySDK" && path == sourceDirectory && status == .optional && source == .developer + default: + return false + } + }() == true) + } + + @Test("Resolves an XCTest dependency to an XCFramework graph dependency") + func testTargetGraphDependency_XCTest() throws { + let dependency = TargetDependency.xctest + let graphDep = try dependency.graphDependency(sourceDirectory: sourceDirectory, allTargetsMap: [:]) + + #expect({ + switch graphDep { + case let .xcframework(info): + return info.path == sourceDirectory && info.linking == .dynamic && info.status == .required + default: + return false + } + }() == true) + } + + @Test("Throws a MappingError when a project target does not exist in allTargetsMap") + func testMapProjectGraphDependency_TargetNotFound() throws { + let dependency = TargetDependency.project( + target: "NonExistentTarget", + path: sourceDirectory, + status: .required, + condition: nil + ) + + do { + _ = try dependency.graphDependency(sourceDirectory: sourceDirectory, allTargetsMap: [:]) + Issue.record("Expected to throw TargetDependencyMappingError.targetNotFound") + } catch let error as TargetDependencyMappingError { + switch error { + case let .targetNotFound(targetName, path): + #expect(targetName == "NonExistentTarget") + #expect(path == sourceDirectory) + default: + Issue.record("Unexpected TargetDependencyMappingError: \(error)") + } + } catch { + Issue.record("Unexpected error: \(error)") + } + } +} diff --git a/Tests/XcodeProjMapperTests/MapperTests/Workspace/XCWorkspaceMapperTests.swift b/Tests/XcodeProjMapperTests/MapperTests/Workspace/XCWorkspaceMapperTests.swift new file mode 100644 index 00000000..6b3ae738 --- /dev/null +++ b/Tests/XcodeProjMapperTests/MapperTests/Workspace/XCWorkspaceMapperTests.swift @@ -0,0 +1,205 @@ +import Foundation +import Path +import PathKit +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +@Suite +struct XCWorkspaceMapperTests { + @Test("Maps workspace without any projects or schemes") + func testMap_NoProjectsOrSchemes() throws { + let workspacePath = try AbsolutePath(validating: "/tmp/MyWorkspace.xcworkspace") + let xcworkspace: XCWorkspace = .test(files: ["ReadMe.md"]) + + let provider = MockWorkspaceProvider( + xcWorkspacePath: workspacePath, + xcworkspace: xcworkspace + ) + let mapper = XCWorkspaceMapper() + + let workspace = try mapper.map(workspaceProvider: provider) + + #expect(workspace.name == "MyWorkspace") + #expect(workspace.projects.isEmpty == true) + #expect(workspace.schemes.isEmpty == true) + } + + @Test("Maps workspace with multiple projects") + func testMap_MultipleProjects() throws { + let workspacePath = try AbsolutePath(validating: "/tmp/MyWorkspace.xcworkspace") + let workspaceDir = workspacePath.parentDirectory + let xcworkspace: XCWorkspace = .test(withElements: [ + .test(relativePath: "ProjectA.xcodeproj"), + .group(XCWorkspaceDataGroup( + location: .group("NestedGroup"), + name: "NestedGroup", + children: [ + .test(relativePath: "ProjectB.xcodeproj"), + .test(relativePath: "Notes.txt") + ] + )) + ]) + + let provider = MockWorkspaceProvider( + xcWorkspacePath: workspacePath, + xcworkspace: xcworkspace + ) + let mapper = XCWorkspaceMapper() + + let workspace = try mapper.map(workspaceProvider: provider) + + #expect(workspace.name == "MyWorkspace") + #expect(workspace.projects.count == 2) + #expect(workspace.projects.contains(workspaceDir.appending(component: "ProjectA.xcodeproj")) == true) + #expect(workspace.projects.contains(workspaceDir.appending(components: ["NestedGroup", "ProjectB.xcodeproj"])) == true) + #expect(workspace.schemes.isEmpty == true) + } + + @Test("Maps workspace with shared schemes") + func testMap_WithSchemes() throws { + let tempDirectory = FileManager.default.temporaryDirectory + let path = tempDirectory.appendingPathComponent("MyWorkspace.xcworkspace") + let workspacePath = try AbsolutePath(validating: path.path) + + // Create a mock `.xcscheme` file in `xcshareddata/xcschemes` + let sharedDataDir = workspacePath.pathString + "/xcshareddata/xcschemes" + try FileManager.default.createDirectory(atPath: sharedDataDir, withIntermediateDirectories: true) + let schemeFile = sharedDataDir + "/MyScheme.xcscheme" + try "dummy scheme content".write(toFile: schemeFile, atomically: true, encoding: .utf8) + + let xcworkspace: XCWorkspace = .test(withElements: [.test(relativePath: "App.xcodeproj")]) + let provider = MockWorkspaceProvider(xcWorkspacePath: workspacePath, xcworkspace: xcworkspace) + let mapper = XCWorkspaceMapper() + + do { + _ = try mapper.map(workspaceProvider: provider) + } catch { + #expect(error.localizedDescription == "The operation couldn’t be completed. (NSXMLParserErrorDomain error 4.)") + } + } + + @Test("No schemes directory results in no schemes mapped") + func testMap_NoSchemesDirectory() throws { + let workspacePath = try AbsolutePath(validating: "/tmp/MyWorkspace.xcworkspace") + + let xcworkspace = XCWorkspace.test(withElements: [ + .test(relativePath: "App.xcodeproj") + ]) + + let provider = MockWorkspaceProvider( + xcWorkspacePath: workspacePath, + xcworkspace: xcworkspace + ) + let mapper = XCWorkspaceMapper() + + let workspace = try mapper.map(workspaceProvider: provider) + #expect(workspace.schemes.isEmpty == true) + } + + @Test("Workspace name is derived from the .xcworkspace file name") + func testMap_NameDerivation() throws { + let workspacePath = try AbsolutePath(validating: "/tmp/AnotherWorkspace.xcworkspace") + let xcworkspace = XCWorkspace.test(withElements: []) + let provider = MockWorkspaceProvider(xcWorkspacePath: workspacePath, xcworkspace: xcworkspace) + let mapper = XCWorkspaceMapper() + + let workspace = try mapper.map(workspaceProvider: provider) + #expect(workspace.name == "AnotherWorkspace") + } + + + @Test("Resolves absolute path in XCWorkspaceDataFileRef") + func testMap_AbsolutePath() throws { + let workspacePath = try AbsolutePath(validating: "/tmp/AbsWorkspace.xcworkspace") + let elements: [XCWorkspaceDataElement] = [ + .file(XCWorkspaceDataFileRef(location: .absolute("/Users/SomeUser/ProjectC.xcodeproj"))) + ] + + let xcworkspace = XCWorkspace(data: XCWorkspaceData(children: elements)) + let provider = MockWorkspaceProvider(xcWorkspacePath: workspacePath, xcworkspace: xcworkspace) + let mapper = XCWorkspaceMapper() + + let workspace = try mapper.map(workspaceProvider: provider) + #expect(workspace.projects.isEmpty == false) + } + + @Test("Resolves container path in XCWorkspaceDataFileRef") + func testMap_ContainerPath() throws { + let workspacePath = try AbsolutePath(validating: "/tmp/ContainerWorkspace.xcworkspace") + let elements: [XCWorkspaceDataElement] = [ + .file(XCWorkspaceDataFileRef(location: .container("Nested/ProjectD.xcodeproj"))) + ] + + let xcworkspace = XCWorkspace(data: XCWorkspaceData(children: elements)) + let provider = MockWorkspaceProvider(xcWorkspacePath: workspacePath, xcworkspace: xcworkspace) + let mapper = XCWorkspaceMapper() + + // container paths are relative to workspacePath parent directory + let workspace = try mapper.map(workspaceProvider: provider) + #expect(workspace.projects.isEmpty == false) + } + + @Test("Resolves developer path in XCWorkspaceDataFileRef") + func testMap_DeveloperPath() throws { + let workspacePath = try AbsolutePath(validating: "/tmp/DevWorkspace.xcworkspace") + let elements: [XCWorkspaceDataElement] = [ + .file(XCWorkspaceDataFileRef(location: .developer("Platforms/iPhoneOS.platform/Developer/ProjectE.xcodeproj"))) + ] + + let xcworkspace = XCWorkspace(data: XCWorkspaceData(children: elements)) + let provider = MockWorkspaceProvider(xcWorkspacePath: workspacePath, xcworkspace: xcworkspace) + let mapper = XCWorkspaceMapper() + + let workspace = try mapper.map(workspaceProvider: provider) + #expect(workspace.projects.isEmpty == false) + } + + @Test("Resolves group path in XCWorkspaceDataFileRef") + func testMap_GroupPath() throws { + let workspacePath = try AbsolutePath(validating: "/tmp/GroupWorkspace.xcworkspace") + let elements: [XCWorkspaceDataElement] = [ + .group(XCWorkspaceDataGroup(location: .group("MyGroup"), name: "MyGroup", children: [ + .file(XCWorkspaceDataFileRef(location: .group("Subfolder/ProjectF.xcodeproj"))) + ])) + ] + + let xcworkspace = XCWorkspace(data: XCWorkspaceData(children: elements)) + let provider = MockWorkspaceProvider(xcWorkspacePath: workspacePath, xcworkspace: xcworkspace) + let mapper = XCWorkspaceMapper() + + let workspace = try mapper.map(workspaceProvider: provider) + #expect(workspace.projects.isEmpty == false) + } + + @Test("Resolves current path in XCWorkspaceDataFileRef") + func testMap_CurrentPath() throws { + let workspacePath = try AbsolutePath(validating: "/tmp/CurrentWorkspace.xcworkspace") + let elements: [XCWorkspaceDataElement] = [ + .file(XCWorkspaceDataFileRef(location: .current("RelativePath/ProjectG.xcodeproj"))) + ] + + let xcworkspace = XCWorkspace(data: XCWorkspaceData(children: elements)) + let provider = MockWorkspaceProvider(xcWorkspacePath: workspacePath, xcworkspace: xcworkspace) + let mapper = XCWorkspaceMapper() + + let workspace = try mapper.map(workspaceProvider: provider) + #expect(workspace.projects.isEmpty == false) + } + + @Test("Resolves other path in XCWorkspaceDataFileRef") + func testMap_OtherPath() throws { + let workspacePath = try AbsolutePath(validating: "/tmp/OtherWorkspace.xcworkspace") + let elements: [XCWorkspaceDataElement] = [ + .file(XCWorkspaceDataFileRef(location: .other("customscheme", "Path/ProjectH.xcodeproj"))) + ] + + let xcworkspace = XCWorkspace(data: XCWorkspaceData(children: elements)) + let provider = MockWorkspaceProvider(xcWorkspacePath: workspacePath, xcworkspace: xcworkspace) + let mapper = XCWorkspaceMapper() + + let workspace = try mapper.map(workspaceProvider: provider) + #expect(workspace.projects.isEmpty == false) + } +} diff --git a/Tests/XcodeProjMapperTests/Mocks/MockDefaults.swift b/Tests/XcodeProjMapperTests/Mocks/MockDefaults.swift new file mode 100644 index 00000000..b74b204b --- /dev/null +++ b/Tests/XcodeProjMapperTests/Mocks/MockDefaults.swift @@ -0,0 +1,22 @@ +import Foundation +import Path +import XcodeGraph +@testable import XcodeProj + +enum MockDefaults { + static let defaultDebugSettings: [String: Any] = [ + "PRODUCT_NAME": "$(TARGET_NAME)", + "ENABLE_STRICT_OBJC_MSGSEND": "YES", + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.debug", + ] + + static let defaultReleaseSettings: [String: Any] = [ + "PRODUCT_NAME": "$(TARGET_NAME)", + "VALIDATE_PRODUCT": "YES", + "PRODUCT_BUNDLE_IDENTIFIER": "com.example.release", + ] + + static let defaultProjectAttributes: [String: Any] = [ + "BuildIndependentTargetsInParallel": "YES", + ] +} diff --git a/Tests/XcodeProjMapperTests/Mocks/MockProjectProvider.swift b/Tests/XcodeProjMapperTests/Mocks/MockProjectProvider.swift new file mode 100644 index 00000000..2beaf4ac --- /dev/null +++ b/Tests/XcodeProjMapperTests/Mocks/MockProjectProvider.swift @@ -0,0 +1,84 @@ + +import Foundation +import Path +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +/// A mock project provider that sets up a minimal, in-memory Xcode project for testing. +struct MockProjectProvider: ProjectProviding { + var sourceDirectory: AbsolutePath + var xcodeProjPath: AbsolutePath + var xcodeProj: XcodeProj + + var pbxProj: PBXProj { + xcodeProj.pbxproj + } + + init( + sourceDirectory: String = "/tmp", + projectName: String = "TestProject", + configurationList: XCConfigurationList? = nil, + pbxProj: PBXProj = PBXProj() + ) { + let finalConfigList = configurationList ?? .test() + pbxProj.add(object: finalConfigList) + + self.sourceDirectory = try! AbsolutePath(validating: sourceDirectory) + xcodeProjPath = self.sourceDirectory.appending(component: "TestProject.xcodproj") + + // Minimal project setup: + let mainGroup = PBXGroup.test( + children: [], + sourceTree: .group, + name: "MainGroup", + path: "/tmp/TestProject" + ).add(to: pbxProj) + + let projectRef = PBXFileReference + .test(name: "App", path: "App.xcodeproj") + .add(to: pbxProj) + mainGroup.children.append(projectRef) + + let projects = [ + ["B900DB68213936CC004AEC3E": projectRef], + ] + + let pbxProject = PBXProject.test( + name: projectName, + buildConfigurationList: finalConfigList, + mainGroup: mainGroup, + projects: projects + ).add(to: pbxProj) + + pbxProject.mainGroup = mainGroup + pbxProj.add(object: pbxProject) + pbxProj.rootObject = pbxProject + + xcodeProj = XcodeProj(workspace: XCWorkspace(), pbxproj: pbxProj) + } + + func pbxProject() throws -> PBXProject { + try #require(xcodeProj.pbxproj.projects.first) + } + + /// Creates a basic mock project provider with a unique temporary directory. + static func makeBasicProjectProvider( + projectName: String = "TestProject", + sourceDirectory: String = "/tmp/\(UUID().uuidString)" + ) -> MockProjectProvider { + MockProjectProvider( + sourceDirectory: sourceDirectory, + projectName: projectName + ) + } + + /// Adds the provided targets to the project's PBXProject. + func addTargets(_ targets: [PBXNativeTarget]) throws { + let project = try pbxProject() + project.targets.append(contentsOf: targets) + } +} + +// MARK: - Extending PBXProjectMapper for Testing Utilities diff --git a/Tests/XcodeProjMapperTests/Mocks/MockWorkspaceProvider.swift b/Tests/XcodeProjMapperTests/Mocks/MockWorkspaceProvider.swift new file mode 100644 index 00000000..477679ae --- /dev/null +++ b/Tests/XcodeProjMapperTests/Mocks/MockWorkspaceProvider.swift @@ -0,0 +1,18 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +/// A mock workspace provider for testing, supplying an XCWorkspace and directory paths. +struct MockWorkspaceProvider: WorkspaceProviding { + var workspaceDirectory: AbsolutePath + var xcWorkspacePath: AbsolutePath + var xcworkspace: XCWorkspace + + init(xcWorkspacePath: AbsolutePath, xcworkspace: XCWorkspace) { + self.xcWorkspacePath = xcWorkspacePath + workspaceDirectory = xcWorkspacePath.parentDirectory + self.xcworkspace = xcworkspace + } +} diff --git a/Tests/XcodeProjMapperTests/Mocks/PBXProjectMapper+Mock.swift b/Tests/XcodeProjMapperTests/Mocks/PBXProjectMapper+Mock.swift new file mode 100644 index 00000000..3e405616 --- /dev/null +++ b/Tests/XcodeProjMapperTests/Mocks/PBXProjectMapper+Mock.swift @@ -0,0 +1,35 @@ +import Path +import Testing +import XcodeGraph +import XcodeProj +@testable import XcodeProjMapper + +extension PBXProjectMapper { + /// Creates and maps a test project with given targets. + func createMappedProject( + projectName: String = "TestProject", + targets: [PBXNativeTarget] = [] + ) throws -> Project { + let provider = MockProjectProvider.makeBasicProjectProvider(projectName: projectName) + try provider.addTargets(targets) + + let mapper = PBXProjectMapper() + return try mapper.map(projectProvider: provider) + } + + /// Creates a mapped graph from multiple project providers, useful for testing multi-project scenarios. + func createMappedGraph( + graphType: GraphType, + projectProviders: [AbsolutePath: MockProjectProvider] + ) throws -> XcodeGraph.Graph { + let mapper = GraphMapper(graphType: graphType) { path in + guard let provider = projectProviders[path] else { + Issue.record("Unexpected project path requested: \(path)") + throw ProjectProvidingError.noProjectsFound(path: path.pathString) + } + return provider + } + + return try mapper.map() + } +} diff --git a/Tests/XcodeProjMapperTests/Mocks/WorkspaceFixture.swift b/Tests/XcodeProjMapperTests/Mocks/WorkspaceFixture.swift new file mode 100644 index 00000000..cb02acbc --- /dev/null +++ b/Tests/XcodeProjMapperTests/Mocks/WorkspaceFixture.swift @@ -0,0 +1,68 @@ +import Foundation +import Path +import XcodeGraph + +import Foundation +import Path +import XcodeGraph + +// MARK: - WorkspaceFixture + +/// Provides references to sample Xcode workspace fixtures used for integration testing. +enum WorkspaceFixture: String, CaseIterable { + case commandLineToolWithDynamicFramework = "command_line_tool_with_dynamic_framework/CommandLineTool" + case iosAppWithRemoteSwiftPackage = "ios_app_with_remote_swift_package/App" + case iosAppWithSpmDependencies = "ios_app_with_spm_dependencies/App" + case iosAppWithExtensions = "ios_app_with_extensions/App" + case iosAppWithMultiConfigs = "ios_app_with_multi_configs/Workspace" + case iosWorkspaceWithMicrofeatureArchitectureStaticLinking = + "ios_workspace_with_microfeature_architecture_static_linking/Workspace" + case multiplatformAppWithMacrosAndEmbeddedWatchosApp = + "multiplatform_app_with_macros_and_embedded_watchos_app/AppWithWatchApp" + case iosAppLarge = "ios_app_large/App" + case ios_app_with_transitive_framework = "ios_app_with_transitive_framework/Workspace" + case macosAppWithSystemExtension = "macos_app_with_system_extension/App with SystemExtension" + case iosAppWithStaticLibraries = "ios_app_with_static_libraries/iOSAppWithTransistiveStaticLibraries" + case tuist = "tuist/Tuist" + + var fileExtension: String { "xcworkspace" } + + // NOTE: - This is temporary to reduce PR noise + /// Unzips and returns path to the Fixtures directory, if not already done. + static func getFixturesPath() throws -> String { + let fileManager = FileManager.default + let tempDir = fileManager.temporaryDirectory + let fixturesDir = tempDir.appendingPathComponent("Fixtures") + + // If already unzipped, return early. + guard !fileManager.fileExists(atPath: fixturesDir.path) else { + return fixturesDir.path + } + + // Otherwise, unzip the fixtures. + let zipPath = try AbsolutePath(validating: #filePath) + .parentDirectory + .parentDirectory + .appending(components: "Resources", "Fixtures.zip") + + let process = Process() + process.executableURL = URL(fileURLWithPath: "/usr/bin/unzip") + process.arguments = [zipPath.pathString, "-d", fixturesDir.path] + try process.run() + process.waitUntilExit() + + guard process.terminationStatus == 0 else { + throw NSError(domain: "UnzipError", code: Int(process.terminationStatus), userInfo: [ + NSLocalizedDescriptionKey: "Failed to unzip fixtures", + ]) + } + + return fixturesDir.path + } + + /// Returns the absolute path to this fixture's workspace. + func absolutePath() throws -> AbsolutePath { + let fixturesDir = try Self.getFixturesPath() + return try AbsolutePath(validating: "\(fixturesDir)/\(rawValue).\(fileExtension)") + } +} diff --git a/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift b/Tests/XcodeProjMapperTests/ParserTests/ProjectParserTests.swift similarity index 70% rename from Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift rename to Tests/XcodeProjMapperTests/ParserTests/ProjectParserTests.swift index b7191b60..724b88bb 100644 --- a/Tests/XcodeProjToGraphTests/ParserTests/ProjectParserTests.swift +++ b/Tests/XcodeProjMapperTests/ParserTests/ProjectParserTests.swift @@ -4,10 +4,16 @@ import Testing import XcodeGraph import XcodeProj -@testable import XcodeProjToGraph +@testable import XcodeProjMapper @Suite struct ProjectParserTests { + let parser: ProjectParser + + init() { + parser = ProjectParser() + } + private func createMockDirectory(withContents contents: [String]) throws -> AbsolutePath { let tempDirectory = FileManager.default.temporaryDirectory let mockDirectory = tempDirectory.appendingPathComponent("MockDirectory_\(UUID().uuidString)") @@ -29,73 +35,73 @@ struct ProjectParserTests { } @Test("Parses a directory containing a valid .xcworkspace file") - func testParseWorkspace() async throws { + func testParseWorkspace() throws { // Arrange let mockDirectory = try createMockDirectory(withContents: ["MyWorkspace.xcworkspace"]) let workspacePath = mockDirectory.appending(component: "MyWorkspace.xcworkspace") // Act - let graph = try await ProjectParser.parse(atPath: workspacePath.pathString) + let graph = try parser.parse(at: workspacePath.pathString) // Assert #expect(graph.name == "MyWorkspace") } @Test("Parses a directory containing a valid .xcodeproj file") - func testParseXcodeProject() async throws { + func testParseXcodeProject() throws { // Arrange let mockDirectory = try createMockDirectory(withContents: ["MyProject.xcodeproj"]) let projectPath = mockDirectory.appending(component: "MyProject.xcodeproj") // Act - let graph = try await ProjectParser.parse(atPath: projectPath.pathString) + + let type = try parser.determineProjectType(at: projectPath) // Assert - #expect(graph.name == "Workspace") + #expect(type == ProjectType.xcodeProject(projectPath)) } @Test("Parses a directory with both .xcworkspace and .xcodeproj, preferring the workspace") - func testParseDirectoryWithWorkspaceAndProject() async throws { + func testParseDirectoryWithWorkspaceAndProject() throws { // Arrange let mockDirectory = try createMockDirectory(withContents: [ "MyWorkspace.xcworkspace", "MyProject.xcodeproj", ]) // Act - let graph = try await ProjectParser.parse(atPath: mockDirectory.pathString) + let graph = try parser.parse(at: mockDirectory.pathString) // Assert #expect(graph.name == "MyWorkspace") } @Test("Throws an error when no valid project files are found") - func testParseDirectoryNoProjects() async throws { + func testParseDirectoryNoProjects() throws { // Arrange let mockDirectory = try createMockDirectory(withContents: ["ReadMe.md", "file.txt"]) // Act & Assert - await #expect(throws: MappingError.noProjectsFound(path: mockDirectory.pathString)) { - try await ProjectParser.parse(atPath: mockDirectory.pathString) + #expect(throws: ProjectParserError.noProjectsFound(path: mockDirectory.pathString)) { + try parser.parse(at: mockDirectory.pathString) } } @Test("Throws an error for a non-existent directory path") - func testParseNonExistentPath() async throws { + func testParseNonExistentPath() throws { // Act & Assert - await #expect(throws: MappingError.pathNotFound(path: "/non/existent/path")) { - try await ProjectParser.parse(atPath: "/non/existent/path") + #expect(throws: ProjectParserError.pathNotFound(path: "/non/existent/path")) { + try parser.parse(at: "/non/existent/path") } } @Test("Parses a directory with only an .xcodeproj file") - func testParseDirectoryOnlyXcodeProj() async throws { + func testParseDirectoryOnlyXcodeProj() throws { // Arrange let mockDirectory = try createMockDirectory(withContents: ["MyProject.xcodeproj"]) - // Act - let graph = try await ProjectParser.parse(atPath: mockDirectory.pathString) + let type = try parser.determineProjectType(at: mockDirectory) // Assert - #expect(graph.name == "Workspace") + #expect(type == ProjectType.xcodeProject(mockDirectory.appending(component: "MyProject.xcodeproj"))) } } diff --git a/Tests/XcodeProjMapperTests/PerformanceTests/PerformanceTests.swift b/Tests/XcodeProjMapperTests/PerformanceTests/PerformanceTests.swift new file mode 100644 index 00000000..06f18c27 --- /dev/null +++ b/Tests/XcodeProjMapperTests/PerformanceTests/PerformanceTests.swift @@ -0,0 +1,84 @@ + import Foundation + import Path + import XcodeGraph + import XcodeProj + import XcodeProjMapper + + + import XCTest + import Testing + + class PerformanceTests: XCTestCase { + func testFullGraphParsingPerformance_iosAppLarge() throws { + let path = try WorkspaceFixture.iosAppLarge.absolutePath() + let parser = ProjectParser() + measureAsync { + _ = try parser.parse(at: path.pathString) + } + } + + func testFullGraphParsingPerformance_commandLineToolWithDynamicFramework() throws { + let path = try WorkspaceFixture.commandLineToolWithDynamicFramework.absolutePath() + let parser = ProjectParser() + + measureAsync { + _ = try parser.parse(at: path.pathString) + } + } + + func testFullGraphParsingPerformance_iosWorkspaceWithMicrofeatureArchitectureStaticLinking() throws { + let path = try WorkspaceFixture.iosWorkspaceWithMicrofeatureArchitectureStaticLinking.absolutePath() + let parser = ProjectParser() + + measureAsync { + _ = try parser.parse(at: path.pathString) + } + } + + func testFullGraphParsingPerformance_iosAppWithStaticLibraries() throws { + let path = try WorkspaceFixture.iosAppWithStaticLibraries.absolutePath() + let parser = ProjectParser() + + measureAsync { + _ = try parser.parse(at: path.pathString) + } + } + + // Current PR 2 seconds + // Sync 5 seconds +// func testFullGraphParsingPerformance_tuist() throws { +// let path = try WorkspaceFixture.tuist.absolutePath() +// let parser = ProjectParser() +// +// measureAsync { +// _ = try parser.parse(at: path.pathString) +// } +// } + } + + + extension XCTestCase { + func measureAsync( + timeout: TimeInterval = 30.0, + for block: @escaping () throws -> Void, + file: StaticString = #file, + line: UInt = #line + ) { + measureMetrics( + [.wallClockTime], + automaticallyStartMeasuring: true + ) { + let expectation = expectation(description: "finished") + Task { @MainActor in + do { + try block() + expectation.fulfill() + } catch { + XCTFail(error.localizedDescription, file: file, line: line) + expectation.fulfill() + } + } + wait(for: [expectation], timeout: timeout) + } + } + } diff --git a/Tests/XcodeProjMapperTests/Resources/Fixtures.zip b/Tests/XcodeProjMapperTests/Resources/Fixtures.zip new file mode 100644 index 0000000000000000000000000000000000000000..732c19c9fce41862f86af45c49d04d15ce228986 GIT binary patch literal 8760289 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

N|^0be44*|6>u@C#|^w^o!bAl7$yyalm2Q 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

J9=!5xw{MCfpoK;0xqm!@X2D$YWHNpMzf_4C< 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

A-vxj$=u$|&RA3T z8xQ(hy9M{3iQNFBfb{?7i-~{y#d7ulfx|BZi{sC}9wh(JI{fBf}y0=+(SCQ5^EYCyBD_~4zBc@>=`yY*>5rCUMgIf#HR)(sz~*E{iL0vzklSAJ*( zR9KZyJ&Lfy(QK&^x)>0;iXoq&_nj>n;uySpdj%cNLL|YAi9sK!V8cpR@CG*`HxX`- zI#NNHKqh{g1W|ZOd^eZO=#=<#zmEb%C)tJYyH|O`40wJjP4REv_~?BcD_hZAc}bGR zfzZ@dAABIlceT3Kk`^wsA`rc=RV3qN=9t_0j+*>s`Tp*=4FQ!8#iHGNOh; ziRzgPzlB0^sE2w{>hlGYD%vb6N74=3#23AYZV%0AlIG5FrWOONmtKsD$H;TrRk?R= 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

5GPg{|!)d#$c--QeNGXHYVD_#H;0F9s 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%0A4Qx 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

    ~I|djIy1gzPCb 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

    dVXR#b{6&3@6>aoQIx7UkS5Xb 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

    i&{7^k1L=pHsa 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

  1. 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

    xw733*f;@K;)DNBVcW@5>^c! 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

    GA2G2QmTc(eiLH_`E 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

  2. $d3wyoQZz&)3+>RrxTI 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�UDQX~ngSE1Jx^*efF!WZxZl7vPI%%UKL5!R z+!U6+w%XoA+hP&Z9yPWFut~=*97?CvLm@D-!+A?@zC#X#&ImzKqY1Pbss;zW$O~8> z^v3mlOr0nkG}2EQyrMRfQk;!aTzFs-M|tK_79Slg@+}<_Np_(I43S z)GW5!V|Z++R}U>TU`KUVCWR9&Gzj{RGKw}ojm#RKu;j2WO`+!e(`%vp_p+&N1f?oH z$O5i<{+g;m_>y~Sz7kUU-4{h_?+BMnTZaUFBFQ2E(^*CR^P*%P+Wy3c1#}teu);Vb zJ|C%ij0`Np_Pna#oM`LGfYB9JrNIj#B8uO~#yhbbCk)&C3o(Puj?~kVaqlTHrt(!P zHI6_&NIFAc^=Wgf5s&|$fmmv3G8OvU9f?Ev%)tleWWbt9NdZd!?MRsK=WRf1RCzp8$|1)Z! zYWUq4b!HxxrN;nidQl;&^d$lBg;QOI`Bo&~c84}*uB$EIMHbz)XFN>#4F3X?ZR_6r zV$6-+MXBM zcmix9c8Y2!6eAleC2YwfXPL|wd<5PGz&R;S@ZP_Y3E_9D%v+2lEb?~<;`Rd7j`&+y z+Q~3Q`2@oqzpE($y)^!aL35~g?VWnX7_y8-p6?k+{&%<^=8z+(iwK4G3*M)Yx8v1UU$d>Q%nA| zH-M?e^0vfAw~n1{B!+3OlN}?vD4rwxTpGP4 zy{f);K>k4{AIknoKQ*6kwVqnb596%CheQd$i^#cQwZ6S^4^?s~#~HhNc574L@3j$` zPX@~wU3wG^B?R;hNZu*=Q>eEfFEjl_%|z*^g+Gw35DM4Dm!mfsWuUAnmGOm%Y}{1*k__M{L0tuv!@0jmFT0 zKytWjbRbzhk^@kLInwbz9B7BqQ}DMa%E_~}nCaH&EylSK4}%`szn=dEGeFG0^=E&$ z88TCu@&xG^);VA7d@C6f`R={D#q{ewO+)K+MVp@eG8IV zE4R|sEYXl{Fa$iG0j7Gf0f{IWUu2so{ou%$zG+9lMosK_qb|1e2jdFK7;Mr?FQp`& zgPhEn?i!ti`OJDCkAL@vNgJVg2fzGklOFdEu}!wfd^lR$sJ2>ezgRO1%1^f{e)r8R zLRrAzt5vC4pYyV%ofh=LX!)I1nE`p9Scekd^xFv*WqIpDZyMHce>0axQS;N@bm@Bu z=@Mvvl6PG2I8mA~0aA|5sI@C7uhah|silK1`1Q8Wd@@!);oi_>oUAV7&-BYnLk|5# z!aN5zB4QKgWaQX@pFK|h3=IdlM{rbor4}-lbS0n{QrX*u7otZ(zOMnFLc-7@6+7b1 z_=_#)wj3q{?~;Yni|B4c9V{bwalx{L{D^czb4y%z5P4OtQNMoQw?gN2DYs@F_pA4X z1G_D^Gb}f2O7+aY{P3n3W>ut>WY#x`F(unzj6}+|#VANoziNXwOUd@h z>6t-$%sf}jJeP~IN9{l*TBar7=jh2A&YZeL8_=fJjqV)T8}Zy7)VCP-=i$}qCm49~=r1ic7KzAq7>UFt z|1^G(eMfS|s#Nj^bkw-;O}?BuG0sIqdPmy)sWpna#_D68;c%f!RFy~=1NhJ7!Ja zZse25$Aof*HI%{z@U_2jR_P!vMIfv(+4@$M20lKDMd@TbuahC=x#yn`5KVC!67GUU zIoESUgiKgFjv9J!h?8N;!hi@|AXT%FQ6BcsB|*n}@Sl8iS!ISmK4p&cMlQ#6vH`J# zwBWh$77N~ueChxh6M4~v1dP(sL*G<^FjL(X{qq82^^#Ty$`|PN7B`-b5Lf!Q&VsH8 zSa8Cuzf+cZw|yxv!2aA1c?(Yvb-ST9Uru^_y?~^kWB6g;)eU`qW7#0+dV)~3Slg363js#RB3RhDS zau7-~t!M!MiKgF7X9(1gA{hc96m$n05RT^2_NL&kc(AnSCOP0Se;}|SGSj?fEVD;K zin?4~t#jqOpOM*fML(mUZ#lEJi~~33etMP2PR^wvn&_ece^i%wzMiFzM2|{7zMry| zd$%pfV0H_p53_%mm-S;5F69pAJI{$<2&W{}z#dq-EWV3}lgEhbRh87ux7u=`XnGs%W@N$lS%i3KmiH=LkZ%0Gq8o_H}%-R`E(9;p*y8%@1J%UCXWp zt#N_9OP+7`>g;A#3$>tigXVUMc^C!V#-Uqw8+(sgjjRitHLK8-)?qv1vPgM)4F%GZ zC={Blhb_UAV}X%vVi}um6X}nr_;5eM_)g{npX+ujIk#z&%hCamK2iR}L7H|**0apO z;6Mk(yGK=)GoH~XWTAm?-$74`$cLfTp+m{^IVO@zlSX0j{=tmXhLMgY=zKH*@@6|w zO!79$)u7CC4=B)b_U5d;ps~wugqyWEA)VzkN&E7 z3+L38QkfezO+w|&sqX%q87YIA=~=rU&we%-U>niB;Pt|zi-;iRJDuAQgeZOcv%T$# z+w_rrM~>34YtxuEKaH!?RJENiiUBNhw4F2!a+A@oZ>wsn8r{v7*cHQDjlNt|i3UIE z-*%Aj4!0@0JRN`FX^~-8s#jP+vXZOKt~1uuGqUN+FS^aCJgS-U8sCu?-F>f?S&2N! z8p^pn0h;3tbRlD7y|lq)t2v@9yx3kg?DX5R6*BzRN`1g#;8&>MBzbT=yX(2;B+A0M{)TaP@(C49t;&dKTSz6oa@#{2`!s5Wv``ilP#4(=UylIJFJhjS3 z?}x&!6j<>E1l_j1{|ZL(oxR)j+-EZQ67kMuC1GE5JvO*%&nI59Pi@J{tU1L+Fe9Kf zsaa2@Y}%k8-MV;r?j(m)jHBOOpaTsu_hOj&EV&glf5qCmmw&19yEi#}RQ$W0yUU;B zH+DjJ@S=40o?u+`wW_SXlXg4xEHSN^>p!k=nJWG~kFbui!NR4&zL6;R)j!je%2ozt z3JQu%Qhp~+e9+ul$1Ao^1niqPWU~Q!i9gwZy&rT@5_&3gub%lC381T5PWa=v8B+95 zWZQqZ``yzd)OwtX^py!m6iYmbG3sj3^)v)@r9^MH`I*dxZ|ApT!m@4!jEN zuX->4+~YwR#bkv)C9Oo>#JmC4hf@t~^C;T)TpD=xOYr}PT_DGpAXIx9cnbl!0$v+y z(PslnL*{o8GEv|yxenB151N(#JWhe3FtOvluR-BEPM0A|{HewVq~GmmyEAOHA-?-v z+nKa}ql@@kTfMFM><+YPym0+v^IMru*BUPze7`wTq7{7^*ax*L)pOYK94ovF!W;Tx z6z)x^iM@GaZCxKJw!d1~t=M{{m?|!*#aB8r8 zyzTAfz5NS+l}cJXylx==<;Cyc#AYb85tG|Jf?UI-|DahPLbtm|-p@B4;xu z)*C-F02AJ9!0)KDjN7!x9+IjqGn)o97gi8c%3# zRRwg{d01v%Hztg$l$p!$uv|apZMcduPQG{_a`JBeyteWYi?jT9AL2T5^ z-8-LKDsk0~(Ph)dNwdUz>asVg8tOUEh)Zk$qNA7h9O%saxKy|$W$j+9NqTi1d7k1g zNobisOf>4RB6HsfM90iUBzX|x|+|kY8 zbXJC63^OqT_48pW8!&kjwNre>k9Fn{iP>{u15R^Fsb8s03^ip)?`8vv>(-Hw9yVa> z>2vUEj|dy^q-(L9p})oW!01P{_kp*P69w6TsmpZzf9@$C9u1xT=bke7=qzXD<;Sy$ z?c46_$_%k$HbA=dh%@?5Ax6NvP9D#;X0M_C>O98r0mr`4ZB;BynaV1ozhj-RW&@Jn zGE-1%34x<*fQ3gXfx68cP~mu?1ajz6B5pJ;kotU}6Y0HsJPc1bx`4fZ#2g}>#EFCUfr?2G;|A5gS9f~GmmTQx*=F-Wi(rxd&zci zNOS}LtSNb^kB`_*Lt8|80?Wn~D7*OwRzJKAnFv~v=OXLQ> zgRcXnbOxZg)16`$u0D>*g^bMcykZm|DX;Z&t2f+EeP%H+EuS-v(@;Okmgooe;{=ZW z+0bwg)ozr|;?_R`!`iOX+`gPGVJwV;3~j=+-pH35UYp)K zt>WEJmzxHwMz9+d(v^fAUa#5N#g+D(OQ`;@nb%pJJspBe@*kf(akb#pWcd7qS{AA& znWt*Vw!KJ7kvTn*`hC#+a-wn0+)v~q4$1f*w*-gEM51~J!K(yL;u%#y9|i?0kFgX> zcLfS$PwY3dcgr&F##TnaSjD} zP3Wa@S}%(S%Sjsr`XD9Sv|G!4{cHsTNL|Y)m_S~phf;F}^r-mA77*s3f{<q1VwQN5}qxK0AyWPRK zCl^;8shEhx2l$S5te#9&G`3TAB*iC-Y=Q4y&bv(=0&{S&q zp3hyu3lrTM$o+2RP#HQKyTk?@U)txu=&7sBa)iZ^2(mv%mEK9+ClShN*5vSRR`NVH zLV|nLFBE21*GfZ2vBvfeF;R*Lu(wYMs^c!H9B4{F7!*JB-m@AvNj?2XMq08uRu}_4 zIIo{JI;bjU@1Z38dIHebzIht_Ab+GsaQ@g%O0n!ioV$x1d+U6sG#B6>`t91 z<2d^2=lWh4oPUO&d ziTG5d4OT3bV}PIvxYim0ktGh9cWpmIBF71P(QPY+GdKNx%~_jsY`{rYH)=i+ z*I?R%nug8uMR}n-<|4%Kor&>m05^yU?sU4@+Dt8~nrDiTPp6jI;6q89VjhP|Sa&G% zQ_$-@MGGU^`BY3RA=CTI@;i&l5b=9%bGjqA+hhj}PpZq+$~#dL9nY`Hr;HSfRp-mr zVhk-}5q(a#-xosf45ZF<4>{~!&tp#bF*aQetl5BfAJ_m_;CaSzX8n$LY|hz{^;&Np z)|k`zM%p6Q*`0gZPM2oUY4`cN&NW9n`%doPqOo=}bffOzlsp3^Z*5~T-vy^11t^c` zMJCVNZBfeYV&{^+{vyaTvskaqmF>iPg3|%}V#Ov3t|k|Z;2QY~J@~a|L=*6a2OB_j zNTkb0yen7^7XEN#_G2ORk!Cs6f-a%%ow41N0x!hnwA`ZgyKSgp+G7ziXqMp8^K{9;|Bf{HSW zm2yeIlXR5T92{P**W zuU>5BGu{n@E$6G2n()Vy%Ql*DI%~{e4iIi4$50Ze7p9Zx26XI^7UQ=@I-GVKmEd%O zn$>o#ZkVA=J`3z5_C~h64k(6}W9ZF~Xs45_7ncl27gS@9`HS1jMg)%kH zztoX12EGK!nEr7HG5Z^&I81Z{siPDxuuXthx+(b1q`QZwjIJX9ZIH zW9v4`)`kjA_yY_FgK#EgOiq~JdEj2K0ep;C%qneH+EVwPif4w*S}Dm<975egYafR} z=yni(B~Yt)yImczAA15DxdY*&&)JUhr#RRLCXL=FC`u*3WfVz11Q%^-TO%%mExbyx ztck%C(<$tINw@$0f|gmjKGz*wRLn@NIm^4x`w%!L!VnhU`$g|N5=7#gcvwT=^ZxiK zpoESRECU^Z5D#)D@!I#;nRd>I>y46{X&QiNWY##@Y8=o(N?=*UgGa!_zWXwmwl<<+(h1?CS^gqPfxov zbP%eZ4k>3VBE z3>9pSvmF2az0Z)ak7S}$k2oDK>=lckqsXkqxhiuZey1l>@s@Nmnxb+Y>J-9|YE@jY za%h}|RG|K<6A5m6=Zc+fFOi907-1mLrj2Y^pi;poxK?KP=a|3yDA1yXfz}=bJ z0CCg0p4NH}mx}6{P7UqF{SZ&Qrzv;8&dckWj?K1jg>AQx}i^6k15*VP~=ms^?mFTZv!?OR#UQu>}5(rA*5(QGKqDqzexYQDa& z(T4wtazRtQHW_&}^Xbe4h!|=Y7FdG2O@SQ9`apJ9Ig`nkouS~lE@bSM4hJ*C#!>BX zoomPr9KRoUs&o%d?S1dB9IG+QUr9?$XbGiciqF6dsXE!%fgq8{TGR7%FXH}_`mq+X zAh;WGX0fo`VfI&(Tc%IZG_QbF(-0wo#wE=< z88K*^?jdwfSQn7Ps0$1YG6Zm+Jfqx0 zI8;xhZnis#r16I6)s4Tbol3SG-U+$)Y<<1lzm(oK2>MwyxOfA<*mv;`lShg4cd0yf zH%mygqXr{yVve=S`*r^MQsIgsiSId+hyv0#P6*}%6!X63Bt~l-#u>=k&Gft zN#D!1Yt*cU^o9$Z);p_H!3VNblrPM4Es|ix88eH0eiLlopW^AVBCyjdTGKfdB$h z5~K%6C}Bg|7r*a&XP$Sy=kIss`-jXhduFe-?zOIUUH88C+C<;I43dnt*=SPWfR!}n zhD`=O(<~sYuAwEw@GIASu8isoN8VtMhtK~;m17F`bM>BBhX_+St}79bxI+WSg;d&f zqAqGcFKuW=xlf{t*-bj&AB}(9jkJRvZ{bWD8sj8wjLW`TQ`31K7tuE~+ zzgN2GVqq zmMK$eSZ(WNyYox%sz=MBgXD>dxx05V>(hMPoQHNHT(t@)?Q{|Nnf6?h9wLch9hd8x z@;5&r&yBMc;Lhy3quU{{b8sHF@rKuU^&=@AA&LIsh4kUnYoNJU&X2*EJg2M%huYx~aaAI9S6DWu3aT6c}CMUtJoAUp3P{=9<8v*a&lPCI;Azh0F$hgVi7@B)P<XQ_-+5|ZdUQ}`pJ3-as!J?Z&?rJ1DP$~5x5#F-=2fHBZMGW@oWX0?xP;r4 zt8(3t{b0I<3I}wcNwY(0^g?#;KSmv}A;-S&25gqlWk;smgc#r^#1z7cmClwXP~sVK zb89mKy?g@vKH>|#goLT%&=f)$T!iU_RmPEaP68%I6YoEcZZXXvu~qx{^BWQDng_Vq z86Wq{qyGDecMmjM+N+P1g-Nc49(Ne#s@C~Zb~0x)rEWe=hIuJFP2jFK$XVE0V=o%@ zHs20_W(};HrKPQ8&52@zk7fWU*PcPHJvq!9wBoo#PgZf8DeY>PlCj>fM<+~pf0(D& zU3hBCMA#>|TlSql&O0leTXrra3zxszUv{;L%I_(%s;))vUNVw{ZV0|V@)!U3+%oU3 zVH)&ZpFe8+^RQv*^jH*(zipJo0UIqz``_&G_obRIA^f`A2QBwSfzJfFn=p> z8zH(x5ctuUL&or%N7T5m8fWI|8idhMp2m8#Ep@xFa3kHxaVUcR6seQ5ocS#21%lrx zn4wv0S#EFVJsfOP=GUrOpAm56C1#}M*J0Y9WoeMQD8c57XQ%*vbUUt_@l020)60;z zAp#(TX*Kn*56|Nr_U-kJ{Y02lXNbN9cKusl*$HurrXK!lee#9VGyRf{?}}K7<}sSn z0fFB?LjNp#`}3`DX3?s1RQ`pE`6|mq_pjC)Ki3A)Y7v7D=|47$mAw_W>luVa@b@XE z#1;p13d7XJ&_lVb@(#FGw_kBe)9u)ZXm17>~k^ z%&U0xRW+n%pZhrLK_A0>7R^t=H`N_is>BUp@;RXS6&)@wJqJ@60LR0qE|{~Z&PUuE z`2|V-oX4EeZ^_i%RCbD4J;30NQyVgxmxn0W*RHiC>$@}Rd0A~V zYio^S%8}jC^Oikl4k*40`H71xPp5hord>#o9zqPE>B37|A^j!rlC)*=H)e5e8>f_s zPL9^Pzv0JSTc!gIlN9)1sxJ>a99TFH1iN5v(cn=c|_zpKQRNgQvp23EQ_$?B}2^0tsvbxqFkc-(-mz z7x!^_YF*hUx(qCj^(NbzEN(8`JH8huonjJG7Mr46C2w1{1*=bba0;4fY?&dd{sHT~ zCvTg5XjgHRTOX|>Qng^S7uMd@^$)}xDa7sA4r+p$7CNTJ`ZZxIIT`tt+p{{dX&GtL1_D0=*{8WT`~$%)s3azc z)q(O!jUt>v`B>O=F7R`)6=xyWg%pb;t#(PeD_w)4yXL{fM~xQdJz#+Y|HtdjyYvnJ z!{cNkZso}Da{M(T*0sx|wsf)dMOE$GGrm)mMuWvBF2bVn3hBv551dtfnL1pLd)D7$oc#Z!sY3 zgo^DD%(l?$C!7x5xs-UJp4x|2Nel@l5rmw5aAgDj&r3Ta7uywnD|Y$eG_!f~XzP&e zV+iWIBWiTRO&pN7Pi-n~E+tk}MGR|6xUSOAZrV;9tZlKLW4;TEY`-vbh}^TA)OH?_do zalO&m|7-Dw4c*X=GAWFgKX#;I+Sj2`v(dgu)o~Vir)L@|sx*wd-`Q~Bb34!XsZB85 z>;r;$G@G85R46CWBqMr$)^{hZ$oA3LYzXQ+h6+=OMP33txfy57Dkz{f;VUY? zA?~$RHzW?mf`x$bPctGMP$FJ8U8b*{oH40y9x30)*z#QkUH_e6vv|DM^OVg?46y#N zdEa7Zz^r0IWBoLuek#Li+;pCAaC6&>!ow7g&MPoy*%_HL<5*RA_37{jtDSYZ-E! ztpy0-);g{>&`i1m6E7fTC)romblY^5=mjJ<7t%MNxqQu`#i$#|RG-sx8Hc&oe3SbY zn(Sho18tt5>^FNb^p|3HzpS2G%{2MVL` zkrBP-G@dloI`l%r1wna)>a-&)HjSb>jSa<|nP<7g`f=)6CWI;#w`8Hxmo1Qta3SZ6 zTtM7wmDie=)he3yk4t`2K}nJ(4njOb{8uY2E3RRS8EA#4>8%b({Jz&Aw=121u!@md z$Vo_b>`PiC{S|GZzX$rd2_tNH&0EV*x_K0#@!niHy+GMZfx}>+8S~?%k)(qJzsQD-=s%+X& zm)LwSxz%FIYWuahG)sU1cNm6D6cH)O)U5-&sH^Uc)VZdY$P1e^Bb;A$=+EQgMIyp! z@kOM= zeH~^#joZ(5=1WqSGrRcBt=pT0=VqZH;-o_1BeOU7x&ONP<*b8cNVWO}sXSALX|H9) z5q7X}IHE4conl?<<5Sb-adBNFFbDOHor&VMziDVUrUp-Op=vF5q!u~*bX-mBJccGA zug`a%5Sr(%f(X;26sCPQ?h}DmV-qC`tPI^IU@TMn*wVDjg_r~WXLARK zvHo`~zqRSTC|sKqH=2maFYw20WTkD2f%}`xP3`mZF8Mp$eEYT0h2vtkkv|9IJrcJ7B0Pcd zGTnhnYC3uK^%H%O62vVUx~o0VoEF|KaAEV=i^Oj6%>H-^LZ!r{3T|#UB~v@fG!aOY z{)jPt#a0pYIi5?ddV?zRb48eTPha~q+2@)0=XZpq_&J<{dW~SFzLB<{wL(srve}!M zWdScw+2%_UX&H};t~@4>`F)6F%Tb_AQ3BnXdblOWweJ8ZCijmoLIfd?TO|l7?k6XE zYumT--;r=n7tV#)H{YUXj%g5nmo0l9{bI5CP$h$>mANqk&calN!Ryy(hf5AoC@=6U%=r#I=B>!i#f9j39vV+d=vv5k zQjQ%_DMZrH@AH1Ll*GF&f9zx^E+fix>`HS>Lt~D0dqWC&W9Gv1C8i!v3@)Yj0X4*b zD@fyk*;xmx#N4!%bkl~5ih~xiM>e&AcajzB(GDKKEufp*4ir(HcMyR~1|If+Q!sUC z5&O!sjoV#zc-A{kd}9WeI{J8z@p(58&ckO$Y|u^<`Ep4cqQ^)yiNU-2+8`?#`}YVR zyES&vH7oOazhKS9^0LSSPv;QZ;;F1WIgyKWOBpCfW8&|0hPWva<<`li(vml@tu! z*PScCC)%kI9l|}}qw^#P#e*wst!j)#*dm+9YV=w5S=UJoe_=N7#0U4amXg9Eckm2^ zlqwxF@|QC&9$Eg8A|l{xcKUo0<@zvDHyrgfItQ7W-UWvg?g8z=7%`(YV%e>d{B^8^TGdc3BXwt$&HsZ{X{d=L5^AuC zTSy(C(1F{QUK^f4*tG!9-@`eep78OF{OeO~ib15nvp_nuhNg*!@4+@(I--Kh=Vz3g zOMgI1-F<9)!Vc3$f;?p=MwW8@&<~z5$8x%Ck}p22-e_CvygnXdWc@T9E8^XyW(7@? zmr;J4W+5}+tZ;MGd1IBF%9K>026q_>uu2VoLp=DVJ|wBu1HQ<<07RM7>a*-OPh@Z7 zs6)E z@f){7)(2NY*^o3Av=asB%uJFO*r(MhA!|=Z#J6Wc$Ad@tMRp8x%-n(`iYs@o6i-AOjeI@ z^1U663}?U1@2}^c{7}%=Ly$S3JOArM50gPytmc4r(^F@)*h5mq98gK#Re~o8b0oNo zqVs`S3MOulSB99fUt_yEn<2Z2_*e|xxb%77!GJ$RR@O>ViKfL zH!;*_P-f9mFNAJl$kmzaCG3v9mxP~ppzN+7$g#CnAr&#rFz0|ymZJvn$Z-@Mrk=`j z$QD5~y@u`n`3d#?5@DbDWs_;ngy0M>b3joQgrAEjPcY+JzB&g)oKZMv)8~MmeL+za z(Clo5*s%kX^;D+#QY3bm3)?K9*yG74-=@mUP(Qxx@A5L`O+pOh5AiXw>zU8Bvt5@{ z><1u^;J11}0(`0CPG2S4^W97`j~}W!z+`v!2-b>BKc?cI*H0~`q(QOYQ}z$=?+pWs zt+2DckXlS!eWk+k7t8~+%V>u(6V^sMabXd2-EH=}-@JI*{`g0HA$pzU}cR1fkWX`Rm6vsN#l5@^WR>_?kB{3DzFZ2rH-G*)PstunlcSk}FgE6)Y;j+$Pl#nlcLgl-v> zD4T}fw|bwmYw_{8p_sBY0;4dwOFRkr|BUr${_kTwg6_||Cmui&eOZ66p9ZnExpDR< zEXzq<;DBm%Xu%wig{BCN$^E@5j-d<3azJD6k^`ewQrDx{XAMU~hh5mbQA@btD>9KP zXPI_@Q6(HbWISU3= z3ArTX#KUQQm0~}ENR_)cCZE5)dQ%{=$0qvbjft;6@P9a;-kxXO-L*Mlm>Lh^YOi8D zRqn9Pq83XeyZeX7KZzsxh%Qj zb4@7f%6*jRXW{4bwpsX1z+pGpaS#?_6ZrXOTtAq0?MRUuEyo5)U4dD@rN$h+zgzMP z7|NUB;?IKw)6D%LWPDd==^eg0Uh@lWweLvrj=F!14ZQq4nYfPnNaR6e|qd zmX={pnF)sZ>kS?VH$7Uoldt+L%w=YEMU?q>I=5!}IiLdU5|}M+;KBiAiE!Cj>GUC! z(ZvCg?xBv(v62`n?L7a}rRP!q{X#*y8l__&rAMH;F97nQ6fQ3Q!5cVj!2x+mLi@zi znbNQn^CeB1SG01Q!l+8BK<6H*q1vx(Rrgg5HJ~Hlw#bF(zbuhNReBrv&C)Jx3ye3; zK-L{VJt-UIn9k!70}5J&_8{Pxu35}`Cnu+}67Po@;eSz3!)_y-g#1iJT<0dQ-y)1< zv|rBl??ttdA)721OXu2G$UyoMgqa0S;DG4XZCu4%W?Tjvg~JYAwOH^%F6@yb_&nEA z=K=vu2;17Ak^`Ds3!X5OPB)BN4LrjQVj9|S=w{!<~zSZQc}YFpqb-i zX4SZRz`TjZi={o5z?vd`p35JTk;51&GzS(twNUT2lU%26El$%Ts#)@Z8$aoD~Mno8v?0;Cgkbg*6Ox+A*^UrZW8TN>CT)Y`tg0d?E zMI2TyaYdNSS;b$&Ll30h#RQTeMn~X581s@52PAI;%yK{v13Lp*c7`JOZ-64(l%n!$ z8tI17od`&`JAMx$h}#&x{fqmxLl*ymQ13!t5yaT%XOXk02A=5po%or@1Ts|68*`#V z6rT3Y9XP+vK07IKd&=-KfH!}`9wHAlGaX9&*cZq2)o`<}@Mm2Me-kwf%toBsiTjzIzeahZfa^O<;So0PQH3{*2dTugrKWcIhgm2{y4(Z27GWTGVUMV|Yx+L|Lb$ zU#QqrnWz=Me(B4H{d9|>hXpzt>Bw*xPJe-<#k{b`=B=c4lf7Od1rZv+LAhTC1V|^p zkn5a3J6Zy8wcg!CTiV&?kSu4nsEzFYe=0&M4FUp+Q&bu@w6YqXZZ8A{oxhbE@(^xg z&~?8u9v_`_{To)H;ZcpYk9ODTT|`aAPfA0*P2dNKV)dM$(ZF&p!6Bj+D`C6I&{-Sy zXSrm^ewOYEY2-+18AcZ~-xGnP7-El}PVKA)v8!R#DCXN8iWdj;xR{~G0c{jeU!e3> z!MmEnT&|wXg@SA>MkV3b8h_bipBDJw$ChHXL7vPh_G|{Tn!#J9H1Y=B?_-i0EE!4; zk8dz{b9o?lsN0*l+<|+t;Uv@87Hj+1#2OVgfaP5lb1j=qXFyJ-xhOlICoge80rh0& z=$t?-gamuD`$vQkcwK{ww!e)w42!aPO&RJYl|6J0XhsWiQ6ul_yzQeb0|7f=igt3N z%fX(_$J*Tp`})!8#*Tjx7$rxYSIw2{aojdR+Qmj=4wqs+WFPs6u4HTfuV*r!G0aO! z&#`X5Mqhhhq&$i>r6BaE)+2Vi>3$}q98lL=s?xWV@R<)zXv>!Ifv00nlKOx9uW$81 z>^Ggh=5f{G?Zx^wsQ|LU&SyGU9{IvD0n!bF3}a?^m_os9t5C)z)U-N*8?xD6yCc+j z4rt)kI}T_H;F7^|FAZplJC@3I`H#L)jbQ=yX$-@q7w=+mVkR|#39eipQK&X=7jOVP z78B>hS7vUPr{AITUTJ!q)Y2OiXn#_i42~E zbtZNyuQa!gG3f{U#&L%%F3arnj+p<|xi)EeY}}a|M*u@F2GXnGK0lpAltau>aSNvq z8v5VR$s%N!5D*D#QsT3?n9Y0tvyAD(MA}!wT$#MFB)2*Jj%bDF7Lz?hQx0f0J!*1B zW8>)m<%;AHrleB%1Ffwc>a&^OQ&CmFLk_x6;LWMS@ zM5t47TOCRW!C#82q5&$3xI_$)t7%6GnM-D6%*z0%s+pMuS8qe*_VLOaA+2vq#v5LM z-5cwx8wq3CyCe6AAsmp)Ywcj3yiVIPt=QhtsAPRxYrnK@*Ua}bHYGXFEX;03`Ik8j z-fSMXnR?v90li~|F!{JlCjqjU1G%u}|DJ|TK?E@j;aL{dBLxT-s%)Lo+cxWSAx$)B zH^B5KeWy$uz705-T@V&_2`Z@ zoFT4;JZ>~ShU`J^{H$R`bAA4>a8{*g7v+VS87J+QjRmUs=X7#FLK5BK!QD?sXO#&4Xsa{#< z%vXlc&aHz)27xp}_G9y5xap8hMN|Gm-Z{a12nZQ+8NitXTB0+NX&?}z5jk*RaEBD0 zTJglPy5myQWWaRQ0qP7q)ilwXh`4z;Hn(vc?Cm^>DW7-k%l2Ge*vOUX302Duefqrt zTtzAnYk6a)+G7=n&g=CN{}+A3*Lf7JFLS>AXN!;RYD*-(7d*23;!X9h(X1Q%TuZpJ zIm3h92cw&)FR=7{4*;+*>NA5Yb*kT?)>XBA5zh|1sG+~kWN|P2!2bS=!cZUwywpl$ zYuCaqbQyC%h8>3$OhFe@3-(MXCX5^KbUKk$W+=!WHoQ1t(|w3K*TBHNu<5CtHZL_I z;rZ5d4U5UB3x301!p6!a<869{zSiHJErNXhpkwKZyn#ygnK(BzDhG%KubW{rrVMY*=F{$NJL?s%c-kauyoj=O8kN}1NCgIOw6#Iz%W%=ACO%p#IBXF`T{H~&HTv&|vGxQWCkrvGg6@bnhEtdyx+-;~g2{iK)bn!GhTxUYn3^@Jv6Qm(>!| ziU$GQI{lX-mc+n$lptJ4zex6j_=vQL!$0@VcyTow2P zIf>w*?QFeZT!r5T#~?2Q9=tSIFC<3yL=(>^q%76O&BbLi|0*><`FXHR)2q;dl%jFXkX-qV%Pl_3&aGg$l$MZvCH|_6C2vN?zdkwLPO{GkYEV&lBm7l7#jeK3iM7h_oolN-jyK zY!#HTyTj1-Q}o8E$>82lujhgM6UASYrDMr6WQ}ZI(i>BU1joEb$;5v@e~OBN4fCr2 zPe8E0&-e~&W=EFP`y5L>2dubEqqC1dweT0PCDyw+z<_bjav#ydZ1-Z%U@FQvmORD* zK|iLA?M}iy+f5&4&y(e^X2}alCy!=MI0_mz>I>z6Rn2`66O>{5VNzDp*KEB~x5V%N zmKG!2{+EVYe9QG$oyk=a-6lBHZWr!qc|jJE5^tV#}eP)&lOZ z&gOXu@XH?CSV^0Lq;C71l&i{S=W(~6`N)J3A5yX?LB$%^8#B`_Hd@q<;Q!OcK7oum zlG}qE)4(i)d-Hhe@-B0fHHGT*ewWVX4P|&_KDI`ReJ@kED+BB65HWF0LR2LUb{EPk zJmVEPlH)ex&m0gJ&+uG{ZegqA!wfoL3G4~t=TjE{k9=m#ppNbXSb5P_>B+!vR4uDX zWrQA<`52g{;z&k^uWwX7>}dN&VPA#s+@i)z*7$hpSKoRbTym?zfO4VE;*7(&Pj5_b zcrW)WLj)vvYdIQN8@O$9%muQHrx$sSW;*epZM-4*wo|}W zbk`fFM6VbR?;Yuk!OGKxY>j-H#gjcgb3Pkh=-IM|*W4^cJT-s#5V3>A!t|#8Uj9n`A5MFoYB1?cx_5w^5mN!oMr)O zPS1VZpW?0*Ft+<;`o|sokG9^2PCfsAvi_^%ApxEK_~4nVN1s)(W&NDk=+E+>g+n^G zEf~pqRYn2XHMd<;=p9)Q5pKT+G+=bg6#Be{1N{x_gG$IUV$OM;zQA8UG+j8;?cdHC zi4KJ;VZz2&OiSjfz6~ueN8yPC!8!>;*R#Clg#m482WCYs9MGpX*e28x|$Fo|$t4K3~K6t>ufQ$JPr)FK)I@Eq`NiK_H472EUQhKAI?T)WcMfjmd0> z*UUTQFkp$AFR}TNWGMSFy?e$a7I_T_w-j!9o?U`2fy27k*J{U=^fwcS|Agagc0Hnu zTQixKkRe}FQm}K-vuJsijo=ue&ULr!_OqtxjB?wk^jd3r(EQy5+Kl-qJ8tukDS~02 zI$Fd7^8V;oOs^vNAzK8}4~rAmn2N0zxG?8Ej0gOBI?lBaXYFBp@Ft5_8$(vHk}6g$ z6M_4ZF!N@gkl8#hdzVTryVz~@`lG5#WanmKoS7}ME*dXm9YSnYuqiDZ+L9l@iVlm2 zXb(7>sn&m(Y#uKqh5D5s|7L%IQT;*}VmqYQ=5Mg73=QFWy_hph4b(||DZ&7-!@^U> zP!hKuXg9O_X#zNy~%A?|MUAFLR;Wm zd#rP&a|TVY%(DIwt4N{D_(S@{URmUiuZQ6i^Q(FUw~@W;|Ip@ zYbKHXqeBc3rmgm)Y6(5V&&F?4Yv`}+mFNEz`<;2` zn+nFfKFcA?9DfcT*>x;aB>Un~^+HN*_S-heOI^{IHWr^RIjdR>Iy%i*`Y1M09ye#N z^AdByUT@xBHw|do=Yak}*)345!GP>YCpTYJx-8^A!GuC3O*-ARs1^roJhh2j72|ml zTLD+JnkcM~a;|S4tqQ2{Z!;pL3f{r4Z&rEVTv)IDF;ueNl%-ph6Y0VKiFtT!B*;lh z)~?i8!^h4{J4t^w$+u7IsjsQl>3^T0rMDF2O|=I!ldfp-gqBBEt?r2wbD2UptiB>& zwW)5B;4AR55hXDE*#$4O9wCt0pmMPollvd@z(riUirJ`4v*yvix8zdEuPt6DcgyYI zc09=!c&4>35iV@H+%*gFFr!aTSZ7osJ9=9~)&jSdm{lB*$_V>6mIbmCRx3bRX8ex$ z6FMEd*hj$nN&Q*V6h)Tn$=UL-`Su7XATvgUTwT}gk=iuN#FDpx>N^5ok2OZ(5VEfZ z)D!g#&iNb8Y;ZufaSnu5CPVv6&2-;2#vKt}lt4~B=U$S1WxIkh(-*ed~KH<*TSM>rSK8A9B zj+(WbiY0(kRbCr{D#5zMnfXqpf2pGqpB<9mZJ%cm|~NSk1`rM zw?^_SpPP{AwWdb5RpxEU*{f#O8Mz)qd1h4+GM-1r7#&pSAh<~`rsF*Fiz!0_fVtGS z0L_fsu5gqMEjHaxO=5=^Ax34lwftyl*!%lb{YM%$p-l%11e(?7;^|p&{!3zpcJCU#jmX~tN8RfRC@&owT0Cc#Qu_#(?+JA-1KEMNUOkrU< z7r$aJuPK7OnM~CDEcF*6SwlCMG_wvs;Z_b~ktww2t zzgm%Sb1`pmk%XBwr_Fmye?LZ+d4*%=VBeuYn6OCFK;5aSlDtdy=PC+xLxt;nsW{_` zfSjbvC7BR5(b-3%FDDvb=LRuG$w=vOJGdl?eSv>XT5Ioltw{XZ#hKQcOq5D66QyD86HWXN`!s-KlFj_32@u^GsjT zx^2<&vd&=cSmdU~$E_XbolrLy$JQg~{vA2WuThHkSZQ2OQ>O`im=hg}fJYaszORAi zzCC3BYfjN?DgJT)${o+K8{3uj{3@Mc=Ug{*Q(uJ;PAeCb&wI}_Vz^M#b-(3nS?MNf zRx@eFGxp7{4qoK3PONU03cq#9@7f_tvBky}Ic63*gSdJRdpn(n#bS4+cl%VAk$YLz zIC)bI`0S&1Olef7k-h}u8p428X($Jmqf1XQ&B>`Rkz#F8<~36qTVYc@$DUIOSI zx7v8gr~H-hp%~D*Xsv7_iRI#mwj+kxVBLL#Hd|KE;UybrSk)6Es~I45oo!tS(QHFAKv^8hf@hP?Xu6uq3oMMX)RBk)vIzQE>Y3ac)xWIpySuGKW>TgcUl+mVi8hHgjIe@=jSD;c)l^2e3?U7F zrNzX__HR25$Z9~lHYGd>t_#<#moBwz(%^Rqp zDcD4(QdcPkj7Kg_J#&uU3x6PW*Q^kK0#Ox~K@Ug<77cnY?tGfpB?d`okJl?ba$Ohi zS-DFZZ-bEiy&T^?)_oGB+2)b~)f@s>r)nzlYP~KLq1mP?Ci|+g_m_N(UX+bThpc?G zi&GDo^Cj4#LNQHPiW1e28)53nrNyZpMozn`2k{Bhjk-rxi5(lio^ zUKhu~n`ZYj@nTB3t{;vba4E{3+sLw6AfRDRe+RqxB4L649uQIa$8g~Wikfcmp7~c) zA9(uV?JI5ED2u7LCW~(E8pWZxr4o}sf1e`n7K`HKj0lz2N?Y}KzO~6o@m_kp zi+u-?eY5G@s&?Ci$I}Mi(MqfFf;+so28*@+P_%i!ZmK=?EH?-7Ex=CphpoZHB{$P% zH_iNbnI`Nzb~vowGw#!t;u5ykK!xr*q3=CiSt?DI~V~Ec*-Rl5cs|i(_P%W ztoWmE7Y3V-VVTBixgRs3gr_OR2vcOC=RP=_dl;hf1>`mLk8-HJ4nC>f_ z=+hs|X|v0yls9>2p84@R#i6!?KG}bK0@c|{*i9ID1*7XAxK%q*NiJswCZm29^rEIJ zRM>^%I*KTvW0lWrYi`uYDo19Rz6FLbk`J{}My*7~b;5R`4^W%iiX4!&g2X6W`~dY1 zh=JMro(J9MIacGAN*hFsDM`~}^S+}Nc8bdud#EHDo`gq{!CYY>wN^b4D7lS(j)OCL z<_)NG`;)4ayeFY}J^*hK>2FHj)sVCva*fqXOl;S?FNBoo`{-P+Mlo{gW$3$JpDfgh zG&N4vRWsd!+hP^_4wGCZ(=r14?KHGjA9w8RLAVvU$ZZwWTc{Z@y^&Sk=E1N@cTAqpKK`hH3WbBhEOdSmdP&+E!ogT z7AXC+kB@x#UoJ4OSb*?H*7ANWGgN%^xD`ji-H-MX>nb+2^DS~+x;|`KG(j#FGg6#! zXdf>x6cK}2WHW{r09h1MaQxn{Z+im^YzaU5IzXVd`NB@B`@?#r#J;IZT5lmGn0n3r z%H*-l{ti7FAz^>#Y;UP=#M!*(@NDCB&q7&rv7f(R6bA-X8iTyU;jO$D&Uy&2{YAN`?y0DeM(XJf!u+0b?P}Wd9b!o_RKkUd2MQ z)tDz5Xb<6*;A9AY=m^huV9?-(A9W22tKoodOPVYaqLexU*Aj5d}X(w*8Kc=ZL zg#(xH(d?4|mTVkHGr3Q5=yKyDw;5jkrY^w&ot>VZ-pp5}twvuPU9Ket9`G(VH(@?C ziQ+@*Za^;-oH0Mwc6Nu6Vw5{R@@J-M$Qo2Y9R7~rr;ilhk4$nFCuk|pDIko#CC`xp1#{|Q(I!JZ57fSy78}_ccS0IBcQd_2Jaxd&jrimmu^3*z>1W`=P3oC!#FQ4;A*u2WWCYDq&8|Y+NY`m3paG@Y?$ zFJ`@tyx5bF`m?PJJLDKfoXbB`gIqCi+6n{MN`bQ`~ z{PEP?Zyq17h0xZA)RyPs+5ZexKOLfKyPlU^iY+`H;1WEnNX%=AG)u8*vhn*Gl2qhcF0d4qm0nR)D_4EA~4rr5!+MiHM!S<`ze1a^NVyJfoUO}if zH~{ftaVNgTtLxV>08(BP^Rg~BaX&{-Ky=NyH?zeBh=NibdLd^WH|)hTQ|bz5{jMI~ zn%LT*9OS8)(FAp~GRaEU*ECyD0k?WSw!KnLcGa)BD84gmoSR!_sWgAKN-98E`CL#v zc|56DAnZO`FY|U`Y_hw`@i!(EaQJmx6A|1@%lrqJWmq8OMv+q8FZ`8DIiS<~_=|8% zpL15urG&#Qdm(t!U(}TNf(5r8srgykk2yV>$A~ngpDo5E)j48ptPuHvkTrVZ>BV?^ zpIz2N+p@8w%0hHqp6Re0F5&(&=V0SQXWh*rH|Ex_2|?{07nmA=JVT5HobiOhytV_Sf91pW$ zptt}mx{0a<_d>p>ljKs^ya;(fV{s&r%|~6yp{_3V_D3@XNO_|Dqf8U(K}<(psb9YQ zq|%l|kM2LTgXBzfQV7dz)4HX;t%;aFDEeyCv}0U-XHdIQCkw36Gur!5)$Zwpmja++ zU1@4X7Y?wB(Qf+Oo*0mxkl@p|y zWPK=g$qopniT1QCBs~H=mnxs_bh0l~Pgauojx^j%{-SQ}>&kFIaR(!(I$wl7XZ<;|R_VpRUXVn2t6TyM2RC~${Hs7vAwn5I zktLx$_EW!eKs`uF+IhANEx$k+UF^*P`HgZwBrtn~%1U`VGvwhk5l}*?KGoPXZz4j| zY+*Ab>TIQiJ% zimN~q=FG;|!V8z19OAy~;zg4CKQ`RfMwJ^wjdU9n#&9xH+qpi<0rO)9gYWZxv^Xzt zN&OuFjh{IC@B82XfeuUmnBf>rT%Q>LG@8zNBM&1bnx*oHdo#nn3n&o7N!m1D5ox&9K zu+;a>!C4FJ2i`{?%%*W`NQePH*K>MsK*1KSgiosmnm{_^3S6(}BFRt`y~qzG6l>7j zKjw$(@g~mM;-Vi2I@~89WJ$CYj6_)n%NkOw=9tjH& zrWlOP`v(P@!Zn1yb~QfnsY~m7o5ITl@YBb$9MFp{@wIt@uC_@mZ*Nv^XZgn@;A@S!MaN|VJxXR}reB%n2T}8>qZ}`iL*WQ@uc)f^x zY_X|g-|}SBtkm@STqn!w*QLIP-J0PUkc1In&q)GZf=o%SZh-Ouq8vdnjM*bG7pb|iF`AX}JL$*Zq;9re4hM9Lnx3vn0-txiulqF(U+xz* zJfA?R(=fd^CjV^PylreZRl{nml;IGkjS2~=0+^Qwe-A1R{gH;YsSukrLn}82Drb3L z_2s>8lT>uYoYa<)<$caiORh|K?Pra7;DkGP1PmzRnNp*S2MBpqodGX12$)`kaH))6 zUx?~Ov5Jp5I}bSwU%X9&q;}Y`1t&|0b^1DGu73H#lHOe}Ddx$Scc4OF0(6O}v+xM( z$qbU^B>Ha`Tx%h%!ai}R!O2ZUd3TNS#_n}zo%}I7R=Jzo(z1@CvfuWEb@JY1uu`3Q z(fxPLnSnL_&Fpr_r)j3>lSRz4uEWS~9jHGaUd&&c3S-^|0x6JZF}&k0H^kVdX~Bf6 z>gzo%^w}_eIiJU4J2jh*1l^bXj8w?ANkzU3iP9Y;u^zzeUB@=4itvuS-Yen&^AV>0 zw3o_U9hR32**Zt?Ya7fD3c(pid{5t&z|31tu#O@ZW+6h~qo$ccAz@dw*;1*F-6ZK4 zML&Zx4UVv8zv-w#87Z1{LV+lvn}0sL)_M5Q@(r7Jt?}A^DiyrIsPsgk#z>?>nIrG@ z+tG5RYuDDlnyF}UZ;`QdaQc*N5*OLf$Zj5{D>vqUV^zZF$<&BVAu=i94_m5Y98Dm0j*SGfpCkXL*rmB?xjb$s3bQa#U?(y zh1k?QD~fTMQZ_>Cj>S!x>qr>gejMUAQ{|sOruBGr>UL^=u8gysbl7>;4WqA5R{xT4zuJl?Zdq}jm8P<_p;g5P$z&%L8GjYp0Vh2{K&F%)o6`RQn@e(X8 z#o+8X;tjc_A%FX)s`7`m<;WucB=8!1FcTC1Cih+8T#*_72HMQxP5)k4tNhelPVJR@ zjH{0Oi1fdH?ezhr2FWBaOqq9R!2|diU#>4_AT|zD3!fO$gdln z4aWIwfv8*iq_^g`cs0Gr8=L;!}C#bw<{`X^nRdjm_DcO|Hz505x-(Q$@aKxSvwy8)^k5FyI@qfWj|>!O+fP(5ncNet^0TodU^ z?>PzB%nvzC$~H#B9NvwqV479DZmp+zXzt{CD_=hOEtiGwhOwrjLqrVm~T7=B_vU$0+>7JLO<^I(n=10ZRy8#r&mGoWa zIAASbAGfe|61YCjC8K0!Fb(|P+SQ!Ad7=-}yn3M8KrTQY4=7fm#m!kfMi_gQ!c&{) z=XpPBeDrq7sJ?$}H$4gw8+fU3w-mG0OlK1{+<%ECPIh@ay2ni{d z2jp>elk2~w3l2c&Hdrw0I>H`iPk{ck`i9)4Ko6qw&@l4Q@_rekmK&?%$U#-)10+MC z4au%x3u8W9hOv$JeOXB4fq%)6`C>Ze`{=gd|94p?=NASD(36PcKrgjy(KohsC(xJx zgN;{W2K3{Pjv}ZN}3fVF24lBpn6h9N5SkmE=D$}G*2~s%9(YbYP-}GQbi>E~bZaXQuQ!BI>{|~f*o+(D6n)xZ!dO$iwC(cQ zQnYTk-$=F-7d~G;EV@E46H3WOOWdp|&mXI(C3K~*lMRj|yGM~Y@Lz~4zGMz42?_4v zLxi-xZ7~rd98_f10Yd$fSub9o?h{EplI1cdTOXZlU=LD*UJT2&oBZ^?&a^!LS7ZJ} zXfKiADHK7s&N^?Co^`d>-JaXi?DLXK#F_$V#?NAANYsaln@tRNronWVfFFJS5Wqv7 zCOAY$IwoI;5p`YXfT*wF7{g90Wk&DpN-CD+d%NwqVON6o9z8~E0->Q=<*oHCx7KY< z*J6|KobHW~%J#;VBnGvpcWR?8D5tJwU#YVrn+YU^TG_3cRi1AyEtAW$E)!p`iFp#; zpZjZ{Ngn=~Sy&_KJtiL3w9?A~#X}qE4GW`j29nQv=A|c@UJLl7gM`GbFvgSQf~*3U z&aoIR;0c#!)!j`b&85XG|9btW%G7g>3lWExBjZ)Ov|D5^rn=oUwh2Kyf+hVejF(-pNHolg@NQ-)bQe} zO5pC$?RU7A7I>JeN`N!%L`|@dEH%Wi^IKdYk*+9ZZh^jHz4nFq+u2X8zE= zHdb*J4blS>+(ilxMN*1v++nwqzU}ow#Smx8JDYVh)Sb&++}S?@1!}@h1`Pfr}PC>l93UM|8b^&Mdk<)vshA zxWbAINi06n9RGgSnIKCD_kQv)NYdC9{i61KcOjL?qhDv#rCP6A_GR*J~FSJzksh)08pz{X?U^g0UI) zg8Z$UCeu}tnefE%!mKhGyV6zb(u|fp3(_0%VZPaeJ>0(RHv5WPyvetC<6kMENlr5v zCQC-gGmO>@Wy?T=gNElp*A6*0wfgSJGZc{B|3F*t8~fxywf9JoW*859f-N={NT|=N zg&%A?a@7_=>WRtSOS7N9F#jBz{Yi4i{k7@SNi&Yal1_e6-VY7<`0Ns--$x&u?d5OQ zA`|{lL}5#5%(_^*W!FEYc7fy{e&+D_5%n_B9~g*5`kO9AWcL(anu}C0KN2t08y1g0 zp>Gi$sMU#2?C_-V^g)C+n?ET0c6hhqsV5neaB(QoKW@2MGLE&GFdHlA;p8z}PIQ!s z27@0ye1lH>cz(JfKd4Cg;_Kz0w4m^v=*YW87(YcH^lkThq*C14=pbw+fz5ZG;l=(4 zJ!No(J*J%t1$X^gFTUi#juhmD!5Lts48Xx|;;3K0E|0tfCp_p7SVSfe52TB-9Fa3E zE;slT649&LIl4jV6@EnGKiNB15{`SnVk!t7ntGrLIrQy&FR$`LVyT(ik2>X%z`48+ zjGvj0vdU-5tBg!lY#gz5(^DE;De^29+3f_qj{?paq*L)XfR%;OXY<0%fJGHhX-{23 z@iO%mi;hv~iv(huG#7{GfL@AD+G1<`(H%bR23PUs>C~lGjSr77g1r^yz3(ohIVF;n zDb@P7{Q8m3MH1yzt?zz5Q5Jqc((C-v=JM6V_I78%bSM4;BC_^xYi*>@t zJD9W>GgKKEQi@i7f2n8wu1UX)OW&Y~Vz0DcWqK89|b zVj9vy2}Fm6n_7%78og-wpH}?MEx49p3ALqVgnZ8O<;tYqsebzcv`uon0z7j3VNFm# zzqo(k_qy6TpC5SwXz})n`5Yo~dMP@bq0Rwy50kK@9x%^p@o|7moqJDeZoJ<@b8!MD z?1)&k1f&3_u2lI=vBI=wkxrkC%yj)(ob@3W6!Wa8BzEZAmNTBHCgZ%c-N59@q4*Eh z3wAyL>$RiB`>}^Opw%z(N|wBxZqc=+EwOiNvj$^5s<6v#ddM^wH4L{2U4-$w-$(t< z{++1-NYu>FeF$P-oJL%GgSa!T*%B5mRt#yF)C3;^Jovu5mGvPE$y>sH9MJg-vtixc zw;mQlmUpVpQE1t;5KH#p$uvp9p9LvvliXiC3R|8v5jk2nhfLT<4g2<`Cn8T8Tm%;T zkb+(3fT2DQC~Yq}oM)10Od*N*=eqRcYCP2CO!jnek4#U;&(147*a$rPb7P0W_auN% zTxDbP^)qN&$@MhJEG5s?>#33<%axXecAg?#iQ$1Q^FISy<^l`kG8!E`j0Id$Sn8}e z{6Zb915qrY&*Pv4szBWdv6syFbfZO}=G4ePUpuKuUW;k`gr7aDj zuU~8!VDm092hyBt`;Y@Vr*`7|_LJ5+d#Uf}*jRMH=EoX>$Ja=Qwz(42Ti7sw?1pM0 z14)1yaudV22iUp*Fi&Va)ORbk_%tr37e>YPq;JBR7L?Aj6fN^22!V7`D_}kK?v{Dm z$4?%sUEJ3ZGgMprjn96Bq-5pR`0r6i<#ehVFfpm=uZmXXnw9}Z;xb$ zYLVS4b!urMWS97}4)pA|O>tN38%>{>j1;*%@{?QdicR2=?kj0#+>hvw#{tJPP7h6mrmI#;~B(-QxiumB>?^7jvl zSIo3Rk6jAHS{6mA3QXT``|OXs(Bd{Fw}B1(+R+)S_W?1zmY$6d!T>6$O|ED?d>A+v zK!q&o`~~$T9S5#Y3`mNlmrcfq1CA8!REiN%|7zuWRA6?~JiLa2Pu1k2^btIK?{<9} z&g#PBVUeYy8Rhfw);+B;7D@1rDh~q9>a)K8q$uCcy5d7t*t7zhxlKQ7`qr{%g*M8% z^P^yPc8>WH*oED?AJfb3#Z%qDbG~#LD)A+Cy7zz-&%TH_^@$STE=9%>+AXXc5_;(1 zv!-vgJh3YuLv)F&E9Xi`i>!zJj+q}E%6O*jWJ02ra90=Cjc`D`eu9SlbhN&M`H_SNv{^apQTdO9 z+aG?;R32S!ZBeh#6M{(}!^&E!ryk3awNQR|J2m^3mZ|%jn)zV&+Gh1^r4L_m$n(gT z`}+(Z_B2uu83apbpJSDEUHD$iL)}Ydx>vxx%qE*L2~k0v<$wbpk{3W)QRfTk+6MA8 zwd8R4xBLN%XRbt)TdS$+yz}X_Sy2;N`lF7Pc-!ZdPkSwES8cORjee=&pz<%v5tc=l zXRheE@LBxWRlQ{G;E2onNr*c9YwxjL%@UFGNkkATfAB0PX{78yxwDOY5R8G3L_iOlr`Ci|u`R@_=Ed>>%8P*Z=Uwsr> zdu>!CxhVV>z)6YHqd+4_#o(P#TixrpKfDl;YF<9^~^$SR+jRo+LDjE{wFTAk1JWG zNOe`S>ViL@eq)oMxY2$HpoHm%@G~C(Gh}>xml(}4jxG6}1LD(ULCHSplvJVKZ8-7< z%{T?&>K7U5M#TNsP%`9s6fS{jL0uuB zuzLf;j$EC1%;4;dzsu-z)m=Sg^8EQ{fe|+?bR5QZt&YPpwk%Wprd{e^B2Ve2oLuFA z=JFrEZ8OT1u3Uda-oWb(s^=!9tWH&swEtE#fTWYB>h@ds zn+vW{ytCe%r+;$N1!{WRPEALm9r>8&`3|3dyh0y_jb_Z>cygFIGLNDn4XM5K^w<|KaNvKK0qrfPo%5dvhW@C2#B#8Pw^vky7~3<&V+_) z=GFT3OQ}5R932^?CqpON|3_&JV*g!QL;SC_hJ8C$3v!_p-#pC}nq%{cG5q1U1+l~( zaw$;Oj|7Vip!hprl|yw*C~Z>Gst0peT8|N6{%p%~@&Q)ra7Vj2e?;$WOKQCfAw0xi zi|1`?TQh3sLXF&eUpI~HiGJH$EnWN0)F_MVSg{K?J%UWNl->;vQVV@~?(Iir1e9J( zS?y;Pq3o-6=qL_|2Zk_Czu}|>``q5G(?+k( z&^FpdSMJwSrq%cEp+za*tZf|pIiSiCmLT&o2lTv#ef9f+z9>qB1M-H(d0ZuWCMhiu z^@SGk!b}ZZ+oe8%m3QOVXjzJXUEfczF066h)%A#vNnnY^Qv+pu!n-S`9R{8+%6RDh zW0me0d8NVlWbZK2*gX2 znyB?PfnN^tDB^lx~;T9SfT(ZNtsmWVUCOe?coOE6hEZk;~3#)FrS z=n(SvE{T{?6qqf}9-19^ZXgW!gZbbQwzTwT?DK0fik%aiKU9Nk0{!=H0@LJ8WeW8} z_-VfjVeY!WKLz0&jt~F5{DW_B`?xzI@PU!1Vu0u7RQH^^O1R6&PiZx) zaX}TyAvYq^xW;u(Do~r}UMF!^;?~xA-q;5(2X>r}i(F{uF+6(E9u z=BY^Tbr^{e81Ir{+I(WlGpyjY*P2~bq#SANvfA%3;Rl;%EOK&mkSD|XC(qIjqZ_HJ z9aiL`;6C*?CQH*FFAWGXeZ0FRJhaPeJXdUgvkCf{Dk4FidxAA`co>Y;{ref)P{KMn z!egs~6tXKuPy=)^i})A%YDhHmEGsAG6heb`^=oqreO{U7+s7YDiPg2sAm7~0P1r=J zQ0YY1p?j+IGMf(kTQP%MxsSzi#)f>Ms08XB&#@$@!k*43zpoROM&c1_iaIt;P3wc1 z*iE@zn>VVB!OOu@s6^5q(1ka!mdXtl!vygst6E>07PR67RM8#&GK7v*8HOD3wZR#Z^9>un1WTXkIhqO(dBg|Ew zu}<=LN}*05TB zS7qL?Qw@Gcc7KAjKzoM;d#?d=)ONDt=I@$}@K~VoaS63)K(b6Oq;$B}10FtMNAg+wwW!7-B{^uw>jBIfIg z&6~_Q5!Elv9s0fJ6kRniHj*BiZ+BKr>st!f9Lzub)O&o_PRtpafm<70!PEa?bwK?v za{~j9WAs>M`UtjMAir82Q<}^#)6f6M`{E;SC%w}G+ST~rK_6eeeo}V0Hez<9GNc;F zv`-rBzY24m6z%_HNO$(J{%cUF?XskPAwAsRw3S$=RHJB9HZ}WWEGb1cV(4&0blK5v zXSHqL0qkm4G>Rb>L&7(&Z169-d-bE5DpO0w#0a89Q4b9&@`dJSrr|=cgv)A#pqt+i z28g0K*<&>6#XnW_TqabThmjW8$#6Y)s6F<%b*E`Z$Asd0U*R%yDbvxJmR0-MR^{`&ULq6N5zs#7-#w;_`7h7Wppwx4m!1p6pp*xx`v!uSFKDh?X8Bu|W=CGP zzf!F^8&srg-PlsR%xDP^e{=r)Tr{#gQtUk`9VU+VK_yB;2&AXblUf{5JW2qew^ETu zfq{oX1sk~gvfOZ1F*x8GR&*P~EFQ~`PptdwuY2>LlyB(VGlls=4={gPiN3aK%K1-4 ztyRN%?tx0plO^)w4?{A(f12fz?|1e~0|8|BB(gao9s%`6GksVE2BJ(SV(sRc7Nihh zOK98cN$#|9vMckKY$;GkrSX{POrMs^H7|3ypC5txhOH>_{bL}IrkvHOiU7E*;T?@cUjFoUx&w*K_T3JoJzrEKsHJm2Cz-}HuSIBD zhapXhqL{2o_|{3m2+kJ_U*CLr$btCwY^_6nP;TX1`Qs>uRP>y)pXANhi%xzy4mr0C ze~%uK;!Efri-+(T2`kw;#OeBvxzDYi)2ZchuVTc1V_#j;Ofo%zR=I(qt&=gE0@QVL zY8Q497MH&?%K;_q;3b{?XVc>_YKr5#{AVb{2hCT5d-Jh`w=I*E;pQsAmRXiBFTLu= z2$$eW zX1wT#mNslFO*H*50ow=RMaT+&vO11SmeVji+x&=dwx)mWpEYp-*l1*@sy)CHf@Ypqisy59k?}TuN4oUKcywKl2c?wfw1{}kzQ5Y z)7wA;YFOIziQ5hDXbI0}=YRH7q}olVVnl!w+V_K0=1siq!|usT{}t}7|BPqti*g|x zsbXWPVp9_~VS#LR_Ja1P_(}3VcHjDc75^&!Rs5^?SMjgnf3f)O?)dl` zdu_JAf0jb0(qNT3T>%9)3R*^Tw4t6J<>Ah2L=S0TEo9zfV-T zU`=ew%!Fzj>YV$Fbi-B&gW<}S7DgvyZL?Ms%ET+?O!*ZR%7niZn99}9MagAMwd|M% zMc_qZ1P~U0^rD3!nM5ERf+vvoQk&mgsK<0%p}6v1&^lVDC3Ua;ZF{O~n4@;YWJ07P+?Mjg9Z;x1dz!;^Ceb}`v9l5l=?>MbT2czngecUn~6v(PnJ)iE$hw^ zs>Z9t?b1>Qa;$?94q`&j>Mj^4r<#eBW@hWYT+Xm@Ox~Dq)tue_v|YVt`S3qkmK}P1 zLX-pQKc1->g%B{6yaY3d-jM4)on{P;eI)GS zzd!H|{p6NfC-U!5yxRIV2sO_ix!u#tX1O7M+W*(g$`cXGEJQC`NX3c`cS4eC(%EKZ zpA9>@cG=fPn0U-9WREvjG>!6s8M`4I&MUKG~B4im8Y0 zE2n#&_{o^w=h6Gg?&5yNn^VaF>0f|uO$~5B^49+?^>ZZ#HvJJwR-fd6R^k#^2k*Eh zs`~1`+V`*a{i}WdYTy6g+LxzkpwS@+Zg!c|cixXRcwpnzdi>|d^0ar#8Y%aD&*%z# z|H|CpfNq@HYSbGte-j)?X?uz@R$lUz%G$Yihqt%v_geMHQ-T)*@=XcNdp9ei%{Aly zXM7)pdXL{%!Sf(Dsu5Q?ph=twrf?CwF9)w=fB3k?0olJQt31r!kL7^g=0gr1^Q@&a z#Rk|mA`~b?9(f$OGxG#Cf;0s0tBZpfN zCK#sJ@BL19S253<1DX|HHqR-%TB+8AQV&94Ox;yoTUx^#BPMne$hgg~9MB=uRM%O6 z$BfDWF@+2nV2??rA2|?ugNVmzMz9B_wzP(%0(I;@;|K)|1G-5N{mq4WOOV|3womlJ z%D5H(OJAqL;B=B(x988o{w_7%U45GaqG-+u>@6diA4%qO<0-4|-&@lwdsh%@7j7P% zAkUi)VwHLj)IEh25eWp$dxn|b%mFP_a6nijQ)rJ2-n6KJ>(G-~FOcLXOta_RF()Qf zyG|qh{aR4>$JI7|$c=~L71q|y8Po5X(Spulam@1RB@W1##NY9Nf;{nd2J<`6&aPMz z8g4QZ{%KX?ShGR1^Y6J_Xso6CD4lU5KN}MsXyx@{`&Ke<-e8(%W^}~KH)ENYVG+2g zfzwPgYpMjuWO&7JQRb~$KQvC1EyOCo-~Ej$OHqecnoW-O9ig4onQ7*8eX={b(>xJ2 z)ap68G`W;BaymcDXO^g$^FvVWEKZ9ROb$-)(0qs!wEOsOn=sw)EHu<`8M$%uuYg%E zf6L@vij1s)nMUsbSbQq`yOvFPp`YarT4S;4!Kf^OY<~f-aF8QA+wVb|4LpP%mT_u9 z4~KPbimtmta;8{z^+D2M>gf zcSv#R-~$J=&W5oRvGr#Eu5S_#|IaW&<|Q@wcEfm#8bWz0+|AWU(B&RK+{g@aPAo?DiIl|;kOS_}WQNwO)Ah<; z#OXF9*BI3bW!W$Dx_W&FMzG2=%g$p}mbDHLelg|Hl*Jg!fY6)RC#F{q%6|Tie*@0? z&mQS6spf$G(Xi%#Fnpsd#SAX|L;oB6@BYWbzX$)XIrtpVE(fH>&YYc=N2VgEH5QCl+CcW&=<{U0lQ1qs9%^JwhmK?X3r3 zyFnx#6ryI{x{$8jMK&wGgJadOE?-!UpX8e;n%1zPu5%$=887+hJF%V`ewf(*1egL;91Hx|>!)@pO-# znygIpJ@gN>JS4K+Z1wB?n5)yf0zaSr=Yh!WDddvG8xCkXZiSus!5*9jp`?F{rN^Yu zqIQn|uRpH2nr;HP28L4A`cV?tXpfa!7K#*btidTj$1JHk$dl<C>VUix(Ys3LOD2 zTrHpXw4KO9yIZImKK5yw-f7oPI`c?Xb|YRy|1jdgx5W=H%HqooOI2ePk7X;*JGxb8 zU+%{FM%Wx1+!NWwWq%|+L-MN{TtYYlNb1P^HbWgM4$rk3-&MKOFYnHGO;8FW06cTb zdwDP6&rd2?6`!yRB_$2v7hW$}@*JbR>M#&7&z!SQk-y3+y1Hf;fYtT4jj=wmQJ~KO zIVRk~O<_$mU58SQjh|b0CYVmDsT_{`O3#!2SmhZRez)mMT{dB=nxIcl4t=PCejID1 zWOb?aTWO^h@0Dw2W`Y^ZkCK9OEOiidHQMzXJM9t*acJoX*Rh?OlbUsM>yq^-G{2*J zr-jaqi4!Fe{I4gqQjKoHcUa2*4AYCQ?~Y{<$FEd+drBOt1pC_4?DKV+#t ztm-$k(WBFW9#eSF5bNU-C5*rUomiVcLq(&K*}On6MJ)b;TDXc8IpTTOx$kYLzA6>X zuV;2Q4H;_PdoTUkiW{EzmC5?s__?^auZ`Z9bh_YUm+9N&c)H)V$m~+x)4CUE2{R{` z%WaSPu;NclAB`az3$w&DVuSVkOS#G>68*K#V4LDXJ9Z4TYn2Q=iZG@I+f%#JDejIv zF4)mzeO@x^g)U+qOcSY0d{7sbE=&kf$w5_poq3Zq;nu9(WcEfrwL6t&BECjJEiyT0Ra0*|D2v!Grxb?Si{xj8x1{Qb7MPN{=#!fWV}>@o>`%ZP z+8fl7)`i+g~F8 zc60hdNVwEcx8|MgN0!lY>~TO#Sf?yrZ>zE?tm(I@l>FOzPyW7z=6sq;7~gte%#VSQ zsg>hfTBrnrv!A+T04Yk~-e)LT0!XL>7JJz;7r$!eC(sjmm#IzgzhExnS+3W4QZz%o zm50@4LqoHZ|JmOwmPG4cJ#N<;opUyPb)u=G^(}j7HuU^`eDn#&i0H>}F*WXWK%w*< zjgC(-r-0CcOijSQ7GC8 z{2JH8zv6({Y%mZX!N$09Kw7;V(7-T+1|{wK;kUW$NV^E7NFyh??)nl3#9~5d$G2D> zICcQnYo_NzDM7b<_L*sxC3G9Y0g<}7hmCMRQ|riY?~uTL8C#LT zuG3)$qu2^OOhe2;A@UoP1HwONpDE)08IfDBhuoHK8#Ar;ST4a#5|nuh3?#sIFLOX2 zk=&|76xmZ85cSXCbkuJ#kaeVBj3D#YC;WX2sh<46A5D~Wuq)hbi@cXsx07n{X&&aU zd*rFw3#L~E@bW?+xjlcaht#K?|D}O&bUduiVWVx-`+7%sJ6L5S~X*KJRYH3#xVlO;vo}nHzMAgMNjV2fju#%wxc)*Jr zq;fP8^PE*2QVL3zrPcsm3|UG{CaXjyvE8;|65qTdg;8DH5DSe?-pDQ6Xk^tBZ(6BC z)K-{Hg!JP`%DH>5ju)^3DF%WEY2K%L*WIor(gg`~V3&j`TGoEaW|i?Q!v)rn-c%)a z-n_udRdE>E7%++1)mPP+wV@+ky$XHwWGq)xrlW3l)HwVzy8!6}2F~d)RZyR8>4U7- z91uCr;22=Y7LK6%GF>s?&-*baX{6a5MgR(^_GFJF5C7~SDMNQ6**B~SNL29|I4`>n zP9Vb$abxQm<>M$T_+Wskx)>1Zlc&>!u|Y8vt>%Vu3v%;4m|725QYsWk-M!W>C_|6O ze9aBNv9rji-b+Gux>eIVTYMK1HeYhZ9XHtH+W<#zYA;*Db%Ccxtr1>xiw0#X7##UT zqrBsQngX@>f;WZ@IG~Lj$em_91IfH)scJBBoR=pjZ(EE3?HL7eJ3)wa&>3#nruKJO zZ9e*91Y_kEda30Mt&7~ZJ0SQQ5OFOv#-G`X3-r)}B2o_zAz=YG4kvwe9N4w@SLXHOD}0dIXv$+P@#ErzJ@UWAK+7z#EYclR)-$uOHWI>`_B>2}KI-8fI7FPAWo>zF>rr6w9XehNdG?Tp(nOfW z+3CLGGqjb>bCqzEM^ghf*^zkqlWLa$E@1;(bX|!swG?$jvZZv^zVl1{1Rg^#|pm9N^B@lIsByiyLTtsXCQ^Sxqe zlU0}*6tlgD6`X=P?l&pY35{c?fjH`(-I)F*axkx2G6&>~oY@=D?SHvI0?w$)uC;c>0jx*yd)~x0{($2$#|BYU!y4dzsbYDR?pda|Jb zuDoVwQ=>w`l*mejjlUOh!)*RCNAdtO54>skYZZ1nm$}BlDZB9CeSvQ%x>OEw^)fjc z%@*4)-RsdSQY1TW3@t*_W__Rjnm+#`D!tzwOjgK4(!f2s#_5{igkqV@Ze3im>TVsh zXZ~yw2hxfl#`Qd6A*|N^r^b@Z?QW zGrDdkeGTy&%)t8K8dY{N9#g{pfNXwnn`r=?e}n7+E53hn{)!eR)_`|vnfAMX*G1X| z!O=xiwdPi<ab3MAzB)0eA@>%Lc*65niu)~T-nPQs z>WcN&YYac5`K4-i!n$bvKLPVDU7gY3 zvnzjXoTz(*Q?E~7s59yb{KG75ICpTotf?tgbLcLS{_Jw13(b$RY$c$7y(})P;@el{ zSN`@FX)6(kEO{|Y(b;2{+>%XZL;_VXq^ey^U-}`q`ZW8PweNzI8ZZ3O!22flIP`e) zIeiK5GA9?nl>xS+L1M|1n)aW_Ps5hSF{j&GpHbesvWlI2b97R(KSN+b*Pl_m6H+BZ zUT^DbK|RH9+R#I5OwDA5RXvOfEVY{~N}|&l5jzI0RO1)=vNh&Zp8)(*RMQ9KNe-y{ z8sa8HdF?bpk{U`->o!j`ko>>_9c5g*n)2z(`fZ&gwYbXE;IejFc5}#0Vcj)CWNk&w z`llMB;6w9&sIsb13tQd@Q^JLJOrQWe_&x0$MbAIltRqsd{|En^hKB86kBMh z>_a6SPY#Y{+EVbqO@01Fd_wV|V5zU}>rsyzqN%@@JUST$KCv!3e{#AutW&WsN7kwd z)l0Ar${Gc${Hzu`i0;v~nV2P1?{r}8hM2j#WfbUHjX48+M3h4CZT=b8TrUh?` zP|bUF*#)7(wyyq?s+}~oUR{S8uaM)kq2q7eKYz6fzF>P(&c;|)?q!=`CAs7F$4ik` z@x^C--W{9hU2GgVLiy5r_(kQp>*(Vie5XHNy6pd{P+p=xtj0EWQE5;;IVmK=PXm9h z^4Ls;t5LaK)zrs}VJl)jXkN;>ervz4nv~fH2k7`W{QJ;@)Bk?FmN^c606lS^4QACt z{eyYok4LWR^|D1-WidKHsNn>K1G4ul`;HRQx2o{V2|-Tixt@1AZAHKB$k-%5hKl6F zy~#x1v>IjL%fQpi#*h?@T2jk-vEKa{Spf&we3e7_H|7kJR$v=wTYRt#{5T zzQ#=8Ar2@z|5|jztunW=h)gqb!o6XhuYW055~p@!v?Q?McAc}nIS-|62a8ZimhBA}jW-3oL&OYtw%q3&LA43wkjFEtNgrE?NBK%@Z@L#G$IQB1pKG^@h>0J8 zGEFoL-h0Vt+xQOUZSI)A(B@18t+K@4Th+$q*k;-ULC(u)`({4p#Q^wRn7s(8zm@6`QRFcAa9?Yf zz2%w8?H;8_q$sq<>}k~Y0PkpETV7LUR!!ZmJBt@7h@f9df)hfM+a-Jg?s$|^aM~U(N8gzntKDGvAx%fjlLi_TJN;$1qoYe(MKk9(4M)6_^U??j1$nRP7apMZwr-*6lO_&w$g%=eR+&v>gWdlZDYcTKiBPwaJ`WajU>Ok&>~8TJ#n{-Gcuo( zWL;T|o6fnoDT5G%8hptH#z(a+zgKNg=&sP0XuvA^C7u?obUab1D3>BU%=7Hy^8mBG zDYOnuT~2rMR(}!VE4j9<5>og*-s8J>H5}`YBS>b9!B7zHgxDaC2#z8lQ!!73fZ~ zA@C=VESyQ_a|mz|3cRZs5~aKi>7M5xf)chJ?hc1*h07Lql&$HA6X#L*xo0~wdOBco zdsESdCU)|r_fLVn&2#ddnXU=>R|K0g#H`yi1CT-!g}R@YqCjqZzb1Lh(=RB|zGvj; ze3FJ}<+pAC%b<0lC%b{uZx$tboVan!+;-v6|I9{nM9~YCwu)?%Fe#6S?OQ~5@ZSBI zp(9BRqo7IIy-bT@A-v*EMHJl=NIS7O&G!S;r|TFJJ%c6BU#c13IxyzsSUc9M$}9Zp zgE#s8qU`x;<>7;jYWI;RPx600@TrUcrU3mh8ZC~ljS{lV5R?us>&&XN99uj)63P2; zT-sZCWGP0zNpRnYVCXv;)VrDJQAw4htdf)#zQH6Kh-Yew>})B6llN;#`e_8Bh+clHh=%qMNz=!3+pgz#&X6!2YmgIx#NFxZ3#oMlq8Upt_(tvr*HV`wGf z_JXh6rerGusdo+J72RcBvO8evSnFd}rZ2i@9T4egwRlmlwjW{w`+1c2Gl?0HIg{aB z;Wl`G5ega$6KW=9y$N?Hfv)P3RI`X^yjrvhl4P0|=o4Dv{i3}94?ndwDSC~+f#3Qw zGA0gUJ!;$eN2Xr|z5$)HNKz@YskBb3)UWj!MX`%>r_(Bg19O*+A}=|pm-O4@Yd$$A zrPd6|C zof?I3Z1n!Ns1T%@+N?`&oC1E=@$Q`P1 zOD5z+L;tZm;w9WmJ^^&TfFv88Qci)}eGhl3G$cT{pccJ4XNX`d=UE6e^VR|-9>_-N zzcq2-B=7iu0NU2RGT6DjO^ELEx>g;1)2&sDA;(}d+;s`_WepC+<3#5r85G%J(`}ySlu)W>%kM-tY zHlN~kVV#T;hpBZ<@r2@;D>LiUI&axpwOV=Kz`_38(V%gMO6Ur?}$5XQ+zfI*Qa#%4!8}4S0?YoN{!u{Q=gF zoHmK-L89iSrf|4f#5VYXXT7FP%)usfH)Jzz$JNQeD0;-Fo3{C7_YWjtP%Jj+`ef`4 zs!T^KFsd+#ptVyWHBouiI$FF|(#2~WrJn>MKjD|Fm$>Ns6!|(*>g#uGUxgG1F;s)w zg5t}}x{QUAdj>6uwO6JS0s|A$XDy3p8-JOV@aE3=WJ{@r8~6xNMZ`$ne3PzYaChKT z{YBhCsg^>R55CfTW$;W#{QQGsgI-obs7ckZ(?-t@zw4#H>)+d-WdIz@8i3>TK~ zVCA$j?E2*SOn59i_;Tc`Y28R6 zl+o*Ca6weV%ZW=@Ahm$clU;2s5Q z)+aspDV3O#s|uczrr*p7+cX|fJyUP!2VxDpw0 z+Q3&ceZ`+1p8FkTp0lnpWfFWom?jiyfBK)^w(mctHDi{3f}Z%FXr@dvv9-n}plF-K zFuDma3PJXRiZK9oxu57^gP5hD9QcnRAOlcl1=oQM@L-d(&tx>Jp{5b>}8_)Y>;Y4`?@a&p6yFoi}Tb|vAO!|hB{KP&u zZV5}(;RwjM=c=WBth4kkd_G~N)4gd$?DTd0Gat>DDs_EMy(f=5RU4)0^yMA zTvm1~+uMe^dbIi=si&AZTH^9GjSai9k6J`<>sBvx6Nh-W^wJpX4 zv~xBj)}Q~VR{4$o1kqqa&0pPSQWg)h6J7Ym3@HTO2IGW(EhN^^2ZsKDZz^R1hn`PT zlY{(EgcccqL+P@;Hdx~G|HN{aU$w0qHuT%sDKw}vd|fN!0R>N&qrp&b|2>hICZ6 zsqepZm>z9w)8En%Q6urQVOT!ahLvKsILX~F*R?|YdPBq6)k3D*@D9hj(Jr_52OAHo zxr0&H40ujUTZxp8r(8#>Y^2=WK^Hv99)}r4B ziPKi9pt!0&gT2a8`M+T>bOPvZzF1CgAo!KWj!g>cq;CvrBP618+RA_aL9`uqR_soi z_0H#Go6M^07gZT)q-3EmEr|;*n-=!^wv8H=4LPW&9wP?eC)fH|@;>F@Ic~Zw3a}rRNbU+JBw#Sre<?G%zN30`z$3E6PMt;8X zT=p{Y$VKolJkq{5K;k8Z+NJVg{Qf0V`RMtN>pT^ft5otEBV#Ng7Nk4q^v zD8o8QiMJ$YrJv7ZE?AW4+nYT6FowL8>uVa#syvar=i_9tdF09f{PCSuh4GZ1s<}tO zohZ=10&7f5PVR-x^WHF7 zA}q~AX3Aj(=WSy{n4dY8@7-mGN~8p8i4i#Ca^W!xIu|i+gK}Pq$EVnJ)2V@fms=s%7RS zCelV$yw73cd9&ps@y`su_VphEnGX9pi|LJq7`HBuMc_;qnRWO8^G3<(wtppbb-^0V zk5qfJz3ca9Lv8y62O0~Hr;DB+?aO>%ONntJ-nCCU9IvZuFFQS)Jh6I&<6Pi;nSUkB z5#50iBH1QOCut0^GVLmC3tdS=nubW5b(X*9yVq^>n@DLGnZ4)q#sGlCn- zT_K3nkJq#&b9L0GZ$2z4S}RjdFL|Oboxhu*&-`FmRGgne-d#ZVq(n0Swenq@tl*ycEu!>`-!aQn>@FTUyz|&<9@ZZT&Q=aWo_k_~7;G{qckTBI6tm-3h|9+ngwP zPmMnyKjI7Z&U+$;dqLW5YS04mSRBqQ}iZQFUlL^SX{ntSpva&;)VUu*DW_RU?64eXouT75qH-_6!N+_3x|V1TN5gtAcqa(W0DR|UCgu*`T?Rl1jrvt#LNK6R z++mU*tc4B(uyU$!Lw)!7R5u*2?N7f2!ULIMaE*o8aiN|WMH7b^fD1#|lw-A7f9Af$ z5e&e$-ws7WX}=LL#C)c*{S!z`*<=6?PW`GMaR_4odOZK_F#yNOH|Z})5DM6V0r-oP zV!#v-$GLKQn^0BC?i zIF)~%0U%|A2tt&%41oR#GnbNhhcHJkbqbRifDc+Wbe;(YVCfW{iw38^e1V~}`NJs# zKoUEZ$?OUvm^pwF?}4L!0h;x~zl+K+0IZwvz26vsvvdsec-jzV2y4Jl-BT#hu&eOl z_C+{VPidF_kh63Vv&P9}laYs*BLH&)XZHLc$^`fI434g3K)nOv2Cd-&G4w0%nV{WZ z84JW6u*5TU{|g-T<-ajQA^kEU4tU_-h+_b_?w>FK?@s+6Zv);s`SZ|d6HOY=?Fpy( zzI84h<97FFo>$M6fBfC<-CqDe>OFvaxu_83FC>sMN%bemA0d@?Ht8S!APR1R$Xd=r zbQdPpEUEBLzD4G6L8 zT&4$dAO+1~hILIQmRHP}h|FLi$A3b9P21@B^B06CAf`gPWs9MT|C7&Lc2;Bn3XHKh z%H?tR5jWGO^H&&v;Zr>rO8hE@=>t;~CIY{AGXQv%f1rMjltnw|EY7sjc_#FKr^B(T zBmsJ?s0tH88|_~Z(ubHq;XA)P({E7!W} zT6yt+L-2?T4!2%rWiRTFxx@kfNF6bJQu+a4c=gpwu=i>=QQ*=;NibjXLi_a&mof?I zcZrbm9)d4;32A9Tl@2WD0u04x(o+r9K8xF4f6S9keD_YzU+Mvhx6R@8z17X7!H56; zvFreSh6$k}oO$0e6Pe+*Pb#Jd(}_{_;%J92h19)r`Pa3FhXz~BTT!CvM1%pD8iNhN zkL#&okX%X^10bH#4LVWNV)}i>p!#~h!dd&(4q8OdRhqm9PskP^ZNn_5;DSO7l9+5IoFV z<(duWS97h;iD*`P!ydEDY~@33BOG3WDzJ*b>w1TX+h#q{q6UAz{#Ld&&$#=Uy_U|O zCx2cvJ9KEX!S6=bIiSX+ou7vQxuEf(iYb(Lv#&k_^AJ1{Z0ea{p_GMW^#!W0^~R%s zBVR|$PtM~lb6>vBwq z_;G`D2JmNoe<#MCUkKbvcqmb*ftCw{tpYL@r?M_rr?eqMeJ9>3^!5kD`y;3q*4+0^{D z_VAPXjs*E#Vit#eXu4ZM$6`$>esk00sji)z)L_tqR^GhEAoaka8-f+4GB-N$r4NwO z8B%yz;XUIb3DX$m(D8EOXPYq^H`B^8;Q~ZRC*lVWULv;jrVI1NVpZ#rtn-hhYfs{T zHy-e?YMD4Rk=Os6znnE-3_cGH0*?kKM5u_^+v9psI6dxp@8-x!U^MMI6s<}C3qx~G zC0E*ri&QtF>cT*}zrJ@M80c$DnoR=65fpbt&j7AS}oSVnK zc(c6z3-aUt@^+pqqF|Zwf_9Vk_r^w?K1DC*n0+w0pHH$Eyl9 zC;CdXfB=ql<{f(?(em(dgzl;#(LYLdSKx*IbaYhN>{+pV!a@VtW27c4mZJ6r!cD4` zdO$FhT^Mr9ABzIHUVl=$pm@J8%G1KyC`!xJ=e=do)>5hK4dQD0Wm6nir&^b5V~k8> z?x#kr5aN2fpQ(4ox{)jcpcEx+$Yf;P&sscoX>dNo)BhVZ^KS=3(X|(SSxlnOE<)=1 zg$=_r%vOwVN?wm@C&phf(i08%z~4iD2HFHi&WpG?ix8_${T90v0E)qr z6V=e;^hM3uOV({g0Z@%T%Ny^)dUC~ttkQL=?b{6Laaj+`7CsRpAGK9{MA|?5iBzo` z|GAtnqA(@v`)wwI5B4GS|95l|OCRQv)VDRX56^A$KIK|zMN1G7BQaeSD6z7PzMrE(nErq7K~ev6!=O%Wr2Md z4~qNs1oqp(9^^=58AMk40^hI_qls@)c|irgzXUOv)j|RAlL)5XDywtoB9w&?T}E^u zzof8ML7-`P3G7WtIeF!iu>P+HdAd$&c6BvPwe9sR)7VW ztrpMO{yms|JjfqhU>8o0c-uPXf_i}MXG#7tXmz78GAG`*$5hF%O#Vf#hzI|yFl=iy zPzRX6l$LKI>HIZota!xK8*+T~*tH6s8%@o`s^rNsp@@cdF!d_#4?nH1d}eMZ;Fw2G z?HsS~8Z{P6WEq*$$MP#80B#_&< zZ`0o;-=WpFo+h9#(1!}K%@YMgwZ+Mo!3E{(Tt9r&YP_?P(yfDL?JIXuLLve~(73fL zKj}Q+vl|W5wUDX&KS%t7%PL_xDd8G;1XAxDOaf|{=hi5ydK}FiBN*Tw5_?>KZK87| zSv1OSJW^Uyy*$`!w8N|?47im$#9_c8U-7V7Iq*hVf7S}LiaV{ZCZ5mxp?1;o>)r<` z${OyoNKxzYg{3(|UHWu7Ql;OV`whgH>dj1(J5;W*;GhNnAN^k#0A}9wge24DlAR>J zWIJJA9=6GMP1p~NiQf#H)9oayQ=QO5Zeo?Qn&%Vnt1%W1Uij8YW#}`bl#7|S+*}zK6pA`$yWJ;9HPT#EstZ<3WWv<4o}To}APX z^MpJ@QzH^NL;T}1ZxI7v=5w@geCz*;7do6(o3tj7#lL)2o_-190fW02kBMye6^;3a zx;Qyc+SF}F_||Q=p~wE!flhUSJUNeef`?9oDwrZ_ykc^nWu%vGGGWXBxK%kZ0OfLG zI-zlxSt4B(z)%PS)qQqn`VahSZb7JFrIf=V~`2NqgeCR13H|CjDoK7ggT}XaXz>@t%KG`?ub-dZ&XxI7@S2O)7*EpC84QXN zw3dg}NQM{-U>%L$;AgEo^*{Cp96hNiKhQv*v^sgNXgm|;ORY%{I8=CGvUlQ893gvN z2yK4Oio{hQj^0`XPd6SJo)`s!sdC2On7a7a!klGH!795;r`vpoV-XC%I8z@DF!AVd zg&#W53o(1lZtbV&LZkE&AhiK=a%4bdaxj`Bh&qO$x^w>L^f}M-YxxH_UIY`}dlI&t z@0%M6^Cv^5$h+ADpu7h;@u>H0%QI5mk7?B<20)Y2gkPoVwqNZC_(|?1?@lUesRkWl zwwP{)@i_wV(Uq}G{t;nXM#Oo-g>!EU z6&7q(=Vc#M#t~82Syj>8O&csUq9<6=tT?yas?sJ#NjiAFQ^w9TDBYE}&bR1=hE^dv zPC7k1(e?d9H}L}_89u{$+~bTXdio)q1@XP(pUaC)n?86ti;wy#`*V9XgJXlkKJo7w zO)76{JD4;-c*;-cpiyr=oz%7bl;p8@1YUL%0@TY*531EQ4+DP0`|jZF z6Y=JpRK>f4xzc)_MVHMvp{CM-uTn-a2CvqMi5_^0JKruu1rgbtqa1pOHgB{v z@a`>E*RA|aV~T&g@63Gk(P@GIk!JQmkl!_e){%wX?gfwMBSkYsHBTmi@5)W4cd~nI zD*v9#IPwjX>#+=IbkwG!qYLijz+Lt8WRCar)sFJtI7>DDdiT0geez_3|3$-g&WWRU zb_h1~1q^v&N(~#kE=Rc99pdqvWYZnW-@wKFo5H{!aaXv1lkWO682z)W)1EJ2o)794 zjb=4R#}H56NLrW3$LHBQYGjUuQoLJM1Xo20HFT?kahhjHs3Z1*9l<@_No}M6TVv)64tcbm}!UG2^Z|@ z?Vw*fzD-QG`4r94VR~^f7%4Sofleb@vHQ8jB_fnk?GRjqMXMfZxsTrIVx|hOH~Lfi zH{E}Pe2jK5;F+`mvm-S^PC}4y?TlJ&oH>aB=*0;z03A#^;{{@+4>n*}c)FcAX=zlA zg&7n&>4jQ+2%K%kv!0A&3x@Tr1_!z61!+p`tqHo$_Xj;9(A1Y39j7Y(Ib&xQAPJGwsmxNNXZ zbBNVGHxJ}vr2pQn@$DP$H8=4Kuydm13{}=AeHEo`!p# zTyj{j!TR&}FQ&W_z5bb$5*dtYp~-h2-=tWWjcv*K6}-VdyRmk|`)4M{pQ*A+j>9|W zPB-iO4Hem3a&5hJtQ@Ell(LX4yCD6;Px0@ke=kwpGOhb+?wd%f=c0LQqy=A$t@lCC zjr0t$8GTMjtQOR=DhO03OGm-P=6}ywyy)bV#euL))** zM4X8uIK--4lAgGElj8c_WxUQ;4U8el{?%-peXNC8ckQHVX9k3@&%C1E?g+377dQUv z0SUWLGU{XE5scG`Aq>pyI}68jCt4nb$3Sw<6=>o07I3QRr;QLj`H z6t_yS7?vkA8~bcJeK#$TtBkaH;2-_)RByA|68zDlPn7Ucc`V+;Y>4gM!luizbtGZ- z6Q!BEc*CsBtE0)HblLP-ZisnpX3E;*^o7N+oh{B*k1G+WsPgqjEDAX;5Si{y8LP-v$3?+IkX|#N+xh^Li&|zBdVA9Hi%yKEz z$H>W{tfci@{R&Q6#F50QdXvZwO#1m61`#By<+!FP6H-(9c`b? zc44%0c}LkFYqjirgFKpDa^C7Z1U?<5CBWI2>t(=YaiUu%E!!86CHBT!9v_Wp51ng~ zO?krrxH14g5IyjESwwHx&{=42mnaY9CFb0re0(zjn#y7AKB?TMDs%LB1tOKl3s8!U0{@IM?^2k zCx@VRDMld!Acwu4S6*SIc9|zSsPX}cAB5`RU<8+Pb7Ii?i=d4c8OZI*>YNB!#aSJ- zI21E1MLULd&tB?iN(!%uQy-P+G@}o8Om^%?JgXGuGhgj;DFpgR|7f-TO+T_A7A>NE zF1_4R+T*)<)%wF~+e95ZLerH+k}_f{3H{ti)2`ieG{S(&!$N1>$2$d)yM-mT z*+>#(FZviof)vUWq@1nb6Q%GwB!OtE0Rf!I06Zo-*TU;yK#KEGm9LgRzTY9?T}ZzJ zr9vX+>qz!dc-+HpI-w)L9%?@e9x|zZ@lVpJ4XRU@(6i@R&^K=%22$8rSWoWHu+j(e zR+OzYoAh-mq=s0`6H&U3lnlN79vIdAD0lJIO6N%T9zjyKLLsVz_T?_k#Bwo}9-`$>Lg5mC`kx*WI4j)S;wCd-2|Vkam;9B}!jo zg^K!kL0pNnrKEEk^s52)@|irNpez#4^2*bek-!LWe=|K^``1j^T1w=X48U8p`wT#J zHZvfZ*bl&OL|lh2%{|7D?U!-K9|=mU&>UK47AnD0b z1}C@OeoUs<7Gbp+1Vbe}km79|XN{BmgRj>cY-nj#d zaO}0aZy*4W8|PWrcO4aq1|FB}tW9YkabjTt--CxPI?eXtA!nhXopA4l=Cl(<$*Rj^ zDmOPzgsweD#%eUQG$gYn+^ud-usUHEQQSg_b*(h!wr9G<_YyYEknH!1N*^F~H^6Vj zOEipR=TOsz5`02Zgd?QdX$d~wocitRY0$RKLdpd@pXp3y11C4>BM|OZC8An4)4wJ={ZD)0xaH(p zK|YI|F&0j1FiGNkr8puqu-H2@^ul!Kev!>zcT;DyvCp>9D|2_?{=C^ClcrAZmNj}5 zlO1C5)H9-jJ?jQskx!BKNd`jdrm|P(iZaGWCict?JB`fJc~Z+He4iZNr}mL1qjNf7 zs-%=R`3rNHNU9Y9$e}Wv^hiy%!29P52S>qFLu)04Iz_<=J3cmFI}t$dVxTe%9fx(< z9oUi?FC6fJOj)MO`?NqZ$t{QOU*{y|B!1@BJ-qRO^xjxeGeJ0XOn!_EjWa|=*F4ifT(+>dH3{@ns3u3Si6mQBGVEJ)W53tDJFQE zc@^iF*z)}Pd$YLKt1>%67*qzHx8Wa?IKBX`=b9#}wMUq%k zi~pw7>gYgq{?7YQdNk4XFju}N9d)&Gz&yil#H@5H7b%=%Qa^Ut2UGzk zh=G5k(Bu5K%@}}4gHA9V#&?9K-YZE!9GF3w*v z8biJ7b;88}49n8WLBv>!ApwA3CD90(-;6m6p(Z!Uk*O3haaL}qU10D1po#h_Ej4EyQ&8>83tge z(?Ake$(8{FaJPY6$^dkV;UyRV&^Zu6Ps@?{TM1nV>P-@po$3C@0C1gRp74h!%&_WB~R(;aGh{HIT-Qn=WJk z&Za~ns8mS?AdZ(5M30w04=3(oakR56)Vu6C^j9??Do+#xu=4%als=$GpyO+pIs-Zv zkQH=9VIGrPim*!KbrxX;UR)gJ_yQ9FAvM}5cQ{3YjR6=aV4krs3=2OnhI^+_ujp{Y z_lbq{s}|iu$C9lY3_ur#2Y&D;kaR)O|M<)|27qYFlyy1abhtMIKv7S)Lz3?r2&<_!f!z~k$5le4fq^3}`%liez z^^p$C<#Yw;3qh%Iv|)2F$xT0UB;kA#3o~grP`?qVq{0EKJ(P=@GmuUC@@js{qJoWhuhL(wO9hxb2ZwP}- zEz()DNWGoHb)=@clLsXE=vqvq!kUc>n$>Emm?}%jpcQC3M84kGlib-!l>0ObPYQ>t z7-0Q*sUojS%L9i-IN$8wR{?rhOfdi+D}u?AnTi=@-n+2`tv5ez4>XM;rOZnPbIa(V z3D0_5KX1dQYo2HkDz?9>LEd|<+Gn&NKk6{O@wEa}5j+hdi&38AHLNer8IxU@UnWp2 z7O&qJ2o!nh;Hl{!t?cV9ds}q9-Z&rx#6_u~<==2mmAv#}U@YEX6Jg9gt#z8P^Zb2x zUk2v|D(kmK^Pt3Ql4CstB@t(COW|U);B}o-vOkx1^ev3wEeT+ZPT8SjXT_nhK*r#k z(dR}_lWNyJyAHn(Fb^C=`A%T~=xkq4LMe&&DYQ9x9>8FS2y*p7E;D zUB6mRGP&XJ%*w1h)~@~vx2b}6 zU}aKi34d*>_g;h2b0o;4>-`frCOYS^Ot;Q}@)f}b?`YMWPbh}XK)4Q)ENn-W+wSxr zKI5>Eb5QFUv$od*hd8c*Mdsb#Jo`d5TRcSV#T(CK(dx1U+dJQ$)b>w}pL1veevZ)i z^sdz)((b$rM-=vvr<;!0W4lZ@^C+otTdhA7O~pHn1!9-LQx9w_+yywdB|N2n#NY7M zC>$n0zb+pXeVmR~OkWxC&(!H_eU5M&kVLgt%9SAD9Wo4n8#obOjid6R@C}`iWKEs4 zkI=!zgk76MxDsbA6)f#b(-NDqO-WvE zxvr9~pY6v#?WLEMAAFeoNH{7~SFJdlHn#YSX)!&gxmkFJTdPx`_BeJF=L4*zX4MQR zr?Ff5G3fx z<8HWpfCu$0l^M(*Pv|iK<*ib?E||GB_+&QZ_%3(`M7f+ojl~hoF()d_SV>c&-bOF^ z7t2$VwU`;AChHCZVE*~eDkWjD53{8J3m$Z!pS2-?S-t0#XjK>w4%cpB`6w;Oi3xpB zm;rdHbJ2HkO~SGwC!I*v(Ek*v*nADs95Ps_&9gS=DQL#N3FLHwVt zeQwYUJ43bT^%thtbbnjz@Fbc7HM*CMz_Cr*PkOa_m!Y{0r`U%C;`_(hvpBCCC14jl z@#~Y=#fbPkVczAaK$OJ{>UmSK+npO_SrK-Y8Jf_)HOAAgo!#$yP^Z2hZf>YyG<~hV zs-#OZl#1#{!>0&LW{$L1fptUZ7Fnkm0QV~Ru|NL{dAgA&Q_FKQ09Rq<)EgAH6a8>& zqS{t9-v1I+h{klZ1!l_r+*7%ba&B#pK57HT17k3JI-Jm_4ntd&uJ;?qRTu!?P2rtN z6qHjpnbiZ)`9d^p(aG4h7Bd`fMav@i80Xoq9<{_mV_vEIsFQ#SUmMZgoP{N^lqWdF zZiB83ALSvae|#Vbd6+AAMKGM-A*uuaX=*~zBJuM3MFl&3Ae(ivyzKEH#5$iJkz!xZ zpLGB6`ee_t;NN4p?WIi{!)Tcxz0w}8L|1d0k*66d{7ANrQuJ5E>vmyU4jlmRfNBZg zL9g27M;#UnqUiEYp7|Fi{I&FaP@dC%4Fvhf?4-;}yaSL&c_%v~I)wyu7}F9eoSmCB zc?RqEaeE$7=AyP^$bOCOcciyY}c8}?es_dMo z+NVf9bHl53zE^7@YVZ!HU+a}8LTY|)yOBTy2sTgR-X|hr`!XqQF*JqF@3h`bMxY!w zU?M3!H@s6#%BJjZI(kkTdJ*P$a~zfo+0*XFwQTKi{lqYDN^Yo45>*L55Bys}z5EFA zTLAj(Qm%n9*XzpYl9=9p>3q=}T@&RQT25*f*SqO^34vyb7aO!pThlJy;dxVNlwPzN zRS<);Q*UHO?*7N~sWy>ykg_8?$cV(JU+)N_Vc&s!;_C>qk{tuEj(xkr=g)RwR zu*!Jp_VD%}zn}LpQYpu8jG%Rk)+P(g`AR2{66ey(M^p1O(^vVCtet`8ksn7BQ@x6# za}rEcv%QM*vVAN^*G8xEX&>p|g}XC~o*fUy`Bn@GM+tnI&r`I!)gw$$@Cak;pA6E? zT$_b$UFgQ38vWN@v37nCV^*xA+8e@kD?w==g{~FFuQHQ~mgf0#=})P>oaQY*n^t2= zB1>etPXxajSsXipcx*~e3sayrsn+DTWm|6Y8uA|IvOfdOoSn!Z{6_|0!;}H&k6{2> zLk>VBb>N{tXy2CsAU(#>ycmE|AhnqR*bQI+q7xW^vYQNm9FR`>HTUT&2Ecls$M z0RNr;lez{)l0e=5lzY4Qc6!GNFvH_gNd~QqoHQfenDY%s%R8gAx;^u0(J%DU58zZnL=zz_d>Pj}xJ%C!%m4 zd9SaW0t(;YwKAOz)nu*OLgTFIFypsBwI z`OVuy=f1wsEtik5zG;>o5T{)@I|WCY?ADPa>E(FR z#fhqg#P$&gE3~A`Lche}6A4-K(l8!mxG&B>)N&kB(g%biQ8JKnJz{e z?r!fVE1h))>xH3`&3tQhCw~*J5b(l=PEAcGDPA|H?Z!exAj)EHHSMUnwr#pSS!>jU z*zg6%0`CCBgx25y71uJTCg-Io9hAot>j<{4c3Eg$K@~K#OE~uJU`c^jx9oi-x5Ap1 z?0v(A>=hh1K9mr}-oV)d)wHuR4cF|xlP_a$=|kV29xlAu{^G&UC*;K354q_)A~qly!<30T2}H6GHs>{1cFnQZu;t3Ii^KD zD13SP?&WiV4@%CCzHTcxTiWeZzb#mlG2=VsJ>yc3wR-4dyE(n`-Yd+dc+3(7o5tu@ltb? zb%Gaaq)go?cn*0Ds@`H)RgooFpOfg|pql10+}5sd62kk>WfM@3?cW%HD}L`809O?R zJ-aTO{_xnA0r=Yd6~0y1k2%!CdJK}(PNL*b*h(0HVjskxHb*<*>i^ya9HJQuxT7;* z1^}|hq-ENbPi-iZ6q}WS%MC-+^!L?*0)t9w2I=_;LcaTmJ z0qF@P1W37YzIWXes;NW$ptnw9)uglzIFQoPrkPVog2Xmi;f*D|dCU=L)q!VB zs9YQ8ZVdt*o2YO6%Y zM2N3O$qN6ka7l zxCrzP_Kn`DL!sC}Wkkkbr z5mzyDNRI+-&NCwvvSWwtH~uf0{Qci8{?A*4;7*vFu$7roVaVy)Hk%fmseJ`D>TRN1 zJX~(|4TdQuXtEH`O`MOp%$h&0nk8yK9HNYu-2W!ZW%#_r_UBZ(cLq;W)q0@yvlRi? z<<7@-n_^cC^?9J3PUg81@_%8PawXfIIX?b0T7wp;vFiFD;^m~_X(i+A!y_0g{b1&4 z-iBeL*Gu7LYc*3ut;$4Iu20zy z>)5n^I{KwZ9?hbf!X16f@|cWu?o^j8T;yrFMTc$JwOHFnpQ~NolWjbB{ z_<>J^qy2>hqAqW>41qWuMqT?)AN72MI{j7>129F!9)n>H zDRfmj&r#J~FDBy@MVDRp7iAldX_-`^T&f-|NB2yKF6p9v=;>~xKo~zl-Ql%Ll-mdu zObF%pYaGwc{jRsbSY~Zl#kcbh38`yp{Ql0+u5uZ6BM7_EKD3XjT+EMc%?^XTDSq9% zCu=3)S@-0e@@12?d?SsZls^tkppxh@$1%{b_vq+k+vKl9x)*wTdl&xckZzY6Of{w^ z_8*6IoAb*pg>y_3T7#scY1ke?AmE+goz*E$=6AGJWp{y4z((fLtmL6V7WVF`3Qef>Q_O5e!LTPfN+=F?2_qtK1esCK=Cpb@f2rsGssI&ky84BqOFsCRLPDFSK89Xc<8!y`&hC1Uh)S5&tTAh z(JoA`rnKq?QdxbZyIUy)G4e?_l)Gt9^E)_}lE$swWE(GMB@XQrN2U7UEOZ6i9jtO0~v? z-VujXiEJ4L;9~{-?i!XF3CTltbp4v*)=Q(q=9m`-l^ajs%FHjIsJW30!165yfOR#B z0r<(hmZ$}10IvR;HW4DI(|93A6;CS|0FCzlZt(xh271QKY^$sAvW@J43H@>h>L=?( zW>>6fdfJ%lTo#pigXQ9Ro%5nmMKn=uSKp`*m)t}!U2&Ud8hdj2?dtO^)Cm}TwD(Jp z!FvXv4Nr+@0PgV7%~cfW);198J%bp?{sZI+wv7Rx{!pgR4Sk$mmf|y2NLUA zL>YkLPG;L!=H--RWJd>r`A#pA4x=hC9qP~j3)RKcfxPsqa~;GUykUy4bNWKJQFSs0 zSzhkR)okS*;i%9J6dz$Hx^7PAo~pM}M_ZO2)R;Bp$AgQvA^SUgFM5gJOTZ`NrMI0P z_uU+j;Ny!<1Rp_1UbmQsYxIPqYm=b`b*YBi;)%~!o+a8AJWI8G>{q{FC|uQ8DORN@ z+wmh2wyUi#dO5nno+qlpp6hLgWtJx;M$dM#!U=7tX<2HAHZ;mNN=ow0TxI40ubNry zdL#2BWOa`5>s~xVHGp<3IkhiS&QuTmsP(A!N@2y%$UN1)WA7xFehzh`^oi zOiJ3$B#S>qOp#0qE4xAO)QqR+OoFhUG+FxNUwbuW=N7FU>x6HYmO`f2f}Ap7I^^79 zPxbq@4<6Xsb&NSWIW0IeS(9sOhI9LLI(7}X6-5n2OQf!OnVihOnOazCYscK0?D;VG9juf=#fIiO#Wa(0VTH!$y2^r zkhri7318qgF*c4vWF<__I*^>uOEfO)*Gnpa4cBvvp?jh-cLF8)`MS|4*ZqvBETaJr zT8wE8)lx*Vr@gOiI@_V4--V(m1$LX4Y1`rlBTV z&Gu?GtB91@t6ZgbupEiU68C8P-FmhzAv6!=s>Qmp~jxGP~Uuk zoNzBM9!LIl)KJgy;NP`AF46HYf579Q`2PE+64pVAf1WcaqILoVL~{4I|M4-)81M^Z z6GieP4^#SbL%1lag=>412zu9{!=x(Ocio6mNdU`M_{SHN>G6~!Xse@ygxma#S(LAr z*uA`u<#Z=_CG8R-n$CLm(+HCSIGGUXtx}>zO0gHQgm$bxF_E8*EIXv*P$(hk< zic8yq$Z&w9wrvq)NX+8VE(6eQT?2BiLfKBpsW@JrGDCoLN;{8gbZaa7)-2j?n~r#1 zxNJ8tvzv@xn_u(jiVl2cYTCb&0tH2y`0uP$903OcyWqbgEbze2P`DYzo_JzNRF61t z)Sopa*1pjGqoF((1{M7BV2y0;2N`-^vJsRuwavS8-|P@6Qtu;P5r)THm8b^)|J^x27&gOqU}hZ)D&d-2@ly>8*kyJd;jK3{7-Z_0C3 zFnLv=4Qj;oIyqOe*)mt$f6QKG(+*l%7%w?;r|4&_MBPu8a57sim9Wkh@HLpR)TNSk+J|02 zh~UL(7#`ID`WtkviKPGrWTy%QS3tjbK2wIQ+pScx)?%vaN#H2AbTBXM_ii682k@!M zrDqZ9Uq083T_z-QnC8ps+P*^Dutyf;8)YOmG$z-W`h`(b=C}H*M>O`2GSy^&9Y=!~ zE_@)6lp_=_3tIe0jFB1(^tJTJE3)vqo<#O?+%q(p*VI0{1boE+5bp!0U2tg~3h^kG zkh4V_5UwUxXsKtQ;Iq`vo(m!q<-9PN(nS_Z0a&?Hi&vr+7Ay`cLQtGmX+^M?P^h&8PdqMWRUo`ik@DW674Ldp%9L1o z7OJoMvtn+1WX1_^vS4=qnepDn61|GVLTB|kv7s1~ACnk>m;O}f;zgnI8#a=G$5qW%XYYJR+s?t za1%}o$Ak9wht`^2(f_hlphfxa(C&N+nRkdR`?rbL2Jn(D-#ld`E*Ghi9vGRE+%Yh-=FBpHz^`5jzc0NrB{YFc$TI4`TNqc z6c%g}!}cZTRX){Z+4$#gcPS^PNvt2fWB`^>T3xZYEYVI~-K3?}&BKoyHTTz@gvPNR z3Ot=Th}w>s$KPB{+;0=b3o`ISQE4->3D5m*mCaI=ba+YfUW=v;bvBOJ>3XrScwwIC zigvm%#W9X_Q?qBom_41K0eW5Rllf&XK%&Qj{e#ccW&DjM&6oXGOats?^E>=YoePcf zU=NAwnU6xV&Og?W(h>->m2E>y^qC``NO#tmgr>ir`z!Z0m-k^oC2MCvrf6^C=0jRK z(*3(jSMCWsY@nt}-%89x23NRcQ)~h*T#1h1b zs`h#c#~KZ5V*4$$;g)(P-}w~C!vKT}fEWPvFy^SYtJ4QiAgVj~D@W2<5)n!MOj!Aj zTv@yn=5{)U0SNw^mF0M~t7V7kyUM?jhh&OW8{GJS9OxL+qXp>J{*yp12H@2$lJ0#J z%K$_?rDgn9ifs1}0nC`PP;D82nI_?)vvtfXA#+a!f*-~KzU9*V2(VeYcwh`1hNbj` zTpYPMOZS#*(5>Y_GXvkxtWF5MO^GS+3IlL)@kH%M5v@TNzoyZE<>p z-~v1G4IA9kxO#h@DorabTUwZnip-=BR&5QA20r(yg?{_tmL@>*^VC3n+7T>LnI+rq zymujmgMK-kws^ww zAlq1A6HdKZ-gLRo2MR5=|JI_P591!4cD%#!;cRE})Kk#WR{K$mQqvP3o+9b-^yRd@ zv6cxa#6V-cY%|@z8~QE`e+V}_K^O(1&qiyx~D!0xp{?4|`XTdiMlIU!e!4z2w8@se@(apz%V2rB{d zI~0bs7^aHjOL%UO6#GaXi?!KsQi$?4E(`SQNMFu^iat99PZ!fL@OQyrG!f-0o@0n+21H(vhQ zrzl8Y3iJG?zKpF(k~@?75brSnvytR5=N!`Jvb?rnpSn8f>Bt~{bpCi^% z#RNCCQbxrqA`WiW3xVs#CDKLLJx6?ZYkWA+ob0dMLflxtr;-Vd|PWMjHK%JnC;_L&TbEzZBs32COeT^h!xc zShM+C>a1DXOEGUqo#43-&rkmF2$M?g_QG?Vp}G*=@^J%t7kwb@y19jvNaN;eOlC2v zH=UI*E>RmkY^avt9&ml%oMHN;b`Vbc6f&LVH71T(EgmWB!}3 zkFHv4)nQo8GhM|oW2REg$;&(>V3{spQX%Bd68J3aI62HZw;W;I9@I&F;JUjLpd&a) zUe_rm@8K-6OUrE@3}o+B0)G>8Dpjj;!gm2oXV}W>5b|hgHR@ z7aIL-8g~u012-%45%x>9Z56<TKpYz-Ci0KY z9~w=wF_rbMP-j13^+*S0*>koQlI@R(^saKC5+USJxpkS+-xhoKQGUuO-fn+!GGFjB zEs)C)`S}OJ)+m@m6Qi$Jd8W6Zk=l}v>sy-Z;|vRu9(|I8su^$^T)g|P>kX>@ z$C0T`d%YTm=r>;~R-)%iuMBJ2@`q=f*<5E|wT~6c+dT-;kzn&DJo|Cv@_f)dbFNUz z@PxZ~EXPR2qm8@RB3@4GX;h3T&lf|FwAJ9F%+ZBAKYCs#i98XbADuc$+B($~-=NVW z8dvWC2({7N>s|;yk{|>3EE?z%_DK75wQY>OZg#fI%(k#CHSuwm8vTIf+{#1ba-@XV z4^sB~GrK8<^dmn5{M1|;^*Hj7IqZB#x_zMm>%ri!$X5+%-B{uEZ1xe%fM`31Gj7YE zBR!%5&oUwY%Oza<4dGN)e)b=KtG7{JbyFZ5zQXc> zv3;cak`A{A4iy|P`>Z*6)*tz3JaI(y1}J{-mt*sXjz8EGn|d2=XELRJNMM zLT?9X77F^ra9d{P3m8JO&7zDHy*9#nvJAGkPP9B1t2&(6Gb~7u$R_7PN*A27yKo-y zJfPI3x}G>n@in>4etXtoM1_3z6X{ZxTy;%+fbgrWQ~h#+k-JT5BpVjI-o5Q?q3iu$ z?wJ~brL(W6y2_qKOy;K>E5`{Ih?GO(I|}=>tGEO!O9hqUx96UZXT%{cc4;sGPjZd? z^NpwHEq_2uvd7X=+I%-mZA>Q{Fhd#aKW@9761#W}dF1(C6Z3?4b$yO-T89{9vqm2c z8wehmG~T?)09;lj)8XItxt`6#XNSfgHbrjkh9qVhbLjeJW>xLOCAMF5-v(VxlTKQV z$8tmzeh*z^0FWdhc*6u}te?h2#4m5pKCm@Du|gbLjmRG~bKIuDa60E0fV&Z`0i{{q zSFATW?G6^=o%2;5OelDxo5X)~7w(Zic*}jfa6)XS=F##sz7HUbQ;R$C?lA;ycUk`w zt*3?U8VDn&y+kVsJ0k_RH4~@x?v+fWj&E;}CPYBy8Dz5uT7En`f_eoJLN1k}YD8*J zYzm`v`6xr(PJmyv;|HZX=c(5y0&0zAh|*ROapLQl{t>8FSUrw5;7Wk=ct&hr(Xv&& z5S-|)w_FWT8!m5hhvC?RWGZoJh|Q=R=8DZ<(U$!+=`C3RJrd;H9T{WOf$Qmx!|9oDn15IcxI{yGTlW6|M;$Zq+sntu z*7HrLNno5hleu{SX9eNhbGJyRO)E(fFLWn?q(Zm>E{y`|cxkZ*fN!9YsN zaiK^2xz9w0Mo$;-*mHQr=AJiwQ&y4R1bLs4`=@DHSz=~gBX9r zLe;RLv;NvavXI%6A#x(KC+!Butr^UYL+JK6|Ln#9?DH`IsT2s^Tx6zjFYGdt z-!K4?Yz#oF1or1R1F)w_AB9jU9t^+(W#sV%2B0s5DO-xe%i;)oo=L@!?cvC!q{V$t zTZ!IZuAH#^}f1449`*0e|a}sRLs{>BU&vc3Grq? zp-PLJ8&V;zVZ5FAOOuLS$R|)dkRlyV=CLb*v$GpG$91={6PT&n-03Ky_GXVEDfQy*0RHV{bfPspl z!yUOMQrTxP_qzeEn7jm|e6iT>0RKm2H(%-r#j2&l^s~k`C%czWn;Zni6E^x7RuK6x zK1O|*64)-HMk=O+pJ*d8tj>)YlQgGB*`>Qpqb*Xx`lp;EhgAmH1_w`T+0Ib9+eNMt z=lteif#jMo>ZGm3$xVSbeXy1Xmc?67t5OqC>J5p(PCjOaPQ7{J?2ku5#&}QQh6p%~ zr1qOU+Cdk%UXSJv9?RXV&@^d<_34+b8=1}xaoDA}rD*h2EV3P2>?wZ@lc4tjtA@JZ zJP7-45SK0|#kf;fndnxLzY)X|n^3d5*@)BeIQo+l1^yRyVhb(^%^rjZA~M=V1dU5ge7o;sz+6g2 zRl-g{*^fs#riGYJQ>`N3d5w7}La#^1YfIw1qoGP@H@ov9`;VhYE<)~RsZBf0Mmon# zagt}gDCqwlp}R2%Mu!@2LB5zx|>Sr{t%% zzvcPpM->Zu@VNhmZ4eMe6zB`FB0N{J{jBlVHdd%qcy-=P37}t^*nD`dd`fsg_126q8 z)TJxH!Y^22_-*L;jYMXUzv5|%%@)YO=yC^T5!b2dC47WOZf){HV!Q5ar<@sbkIWs& za@{~K)+3j=S5+w;v=1cz#cAMY^{@ONU2Q{LPt53Jb`t~v(LYHPV_fa#z$Yjv#f=R= zjoC6Jh;ha~SGy5+>sJY`=c2>$ZA7GbpifVTB(YZEQ?mVXs!s=9%7vt4avi@edyZGh zPD=Xs1}|XYXvoom=6-(a@-XC(@ACUW@M;gwn9C36K=m2X{z{HSg(Da|^GGWD^h=*H zZPNFt&FoR(#8C)0y`KTdI(kl*C>^05gA&FO9Bm>hln;2Fo2^dgM^O-xF6IDHK(4>( zhI66){MzLD@b~YYf~onz&qG54yb9ME+%gJm=huVEi;Ep+pfhe6?g2%Rd3)R00j=k@ zOu+u5Nip@2U(+G~7i!hn^E4MO^VI95s}*nBai7N}hucR>-*(`A9+Zqft-E)fH};9X z43AwZki#h7GZ`maYLgpTC_Pb7JoeII6x!@6*`;U}<(r&;J(s^z)5t_$swQC@Rn4)9 zE2jd8JMC9sR;27#_+qLTD7qT0FL!Q~ET?dLGDJ*UvB>ektY>`JrqH=_&cn2mD(PT-luxB-IY=0zS&k{-ax^kmyyyKQxmbjjIro)`WDqG8_R9)9P zM|yJelvHrJ+-@%^z6{x_td83DF&9b`{`S$zsMNT^ZgU4?UZ}2xtvwj5- zgz+tR)_Ba7a86u#_1NI9?{^!EXAeWhs>nFZ&v*G_FgQN7|2UUOHr_k}N9D;%$^7WNMs(Ve_rFkMhb}J-Z{Xj$dpW zdILFguuANX+w_w2mPc=4yg01JDmD+Uuyh28cchVrVOqS!7tZg<{;0>)VX_6x7tKcx zE*KAp+I}9xz=Sp~AR*xzvypYPa`cIBK0GBBIp*bDS6+7vqa*s2`U5nEOD)dEw^=%j zm+Gh3SwY8Nm4Y!tabl#u2G7f}4U&U#WhJmh|6J+Fkd$EvI%%TLc(hQ7fA?gK(73$2@oPFqxWB&B(gjg5@P>qp^~F^F9ztHW=};yP|NfrD1@a@0s{quVVn$r=t}$ylFr(5;z92U z<03KuaY!igrB-A+2OFid144ZJQ>%F@CQO);sB@=7!lY<zbvIMN;IO9k02y2CuDe z+1oQ0%xkvzQ3H=-8$Syy*rZ!#315=eh)Tw7N${9fYdZJm4g^&%p_;|YGJ>|8yL?g; z0&9~X>AGSSmj5`JnU*_(T>2YAw9pA$ss;&c(m6cthgRIGCCSCNH5+s_m}Zb7_U_i# zsuvl&hVu#u$vHgOsz1g)dktqP zQCnTd!FSs%=~EzyCfBWpSrvOVkp!LrOlMXHIqj(lED)wrGi6n zPOKl^lZh|DS<|sj>LW`lGe2k0whE1U=Axw@x3v8Wi;On?x94pk>0_5sjg1psY%X5+rwxliFE+55o z_CS4q#p>L=E7rNHJhkd7YesZav@sO=;P?X`!J^^aBAx#@e zZs2dT-Y+Huf29w zr5|)~CqrbBY5w1Km^J~CMy^E_ZcKH|)(ve6ocvK8*DFL|0JieZb#R6*vWI=6f4Ry} zW)YQ$xyS$%G%1=JcVqbl4Hw&)fj_A!eO8$i_$B3V7j&=vm*1!`0H0+G835w}RXSFb zkkTBvb(y|vKESOhVvZbYxb!LP{E;C)c{PfbHZzoHr$0A(0;h+8w!Mx;YE4pi_I7pC zXfafy28k^xV)8BJqwMRXn<3g3VxE^dI6SEneJD)cu-u7oK$ zXWwl1mL(@R)VtYVy5_0m4W?Q5-_SPft>7>Cv0HAh?jEdj1$7Q45_0bPiA6!BAaYy< z_hy#?Km`S!3}LY_w4Ap6i3TNgS2<%RGEA9h6BmH$y%AI}J*Id>L!|e7;%?^rr1c^cW_w#L`RjA@UFqLa?`zq-)A+uO498Etx_wDqx zqCV*>_pLp9KN!Z7|UhWFFZU_CXFejg5FZ>MWdUP zo}iS6e5!ZkA!Y6ldTrf|?F98S+afGFstX%m%e1>%*bcf6y=fn@H_tb(PQ~&-PozzP z^i!|u_+#B3P$q~+41fo6<^)&Krdil%!txb$fyy38I(@%3Nu~f{Y*jZECc7x6T$bUb zfH78hGh-8}vSOLmGl`LrD*s)w{z1!ir|ZsCexhhh-PQ@qht*7zY+RiSikvk99l5;nUm|T%W`%k1%Jxgr_(p^gMiaaueD&i_1>U2GZX%-EIom zPE^>zZO1E^A4v7tn&viV<_&$bPcf`F>wJW3fBVVxIVw#Y9OCHiio0olm0SF0$+HWp3gUJ?|77#*`Q~DL-9by){UP-3UffvAv>cREW#X7nvUni(vIVk2KyQZDB;MhLIvJ2^79l)24I|r zi8@n!F6?Wr(;ajlN}k?QphzIMB$%0OnuR<_;W;s&FaUZag*Qz=Vk2ZKz|l{i7$WF6 z^cIdjfSjeIwcjsDIfp6nXmCg}2t?ZtU7KG|g_02kGNMMD>brYo><)c0ol72rnbP>H z=i96tlDT5-{6Yp5GtnN^Xg>6tbl+&>z{PQT6BaME^F5IM2C`+(0K8sp1JXlOk7}uR zHmB&Xlo$Xi2Nx3_cY{8o5VRd?`~qa!fSgE#Zv~&|P*rHTbfCwA1QX7_YLQ$EN-h25 zL0767MQaw`Ql-5^x+^d-6i>@( zMEBC_mS`EG5XTosHCSRtS`jD1iEV`T& zo&iXpC^9ocCNsr%(T9LUvz-^f3t_xeASIB5YHiqg5hmA3*fKiATPH0AvtQpZgs>n` z?P!>bdN?%@pV2iQHjTEsS2<^U>xoxxos0jMyr%;PRE2hpxp=-e9gko*&$b$&@16Hk zY{V5{rh%UM(y-JKnEw1$p%q5U_mvl>q$X|WXZ$K#%iMP+d}FU*hxsAgJAzo=%59+) zytP4SsNEcIAgQTF-4Cih4C(X==7tOPKyS{L*(l~EG`4M*{JiU|`bWv_r(XFQM(pU( zM9+-@2v||aDt_O16tslfpGi**bxlp%&$4p zzUqa9f2?=`FG$=tYV`i9%#rN-yLU$uwGCVBuX2MSC~#)%EsV1 zE>ohHAZ;|5(^NpLF>d8WVA1-_U}Z7FZuS27fy_y zb&?#WNy^I4`+a7{j#AZOJy}yTBF0OeB*OR-?wt9(qg41tyI`4*o?wZ7R8bW7DM;Oj z*GS&1SHn{#gZ7r*YC&g3yZ-b|`S`DFPI8*|uyl8<3nYbIs({pTbipYShnsuE6GD9J z4jWaQge0T7IWB}~lLk?w3kD>8G|Uwzhis#(Oy*DcM-Z{m+7hY}1?g!KPyD}m?<`L| znK*bbzUHTSDZ9qx@0|B|&--YtcNo_3g0P6^w8Q?lnoH&EI)x>;qe-sQ@(FTgft0S`Yc9=$pIOW9>$E#!DrsEPSd@}4h(V!z5!s}5Pa;I)`5lr;j zPixqIPgiZ3?Y9L-vlIRs%WLCZlmO;ns8isCq1g?>>ZXBi zG!DhF20GIsgz&?kMRm(mM5VKLM^FRQu(?#3iN{28MviX0tCw>?A*iExbGa_MbEe%; zA_9J;?4vrE=T&ivRbd*AG?kg}R94);7E@om+gq~Y+vo*y4fZv_+pQHXjdPzg+Rei0 z2FfL2%-G3YJw%Z)iQkm)`9xKz`E};;svjwe0qCp^g1^b3gu~FYcAkOeZO40*77%MI z?q_PJlgA42MdRJ3NiQ>f0V&u0?E9p3D@SBm2^(wobX{X;wrQ9bGJE0Hw`P=X?Fy#B ze;11n`-t%CbmAvPWCy@m5%IT3rpdL+wrYjA0T=M({y|gCEIIm4aDjuP{e}1Hg;}SP z2BL#@tmc%Ld%0d!6C`gsjYdaTO;6`->URO7>5^1sN~mfqHooN=g|C%QFvn`_4-zuE z34|-g@ILd`tBkfCm(AX+>b@pfYkNUSD<!8$U zniv34_yAUTq)*=4)Yi{wt|nw^%WLNcOFtHa+VWaLPQ%GQl(#3hZc+lfU$wSeY9t{e zsaIfxSkYVcq_;*vH73z%~>n?JF`IE3mIojpXn|{!V4jMGRR`LcQ?w z>YaAouRxd-EZ(MM-p+0$o#97@&Q0>DC7U&k+V)vk5mWYU|79S8d&HGrQp`jnr z{3rwVBae35Y}xDCGpyf_#o2az1(nAhHx#%30qKl-0jxrHFtG<2$v)*ss(sUly`+xU5RMB#BFolI64FOZg#)7m|@HL-(l9FQza zwVJ94w-%IIiza|GuXc($$PKYhV z{X~`CIaAxJLV1_XN=kbhNWr#iO@26+Bp?19zoxRK(1EIcxu7$M%7K|VPCHzYCr`p& z7JZ)QU;g{}{brTu*Ir9cd}S~83;A7qy=3E_q+>TbOjCcr@#Zs?OsQMb^$SyLbc6ko zPn7uf1+mXwHtjRy*a|3A>~l;0r}b2={Fej2m6~ulJs8qy=wWM6sr+zSzbyajMdjVy zn2%eMy$aPy;O%Gbn#|C)g(g)I;4c^eSKu2YH`aw+0T=Bm0RPG_%Vpqj17df4l{CGIzChmg5^g8=*j>>rSYNs5>{So^0 zf$}SwCNE}yR@i8PJzpPy#+Et2~A|*?yoh;eYEeaQ7khJa%)3dYSoyoWhX z#HXky4#>q1AWFJ?V?{F{G;xC-S`OOjM^R1q9H$ok*6m>?4&5o>;R=|3J-U2j=TG3{ z1_l5Hi$B?uU;w!ErUDK>a(r<_4q>`!M@bC8+fN$}C&Mh$^4QfG0-f5!0CbE5%!mFw zy_p8t+wx%m!X7gKc#nqdmi<#?LXuP*10g|x|5oU~NFl+=y^nLmdr?|d z`s*xsOE!6w)!_^F8~@>IRD-Z?`2_kD5?Mx z_wN8_lA<=gBC!t{fK3G^Dl7c>T$5Zc;-89M{-4$S>Ho8u|6ib4`YGfSLzfJ4J*~JP z;;(c8tjA95Zl|p27Xw+}5EIhPyo3hM^0+)Dt;Djt-|zl0^^b+^?*D6Hd$?-CkDgN1 z2#CQuxyb^J-sy0yeu@UNb;n^ksUPkOIRFCWpZ&-6HL$SpE^?R!@7gQ<4N&& zOF`4JS~U?CVoL%O_(gV@SPxu{B9FCcxpt*F%Vnqi58~cCs;TYk_s;p*MT~%efDjcB zk*4&XV*>#J>75)!qzOoq05Lf#5a~y%(xOsgC`L-?5GjEJhzOyE5)uTYCzKFKd*k!m zKc73^aqoD?c>f_Id+g0#S!=F2Ki|Ffnp1x47rxH$R;51)9H;4b%IUg`zw1m}Nld`y zcV4jmT|-1Scm;KOP~=tk>XJ*L8cP;Q8_i$1`8nVO_HGq(8>3^4RGI?& zN^p{lH1h=wZ=PdD1HO(hQtE*Sj!9s5g(!hxo#RiZp~!YY4B5lqi8upQ>rx6LJ!vZ0 z-M~f8aopMu808mQ#wG*W=T6JP0y`$-Z*(ymsN2&=r9{(1&X$}!7n%E4*hxF|-`}$( z=Ca8Zd0pl3!ZPHx(aOI}omg9o? zb@NJt?JI;E4k^xeLcem{=qhzN^Xrj4GXEKd_o}|2zq&&QAz^Ys-YJ^Bfo-zO>SUPm z82T+r{)y&{lPxVWVfbEVvU8`ZRXb`?xmi51SA8wRsH>^!o35#N_M#rPCb=Xb#Z#JK zk|r{@Oi=ZK2*q_S?t3Mg+cLIOa;|Ux$oxbsa&>aJR*kl;%xR4luDh%lJaEON(wMt# zy5zJ542$rhqDT@Om5*xE$#X5PuyQ%z;WyvN=Z()aw_kW;Uy=Cat-8)PN#mQDTCBZP zQNM?wo4|SVvT})#WV%pDZoa$Ik&q{{y0s+#(Vg@mj9=sWl33<7?Z`Hj-hdb$po&^q z|9NlyaU`VPXeS4C6fWp)DwM}Ephgm2n+ff=K^XOM@UwW1 zPZRI3`+3lFidLJ`+CQ*+Z#>b-V;|nk17rkwWfoUC7w;@~Qc$R7I}skB_n?qW<2+z` z(9|fV@w;M{`ip9Z2y{@_JI*&S2_n2b?+1Wq%AHVV9waLrrUeNTr#Wpl| zr@SBEnCKMUL>#o@sFZq_x8`-N$Bj?-gHI5nJk`~6lOhCygfQF8^H$0Z z&Q@(YLW=TMq6(JgjwQE~N+v(;|5q5{v>@c;|h*M>2< z^hJZi^wIKL%6(6hPGl_G#S zKgdAZ31nkcl#V{WHB=JWZ>4G#mY!xdicuWRo87+OoP5cf`{VbHa%r!5az`tOqQ9*6 z0ou)Szy-hdvQ9S(e{O18vsL<~k$C9eJ?%PD0o6ifHY;k$xF96hUu9R?L_Vr~2Uz5D z=mE2)OaEL2q^3|H{#V6p_~X&lhojcsf2S$Ac4q}WvB=q`EVq}I89aN+J*r#Lp&H$J zseu2vxgWi*2@PZ2iWcUIeV;yABN4&8lZuGT=A^~7 zgk8w!@!%%>Dl{tJms-vx(t}m%t&a3MaUVmI_fKm&4qy-yf*_7jg5Fi` zJ>%Q|z1m82;vRp_16--#r11lWB|V2*84PloV>|Hx@~3_HUe^z?VkDA?rOU4#$TEMg zyO;6+eWv(8JWJ0yk$jK^8DIPT((on2a_-lsJitMqv_1Fuf$S7wE&=hMHevWMh<1N7 z4txTx3k8`mlW0qxw0eTY0HmXdNH#^!&iEouvu{=SX_#Hki}Zq~d1G9rJh~n>CX2sT zelhQ3vOulyR5+AQy{>Cs{lQc8+KSf2fD-*5$vG{#V=9$#4!EPl8sawiA$X25I3dn3 z=45~$2fy^xR+#cjc%Pp<$qW9px4ZX^>^Yr}>#!7-Na)*dd zKEEPlq1`_DCR^;WK93M9;J z{pxmBR}hyX4sQHFJjc^4fJ}KLTV!({!T-Z}z^tUZF&@wqQs5Vv<6m={(1|d+GEZiu zmY~mlYf)w*K{d#>r^_)ran;W+5OBur_KQo996bg4#s%uBr4#w{G$!o1zrCNM4ch8z z!N=Bo>8!cg^;Wm(`TRw+T=DQdE`J>S!2-Wzj&Vv6zStv7J4>Vq4IgW)&vvKb<9A{n zzgyoaIMm4n(~o8pEq^iUs&O~e){iK`RahDhf9n-~=l!PtI>${7qu+2!)HOX6V|OAR zqi5i0S8&eU_E~jvM(`c4GJOJAejh}R?AT<=nX*M9-8t!SY38Z}C!-DI$!vDw6d1}< zXDmF@d4O)Es7R{OElMe>!qa~^3V!+Soo@&E)t)*z!Y1-zbz1IM*fBy~?|y1r-SK)m zW?z(wvAVWU;(f%^#)d1s_OY_DcU@tCZo~uFu{YV$6r-4)SydYL1x)E-1XzSg?8*hj zvh_+U-gJ@TTd77?mXV9QXi{K43R2O(Utrb` zcfP4=`^@3o22vWt3D31c~rSYlKQ6#%jm{7nLNLyEG0*b`KGtyHpWtW$ENJ_%xL{h_?UjZ z{K_P|pD%KPz;j7lDNcO&j2a`IlNYobgPol3DpWvraIer*TM^pWa`q+q(eh*OD8$m$ zy>XG1SvlHcyw>LuFVXJW;ZVr zgjfiE;Be*x#}lO^fhT(2ed>IJZoQg6yH>xv2S<}|95;H?fXBh*dr=L z;jYl0c`#di{;N+nnPxGVCjQUYAhni56>MetLUMrQzkSNa@=%|fqv*p$wKvB*+b)g; z6{o8wUyQ%)vsHK}H~?7|V>o^q>uuvu$_+Kdci@zA8Kax zSGdliO8CPm3YTQ7)e4!UAEk@03()v3pp|jr^4-~4iCH2Qm8`ts6;DSe&RO^^2_4yO zG5##ixuy2LO`4(r~o@sdJ_`J$_~^&UP3c!OuE=ChM~i9EotD;GZpssIbNh)~iJAhf4=_E{gw zU`p-aI`-)ADp)5t-g79iU*y0M&CT`TQ_%8Ge6@BQ)(=IJw48}Af56~eajkOTOt9O4fShQ+YHAw$xh?_@srJ85jX_<{Gksp zNhUgq`hrGu;iPL0*!9Rr)9Mqn5GO6>D@AVC(?z$S8g65?QvHGtL4y9#Wy|%^18u0N zz=)`$`E^z9q?YoCqv!59+*1IWx5@(p&U@J}=weuU7Fl84>Xu>h5n@F1y_$))z1>Ov z;*fb3^ZmN5`&z!2l}#Ts;w@sN|3;Y@>k1tlS>XYi@JJV3k-{Ni|v#mC8j1Mh}r z;-)4GFYNF7xkhCmzNmObM_atRx+WSo z$!ksn?U(E4yQ@168<&3F2QP{Jsyp=l%MZ+V3=vhAmszChbEQ|u7c)TEHXCVa1GpWmMEQJ86M>?Cr;m!@n@SiD;B5r%&Ryz4y&zX(lXej&*+=Nwm7k=a z-Jl5I&oP&7wGeC9@5nmGzX>dc>Cu*6=MGvr?+Cb&&-mx2W(d3a+YYEsyzX$xzLoSe zFuq)E#V5y5 z9B#pL8=k0?%fV^q$v2 zB6e1V{}tWcWX-;mz5>6N>bAsf|G_pbh5C4G|4h`LqIyWVIM-2yB-4Q&%AS|f&Wv>u zG5w}O$>z0s7xvc$jh659ff;KbT{9eVtxZ)NbAQ3J`2Bbm{|GoaJ~zIWLIX46n1Qry zt`I&MB+Wer)kY-Fs_}1H-=p8dmbcv>_Rr%1zG!WV_!o-vB?J+VsPBwcO~r5Z%UEx$ z_77ff$Yu61{c(DqD0ETLbD?%=3f76&?Xpn=iV~xl`T1@`I^K`qb?lowz?)+|Acg{y z-vRgPaX;<2@?bjuC!3oDgu{>U8`Y5byVm7*dfBBK16UNZsjN&uLj$Trp*c86$R}I? z95tJB`VpeWPT^DEUpt7Mrub3(>sIl_Z+NDTh4XOuCi60|Yl_9O>iFJ&lS!s$Z@V=$ zG{3x}ndBDC_anFy8(NAU9h0{N(+(b`yPq2kyqo_{7%vM06h9 zWnmc;oIr<>HXZ_ zP*O`UvU3ZXWJeo&LBUE+OcNeNskW9b!(~TQH3gJ*GhC`0wrS^bonb){>qaHwwm9ET z>652xpOW!qD5D}(2SxKdC-+K1nAQePC_TAsc4eK_3(0Z9?-FeX`LNoKs2ZzcnQ%wJ z)uyQkZy?Ezp~*~P-DHcNf$lMG(3iT_!#tVCsMvVM7$X{9UjZ|uAI(EU?RpMDa$Rsq zd0=6)iWV`FV-eL7+#XGceY%qC{@BOx$e9okZ4UJ>lPzmOQuWl}hKO!Ef$lUCpqk$n8cpS8s1sabm~2^U>R{cz|Pn zB6?r4FYy31cp8w4NlV+^X;I?4-jig;F*_c>nlkVU7R*-LHl-y%;J;s!{bSc>&4{Hr z!<~TOa=va(woTdQnA9`#=0&T=aWPQ#)PPd^!O(ykemF^FRt%O)6zhR&dSm-3-|AtYG)Z?8TU(38TlVkZl0tJy--4bH9H!vaPR~M z;Jo7=hW8g9AsS1=jxxP|Q?7XU#)%x_F>(_t&ZxY{t74UNn zsI4Rv3Bmn^<<^2bTzAzW`w|rVh7PxARGUwbk|4$&H$#@aSH78c?|)r;^N+)4j$e3r z{ND?-8^>NAU%7JV8_ce>(<}1S*e}_{^+#U9$(JmI{$w4am7fr*OFb0SeH5@(q;sWq zH>9qWIJKpoUbCwgJ@L=~SzcGq;a$sHw?}r?1I(IpI~|7A)^;t`4`%8Hy+1j-n@0LX z9y;@EAUN!7n8}20xZNvD9kCK|AFMrz9#{4C65c!y*!t^N4@3NU2@L9+%Q z=&G>^zt?m2Nkg1Qeq{LJ#I@-{Y`y0JY#PwqIK+NT4r1FG(K*eZwS|bCr;z$-_?4sAdQ$%x%LaaF_d4R1wRUTmR3lD&7H56Psf~MIDIpFW%tu?Z5*b02uarw+;_5)Q(uZ!X)zm-^bF{zhQr8U{00g z0kV!Aq!7S6{JZu~H}e3wom`ov-$lfEfFiyx{$@kR^8f{vps9Bd&Jo1IdDGt;xOb%z z5x@91&1sC}0kn|+Q$K<0)$#w8v{^TeYY$q{Im_<^EDxX-y2%XyGGkC|kwI>%01t5e z_Z}_ovsy%uH)4n1?931l`xAI1NRbEl0O5KrklACfQI-Xw{RzScasn#lT+7K1-bL^s zTWHtFm`dzC$mfdDfpIVpC2ut^YCg$jEG>B_Maps1&HQa=gjkYSky&t=ev;p=#qp$X zde>n$;^Op_m9qRRwZwa`+!RFnS&&TBbChZpY-%QJqxVgbjg>Gt7+tmc; zy2gB8U)d~QfkBQfzFq5Q1+3y`5ao*zia%N&fP5^s;TwikX^k=teFf{En^4)J^B~{< zZKl-$6?QAc9I-KrFbH_T31FlZHP@%WL2Z+TU>?9e>ca+YoSml5kMaBbd2-JIY;CMK zql9QTMtGTO^oSvRQB$#k+y}>kbtCTBubzVI zfhupARkP--<=`J2upmFQw2X7VhNhCYw>1rm7`{xrH!Y94m{ztLo%{wW+r>E64ib{B zO7ZaGdJ!>r(DmDRG+x=q+WVNkwjl1@Oqck^~_AG{La&KUB7On zy%BQV`=8cXW|+5;8Fmxt@i5 zpDY`KL!7>F$5IreD)ai=wbaVH{nx&Zbo8kfhvjF8SggKPHY_@Ce|^F|$a?+S&i1`0 zs24YDKaHT1&=Q(CD*leOOLuUC$HcL9Me>8kr`}m<6hT=o$+YiPR4GIp-?FfVH~b=s zpv|3n0gea?CJE@Yng6r=P4ZL>Jo3=?R?iKy=NG6?5e|;hWt$-)cwvrmDz0Z zEVfRN|LHdQ8yH)RRziu2B*s)+6jEShmt1b%@^Jj_L=SBo`GA(wO(x|LNH9l6A&6N{ zV|_&lX`ZXJy}R}ibcTEB*THyVc&paQzjK4*+b%G}x;@X-IvVsrpBN9vdDM45&iK~g z)cNFNtJz4;)3&IBpSqLw{tl(p%CAIU^kP2GG@iHORXbn$(sRO%BfA@Puut01(ac z^fuKkiSMJ?Sfa1Ko$gWZm|G?U+qTG-^mUFORJuC^glWAD65>WDmZeU#$MAH|b!KbQWkE+fQUUecWC0_bDWE$mPRhBmu=kC582?o7w-M?!0DzmN1 z#gx*3yk<{1|2cL)-%C6hGv=xwX+`!g;;aX1hoq45huJu~OjDudz(_Uwlcdw*;PR?z zH)(_O^Sa-m*!fpKfuhW)^SPzXs<@C#6{Lb4jrVUJ^^vlzt4t(hBd*jH-YYwCvh5;5Igj16^8B;5qJ8fUZrhm$SUGAu zgTM}M&v#YtlcrPh=dEiXeKGUD^k1R6@rm%aTZ?obRmASCpX7rEsw@RM&NbO-LVOwG zYr2UHVSHxVKmWZDzr#nJmmox+64;9eV2QxId4O`ao>3;4AM|=}z2gDKNsxoI+thNl zSv2=G_c&q>gWr0yITg(PZbz->mN@OQjsbaqf77n=71DVyH_y}o{L=U}ONuKv!w;Jn zwlEJ+r895MEklVqz3awrSwF$wu%{U%-~VD&t@cB+JXnT{G4UL15Eba;sMI= zJ-c)+2=Q+}pH=<>v#M_QA-gzWd&J4CgUJyDI+86E#PxSsUcM`t^1>+()`RE>Nj;o9!c1j(;FSbBt9E#;%8SV23e(pf+ zUmn0}^A&i@3x5)^Hqye6|7A!EY3VCvs`jUNy$)Xv| zTP$yuD|7&pL4w9tjC0P#6_4b6mC+o6Ig(%xDcRGlbHkQRCng`LToC?Z*^NhZQ@Hi7 z2$ZNscuhPOxfogd9H&TJBzov!OIuU-l}ejS+jbCW1%ld9_yC#afS<_ef}b2}fpaf2 z<>}jJADF~Hv!Qb0ifCq1N89CL&8P^zn_R8yHMDb`@y#75 zKI(FlD~K#lrA&{BdYevCX%UwTt`5O6lIQj9YKXa_ihb@`7uFx6#lD}N(eosIMsCOO zdF<#9_z0wCvrFwH+n19Deu4n3pw4h5nMIcLp1;Xdg%>zHGO`I?Lt#y5si@9++%jol zmJ|hehINcZj^)-Nz2C1o4x2qFpDfKnM4duBZP--n9>T%QuGSqx2Cmls z%aznvW#oWsxUHXDyVXRvLI!HcbT_t~$Fs5H^G%J!IbsFd!RzELV~lsu?Ldg-KgLoR z%RxDGoZU;#!uv6Gp=daLyiMUv>)HGQ?TwF<#YU)!`c>xY0q9M{PCWA96QW&%OT zTi)d4=6nt2IJTX~E`4KhO{3~L$=4AFaG%3mJwzfT58VHXs>aR)@z0%DpdvU%WT(v$ z@C#FJD<3F^g{JE~k+xOI0-o8I za+3-aF$6Omv2imwDk;G9aY0k63Zb;#YUy9Z7az9p=9~hbZC#joRA8*JHgj~o5<)FZ znS%fWobcz^b`-GiK=Cg;@WJSMt)M~Y044Yj<^_^#lBKPZ;)fA1PWEMw$xy{k2~lMo zow{0oZ6HJ<+0Uf*id~ALeWt@XE1fKhFukx5Ok~7!m5Sn-so^DCJKV5i+bq1YP>-dK zXczun+k4W2kw(L=>(DlP$hE39)Xl^GAR#UA2`IR`P=h8@LL>j#$jqZ~!a8LxNj`q@ z5q6EXQ64DlCv&0oCBcghxcIR;<9^_c%A98t72D!Toz?=jg_74kVHCfg`Bc_xo9QFf z=kN&CdY0TgJJzt^Xq%>FQ&ZPVwv0i!Lk$=bOpCd+sYoh*eX|6Lq^k6E1Czl5wVSbR zmua&f%Ax*{_&VeBL|JBlXzNB?(G=8#NDw1UVLQmccb_AG=T@Gb3f3yfee#g{uOBib%Bv-QTj=~MwhCL18tkvGPzPnn~vRyAKs9eB4-~muxOKBu=?g=2v z2>t_7+lFR2*Au`buQ@z{EacZFKFogboF+?!C(RXTbU)(?)edRS$a00RXjvbIqHMBG zXHl>~znnVPXXT~KIoSs)v0D=e-|oHPa7s=`ExQdGPBOP_XC_Wd9`ei&MZl}yL zO3pGwVf=_?9IbxO}VAz-w`F$l!Mbu;7dT5fIDE#PrQMW$ei)Y%-{c`wDrX&9)}VN+ zc5&FBGjg|Sv^BS2FFd`ia0bV@Lsx`Ay&pnVQwRXH+=8zGR#TXP4)s|grq-FYGkpZu z$Di)@r1_ktI-*1tj=vC;bRad%%Zc~7B7z>u!N$tY$RJwBe|m0iN85PMSk1OJ`KMAw zR?`r2rqzC1Ns)>v78$?pO-C`;N_phBIrApk)_EE`TN0@w+lPNr8Wc%s-h_fr#pXB1 z`Y&}<$#PMIfJ(5g9@4F0>(U`nUt7)!8~O|&gJZ;Va`Ffm%QoNlH6gfu0<1Jvu<%~F&0Y?;&iOw}|?g3#Ps{b2F*@w(%n4$kS3;y5GRCF4A-bwBv*^VTwPqM^? z)^g2#clB0E$zevi%3u4UbkWYw1YTDt^~Q_e|>m6@mSSzn zehji*()2Y$c(r{@1^h6gN3PJjdkN(j=NcXX8%{v~H{PXBo9)b{QusHlJL7FIQ`_llWV3BED4rCy>{ z+^f>=9JCRu$aab_doR+z)K=IDjND$9&YEZi?-;k1FT_WlCDRfBTqqcTzXEs?#TxXu z#k||O&X(l(fV(8sqra!&zF>A5SxUUpl(l?2X(lu2x$Th~s4lW`n~0kKv}GaR`SWCw zM#4(dO_kB7GM9D@I*@LkFcZuLj*8yRUtsR=2a?BFcQR1D=0DXZ>E{ixrS^CHQ#Y|$R%{}U<7Z3 zRCoI8uki|yLH+y1S6|dMnJf175t_hHG_&cqAL&60a~8E3u$u3bU8?Nor}szs9v<2t zQvkeR9H9?^qpWw`!K6Y9od_#aT#X>4A7I*H(4Xg37AN-e5bWg(GF!w8WVFBUquw_l zArIg`G82A*5Ab|p)w*!otn-!yt}{|7Vn4=2B|D;&{^xr&7tXuB1NXBN{zB0%Pt!H# zXy~}nkX`-hCZlKPsJrYc7Z8_bPSJtLb;ozM)?+)X4ev= zua1H1E_PSNa!oDCL z;og2|8#BNz_W)TDN1EQ!efXC_Is3T@T7&yqBvYZV$0)y|Di~EZ$pLIeEoLTRx%|y> zgC-S=1m0Loq(09en@=T^Gd*xe(8gEXpXr2AR!;O$_}>?RCCs==n`7K9{IxDHrZQR; zTRmQEtLRA}eLLnHD2;(-`=T6KJOS|V0#Mn?8f_WgwZfpjEpjYqX1xW?Su#{6^&r>! z*J@DwZnMwxgyT8>ua4cKHG{7CX(|=Rk~+$t1WrdrHs%ubOnhetEny~}%GQLB_lH5N zp|L-AgL&4=z&o9-BW1pqlB{vtr$U`g_rIzu^ZC*?j*&F?I&kG_rVh_g@CaoY-wMkh z2ia(!KZ-y27ygqpk+ombx*=dqN*)37U1|Cr069K(^FA$+D;>8IyQTO?4oe;Z!-ad{+&}!Bo3_n)cXyTxU*l#h=pU#l2+J=}O?J7q zJz@4S*zoZ}J)@j=Sj%~yEGJ~t?ss9iHb;t0*7EjfK2+R4x+KNkH!e%xWfe0u*OOMU zF{iXWsfoWsq5;1Tz;R~4e*9%3E+kAd6n{8CYTy9_K>wC`0ovhCrN!sTeqbhaiEOH3 zwYTI+ACuhHbe-Y|>|)TK9Qo$<1l3itVxCxo--+dak2E0Edl#{KgtBhqG_$faY4rj< zK3Sh>Cpc|(e zi@vS|=vz-|!&tr2Uq#S)uW~hukxwW0nGPZMHjxTHafo=PoGFX@!Ob#trF63 zFDyTls2j$9NI}b~^sX10PBm9W`Kg!}=I@XsMXFE-?K-R4BwA7GB!EsUSZ9$M%m+9a+96)NMwT7=RKo&Yy*CQz5ddgUUXH%vDAuA78ET}An!+=1czIMj zAf#p9NCEL*=U1Hke4lKZB1hhTJTm}7srst4V_5=NT{OmD!b`^%u(8U_CqXHXa2gE< z>rPLoRfV;6U5l$KDmb5THHYeU+IlGURjQE!NIL?GsdhNV9EX(l8(4`cnD98tyy6iX zY}|H(K6*Yyg;SrY(6$VEP5Kw&Ck>PFImuGREqu9JODe6(cl;&inJZ6DNd{=zk~RJ=O@8j$K6pv@g}up_dVx9 z8}5eir)ZTQDr|bwRgin%XurCd*o^Q?q;Hf7B55cbi$20ZQs%@b?e)Q zfKGD_`4yHf%58J}@qXFA8sg)UEDhEy;!{3Ej_SLuMv4An8fJ#}0qz0JU2|;Ck`G;} z!9j(p8ZT${-6PZ8GgHcQZ2mOYWF^}~F!V#B{yDk2iHY`RxqWgFkZ`ADIX0XUgRyZw zgdHy+;Qv@O@iE>H*i_Ft&v}j;yy{Njxohm@Nr6Vh?gmtkMp$mqIW)P9W;G41=aF9W z8A>}u9XowTG6T)g@t%2O@7t)8(%7!jRETQ4WvE!ILcEEr%?;JZVnx3?7KeAQs<5!FE1{&qTmHt_W$qsV=UkcTG($)>^}Xoerw=>$ zGqlj87;=rf-Q6cRf6)E?P<&z8;hQ-LXX!Q`LqI_^P&N2D@k1XuON)qv6^o3xaBa9D zGD;++p@w!|wpftNmI)ui(3O6th6PzOZE|u}eNGv?1CD|!jOl4fIU`~amUB+uqn^(~ zE~R7o#DPcnO?z}Rp$=(s{D{Zvmqb%o@1e-AKs+fRbF&r8As%^!gm`LQsIWu**V8qi z6>y3ARL5|*LYLW3K1uS=po0%^Y9f@HV#OBgqX1#bJvTT+WIBM%#}o@?dP@-Vv;BVc zx$j+O&>zbO!5@a;Hbn3C`>FH&)r#OG@uYTi2m;@COC&|0Hh$9ONC;T(?2A}8J$8r= zbD8o0FqHoizn4aMv|{Mu2xA-pUN&KR9}aii@89w-yHC3rs{8gc(&1vU;!S^9;E2XA zh!<4n?g;;_nq3r#i_w8z?98&8R1^C)UtHSx`^6f%7Dm@B2Q)$6Yjmie?5lI~nEPC` zV;+moI%4dDEYBY*#GRy`@APbELEj_?H!l971+BR;ut&gJmNuvQncmijetAFsQm!(O?`Z}zOnwxmKH4@wkI?XzHGpS8rDp+-AI$-X9xV495ZVl63rb&+``4E1 zL(r7>cB{2woM2Vvy_1@Gy--SnU}VPBCsIS3K)5{yUlm%#FCTYS5URw5r`?D!Y2H-Z z<EC?8+~>rJD27p8e$H)?c`F0)1RIoNbsNFcX-20L+^lr?1VR20o(`@ExSyIsA41 zD^>qGC<=$@2r#|oJi_)1K@yoD|4NpnIB*XgCh&vxEAM_#B+meL*T!u-+TmMMWdh6m z=v{xfJMm?k=0==${(c~cd=@}6S?>czu805xu)M#tDdxQq12oQ})?#Md7~n(3F`mf> z5o%4c+g(vPTl{&|YjRqsilDNz5zrmJKpFc|Jl9*#^xyh9$-pzjU)+HL{NE1V_St#v z>EX=L#WL%|1kpAH(@;t?VxvJPlOG`Ln6*Q|%~Qd_2r`_4^sUH3w^ zq>19ta(&rXdolEvB$>?7*I3YX%eSoy`!xfG^Cy2w&%a;ZSMahTH&ki;v#ZI&jZmAf zOS72hUrx@_Qybba2+d+^N0Mrfvq{O4NIrg;kXcWM&`zY+KG1E`-+KyUAu<48kHu21 zjf^{j=FKWyzsyw)TeSF%c~2ja+|3j}1+4_fNnw-3wPC%iIETs^S87zp+(eqN6@`ED zTKVbDRXnH4_qK+Wer+}1RNpt{jV~<3UE#?~6v&fgoxXQUl$8ATY2KNL%1~!xKx*zs z-VX%v2$++$BF*1~fBNq_nS>uGVrP6WM467T0>L$Q=g;~-xKaWiEv$SwF_2%R5!JHmkhD9Rf!6= zK533M`{xQgw~Y^D?f@=Mf4xQ5Mo4ZiKsp_h@TGCwf?h1{U_V&#A0+E!&PO@Vb4;cp z;$@VhSO=6QnojKegQ^0TOHo+PL&B@?5N>mdETtR=i-6lLoC*RH1Z7miJD`Z2SI9sL zT@O9kkrM;<_S2e{C@O5ZtA6>@RX*`ecGNRSn2qE%gS>P8)l)NLFr*ZW#_LE&)<7xJ zz{p&--AOi+v?@$YFNPq-JTct8MneoGkbxi+%{r^&4f3-;te&vJTohagW*5-db-JD&Ht?uooN_mubd>ttqCnIIJ?S z*_4bN=enPA4x56`+Qa;P{V{UR!HFk;^F@thQM(L`5{tEC58#%= zkPC^sIwk3Ye0}tdW74VWsz6mV47JoM;=^slng&b=Lokoi<~MAtB9$yO_J;!5RF=LR z!)#MA*C@X}w0;_-Q42H-;jZ2%>3h%mIjiv3$)pt+W9PnJFHJZEYFL%PbUR36f6h zJANMgTuIzi26L%XdR(2KvyBcl|6Fw^DSiBGsBLMKs}fk>DzzIME+$;pXVwEcqTjHx z5qYmB=R0ylbykp1(icnM?#*7`rt7Xu3R0MvD;y#UcZBb>B|S}CiDM&uv6-WX?#=v` zmj7NXX@hdsi}!+WW13}9#EkE@4SQo<#~d3alTc;PheX86%x9KzfiC{z z*xpK&_w&zW?1<69^Fi)gg3jS`L@*5}&b%JS6&o>>9LR1!hoygct6M}973-j(~T zA%C>o-sdL^-|1bMz>cuj6tP~Y_#k%F!@7HY@rN$nJ_-+%oJfQZTX*nH0g45`6#nm$ z!RX4uyK~5fxc1)`ZCGXHO=J>Rdi<384tx2J4#Bw-EDfAJ&ylk2qLolK+=_fq;hCp` z_ojNM=P1i|EzkVf4)f z(_pe@WJ>mt#n0IvLqabZ4YBs?LjbT)fU=RwS;)Bgf7~jzO26Q0$5>YcfgQ-jJO*2H z!^6m;%=%fqJpgW4hC3oNb;n|gQNNft4$CXg)@n(w51SNL`uC0M@u-oRtfFf*C44dT zc^oL_T~O#vY9v}(ahrGqg?(HW^HOtf6Df5J_OMv_JnR{!=Si7~t!dP1=ym897^pV6 z`MMoUYk9+u+sG!6V6VZ=%6f>DHH7qcl^3yEFZ?N0k7rk$Oj+K zu>QF%i%+X;ooIgVD70E|)574cSQFe}8qp_{i^6GsQ~v&RNCe-*)l13dbm7!GNq5bW zL<}&=&(%wCkZ4=3`?6c<5|y!@%!gtnke9MkXg@nJk?t7jLXiWKd#mzxY=Yj!=fJFd zuh)5z{a~IB?fYvgq=2TIpBl0qAEqTZzVxm&w&EK(@XDK49+KaoQvy7v2R+!+dKc3X1#d9^fjqk`)=#!> z(JMf_5cK&2g-^UXop;a#uKdH@TdVCLe|!%h?&Xhu_ar9U&S;b&ey*oWkSK5zZKJz+ zdZpDEkxeh;pw89L%e~LI`+Olbyp1%?csQCNDzkz|E$&l>)abiUJj#>Wo zEZCpg2$m65Jfs;>%6sAvsUNZ=b$^f;9y;a3zywO)%;lX$_Y%}exz8^LL{_g#_03~y z89h^?7E^jnQf+?>|7(#f_2lw;bIrTh1P?f%==Wi65nLvO8owRc9N)8v*y}V_xnJ8M zVYB*$D!s$!3jY~j9Kb~XmliE4IV4|OM8*y2z8@DMK{~2c&IUQK1BM#BcEE1>D4w}S zW9N@D?JgB9TbnukDk3cFiWUJ1Ja;z2`z?G5-KLT0g2`RieI|reaCjIib_u6BMu9wy zODELK+O)UU@ms?%Gq0EQ9A4QknJa|pTLgDu2L$#{dq=|}j$zahT#-eAr8N@E-?i<~ zffijDRKb`$^g~#t_DcwhBABO8`72oSh@)CS=?NG@v|D}2SyR_>r&e~#o zcZ#E;qEH-(GNUNMMIow10tJqMkU*!a;)R|F5Qrn_#l2W45P?M$hQ=ikjQ|9WK-42C znXrpw6_C*V=6w{)e(UYNt$yoyvup)boTqPe~~&h zH!r_0zt7BIf2_Ga4UhXm}*`i@D(3$j?o6?`or(;qDj#Ii2VqkdJKiO&D*Ll(La z7!HmgbV3ZflS*34rx70$wmq9*aJJ_j$+6V+<#CcoQ6^=Y2ejG4MhBRs#-pzll$>V~ zms%%a)4p#I#iA@F&hs=269*@9hGTPz>n zfkC|vbnPSdlwsCuAuc&HK>0S#N4!OW0rL%MqNm4*!gn+-2TM}@UE+#t02xOOF z>fD0mTj`IX+OWE5Uc>Tt2+zAOeho7(=aUa7&fUPK5|2O2j-Uwb*Wu^}<5X$RC^~06{ZG!nYB%Kodr2=0ewKiXYVxrL+*?kVW zS3a7&Uc)1zoiUJyNvacCDr>u3N0l=aM2rqnLHkV_ff9r0(o!69^LncZJby}$c#n>Z zud-mbnLCWg+9)U!{TmXqM0?R)x5ce>Lpd3p0opksC(D^P@xYsou$Gu0dWFaiUbb!9 zO#)Zlip=|{MbL~15#`T4+P!`Iqy`T%gIc||ETu$^mZWb5T(Q0-pPV>?moF|a&We^%C&X3{VL+AT9R zpKO)73=7w0Chqil&4K;vlKJzqIu!joAqOrf)vGk;PYcsd?9XvdjtP$bnmxy&R8lLZ zCE1{l1lkqESpPfOuj{SrYM}HM9Ab3BH(g;Y7*Jl>tt`Rz20klRPToY~-zBNX5kY&k z)dI-9mX~&+i$Qd1NKNt}6&+l&zS{R249LA-s?UDoHv(s>jjP~rTZiSVyFO$ZCSgxn zDDTq0`Nt^b^JS}3i}0}|r1qY~WT(+aGX=i$QT3K>p?B5KjZ6LQMm{LO+S3Lwz?Pfy z`WXSCsNz?_@)I%ujkA${t!a=6?S2YIGMqV|@FzX`h~YUh0{O>^j2TG6T|*!U;mYnn znx?qx_~KpXW9{(G!!m#c?cdHa0yc*n<}fOj+S`27;*6pGb|(g9PCR51`pF@=1x{#BYLyX775p9LD@w0MEw z_SpU1?dR#)a|5kz3gRy}G#tGX%vUg|*aboKA2b0*4f-YQ%PB<*h^HzvsKwFrTjKjSAwS>u}K zR>fN-{n9uQ6Gm%E$QK=v^>!{dz z4tN}{5?o&?F7T~_vuX~SyxV1K`#z2LohYFh957=_1B`2y*MC2(&M8Jy_u};W(ey=Q z7yz5MT+|*uj{eLEE?8qYqK@wmGXd&LR2?es*Z(50$9O~g{ZlMjsmOvf$N|m=xNGYF z)+SdOlDjF9Yv>10CT$l3#drX+W?1EMY$;|k*s33tZ*UQVhAyNd3)uC(_}$(kq2tq# z#&7327xwY!hq(o9{{V^eac^ZO&ktKH$xNpETmAVWD_jU;k+D%v?0O%Vjt^-Vq8&va z!^@iuy@qnqUVoH-v4B~*^b0t_f!5O9!6QBN4A@n@76(WCrBu33r4bGdEGX= z=?3na1ZVe*#nTTh{`-k_~iaKeFN7LW1 z*Hn8{OkXwNvm}_plx(cWj?!k&GmuhS7I_)_%C<20!xu(G_Y3i56p1)PlRwrUj|PL2 zdC`g<@GoW}K)TNqnvWQ;qa2}Sc(;RK{e0N;k0O?MO%;&^RFDcc!aLw^n2Ry^1}8pl zg3$-o2_BB&_$!b1t?>h;$e)LgP6x1wBZ%T{CM8KWcSe~T1rA%_Ia2b`v7ox|!>$Vn zyWr<5#39ASk54N|;V-d_LFt)ayH$YteKLcCex*e+ZG~8-y1ddq)6g+?X(jDTQC2TY z8Q~EM`I%#@mP)c8Suc}ZyMKyuVOJsy$N=;wL3k4R89-{~m;n1^od@A+rQ8|0_?Q9p z)#Yw7nE)SCr|JYhsC&UsPplpg%j)`eZ-uEzs(}d2}O9d4z(kY157V9?}_!`jQUlrRtqtnF>zDe_j3IdTG0z*o5*R94*FF6Y8ICSKcN`bG4N6yCf{N1N|Qr{&GzQb&MLBGQ$Wk)4!d%$T8%RR zqRI?tA^XeltP@-P*XNph6yP4?yImmWZnR7Pn~DeI@>OkYJggEM+Sq2Q<;=R4!*W(X zgQGLa$DI!T3BvSr9TNc?_wWXOM;1&|vag(4VMci_rF-M)Knu-&(p5SfI!;fgEDWd@ zU1Bo6B6Mi(x!ff+{=(v)CUSrSklPUwEVU7tfU&WIx?L>d-($?0{Gi#bj~fl&aJO6z zJs3^tNKvb{s;(OpMEx27Dke$G(=3fzM-hWIAqxqa}k-HNK=|HXY8~aotk1T7edGlOn0?)m1w=Tf`u6 zIi6kpXoQTOf3&uWrGyV&Vj=U^@L#Bh;gtZ*(~z8x{Nj!~SMk;_X#%d#ee!LXJ znk2eI_euBnGmR>TUoLNB*xd{?^T>|{`daly4^9}4M%o@RCtfhUEY|d_3vODTi}ra{ z9_#6Elmhw!Qe2vUT9yCig-4~fH@K^5WD47lYkPuqu-w~A&_7`gb<(U{$A@lkgyei| z&jo__>UdS4dI29Bf7$-A##{)9Y|tEZ^J_8#z9`s9)jUnN0YN@l-mm}U0#FBv7%BwzqzR+(2Pl|JaMJ)(rlo=-tz>sequ})>% zyH`CnVzeVESP@UN?q(`=O&Sr8by$>}Te^2k6=1Op2(wC1cpg#m`q}34Lb*@MR=%CM=BB*P(IlM4AFE1_jClFjFV}F!hA8 zS3K$5QGf|zw()+^9Bx7&zTe{W12@&ywNU@1$ke+-w1cnv);vHHY?oNdtL&-&s9Mgo!oiH+ zD6m-r`vh^%wUrPLprzrzBgn%QdKKR;fVQ}NpT0EZ%cM4wDZ$|#Bv1$kMxmePwW5oj zIrbPBT-PnPqvRB_AJ5C*h717MA))yfZ&`=>g@KbLMY4vcGR1mq%${u*<;cy0x@bhbn^swDiNlZ{B+;e|Q5Iw3P@XI5AWw)5{2nCrTIvSlIDOXGpH|tv56mc-Q zmd|O2_8D|RVPa@2L4i&ZPt&pS?GlM|qcyu4a;z29I+n#bMOmCEb%fY9Zvxt5mxC0m ziwcm?gb#E2(Bd;pwXnJz{a@o|cl$1*PX$=~?Iacm!K z!1Qwh0Ef0Q&*v`!OX{_*hJC6YiOP*V-sZLE0RaG#ley!bbS^%sS5;>+kh{FdhPILKqI670E;jKb|O6^?6c?^Xu_~^b$jJb95*9Bwct?F z$IX&ObEt-lD?@m&>6~d~scl{9PT-&JyGBtvHnd>1vxd%Y)!9nTLvcf0Qg6T zhvbaB0C3_6A0nE@SeNe^XSW{=A;VHLQyelh>urjSJWlI`V1=um#4Z9$m5>G1EZ_WU zU~g1H@w3uZzn29jm%|k}0$^k7;5wP@lHM9mul)zACG%{GKeWfZ3Rx*iP24|eL!4jf z#T4-dp^Wd}sR)m}^0KdFiq=sVV^~ckc|K+2$rZZ6q%$Yj$l$;!s?JdNP0CP7eU}ch z*&sHIk|2+1BJha%X*BbL6iqjAR4c&D!1TePX1KkA23*4N$gR^^_D~%uB|DG^)>7{z zi?3eaud~93_Evu8oydu2KrX_1zW66H2|jNa2V9fy7m9!8^;8mnj<9_W-q)CgdQZx* zQ!p|}eZBfxW!0BY0p4NLg_G=ZTN89mQ?`hPmzThHLoTH4rT+Z@gMmgTMYKGWbLq97 z+F>6sU2kDnLCB}?ZI_}G!ly^8eeVw#`1e<4(aVtQBYX3QoUH%60-ygW{g%{Ox*XG# z_l!>m5G&wrkzXdQX&TODQ8*n*oYLOv38vUtrPFL}EF)kQ!%r5ZZ_Vl44lWutIc|PF zyGw|Mj^>gz7)O^tc65aRx8lA9+e9;N?oxO~RsK0OtW3m0tAfGGHvH(M+R^Y00GCHN zriT6k^ULd7InJ@>+Id)^=vC$cc@8s62ZG5ie;bOYG-x?i}OV;r|QhxXa2xi>zn4QxgRjrdlxhpl}#0fB@y=}%uq zUsk1yN`JekI(DFx(us|KP zdgTNl=;L+@{hf<#atwV)7QG1cJH3e$n}bAQ$s#Z_)M1n&IvD?KX6vJ&OWEvkJfw3@ zN-l?Em!V#B!=cgdQDlJr?4keYvx8l^s{%c!nXatizUhnKX?!?-E{$HwiFoQH zbfc^d3*;_6-`Lm2gzK4fOHnZu6C#NN%tI}S`4NL5m#@{33DWDDnCnZJ4S=KxOmFWl z#xZW9?^{+#83A979k25v5Sp^TJymvjU$vp5L?;87ghKOq0-EM=4TZARqkb(y514m$ zwK)T?&J{Jjp6P|(JSn@F-e_Jh89VZIa5pMT6;#VKDWM_YdLQ5Zi1(md2k3YsH#4=- zz405|SIGW9sTLJ(GT)1bXB1w%nD>c3z)4C6OoSQl}Rad zAeR&&Vd@7HcxmO<6c0_eH({dJ6CmhX+eM9kKx@QEA1SH=>Q@6;es%VNjYCD?VZjxR zEQ?4ohn^=xTVm@Dj0@|uYa6=Aj-)3pi|2;7uo$E#M*+gku6&!_fMi2?$C$88YwyR> zilt3!Pa>2=i|XqC1fHxU;Z-D@FAZ=sK;tX)pQ35`Y)dQ7LWD1UtI6&*%EgyDE0}$C zBWA*5yL9*9RrkMD9(sV?!V2C%UAy>;u@jFk?o@7jak)#gjdQ))e~rFo+zh6kzJh)e z_klVPzDr`Ch4C?wz|QSkGA^x(JVpm$eUc7fE%kHe9U!Q0oF>7+J@kBNWeg&ruGTsP zLvoZPK>aI3h0N6RW zk30LiXSag$Y@~1E;7Flo)#k%Qte66L-FK44(2M;ul3Y4Cf$Ib4;P*?Do0znX#Zl=Y+zGfwCNPAvL;A15@Gn@T{lT;rx6L(>@5>PvJ1rs zx7>AiQ;Hn&^|Z$hb0eYM!BHeuhFui=R)>9a^}weD8a#3I)hy5ehmOrCT?5Z|{|TS8$+J`A|IaqO`v*0N7PxIejwwvIGQ~^0(iv@{;Hw1uaYY!y7@2z6KfiMMG9v z9!ijR0;jpWc3ykj@sGA?O?;gkT@`=zb=_aYOY%c&!=hHf6~+a8n{+#=Jjsa;Ro%Uo zu51tM8fEVLBJ#WAMk!Hw34{ob;ulTju+x|KSZamJ(8599px-D42}rFkz4V?V%gp31 z1Jy&^tVDiA#!~MOuOQ2y-3)1nA%-cM_aJE4BGRq-60Ab~CccB{(xIg%+ihRg?DAF< zwz_^Jt+g*mL+t|U|z@`<6Yn}AJoLEXOolWOGHYqeZZvo(&pAiD%sBR?unZPS-0N!^{*2~skF(;naV z0sQvk1bJv+0l+2`VDFJR$O*zlvm5BoXN=${#Ox0CxloiS>%6TLh`r8rbmAQ|QM}WH z3ai@=bIcdVBFW3%24q>}>h*bWrKgEHT=Y+0r!4O0)wBG%a5U-i%j*Ct{0~02%R=t9 zC0g!LCtzPwFQ_wo5)6>$1O;@7>?+nwFQ7}SIeCJ$sd5QSKke%`;yPhhe!H>5whfj{ zyOX&00zwOg2-7h7Qc{|s+K}d+MNm7pO7@P?}!;7#h>Zf0skYed;dL}pp=Pr zXO{YkL|ndRuOC&BL0|7|`V=tTpn}^R1Ba~~)@5?y?sB=~C-*_&-_C(*YD>E?0Ml3;Rz8mnO2d(br>6S@Chh*3wUQ!__ukf@q*u`$imce=mxsdxYb1a;U@e<%B z%V3u>?Ff>KXw?C#Z?CefY&(^@ndMcC)8TAbdA{BsEs@)1p(urJ;nq)!J)I`7CmOroL5Wi5Tx`fF0;f0jQ0Vf1_k!7erqWvHS za}_JZf`4ZZL;1B4e)1E;f74m~YkK?#c|28hb|K{K5nCLl580F#*yaw{fsUUg=bklEt9&=g~HS zGXUO1LpNyS%Jk34J)R9E?gbdPjuW%dAPaC#brN;NkGCXDa)f;nIYZO}tE&XVujgv; z>6qve#7qJs1wJX)ud#J8_-90u+kDc*odk(d35&vm%mOcYWCUELR>fe7tq~yCdmxU2 ze4)V^ncmpYhSu2Lmd@GDTvY`Y0DPGM#ys59*xdC$#{(Jw z5abyU0N~$i006$K19mviG?WZe9h@PJ~M{)11zz?)i-~vuTLL8DJWn5 zR6q|MktY_8kBPsZ`n+TL@#N*rwoMI9O})a04?TO8SeKsl_2DVSJOIR#em&o~bn52i z<@eGY{Joiaem%o)lZIh*I8In}a)11OoEmcZq-Fip9L#T<;uVk55{^>Y_(7PAJR6ip zms%ApKJ-s5Od%L1DG762JxGg`zJ=4w%yMLi3I%@2&RZ2ZO;@n8)y~ww?xlo=sRV7m zjOsGRV^FRktPLeH&#_`N3}lCis9YI3(ea`0G~Eo$q-nWLRinCoH>=_O3mNGVn4k+DW%d$WJ+a~YxiPqo&RFqv^jeL@yrwQ7`> zH#7GU*U^vdC%8iELmew-`~(0_c5IKK zWwVPN)ThZQC|^6o)ny;HtR-@UWMmT{$)Z2qH&si&<#tKTFG0!7hV1!kvy&Rt+(WCH zC#gnW;cG|4!NAil+m>1`m+fnL-X$e!pQ@`TysG))%>}2r$HaN#5J>%@`PJ!B ztKG4E1+={EFon_^U$aQM1F$VH+n*TQRc2p@tmhQ%D|8TsH^w8~XZlC1-}xRt5-WIh zMZVpcfBIlcesDzQmD&9(bHvv0+z*#Wg2Mfc+9BuG!gQ-)oGtkv49K~~SIy~~%1rHQ zd6V9Q@mKB~eWwuo=#W2&ZO2X=+>d@+Zhrv(gTOj$Q$8GE0D%AC?0-if);|J;DKA6~=(;EHr!`#W<)y{;@!S4SX3~zpPC~Rh!B}a-^rCao^W}sBIQXy+=lk z$?Dh3U1CeLV)-N|;HP~f`guv1Y0-O7H1BEx%M4B9Tjdk_l6j-jJ4>TptO1FnPOEzW zth%wWi~j>6&WBxJI6ax_3{_ipJAs{HJ~t< z2{|u#4?IlBGMd($-XX$^rsq%)byYbc4ztWbc`Zyr%JjlXxI)+WWIX!iagsB7IdWEh zX=|Fod3mK%(GKdYI?V@N2lNqRn2PWrY=MTv0a;r@cy&zvsiRBbZdI>-WkXq zdj?ySYzun6lzmRVfq~V{ash~w*Xu;HhfomZoP>>sHSU%XV2hNFK3EROT>}T`^#RDn zeHkzX-$d4%JcTS2(O{%F)T4h|o`9YUZy+urGF)lmKw`Nrkp^7$(YJ;BOy5Kr_?zk! zEcL^bV8;39`){=Oja@=HPUo7)TUq$7mII z0^J`MQ~bSWdNp#&gQkW3S(ZB4P%tuRPi+;A3VuHQ?1T)7H-!!zl&lVS8tr}?g{O>D zC)f$Y_^oHCaC-fR?D^DH-=V^UK{Z)(q!$Dfv zzjb`U{HaxBIU7MEevP=lE45PH* zfW~AbCxB=w`=m5{l9~iW?pbcQE(%@l+PaQw9ssUX+cw4j`80@40VwAo7yy2-L=oi# z>Sa58e2y(K2t2qS0R2YxI(r`Lub{aB2nyZWPSF3c&|1QoTrK3Vu0lWZ5U*Bz%)M|z zK?r?k?B6Kh#4;tdu|w)^lMlq;M)o_4n$LQwxNHCu6%d(RF zj&d^E^vRhfA|jOt!!Nm5Yx0schl36P)ihEH0kLt8=K?zRO-Z!C`8pDRt~UrCIkH|y z7qK(}Q|riPfD4#Do5uk2&1en)$_g012dcd;Ms#^u2;y8Uccmy&eCOCwZZi`seghuVqA0iZPX<1f!qlgQ`GdcA(Ek zbtT%jq~AXx1D3JHBrf?H5ej1zS0w~@bQ)GCycxee!}%MDB><}D5g-cjeB~fssTmj? z1OnDC^!i}<5s+}FATZ5Gv5p5!FxUZD&OcF!*v0k(^>Rf{+y6)kR|hPP08`RG={VZ# z7r73Y4BJ7QodI+eMWZxb0spngNNs% zKNBbUuUL)?igN000aCf3C)+2IqS&M0BFO8I^FQKFjMehAjL`Xt!9QijgN`ZtkoaBn za}rEow`?EV2bf;p+3&odV6Ra?ZHFx|8`5~F;64yA0L&b~S8O{)08<-{ei#_QW6+cv z6dZ9K@F0%l@Dhv9wAQ`<^Ys7pZ4|VEc(VoPknBVd=tr?$kg)}Pn-Kih^1$9>2$drJ z9tc|G1%{fCzH}mJ>W&ee<4XD34m5!B7!eLdzRZU>oQsceZbQ^f&d2y?LpW!q&o)w} zkG~B*EFI}a!z3utXi)&-tTBA7who)x{|6ex?=vnn^@3zTg8iK)QYeJM=5<6WptuhE z%Sh@VxQSkH0hK6A6n-6;!Fv#!KLEh@zJL79NvMLbt3{7i)4goS7usVo%l!kN)TAHa z%7wQh3Y@2+!|Tu8L?!0Dp5mUjYVNhfts2NM@+@;mQQ}XvSz2A|? z+OUvTVjSHWH&w7k?h1Ugm37zo3$Sq?(w=vQccFB$102A(>MiUAg@^&9CQk{Bkq}Zy z3nKImc?_%24@3Qb_x>X#;Sl#EKNbKlXr1|%KYKkcoMMk2W?0Kd-L8Wr5tNY z;kc6z%peAuDm(D{z+U4mu<))nWrKt`*{M@pW`6~_du|i*3Dl8y!0CG;wr?`vFhw*$ ziQ_|{PU|=+_fDF|ZxF^|c{ibp4Y%p@VZAa6d>^Eu88ggEDzw0&H@7uUC8zgGqozC{ zn7hYhI}+Y$6+3{0DN?|+Sadw_%6>Je+IatdA2PX){G5bI8)ro)0K-7hq0}M-@vlmV z_04#E0BIbz92R+>0_wDVXP*ol#2^(YPBXs`FA3{$AdK|ID@U4$BGMt}P0<8Z{RDV#QO(%*bS|EEu-pL_So z;02%DO2N#H;hdzX%k&(__Z~!AaMZXz@+)a_eEtzONl6*^%RuXG{}A=o97Jwzsg7L) z8L7BVSs#>^!aoPBoDN0OzCnltRts{W~5cRL&V9^zb|dV?PM+Guqm{ zI_3f(Cl|SaAKHQ0+A*ID>^~@58nE_=0`EH~E>R%rHZk}|N&1W0e{$C4mVs5%p1R-E z|EV{`T|?!tFAjC$KukCjABRty_#0D`rG`4|x7$&PEAZ3Y=->7BZ&6?Hyu7pwCmRd;SJNG(qzf6qk<)CjM2#eImXiHgI|bo(8AW*cV7WxQ%0B!IXGrU>T%o|G+$da!Nv7#8~n*lj&D zrvMud;LsJ+Jr2@OZPj`yeF*I@Z!rDz3|2q;)i(AOg!Yawg33YQ1S9};C_34r9}`E1 zupp$~TaAtF4yUUnOWh3H^)4DX8h(MG`HV*_YV24eG-@sD66G@F+-IH66iq6-u|^hI z>fv`ne05kpJhiD=(pJ2h%flNyH1wLM(BMLnKC9XJv;C<;D-JsB)L^e`y=5QxrS^MY z^%g;KV}qu8FR`iTWR?eG?L0boZLrkg*rL*`E&kmNi!UXx?I*7XYFDig0)YA>VGwy+ zlxz^}#cz9(61-VjZogyeJRbbCtrS-gN-J5QRsTDH1l~+vsY1YdYEtYu*&&0S@UMu& zpq>fHd2k9)&5~6{B1+9isLl~XG%hr^+ROaT6{LXrPQ+Mk(mebQboWs|uK~maw~T?H zHf$i|-@lOp1!X!VYHOglZL%gk4db$9|5yVU2W76oGR%Ssiw3-Cl;*xO{(++d%hU;- zsCC(^;l!2Z>FQvTRqW;b92SWvP9BuHT>Ab@Lle=nPCD{Kpp4WmVW%b_9IalKC7ES9 zSmWaG!Ju@|bbGLWXx&@x{Lxj*NWZb})_2J-avCJ<8m0ao0{79k)Chh+c9s{1M%^Yue$4w3IOQR^ME&e)3Bex2Zp4}VSnb= zk)5!f&tq+%eMoH2+cs0RFX+=9?-HP_y{F*|X=b08NsP3lV4aV~e*tKItTIKv4CX>< z1}gzoHv9O-AGMjVDBiK9> zVUf494Z41sB20qIggK{nk@* zC6b$v2KmI{ErlcU!{Z92osF($Z<6Kd9xC-8f~{c}ND7dvdKXvd0Bh==j2tFR^o*Iu z!%ogLLQ>bOJ1uJuH3^G|X;(GyMWvD@MpVC%nZ`IFSe$II@;tN^|B&7+13?uo9hI(Y z#9cj!wCH$te{SB|vEJQx&1OGnb12`&%bry!Ua5>Vp@Qn2xl-Ex=@Lr^U*s7?t_R$| z7ee|TvD;>C`(Y;1t$R>c8P7QOkhHvyi0)qk{w*Zg-!~UP8k%cF`$@9wI&g7zc^E)? z5EHPb9KU&;zeK_!Jg*EQ%IC^@Dg=)z_`5-FdF~oVuTDD4v%!-QFimqD=lAj1Fwe%+ z4si|-B9#ukooHZ%a~j>nvQ?J{iu0|dV22e7+yE;9WE3+VzxS~I$jfvVBr5YEvSIS= zNJEU~+0S0Mrp6B5Tq5hdVfl+w8S7IsUyhy#P2Lon%F4Gw7*k4ZL=wyO&djpcy7>rN zM02v%*_#EW&iQA@P_u|{wand9*tnreiu=r<>6XOE6!vs#1ioZDSn3rpeivqQeHz8c zGdiJ%rNnp_+f!%mS;UX_CK
    #~)(!s~~qlsL1kw5_FlswWgO>r76z{ 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�i+nWA~CJT=xh;O>coeKE~I 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⪙5oj`jIXC2MWv;Q3VIw2Jm0rh7!x4 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%0AHgLksWQc^0YCYSi<>IQ@bJ7V z^OP+(6Dj_t)&L}rc@TPnuRRk!Xtkx|14-Dnl(TWtaKsx}>EM%FENqeEbVNn<|m-QJi1^EZfIvHuc?FxX)h$j%d&fkiY<4 z{wQgG%HX#lK}LXtGWt}=CEVXas?=dLy6ZsR8X_N+IfIB!xI|tsWS&sBo z@r!=B zq>Zh~r1d2(z3Ems3#B^>cZURHC`Il%K}El@K7v4XHTg6j#&DfhsKum9(}nSaBw3&b z+^6)*yPgjpm#(|8N^=jB@14FHx5eizGampU(?=Zr7<(81vzO-|vG>mtFMbV`)xU@9 zw^eRt#5J5t!9b+237DCI`9)g^%@wc{NaFX;GEBduWt%q|1%$xz)DI8250`8<(2LSD z#Y=ODWhE^T+Q${$$cJ3Hw^3N1--{KczRXvhMfm+S6-XeO>-V>~{Co z96<6%;{HkYZ+#jKfJia_BiVnnkK-F+KYBAik(+oqZa{7ZY4H=4m5zyjGNTBH4<+A| zJrKBXN4y~1x|;G~MWx9vktv)x=yD`Yn~ROtwr%k&kt<7JTK4=|SoqQPPu_au8+`eM zJu*H~M|46eN%Iu9mPWr;qy}Ch0Hlb?z+a9&t|?(iCW18IwEI=q9bOIGnz=9fh_J~7 zzN(T8o%g*IuKfPMT*nQBc5jzZjlKnAQmdY<)9B!cU)&P*Ap?YOH#?G%A?RU*>o$fX z2j9pITJ{{!lpH9|Yn~ycBIsNn)O@;)K5#xz$LzwPgers&9AdJudXW}1+m(^{umi{G zZz(Z5vV=LkDL{pF9F(&}bMLov%=*LOr(Jy`8}8S+W=LVrzC3k~HTQxlQB)5GqAZX#8WcJ`MER1GQ@SGDHdtGyab+yU>G14Ww$W?I{10#qr+e+psOst{*9_fo$SBws z58*8~fI}T7@$SE>LvcMOZdCwfAL;iSWgjyl->SpM?|*i8{m3NwzDMm}lO*5Ap{)Q3 zzvutRJpVLh>Ki8d2jyEGzZ^F4I3DL-B|Hp~W@0T16}3}9sQ#%<5Y#@;##lZcUCL|X zW_#`{FXu6<#=+2@rH(5K$rh&Dfo!G>NAsefsNC`R69Wf+zfJKQBh6)pjR#15TV{{M z+;$n|Dyi72#o}ks#VkvrSu6cx&Cx0L8Ts8Sx!h)7)an8+WB}2k4-MnU*sM8dFT*G@w}2xKU@nM&L{{Ig|}YsaNA|&Ttih#WmtrTtsqoVn;@aSPDZPwQRySb z6$&uXm{4j^$@M7#vu3kp6q0$xtLj3vp+zo{c8PgQIxE!m6}E{&h*HQJrfkvUnxR z>xx7H>t#FcOeJka%Mjy5)9n_c-6a8;FH~*47+9b43o#BDv~k2nQr0a)V_o4!;%T?g z=F)qtIi1boquYse3A}_8I*=QcKRJBq`|KbGaU-S7(e*y;OR=4BlAo#HP`oU=CtBHE zXvzp*-mU9Sp`t^JXI%3e@mq|?*x`vSw?8Z(O7qBiKh|hGfHE-le`LzvWa00t2)<#+ zf6!{p35$>Onp&4Xso-WILT3+MVNaFI^(qVZn0&-^@F}Rl4WmpT?Ss$Q@LCp2c(KlI z$ypFI!M(UG<6JQ-4r8c8dqzzf7(%TRupuvqxRE}7_9Z3N)Sgz69}`Ycfl7#npNYyb>oHhW_{*{QnPmjoUuvCJ1c?CoEiN%@H`w8*nxy5Di9pij&RT*fa>5gY zCuHi!8Ecd;S|up2MB%`trLf*HTkap5NJzt>H}F@#nT>t`*yMr5&R&jC%~0aroYhi(&bcKaYG>HGF8K9)Z04gTDXr$&>v3 zSBmn{HWd?7W8%eHP#6$BQrlF=+<;BjFx=-XvnG-6Qp%{Zn96Q!6oc5Nu_U^x znA-#)jBq`f120>VHLCUGm!ZM2gh+;H`l)Mkkn0Z+o;C0yUhPZ`WGjJe3bO87Tpf9} z1Y*PAiqc#4yA+uOBABItvrZpA%R@aR*`VTM=P^*#!CSO8Isqd)77&w!dAhnGa9U+~ z)uKgh+i?_mHQ;VKBp|XVRWM9TeW$PZo_%h#`r}=C{j%7xXWToP)~!9y=cC$<5IJ3u z?Jf(*mOge;?xE#%Vehs-F7p<8o*WcTJ29<3NDIwe=fAf zdHC9TSV+fC%LTZ!9>w%e0seN{t21B@EYm*<@DE14ej~e&Q(k{!kqlzaTg|gxEWYGJ zbuSxHoUQb>B1d+h2(%DFMg^?^G9>2QB9OoqB7ueZa_>@3jDIGZu#mV%SnhIkEpV!( z04v5brKKd>w{O;U*k?>x`{}qbvi2+!9S(QFDZ+Di_;de0VB3pHrB-qBQTYaksUXdM z6Kx+JnvA4v9&zCYnq_U1+p}e5LGF~2elZ^YsjUfKGrnxXf#6m1`c!x*jesE-_c^1D zB?2vuAgua${t&kl(<l7&iZ_JL>E=;AGhkeTm(#c-!NM?5xlQ>{(AI49QKSfkqzY=j#zaXT8`4kO>Xnfn& zFLhnpRGUG9HrhVi^P@?dzsxJNRJ|&2^Zq->_w*ywbr-EYGb}l#9Ns;~$8hjuahxH3 zs)0REh*WdzxVL=}>1?C7^k(u38a~^cy9+PH$e<-s)mkZ8y{HVO(i5%&DItsF=1>gs zETYO&L~Bq`t-%8x>~-HvqyT$~=^_OoMnlDxFK5L*HjH|T)vBp3D$d0FK{EODD0^}C z3A;`r@6mhI3kI3DuAbaEJ~VOV*=c~*9?z`XnDytit2F0B&Q@QENWcoDI8zFiuJTKp!r+TuTw| zVN?Po?VWf4!Mlu-01}rxM9g-MW{{b@u!5J_T_Gpe#oJP3!jIJ_M{a;3W6?!|;4gVH zpa^H)(rs%6jBbSls&^hoH`)irHhQ977$Xf(;-0jS+!zsMSt68&!t_x+V;)7 zP?{EcW3!Jk*DEhC?Bl~1Dz-FqOUwO2pAbL7XJgzIA`HVO-cD6>aqHxsRqGsMh?7d;yI3p1n9b_v$`6LY$Z(bcs4wseMU< zxjPF;z>`q4M~g+t_qEmsQ^ag#^&O9rR`*jcxblIhSRQg`eDA_{TJ!HA| zC|X*7{n7?|`My2wKH=nYpb2fMsX$B2TTkUScUYnm)}jh;C1krG$5ifCCA_{u=ybJ4t!6KnlFX|xIuG+>IuZz-mA5H4XCSU+#pZ4 z;Bsx%oYoV^gt;=l?2LS_=PPucQh#!U7IY8MQgFdrXTxs5N2ouIkunb{I+aCCANr;% z63Kb%&JujV2{(e2j$fJLDY$hwurebah2;B@^QO6ptwNxq`zN?=Uf$rJ5$UX_WbM;q zV)or`;s=7kkb)0iK&D*W#FLEYipaz0_$Sn_bamHvnqM16hO`(kuQ!FkR77MoX?eUp zZo>1l^MdsKRN8kgyx>{=@)P2tMaM^**&7WAtUjv!KQDxDeN+;_D4m~F5B?t5k+lE} zl=#a4&TsC6f3W2a0d=o{aSV@juWojotj&;UKD@A0RmdO+q6eWaDDSa~%^~Ma^JPDC zt!GQckrr3gYC*qT3*T;bJ=a}tnCNb+E>Y~pGegrcubi77wEfq70Li#$)XD$+kI@1S}snT zfKd(DbGDN~ED&%cLGg71&JIMI<<@ji> z)^Kuq5#8NXu*CMd#f5Q!NWnJ2s!)P@x%x=#5NIS*WY^bmdQvY_{DZ>n6*c)O>#MV} z148IfGnwmFrM*!ji4l1PzPz)2uW7yf>Jx4Ut`%y-R2_zofer>o`zzTGMbWOzCxM%? zeCz5_YtkEx(Wg~YS7?@_IpEBB=^UFiG&24Z;ep|fjr2zkZm5g4QAVPh?gQdSp(r39 z!foQ^Rt6Am64u3DX0o#Qc8?&XhD7V`S);OXIV}XL9A?}I_+#aK;oE46EjeaHuUdtO zM7VFD(PhPPy=(JAWnL_R4DQtL zO7yB!bOn#dqpnFG-u}jox~@g>Q%J+xKn|5p@v`kB&HW{>vb^LF7EV7lr-yFwfl6{S zBzz+Cx%A2nsyw!J;>q9Kd8_C&^IXjx(!+>t<%`RQ;M0=pQZKyUY!*xeIBOz+)A7iN zKW5P`KveQ4-6g-X=#RHm{~DVP0(P2yof`7eHu-8qR13EB3BgDwP{uPwmp9C$gN~__ z>SmDhvx-WemO02w^|;h9sYGvd?T@ydm(xl;6hsYI_!FLy1WG(PRj-J?h%B;my7{ba zXE~H(2A-&xd*Ju1i!*eoW=g2OpCf=@j3|FVx37vC%@B|P=h z*yOf$OWSpS)X-&=4gzC{a+k=KSHlerAA3U>AuCIFL4&rrezo*9YHW?}V8Vgb_ zQs>Y)X-@Fca@n}D8Z)O_;K4&W6;otLOi6ae1o1`F)&8kej~VYUgCmkj6%vlwMC)M) z(^XWHL#gu@3t-NwC6ono^Yr(jAz&q(Ddt53c{I_G?NW&rQ^m~AEymcjJQ8GumLOd0 zuNbI;)jFuyU#Tr$m0L$fWaYG{8u7tg>@d!{LGC4$-Ff-8t%JV3IM7a_#>i}6t=b_zd69HA02)S&>Vja~lde#&m#f%rT8P-+E=j3p z`qWe7A`mt1X*@N8a)O4e^IHVF#Hw161i5q2G3g7FAjsEV`pKowcMvS`6fU65A6C3#?^iJ90dZu;n|KpN1`2 za_BXKZ7TI>=fcrSlW{fuR3#8aBN+!bapu*`?mSWOVsP%u_;zj7Z-v4$;|2?L0NHtz zkRQuV*`qh`kM=%b3@)Hl+Y(Um`J3hc*Zn%bCPO*$+|~fMeesqGA)S~Y!5Nf7JzG>A zRZX2}C%P@%p`tX$<>2&9JJiFnL|+Zkqz~5xD-X}YJwZM!HB4=)hkpDF4ky92=9elN z1etB6%se(~qLbz=h~v({VuoW8CsCP5GpP1{7OtD%w$l=UQYtE(36~D-^WC@zjWZk< zhUoWFErFJSpn8_+)E>3&9N$=_fxvL4VY_r4_Iczwy63FXUB7WEoW;3Ei& zGok5m4+1N|#t}{TByr$+2iUEYK)-cwA8|?HD6zzumlkoVXY-m(zFAEY$*m@IMYgi9 z&zE8u?jrT*bH_BD#G4Ld88@J)EppJVF1$^-s<*)<#iSN>>71B(_e_gk8_BA7%f?=t zwRGeNE1~ZBn;~}a#*O!yG?uYC=ibQY@1vBAL7RAOl+V3(N>*-dVl;3_?vl9C$)uI$ zgAu1lsJElKVqOjj-?iMeZIn|ygP>C8xaMw5jyE!ZGDAkBY&5N$1h`7fo8<@1w_ja9 z%$<+sUcf*=j|BgX6@C=6{7F&q?`rhdi;BOWN!;_VD*DF@Du0c=s+IqkgKz8416YqY zU#Qk2{%#&~R+y{*9azDP9nqd>I&rOk?3Y($w}}Q^(h_Xk{x?Ss*RPh-=yc~bMd1@O zSD;5FPrTz3a)O`sa%Nqgm-ZFV2G9KS3(J`L<2hA=9@+!@O*qLUw~K7 zltGM+04eSa%EBU1ILNl47aA9!^O>r3x&dm{>@|}$D?~CW3>1mVhJ@H!Fw%?#iPC5S zNd{W?CO&bjvE5qmE1J04Uefp~-1H~WMxfCJ2JVvQ&T8=a$HQ!qC+FCg;-=om-ej!j z046khOVu3b+q~0Ar~hJ{ibrukZ=sqX+8+~~z(pYAzsp+tgp!u{?lN}c1TH&OvO9%% z>p8NTE4mUV*kppH?wQ81FGsPLnW%70%XDx($xG67`-+@ZI86%DZdPbxYpFEZfaCl{ z6??ICD^cYOaSn#XP^#m;VD+tP7`F!HOL?l|cEE_sT{n!360+khj!~Q&AhP3+*7s#( zE%np!EeXpv+Jv9^;`e}eObvO3YQnpwC*LXf5>VheU^G=U=|%!ni$)!!w;J~p2^r@ zpvrFVHkp~ww~|ADkaW!*mfaA&a5$h-l66>c$uZ)ZXvvg!m8G8SSG%@VY%6iW|0P z!EmmYiGujGa_oNi<1DkbvshGF2a)MK^v6F>+V4B{kF4n(J3dG4a%v2y#hVIGPK%AqzK=+Vah33@1NX1wEAI1-U3m>L z3DNot6;}XqhM7D-0L{8}q(M3DD)OTjFuzVYkxonp`rKQv(u_@H z@ClIO07OltXgs1pcVJ!94tEDIU)+h>wJ=nCWcQdd`dLbpD)3oCj6iN+7=anh6+vRi zltKPt5vB$iX(|`PCuKbeE%+^Oi;$P(JVIfvhQKb@nLIxFDhKVUB1Co{)NfchGWqb9 zk@pr*_h5G#idCh6^K{Y;QCu`2SvD6b;1_;CnuDUc!D=xi_m?w<-QOO4mAkIDXg4R- zF5=)S(nea6|12sG4({4P8nBaDtu3m|RnUm|Mw6$;x8tTe>b=3SDN9qNLgW_X$HC&u z5%)ol+IYvERc1T^rtM-akU5FqM#7zZnaLRtAPv`lg2ei=D8kssWfTkLo#HO5h7z4kQAI5h75z zeUvqTn$p3EhM=JtWyMibbj>$L1+2v+b|e&{bn+z;W#A@$=IU~jcI@#yTapca9l6=C zfVMolNILJ3!?+7xTQS@GrB40P5*-@a8QOa1{>?k=#hts)w5noDwhKjZ8`Db~S?Fjq zvK>hV;DsaRW6=%7j(j05U1nltu7O?2Q&bn+d?(aOTJKmK1|=0h$4h(Ms4rVUxp{bwo#IVSY3B_vkIvm0L5wA*P!ieB<5qr z&S%4_h?c-`7|saK%_$4whZ{2I;7m}(saxiv6FG2Q*Qh&VV0~m;F4}adG~=ms_8JRk zgC+`b#1qcXm_^a}wJl(JEEZ7HtPQ;k>UK2@2_SO~a3-oy5)(ko8`Aa!#%?2wuQLym zfg#n8?qpt3kNQSqYsOf=rjR@I&MuHeOUNFG%uRxwLPu46& zZ^Y3uby+Re#PBR%OKg%$>FxyldI)VLsSlJOMY1*|yT}C$;k6XlGe^>4B*nG?p)jxv zT5ac_M2tIj*?PU@Uabya9$NAfWS%E_H4TqK-xcRF+R9+U;8k+H%CTrC*m_oC%0*wBf**U5e$e?+k!p+Uj#-3d_Hzi85cB<~dq5J4_s(>G z+&|VxA-YLt+ec|hh+-vHx?e4MH#q>-H4=ySW_);u^}gMtIOwi#x6`w^42|@(f6&kA zeIYQ{6=$aZc1;lCeA1!X)w94B!?qxf<&1tiB54{?PO>_E>JVY=lo_y5$>-X z**x{F=sVi$&(pQtKgNki%gK#Ity&CE3vYB|-!NE!vz>{?6tKJ)-9?$cBv|5(qsy`Y zi+gCd*{?pT^t!a4!9Sutj{zd>pL!v~`&IL6fZa<9;xJUaOX=5Duz@myfnoW@e3f(AO+YkfVPEWc_x zA%(rC0jvuRP4`vxZkVA5p}SgY796e&5r_3LC^1q(7`W$JRIvBDHo`Vy> zy)S$A{3?ST%@bCp#~gTXgrzfF|K64zfy*f{^vuY}3Qts&I^Kon6qpf8RG+DWW#>u| z?0pL{KM&#q`bXlG)$8`(3Lc}XDcXPmI`~oB{%NUy-$VD4>H@$-XS(0#RSN-D<5>Sb zE%<-xqQm>Ks(%FW&6wcF2;aYUcYbT1Jo+6!Y0!H-`oAuWcs%dh6xQSSpENK&o-bl( zWoW1SAIv-^tp4lA$N4#Ce%(iUe9rHw`jejB$LAKXwzSl>GWfr=MgDyl@YkN*$J76^ z+UA!?`d>Wy|IpES5c=14;Ga0Azs(na9EbW_H|OKBoPVX}_hH1pzdF* zxE=w0&woE@w)+;)_e$}XaQ6KR{e;iIh4U9R@UJiPeM#CS91zgovGzMt^EoVv6hDuT?S%FYh z;u}1aMuRA7|3WiOU2B8n1S!*RTBe;bx)-zU1lVdtVz)9jNi#8xwKD$2Hm7t-5v z3b)vraw&8)j;W(9xL9z$DcD|VS`rfV>fkc4V zp$H((_n*IL>ElZ?Uq65?&C~d2sL~YrH2Bbml^^#*aKA zwq9wK?5%Tx@1`S8tF8x*rFH=!4!iXUkpzllCSQnaS6ogoV)|E1-;UcV&}BZD8{!gjbsU z9S5|B6X-X^Sh2{{o@D2-RlXh4I`iOQl?o-4I)1JqTuq|7O1`L*3t`*R=8?A-X6@cg z@lk&A zcSHBGA1sGC7M?$a-bLLL8iN{jx0mpIDf#Ywk!iHTC?E2z*lJ6sUw4d(#8bc~KgL#K zaecRaGgPMFThrI0z4ji=Ppw@>@*}!36&sB5z+!4SD6Q?+DOBk#SWgg)CMKwG*J+MDwGE=Z+4!=5nXYZvjw+ zW);uX4{u@gqrlUpHgt9}=&pD{$0HU^%6l5{FNSaBUzn!fM;*Vk#EY#b=&S3@TDf;7 z&e2$Y{d7vq=k3BPA&orVXSOJV=n}`(+>3)!*yPM9C+9NWoMtuPiEC4L#p99Jc_@-%gAd) zh*Q?0wWS;1z^46x(gQd4_DooNF30tdBIE_LlWtBX$ik_1%&Rg<2K>r>N1a{E*jn;A|0 zwNxK#+Lgo3>J@Gij`!!JIkI1TOOzkfccW6}#Po+NeTk1J;;F5~3+7x320t~WUn$)0 zo-nUU^rT&`%_X91ZYiDfe@M~%+P2r;%pxU}=pXzD~o!CuXAJiE`G2l`a=8QF&q57(*-z zM5xH3;XVz25Q&`lB~aU0mjZ5|kBBa>b;P52$BtqWGOrrNH_M*@7N&tmV6h;8VM}OrW z`f4Hk8i50%%cVQ%kp$hnx?U3qCGyBqf>nt+<7L{!4tDjHM>L~@H+c2f;yUo{%=9PY zeMr+{;o8TNVNK?%s1OcrD6vh3@_BW@;nvQZ#n_+PCRP)pW#I3bsn#B;M%+P(l~#K^ z!8D}ZuuGtMP_+jOH5@jx(uPnmuDE(iB(D8dgi)TjdVGPI*M*j}hDfK>x3Z zkOE+ql;!tB0)BGSzlt7w6e0g(w@?mNq_sxE*Ya~1HV6UHe$>S%KGgMNl!?*KQN&!) zNa|^wwM>;Sj8Z*xJnlED4A#?-q{elep8+N&*}{NH`Pp{kwPD?ND(DG1X3DiAMkBoF zH&1?I+4^AqI8+q^|R9kWv39q2X|vK5z4-tMeeGJL>&oD5*khf zSL#y(Bdo|yh7=Nk&DFaBaz@kCh=G~T5By;V0`XJ_ThZwE^=A(&FG9D2pQcG32F?hty6CS-9ebf4)bZHeE9+!$lTy za~q2zmPum;lbOqxkDj0uV@-iSzyXu!M%#en4~bWlpX5E5isTg034@RUaR3L=hS7TF zApAj}Z$I0)sgsH`OjHAE54uX(CkNjWqsV@)RWe}Dz%lXEviC>(ize>8@2p~; zlLn;1u_Xx3u9-OQ2P=THd>OrX!!cM%X-Eh~lZvz9z_bZu%6C_<+vl03wb-gl7K$jh zK9_DN6r_e{TD$Bo9Ksp^Sv+62*(9^3{XD=>p6_9eQ=ku-3qKyb__M6dp!h1w#R+;` z96d{H1oW*&1IS@G?Ykt)<6=B9t6uplWI1-qrUtNYQW6F<_j`bs6$Rm!$?*>KCS z%SR45sORndfep#5lnET>RT})>+DTcP1=40m;zsPl*UQP`&Fq&z0P!Em{9^_P1^i13 zL;&RQbxY45j>q2_;E#^hU*mx4C#)D@a~M){AS{a^Mzrn zAE@GiZLXx~=$4xk$F*c4PbJ%?d|A}InY(Z`L^4FoMyQM|HKJlIvgTKwZK8PdC<;ql z9QYbglhJmJ6G5TJ%W+ZXeNL92-8lij8FjcrwNgr1yQ`M57V`So15rL{dkh7 z4itnl5L7kU6w;RWK`L@{ez!|bJBd`SWYv@9=_)XU%hy!(Eb2&h0YFS1aq(j;6#+EU zFNw)-i?eFfyb{xIn4N1TKdw%Nre%GFMtCXsRt8kY7_>$4;o>?QAZ-U zN4<>*jib)E^Z zz#(itL3|C1K~=o50VI>vMh6}Q^)Pbj_++WD{yb8RgITy z?h;>Li#78-pXEak5d)IT9`(5TxN@fSn40FnRw)lN11^f!=)hb%VXX#i9ougD$}8&A zZIj;Ig%)XWUQku=LLwRL`5cUi{y2kunOioe^~mu7`@Wqok(^^dn6#zCQC}iB%C=d; z49mU<-0V#wS17ezuAzbKl0H4ted|<ndm+}}nfJFslK<>i{&o-5W9aE87er3ns&qS`8R^3@1vU?SB^dz&wh(_NG3hzD z)gi-PLrs;659ab>q*x6f{ku;S+Q(l$d^}cH(^wB4lpFyO#ZDt;MHROT}VA<+YEOs zB^aLmmT`vY8d;u_mSfV3qo zUHNk)>C$n_+n4d;=m-l(qLXLoL{JXR&O2;&Vz5NM?cg&44<%8+F5o1&PlBMDdVu#q z0!*}9{TL{vU7-8d^Ust5Cd! zs6&6JMITq%R6L+UBQ}nsCWY@Zv%~rNzAnyk-c|2rCu=;m*jZ?_%TgZ=EH@9crT?Td z5H0tjhR=nPAWdJ)53c2-Rz~3EtEZM*;0vG&2vB;>dKFfQy!Y-3AYTZ+AnDkGE;mhf zVFGJeta@v91ih5AgQ!o2?HB3u7U5U}(z>eu1UAC?QE$gJ7k{bU&7Ngrd(E1Ge3oPf zW2X1hrs&JoZbgxHLHqFB-GM~ATgpHd)>q7=1&er3!_s8p*{FQ(U&^ zl{r7na%yr$cp=YXoWTgFa;_Izp-Rkkq2mShtHLZK!djcvX;QP#wT8jDsHNvRvJ-`d zXRK^dpN|Ac&CR1A*%2oeeY#I4k&y0K6z;Zpb0)D-GJNL&Udje~amnHjXKX- zL1SHP)j7B43%O{NLCskcgsAMkVanV`Ldq1X)`Mac5%1`m~ zog-{2F@q^*dL~pd$IKslTe_g%J-5bK#Hzj5d-(wVXr!<tRrGbkgW}3iI0|ajbjAwiZOTj#3K3zwx&vS7jap#0p)>2Cs7A1`H8LCZZ-I) z-2jX_^4K`CPUhL-{Wi!Uyp!kp#u-c`)2tZHQ>O6!m5c{QgnO6q(uUKv(j&|60X+maX$~D2k18X92zkO z9^LhpT+Tt$sSlsA?t%;FoJ?d9hG}tH<{zD(gQ%pHqZyRP;A5q|w;OUYV9&xZ+@jqb zne=+3?mObBJ1qcpA8Gg-bpaRc-$I{%j}(5jNAv)ReG^Mvz+6xM|9tv7LG)iEg+BuF z_YG&?0g-2Pt75f`mOxl_DI2m)jzrNG9SQC>$fDWUzg2^5T#wdJA=5RqS|~8PlAV z`&vXwS(Ad4z#!+o?<5w2o=#~n_RBtIdB}u3tjnRjBa{J;6MHo*9f>u(p(n?5F>@L@ zrC1h&Tc1Q^t*u-WzoIjpF;nhNj9PW=G291im~; z-XEq#MZS9-qPFegaBj71p+BP`zv{#L{pGpW`Q(#dCot?2jiR3ec<>RMKj-?Nf07sZr7Ya{aQ@CKf5Q2u;OlEfOA#Ij@|S>o zpX&Q3M17NW`K6@ue{=RX!um^Re~+A>p{gs6P2AqSnzV#nM@Q9^#2CwwLo-;l2DrCJ2-`QI(~ zW6l!Lso4uH{`EyV)uGkA4_YeF+4 zvVAw^)CUOTzl9E8)aj#oV9(=3%$w}O=Ye%Mv1hGLe(9ghog77s$hP~we%xEAFDQg< z&u&wm2qpld#N(<8bxsMU5A9Z-jY%);?lOoS2Jy|oQ>Raz=>~}i;5}$mp2!6us{~_Ghatl)jKo#k43H<*F$WMxZ{si(Djqs1W z{>Y2p^13%*JIGJ2^xxOF1L}1i_uX4L*nh)>k39b~4_QUSew-cE^SBhr)fdlZrJ9LL zfYxe1BSPT7AyM~@Vz~^ioCsqqu9?%#u{$wGM!o7tP8n zHVfUhOZ?3UJSOkTfvK?@UMtDEO6C9`ew)n#=qyc*dE*qCP*cK`+k+{fDRq^- zishbq$7VRj@?8yt>ldxMh&az6#&?24l&NpJwnWGbwGIZ4+#^Ivqz02dGj-f^D5w>O zXDPkN!iFKl%JT%qC8pux4yoS)se!#*YFL3RY|v4kvazlZ*NPoRxCZxm>wfH3`XsV) zi!E(X;C$Yj@x|Nr?CYGckpp%kbnEeepCvhP=Rtpa+sGZV0g;YIM|4uXawDw)E#xPu}4RA;3Us$d(SYFh0H zxmK+j#+jCrgx@a9#<7xtw+Uh#73w^vFue-Sxx=lYQZw92EdrOk;HqVVEwOCVyBQ)k zEl=4WAZR>_w5tKhdCN3|3^UItkv>HL45_Sa9D7K;44izsjThXj0GwE~n zX0L3+lD~T+wz9u%?R1H$=||Bi#bRg(n8G*4yk)h9M&LrJ>ljqb3V4?G!bTBN*GCuK za>u^4ZSw+O=B`pOr==JotAHHnKPOre@eFI!=b+cX^206%tk&u%aBQNV={H&QeDT&Z z@vxOeV0~K@hWoI+tJXt+HFm7Ks&W=K#g||zqwG0iMP7v!ie>Hjxg)iX#jFK zgP(>;FPPsGw=~V5x$iCHrero`!Rl-e_KD|CnC()|dvv!}D;QVtcr*yZqx9HOLsS3u z-VUNYsp6`cmCL|VRXGXwah5JKc+V0^NRv<%71|MV#{dk@vg>)0=(*>#IL{@m(sSle z;LH!fU_)E;Kr_@J(6rylQCEeupdtDwi%$RrXxMn;&SLhUx0Cf3hfa@+zzGW zSf_^MP2QS#Pc=`5*ce|j^_poz@OFNbfmfSM7tsky`aXGc5+Vls2hnxJ)y|h`$$Hm= z)>Qm*nqFnqOa`g_-GbLXI$x@Cbdg`K))H#4G=7Gb zak$Pm;mJnQQ!jF#R^%>d)gK=fCYyrK>eIQ}t)<8w=Dg`GJl;irWfFR@`LZ-(Nw+)c zCk$-OPx5NbEf0=_jw++LHO(q? zbC#ak4_}kUpSjElH2_7mkBa-}SKm)=j6YPmsy@I;_&;1oe@~fyy;=V_9$KOjBYdxC&Uyx*7p0IJLEboBuxvEN)(k2mg5uBt(0 zxyM1-fUAmq(=Z=wm3xe|9Aqpzf{=HfIFNL@Ue>xKZ5F|j>2>Q?jC@`7H-n?gDu z#*ap2wt}#?0mbN-O@NE5($CwK(~KaTya~ps5fsru%ZUa}(V#I8T78llD1#qx+dXJS~8ZHt7)2H zBx;b!cAFN;yqK!FHt>b+d4rMN^&-!@?=q4uoxux!-`qgxLjzG!ZTV*Y?n}mW0e@WD zop`uw5u4AAx$o;chjtL)iyk(VGhWUg!A|f~4L>OZ&Y{5X7ANU@1DvsY`>FcaanZnf zr0q>6!x^a{t74J`rdhTQQHEX;eiCqPK7EjEkVeCyiJ?k+*tSM?C3YsBjna}jslNT) z&=Ch)cKz`}4c9PN6KvH&aDPCSpPHk0qxH6c)@sl_^HXzQgDsicI|-@o?iwnmDI~Ll z4&?Avg)J}a_Hj5XQ&BaCq48_q7eShgN=y`NpFsyPdcAzeMc82WZM|DEI`y*5 z*T1ygge(~L`8gXJm`MxwEiKi z3eKiR4zj;xGNp8_bdCS;03Tx@|7f*7y4>Ge-an}@{{xtcq3$ zzX{;{tNZt(hyRIt`NzY5yA|q}JcjQd|0k}`ALoBxh5P@TiPn zQD){ZmyDFIzKN-oA)s*H)Xv)Kv915tlzxu#ycJ+M(W`3}dVV@&9rD>scOM_1MM`NZ z3p_~M3KJh72B`>3Qsn%zwN9wBW3H?)8dtXak-fIu-qn+Vq$Gj9%!%&uP78_mFT~iQ zFFWh6DA%RUCWj=eTvozxA^et|I>zYiC{#_W#`(7`+Pl;#F$*J@)zRK9ps^F_5>1+Q z8hO*&;<)3}d$2Ch$4D@XGieHPRqG8~fJZhTz`@YwRu1b>KXaWl8I-!}h1Wa*(PoKd z6%#pdj-a2F+X7r6-^|ZuFAO% z0ql(jgA2$i9&r8DSVKZVj^gv4vij;}9rFt<2%IHsnW@!L-%ZRAArJ!n_scVQ!k73& zYzx483G7|z40g#Snb!6rod@v`)1d3(g_ar3LQaPb2wFxa{lgBs=jT$V(-VhxSY6kpS-16#iA}@iyEk0 zpMg|IF`pW|bv*(ujG51>VK2i!%+hSo)MGLji`5KYz=lQ1fT}}j%BOdO(@~*JpbRTE zB1lhd{(rQ+V|1lkmo{9nQL$~?Nu^@jwrv{~JE^c@+qUgg?22uFsnh+u=k$51x=;5Q z-=Cd~y?@Mc-*c{OUTZR1T*TXJ3S~ac|UC%`u$*iPs+s0dYa5=r=Rk^}gvR3;VA^&`C0}oilX651_$uEj;$l-O9OaraGjB2G6z|0fzHkT9QctYlO}q~reC4@gZdgG&^Md)xLgn&! zehNDfOyxWwkf-W$I+G}72kMubVQXIdFQjkJgFO>p}QeK-v zH&zJxR&5Q$#UhfQ^>T;Bt~ek?WJ%JmMzmRN#TcP9zOJj__QzGz zKE#W{g_?5ePQ_FX6-WFGx2Tt}gsMwrc~D3pH{-EUl@)s~6p#?q%3+_FZ>N06>x~L5 zo}Jx1SzAP7FD&LoETy$5Kb3J`dSlLSlYN2ht!=)MUPKoi&}I+K6lX8 zZ|`nd{8ZBt78Q4)y&Xoz5nmuAhatR!DJ}z%K9|y47R|sBI#t}Mq(&@4HTiAH~Vz5k^n5>Zf)`G+X@D^Ky8SoXh=T6J^dL(>S>zJ&XT;yZ*4VjoRRuVNJVhC2=2}}>mH1pH6E&Bh8q$} z1ja$)^c!Bg{-dYgYdgC>2)+-#!kB9!qr8GpjXYE!FOp-^4?;fm1TI*ocqD+i=lS5q zkpD5D)krY#QEtdRLm$VJB{a;H%ZA`i;&UX2d~0pF{CP{4kLPu0ss#W>n5y|)GR-7! zwPA;XooWi3rNK$gq=H!Ic@9yM5>|MC1wL_datz>TE?^Ds`4U~x7&IoMG|=1f21^ui z{)S#h_QEQi_2x-mvP8*4qQ0Hy%1&-+KF9=>1|g%Wg^}^tMpqZWcVrle52&Dfg&v(O z-$UbLg{*LClJ&%y3LTb80n6NJEbChS)^m6+%o2Fi zp0iB&*uE+&g-4lNj?~O3#e+N&9yoc(X+;Si-N?I?s-b=@X*!oDjOG&5Y^zN%D@#AgQ_wbZ4lSkJuv-Now+;w8h~~89h{nwfdLzsg%_u z_q1aiLF{Y5Z*tuYA~sS@u2on7!IrI@G+|0lhdh`z>>RU+yh$>6^;3kjeUan5@4lGv znHL{BD#TY3sXD9gu6-u1llI5`32F2m6a)$HME>W&|2?Gr5A;;f&hEdY&;Hl!`ZqbK ze}US2INSKYBzFJT0)7*g|Ca#%cf@=rjHbH($`Spa2=H&9`Tvyz{tWv6^T_;9@c%oF zC;K%t{}&1WrPJ+ye2%|6fVTG<$luJlma%Yr*TVnnd9>Cy|Br9}vkCTZj==BN^>TsH zBUbOVj)Hfup)C$5Ctw0*H9DFQ0EeLX2H|nx7#2HV$f1{KAhGpUY2C-i7u@#!4r~}l zRggQ+qbhx5&0krw2*$qCA7jLliH3nze;nT&8;ojiQ@9n7+x-%iOIZt@gi)P4bOmiW zu(cdlX%hbZPPXA%H_3k@oTg~_{F;LfTWeC!-FHJ3vuv_2n!yBJ-o<9&;!SK{@QEMscp-$@~<@k*1SWJwT!oqWH=_vWOS(Q z?fPw6;p5p69;{`prT3&-45* zL4UcG|DUA%dnNX-9_R0u=l_$a-)R4D5A-K@{67i#O~>@#g!~oF|B;x#6X4&3eg5o| z{i}ZdH@VQigB8O&7yr$EtUrq`{v}NE9kBkW!uUI7{S8tj$Z3lA&>?wFR5V6W`|Tg; zhCEV4uy|xCB`F})UV5CJRe^PhO~s@F*f|$Dr~Gnf zsJYv#a}d?$QQyZ_Y1e}LQHwe;ovw#5Hy$MtJ1{rRncslAP^ z!+WpQKh)WrqNMc0@_o^*<0T3sD(Q8C3^y6S+I zcV88V#yRoD{n*tq>lH%P2&3VKy^*1xkO2eyz;GM#lE>@>!>jI)TuJL763AyO<)SaX zxvO1wRBQ7ad6VoZF8qf=MG}HC9-ZPJJo*YDVi9Dyz+p3}q-2ji*MmPQ;^T^M#qx>h zcB8k_ndUSL_etL_CdO7kh!W2G&7v{{A&u%r6y=AUgQy!e?iGhE^p`71dH_2MRkbUJ zw>R#O8~}{?H=3)I$R_sd2uD=xosSbDqn8+H8vvkP7u&h^=0MhWGQ9*`umEOsF5jI; zhXkm*q7ZuWXE@n36xs-Tbf$72S(o$6HfAi9Lp8qkw~Si9EM`3*kAoVuSd?2f%`Z@& z%`5eLweWM0U%~V)(nt^WQTxH=>W{8oFEToa&|xNU9}IV@I<7BA_B%*f3NEkCv!vZ5 z96)a7><2|8ecdC9+YT{y+{3s};}v|}Bek@^I*Pxw%js5yQe?Bsy}9YxczD8+iqFUX zf%!_VuZw(LUL5EyK`m&bc(;lYg8t#-}+DfYms!- zPV?@Ue;Vnp&3EU0CkWsF&3t9vb6xMXkpGr``VHdb#Y;+e^S<}#ydc}>(qpu-WXsOR zk=*;@KnLfgr@)L@)!?G>-=A5vAl1iP(cgX;x^^`-UTdJ%MB+1Zfe$hkknbWqq_7U6 z@XYaYd9;|+$>Bmk$SI^_6p|k#Cxw<1iuWUp8Fx;h7c(@)rzM3r9=;Rbc^s~=;2rMJ zLH2E9DI+g%gYPlJewZVUxgD1qrFZ`vyGjSjKL{a@mM`QaY&mu1DPhW(YFUM<5Oe^{ zb4TLE2+~tD=PiY~y%SV`mp%{c?lza_P?Df*?nVvcwBjiL4SG`#N@P~((qCU$qCgWj z*6f(RM31BFGRv$1m}H?XnnE*G0?c-~@eBbY(>$*i@D4Y=@kG6?AAh0s0yAR@3(c$$ zwp#8^dX`zD_4Uc~)RRM^h*1t{kg-9mHE>~5;B-=Im*d*?bn>I_aboTj@Jh`sjfs(9 ziQ^l9Zy^^&w4#!%H*`teW{2KIbD-VD9R%pi^z19_mcE~RCN#V1b(_58ePgD%n?&x* z92ug^+_V=#4|=`9;gpx^h(tOEl12N}JgH;;L7C@1Hdn0``swr7;s+9~|RgwY-np#`Hg0D}ov;^epcGFoi{1jJqKsh)r6Q)PXeA2;If-@8kikA-k5ZFojS^)mECBFu2FcBBVOo}pHZx>M=i%F zt7G`W#AbICxa$)V`j(L&Sn%&#U9WYePzG+P5K|!OQCiN?J zAOk=J;MN#ASTJR{5SGbfpop0kJf*Z#*4M~w@MHO)#%U^BwtQv$0uCha%|B#A==VOI zKng;v#F|1%GH#T@f zT3fEUtGpiUsnL#4y5r`A2z~cT839q4W>lAt@IAXPuO5&qHGoKEfR{?G{DpvzACF=wdq$SCdh_u_cswH zkf`3f4<%fcu)PRMiA@GE)l9LeE5lTI3kRN|c~fTXJ9w4^GeYHD!e&9+o+ETa2oR)5 zdef4c7xR7$1Bu0CPs!^bc*WVwhhYOmx$F2f1y{a;K8mt_jm?|ZV{_1a>b z9%!MJJk=IrQ0IyQ><9Ea`-z=wPnH4@V2*F2%k2%^l!L^643iP(ClNcIsGF*(R$>Cy z`C$W=^qB>I)U`2J>MLoYW3I^!g&wtAR4-o$s6l^d`HrfAgXlQGim8rCZTk4^B zTl?5(EP$@a3||RReG>9+`)>WY&rz$b8u7IuB@h^hjo^jnM zWmF1G&I26v@6wRRj<)M?4)$~6H?ghq)=cf3h}JJmf~|f1fnXlvj{za!)yiDk?vUWV zmFD)tkMeR$b>c3l@uhiR&UMO@{@z0a9gF9V2YAJ7;lmryH~qA{>Arb{Dd>-HSF|&n zyh+j`a!Z7UmkO^OZ3WD*xInevqIa{9JZ<_>?%O`7cDWv`>ai>6vPo=1Gp+Gb3HD2u zwBA?eSD*EcJoVE=2x$g4%@#fT1}p&$0$^tE=#0XvP4hldr3X#f2grA%O1&-SO?@`P z+?($bcq2m5mYk zs4I_;?ykyk#vuCvuRU9MZuz{>W0wpx|AaKdBU|m;*g5S_qH!DFb(;HLr}NVb{MtW! zeXrnQ{hx@&U;M+b*u{V2DB6_OrFY&(kbcv)9Tty6#{6zMS1g;w$4ji%H64fyM^(&K z#kgHQAY~b>8*qQdU2kto!pL7zJk}GA{cXhAiigxgmfUjFnCAP~uuA>c^B)n##Keh| zi|tJ$PHW}X=2pi=(-!Aj`QcX z10EOa3E1du^p+Z2sE?UBy$fAq5dJEJ&9#i`opds4r}2Xk7n8l(3Syv z+Gd3|Vh72SOtxYymC8t*lv;X%k`l6*07XSIiwRI{*A?(NJ1-><10M`Le&;y4f^UGV z4lFK?2xQ8ln)o(2O0qGPx$1^FpLBqT9G(;ij(Hu^`7PQhYw`o#fdeQW8I}>&gnxM{ zr&pNoq)EIX2iERJpN}G41f7sdVv73hwq^V2#&+&Un^cy2HzZ?;Oh{{`a3HZV6d!HZ`(S3GT1|$jEG7ennn6%wm(OFjDK04QEIvnpPwWyd zh|y@orm|0=`Fu+MHm(-=A~k5#NS3osWGdZ`%~E~sKF>yCxwVPYBarO)HKtV^PIMSe zko{VRwm^B8=!R4JmO+(rwjMORn@W>1x?YN~kcL;$#t@8wP_d6lP&|%r6NI|0lO;kO zl@rwupTx)N@)$nolA{cn8S{5 z{+3g-j!hO1+;ueZrjtf}3)On2r*qpI<@%jf@|?g7xWhMYboXwkZXzi=NC`C13CYyY zwfgpiQe!BGF(BhHj&HTZW$4YE5$eSY6xoi+rkBPB-4cbS2%4y?2%POy0+RGpckb2< zNiObira_t-cwK5iL7?f@HOGZhM=_b;sv9@S-TIuKxa@}q z)#UU%!_F(?ik1`Kj=xllK+N0^KnzI`pVu>$c3bT}^=Z{7!MgA_U$1~S_oKW|U|v6l z19w+Ur2SfDAlq~#wYkyr7|wJT40pgHBo)&Wp(Ltlk71Ts7O2wu6zl-buyZIyvLD7@7v;P9E$$fhs&my*tLp<$<-H2RY_}&)MBw*pM)79cH!@O zJ2S6#kew8HpOO-%0Ueo=a;V#>8Jvv{eUhfqsRb(5$P=y}aw}VHmjfD?KM!EDu2-lh zy4J4bH?%DHx?WPOPQwm zx|O@nTPp|8k6EKR7^h3q9PVGeFYFEY=NbWwpCb?!hFivVL0=hzX2y&+d-`9jxJh5r zEO^c^7w;o6=q+v<_ORWsAdQdSJ}zBQ2pMjXphjdZ=(=G`O|?UmM**e^Lm!9W2gHQ9 ze?uI-?c6hNwgqU!5Sux+7f0F^cuSlq?NFMT9MEF~wP_gF-_|8^_)@V#y6Zrg-%+vl1J-z2J{zB@17V`Xt)JsNI!FJO@ z3pjfR4qQU5HaiGHkCG9AQsp`A5CIk)b|4~~G#y-@N^xYws&&bh04uA2-1AE%P@wY` zFAUUrf1hV$iW4R+E!T7#E+t26wk0*cs=ikb%ev=yd%ai}}kn+#S z(O+*&z3d-8aQvG`{Lg;ue>HCXoV)k0H8}FFRt_eH_NH$CC1CW^Df<699WkeFDZR}G z|2ke#*$AghWYQt*OxabP*67JUawtU^P;a#*Q!(9$$;oTo=iPCkj=)JvJ!_aGR%pqE zGr`3;@m&(MS*4mUlTqmh1WNp_yL;RaFm{fgjS>p|XODz1_RZ^0a+&eS`$225Sb0o@ zUsj-E?Z5U8*d?a8f)ecD&?eH+sOUSDeH@_QOheW<*v`&;fcYdqsg#YjSGYqYR~$L% zU?C(7CQnQyHr#iHMNHIZNTQ}Eu3;nRp&=&i5>S52?klcRsrQNRDelF55=f~F!AX+{ z{Cg`csaMpzDX4m0v;%f(MWtiFFm|$M zi}uT*Jd_WgV+WWp)c~L-D+p_VncYY15~oy#6RLQ>L0=|0k`Z2~5W6JC@L&IM4+(sA z5w&yt_`<70l%!(7geuF|)QT0t9w?|Re(BgBJGT(N!&-^vm*h}ftr2J|1TQ`Xm@S}4 z(@9k>5MkNSSa|#f?Jvu$?R7=$s6&XDcsj*#jKNOHJrA_-TFT)`c&_oBW!$!O@6P;Y&*5QVCdOzdWuxIOtf{(t&Zv+s=SsS9^?#2n?J& zGF?h`8bmGdE)nYV5};1f_hIxekW$qSFnY*%)5>sMCwI{mB)S$f;g72xCPc-xh`RSB z_xa>qCB+yM=-V7G#irIaTÿL+Ybeud}|lJYVT@Kj$qD;afCR}=c=x=?dk@z_2? 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