Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a0d3789 authored by Anjana Sherin's avatar Anjana Sherin Committed by Android (Google) Code Review
Browse files

Merge changes from topic "vkjson-tests" into main

* changes:
  Unit tests for vkjson.h generation
  Unit tests for vkjson_gen_util (Part 2/3)
parents 187edc86 97fc923f
Loading
Loading
Loading
Loading
+450 −37
Original line number Original line Diff line number Diff line
#!/usr/bin/env python3
#!/usr/bin/env python3
#
#
# Copyright 2019 The Android Open Source Project
# Copyright 2025 The Android Open Source Project
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# you may not use this file except in compliance with the License.
@@ -18,13 +18,79 @@
This file contains unit tests for vkjson_gen_util.py
This file contains unit tests for vkjson_gen_util.py
Each test class focuses on one specific util function.
Each test class focuses on one specific util function.


Temporary location for this file, pending CI/CD integration.
TODO (b/416165162):
* Temporary location for this file, pending CI/CD integration
* Testing infrastructure (such as BaseMockCodeFileTest etc.) should ideally be hosted in dedicated files within the test folder
"""
"""

import difflib
import re
import unittest
import unittest
from unittest.mock import Mock, patch
from unittest.mock import Mock, patch


import vkjson_gen_util as src
import vkjson_gen_util as src
from dataclasses import dataclass


class BaseCodeAssertTest(unittest.TestCase):

    @staticmethod
    def normalise_for_code_compare(code: str):
        return re.sub(r'\s+', '', code)

    @staticmethod
    def normalise_for_diff_compare(code: str):
        return [
            line.strip()
            for line in code.splitlines()
        ]

    def assertCodeEqual(self, expected_code_str: str, actual_code_str: str):
        """
        This code comparator lacks semantic awareness and performs a naive normalization by
        stripping all whitespace characters, without distinguishing between executable code,
        string literals, or comments.

        Eg: It would treat "Hello world" and "Helloworld" as identical.
        """

        expected_normalised = self.normalise_for_code_compare(expected_code_str)
        actual_normalised = self.normalise_for_code_compare(actual_code_str)

        if expected_normalised == actual_normalised:
            pass
        else:
            expected_for_diff = self.normalise_for_diff_compare(expected_code_str)
            actual_for_diff = self.normalise_for_diff_compare(actual_code_str)

            diff_generator = difflib.unified_diff(
                expected_for_diff,
                actual_for_diff,
                fromfile="Expected Code",
                tofile="Actual Code",
                lineterm="",
                n=1
            )

            diff_output = "\n".join(diff_generator)
            standard_message = (
                f"Test failed: Non-whitespace code differences detected."
                f"---------------------------------------------------\n"
                f"{diff_output}\n"
                f"---------------------------------------------------"
            )

            failure_message = self._formatMessage(None, standard_message)
            self.fail(failure_message)


class BaseMockCodeFileTest(BaseCodeAssertTest):

    def setUp(self):
        self.mock_file = Mock()

    def assertCodeFileWrite(self, expected_code_str: str):
        actual_code_str = "".join([c.args[0] for c in self.mock_file.write.call_args_list])
        self.assertCodeEqual(expected_code_str, actual_code_str)




class TestGetCopyrightWarnings(unittest.TestCase):
class TestGetCopyrightWarnings(unittest.TestCase):
@@ -155,7 +221,7 @@ class TestGetStructName(unittest.TestCase):
            "id_properties",
            "id_properties",
            src.get_struct_name("VkPhysicalDeviceIDProperties")
            src.get_struct_name("VkPhysicalDeviceIDProperties")
        )
        )
        # TODO - Fix source code
        # TODO (b/401184058)- Fix source code
        # self.assertEqual(
        # self.assertEqual(
        #     "id_features",
        #     "id_features",
        #     src.get_struct_name("VkPhysicalDeviceIDFeatures")
        #     src.get_struct_name("VkPhysicalDeviceIDFeatures")
