"""
* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
"""
import json
import sys
import unittest
from os import remove
import CppHeaderParser
sys.path.insert(0, '..')
try:
from _header_parser import HeaderParser
finally:
pass
class HeaderParserTestCase(unittest.TestCase):
def test_extract_path_and_file(self):
parser = HeaderParser()
parser._extract_path_and_file('include/test/audio_manager.h')
self.assertEqual(parser._header_dict.get('path'), 'include/test')
self.assertEqual(parser._header_dict.get('name'), 'audio_manager.h')
parser._extract_path_and_file('./include/test/audio_manager.h')
self.assertEqual(parser._header_dict.get('path'), './include/test')
self.assertEqual(parser._header_dict.get('name'), 'audio_manager.h')
parser._extract_path_and_file('../include/test/audio_manager.h')
self.assertEqual(parser._header_dict.get('path'), '../include/test')
self.assertEqual(parser._header_dict.get('name'), 'audio_manager.h')
parser._extract_path_and_file('\\include\\test\\audio_manager.h')
self.assertEqual(parser._header_dict.get('path'), '\\include\\test')
self.assertEqual(parser._header_dict.get('name'), 'audio_manager.h')
parser._extract_path_and_file('d:\\include\\test\\audio_manager.h')
self.assertEqual(parser._header_dict.get('path'), 'd:\\include\\test')
self.assertEqual(parser._header_dict.get('name'), 'audio_manager.h')
def test_extract_include(self):
parser = HeaderParser()
parser._extract_include(['"buffer_handle.h"', '"buffer_type.h"'])
self.assertSequenceEqual(parser._header_dict.get("import"), ['buffer_handle.h', 'buffer_type.h'])
def test_extract_include_system_file(self):
parser = HeaderParser()
parser._extract_include(['<fcntl.h>', '<sys/types.h>', '"buffer_handle.h"', '"buffer_type.h"'])
self.assertSequenceEqual(parser._header_dict.get("import"), ['buffer_handle.h', 'buffer_type.h'])
def test_extract_enum(self):
header_file = """
typedef enum {
DISPLAY_SUCCESS = 0,
DISPLAY_FAILURE = 1,
} DispErrCode;
"""
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
parser = HeaderParser()
parser._extract_enum(hjson["enums"])
self.assertSequenceEqual(parser._header_dict.get("enum"), [{'name': 'DispErrCode',
'members': [{'name': 'DISPLAY_SUCCESS', 'value': 0},
{'name': 'DISPLAY_FAILURE',
'value': 1}]}])
def test_extract_enum_with_type(self):
header_file = """
enum CamRetCode : int32_t {
NO_ERROR = 0,
CAMERA_BUSY = 1,
};
"""
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
parser = HeaderParser()
parser._extract_enum(hjson["enums"])
self.assertSequenceEqual(parser._header_dict.get("enum"), [{'name': 'CamRetCode',
'members': [{'name': 'NO_ERROR', 'value': 0},
{'name': 'CAMERA_BUSY', 'value': 1}]}])
def test_extract_enum_unexpected_value(self):
header_file = """
typedef enum {
DISPLAY_SUCCESS = 0x1234u,
DISPLAY_FAILURE = -1,
HBM_USE_CPU_READ = (1 << 0),
} DispErrCode;
"""
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
hjson["enums"][0]["filename"] = "test_header_parser.py"
hjson["enums"][0]["line_number"] = 0
parser = HeaderParser()
parser._extract_enum(hjson["enums"])
self.assertSequenceEqual(
parser._header_dict.get("enum"), [{'name': 'DispErrCode',
'members': [
{'name': 'DISPLAY_SUCCESS',
'value': '0x1234 u // unexpected \'0x\''},
{'name': 'DISPLAY_FAILURE', 'value': '- 1 // unexpected \'-\''},
{'name': 'HBM_USE_CPU_READ',
'value': '( 1 << 0 ) // unexpected \'(\''}
]}])
def test_extract_enum_without_name(self):
header_file = """
enum {
DISPLAY_SUCCESS = 1,
DISPLAY_FAILURE = 2,
};
enum {
DISPLAY_START = 1,
DISPLAY_END = 2,
};
"""
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
parser = HeaderParser()
parser._extract_enum(hjson["enums"])
self.assertSequenceEqual(parser._header_dict.get("enum"), [{'name': 'LostName_0',
'members': [
{'name': 'DISPLAY_SUCCESS', 'value': 1},
{'name': 'DISPLAY_FAILURE', 'value': 2}
]},
{'name': 'LostName_1',
'members': [
{'name': 'DISPLAY_START', 'value': 1},
{'name': 'DISPLAY_END', 'value': 2}
]}])
def test_extract_union(self):
header_file = """
union SceneDesc {
uint32_t id;
const char *desc;
};
"""
parser = HeaderParser()
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
parser._extract_union(hjson["classes"]["SceneDesc"])
self.assertSequenceEqual(parser._header_dict.get("union"), [{'name': 'SceneDesc',
'type': 'union',
'members': [
{'file_name': '/', 'line_number': 3,
'name': 'id', 'type': 'uint32_t'},
{'file_name': '/', 'line_number': 4,
'name': 'desc', 'type': 'const char *'}
]}])
def test_extract_union_without_name(self):
header_file = """
union {
uint32_t id;
const char *desc;
};
union {
uint32_t id2;
const char *desc2;
};
"""
parser = HeaderParser()
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
parser._extract_union(hjson["classes"]["<anon-union-1>"])
parser._extract_union(hjson["classes"]["<anon-union-2>"])
self.assertSequenceEqual(parser._header_dict.get("union"), [{'name': '<anon-union-1>',
'type': 'union',
'members': [
{'file_name': '/', 'line_number': 3,
'name': 'id', 'type': 'uint32_t'},
{'file_name': '/', 'line_number': 4,
'name': 'desc', 'type': 'const char *'}
]},
{'name': '<anon-union-2>',
'type': 'union',
'members': [
{'file_name': '/', 'line_number': 7,
'name': 'id2', 'type': 'uint32_t'},
{'file_name': '/', 'line_number': 8,
'name': 'desc2', 'type': 'const char *'}
]}
])
def test_extract_struct_include_union(self):
header_file = """
struct AudioSceneDescriptor {
union SceneDesc {
uint32_t id;
const char *desc;
} scene;
};
"""
parser = HeaderParser()
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
parser._extract_union(hjson["classes"]["AudioSceneDescriptor::SceneDesc"])
self.assertSequenceEqual(parser._header_dict.get("union"), [{'name': 'SceneDesc',
'type': 'union',
'members': [
{'file_name': '/', 'line_number': 4,
'name': 'id', 'type': 'uint32_t'},
{'file_name': '/', 'line_number': 5,
'name': 'desc', 'type': 'const char *'}
]}])
parser._extract_struct(hjson["classes"]["AudioSceneDescriptor"])
self.assertSequenceEqual(parser._header_dict.get("struct"), [{'name': 'AudioSceneDescriptor',
'type': 'struct',
'members': [
{'file_name': '/', 'line_number': 6,
'name': 'scene', 'type': 'SceneDesc'}
]}])
def test_extract_struct(self):
header_file = """
typedef struct {
bool succeed;
int8_t end;
float rate;
double rate2;
cstring desc;
std::string location;
uint8_t status;
uint16_t busType;
int32_t num;
uint32_t count;
uint64_t timestamp;
void path;
char chipInfo[32];
enum RetStatus status;
struct EvtPack package;
struct EvtPack *pkgPtr;
} DevAbility;
"""
parser = HeaderParser()
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
parser._extract_struct(hjson["classes"]["DevAbility"])
self.assertSequenceEqual(
parser._header_dict.get("struct"), [{'name': 'DevAbility',
'type': 'struct',
'members': [
{'file_name': '/', 'line_number': 3, 'name': 'succeed',
'type': 'bool'},
{'file_name': '/', 'line_number': 4, 'name': 'end',
'type': 'int8_t'},
{'file_name': '/', 'line_number': 5, 'name': 'rate',
'type': 'float'},
{'file_name': '/', 'line_number': 6, 'name': 'rate2',
'type': 'double'},
{'file_name': '/', 'line_number': 7, 'name': 'desc',
'type': 'cstring'},
{'file_name': '/', 'line_number': 8, 'name': 'location',
'type': 'std::string'},
{'file_name': '/', 'line_number': 9, 'name': 'status',
'type': 'uint8_t'},
{'file_name': '/', 'line_number': 10, 'name': 'busType',
'type': 'uint16_t'},
{'file_name': '/', 'line_number': 11, 'name': 'num',
'type': 'int32_t'},
{'file_name': '/', 'line_number': 12, 'name': 'count',
'type': 'uint32_t'},
{'file_name': '/', 'line_number': 13, 'name': 'timestamp',
'type': 'uint64_t'},
{'file_name': '/', 'line_number': 14, 'name': 'path',
'type': 'void'},
{'file_name': '/', 'line_number': 15, 'name': 'chipInfo',
'type': 'char *'},
{'file_name': '/', 'line_number': 16, 'name': 'status',
'type': 'RetStatus'},
{'file_name': '/', 'line_number': 17, 'name': 'package',
'type': 'struct EvtPack'},
{'file_name': '/', 'line_number': 18, 'name': 'pkgPtr',
'type': 'struct EvtPack *'}
]}])
def test_extract_struct_with_enum_pointer(self):
header_file = """
typedef struct {
enum Status *staPtr;
enum Test *testPtr;
} DevAbility;
"""
file_name = "header_file.h"
with open(file_name, 'w') as f:
f.write(header_file)
parser = HeaderParser()
back_file = parser._pre_handle(file_name)
hjson = json.loads(CppHeaderParser.CppHeader(file_name).toJSON())
remove(back_file)
remove(file_name)
parser._extract_struct(hjson["classes"]["DevAbility"])
self.assertSequenceEqual(parser._header_dict.get("struct"), [{'name': 'DevAbility',
'type': 'struct',
'members': [
{'file_name': '/', 'line_number': 3,
'name': 'staPtr',
'type': 'Status_ENUM_POINTER'},
{'file_name': '/', 'line_number': 4,
'name': 'testPtr',
'type': 'Test_ENUM_POINTER'}
]}])
def test_extract_struct_with_macro(self):
header_file = """
#define CODE_SIZE 32
#define DIV_ROUND_UP(nr, d) (((nr) + (d) - 1) / (d))
#define BYTE_HAS_BITS 8
#define BITS_TO_UINT64(count) DIV_ROUND_UP(count, BYTE_HAS_BITS * sizeof(unsigned long))
typedef struct {
unsigned long absCode[BITS_TO_UINT64(CODE_SIZE)];
} DevAbility;
"""
file_name = "header_file.h"
with open(file_name, 'w') as f:
f.write(header_file)
parser = HeaderParser()
back_file = parser._pre_handle(file_name)
hjson = json.loads(CppHeaderParser.CppHeader(file_name).toJSON())
remove(back_file)
remove(file_name)
parser._extract_struct(hjson["classes"]["DevAbility"])
self.assertSequenceEqual(parser._header_dict.get("struct"), [{'name': 'DevAbility',
'type': 'struct',
'members': [
{'file_name': '/', 'line_number': 8,
'name': 'absCode', 'type': 'unsigned long *'}
]}])
def test_extract_struct_include_union_without_name(self):
header_file = """
struct AudioSceneDescriptor {
union {
uint32_t id;
const char *desc;
};
};
"""
parser = HeaderParser()
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
parser._extract_union(hjson["classes"]["AudioSceneDescriptor::<anon-union-1>"])
self.assertSequenceEqual(parser._header_dict.get("union"), [{'name': '<anon-union-1>',
'type': 'union',
'members': [
{'file_name': '/', 'line_number': 4,
'name': 'id', 'type': 'uint32_t'},
{'file_name': '/', 'line_number': 5,
'name': 'desc', 'type': 'const char *'}
]}])
parser._extract_struct(hjson["classes"]["AudioSceneDescriptor"])
self.assertSequenceEqual(parser._header_dict.get("struct"), [{'name': 'AudioSceneDescriptor',
'type': 'struct',
'members': [
{'file_name': '/', 'line_number': 6,
'name': '', 'type': '<anon-union-1>'}
]}])
def test_extract_interface_with_method(self):
header_file = """
typedef struct {
int32_t SetPowerStatus(uint32_t devIndex);
int32_t RunExtraCommand(uint32_t, InputExtraCmd *);
} InputController;
"""
parser = HeaderParser()
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
parser._extract_interface(hjson["classes"]["InputController"])
self.assertSequenceEqual(parser._header_dict.get("interface"), [{'name': 'InputController',
'members': [
{'name': 'SetPowerStatus',
'params': [{'name': 'devIndex',
'type': 'uint32_t'}],
'file_name': '/',
'line_number': 3},
{'name': 'RunExtraCommand',
'params': [{'name': 'rand_name_0',
'type': 'uint32_t'},
{'name': 'rand_name_1',
'type': 'InputExtraCmd *'}
],
'file_name': '/',
'line_number': 4
}]}])
def test_extract_interface_with_function_point(self):
header_file = """
typedef struct {
int32_t (*SetPowerStatus)(uint32_t devIndex);
int32_t (*RunExtraCommand)(uint32_t, InputExtraCmd *);
int32_t (*RunCapacitanceTest)(uint32_t devIndex,
uint32_t testType);
} InputController;
"""
parser = HeaderParser()
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
parser._extract_interface(hjson["classes"]["InputController"])
self.assertSequenceEqual(parser._header_dict.get("interface"), [{'name': 'InputController',
'members': [
{'name': 'SetPowerStatus',
'params': [{'name': 'devIndex',
'type': 'uint32_t'}],
'file_name': '/',
'line_number': 3
},
{'name': 'RunExtraCommand',
'params': [{'name': 'rand_name_0',
'type': 'uint32_t'},
{'name': 'rand_name_1',
'type': 'InputExtraCmd *'}
],
'file_name': '/',
'line_number': 4
},
{'name': 'RunCapacitanceTest',
'params': [{'name': 'devIndex',
'type': 'uint32_t'},
{'name': 'testType',
'type': 'uint32_t'}
],
'file_name': '/',
'line_number': 5
}
]}])
def test_extract_interface_for_class(self):
header_file = """
class ICameraDevice{
public:
DECLARE_INTERFACE_DESCRIPTOR(u"HDI.Camera.V1_0.Device");
virtual ~ICameraDevice() {}
virtual CamRetCode ICamera();
virtual CamRetCode GetEnabledResults(std::vector<MetaType> &results) = 0;
virtual CamRetCode SetResultMode(const CallbackMode &mode) = 0;
};
"""
parser = HeaderParser()
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
parser._extract_interface(hjson["classes"]["ICameraDevice"])
self.assertSequenceEqual(parser._header_dict.get("interface"), [{'name': 'ICameraDevice',
'members': [
{'name': 'ICamera',
'params': [],
'file_name': '/',
'line_number': 6
},
{'name': 'GetEnabledResults',
'params':
[{'name': 'results',
'type': 'std::vector<MetaType> &'}
],
'file_name': '/',
'line_number': 7
},
{'name': 'SetResultMode',
'params':
[{'name': 'mode',
'type': 'const CallbackMode &'}
],
'file_name': '/',
'line_number': 8
}
]}])
def test_extract_typedef(self):
header_file = """
typedef void (*HotPlugCallback)(uint32_t devId, bool connected);
typedef void *AudioHandle;
"""
parser = HeaderParser()
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
parser._extract_typedef(hjson["typedefs"])
self.assertSequenceEqual(parser._header_dict.get("typedef"),
[{'name': 'HotPlugCallback',
'type': '/* unsupported function pointer type: HotPlugCallback */'},
{'name': 'AudioHandle',
'type': 'void *'}])
def test_checkout_function_pointer_param(self):
header_file = """
typedef struct {
int32_t (*Second)(bool vb, const int8_t vi8, const int16_t *vi16);
int32_t (*Minute)(struct Test st, const struct Test st);
int32_t (*Hour)(const struct Test *st, const struct Test * st);
int32_t (*Day)(const struct Test * st, const struct Test* st);
int32_t (*Month)(std::string str, unsigned int a, unsigned short, enum Test *c);
int32_t (*Year)(unsigned int **out1, const struct Test **out2);
} IFoo;
"""
parser = HeaderParser()
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
stack = hjson["classes"]["IFoo"]
second = stack["properties"]["public"][0]
params = parser._checkout_function_pointer_param(second["type"])
self.assertSequenceEqual(params, [{'name': 'vb', 'type': 'bool'},
{'name': 'vi8', 'type': 'int8_t'},
{'name': 'vi16', 'type': 'int16_t *'}])
minute = stack["properties"]["public"][1]
params = parser._checkout_function_pointer_param(minute["type"])
self.assertSequenceEqual(params, [{'name': 'st', 'type': 'Test'}, {'name': 'st', 'type': 'Test'}])
hour = stack["properties"]["public"][2]
params = parser._checkout_function_pointer_param(hour["type"])
self.assertSequenceEqual(params, [{'name': 'st', 'type': 'Test *'}, {'name': 'st', 'type': 'Test *'}])
day = stack["properties"]["public"][3]
params = parser._checkout_function_pointer_param(day["type"])
self.assertSequenceEqual(params, [{'name': 'st', 'type': 'Test *'}, {'name': 'st', 'type': 'Test *'}])
month = stack["properties"]["public"][4]
params = parser._checkout_function_pointer_param(month["type"])
self.assertSequenceEqual(params, [{'name': 'str', 'type': 'std::string'},
{'name': 'a', 'type': 'unsigned int'},
{'name': 'rand_name_0', 'type': 'unsigned short'},
{'name': 'c', 'type': 'Test *'}])
year = stack["properties"]["public"][5]
params = parser._checkout_function_pointer_param(year["type"])
self.assertSequenceEqual(params, [{'name': 'out1', 'type': 'unsigned int * *'},
{'name': 'out2', 'type': 'Test * *'}])
def test_checkout_function_pointer_param_with_struct(self):
header_file = """
typedef struct {
int32_t (*GetPortCapability)(struct AudioAdapter *adapter, const struct AudioPort *port,
struct AudioPortCapability *capability);
} AudioAdapter;
"""
parser = HeaderParser()
hjson = json.loads(CppHeaderParser.CppHeader(header_file, "string").toJSON())
stack = hjson["classes"]["AudioAdapter"]
function = stack["properties"]["public"][0]
params = parser._checkout_function_pointer_param(function["type"])
self.assertSequenceEqual(params, [{'name': 'adapter', 'type': 'AudioAdapter *'},
{'name': 'port', 'type': 'AudioPort *'},
{'name': 'capability', 'type': 'AudioPortCapability *'}])
if __name__ == "__main__":
unittest.main()