@@ -630,7 +630,7 @@ fileprivate struct InstallLocTaskConstructionTests: CoreBasedTests {
630630 results. checkNoDiagnostics ( )
631631 }
632632
633- // INSTALLLOC_LANGUAGE set to "ja"
633+ // INSTALLLOC_LANGUAGE set to "zh_TW" and " ja"
634634 let specificLangs = [ " zh_TW " , " ja " ]
635635 await tester. checkBuild ( BuildParameters ( action: . installLoc, configuration: " Debug " , overrides: [ " INSTALLLOC_LANGUAGE " : specificLangs. joined ( separator: " " ) ] ) , runDestination: . iOS, fs: fs) { results in
636636 // Ignore all Gate, build directory, MkDir, and SymLink tasks.
@@ -653,6 +653,230 @@ fileprivate struct InstallLocTaskConstructionTests: CoreBasedTests {
653653 }
654654 }
655655
656+ /// Test an App that has a directory or package (not an explicit bundle) in resources phase
657+ @Test ( . requireSDKs( . macOS) )
658+ func embeddedDirectoriesInResources( ) async throws {
659+ try await withTemporaryDirectory { tmpDir in
660+ let srcRoot = tmpDir. join ( " srcroot " )
661+
662+ let testProject = TestProject (
663+ " aProject " ,
664+ sourceRoot: srcRoot,
665+ groupTree: TestGroup (
666+ " SomeFiles " , path: " Sources " ,
667+ children: [
668+ TestFile ( " MyFolder " ) ,
669+ TestFile ( " MyPackage.myPackage " ) ,
670+ ] ) ,
671+ buildConfigurations: [
672+ TestBuildConfiguration (
673+ " Debug " ,
674+ buildSettings: [
675+ " PRODUCT_NAME " : " $(TARGET_NAME) " ,
676+ " INSTALLLOC_DIRECTORY_CONTENTS " : " YES "
677+ ] ) ,
678+ ] ,
679+ targets: [
680+ TestStandardTarget (
681+ " App " ,
682+ type: . application,
683+ buildPhases: [
684+ TestResourcesBuildPhase ( [
685+ " MyFolder " ,
686+ " MyPackage.myPackage "
687+ ] , onlyForDeployment: false )
688+ ]
689+ )
690+ ] )
691+ let tester = try await TaskConstructionTester ( getCore ( ) , testProject)
692+ let fs = PseudoFS ( )
693+ var languageComponentPathGroupings : [ ( lang: String , component: String , path: Path ) ] = [ ]
694+ for pathComponent in [ " MyFolder " , " MyPackage.myPackage " ] {
695+ let bundlePath = srcRoot. join ( " Sources/ \( pathComponent) " , preserveRoot: true , normalize: true )
696+ try fs. createDirectory ( bundlePath, recursive: true )
697+ try fs. write ( bundlePath. join ( " Info.plist " ) , contents: " LocTest " )
698+
699+ for lang in [ " en " , " ja " , " zh_TW " ] {
700+ let path = bundlePath. join ( " \( lang) .lproj " , preserveRoot: true , normalize: true )
701+ try fs. createDirectory ( path, recursive: false )
702+ try fs. write ( path. join ( " Localizable.strings " ) , contents: " LocTest " )
703+ languageComponentPathGroupings += [ ( lang, pathComponent, path) ]
704+ }
705+ }
706+
707+ await tester. checkBuild ( BuildParameters ( action: . installLoc, configuration: " Debug " ) , runDestination: . iOS, fs: fs) { results in
708+ // Ignore all Gate, build directory, SymLink, and MkDir tasks.
709+ results. checkTasks ( . matchRuleType( " Gate " ) ) { _ in }
710+ results. checkTasks ( . matchRuleType( " CreateBuildDirectory " ) ) { _ in }
711+ results. checkTasks ( . matchRuleType( " SymLink " ) ) { _ in }
712+ results. checkTasks ( . matchRuleType( " MkDir " ) ) { _ in }
713+ results. checkTasks ( . matchRuleType( " WriteAuxiliaryFile " ) ) { _ in }
714+ results. checkTasks ( . matchRuleType( " ProcessInfoPlistFile " ) ) { _ in }
715+
716+ results. checkTarget ( " App " ) { target in
717+ for (language, component, path) in languageComponentPathGroupings {
718+ results. checkTask ( . matchTarget( target) , . matchRule( [ " CpResource " , " /tmp/aProject.dst/Applications/App.app/Contents/Resources/ \( component) / \( language) .lproj " , path. str] ) ) { _ in }
719+ }
720+ }
721+ results. checkNoTask ( )
722+ results. checkNoDiagnostics ( )
723+ }
724+
725+ // INSTALLLOC_LANGUAGE set to "ja"
726+ await tester. checkBuild ( BuildParameters ( action: . installLoc, configuration: " Debug " , overrides: [ " INSTALLLOC_LANGUAGE " : " ja " ] ) , runDestination: . iOS, fs: fs) { results in
727+ // Ignore all Gate, build directory, MkDir, and SymLink tasks.
728+ results. checkTasks ( . matchRuleType( " Gate " ) ) { _ in }
729+ results. checkTasks ( . matchRuleType( " CreateBuildDirectory " ) ) { _ in }
730+ results. checkTasks ( . matchRuleType( " MkDir " ) ) { _ in }
731+ results. checkTasks ( . matchRuleType( " SymLink " ) ) { _ in }
732+ results. checkTasks ( . matchRuleType( " LinkStoryboards " ) ) { _ in }
733+ results. checkTasks ( . matchRuleType( " WriteAuxiliaryFile " ) ) { _ in }
734+
735+ results. checkTarget ( " App " ) { target in
736+ for (language, component, path) in languageComponentPathGroupings where language == " ja " {
737+ results. checkTask ( . matchTarget( target) , . matchRule( [ " CpResource " , " /tmp/aProject.dst/Applications/App.app/Contents/Resources/ \( component) / \( language) .lproj " , path. str] ) ) { _ in }
738+ }
739+ }
740+
741+ results. checkNoTask ( )
742+ results. checkNoDiagnostics ( )
743+ }
744+
745+ // INSTALLLOC_LANGUAGE set to "zh_TW" and "ja"
746+ let specificLangs = [ " zh_TW " , " ja " ]
747+ await tester. checkBuild ( BuildParameters ( action: . installLoc, configuration: " Debug " , overrides: [ " INSTALLLOC_LANGUAGE " : specificLangs. joined ( separator: " " ) ] ) , runDestination: . iOS, fs: fs) { results in
748+ // Ignore all Gate, build directory, MkDir, and SymLink tasks.
749+ results. checkTasks ( . matchRuleType( " Gate " ) ) { _ in }
750+ results. checkTasks ( . matchRuleType( " CreateBuildDirectory " ) ) { _ in }
751+ results. checkTasks ( . matchRuleType( " MkDir " ) ) { _ in }
752+ results. checkTasks ( . matchRuleType( " SymLink " ) ) { _ in }
753+ results. checkTasks ( . matchRuleType( " LinkStoryboards " ) ) { _ in }
754+ results. checkTasks ( . matchRuleType( " WriteAuxiliaryFile " ) ) { _ in }
755+
756+ results. checkTarget ( " App " ) { target in
757+ for (language, component, path) in languageComponentPathGroupings where specificLangs. contains ( language) {
758+ results. checkTask ( . matchTarget( target) , . matchRule( [ " CpResource " , " /tmp/aProject.dst/Applications/App.app/Contents/Resources/ \( component) / \( language) .lproj " , path. str] ) ) { _ in }
759+ }
760+ }
761+
762+ results. checkNoTask ( )
763+ results. checkNoDiagnostics ( )
764+ }
765+ }
766+ }
767+
768+ /// Test an App that has a directory or package (not an explicit bundle) in copy files phase
769+ @Test ( . requireSDKs( . macOS) )
770+ func embeddedDirectoriesInCopyFiles( ) async throws {
771+ try await withTemporaryDirectory { tmpDir in
772+ let srcRoot = tmpDir. join ( " srcroot " )
773+
774+ let testProject = TestProject (
775+ " aProject " ,
776+ sourceRoot: srcRoot,
777+ groupTree: TestGroup (
778+ " SomeFiles " , path: " Sources " ,
779+ children: [
780+ TestFile ( " MyFolder " ) ,
781+ TestFile ( " MyPackage.myPackage " ) ,
782+ ] ) ,
783+ buildConfigurations: [
784+ TestBuildConfiguration (
785+ " Debug " ,
786+ buildSettings: [
787+ " PRODUCT_NAME " : " $(TARGET_NAME) " ,
788+ " INSTALLLOC_DIRECTORY_CONTENTS " : " YES "
789+ ] ) ,
790+ ] ,
791+ targets: [
792+ TestStandardTarget (
793+ " App " ,
794+ type: . application,
795+ buildPhases: [
796+ TestCopyFilesBuildPhase ( [
797+ " MyFolder " ,
798+ " MyPackage.myPackage "
799+ ] , destinationSubfolder: . absolute, destinationSubpath: " /tmp/CustomPath " , onlyForDeployment: false )
800+ ]
801+ )
802+ ] )
803+ let tester = try await TaskConstructionTester ( getCore ( ) , testProject)
804+ let fs = PseudoFS ( )
805+ var languageComponentPathGroupings : [ ( lang: String , component: String , path: Path ) ] = [ ]
806+ for pathComponent in [ " MyFolder " , " MyPackage.myPackage " ] {
807+ let bundlePath = srcRoot. join ( " Sources/ \( pathComponent) " , preserveRoot: true , normalize: true )
808+ try fs. createDirectory ( bundlePath, recursive: true )
809+ try fs. write ( bundlePath. join ( " Info.plist " ) , contents: " LocTest " )
810+
811+ for lang in [ " en " , " ja " , " zh_TW " ] {
812+ let path = bundlePath. join ( " \( lang) .lproj " , preserveRoot: true , normalize: true )
813+ try fs. createDirectory ( path, recursive: false )
814+ try fs. write ( path. join ( " Localizable.strings " ) , contents: " LocTest " )
815+ languageComponentPathGroupings += [ ( lang, pathComponent, path) ]
816+ }
817+ }
818+
819+ await tester. checkBuild ( BuildParameters ( action: . installLoc, configuration: " Debug " ) , runDestination: . iOS, fs: fs) { results in
820+ // Ignore all Gate, build directory, SymLink, and MkDir tasks.
821+ results. checkTasks ( . matchRuleType( " Gate " ) ) { _ in }
822+ results. checkTasks ( . matchRuleType( " CreateBuildDirectory " ) ) { _ in }
823+ results. checkTasks ( . matchRuleType( " SymLink " ) ) { _ in }
824+ results. checkTasks ( . matchRuleType( " MkDir " ) ) { _ in }
825+ results. checkTasks ( . matchRuleType( " WriteAuxiliaryFile " ) ) { _ in }
826+ results. checkTasks ( . matchRuleType( " ProcessInfoPlistFile " ) ) { _ in }
827+
828+ results. checkTarget ( " App " ) { target in
829+ for (language, component, path) in languageComponentPathGroupings {
830+ results. checkTask ( . matchTarget( target) , . matchRule( [ " Copy " , " /tmp/aProject.dst/tmp/CustomPath/ \( component) / \( language) .lproj " , path. str] ) ) { _ in }
831+ }
832+ }
833+ results. checkNoTask ( )
834+ results. checkNoDiagnostics ( )
835+ }
836+
837+ // INSTALLLOC_LANGUAGE set to "ja"
838+ await tester. checkBuild ( BuildParameters ( action: . installLoc, configuration: " Debug " , overrides: [ " INSTALLLOC_LANGUAGE " : " ja " ] ) , runDestination: . iOS, fs: fs) { results in
839+ // Ignore all Gate, build directory, MkDir, and SymLink tasks.
840+ results. checkTasks ( . matchRuleType( " Gate " ) ) { _ in }
841+ results. checkTasks ( . matchRuleType( " CreateBuildDirectory " ) ) { _ in }
842+ results. checkTasks ( . matchRuleType( " MkDir " ) ) { _ in }
843+ results. checkTasks ( . matchRuleType( " SymLink " ) ) { _ in }
844+ results. checkTasks ( . matchRuleType( " LinkStoryboards " ) ) { _ in }
845+ results. checkTasks ( . matchRuleType( " WriteAuxiliaryFile " ) ) { _ in }
846+
847+ results. checkTarget ( " App " ) { target in
848+ for (language, component, path) in languageComponentPathGroupings where language == " ja " {
849+ results. checkTask ( . matchTarget( target) , . matchRule( [ " Copy " , " /tmp/aProject.dst/tmp/CustomPath/ \( component) / \( language) .lproj " , path. str] ) ) { _ in }
850+ }
851+ }
852+
853+ results. checkNoTask ( )
854+ results. checkNoDiagnostics ( )
855+ }
856+
857+ // INSTALLLOC_LANGUAGE set to "zh_TW" and "ja"
858+ let specificLangs = [ " zh_TW " , " ja " ]
859+ await tester. checkBuild ( BuildParameters ( action: . installLoc, configuration: " Debug " , overrides: [ " INSTALLLOC_LANGUAGE " : specificLangs. joined ( separator: " " ) ] ) , runDestination: . iOS, fs: fs) { results in
860+ // Ignore all Gate, build directory, MkDir, and SymLink tasks.
861+ results. checkTasks ( . matchRuleType( " Gate " ) ) { _ in }
862+ results. checkTasks ( . matchRuleType( " CreateBuildDirectory " ) ) { _ in }
863+ results. checkTasks ( . matchRuleType( " MkDir " ) ) { _ in }
864+ results. checkTasks ( . matchRuleType( " SymLink " ) ) { _ in }
865+ results. checkTasks ( . matchRuleType( " LinkStoryboards " ) ) { _ in }
866+ results. checkTasks ( . matchRuleType( " WriteAuxiliaryFile " ) ) { _ in }
867+
868+ results. checkTarget ( " App " ) { target in
869+ for (language, component, path) in languageComponentPathGroupings where specificLangs. contains ( language) {
870+ results. checkTask ( . matchTarget( target) , . matchRule( [ " Copy " , " /tmp/aProject.dst/tmp/CustomPath/ \( component) / \( language) .lproj " , path. str] ) ) { _ in }
871+ }
872+ }
873+
874+ results. checkNoTask ( )
875+ results. checkNoDiagnostics ( )
876+ }
877+ }
878+ }
879+
656880 /// Test an App that has a bundle (not the product of a target) in copy files phase
657881 @Test ( . requireSDKs( . iOS) )
658882 func warningForMissingExternalBundles( ) async throws {
0 commit comments