Skip to content

Commit 6aed0d5

Browse files
authored
[libc] created integration tests for newhdrgen (#97361)
- created integration tests for libc hdrgen - implemented sorting function names in yaml files through script
1 parent 4c63672 commit 6aed0d5

File tree

12 files changed

+254
-19
lines changed

12 files changed

+254
-19
lines changed

libc/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ set(LIBC_NAMESPACE ${default_namespace}
5050
CACHE STRING "The namespace to use to enclose internal implementations. Must start with '__llvm_libc'."
5151
)
5252

53+
54+
add_subdirectory(newhdrgen)
55+
56+
5357
if(LLVM_LIBC_FULL_BUILD OR LLVM_LIBC_GPU_BUILD)
5458
if(NOT LIBC_HDRGEN_EXE)
5559
# We need to set up hdrgen first since other targets depend on it.

libc/newhdrgen/CMakeLists.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
if(LLVM_LIBC_FULL_BUILD)
2+
3+
enable_testing()
4+
5+
set(NEWHDGEN_TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tests)
6+
7+
add_test(
8+
NAME newhdrgen_integration_test
9+
COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} python3 ${NEWHDGEN_TESTS_DIR}/test_integration.py
10+
)
11+
12+
add_custom_target(check-newhdrgen
13+
COMMAND ${CMAKE_CTEST_COMMAND} -R newhdrgen_integration_test
14+
)
15+
16+
message(STATUS "Integration test for newhdrgen added.")
17+
endif()

libc/newhdrgen/class_implementation/classes/enumeration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
class Enumeration:
13-
def __init__(self, name, value=None):
13+
def __init__(self, name, value):
1414
self.name = name
1515
self.value = value
1616

libc/newhdrgen/class_implementation/classes/function.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@
1111

1212
class Function:
1313
def __init__(
14-
self, standards, return_type, name, arguments, guard=None, attributes=[]
14+
self, return_type, name, arguments, standards, guard=None, attributes=[]
1515
):
16-
self.standards = standards
1716
self.return_type = return_type
1817
self.name = name
1918
self.arguments = [
2019
arg if isinstance(arg, str) else arg["type"] for arg in arguments
2120
]
21+
self.standards = standards
2222
self.guard = guard
2323
self.attributes = attributes or []
2424

2525
def __str__(self):
26-
attributes_str = " ".join(self.attributes)
26+
attributes_str = self.attributes
2727
arguments_str = ", ".join(self.arguments)
2828
result = f"{self.return_type} {self.name}({arguments_str}){attributes_str};"
2929
if self.guard:

libc/newhdrgen/class_implementation/classes/object.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ def __init__(self, name, type):
1515
self.type = type
1616

1717
def __str__(self):
18-
return f"extern {self.type} {self.name}"
18+
return f"extern {self.type} {self.name};"

libc/newhdrgen/header.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,24 +44,24 @@ def __str__(self):
4444
content.append(str(include))
4545

4646
for macro in self.macros:
47-
content.append(str(macro))
48-
49-
for object in self.objects:
50-
content.append(str(object))
47+
content.append(f"{macro}\n")
5148

5249
for type_ in self.types:
53-
content.append(str(type_))
50+
content.append(f"{type_}")
5451

5552
if self.enumerations:
56-
content.append("enum {")
57-
for enum in self.enumerations:
58-
content.append(f"\t{str(enum)},")
59-
content.append("};")
53+
combined_enum_content = ",\n ".join(
54+
str(enum) for enum in self.enumerations
55+
)
56+
content.append(f"\nenum {{\n {combined_enum_content},\n}};")
57+
58+
content.append("\n__BEGIN_C_DECLS\n")
6059

