--checkapi=equal checks the equality of two dumps

Switched from diff-based test, which often breaks for trivial changes.
For example, changing '/* @hide */' to '/** @hide */' shouldn't break
the equality of two dumps.

Similarly, adding license/copyright headers to dumped .aidl files
shouldn't break the equality.

Bug: 172476424
Test: m (triggers checks)
Change-Id: Iea2d3b9f8597977ab276828e943dd6e84debc8ce
diff --git a/aidl_checkapi.cpp b/aidl_checkapi.cpp
index 2b5664a..6337f8e 100644
--- a/aidl_checkapi.cpp
+++ b/aidl_checkapi.cpp
@@ -26,6 +26,7 @@
 
 #include <android-base/result.h>
 #include <android-base/strings.h>
+#include <gtest/gtest.h>
 
 namespace android {
 namespace aidl {
@@ -38,6 +39,24 @@
 using std::string;
 using std::vector;
 
+static std::string Dump(const AidlDefinedType& type) {
+  std::string dump;
+  type.Dump(CodeWriter::ForString(&dump).get());
+  return dump;
+}
+
+// Uses each type's Dump() and GTest utility(EqHelper).
+static bool CheckEquality(const AidlDefinedType& older, const AidlDefinedType& newer) {
+  using testing::internal::EqHelper;
+  auto older_file = older.GetLocation().GetFile();
+  auto newer_file = newer.GetLocation().GetFile();
+  auto result = EqHelper::Compare(older_file.data(), newer_file.data(), Dump(older), Dump(newer));
+  if (!result) {
+    AIDL_ERROR(newer) << result.failure_message();
+  }
+  return result;
+}
+
 static vector<string> get_strict_annotations(const AidlAnnotatable& node) {
   // This must be symmetrical (if you can add something, you must be able to
   // remove it). The reason is that we have no way of knowing which interface a
@@ -367,15 +386,33 @@
     return false;
   }
 
+  const Options::CheckApiLevel level = options.GetCheckApiLevel();
+
   std::vector<AidlDefinedType*> old_types = old_tns->AllDefinedTypes();
   std::vector<AidlDefinedType*> new_types = new_tns->AllDefinedTypes();
 
+  bool compatible = true;
+
+  if (level == Options::CheckApiLevel::EQUAL) {
+    std::set<string> old_type_names;
+    for (const auto t : old_types) {
+      old_type_names.insert(t->GetCanonicalName());
+    }
+    for (const auto new_type : new_types) {
+      const auto found = old_type_names.find(new_type->GetCanonicalName());
+      if (found == old_type_names.end()) {
+        AIDL_ERROR(new_type) << "Added type: " << new_type->GetCanonicalName();
+        compatible = false;
+        continue;
+      }
+    }
+  }
+
   map<string, AidlDefinedType*> new_map;
   for (const auto t : new_types) {
     new_map.emplace(t->GetCanonicalName(), t);
   }
 
-  bool compatible = true;
   for (const auto old_type : old_types) {
     const auto found = new_map.find(old_type->GetCanonicalName());
     if (found == new_map.end()) {
@@ -385,6 +422,13 @@
     }
     const auto new_type = found->second;
 
+    if (level == Options::CheckApiLevel::EQUAL) {
+      if (!CheckEquality(*old_type, *new_type)) {
+        compatible = false;
+      }
+      continue;
+    }
+
     if (!have_compatible_annotations(*old_type, *new_type)) {
       compatible = false;
     }