Преглед изворни кода

Fix conv_linker_config with multiple input json files

`conv_linker_config proto -s` should work with multiple json input
files, but ParseDict() overwrites list fields (e.g. provideLibs), not
appending elements.

Also added a test.

Bug: 264330513
Test: conv_linker_config_test
Change-Id: Idc482f941201f15e5fc276c0ffc0dfeaa09d0cc2
Jooyung Han пре 1 година
родитељ
комит
f6fd4c2823
3 измењених фајлова са 111 додато и 7 уклоњено
  1. 11 0
      scripts/Android.bp
  2. 14 7
      scripts/conv_linker_config.py
  3. 86 0
      scripts/conv_linker_config_test.py

+ 11 - 0
scripts/Android.bp

@@ -191,6 +191,17 @@ python_binary_host {
     ],
 }
 
+python_test_host {
+    name: "conv_linker_config_test",
+    main: "conv_linker_config_test.py",
+    srcs: [
+        "conv_linker_config_test.py",
+        "conv_linker_config.py",
+    ],
+    libs: ["linker_config_proto"],
+    test_suites: ["general-tests"],
+}
+
 python_binary_host {
     name: "get_clang_version",
     main: "get_clang_version.py",

+ 14 - 7
scripts/conv_linker_config.py

@@ -27,6 +27,19 @@ from google.protobuf.json_format import ParseDict
 from google.protobuf.text_format import MessageToString
 
 
+def LoadJsonMessage(path):
+    """
+    Loads a message from a .json file with `//` comments strippedfor convenience.
+    """
+    json_content = ''
+    with open(path) as f:
+        for line in f:
+            if not line.lstrip().startswith('//'):
+                json_content += line
+    obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict)
+    return ParseDict(obj, linker_config_pb2.LinkerConfig())
+
+
 def Proto(args):
     """
     Merges input json files (--source) into a protobuf message (--output).
@@ -48,13 +61,7 @@ def Proto(args):
 
     if args.source:
         for input in args.source.split(':'):
-            json_content = ''
-            with open(input) as f:
-                for line in f:
-                    if not line.lstrip().startswith('//'):
-                        json_content += line
-            obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict)
-            ParseDict(obj, pb)
+            pb.MergeFrom(LoadJsonMessage(input))
     with open(args.output, 'wb') as f:
         f.write(pb.SerializeToString())
 

+ 86 - 0
scripts/conv_linker_config_test.py

@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2023 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 conv_linker_config.py."""
+
+import os
+import shutil
+import tempfile
+import unittest
+
+import conv_linker_config
+from linker_config_pb2 import LinkerConfig
+
+class FileArgs:
+  def __init__(self, files, sep = ':'):
+    self.files = files
+    self.sep = sep
+
+
+class FileArg:
+  def __init__(self, file):
+    self.file = file
+
+
+class TempDirTest(unittest.TestCase):
+
+  def setUp(self):
+    self.tempdir = tempfile.mkdtemp()
+
+
+  def tearDown(self):
+    shutil.rmtree(self.tempdir)
+
+
+  def write(self, name, contents):
+    with open(os.path.join(self.tempdir, name), 'wb') as f:
+      f.write(contents)
+
+
+  def read(self, name):
+    with open(os.path.join(self.tempdir, name), 'rb') as f:
+      return f.read()
+
+
+  def resolve_paths(self, args):
+    for i in range(len(args)):
+      if isinstance(args[i], FileArgs):
+        args[i] = args[i].sep.join(os.path.join(self.tempdir, f.file) for f in args[i].files)
+      elif isinstance(args[i], FileArg):
+        args[i] = os.path.join(self.tempdir, args[i].file)
+    return args
+
+
+class ConvLinkerConfigTest(TempDirTest):
+  """Unit tests for conv_linker_config."""
+
+  def test_Proto_with_multiple_input(self):
+    self.write('foo.json', b'{ "provideLibs": ["libfoo.so"]}')
+    self.write('bar.json', b'{ "provideLibs": ["libbar.so"]}')
+    self.command(['proto', '-s', FileArgs([FileArg('foo.json'), FileArg('bar.json')]), '-o', FileArg('out.pb')])
+    pb = LinkerConfig()
+    pb.ParseFromString(self.read('out.pb'))
+    self.assertSetEqual(set(pb.provideLibs), set(['libfoo.so', 'libbar.so']))
+
+
+  def command(self, args):
+    parser = conv_linker_config.GetArgParser()
+    parsed_args = parser.parse_args(self.resolve_paths(args))
+    parsed_args.func(parsed_args)
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)