61-
# TODO: replace line below with common.h functionality
62-
content.append("__BEGIN_C_DECLS\n")
6360
for function in self.functions:
6461
content.append(str(function))
6562
content.append("")
66-
content.append("__END_C_DECLS\n")
63+
for object in self.objects:
64+
content.append(str(object))
65+
content.append("\n__END_C_DECLS")
66+
6767
return "\n".join(content)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===-- C standard library header test_small-------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_TEST_SMALL_H
10+
#define LLVM_LIBC_TEST_SMALL_H
11+
12+
#include "__llvm-libc-common.h"
13+
#include "llvm-libc-macros/test_small-macros.h"
14+
15+
#define MACRO_A 1
16+
17+
#define MACRO_B 2
18+
19+
#include <llvm-libc-types/type_a.h>
20+
#include <llvm-libc-types/type_b.h>
21+
22+
enum {
23+
enum_a = value_1,
24+
enum_b = value_2,
25+
};
26+
27+
__BEGIN_C_DECLS
28+
29+
#ifdef FUNC_A_16
30+
void func_a()CONST_FUNC_A;
31+
#endif // FUNC_A_16
32+
33+
#ifdef FUNC_B_16
34+
int func_b(int, float)CONST_FUNC_B;
35+
#endif // FUNC_B_16
36+
37+
extern obj object_1;
38+
extern obj object_2;
39+
40+
__END_C_DECLS
41+
42+
#endif // LLVM_LIBC_TEST_SMALL_H
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//===-- C standard library header test_small-------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_TEST_SMALL_H
10+
#define LLVM_LIBC_TEST_SMALL_H
11+
12+
#include "__llvm-libc-common.h"
13+
#include "llvm-libc-macros/test_small-macros.h"
14+
15+
%%public_api()
16+
17+
#endif // LLVM_LIBC_TEST_SMALL_H
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
header: test_header.h
2+
macros:
3+
- macro_name: MACRO_A
4+
macro_value: 1
5+
- macro_name: MACRO_B
6+
macro_value: 2
7+
types:
8+
- type_name: type_a
9+
- type_name: type_b
10+
enums:
11+
- name: enum_a
12+
value: value_1
13+
- name: enum_b
14+
value: value_2
15+
objects:
16+
- object_name: object_1
17+
object_type: obj
18+
- object_name: object_2
19+
object_type: obj
20+
functions:
21+
- name: func_a
22+
return_type: void
23+
arguments: []
24+
standards:
25+
- stdc
26+
guard: FUNC_A_16
27+
attributes: CONST_FUNC_A
28+
- name: func_b
29+
return_type: int
30+
arguments:
31+
- type: int
32+
- type: float
33+
standards:
34+
- stdc
35+
guard: FUNC_B_16
36+
attributes: CONST_FUNC_B
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===-- C standard library header test_small-------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_TEST_SMALL_H
10+
#define LLVM_LIBC_TEST_SMALL_H
11+
12+
#include "__llvm-libc-common.h"
13+
#include "llvm-libc-macros/test_small-macros.h"
14+
15+
#define MACRO_A 1
16+
17+
#define MACRO_B 2
18+
19+
#include <llvm-libc-types/type_a.h>
20+
#include <llvm-libc-types/type_b.h>
21+
22+
enum {
23+
enum_a = value_1,
24+
enum_b = value_2,
25+
};
26+
27+
__BEGIN_C_DECLS
28+
29+
#ifdef FUNC_A_16
30+
void func_a()CONST_FUNC_A;
31+
#endif // FUNC_A_16
32+
33+
#ifdef FUNC_B_16
34+
int func_b(int, float)CONST_FUNC_B;
35+
#endif // FUNC_B_16
36+
37+
extern obj object_1;
38+
extern obj object_2;
39+
40+
__END_C_DECLS
41+
42+
#endif // LLVM_LIBC_TEST_SMALL_H
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import subprocess
2+
import unittest
3+
from pathlib import Path
4+
import os
5+
import argparse
6+
7+
8+
class TestHeaderGenIntegration(unittest.TestCase):
9+
def setUp(self):
10+
parser = argparse.ArgumentParser(
11+
description="TestHeaderGenIntegration arguments"
12+
)
13+
parser.add_argument(
14+
"--output_dir", type=str, help="Output directory for generated headers"
15+
)
16+
args, _ = parser.parse_known_args()
17+
output_dir_env = os.getenv("TEST_OUTPUT_DIR")
18+
19+
self.output_dir = Path(
20+
args.output_dir
21+
if args.output_dir
22+
else output_dir_env if output_dir_env else "libc/newhdrgen/tests/output"
23+
)
24+
25+
self.maxDiff = None
26+
# Adjust based on your directory structure such as being in build etc.
27+
self.source_dir = Path(__file__).resolve().parent.parent.parent.parent
28+
29+
def run_script(self, yaml_file, h_def_file, output_dir):
30+
yaml_file = self.source_dir / yaml_file
31+
h_def_file = self.source_dir / h_def_file
32+
result = subprocess.run(
33+
[
34+
"python3",
35+
str(self.source_dir / "libc/newhdrgen/yaml_to_classes.py"),
36+
str(yaml_file),
37+
str(h_def_file),
38+
"--output_dir",
39+
str(output_dir),
40+
],
41+
capture_output=True,
42+
text=True,
43+
)
44+
45+
print("STDOUT:", result.stdout)
46+
print("STDERR:", result.stderr)
47+
result.check_returncode()
48+
49+
def compare_files(self, generated_file, expected_file):
50+
with generated_file.open("r") as gen_file:
51+
gen_content = gen_file.read()
52+
with expected_file.open("r") as exp_file:
53+
exp_content = exp_file.read()
54+
55+
self.assertEqual(gen_content, exp_content)
56+
57+
def test_generate_header(self):
58+
yaml_file = "libc/newhdrgen/tests/input/test_small.yaml"
59+
h_def_file = "libc/newhdrgen/tests/input/test_small.h.def"
60+
expected_output_file = (
61+
self.source_dir / "libc/newhdrgen/tests/expected_output/test_header.h"
62+
)
63+
output_file = self.output_dir / "test_small.h"
64+
65+
if not self.output_dir.exists():
66+
self.output_dir.mkdir(parents=True)
67+
68+
self.run_script(yaml_file, h_def_file, self.output_dir)
69+
70+
self.compare_files(output_file, expected_output_file)
71+
72+
73+
if __name__ == "__main__":
74+
unittest.main()

libc/newhdrgen/yaml_to_classes.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,13 @@ def yaml_to_classes(yaml_data):
4646
Enumeration(enum_data["name"], enum_data.get("value", None))
4747
)
4848

49-
for function_data in yaml_data.get("functions", []):
49+
functions = yaml_data.get("functions", [])
50+
sorted_functions = sorted(functions, key=lambda x: x["name"])
51+
for function_data in sorted_functions:
5052
arguments = [arg["type"] for arg in function_data["arguments"]]
5153
guard = function_data.get("guard", None)
5254
attributes = function_data.get("attributes", None)
53-
standards = (function_data.get("standards", None),)
55+
standards = function_data.get("standards", None)
5456
header.add_function(
5557
Function(
5658
function_data["return_type"],
@@ -99,6 +101,7 @@ def fill_public_api(header_str, h_def_content):
99101
Returns:
100102
The final header content with the public API filled in.
101103
"""
104+
header_str = header_str.strip()
102105
return h_def_content.replace("%%public_api()", header_str, 1)
103106

104107

0 commit comments

Comments
 (0)