| #!/usr/bin/env fuchsia-vendored-python |
| # Copyright 2021 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import argparse |
| import os |
| import sys |
| import unittest |
| from unittest import mock |
| from parameterized import parameterized |
| |
| import fidl_api_mapper |
| |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| "--test_dir_path", help="Path to the test data directory.", required=True |
| ) |
| args = parser.parse_args() |
| |
| TEST_DIR_PATH = args.test_dir_path |
| TEST_FILE_NAME = "fidl.h" |
| |
| # The python_host_test build rule calls `unittest.main`. |
| # So we need to get rid of the test arguments in order |
| # to prevent them from interfering with `unittest`'s args. |
| # |
| # Pop twice to get rid of the `--test_dir_path` flag and |
| # its value. |
| sys.argv.pop() |
| sys.argv.pop() |
| |
| |
| class DwarfdumpStreamingParserTest(unittest.TestCase): |
| @parameterized.expand( |
| [ |
| ( |
| "not_subprogram_skipped", |
| [ |
| "0x01: DW_TAG_member", |
| ' DW_AT_name ("member_name")', |
| " DW_AT_decl_line (1)", |
| "", |
| ], |
| {}, |
| ), |
| ( |
| "one_subprogram", |
| [ |
| "0x01: DW_TAG_subprogram", |
| ' DW_AT_name ("function_name")', |
| " DW_AT_decl_line (1)", |
| "", |
| ], |
| { |
| "0x01": { |
| "DW_AT_name": '"function_name"', |
| "DW_AT_decl_line": "1", |
| } |
| }, |
| ), |
| ( |
| "two_subprograms_sandwiching_non_subprogram", |
| [ |
| "0x01: DW_TAG_subprogram", |
| ' DW_AT_name ("function_name_1")', |
| " DW_AT_decl_line (1)", |
| "", |
| "0x99: DW_TAG_member", |
| ' DW_AT_name ("member_name")', |
| " DW_AT_decl_line (1)", |
| "", |
| "0x02: DW_TAG_subprogram", |
| ' DW_AT_name ("function_name_2")', |
| " DW_AT_decl_line (2)", |
| "", |
| ], |
| { |
| "0x01": { |
| "DW_AT_name": '"function_name_1"', |
| "DW_AT_decl_line": "1", |
| }, |
| "0x02": { |
| "DW_AT_name": '"function_name_2"', |
| "DW_AT_decl_line": "2", |
| }, |
| }, |
| ), |
| ] |
| ) |
| def test_parse_line(self, name, dwarfdump_lines, expected_subprograms_dict): |
| parser = fidl_api_mapper.DwarfdumpStreamingParser() |
| for line in dwarfdump_lines: |
| parser.parse_line(line) |
| self.assertEqual(parser.get_subprograms(), expected_subprograms_dict) |
| |
| |
| class FidlApiResolverTest(unittest.TestCase): |
| TEST_DATA_PATH = "unknown" |
| |
| FIDL_HEADER_FILE_CONTENT = "\n".join( |
| [ |
| "// cts-coverage-fidl-name:line_2", |
| "first_method()", |
| "// cts-coverage-fidl-name:line_4", |
| "middle_method()", |
| "non_fidl_method()", |
| "// cts-coverage-fidl-name:line_7", |
| "last_method()", |
| ] |
| ) |
| |
| @parameterized.expand( |
| [ |
| ("empty_subprograms_dict", {}, {}, {}), |
| ( |
| "successfully_resolved_first_line", |
| { |
| "0x1": { |
| "DW_AT_decl_file": '"fidl.h"', |
| "DW_AT_decl_line": "2", |
| "DW_AT_linkage_name": '"mangled_name"', |
| } |
| }, |
| {}, |
| {"mangled_name": "line_2"}, |
| ), |
| ( |
| "successfully_resolved_middle_line", |
| { |
| "0x1": { |
| "DW_AT_decl_file": '"fidl.h"', |
| "DW_AT_decl_line": "4", |
| "DW_AT_linkage_name": '"mangled_name"', |
| } |
| }, |
| {}, |
| {"mangled_name": "line_4"}, |
| ), |
| ( |
| "successfully_resolved_last_line", |
| { |
| "0x1": { |
| "DW_AT_decl_file": '"fidl.h"', |
| "DW_AT_decl_line": "7", |
| "DW_AT_linkage_name": '"mangled_name"', |
| } |
| }, |
| {}, |
| {"mangled_name": "line_7"}, |
| ), |
| ( |
| "non_annotated_function_is_skipped", |
| { |
| "0x1": { |
| "DW_AT_decl_file": '"fidl.h"', |
| "DW_AT_decl_line": "5", |
| "DW_AT_linkage_name": '"mangled_name"', |
| } |
| }, |
| {}, |
| {}, |
| ), |
| ( |
| "line_number_too_large", |
| { |
| "0x1": { |
| "DW_AT_decl_file": '"fidl.h"', |
| "DW_AT_decl_line": "100", |
| "DW_AT_linkage_name": '"mangled_name"', |
| } |
| }, |
| {}, |
| {}, |
| ), |
| ( |
| "subprogram_missing_filepath", |
| { |
| "0x1": { |
| "DW_AT_decl_line": "1", |
| "DW_AT_linkage_name": '"mangled_name"', |
| } |
| }, |
| {}, |
| {}, |
| ), |
| ( |
| "subprogram_missing_line_number", |
| { |
| "0x1": { |
| "DW_AT_decl_file": '"fidl.h"', |
| "DW_AT_linkage_name": '"mangled_name"', |
| } |
| }, |
| {}, |
| {}, |
| ), |
| ( |
| "subprogram_is_not_in_fidl_header", |
| { |
| "0x1": { |
| "DW_AT_decl_file": '"fidl.cc"', |
| "DW_AT_decl_line": "1", |
| "DW_AT_linkage_name": '"mangled_name"', |
| } |
| }, |
| {}, |
| {}, |
| ), |
| ( |
| "subprogram_missing_mangled_name", |
| { |
| "0x1": { |
| "DW_AT_decl_file": '"fidl.h"', |
| "DW_AT_decl_line": "1", |
| } |
| }, |
| {}, |
| {}, |
| ), |
| ( |
| "subprogram_already_in_mapping", |
| { |
| "0x1": { |
| "DW_AT_decl_file": '"fidl.h"', |
| "DW_AT_decl_line": "1", |
| "DW_AT_linkage_name": '"mangled_name"', |
| } |
| }, |
| {"mangled_name": "fidl_api_name"}, |
| {"mangled_name": "fidl_api_name"}, |
| ), |
| ] |
| ) |
| def test_add_new_mappings( |
| self, name, subprograms_dict, input_mapping_dict, expect_mapping_dict |
| ): |
| resolver = fidl_api_mapper.FidlApiResolver( |
| subprograms_dict, input_mapping_dict |
| ) |
| with mock.patch( |
| "builtins.open", |
| mock.mock_open(read_data=self.FIDL_HEADER_FILE_CONTENT), |
| ): |
| resolver.add_new_mappings() |
| self.assertEqual(input_mapping_dict, expect_mapping_dict) |
| |
| def test_add_new_mappings_snapshot_fidl_file(self): |
| # This testcase differs from "test_add_new_mappings" in that it uses |
| # a real generated FIDL binding header file snapshotted at a particular |
| # revision. So there's no need to mock the content of the file and we |
| # can just directly read it instead. |
| testdata_path = os.path.join(TEST_DIR_PATH, "snapshot", TEST_FILE_NAME) |
| subprograms_dict = { |
| "0x1": { |
| "DW_AT_decl_file": '"%s"' % testdata_path, |
| "DW_AT_decl_line": "652", |
| "DW_AT_linkage_name": '"mangled_name"', |
| } |
| } |
| expect_mapping_dict = { |
| "mangled_name": "fuchsia.diagnostics.stream/Source.RetireBuffer" |
| } |
| mapping_dict = {} |
| |
| resolver = fidl_api_mapper.FidlApiResolver( |
| subprograms_dict, mapping_dict |
| ) |
| resolver.add_new_mappings() |
| self.assertEqual(mapping_dict, expect_mapping_dict) |
| |
| def test_add_new_mappings_generated_fidl_file(self): |
| # Test against generated fidl headers from the current build. |
| # Since the line of function declaration can change, we can just |
| # the following assertions: |
| # 1) At least 1 mapping can be added from iterating through all |
| # lines in the generated fidl header. |
| # 2) No crashes from iterating all lines. |
| testdata_path = os.path.join(TEST_DIR_PATH, "generated", TEST_FILE_NAME) |
| num_lines = len(open(testdata_path).readlines()) |
| |
| subprograms_dict = {} |
| mapping_dict = {} |
| for line_num in range(1, num_lines + 1): |
| subprograms_dict = { |
| "0x1": { |
| "DW_AT_decl_file": '"%s"' % testdata_path, |
| "DW_AT_decl_line": "%d" % line_num, |
| "DW_AT_linkage_name": '"mangled_name_%d"' % line_num, |
| } |
| } |
| resolver = fidl_api_mapper.FidlApiResolver( |
| subprograms_dict, mapping_dict |
| ) |
| resolver.add_new_mappings() |
| self.assertTrue(mapping_dict) |