@@ -190,7 +256,7 @@ class TestGetStructName(unittest.TestCase):
            "bit8_storage_features_khr",
            "bit8_storage_features_khr",
            src.get_struct_name("VkPhysicalDevice8BitStorageFeaturesKHR"),
            src.get_struct_name("VkPhysicalDevice8BitStorageFeaturesKHR"),
        )
        )
        # TODO - Fix source code
        # TODO (b/401184058)- Fix source code
        # self.assertEqual(
        # self.assertEqual(
        #     "bit16_storage_properties",
        #     "bit16_storage_properties",
        #     src.get_struct_name("VkPhysicalDevice16BitStorageProperties")
        #     src.get_struct_name("VkPhysicalDevice16BitStorageProperties")
@@ -203,10 +269,368 @@ class TestGetStructName(unittest.TestCase):
        )
        )




class TestEmitStructVisitsByVkVersion(unittest.TestCase):
class TestGenerateExtensionStructDefinition(BaseMockCodeFileTest):

    @patch('vkjson_gen_util.VK')
    def test_extension_with_single_struct(self, mock_vk):
        mock_vk.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING = {
            "extensions": {
                "VK_KHR_driver_state": [
                    {"VkPhysicalDeviceDriverPropertiesKHR": "VK_STRUCT_DRIVER"}
                ]
            }
        }

        extension_struct = src.get_vkjson_struct_name("VK_KHR_driver_state")
        struct_name = src.get_struct_name("VkPhysicalDeviceDriverPropertiesKHR")

        expected_lines = (
            f"""struct {extension_struct} {{
              {extension_struct}() {{
                reported = false;
                memset(&{struct_name}, 0, sizeof(VkPhysicalDeviceDriverPropertiesKHR));
              }}
              bool reported;
              VkPhysicalDeviceDriverPropertiesKHR {struct_name};
            }};"""
        )

        self.assertEqual(
            [f"{extension_struct} {src.get_vkjson_struct_variable_name("VK_KHR_driver_state")}"],
            src.generate_extension_struct_definition(self.mock_file)
        )
        self.assertCodeFileWrite(expected_lines)

    @patch('vkjson_gen_util.VK')
    def test_extension_with_multiple_structs(self, mock_vk):
        mock_vk.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING = {
            "extensions": {
                "VK_KHR_variable_pointers": [
                    {"VkPhysicalDeviceVariablePointerFeaturesKHR": "VK_STRUCT_VARIABLE",
                     "VkPhysicalDeviceVariablePointersFeaturesKHR": "VK_STRUCT_VARIABLES"},
                    {"SomeThingElse": "SOME_OTHER_STRUCT"}
                ]
            }
        }

        extension_struct = src.get_vkjson_struct_name("VK_KHR_variable_pointers")
        struct_1_name = src.get_struct_name("VkPhysicalDeviceVariablePointerFeaturesKHR")
        struct_2_name = src.get_struct_name("VkPhysicalDeviceVariablePointersFeaturesKHR")
        struct_3_name = src.get_struct_name("SomeThingElse")

        expected_lines = (
            f"""struct {extension_struct} {{
              {extension_struct}() {{
                reported = false;
                memset(&{struct_1_name}, 0, sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR));
                memset(&{struct_2_name}, 0, sizeof(VkPhysicalDeviceVariablePointersFeaturesKHR));
                memset(&{struct_3_name}, 0, sizeof(SomeThingElse));
              }}
              bool reported;
              VkPhysicalDeviceVariablePointerFeaturesKHR {struct_1_name};
              VkPhysicalDeviceVariablePointersFeaturesKHR {struct_2_name};
              SomeThingElse {struct_3_name};
            }};"""
        )

        self.assertEqual(
            [
                f"{extension_struct} {src.get_vkjson_struct_variable_name("VK_KHR_variable_pointers")}"],
            src.generate_extension_struct_definition(self.mock_file)
        )
        self.assertCodeFileWrite(expected_lines)

    @patch('vkjson_gen_util.VK')
    def test_extension_without_structs(self, mock_vk):
        mock_vk.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING = {
            "extensions": {
                "VK_EXT_image_2d_view_of_3d": []
            }
        }

        extension_struct = src.get_vkjson_struct_name("VK_EXT_image_2d_view_of_3d")

        expected_lines = (
            f"""struct {extension_struct} {{
              {extension_struct}() {{
                reported = false;
              }}
              bool reported;
            }};"""
        )

        self.assertEqual(
            [
                f"{extension_struct} {src.get_vkjson_struct_variable_name("VK_EXT_image_2d_view_of_3d")}"],
            src.generate_extension_struct_definition(self.mock_file)
        )
        self.assertCodeFileWrite(expected_lines)

    @patch('vkjson_gen_util.VK')
    def test_multiple_extensions(self, mock_vk):
        mock_vk.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING = {
            "extensions": {
                "VK_EXT_custom_border_color": [
                    {"VkPhysicalDeviceCustomBorderColorFeatsEXT": "VK_STRUCT_COLOR"}
                ],
                "VK_KHR_shader_float_controls": [
                    {"VkPhysicalDeviceFloatControlsFeatsKHR": "VK_STRUCT_FLOAT"}
                ]
            }
        }

        extension_1_struct = src.get_vkjson_struct_name("VK_EXT_custom_border_color")
        struct_1_name = src.get_struct_name("VkPhysicalDeviceCustomBorderColorFeatsEXT")
        extension_2_struct = src.get_vkjson_struct_name("VK_KHR_shader_float_controls")
        struct_2_name = src.get_struct_name("VkPhysicalDeviceFloatControlsFeatsKHR")

        expected_lines = (
            f"""struct {extension_1_struct} {{
              {extension_1_struct}() {{
                reported = false;
                memset(&{struct_1_name}, 0, sizeof(VkPhysicalDeviceCustomBorderColorFeatsEXT));
              }}
              bool reported;
              VkPhysicalDeviceCustomBorderColorFeatsEXT {struct_1_name};
            }};

            struct {extension_2_struct} {{
              {extension_2_struct}() {{
                reported = false;
                memset(&{struct_2_name}, 0, sizeof(VkPhysicalDeviceFloatControlsFeatsKHR));
              }}
              bool reported;
              VkPhysicalDeviceFloatControlsFeatsKHR {struct_2_name};
            }};"""
        )

        self.assertEqual(
            [
                f"{extension_1_struct} {src.get_vkjson_struct_variable_name("VK_EXT_custom_border_color")}",
                f"{extension_2_struct} {src.get_vkjson_struct_variable_name("VK_KHR_shader_float_controls")}",
            ],
            src.generate_extension_struct_definition(self.mock_file)
        )
        self.assertCodeFileWrite(expected_lines)

    @patch('vkjson_gen_util.VK')
    def test_empty_extensions(self, mock_vk):
        mock_vk.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING = {
            "extensions": {}
        }

        self.assertEqual([], src.generate_extension_struct_definition(self.mock_file))
        self.assertCodeFileWrite("")


