Rewrite hidden API list generation in Python

Generating hidden API lists has grown in complexity and the original
Makefile rule has become a bottleneck for build times. Rewrite the
logic in Python.

Bug: 113278235
Bug: 73736106
Test: frameworks/base/tools/hiddenapi/generate_hiddenapi_lists_test.py
Change-Id: I63f03133d70260d06c55f482b844a4980dc6f734
diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py
new file mode 100755
index 0000000..8f79318
--- /dev/null
+++ b/tools/hiddenapi/generate_hiddenapi_lists_test.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Unit tests for Hidden API list generation."""
+import unittest
+from generate_hiddenapi_lists import *
+
+class TestHiddenapiListGeneration(unittest.TestCase):
+
+    def test_move_between_sets(self):
+        A = set([1, 2, 3, 4])
+        B = set([5, 6, 7, 8])
+        move_between_sets(set([2, 4]), A, B)
+        self.assertEqual(A, set([1, 3]))
+        self.assertEqual(B, set([2, 4, 5, 6, 7, 8]))
+
+    def test_move_between_sets_fail_not_superset(self):
+        A = set([1, 2, 3, 4])
+        B = set([5, 6, 7, 8])
+        with self.assertRaises(AssertionError) as ar:
+            move_between_sets(set([0, 2]), A, B)
+
+    def test_move_between_sets_fail_not_disjoint(self):
+        A = set([1, 2, 3, 4])
+        B = set([4, 5, 6, 7, 8])
+        with self.assertRaises(AssertionError) as ar:
+            move_between_sets(set([1, 4]), A, B)
+
+    def test_get_package_name(self):
+        self.assertEqual(get_package_name("Ljava/lang/String;->clone()V"), "Ljava/lang/")
+
+    def test_get_package_name_fail_no_arrow(self):
+        with self.assertRaises(AssertionError) as ar:
+            get_package_name("Ljava/lang/String;-clone()V")
+        with self.assertRaises(AssertionError) as ar:
+            get_package_name("Ljava/lang/String;>clone()V")
+        with self.assertRaises(AssertionError) as ar:
+            get_package_name("Ljava/lang/String;__clone()V")
+
+    def test_get_package_name_fail_no_package(self):
+        with self.assertRaises(AssertionError) as ar:
+            get_package_name("LString;->clone()V")
+
+    def test_all_package_names(self):
+        self.assertEqual(all_package_names(), set())
+        self.assertEqual(all_package_names(set(["Lfoo/Bar;->baz()V"])), set(["Lfoo/"]))
+        self.assertEqual(
+            all_package_names(set(["Lfoo/Bar;->baz()V", "Lfoo/BarX;->bazx()I"])),
+            set(["Lfoo/"]))
+        self.assertEqual(
+            all_package_names(
+                set(["Lfoo/Bar;->baz()V"]),
+                set(["Lfoo/BarX;->bazx()I", "Labc/xyz/Mno;->ijk()J"])),
+            set(["Lfoo/", "Labc/xyz/"]))
+
+    def test_move_all(self):
+        src = set([ "abc", "xyz" ])
+        dst = set([ "def" ])
+        move_all(src, dst)
+        self.assertEqual(src, set())
+        self.assertEqual(dst, set([ "abc", "def", "xyz" ]))
+
+    def test_move_from_packages(self):
+        src = set([ "Lfoo/bar/ClassA;->abc()J",        # will be moved
+                    "Lfoo/bar/ClassA;->def()J",        # will be moved
+                    "Lcom/pkg/example/ClassD;->ijk:J", # not moved: different package
+                    "Lfoo/bar/xyz/ClassC;->xyz()Z" ])  # not moved: subpackage
+        dst = set()
+        packages = set([ "Lfoo/bar/" ])
+        move_from_packages(packages, src, dst)
+        self.assertEqual(
+            src, set([ "Lfoo/bar/xyz/ClassC;->xyz()Z", "Lcom/pkg/example/ClassD;->ijk:J" ]))
+        self.assertEqual(
+            dst, set([ "Lfoo/bar/ClassA;->abc()J", "Lfoo/bar/ClassA;->def()J" ]))
+
+if __name__ == '__main__':
+    unittest.main()