Verify the locale format within a localeConfig file

Leverage the existing mechanism for validating the locale format to verify whether the locale format of the compiled localeConfig file follows the BCP47 reqular expressions

Bug: 208943132
Test: 1. atest aapt2_tests
      2. Build the app bundle with the local aapt2 in the Android Studio
         a. Make sure the app can be built pass with AGP 7.3.0-alpha06.
	 b. Make sure the app can be built pass by using the local aapt2 with gradle: set the android.aapt2FromMavenOverride=<path> variable in gradle.properties.
	 c. Revove the property above in gradle.properties then apply AGP 7.3.0-alpha07. Make sure the appt2 shows error(AAPT: error: failed to load XML file: No such file or directory) when building the app.
	 d. Add the locale aapt2 with gradle: set the android.aapt2FromMavenOverride=<path> variable in gradle.properties. Make sure the app can be built pass.

Change-Id: Ifa4b9123d36f9c2d450fdf16e1f52963962d7d81
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index f20cf2c..254f3a5 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -785,4 +785,175 @@
   EXPECT_THAT(xml_attrs[1].value, Eq("Hello World!"));
 }
 
+TEST_F(LinkTest, LocaleConfigVerification) {
+  StdErrDiagnostics diag;
+  const std::string compiled_files_dir = GetTestPath("compiled");
+
+  // Normal case
+  ASSERT_TRUE(CompileFile(GetTestPath("res/xml/locales_config.xml"), R"(
+    <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+      <locale android:name="en-US"/>
+      <locale android:name="pt"/>
+      <locale android:name="es-419"/>
+      <locale android:name="zh-Hans-SG"/>
+    </locale-config>)",
+                          compiled_files_dir, &diag));
+
+  const std::string localeconfig_manifest = GetTestPath("localeconfig_manifest.xml");
+  WriteFile(localeconfig_manifest, android::base::StringPrintf(R"(
+    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.aapt2.app">
+
+      <application
+        android:localeConfig="@xml/locales_config">
+      </application>
+    </manifest>)"));
+
+  const std::string out_apk = GetTestPath("out.apk");
+
+  auto link_args = LinkCommandBuilder(this)
+                       .SetManifestFile(localeconfig_manifest)
+                       .AddCompiledResDir(compiled_files_dir, &diag)
+                       .Build(out_apk);
+  ASSERT_TRUE(Link(link_args, &diag));
+
+  // Empty locale list
+  ASSERT_TRUE(CompileFile(GetTestPath("res/xml/empty_locales_config.xml"), R"(
+    <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+    </locale-config>)",
+                          compiled_files_dir, &diag));
+
+  const std::string empty_localeconfig_manifest = GetTestPath("empty_localeconfig_manifest.xml");
+  WriteFile(empty_localeconfig_manifest, android::base::StringPrintf(R"(
+    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.aapt2.app">
+
+      <application
+        android:localeConfig="@xml/empty_locales_config">
+      </application>
+    </manifest>)"));
+
+  auto link1_args = LinkCommandBuilder(this)
+                        .SetManifestFile(empty_localeconfig_manifest)
+                        .AddCompiledResDir(compiled_files_dir, &diag)
+                        .Build(out_apk);
+  ASSERT_TRUE(Link(link1_args, &diag));
+}
+
+TEST_F(LinkTest, LocaleConfigWrongTag) {
+  StdErrDiagnostics diag;
+  const std::string compiled_files_dir = GetTestPath("compiled");
+
+  // Invalid element: locale1-config
+  ASSERT_TRUE(CompileFile(GetTestPath("res/xml/wrong_locale_config.xml"), R"(
+    <locale1-config xmlns:android="http://schemas.android.com/apk/res/android">
+      <locale android:name="en-US"/>
+      <locale android:name="pt"/>
+      <locale android:name="es-419"/>
+      <locale android:name="zh-Hans-SG"/>
+    </locale1-config>)",
+                          compiled_files_dir, &diag));
+
+  const std::string locale1config_manifest = GetTestPath("locale1config_manifest.xml");
+  WriteFile(locale1config_manifest, android::base::StringPrintf(R"(
+    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.aapt2.app">
+
+      <application
+        android:localeConfig="@xml/wrong_locale_config">
+      </application>
+    </manifest>)"));
+
+  const std::string out_apk = GetTestPath("out.apk");
+  auto link_args = LinkCommandBuilder(this)
+                       .SetManifestFile(locale1config_manifest)
+                       .AddCompiledResDir(compiled_files_dir, &diag)
+                       .Build(out_apk);
+  ASSERT_FALSE(Link(link_args, &diag));
+
+  // Invalid element: locale1
+  ASSERT_TRUE(CompileFile(GetTestPath("res/xml/wrong_locale.xml"), R"(
+    <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+      <locale1 android:name="en-US"/>
+      <locale android:name="pt"/>
+      <locale android:name="es-419"/>
+      <locale android:name="zh-Hans-SG"/>
+    </locale-config>)",
+                          compiled_files_dir, &diag));
+
+  const std::string locale1_manifest = GetTestPath("locale1_manifest.xml");
+  WriteFile(locale1_manifest, android::base::StringPrintf(R"(
+    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.aapt2.app">
+
+      <application
+        android:localeConfig="@xml/wrong_locale">
+      </application>
+    </manifest>)"));
+
+  auto link1_args = LinkCommandBuilder(this)
+                        .SetManifestFile(locale1_manifest)
+                        .AddCompiledResDir(compiled_files_dir, &diag)
+                        .Build(out_apk);
+  ASSERT_FALSE(Link(link1_args, &diag));
+
+  // Invalid attribute: android:name1
+  ASSERT_TRUE(CompileFile(GetTestPath("res/xml/wrong_attribute.xml"), R"(
+    <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+      <locale android:name1="en-US"/>
+      <locale android:name="pt"/>
+      <locale android:name="es-419"/>
+      <locale android:name="zh-Hans-SG"/>
+    </locale-config>)",
+                          compiled_files_dir, &diag));
+
+  const std::string wrong_attribute_manifest = GetTestPath("wrong_attribute_manifest.xml");
+  WriteFile(wrong_attribute_manifest, android::base::StringPrintf(R"(
+    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.aapt2.app">
+
+      <application
+        android:localeConfig="@xml/wrong_attribute">
+      </application>
+    </manifest>)"));
+
+  auto link2_args = LinkCommandBuilder(this)
+                        .SetManifestFile(wrong_attribute_manifest)
+                        .AddCompiledResDir(compiled_files_dir, &diag)
+                        .Build(out_apk);
+  ASSERT_FALSE(Link(link2_args, &diag));
+}
+
+TEST_F(LinkTest, LocaleConfigWrongLocaleFormat) {
+  StdErrDiagnostics diag;
+  const std::string compiled_files_dir = GetTestPath("compiled");
+
+  // Invalid locale: en-U
+  ASSERT_TRUE(CompileFile(GetTestPath("res/xml/wrong_locale.xml"), R"(
+    <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+      <locale android:name="en-U"/>
+      <locale android:name="pt"/>
+      <locale android:name="es-419"/>
+      <locale android:name="zh-Hans-SG"/>
+    </locale-config>)",
+                          compiled_files_dir, &diag));
+
+  const std::string wrong_locale_manifest = GetTestPath("wrong_locale_manifest.xml");
+  WriteFile(wrong_locale_manifest, android::base::StringPrintf(R"(
+    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.aapt2.app">
+
+      <application
+        android:localeConfig="@xml/wrong_locale">
+      </application>
+    </manifest>)"));
+
+  const std::string out_apk = GetTestPath("out.apk");
+  auto link_args = LinkCommandBuilder(this)
+                       .SetManifestFile(wrong_locale_manifest)
+                       .AddCompiledResDir(compiled_files_dir, &diag)
+                       .Build(out_apk);
+  ASSERT_FALSE(Link(link_args, &diag));
+}
+
 }  // namespace aapt