class TestGenerateVkCoreStructDefinition(BaseMockCodeFileTest):

    @patch('vkjson_gen_util.VK')
    def test_core_with_single_struct(self, mock_vk):
        mock_vk.VULKAN_CORES_AND_STRUCTS_MAPPING = {
            "versions": {
                "Core11": [
                    {"VkVulkan11Properties": "VK_STRUCT_TYPE_VULKAN_1_1_PROPERTIES"}
                ]
            }
        }

        expected_lines = (
            """struct VkJsonCore11 {
              VkJsonCore11() {
                memset(&properties, 0, sizeof(VkVulkan11Properties));
              }
              VkVulkan11Properties properties;
            };"""
        )

        self.assertEqual(
            ["VkJsonCore11 core11"],
            src.generate_vk_core_struct_definition(self.mock_file)
        )
        self.assertCodeFileWrite(expected_lines)

    @patch('vkjson_gen_util.VK')
    def test_core_with_multiple_structs(self, mock_vk):
        mock_vk.VULKAN_CORES_AND_STRUCTS_MAPPING = {
            "versions": {
                "Core13": [
                    {"VkVulkan13Features": "VK_STRUCT_TYPE_VULKAN_1_3_FEATURES",
                     "VkVulkan13Properties": "VK_STRUCT_TYPE_VULKAN_1_3_PROPERTIES"}
                ]
            }
        }

        expected_lines = (
            """struct VkJsonCore13 {
              VkJsonCore13() {
                memset(&features, 0, sizeof(VkVulkan13Features));
                memset(&properties, 0, sizeof(VkVulkan13Properties));
              }
              VkVulkan13Features features;
              VkVulkan13Properties properties;
            };"""
        )

        self.assertEqual(
            ["VkJsonCore13 core13"],
            src.generate_vk_core_struct_definition(self.mock_file)
        )
        self.assertCodeFileWrite(expected_lines)

    @patch('vkjson_gen_util.VK')
    def test_core14(self, mock_vk):
        mock_vk.VULKAN_CORES_AND_STRUCTS_MAPPING = {
            "versions": {
                "Core14": [
                    {"VkVulkan14Properties": "VK_STRUCT_TYPE_VULKAN_1_4_PROPERTIES"},
                    {"VkVulkan14Features": "VK_STRUCT_TYPE_VULKAN_1_4_FEATURES"}
                ]
            }
        }

        expected_lines = (
            """struct VkJsonCore14 {
              VkJsonCore14() {
                memset(&properties, 0, sizeof(VkVulkan14Properties));
                memset(&features, 0, sizeof(VkVulkan14Features));
              }
              VkVulkan14Properties properties;
              VkVulkan14Features features;
              std::vector<VkImageLayout> copy_src_layouts;
              std::vector<VkImageLayout> copy_dst_layouts;
            };"""
        )

        self.assertEqual(
            ["VkJsonCore14 core14"],
            src.generate_vk_core_struct_definition(self.mock_file)
        )
        self.assertCodeFileWrite(expected_lines)

    @patch('vkjson_gen_util.VK')
    def test_core_without_structs(self, mock_vk):
        mock_vk.VULKAN_CORES_AND_STRUCTS_MAPPING = {
            "versions": {
                "Core10": []
            }
        }

        expected_lines = (
            """struct VkJsonCore10 {
              VkJsonCore10() { }
            };"""
        )

        self.assertEqual(
            ["VkJsonCore10 core10"],
            src.generate_vk_core_struct_definition(self.mock_file)
        )
        self.assertCodeFileWrite(expected_lines)

    @patch('vkjson_gen_util.VK')
    def test_multiple_cores(self, mock_vk):
        mock_vk.VULKAN_CORES_AND_STRUCTS_MAPPING = {
            "versions": {
                "Core11": [
                    {"VkVulkan11Properties": "VK_STRUCT_TYPE_VULKAN_1_1_PROPERTIES"}
                ],
                "Core12": [
                    {"VkVulkan12Features": "VK_STRUCT_TYPE_VULKAN_1_2_FEATURES"}
                ]
            }
        }

        expected_lines = (
            """struct VkJsonCore11 {
              VkJsonCore11() {
                memset(&properties, 0, sizeof(VkVulkan11Properties));
              }
              VkVulkan11Properties properties;
            };

            struct VkJsonCore12 {
              VkJsonCore12() {
                memset(&features, 0, sizeof(VkVulkan12Features));
              }
              VkVulkan12Features features;
            };"""
        )

        self.assertEqual(
            [
                "VkJsonCore11 core11",
                "VkJsonCore12 core12"
            ],
            src.generate_vk_core_struct_definition(self.mock_file)
        )
        self.assertCodeFileWrite(expected_lines)

    @patch('vkjson_gen_util.VK')
    def test_no_cores(self, mock_vk):
        mock_vk.VULKAN_CORES_AND_STRUCTS_MAPPING = {
            "versions": {}
        }

        self.assertEqual([], src.generate_vk_core_struct_definition(self.mock_file))
        self.assertCodeFileWrite("")


