CompatibilityMatrix::addAllXmlFilesAsOptional

Similar to addAllHalsAsOptional, addAllXmlFilesAsOptional
adds <xmlfile> entries from higher FCM Versions to
lower FCM Versions.

Test: libvintf_test

Change-Id: I0b5244d209eda2409f2a1a04dd84ce620abc0374
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 264b905..7afaa9b 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -135,6 +135,25 @@
     return true;
 }
 
+bool CompatibilityMatrix::addAllXmlFilesAsOptional(CompatibilityMatrix* other, std::string* error) {
+    if (other == nullptr || other->level() <= level()) {
+        return true;
+    }
+    for (auto& pair : other->mXmlFiles) {
+        const std::string& name = pair.first;
+        MatrixXmlFile& xmlFileToAdd = pair.second;
+
+        xmlFileToAdd.mOptional = true;
+        if (!addXmlFile(std::move(xmlFileToAdd))) {
+            if (error) {
+                *error = "Cannot add XML File " + name + " for unknown reason.";
+            }
+            return false;
+        }
+    }
+    return true;
+}
+
 bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt) {
     return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
            lft.mXmlFiles == rgt.mXmlFiles &&
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index 23cbe53..1bb6387 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -68,6 +68,8 @@
     // Return nullptr if none is found.
     std::pair<MatrixHal*, VersionRange*> getHalWithMajorVersion(const std::string& name,
                                                                 size_t majorVer);
+    // Similar to addAllHalsAsOptional but on <xmlfile> entries.
+    bool addAllXmlFilesAsOptional(CompatibilityMatrix* other, std::string* error);
 
     status_t fetchAllInformation(const std::string &path);
 
diff --git a/include/vintf/XmlFile.h b/include/vintf/XmlFile.h
index 787e217..1ad57bb 100644
--- a/include/vintf/XmlFile.h
+++ b/include/vintf/XmlFile.h
@@ -44,6 +44,7 @@
     bool operator==(const MatrixXmlFile& other) const;
 
    private:
+    friend struct CompatibilityMatrix;
     friend struct MatrixXmlFileConverter;
     friend struct LibVintfTest;
     bool mOptional;
diff --git a/include/vintf/parse_xml.h b/include/vintf/parse_xml.h
index 61c4f8e..a92facf 100644
--- a/include/vintf/parse_xml.h
+++ b/include/vintf/parse_xml.h
@@ -33,6 +33,7 @@
 
     EVERYTHING = 0,
     HALS_ONLY = ~NO_HALS,
+    XMLFILES_ONLY = ~NO_XMLFILES,
 };
 using SerializeFlags = uint32_t;
 
diff --git a/test/LibVintfTest.cpp b/test/LibVintfTest.cpp
index b33d0bc..8c07075 100644
--- a/test/LibVintfTest.cpp
+++ b/test/LibVintfTest.cpp
@@ -106,6 +106,10 @@
     bool addAllHalsAsOptional(CompatibilityMatrix* cm1, CompatibilityMatrix* cm2, std::string* e) {
         return cm1->addAllHalsAsOptional(cm2, e);
     }
+    bool addAllXmlFilesAsOptional(CompatibilityMatrix* cm1, CompatibilityMatrix* cm2,
+                                  std::string* e) {
+        return cm1->addAllXmlFilesAsOptional(cm2, e);
+    }
 
     std::map<std::string, HalInterface> testHalInterfaces() {
         HalInterface intf;
@@ -2232,6 +2236,51 @@
               "</compatibility-matrix>\n");
 }
 
+TEST_F(LibVintfTest, AddOptionalXmlFile) {
+    CompatibilityMatrix cm1;
+    CompatibilityMatrix cm2;
+    std::string error;
+    std::string xml;
+
+    xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
+        "    <xmlfile format=\"xsd\" optional=\"true\">\n"
+        "        <name>foo</name>\n"
+        "        <version>1.0-2</version>\n"
+        "        <path>/foo/bar/baz.xsd</path>\n"
+        "    </xmlfile>\n"
+        "</compatibility-matrix>\n";
+    EXPECT_TRUE(gCompatibilityMatrixConverter(&cm1, xml))
+        << gCompatibilityMatrixConverter.lastError();
+
+    xml =
+        "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"2\">\n"
+        "    <xmlfile format=\"xsd\" optional=\"true\">\n"
+        "        <name>foo</name>\n"
+        "        <version>1.1-3</version>\n"
+        "        <path>/foo/bar/quux.xsd</path>\n"
+        "    </xmlfile>\n"
+        "</compatibility-matrix>\n";
+    EXPECT_TRUE(gCompatibilityMatrixConverter(&cm2, xml))
+        << gCompatibilityMatrixConverter.lastError();
+
+    EXPECT_TRUE(addAllXmlFilesAsOptional(&cm1, &cm2, &error)) << error;
+    xml = gCompatibilityMatrixConverter(cm1, SerializeFlag::XMLFILES_ONLY);
+    EXPECT_EQ(xml,
+              "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
+              "    <xmlfile format=\"xsd\" optional=\"true\">\n"
+              "        <name>foo</name>\n"
+              "        <version>1.0-2</version>\n"
+              "        <path>/foo/bar/baz.xsd</path>\n"
+              "    </xmlfile>\n"
+              "    <xmlfile format=\"xsd\" optional=\"true\">\n"
+              "        <name>foo</name>\n"
+              "        <version>1.1-3</version>\n"
+              "        <path>/foo/bar/quux.xsd</path>\n"
+              "    </xmlfile>\n"
+              "</compatibility-matrix>\n");
+}
+
 } // namespace vintf
 } // namespace android