#!/usr/bin/env python3 # -*- coding: utf-8 -*- # This file is under GNU Affero General Public License 3.0 # see LICENSE.txt import re import pytest import pEpACIDgen # input() # "type" - is the name of the type for which vars of all variations of this type exists # (Variations being combinations of this type with qualifier alias and typedef, # Which means that all variations resolve to the same underlying type) # # "requires" - is the list of types that this underlying type depends on # (a type is not self sufficient, a struct for instance can have members of plenty of types, etc...) # # Subject of this test is to make sure: # All variations for all the "type"s given extract the ACID of all the types, # and only the types specified on "requires". all_types = [] all_types.append({"type": ["_P"], "requires": [ ]}) all_types.append({"type": ["_E"], "requires": [ "enum _E" ]}) all_types.append({"type": ["E"], "requires": [ "enum E" ]}) all_types.append({"type": ["XE"], "requires": [ "AXE" ]}) all_types.append({"type": ["_PS"], "requires": [ "struct _PS" ]}) all_types.append({"type": ["PS"], "requires": [ "struct PS" ]}) all_types.append({"type": ["_PSa"], "requires": [ "struct _PSa" ]}) all_types.append({"type": ["PSa"], "requires": [ "struct PSa" ]}) all_types.append({"type": ["_CS"], "requires": [ "struct _CS", "struct _PS", "struct PS", "struct _PSa", "struct PSa" ]}) all_types.append({"type": ["CS"], "requires": [ "struct CS", "struct _PS", "struct PS", ]}) all_types.append({"type": ["_CCS"], "requires": [ "struct _CCS", "struct _CS", "struct CS", "struct _PS", "struct PS", "struct _PSa", "struct PSa" ]}) all_types.append({"type": ["CCS"], "requires": [ "struct CCS", "struct _CS", "struct CS", "struct _PS", "struct PS", "struct _PSa", "struct PSa" ]}) all_types.append({"type": ["_HS"], "requires": [ "struct _HS", "struct _NCS", "struct CS", "struct _PS", "struct PS", ]}) all_types.append({"type": ["HS"], "requires": [ "struct HS", "struct _NPS" ]}) all_types.append({"type": ["_NCS"], "requires": [ "struct _NCS", "struct CS", "struct _PS", "struct PS", ]}) all_types.append({"type": ["_NPS"], "requires": [ "struct _NPS" ]}) all_types.append({"type": ["_HHS"], "requires": [ "struct _HHS", "struct _NHS", "struct _NNPS" ]}) all_types.append({"type": ["HHS"], "requires": [ "struct HHS", "struct _NHS1", "struct _NNCS", "struct _CS", "struct _PS", "struct PS", "struct _PSa", "struct PSa", "enum _NENHS" ]}) all_types.append({"type": ["_NHS"], "requires": [ "struct _NHS", "struct _NNPS" ]}) all_types.append({"type": ["_NNPS"], "requires": [ "struct _NNPS" ]}) all_types.append({"type": ["_NHS1"], "requires": [ "struct _NHS1", "struct _NNCS", "struct _CS", "struct _PS", "struct PS", "struct _PSa", "struct PSa", "enum _NENHS" ]}) all_types.append({"type": ["_NNCS"], "requires": [ "struct _NNCS", "struct _CS", "struct _PS", "struct PS", "struct _PSa", "struct PSa" ]}) all_types.append({"type": ["_NENHS"], "requires": [ "enum _NENHS" ]}) all_types.append({"type": ["_HS1"], "requires": [ "struct _HS1", "enum _NEHS" ]}) all_types.append({"type": ["_NEHS"], "requires": [ "enum _NEHS" ]}) def resolve_vars_and_funcs_to_acid(vars, funcs): header_filename = "examples/lib/lib_test/lib_test.h" libclang_path = "/opt/local/libexec/llvm-9.0/lib/libclang.dylib" acidgen = pEpACIDgen.pEpACIDGen(libclang_path, header_filename, "test_pEpACIDgen") header = acidgen.extract(vars, funcs, debug_ast=True, debug_acid=True, debug_yml=True) return header["acid"] def check_expected_types_resolved(vars, funcs, type_names_expected): print("RESOLVING: ", vars, funcs) cid = resolve_vars_and_funcs_to_acid(vars, funcs) # Check on unresolved vars assert len(cid["vars_notfound"]) == 0, "vars not found" # Check on unresolved functions assert len(cid["functions_notfound"]) == 0, "functions not found" # Check on unresolved typerefs assert len(cid["typerefs_notfound"]) == 0, "typerefs not found" type_names = cid["type_names"] # test for no dup types for tn in type_names: assert type_names.count(tn) == 1, "duplicate type" type_names.sort() type_names_expected.sort() # test expected types match in no specific order # print("GOT: ", type_names) # print("EXPECTED: ", type_names_expected) assert type_names == type_names_expected # Variations # a var var_X of a type X can generally exist in the variations: # * X var_X # * AX var_AX # * TX var_TX # * TAX var_TAX # * TTX var_TTX # * TTAX var_TTAX # AND the type of ALL these vars resolves to the same underlying type X (and its dependencies) # # types with no alias # ------------------- # type with no alias can only exist in variations NOT ending with A # # Anonymous types (enum only) # --------------------------- # an anonymous type only exists because of its alias typedef enum { a;b;c } XE; # Therefore, only variations ending with A are valid @pytest.mark.parametrize('variation_a', ["","a"]) @pytest.mark.parametrize('variation_A_and_T', ["", "A", "T", "TA", "TT", "TTA", "TaT", "TaTA"]) @pytest.mark.parametrize('typekind', all_types) def test_single_var_no_alias(typekind,variation_a, variation_A_and_T): type = typekind["type"][0] var_name = "var_" + variation_a + variation_A_and_T + type # it the type begins with _ it has no alias re_type_no_alias = re.compile("^_") # if the variation ends with an A is an alias of something re_vari_alias = re.compile("A$") # if the type contains an X is is an anonymous type re_type_anonynmous = re.compile("X") skipmsg = "variation not valid:" + variation_A_and_T + " for type:" + type re_vari_invalid_for_anon = re.compile("") if re_type_no_alias.search(type): if re_vari_alias.search(variation_A_and_T): print(skipmsg) pytest.skip(skipmsg) # the anonymous type only exists because of its alias if re_type_anonynmous.search(type): if not re_vari_alias.search(variation_A_and_T): print(skipmsg) pytest.skip(skipmsg) check_expected_types_resolved([var_name], [], typekind["requires"])