class TestGenerateMemsetStatements(BaseMockCodeFileTest):
    @dataclass
    class VkCustomExtension1:
        memberInt: int = 0

    @dataclass
    class VkCustomExtension2:
        memberBool: bool = False

    @dataclass
    class VkCustomExtension3:
        memberString: str = ""

    @patch('vkjson_gen_util.VK')
    def test_multiple_structs(self, mock_vk):
        mock_vk.EXTENSION_INDEPENDENT_STRUCTS = [
            self.VkCustomExtension1,
            self.VkCustomExtension2,
            self.VkCustomExtension3
        ]

        struct_1_name = src.get_struct_name("VkCustomExtension1")
        struct_2_name = src.get_struct_name("VkCustomExtension2")
        struct_3_name = src.get_struct_name("VkCustomExtension3")

        expected_lines = (
            f"""memset(&{struct_1_name}, 0, sizeof(VkCustomExtension1));
            memset(&{struct_2_name}, 0, sizeof(VkCustomExtension2));
            memset(&{struct_3_name}, 0, sizeof(VkCustomExtension3));
            """
        )

        self.assertEqual(
            [
                f"VkCustomExtension1 {struct_1_name}",
                f"VkCustomExtension2 {struct_2_name}",
                f"VkCustomExtension3 {struct_3_name}",
            ],
            src.generate_memset_statements(self.mock_file)
        )

        self.assertCodeFileWrite(expected_lines)

    @patch('vkjson_gen_util.VK')
    def test_no_structs(self, mock_vk):
        mock_vk.EXTENSION_INDEPENDENT_STRUCTS = []

        self.assertEqual([], src.generate_memset_statements(self.mock_file))
        self.assertCodeFileWrite("")


