#!/usr/bin/env python3
#
# Copyright 2025 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from unittest.mock import ANY, mock_open, patch

import os
import base_test_helper as helper
import vkjson_generator as src

"""
This file contains unit tests for vkjson_generator.py
Each test class focuses on one generated file.
"""


class TestGenH(helper.BaseMockCodeFileTest):

    @patch('builtins.open', new_callable=mock_open)
    @patch('vkjson_generator.util')
    @patch('vkjson_generator.gencom')
    def test_header_file_generation(self, _, mock_util, mock_file_open):
        expected_abs_file_path = os.path.abspath(
            os.path.join(os.path.dirname(src.__file__), "..", "vkjson", "vkjson.h"))

        self.mock_file = mock_file_open.return_value
        mock_util.get_copyright_warnings.return_value = "\n// Copyright generated here\n"
        mock_util.generate_extension_struct_definition.side_effect = lambda *args, **kwargs: (
            self.mock_file.write("\n// Extension struct definitions generated here\n"),
            ["VkJsonExtension1 ext1", "VkJsonExtension2 ext2"]
        )[1]
        mock_util.generate_vk_core_struct_definition.side_effect = lambda *args, **kwargs: (
            self.mock_file.write("\n// Core struct definitions generated here\n"),
            ["VkJsonCore1 core1", "VkJsonCore2 core2"]
        )[1]
        mock_util.generate_memset_statements.side_effect = lambda *args, **kwargs: (
            self.mock_file.write(
                "\n// Memset statements for extension independent structs generated here\n"),
            ["VkPhysicalDeviceProperties properties", "VkPhysicalDeviceFeatures features"]
        )[1]

        src.gen_h()
        mock_file_open.assert_called_once_with(ANY, "w")
        self.assertEqual(
            expected_abs_file_path,
            os.path.abspath(mock_file_open.call_args_list[0][0][0])
        )

        expected_lines = (
            """// Copyright generated here

            #ifndef VKJSON_H_
            #define VKJSON_H_

            #ifndef VK_USE_PLATFORM_ANDROID_KHR
            #define VK_USE_PLATFORM_ANDROID_KHR
            #endif

            #include <string.h>
            #include <vulkan/vulkan.h>

            #include <map>
            #include <string>
            #include <vector>

            #ifdef WIN32
            #undef min
            #undef max
            #endif

            /*
             * This file is autogenerated by vkjson_generator.py. Do not edit directly.
             */
            struct VkJsonLayer {
              VkLayerProperties properties;
              std::vector<VkExtensionProperties> extensions;
            };

            // Extension struct definitions generated here

            // Core struct definitions generated here

            struct VkJsonDevice {
              VkJsonDevice() {
                // Memset statements for extension independent structs generated here
              }
              VkJsonExtension1 ext1;
              VkJsonExtension2 ext2;
              VkJsonCore1 core1;
              VkJsonCore2 core2;
              VkPhysicalDeviceProperties properties;
              VkPhysicalDeviceFeatures features;
              std::vector<VkQueueFamilyProperties> queues;
              std::vector<VkExtensionProperties> extensions;
              std::vector<VkLayerProperties> layers;
              std::map<VkFormat, VkFormatProperties> formats;
              std::map<VkExternalFenceHandleTypeFlagBits, VkExternalFenceProperties> external_fence_properties;
              std::map<VkExternalSemaphoreHandleTypeFlagBits, VkExternalSemaphoreProperties> external_semaphore_properties;
            };

            struct VkJsonDeviceGroup {
              VkJsonDeviceGroup() {
                memset(&properties, 0, sizeof(VkPhysicalDeviceGroupProperties));
              }
              VkPhysicalDeviceGroupProperties properties;
              std::vector<uint32_t> device_inds;
            };

            struct VkJsonInstance {
              VkJsonInstance() : api_version(0) {}
              uint32_t api_version;
              std::vector<VkJsonLayer> layers;
              std::vector<VkExtensionProperties> extensions;
              std::vector<VkJsonDevice> devices;
              std::vector<VkJsonDeviceGroup> device_groups;
            };

            VkJsonInstance VkJsonGetInstance();
            std::string VkJsonInstanceToJson(const VkJsonInstance& instance);
            bool VkJsonInstanceFromJson(const std::string& json,
                                        VkJsonInstance* instance,
                                        std::string* errors);

            VkJsonDevice VkJsonGetDevice(VkPhysicalDevice device);
            std::string VkJsonDeviceToJson(const VkJsonDevice& device);
            bool VkJsonDeviceFromJson(const std::string& json,
                                      VkJsonDevice* device,
                                      std::string* errors);

            std::string VkJsonImageFormatPropertiesToJson(
            const VkImageFormatProperties& properties);
            bool VkJsonImageFormatPropertiesFromJson(const std::string& json,
                                         VkImageFormatProperties* properties,
                                         std::string* errors);

            // Backward-compatibility aliases
            typedef VkJsonDevice VkJsonAllProperties;
            inline VkJsonAllProperties VkJsonGetAllProperties(VkPhysicalDevice physicalDevice) {
              return VkJsonGetDevice(physicalDevice);
            }
            inline std::string VkJsonAllPropertiesToJson(const VkJsonAllProperties& properties) {
              return VkJsonDeviceToJson(properties);
            }
            inline bool VkJsonAllPropertiesFromJson(const std::string& json,
                                            VkJsonAllProperties* properties,
                                            std::string* errors) {
              return VkJsonDeviceFromJson(json, properties, errors);
            }

            #endif  // VKJSON_H_"""
        )

        self.assertCodeFileWrite(expected_lines)
        self.mock_file.close.assert_called()
