Skip to content

[libc] created integration tests for newhdrgen #97361

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jul 3, 2024

Conversation

aaryanshukla
Copy link
Contributor

@aaryanshukla aaryanshukla commented Jul 1, 2024

  • created integration tests for libc hdrgen
  • implemented sorting function names in yaml files through script

- added sorting to script so C headers are outputted in alpha order
- added sorting to script so C headers are outputted in alpha order
@llvmbot llvmbot added the libc label Jul 1, 2024
@llvmbot
Copy link
Member

llvmbot commented Jul 1, 2024

@llvm/pr-subscribers-libc

Author: None (aaryanshukla)

Changes
  • [libc] created integration tests for hdrgen
  • [libc] created integration tests for hdrgen

Full diff: https://github.com/llvm/llvm-project/pull/97361.diff

5 Files Affected:

  • (added) libc/newhdrgen/tests/expected_output/string.h (+102)
  • (added) libc/newhdrgen/tests/input/string.h.def (+18)
  • (added) libc/newhdrgen/tests/input/test_string.yaml (+303)
  • (added) libc/newhdrgen/tests/test_integration.py (+42)
  • (modified) libc/newhdrgen/yaml_to_classes.py (+4-2)
diff --git a/libc/newhdrgen/tests/expected_output/string.h b/libc/newhdrgen/tests/expected_output/string.h
new file mode 100644
index 0000000000000..4dcb693c353e4
--- /dev/null
+++ b/libc/newhdrgen/tests/expected_output/string.h
@@ -0,0 +1,102 @@
+//===-- C standard library header string.h --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_STRING_H
+#define LLVM_LIBC_STRING_H
+
+#include "__llvm-libc-common.h"
+
+#include "llvm-libc-macros/null-macro.h"
+
+#include <llvm-libc-types/size_t.h>
+
+__BEGIN_C_DECLS
+
+void * memccpy(void *__restrict, const void *__restrict, int, size_t);
+
+void * memchr(const void *, int, size_t);
+
+int memcmp(const void *, const void *, size_t);
+
+void * memcpy(void *__restrict, const void *__restrict, size_t);
+
+void * memmem(const void *, size_t, const void *, size_t);
+
+void * memmove(void *, const void *, size_t);
+
+void * mempcpy(void *__restrict, const void *__restrict, size_t);
+
+void * memrchr(const void *, int, size_t);
+
+void * memset(void *, int, size_t);
+
+void * memset_explicit(void *, int, size_t);
+
+char * stpcpy(char *__restrict, const char *__restrict);
+
+char * stpncpy(char *__restrict, const char *__restrict, size_t);
+
+char * strcasestr(const char *, const char *);
+
+char * strcat(char *__restrict, const char *__restrict);
+
+char * strchr(const char *, int);
+
+char * strchrnul(const char *, int);
+
+int strcmp(const char *, const char *);
+
+int strcoll(const char *, const char *);
+
+char * strcpy(char *__restrict, const char *__restrict);
+
+size_t strcspn(const char *, const char *);
+
+char * strdup(const char *);
+
+char * strerror(int);
+
+char * strerror_r(int, char *, size_t);
+
+size_t strlcat(const char *__restrict, const char *__restrict, size_t);
+
+size_t strlcpy(const char *__restrict, const char *__restrict, size_t);
+
+size_t strlen(const char *);
+
+char * strncat(char *, const char *, size_t);
+
+int strncmp(const char *, const char *, size_t);
+
+char * strncpy(char *__restrict, const char *__restrict, size_t);
+
+char * strndup(const char *, size_t);
+
+size_t strnlen(const char *, size_t);
+
+char * strpbrk(const char *, const char *);
+
+char * strrchr(const char *, int);
+
+char * strsep(char * *__restrict, const char *__restrict);
+
+char * strsignal(int);
+
+size_t strspn(const char *, const char *);
+
+char * strstr(const char *, const char *);
+
+char * strtok(char *__restrict, const char *__restrict);
+
+char * strtok_r(char *__restrict, const char *__restrict, char * *__restrict);
+
+size_t strxfrm(char *__restrict, const char *__restrict, size_t);
+
+__END_C_DECLS
+
+#endif // LLVM_LIBC_STRING_H
diff --git a/libc/newhdrgen/tests/input/string.h.def b/libc/newhdrgen/tests/input/string.h.def
new file mode 100644
index 0000000000000..1bd2687db2bea
--- /dev/null
+++ b/libc/newhdrgen/tests/input/string.h.def
@@ -0,0 +1,18 @@
+//===-- C standard library header string.h --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_STRING_H
+#define LLVM_LIBC_STRING_H
+
+#include "__llvm-libc-common.h"
+
+#include "llvm-libc-macros/null-macro.h"
+
+%%public_api()
+
+#endif // LLVM_LIBC_STRING_H
diff --git a/libc/newhdrgen/tests/input/test_string.yaml b/libc/newhdrgen/tests/input/test_string.yaml
new file mode 100644
index 0000000000000..2754f856bc807
--- /dev/null
+++ b/libc/newhdrgen/tests/input/test_string.yaml
@@ -0,0 +1,303 @@
+header: string.h
+macros: []
+types:
+  - type_name: size_t
+enums: []
+objects: []
+functions:
+  - name: memcpy
+    standards: 
+      - stdc
+    return_type: void *
+    arguments:
+      - type: void *__restrict
+      - type: const void *__restrict
+      - type: size_t
+  - name: memmove
+    standards: 
+      - stdc
+    return_type: void *
+    arguments:
+      - type: void *
+      - type: const void *
+      - type: size_t
+  - name: memcmp
+    standards: 
+      - stdc
+    return_type: int
+    arguments:
+      - type: const void *
+      - type: const void *
+      - type: size_t
+  - name: memchr
+    standards: 
+      - stdc
+    return_type: void *
+    arguments:
+      - type: const void *
+      - type: int
+      - type: size_t
+  - name: memset
+    standards: 
+      - stdc
+    return_type: void *
+    arguments:
+      - type: void *
+      - type: int
+      - type: size_t
+  - name: memset_explicit
+    standards: 
+      - stdc
+    return_type: void *
+    arguments:
+      - type: void *
+      - type: int
+      - type: size_t
+  - name: strcpy
+    standards: 
+      - stdc
+    return_type: char
+    arguments:
+      - type: char *__restrict
+      - type: const char *__restrict
+  - name: strncpy
+    standards: 
+      - stdc
+    return_type: char *
+    arguments:
+      - type: char *__restrict
+      - type: const char *__restrict
+      - type: size_t
+  - name: strcat
+    standards: 
+      - stdc
+    return_type: char *
+    arguments:
+      - type: char *__restrict
+      - type: const char *__restrict
+  - name: strncat
+    standards: 
+      - stdc
+    return_type: char *
+    arguments:
+      - type: char *
+      - type: const char *
+      - type: size_t
+  - name: strcmp
+    standards: 
+      - stdc
+    return_type: int
+    arguments:
+      - type: const char *
+      - type: const char *
+  - name: strcoll
+    standards: 
+      - stdc
+    return_type: int
+    arguments:
+      - type: const char *
+      - type: const char *
+  - name: strncmp
+    standards: 
+      - stdc
+    return_type: int
+    arguments:
+      - type: const char *
+      - type: const char *
+      - type: size_t
+  - name: strxfrm
+    standards: 
+      - stdc
+    return_type: size_t
+    arguments:
+      - type: char *__restrict
+      - type: const char *__restrict
+      - type: size_t
+  - name: strchr
+    standards: 
+      - stdc
+    return_type: char *
+    arguments:
+      - type: const char *
+      - type: int
+  - name: strcspn
+    standards: 
+      - stdc
+    return_type: size_t
+    arguments:
+      - type: const char *
+      - type: const char *
+  - name: strdup
+    return_type: char *
+    arguments:
+      - type: const char *
+  - name: strndup
+    standards: 
+      - stdc
+    return_type: char *
+    arguments:
+      - type: const char *
+      - type: size_t
+  - name: strpbrk
+    standards: 
+      - stdc
+    return_type: char *
+    arguments:
+      - type: const char *
+      - type: const char *
+  - name: strrchr
+    standards: 
+      - stdc
+    return_type: char *
+    arguments:
+      - type: const char *
+      - type: int
+  - name: strspn
+    standards: 
+      - stdc
+    return_type: size_t
+    arguments:
+      - type: const char *
+      - type: const char *
+  - name: strstr
+    standards: 
+      - stdc
+    return_type: char *
+    arguments:
+      - type: const char *
+      - type: const char *
+  - name: strtok
+    standards: 
+      - stdc
+    return_type: char *
+    arguments:
+      - type: char *__restrict
+      - type: const char *__restrict
+  - name: strerror
+    standards: 
+      - stdc
+    return_type: char *
+    arguments:
+      - type: int
+  - name: strlen
+    standards: 
+      - stdc
+    return_type: size_t
+    arguments:
+      - type: const char *
+  - name: memccpy
+    standards: 
+      - POSIX
+    return_type: void *
+    arguments:
+      - type: void *__restrict
+      - type: const void *__restrict
+      - type: int
+      - type: size_t
+  - name: mempcpy
+    standards: 
+      - POSIX
+    return_type: void *
+    arguments:
+      - type: void *__restrict
+      - type: const void *__restrict
+      - type: size_t
+  - name: stpcpy
+    standards: 
+      - POSIX
+    return_type: char *
+    arguments:
+      - type: char *__restrict
+      - type: const char *__restrict
+  - name: stpncpy
+    standards: 
+      - POSIX
+    return_type: char *
+    arguments:
+      - type: char *__restrict
+      - type: const char *__restrict
+      - type: size_t
+  - name: strnlen
+    standards: 
+      - POSIX
+    return_type: size_t
+    arguments:
+      - type: const char *
+      - type: size_t
+  - name: strtok_r
+    standards: 
+      - POSIX
+    return_type: char *
+    arguments:
+      - type: char *__restrict
+      - type: const char *__restrict
+      - type: char ** __restrict
+  - name: strsignal
+    standards: 
+      - POSIX
+    return_type: char *
+    arguments:
+      - type: int
+  - name: memmem
+    standards: 
+      - GNUExtensions
+    return_type: void *
+    arguments:
+      - type: const void *
+      - type: size_t
+      - type: const void *
+      - type: size_t
+  - name: memrchr
+    standards: 
+      - GNUExtensions
+    return_type: void *
+    arguments:
+      - type: const void *
+      - type: int
+      - type: size_t
+  - name: strerror_r
+    standards: 
+      - GNUExtensions
+    return_type: char *
+    arguments:
+      - type: int
+      - type: char *
+      - type: size_t
+  - name: strcasestr
+    standards: 
+      - GNUExtensions
+    return_type: char *
+    arguments:
+      - type: const char *
+      - type: const char *
+  - name: strchrnul
+    standards: 
+      - GNUExtensions
+    return_type: char *
+    arguments:
+      - type: const char *
+      - type: int
+  - name: strlcat
+    standards: 
+      - BSDExtensions
+    return_type: size_t
+    arguments:
+      - type: char *__restrict
+      - type: char *__restrict
+      - type: size_t
+  - name: strlcpy
+    standards: 
+      - BSDExtensions
+    return_type: size_t
+    arguments:
+      - type: char *__restrict
+      - type: char *__restrict
+      - type: size_t
+  - name: strsep
+    standards: 
+      - BSDExtensions
+    return_type: char *
+    arguments:
+      - type: char **__restrict
+      - type: char *__restrict
+
diff --git a/libc/newhdrgen/tests/test_integration.py b/libc/newhdrgen/tests/test_integration.py
new file mode 100644
index 0000000000000..ca485dc0377c1
--- /dev/null
+++ b/libc/newhdrgen/tests/test_integration.py
@@ -0,0 +1,42 @@
+import subprocess
+import unittest
+from pathlib import Path
+
+class TestHeaderGenIntegration(unittest.TestCase):
+    def setUp(self):
+        self.output_dir = Path('tests/output')
+        self.maxDiff = None  
+
+    def run_script(self, yaml_file, h_def_file, output_dir):
+        result = subprocess.run([
+            'python3', 'yaml_to_classes.py', yaml_file, h_def_file, '--output_dir', str(output_dir)
+        ], capture_output=True, text=True)
+
+        print("STDOUT:", result.stdout)
+        print("STDERR:", result.stderr)
+        result.check_returncode() 
+
+    def compare_files(self, generated_file, expected_file):
+        with generated_file.open('r') as gen_file:
+            gen_content = gen_file.read()
+        with expected_file.open('r') as exp_file:
+            exp_content = exp_file.read()
+        
+        self.assertEqual(gen_content, exp_content)
+
+    def test_generate_header(self):
+        # this is for example, will find a way to test everything at once
+        yaml_file = Path('tests/input/test_string.yaml')
+        h_def_file = Path('tests/input/string.h.def')
+        expected_output_file = Path('tests/expected_output/string.h')
+        output_file = self.output_dir / 'string.h'
+
+        if not self.output_dir.exists():
+            self.output_dir.mkdir(parents=True)
+
+        self.run_script(yaml_file, h_def_file, self.output_dir)
+
+        self.compare_files(output_file, expected_output_file)
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/libc/newhdrgen/yaml_to_classes.py b/libc/newhdrgen/yaml_to_classes.py
index 9b52c9cf9bb7c..65a990c8a8767 100644
--- a/libc/newhdrgen/yaml_to_classes.py
+++ b/libc/newhdrgen/yaml_to_classes.py
@@ -46,11 +46,13 @@ def yaml_to_classes(yaml_data):
             Enumeration(enum_data["name"], enum_data.get("value", None))
         )
 