class TestEmitStructVisitsByVkVersion(BaseMockCodeFileTest):


    def setUp(self):
    def setUp(self):
        self.mock_file = Mock()
        super().setUp()
        self.mock_vk_patcher = patch('vkjson_gen_util.VK')
        self.mock_vk_patcher = patch('vkjson_gen_util.VK')
        self.mock_get_struct_name_patcher = patch('vkjson_gen_util.get_struct_name')
        self.mock_get_struct_name_patcher = patch('vkjson_gen_util.get_struct_name')


@@ -247,65 +671,54 @@ class TestEmitStructVisitsByVkVersion(unittest.TestCase):


    def test_handles_single_matching_struct(self):
    def test_handles_single_matching_struct(self):
        expected_lines = (
        expected_lines = (
            f'visitor->Visit("subgroupProperties", &device->subgroup_properties) &&\n'
            'visitor->Visit("subgroupProperties", &device->subgroup_properties) &&'
        )
        )


        src.emit_struct_visits_by_vk_version(self.mock_file, "VK_VERSION_1_1")
        src.emit_struct_visits_by_vk_version(self.mock_file, "VK_VERSION_1_1")
        self.assertEqual(
        self.assertCodeFileWrite(expected_lines)
            expected_lines, "".join([c.args[0] for c in self.mock_file.write.call_args_list])
        )


    def test_handles_multiple_matching_structs(self):
    def test_handles_multiple_matching_structs(self):
        expected_lines = (
        expected_lines = (
            f'visitor->Visit("multiviewProperties", &device->multiview_properties) &&\n'
            """visitor->Visit("multiviewProperties", &device->multiview_properties) &&
            f'visitor->Visit("idProperties", &device->id_properties) &&\n'
            visitor->Visit("idProperties", &device->id_properties) &&
            f'visitor->Visit("multiviewFeatures", &device->multiview_features) &&\n'
            visitor->Visit("multiviewFeatures", &device->multiview_features) &&
            """
        )
        )


        src.emit_struct_visits_by_vk_version(self.mock_file, "VK_VERSION_1_2")
        src.emit_struct_visits_by_vk_version(self.mock_file, "VK_VERSION_1_2")
        self.assertEqual(
        self.assertCodeFileWrite(expected_lines)
            expected_lines, "".join([c.args[0] for c in self.mock_file.write.call_args_list])
        )


    def test_handles_empty_struct_type(self):
    def test_handles_empty_struct_type(self):
        expected_lines = f'visitor->Visit("lineFeatures", &device->line_features) &&\n'
        expected_lines = 'visitor->Visit("lineFeatures", &device->line_features) &&'


        src.emit_struct_visits_by_vk_version(self.mock_file, "VK_VERSION_1_0")
        src.emit_struct_visits_by_vk_version(self.mock_file, "VK_VERSION_1_0")
        self.assertEqual(
        self.assertCodeFileWrite(expected_lines)
            expected_lines, "".join([c.args[0] for c in self.mock_file.write.call_args_list])
        )


    def test_handles_struct_var_with_single_word(self):
    def test_handles_struct_var_with_single_word(self):
        self.mock_get_struct_name.side_effect = None
        self.mock_get_struct_name.side_effect = None
        self.mock_get_struct_name.return_value = "memory"
        self.mock_get_struct_name.return_value = "memory"
        expected_lines = f'visitor->Visit("memory", &device->memory) &&\n'
        expected_lines = 'visitor->Visit("memory", &device->memory) &&'


        src.emit_struct_visits_by_vk_version(self.mock_file, "VK_VERSION_1_1")
        src.emit_struct_visits_by_vk_version(self.mock_file, "VK_VERSION_1_1")
        self.assertEqual(
        self.assertCodeFileWrite(expected_lines)
            expected_lines, "".join([c.args[0] for c in self.mock_file.write.call_args_list])
        )


    # TODO - Fix source code
    def test_handles_struct_var_contains_number(self):
    def handles_struct_var_contains_number(self):
        self.mock_get_struct_name.side_effect = None
        self.mock_get_struct_name.side_effect = None
        self.mock_get_struct_name.return_value = "image_2d_view_of_3d_features_ext"
        self.mock_get_struct_name.return_value = "image_2d_view_of_3d_features_ext"
        expected_lines = f'visitor->Visit("image2dViewOf3dFeaturesExt", &device->image_2d_view_of_3d_features_ext) &&\n'

        # Considered acceptable
        expected_lines = 'visitor->Visit("image_2dViewOf_3dFeaturesExt", &device->image_2d_view_of_3d_features_ext) &&'


        src.emit_struct_visits_by_vk_version(self.mock_file, "VK_VERSION_1_1")
        src.emit_struct_visits_by_vk_version(self.mock_file, "VK_VERSION_1_1")
        self.assertEqual(
        self.assertCodeFileWrite(expected_lines)
            expected_lines, "".join([c.args[0] for c in self.mock_file.write.call_args_list])
        )


    # TODO - Fix source code
    def test_handles_struct_var_starts_with_underscore(self):
    def handles_struct_var_starts_with_underscore(self):
        self.mock_get_struct_name.side_effect = None
        self.mock_get_struct_name.side_effect = None
        self.mock_get_struct_name.return_value = "_3d_features_ext"
        self.mock_get_struct_name.return_value = "_3d_features_ext"
        expected_lines = f'visitor->Visit("3dFeaturesExt", &device->_3d_features_ext) &&\n'
        expected_lines = 'visitor->Visit("_3dFeaturesExt", &device->_3d_features_ext) &&'


        src.emit_struct_visits_by_vk_version(self.mock_file, "VK_VERSION_1_1")
        src.emit_struct_visits_by_vk_version(self.mock_file, "VK_VERSION_1_1")
        self.assertEqual(
        self.assertCodeFileWrite(expected_lines)
            expected_lines, "".join([c.args[0] for c in self.mock_file.write.call_args_list])
        )




class TestGenerateVkCoreStructsInitCode(unittest.TestCase):
class TestGenerateVkCoreStructsInitCode(unittest.TestCase):
+164 −0

File added.

Preview size limit exceeded, changes collapsed.