-    for function_data in yaml_data.get("functions", []):
+    functions = yaml_data.get("functions", [])
+    sorted_functions = sorted(functions, key=lambda x: x['name'])
+    for function_data in sorted_functions:
         arguments = [arg["type"] for arg in function_data["arguments"]]
         guard = function_data.get("guard", None)
         attributes = function_data.get("attributes", None)
-        standards = (function_data.get("standards", None),)
+        standards = function_data.get("standards", None)
         header.add_function(
             Function(
                 function_data["return_type"],

@aaryanshukla aaryanshukla changed the title adding tests [libc] created integration tests for newhdrgen Jul 1, 2024
Copy link

github-actions bot commented Jul 1, 2024

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff 03e46475f510d9d7fa813dcfa1fd91894af39862 36332e3562f558af01a4ae1f161da5ec7f8c416e -- libc/newhdrgen/tests/expected_output/test_header.h libc/newhdrgen/tests/output/test_small.h
View the diff from clang-format here.
diff --git a/libc/newhdrgen/tests/expected_output/test_header.h b/libc/newhdrgen/tests/expected_output/test_header.h
index d6ae0d0e28..be891cdb61 100644
--- a/libc/newhdrgen/tests/expected_output/test_header.h
+++ b/libc/newhdrgen/tests/expected_output/test_header.h
@@ -27,11 +27,11 @@ enum {
 __BEGIN_C_DECLS
 
 #ifdef FUNC_A_16
-void func_a()CONST_FUNC_A;
+void func_a() CONST_FUNC_A;
 #endif // FUNC_A_16
 
 #ifdef FUNC_B_16
-int func_b(int, float)CONST_FUNC_B;
+int func_b(int, float) CONST_FUNC_B;
 #endif // FUNC_B_16
 
 extern obj object_1;
diff --git a/libc/newhdrgen/tests/output/test_small.h b/libc/newhdrgen/tests/output/test_small.h
index d6ae0d0e28..be891cdb61 100644
--- a/libc/newhdrgen/tests/output/test_small.h
+++ b/libc/newhdrgen/tests/output/test_small.h
@@ -27,11 +27,11 @@ enum {
 __BEGIN_C_DECLS
 
 #ifdef FUNC_A_16
-void func_a()CONST_FUNC_A;
+void func_a() CONST_FUNC_A;
 #endif // FUNC_A_16
 
 #ifdef FUNC_B_16
-int func_b(int, float)CONST_FUNC_B;
+int func_b(int, float) CONST_FUNC_B;
 #endif // FUNC_B_16
 
 extern obj object_1;

Copy link

github-actions bot commented Jul 1, 2024

⚠️ Python code formatter, darker found issues in your code. ⚠️

You can test this locally with the following command:
darker --check --diff -r 03e46475f510d9d7fa813dcfa1fd91894af39862...36332e3562f558af01a4ae1f161da5ec7f8c416e libc/newhdrgen/tests/test_integration.py libc/newhdrgen/class_implementation/classes/enumeration.py libc/newhdrgen/class_implementation/classes/function.py libc/newhdrgen/class_implementation/classes/object.py libc/newhdrgen/header.py libc/newhdrgen/yaml_to_classes.py
View the diff from darker here.
--- tests/test_integration.py	2024-07-02 23:49:18.000000 +0000
+++ tests/test_integration.py	2024-07-03 21:32:14.245233 +0000
@@ -17,11 +17,13 @@
         output_dir_env = os.getenv("TEST_OUTPUT_DIR")
 
         self.output_dir = Path(
             args.output_dir
             if args.output_dir
-            else output_dir_env if output_dir_env else "libc/newhdrgen/tests/output"
+            else output_dir_env
+            if output_dir_env
+            else "libc/newhdrgen/tests/output"
         )
 
         self.maxDiff = None
         # Adjust based on your directory structure such as being in build etc.
         self.source_dir = Path(__file__).resolve().parent.parent.parent.parent

@@ -0,0 +1,303 @@
header: string.h
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the test, you should make a much smaller yaml file, probably with a different name as well (so it's clear this is just for testing). You also need to make sure you're testing all of the parts, not just functioins. I'd recommend something like this:

header: test_header.h
macros: [MACRO_A, MACRO_B]
types: [type_a, type_b]
enums: [enum_a: [value_1, value_2], enum_b: [value_3]]
objects: [object_1, object_2]
functions: [list of functions]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently it tests the expected output such as string.h from the build directory vs string.h from us. Each line is compared to ensure that the certain macros, enums, objects, etc are there. Does that cover testing all parts?

changed header.py for spacing issues
added .strip to script for spacing issues
@aaryanshukla aaryanshukla requested a review from lntue July 2, 2024 22:53

set(NEWHDGEN_TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tests)

add_test(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add only when in full build mode

Not sure if this is correct but: if(CMAKE_BUILD_TYPE STREQUAL FULL) /..../ endif()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix!

Copy link
Contributor

@michaelrj-google michaelrj-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@aaryanshukla aaryanshukla merged commit 6aed0d5 into llvm:main Jul 3, 2024
3 of 5 checks passed
kbluck pushed a commit to kbluck/llvm-project that referenced this pull request Jul 6, 2024
- created integration tests for libc hdrgen 
- implemented sorting function names in yaml files through script
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants