xref: /aosp_15_r20/external/vulkan-validation-layers/scripts/vk_validation_stats.py (revision b7893ccf7851cd6a48cc5a1e965257d8a5cdcc70)
1*b7893ccfSSadaf Ebrahimi#!/usr/bin/env python3
2*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 The Khronos Group Inc.
3*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 Valve Corporation
4*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 LunarG, Inc.
5*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 Google Inc.
6*b7893ccfSSadaf Ebrahimi#
7*b7893ccfSSadaf Ebrahimi# Licensed under the Apache License, Version 2.0 (the "License");
8*b7893ccfSSadaf Ebrahimi# you may not use this file except in compliance with the License.
9*b7893ccfSSadaf Ebrahimi# You may obtain a copy of the License at
10*b7893ccfSSadaf Ebrahimi#
11*b7893ccfSSadaf Ebrahimi#     http://www.apache.org/licenses/LICENSE-2.0
12*b7893ccfSSadaf Ebrahimi#
13*b7893ccfSSadaf Ebrahimi# Unless required by applicable law or agreed to in writing, software
14*b7893ccfSSadaf Ebrahimi# distributed under the License is distributed on an "AS IS" BASIS,
15*b7893ccfSSadaf Ebrahimi# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*b7893ccfSSadaf Ebrahimi# See the License for the specific language governing permissions and
17*b7893ccfSSadaf Ebrahimi# limitations under the License.
18*b7893ccfSSadaf Ebrahimi#
19*b7893ccfSSadaf Ebrahimi# Author: Tobin Ehlis <[email protected]>
20*b7893ccfSSadaf Ebrahimi# Author: Dave Houlton <[email protected]>
21*b7893ccfSSadaf Ebrahimi# Author: Shannon McPherson <[email protected]>
22*b7893ccfSSadaf Ebrahimi
23*b7893ccfSSadaf Ebrahimiimport argparse
24*b7893ccfSSadaf Ebrahimiimport common_codegen
25*b7893ccfSSadaf Ebrahimiimport csv
26*b7893ccfSSadaf Ebrahimiimport glob
27*b7893ccfSSadaf Ebrahimiimport html
28*b7893ccfSSadaf Ebrahimiimport json
29*b7893ccfSSadaf Ebrahimiimport operator
30*b7893ccfSSadaf Ebrahimiimport os
31*b7893ccfSSadaf Ebrahimiimport platform
32*b7893ccfSSadaf Ebrahimiimport re
33*b7893ccfSSadaf Ebrahimiimport sys
34*b7893ccfSSadaf Ebrahimiimport time
35*b7893ccfSSadaf Ebrahimifrom collections import defaultdict
36*b7893ccfSSadaf Ebrahimi
37*b7893ccfSSadaf Ebrahimiverbose_mode = False
38*b7893ccfSSadaf Ebrahimitxt_db = False
39*b7893ccfSSadaf Ebrahimicsv_db = False
40*b7893ccfSSadaf Ebrahimihtml_db = False
41*b7893ccfSSadaf Ebrahimitxt_filename = "validation_error_database.txt"
42*b7893ccfSSadaf Ebrahimicsv_filename = "validation_error_database.csv"
43*b7893ccfSSadaf Ebrahimihtml_filename = "validation_error_database.html"
44*b7893ccfSSadaf Ebrahimiheader_filename = "vk_validation_error_messages.h"
45*b7893ccfSSadaf Ebrahimivuid_prefixes = ['VUID-', 'UNASSIGNED-']
46*b7893ccfSSadaf Ebrahimi
47*b7893ccfSSadaf Ebrahimi# Hard-coded flags that could be command line args, if we decide that's useful
48*b7893ccfSSadaf Ebrahimi# replace KHR vuids with non-KHR during consistency checking
49*b7893ccfSSadaf Ebrahimidealias_khr = True
50*b7893ccfSSadaf Ebrahimiignore_unassigned = True # These are not found in layer code unless they appear explicitly (most don't), so produce false positives
51*b7893ccfSSadaf Ebrahimi
52*b7893ccfSSadaf Ebrahimilayer_source_files = [common_codegen.repo_relative(path) for path in [
53*b7893ccfSSadaf Ebrahimi    'layers/buffer_validation.cpp',
54*b7893ccfSSadaf Ebrahimi    'layers/core_validation.cpp',
55*b7893ccfSSadaf Ebrahimi    'layers/descriptor_sets.cpp',
56*b7893ccfSSadaf Ebrahimi    'layers/drawdispatch.cpp',
57*b7893ccfSSadaf Ebrahimi    'layers/parameter_validation_utils.cpp',
58*b7893ccfSSadaf Ebrahimi    'layers/object_tracker_utils.cpp',
59*b7893ccfSSadaf Ebrahimi    'layers/shader_validation.cpp',
60*b7893ccfSSadaf Ebrahimi    'layers/stateless_validation.h',
61*b7893ccfSSadaf Ebrahimi    'layers/generated/parameter_validation.cpp',
62*b7893ccfSSadaf Ebrahimi    'layers/generated/object_tracker.cpp',
63*b7893ccfSSadaf Ebrahimi]]
64*b7893ccfSSadaf Ebrahimi
65*b7893ccfSSadaf Ebrahimitest_source_files = glob.glob(os.path.join(common_codegen.repo_relative('tests'), '*.cpp'))
66*b7893ccfSSadaf Ebrahimi
67*b7893ccfSSadaf Ebrahimi# This needs to be updated as new extensions roll in
68*b7893ccfSSadaf Ebrahimikhr_aliases = {
69*b7893ccfSSadaf Ebrahimi    'VUID-vkBindBufferMemory2KHR-device-parameter'                                        : 'VUID-vkBindBufferMemory2-device-parameter',
70*b7893ccfSSadaf Ebrahimi    'VUID-vkBindBufferMemory2KHR-pBindInfos-parameter'                                    : 'VUID-vkBindBufferMemory2-pBindInfos-parameter',
71*b7893ccfSSadaf Ebrahimi    'VUID-vkBindImageMemory2KHR-device-parameter'                                         : 'VUID-vkBindImageMemory2-device-parameter',
72*b7893ccfSSadaf Ebrahimi    'VUID-vkBindImageMemory2KHR-pBindInfos-parameter'                                     : 'VUID-vkBindImageMemory2-pBindInfos-parameter',
73*b7893ccfSSadaf Ebrahimi    'VUID-vkCmdDispatchBaseKHR-commandBuffer-parameter'                                   : 'VUID-vkCmdDispatchBase-commandBuffer-parameter',
74*b7893ccfSSadaf Ebrahimi    'VUID-vkCmdSetDeviceMaskKHR-commandBuffer-parameter'                                  : 'VUID-vkCmdSetDeviceMask-commandBuffer-parameter',
75*b7893ccfSSadaf Ebrahimi    'VUID-vkCreateDescriptorUpdateTemplateKHR-device-parameter'                           : 'VUID-vkCreateDescriptorUpdateTemplate-device-parameter',
76*b7893ccfSSadaf Ebrahimi    'VUID-vkCreateDescriptorUpdateTemplateKHR-pDescriptorUpdateTemplate-parameter'        : 'VUID-vkCreateDescriptorUpdateTemplate-pDescriptorUpdateTemplate-parameter',
77*b7893ccfSSadaf Ebrahimi    'VUID-vkCreateSamplerYcbcrConversionKHR-device-parameter'                             : 'VUID-vkCreateSamplerYcbcrConversion-device-parameter',
78*b7893ccfSSadaf Ebrahimi    'VUID-vkCreateSamplerYcbcrConversionKHR-pYcbcrConversion-parameter'                   : 'VUID-vkCreateSamplerYcbcrConversion-pYcbcrConversion-parameter',
79*b7893ccfSSadaf Ebrahimi    'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parameter'        : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parameter',
80*b7893ccfSSadaf Ebrahimi    'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parent'           : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parent',
81*b7893ccfSSadaf Ebrahimi    'VUID-vkDestroyDescriptorUpdateTemplateKHR-device-parameter'                          : 'VUID-vkDestroyDescriptorUpdateTemplate-device-parameter',
82*b7893ccfSSadaf Ebrahimi    'VUID-vkDestroySamplerYcbcrConversionKHR-device-parameter'                            : 'VUID-vkDestroySamplerYcbcrConversion-device-parameter',
83*b7893ccfSSadaf Ebrahimi    'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parameter'                   : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parameter',
84*b7893ccfSSadaf Ebrahimi    'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parent'                      : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parent',
85*b7893ccfSSadaf Ebrahimi    'VUID-vkEnumeratePhysicalDeviceGroupsKHR-instance-parameter'                          : 'VUID-vkEnumeratePhysicalDeviceGroups-instance-parameter',
86*b7893ccfSSadaf Ebrahimi    'VUID-vkEnumeratePhysicalDeviceGroupsKHR-pPhysicalDeviceGroupProperties-parameter'    : 'VUID-vkEnumeratePhysicalDeviceGroups-pPhysicalDeviceGroupProperties-parameter',
87*b7893ccfSSadaf Ebrahimi    'VUID-vkGetBufferMemoryRequirements2KHR-device-parameter'                             : 'VUID-vkGetBufferMemoryRequirements2-device-parameter',
88*b7893ccfSSadaf Ebrahimi    'VUID-vkGetDescriptorSetLayoutSupportKHR-device-parameter'                            : 'VUID-vkGetDescriptorSetLayoutSupport-device-parameter',
89*b7893ccfSSadaf Ebrahimi    'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-device-parameter'                         : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-device-parameter',
90*b7893ccfSSadaf Ebrahimi    'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-pPeerMemoryFeatures-parameter'            : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-pPeerMemoryFeatures-parameter',
91*b7893ccfSSadaf Ebrahimi    'VUID-vkGetImageMemoryRequirements2KHR-device-parameter'                              : 'VUID-vkGetImageMemoryRequirements2-device-parameter',
92*b7893ccfSSadaf Ebrahimi    'VUID-vkGetImageSparseMemoryRequirements2KHR-device-parameter'                        : 'VUID-vkGetImageSparseMemoryRequirements2-device-parameter',
93*b7893ccfSSadaf Ebrahimi    'VUID-vkGetImageSparseMemoryRequirements2KHR-pSparseMemoryRequirements-parameter'     : 'VUID-vkGetImageSparseMemoryRequirements2-pSparseMemoryRequirements-parameter',
94*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-physicalDevice-parameter'        : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-physicalDevice-parameter',
95*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-physicalDevice-parameter'         : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-physicalDevice-parameter',
96*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-physicalDevice-parameter'     : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-physicalDevice-parameter',
97*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceFeatures2KHR-physicalDevice-parameter'                       : 'VUID-vkGetPhysicalDeviceFeatures2-physicalDevice-parameter',
98*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceFormatProperties2KHR-format-parameter'                       : 'VUID-vkGetPhysicalDeviceFormatProperties2-format-parameter',
99*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceFormatProperties2KHR-physicalDevice-parameter'               : 'VUID-vkGetPhysicalDeviceFormatProperties2-physicalDevice-parameter',
100*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-physicalDevice-parameter'          : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-physicalDevice-parameter',
101*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceMemoryProperties2KHR-physicalDevice-parameter'               : 'VUID-vkGetPhysicalDeviceMemoryProperties2-physicalDevice-parameter',
102*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceProperties2KHR-physicalDevice-parameter'                     : 'VUID-vkGetPhysicalDeviceProperties2-physicalDevice-parameter',
103*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceQueueFamilyProperties2KHR-pQueueFamilyProperties-parameter'  : 'VUID-vkGetPhysicalDeviceQueueFamilyProperties2-pQueueFamilyProperties-parameter',
104*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-pProperties-parameter'       : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-pProperties-parameter',
105*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-physicalDevice-parameter'    : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-physicalDevice-parameter',
106*b7893ccfSSadaf Ebrahimi    'VUID-vkTrimCommandPoolKHR-commandPool-parameter'                                     : 'VUID-vkTrimCommandPool-commandPool-parameter',
107*b7893ccfSSadaf Ebrahimi    'VUID-vkTrimCommandPoolKHR-commandPool-parent'                                        : 'VUID-vkTrimCommandPool-commandPool-parent',
108*b7893ccfSSadaf Ebrahimi    'VUID-vkTrimCommandPoolKHR-device-parameter'                                          : 'VUID-vkTrimCommandPool-device-parameter',
109*b7893ccfSSadaf Ebrahimi    'VUID-vkTrimCommandPoolKHR-flags-zerobitmask'                                         : 'VUID-vkTrimCommandPool-flags-zerobitmask',
110*b7893ccfSSadaf Ebrahimi    'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorSet-parameter'                   : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorSet-parameter',
111*b7893ccfSSadaf Ebrahimi    'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parameter'        : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parameter',
112*b7893ccfSSadaf Ebrahimi    'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parent'           : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parent',
113*b7893ccfSSadaf Ebrahimi    'VUID-vkUpdateDescriptorSetWithTemplateKHR-device-parameter'                          : 'VUID-vkUpdateDescriptorSetWithTemplate-device-parameter',
114*b7893ccfSSadaf Ebrahimi    'VUID-vkCreateDescriptorUpdateTemplateKHR-pCreateInfo-parameter'                                : 'VUID-vkCreateDescriptorUpdateTemplate-pCreateInfo-parameter',
115*b7893ccfSSadaf Ebrahimi    'VUID-vkCreateSamplerYcbcrConversionKHR-pCreateInfo-parameter'                                  : 'VUID-vkCreateSamplerYcbcrConversion-pCreateInfo-parameter',
116*b7893ccfSSadaf Ebrahimi    'VUID-vkGetBufferMemoryRequirements2KHR-pInfo-parameter'                                        : 'VUID-vkGetBufferMemoryRequirements2-pInfo-parameter',
117*b7893ccfSSadaf Ebrahimi    'VUID-vkGetBufferMemoryRequirements2KHR-pMemoryRequirements-parameter'                          : 'VUID-vkGetBufferMemoryRequirements2-pMemoryRequirements-parameter',
118*b7893ccfSSadaf Ebrahimi    'VUID-vkGetDescriptorSetLayoutSupportKHR-pCreateInfo-parameter'                                 : 'VUID-vkGetDescriptorSetLayoutSupport-pCreateInfo-parameter',
119*b7893ccfSSadaf Ebrahimi    'VUID-vkGetDescriptorSetLayoutSupportKHR-pSupport-parameter'                                    : 'VUID-vkGetDescriptorSetLayoutSupport-pSupport-parameter',
120*b7893ccfSSadaf Ebrahimi    'VUID-vkGetImageMemoryRequirements2KHR-pInfo-parameter'                                         : 'VUID-vkGetImageMemoryRequirements2-pInfo-parameter',
121*b7893ccfSSadaf Ebrahimi    'VUID-vkGetImageMemoryRequirements2KHR-pMemoryRequirements-parameter'                           : 'VUID-vkGetImageMemoryRequirements2-pMemoryRequirements-parameter',
122*b7893ccfSSadaf Ebrahimi    'VUID-vkGetImageSparseMemoryRequirements2KHR-pInfo-parameter'                                   : 'VUID-vkGetImageSparseMemoryRequirements2-pInfo-parameter',
123*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-pExternalBufferInfo-parameter'             : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-pExternalBufferInfo-parameter',
124*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-pExternalBufferProperties-parameter'       : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-pExternalBufferProperties-parameter',
125*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-pExternalFenceInfo-parameter'               : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-pExternalFenceInfo-parameter',
126*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-pExternalFenceProperties-parameter'         : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-pExternalFenceProperties-parameter',
127*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-pExternalSemaphoreInfo-parameter'       : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-pExternalSemaphoreInfo-parameter',
128*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-pExternalSemaphoreProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-pExternalSemaphoreProperties-parameter',
129*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceFeatures2KHR-pFeatures-parameter'                                      : 'VUID-vkGetPhysicalDeviceFeatures2-pFeatures-parameter',
130*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceFormatProperties2KHR-pFormatProperties-parameter'                      : 'VUID-vkGetPhysicalDeviceFormatProperties2-pFormatProperties-parameter',
131*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-pImageFormatInfo-parameter'                  : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-pImageFormatInfo-parameter',
132*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-pImageFormatProperties-parameter'            : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-pImageFormatProperties-parameter',
133*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceMemoryProperties2KHR-pMemoryProperties-parameter'                      : 'VUID-vkGetPhysicalDeviceMemoryProperties2-pMemoryProperties-parameter',
134*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceProperties2KHR-pProperties-parameter'                                  : 'VUID-vkGetPhysicalDeviceProperties2-pProperties-parameter',
135*b7893ccfSSadaf Ebrahimi    'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-pFormatInfo-parameter'                 : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-pFormatInfo-parameter' }
136*b7893ccfSSadaf Ebrahimi
137*b7893ccfSSadaf Ebrahimidef printHelp():
138*b7893ccfSSadaf Ebrahimi    print ("Usage:")
139*b7893ccfSSadaf Ebrahimi    print ("  python vk_validation_stats.py <json_file>")
140*b7893ccfSSadaf Ebrahimi    print ("                                [ -c ]")
141*b7893ccfSSadaf Ebrahimi    print ("                                [ -todo ]")
142*b7893ccfSSadaf Ebrahimi    print ("                                [ -vuid <vuid_name> ]")
143*b7893ccfSSadaf Ebrahimi    print ("                                [ -text [ <text_out_filename>] ]")
144*b7893ccfSSadaf Ebrahimi    print ("                                [ -csv  [ <csv_out_filename>]  ]")
145*b7893ccfSSadaf Ebrahimi    print ("                                [ -html [ <html_out_filename>] ]")
146*b7893ccfSSadaf Ebrahimi    print ("                                [ -export_header ]")
147*b7893ccfSSadaf Ebrahimi    print ("                                [ -summary ]")
148*b7893ccfSSadaf Ebrahimi    print ("                                [ -verbose ]")
149*b7893ccfSSadaf Ebrahimi    print ("                                [ -help ]")
150*b7893ccfSSadaf Ebrahimi    print ("\n  The vk_validation_stats script parses validation layer source files to")
151*b7893ccfSSadaf Ebrahimi    print ("  determine the set of valid usage checks and tests currently implemented,")
152*b7893ccfSSadaf Ebrahimi    print ("  and generates coverage values by comparing against the full set of valid")
153*b7893ccfSSadaf Ebrahimi    print ("  usage identifiers in the Vulkan-Headers registry file 'validusage.json'")
154*b7893ccfSSadaf Ebrahimi    print ("\nArguments: ")
155*b7893ccfSSadaf Ebrahimi    print (" <json-file>       (required) registry file 'validusage.json'")
156*b7893ccfSSadaf Ebrahimi    print (" -c                report consistency warnings")
157*b7893ccfSSadaf Ebrahimi    print (" -todo             report unimplemented VUIDs")
158*b7893ccfSSadaf Ebrahimi    print (" -vuid <vuid_name> report status of individual VUID <vuid_name>")
159*b7893ccfSSadaf Ebrahimi    print (" -text [filename]  output the error database text to <text_database_filename>,")
160*b7893ccfSSadaf Ebrahimi    print ("                   defaults to 'validation_error_database.txt'")
161*b7893ccfSSadaf Ebrahimi    print (" -csv [filename]   output the error database in csv to <csv_database_filename>,")
162*b7893ccfSSadaf Ebrahimi    print ("                   defaults to 'validation_error_database.csv'")
163*b7893ccfSSadaf Ebrahimi    print (" -html [filename]  output the error database in html to <html_database_filename>,")
164*b7893ccfSSadaf Ebrahimi    print ("                   defaults to 'validation_error_database.html'")
165*b7893ccfSSadaf Ebrahimi    print (" -export_header    export a new VUID error text header file to <%s>" % header_filename)
166*b7893ccfSSadaf Ebrahimi    print (" -summary          output summary of VUID coverage")
167*b7893ccfSSadaf Ebrahimi    print (" -verbose          show your work (to stdout)")
168*b7893ccfSSadaf Ebrahimi
169*b7893ccfSSadaf Ebrahimiclass ValidationJSON:
170*b7893ccfSSadaf Ebrahimi    def __init__(self, filename):
171*b7893ccfSSadaf Ebrahimi        self.filename = filename
172*b7893ccfSSadaf Ebrahimi        self.explicit_vuids = set()
173*b7893ccfSSadaf Ebrahimi        self.implicit_vuids = set()
174*b7893ccfSSadaf Ebrahimi        self.all_vuids = set()
175*b7893ccfSSadaf Ebrahimi        self.vuid_db = defaultdict(list) # Maps VUID string to list of json-data dicts
176*b7893ccfSSadaf Ebrahimi        self.apiversion = ""
177*b7893ccfSSadaf Ebrahimi        self.duplicate_vuids = set()
178*b7893ccfSSadaf Ebrahimi
179*b7893ccfSSadaf Ebrahimi        # A set of specific regular expression substitutions needed to clean up VUID text
180*b7893ccfSSadaf Ebrahimi        self.regex_dict = {}
181*b7893ccfSSadaf Ebrahimi        self.regex_dict[re.compile('<.*?>|&(amp;)+lt;|&(amp;)+gt;')] = ""
182*b7893ccfSSadaf Ebrahimi        self.regex_dict[re.compile(r'\\\(codeSize \\over 4\\\)')] = "(codeSize/4)"
183*b7893ccfSSadaf Ebrahimi        self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{height}{maxFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of height/maxFragmentDensityTexelSize.height"
184*b7893ccfSSadaf Ebrahimi        self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{width}{maxFragmentDensityTexelSize_{width}}}\\rceil\\\)')] = "the ceiling of width/maxFragmentDensityTexelSize.width"
185*b7893ccfSSadaf Ebrahimi        self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{maxFramebufferHeight}{minFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of maxFramebufferHeight/minFragmentDensityTexelSize.height"
186*b7893ccfSSadaf Ebrahimi        self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{maxFramebufferWidth}{minFragmentDensityTexelSize_{width}}}\\rceil\\\)')] = "the ceiling of maxFramebufferWidth/minFragmentDensityTexelSize.width"
187*b7893ccfSSadaf Ebrahimi        self.regex_dict[re.compile(r'\\\(\\lceil\{\\mathit\{rasterizationSamples} \\over 32}\\rceil\\\)')] = "(rasterizationSamples/32)"
188*b7893ccfSSadaf Ebrahimi        self.regex_dict[re.compile(r'\\\(\\textrm\{codeSize} \\over 4\\\)')] = "(codeSize/4)"
189*b7893ccfSSadaf Ebrahimi        # Some fancy punctuation chars that break the Android build...
190*b7893ccfSSadaf Ebrahimi        self.regex_dict[re.compile('&#8594;')] = "->"       # Arrow char
191*b7893ccfSSadaf Ebrahimi        self.regex_dict[re.compile('&#8217;')] = "'"        # Left-slanting apostrophe to apostrophe
192*b7893ccfSSadaf Ebrahimi        self.regex_dict[re.compile('&#822(0|1);')] = "'"    # L/R-slanting quotes to apostrophe
193*b7893ccfSSadaf Ebrahimi
194*b7893ccfSSadaf Ebrahimi    def read(self):
195*b7893ccfSSadaf Ebrahimi        self.json_dict = {}
196*b7893ccfSSadaf Ebrahimi        if os.path.isfile(self.filename):
197*b7893ccfSSadaf Ebrahimi            json_file = open(self.filename, 'r', encoding='utf-8')
198*b7893ccfSSadaf Ebrahimi            self.json_dict = json.load(json_file)
199*b7893ccfSSadaf Ebrahimi            json_file.close()
200*b7893ccfSSadaf Ebrahimi        if len(self.json_dict) == 0:
201*b7893ccfSSadaf Ebrahimi            print("Error: Error loading validusage.json file <%s>" % self.filename)
202*b7893ccfSSadaf Ebrahimi            sys.exit(-1)
203*b7893ccfSSadaf Ebrahimi        try:
204*b7893ccfSSadaf Ebrahimi            version = self.json_dict['version info']
205*b7893ccfSSadaf Ebrahimi            validation = self.json_dict['validation']
206*b7893ccfSSadaf Ebrahimi            self.apiversion = version['api version']
207*b7893ccfSSadaf Ebrahimi        except:
208*b7893ccfSSadaf Ebrahimi            print("Error: Failure parsing validusage.json object")
209*b7893ccfSSadaf Ebrahimi            sys.exit(-1)
210*b7893ccfSSadaf Ebrahimi
211*b7893ccfSSadaf Ebrahimi        # Parse vuid from json into local databases
212*b7893ccfSSadaf Ebrahimi        for apiname in validation.keys():
213*b7893ccfSSadaf Ebrahimi            # print("entrypoint:%s"%apiname)
214*b7893ccfSSadaf Ebrahimi            apidict = validation[apiname]
215*b7893ccfSSadaf Ebrahimi            for ext in apidict.keys():
216*b7893ccfSSadaf Ebrahimi                vlist = apidict[ext]
217*b7893ccfSSadaf Ebrahimi                for ventry in vlist:
218*b7893ccfSSadaf Ebrahimi                    vuid_string = ventry['vuid']
219*b7893ccfSSadaf Ebrahimi                    if (vuid_string[-5:-1].isdecimal()):
220*b7893ccfSSadaf Ebrahimi                        self.explicit_vuids.add(vuid_string)    # explicit end in 5 numeric chars
221*b7893ccfSSadaf Ebrahimi                        vtype = 'explicit'
222*b7893ccfSSadaf Ebrahimi                    else:
223*b7893ccfSSadaf Ebrahimi                        self.implicit_vuids.add(vuid_string)    # otherwise, implicit
224*b7893ccfSSadaf Ebrahimi                        vtype = 'implicit'
225*b7893ccfSSadaf Ebrahimi                    vuid_text = ventry['text']
226*b7893ccfSSadaf Ebrahimi                    for regex, replacement in self.regex_dict.items():
227*b7893ccfSSadaf Ebrahimi                        vuid_text = re.sub(regex, replacement, vuid_text)   # do regex substitution
228*b7893ccfSSadaf Ebrahimi                    vuid_text = html.unescape(vuid_text)                    # anything missed by the regex
229*b7893ccfSSadaf Ebrahimi                    self.vuid_db[vuid_string].append({'api':apiname, 'ext':ext, 'type':vtype, 'text':vuid_text})
230*b7893ccfSSadaf Ebrahimi        self.all_vuids = self.explicit_vuids | self.implicit_vuids
231*b7893ccfSSadaf Ebrahimi        self.duplicate_vuids = set({v for v in self.vuid_db if len(self.vuid_db[v]) > 1})
232*b7893ccfSSadaf Ebrahimi        if len(self.duplicate_vuids) > 0:
233*b7893ccfSSadaf Ebrahimi            print("Warning: duplicate VUIDs found in validusage.json")
234*b7893ccfSSadaf Ebrahimi
235*b7893ccfSSadaf Ebrahimi
236*b7893ccfSSadaf Ebrahimiclass ValidationSource:
237*b7893ccfSSadaf Ebrahimi    def __init__(self, source_file_list):
238*b7893ccfSSadaf Ebrahimi        self.source_files = source_file_list
239*b7893ccfSSadaf Ebrahimi        self.vuid_count_dict = {} # dict of vuid values to the count of how much they're used, and location of where they're used
240*b7893ccfSSadaf Ebrahimi        self.duplicated_checks = 0
241*b7893ccfSSadaf Ebrahimi        self.explicit_vuids = set()
242*b7893ccfSSadaf Ebrahimi        self.implicit_vuids = set()
243*b7893ccfSSadaf Ebrahimi        self.unassigned_vuids = set()
244*b7893ccfSSadaf Ebrahimi        self.all_vuids = set()
245*b7893ccfSSadaf Ebrahimi
246*b7893ccfSSadaf Ebrahimi    def parse(self):
247*b7893ccfSSadaf Ebrahimi        prepend = None
248*b7893ccfSSadaf Ebrahimi        for sf in self.source_files:
249*b7893ccfSSadaf Ebrahimi            line_num = 0
250*b7893ccfSSadaf Ebrahimi            with open(sf) as f:
251*b7893ccfSSadaf Ebrahimi                for line in f:
252*b7893ccfSSadaf Ebrahimi                    line_num = line_num + 1
253*b7893ccfSSadaf Ebrahimi                    if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
254*b7893ccfSSadaf Ebrahimi                        continue
255*b7893ccfSSadaf Ebrahimi                    # Find vuid strings
256*b7893ccfSSadaf Ebrahimi                    if prepend is not None:
257*b7893ccfSSadaf Ebrahimi                        line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
258*b7893ccfSSadaf Ebrahimi                        prepend = None
259*b7893ccfSSadaf Ebrahimi                    if any(prefix in line for prefix in vuid_prefixes):
260*b7893ccfSSadaf Ebrahimi                        # Replace the '(' of lines containing validation helper functions with ' ' to make them easier to parse
261*b7893ccfSSadaf Ebrahimi                        line = line.replace("(", " ")
262*b7893ccfSSadaf Ebrahimi                        line_list = line.split()
263*b7893ccfSSadaf Ebrahimi
264*b7893ccfSSadaf Ebrahimi                        # A VUID string that has been broken by clang will start with a vuid prefix and end with -, and will be last in the list
265*b7893ccfSSadaf Ebrahimi                        broken_vuid = line_list[-1].strip('"')
266*b7893ccfSSadaf Ebrahimi                        if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
267*b7893ccfSSadaf Ebrahimi                            prepend = line
268*b7893ccfSSadaf Ebrahimi                            continue
269*b7893ccfSSadaf Ebrahimi
270*b7893ccfSSadaf Ebrahimi                        vuid_list = []
271*b7893ccfSSadaf Ebrahimi                        for str in line_list:
272*b7893ccfSSadaf Ebrahimi                            if any(prefix in str for prefix in vuid_prefixes):
273*b7893ccfSSadaf Ebrahimi                                vuid_list.append(str.strip(',);{}"'))
274*b7893ccfSSadaf Ebrahimi                        for vuid in vuid_list:
275*b7893ccfSSadaf Ebrahimi                            if vuid not in self.vuid_count_dict:
276*b7893ccfSSadaf Ebrahimi                                self.vuid_count_dict[vuid] = {}
277*b7893ccfSSadaf Ebrahimi                                self.vuid_count_dict[vuid]['count'] = 1
278*b7893ccfSSadaf Ebrahimi                                self.vuid_count_dict[vuid]['file_line'] = []
279*b7893ccfSSadaf Ebrahimi                            else:
280*b7893ccfSSadaf Ebrahimi                                if self.vuid_count_dict[vuid]['count'] == 1:    # only count first time duplicated
281*b7893ccfSSadaf Ebrahimi                                    self.duplicated_checks = self.duplicated_checks + 1
282*b7893ccfSSadaf Ebrahimi                                self.vuid_count_dict[vuid]['count'] = self.vuid_count_dict[vuid]['count'] + 1
283*b7893ccfSSadaf Ebrahimi                            self.vuid_count_dict[vuid]['file_line'].append('%s,%d' % (sf, line_num))
284*b7893ccfSSadaf Ebrahimi        # Sort vuids by type
285*b7893ccfSSadaf Ebrahimi        for vuid in self.vuid_count_dict.keys():
286*b7893ccfSSadaf Ebrahimi            if (vuid.startswith('VUID-')):
287*b7893ccfSSadaf Ebrahimi                if (vuid[-5:-1].isdecimal()):
288*b7893ccfSSadaf Ebrahimi                    self.explicit_vuids.add(vuid)    # explicit end in 5 numeric chars
289*b7893ccfSSadaf Ebrahimi                else:
290*b7893ccfSSadaf Ebrahimi                    self.implicit_vuids.add(vuid)
291*b7893ccfSSadaf Ebrahimi            elif (vuid.startswith('UNASSIGNED-')):
292*b7893ccfSSadaf Ebrahimi                self.unassigned_vuids.add(vuid)
293*b7893ccfSSadaf Ebrahimi            else:
294*b7893ccfSSadaf Ebrahimi                print("Unable to categorize VUID: %s" % vuid)
295*b7893ccfSSadaf Ebrahimi                print("Confused while parsing VUIDs in layer source code - cannot proceed. (FIXME)")
296*b7893ccfSSadaf Ebrahimi                exit(-1)
297*b7893ccfSSadaf Ebrahimi        self.all_vuids = self.explicit_vuids | self.implicit_vuids | self.unassigned_vuids
298*b7893ccfSSadaf Ebrahimi
299*b7893ccfSSadaf Ebrahimi# Class to parse the validation layer test source and store testnames
300*b7893ccfSSadaf Ebrahimiclass ValidationTests:
301*b7893ccfSSadaf Ebrahimi    def __init__(self, test_file_list, test_group_name=['VkLayerTest', 'VkPositiveLayerTest', 'VkWsiEnabledLayerTest']):
302*b7893ccfSSadaf Ebrahimi        self.test_files = test_file_list
303*b7893ccfSSadaf Ebrahimi        self.test_trigger_txt_list = []
304*b7893ccfSSadaf Ebrahimi        for tg in test_group_name:
305*b7893ccfSSadaf Ebrahimi            self.test_trigger_txt_list.append('TEST_F(%s' % tg)
306*b7893ccfSSadaf Ebrahimi        self.explicit_vuids = set()
307*b7893ccfSSadaf Ebrahimi        self.implicit_vuids = set()
308*b7893ccfSSadaf Ebrahimi        self.unassigned_vuids = set()
309*b7893ccfSSadaf Ebrahimi        self.all_vuids = set()
310*b7893ccfSSadaf Ebrahimi        #self.test_to_vuids = {} # Map test name to VUIDs tested
311*b7893ccfSSadaf Ebrahimi        self.vuid_to_tests = defaultdict(set) # Map VUIDs to set of test names where implemented
312*b7893ccfSSadaf Ebrahimi
313*b7893ccfSSadaf Ebrahimi    # Parse test files into internal data struct
314*b7893ccfSSadaf Ebrahimi    def parse(self):
315*b7893ccfSSadaf Ebrahimi        # For each test file, parse test names into set
316*b7893ccfSSadaf Ebrahimi        grab_next_line = False # handle testname on separate line than wildcard
317*b7893ccfSSadaf Ebrahimi        testname = ''
318*b7893ccfSSadaf Ebrahimi        prepend = None
319*b7893ccfSSadaf Ebrahimi        for test_file in self.test_files:
320*b7893ccfSSadaf Ebrahimi            with open(test_file) as tf:
321*b7893ccfSSadaf Ebrahimi                for line in tf:
322*b7893ccfSSadaf Ebrahimi                    if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
323*b7893ccfSSadaf Ebrahimi                        continue
324*b7893ccfSSadaf Ebrahimi
325*b7893ccfSSadaf Ebrahimi                    # if line ends in a broken VUID string, fix that before proceeding
326*b7893ccfSSadaf Ebrahimi                    if prepend is not None:
327*b7893ccfSSadaf Ebrahimi                        line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
328*b7893ccfSSadaf Ebrahimi                        prepend = None
329*b7893ccfSSadaf Ebrahimi                    if any(prefix in line for prefix in vuid_prefixes):
330*b7893ccfSSadaf Ebrahimi                        line_list = line.split()
331*b7893ccfSSadaf Ebrahimi
332*b7893ccfSSadaf Ebrahimi                        # A VUID string that has been broken by clang will start with a vuid prefix and end with -, and will be last in the list
333*b7893ccfSSadaf Ebrahimi                        broken_vuid = line_list[-1].strip('"')
334*b7893ccfSSadaf Ebrahimi                        if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
335*b7893ccfSSadaf Ebrahimi                            prepend = line
336*b7893ccfSSadaf Ebrahimi                            continue
337*b7893ccfSSadaf Ebrahimi
338*b7893ccfSSadaf Ebrahimi                    if any(ttt in line for ttt in self.test_trigger_txt_list):
339*b7893ccfSSadaf Ebrahimi                        testname = line.split(',')[-1]
340*b7893ccfSSadaf Ebrahimi                        testname = testname.strip().strip(' {)')
341*b7893ccfSSadaf Ebrahimi                        if ('' == testname):
342*b7893ccfSSadaf Ebrahimi                            grab_next_line = True
343*b7893ccfSSadaf Ebrahimi                            continue
344*b7893ccfSSadaf Ebrahimi                        #self.test_to_vuids[testname] = []
345*b7893ccfSSadaf Ebrahimi                    if grab_next_line: # test name on its own line
346*b7893ccfSSadaf Ebrahimi                        grab_next_line = False
347*b7893ccfSSadaf Ebrahimi                        testname = testname.strip().strip(' {)')
348*b7893ccfSSadaf Ebrahimi                        #self.test_to_vuids[testname] = []
349*b7893ccfSSadaf Ebrahimi                    if any(prefix in line for prefix in vuid_prefixes):
350*b7893ccfSSadaf Ebrahimi                        line_list = re.split('[\s{}[\]()"]+',line)
351*b7893ccfSSadaf Ebrahimi                        for sub_str in line_list:
352*b7893ccfSSadaf Ebrahimi                            if any(prefix in sub_str for prefix in vuid_prefixes):
353*b7893ccfSSadaf Ebrahimi                                vuid_str = sub_str.strip(',);:"')
354*b7893ccfSSadaf Ebrahimi                                self.vuid_to_tests[vuid_str].add(testname)
355*b7893ccfSSadaf Ebrahimi                                #self.test_to_vuids[testname].append(vuid_str)
356*b7893ccfSSadaf Ebrahimi                                if (vuid_str.startswith('VUID-')):
357*b7893ccfSSadaf Ebrahimi                                    if (vuid_str[-5:-1].isdecimal()):
358*b7893ccfSSadaf Ebrahimi                                        self.explicit_vuids.add(vuid_str)    # explicit end in 5 numeric chars
359*b7893ccfSSadaf Ebrahimi                                    else:
360*b7893ccfSSadaf Ebrahimi                                        self.implicit_vuids.add(vuid_str)
361*b7893ccfSSadaf Ebrahimi                                elif (vuid_str.startswith('UNASSIGNED-')):
362*b7893ccfSSadaf Ebrahimi                                    self.unassigned_vuids.add(vuid_str)
363*b7893ccfSSadaf Ebrahimi                                else:
364*b7893ccfSSadaf Ebrahimi                                    print("Unable to categorize VUID: %s" % vuid_str)
365*b7893ccfSSadaf Ebrahimi                                    print("Confused while parsing VUIDs in test code - cannot proceed. (FIXME)")
366*b7893ccfSSadaf Ebrahimi                                    exit(-1)
367*b7893ccfSSadaf Ebrahimi        self.all_vuids = self.explicit_vuids | self.implicit_vuids | self.unassigned_vuids
368*b7893ccfSSadaf Ebrahimi
369*b7893ccfSSadaf Ebrahimi# Class to do consistency checking
370*b7893ccfSSadaf Ebrahimi#
371*b7893ccfSSadaf Ebrahimiclass Consistency:
372*b7893ccfSSadaf Ebrahimi    def __init__(self, all_json, all_checks, all_tests):
373*b7893ccfSSadaf Ebrahimi        self.valid = all_json
374*b7893ccfSSadaf Ebrahimi        self.checks = all_checks
375*b7893ccfSSadaf Ebrahimi        self.tests = all_tests
376*b7893ccfSSadaf Ebrahimi
377*b7893ccfSSadaf Ebrahimi        if (dealias_khr):
378*b7893ccfSSadaf Ebrahimi            dk = set()
379*b7893ccfSSadaf Ebrahimi            for vuid in self.checks:
380*b7893ccfSSadaf Ebrahimi                if vuid in khr_aliases:
381*b7893ccfSSadaf Ebrahimi                    dk.add(khr_aliases[vuid])
382*b7893ccfSSadaf Ebrahimi                else:
383*b7893ccfSSadaf Ebrahimi                    dk.add(vuid)
384*b7893ccfSSadaf Ebrahimi            self.checks = dk
385*b7893ccfSSadaf Ebrahimi
386*b7893ccfSSadaf Ebrahimi            dk = set()
387*b7893ccfSSadaf Ebrahimi            for vuid in self.tests:
388*b7893ccfSSadaf Ebrahimi                if vuid in khr_aliases:
389*b7893ccfSSadaf Ebrahimi                    dk.add(khr_aliases[vuid])
390*b7893ccfSSadaf Ebrahimi                else:
391*b7893ccfSSadaf Ebrahimi                    dk.add(vuid)
392*b7893ccfSSadaf Ebrahimi            self.tests = dk
393*b7893ccfSSadaf Ebrahimi
394*b7893ccfSSadaf Ebrahimi    # Report undefined VUIDs in source code
395*b7893ccfSSadaf Ebrahimi    def undef_vuids_in_layer_code(self):
396*b7893ccfSSadaf Ebrahimi        undef_set = self.checks - self.valid
397*b7893ccfSSadaf Ebrahimi        undef_set.discard('VUID-Undefined') # don't report Undefined
398*b7893ccfSSadaf Ebrahimi        if ignore_unassigned:
399*b7893ccfSSadaf Ebrahimi            unassigned = set({uv for uv in undef_set if uv.startswith('UNASSIGNED-')})
400*b7893ccfSSadaf Ebrahimi            undef_set = undef_set - unassigned
401*b7893ccfSSadaf Ebrahimi        if (len(undef_set) > 0):
402*b7893ccfSSadaf Ebrahimi            print("\nFollowing VUIDs found in layer code are not defined in validusage.json (%d):" % len(undef_set))
403*b7893ccfSSadaf Ebrahimi            undef = list(undef_set)
404*b7893ccfSSadaf Ebrahimi            undef.sort()
405*b7893ccfSSadaf Ebrahimi            for vuid in undef:
406*b7893ccfSSadaf Ebrahimi                print("    %s" % vuid)
407*b7893ccfSSadaf Ebrahimi            return False
408*b7893ccfSSadaf Ebrahimi        return True
409*b7893ccfSSadaf Ebrahimi
410*b7893ccfSSadaf Ebrahimi    # Report undefined VUIDs in tests
411*b7893ccfSSadaf Ebrahimi    def undef_vuids_in_tests(self):
412*b7893ccfSSadaf Ebrahimi        undef_set = self.tests - self.valid
413*b7893ccfSSadaf Ebrahimi        undef_set.discard('VUID-Undefined') # don't report Undefined
414*b7893ccfSSadaf Ebrahimi        if ignore_unassigned:
415*b7893ccfSSadaf Ebrahimi            unassigned = set({uv for uv in undef_set if uv.startswith('UNASSIGNED-')})
416*b7893ccfSSadaf Ebrahimi            undef_set = undef_set - unassigned
417*b7893ccfSSadaf Ebrahimi        if (len(undef_set) > 0):
418*b7893ccfSSadaf Ebrahimi            ok = False
419*b7893ccfSSadaf Ebrahimi            print("\nFollowing VUIDs found in layer tests are not defined in validusage.json (%d):" % len(undef_set))
420*b7893ccfSSadaf Ebrahimi            undef = list(undef_set)
421*b7893ccfSSadaf Ebrahimi            undef.sort()
422*b7893ccfSSadaf Ebrahimi            for vuid in undef:
423*b7893ccfSSadaf Ebrahimi                print("    %s" % vuid)
424*b7893ccfSSadaf Ebrahimi            return False
425*b7893ccfSSadaf Ebrahimi        return True
426*b7893ccfSSadaf Ebrahimi
427*b7893ccfSSadaf Ebrahimi    # Report vuids in tests that are not in source
428*b7893ccfSSadaf Ebrahimi    def vuids_tested_not_checked(self):
429*b7893ccfSSadaf Ebrahimi        undef_set = self.tests - self.checks
430*b7893ccfSSadaf Ebrahimi        undef_set.discard('VUID-Undefined') # don't report Undefined
431*b7893ccfSSadaf Ebrahimi        if ignore_unassigned:
432*b7893ccfSSadaf Ebrahimi            unassigned = set()
433*b7893ccfSSadaf Ebrahimi            for vuid in undef_set:
434*b7893ccfSSadaf Ebrahimi                if vuid.startswith('UNASSIGNED-'):
435*b7893ccfSSadaf Ebrahimi                    unassigned.add(vuid)
436*b7893ccfSSadaf Ebrahimi            undef_set = undef_set - unassigned
437*b7893ccfSSadaf Ebrahimi        if (len(undef_set) > 0):
438*b7893ccfSSadaf Ebrahimi            ok = False
439*b7893ccfSSadaf Ebrahimi            print("\nFollowing VUIDs found in tests but are not checked in layer code (%d):" % len(undef_set))
440*b7893ccfSSadaf Ebrahimi            undef = list(undef_set)
441*b7893ccfSSadaf Ebrahimi            undef.sort()
442*b7893ccfSSadaf Ebrahimi            for vuid in undef:
443*b7893ccfSSadaf Ebrahimi                print("    %s" % vuid)
444*b7893ccfSSadaf Ebrahimi            return False
445*b7893ccfSSadaf Ebrahimi        return True
446*b7893ccfSSadaf Ebrahimi
447*b7893ccfSSadaf Ebrahimi    # TODO: Explicit checked VUIDs which have no test
448*b7893ccfSSadaf Ebrahimi    # def explicit_vuids_checked_not_tested(self):
449*b7893ccfSSadaf Ebrahimi
450*b7893ccfSSadaf Ebrahimi
451*b7893ccfSSadaf Ebrahimi# Class to output database in various flavors
452*b7893ccfSSadaf Ebrahimi#
453*b7893ccfSSadaf Ebrahimiclass OutputDatabase:
454*b7893ccfSSadaf Ebrahimi    def __init__(self, val_json, val_source, val_tests):
455*b7893ccfSSadaf Ebrahimi        self.vj = val_json
456*b7893ccfSSadaf Ebrahimi        self.vs = val_source
457*b7893ccfSSadaf Ebrahimi        self.vt = val_tests
458*b7893ccfSSadaf Ebrahimi        self.header_version = "/* THIS FILE IS GENERATED - DO NOT EDIT (scripts/vk_validation_stats.py) */"
459*b7893ccfSSadaf Ebrahimi        self.header_version += "\n/* Vulkan specification version: %s */" % val_json.apiversion
460*b7893ccfSSadaf Ebrahimi        self.header_preamble = """
461*b7893ccfSSadaf Ebrahimi/*
462*b7893ccfSSadaf Ebrahimi * Vulkan
463*b7893ccfSSadaf Ebrahimi *
464*b7893ccfSSadaf Ebrahimi * Copyright (c) 2016-2019 Google Inc.
465*b7893ccfSSadaf Ebrahimi * Copyright (c) 2016-2019 LunarG, Inc.
466*b7893ccfSSadaf Ebrahimi *
467*b7893ccfSSadaf Ebrahimi * Licensed under the Apache License, Version 2.0 (the "License");
468*b7893ccfSSadaf Ebrahimi * you may not use this file except in compliance with the License.
469*b7893ccfSSadaf Ebrahimi * You may obtain a copy of the License at
470*b7893ccfSSadaf Ebrahimi *
471*b7893ccfSSadaf Ebrahimi *     http://www.apache.org/licenses/LICENSE-2.0
472*b7893ccfSSadaf Ebrahimi *
473*b7893ccfSSadaf Ebrahimi * Unless required by applicable law or agreed to in writing, software
474*b7893ccfSSadaf Ebrahimi * distributed under the License is distributed on an "AS IS" BASIS,
475*b7893ccfSSadaf Ebrahimi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
476*b7893ccfSSadaf Ebrahimi * See the License for the specific language governing permissions and
477*b7893ccfSSadaf Ebrahimi * limitations under the License.
478*b7893ccfSSadaf Ebrahimi *
479*b7893ccfSSadaf Ebrahimi * Author: Tobin Ehlis <[email protected]>
480*b7893ccfSSadaf Ebrahimi * Author: Dave Houlton <[email protected]>
481*b7893ccfSSadaf Ebrahimi */
482*b7893ccfSSadaf Ebrahimi
483*b7893ccfSSadaf Ebrahimi#pragma once
484*b7893ccfSSadaf Ebrahimi
485*b7893ccfSSadaf Ebrahimi// Disable auto-formatting for generated file
486*b7893ccfSSadaf Ebrahimi// clang-format off
487*b7893ccfSSadaf Ebrahimi
488*b7893ccfSSadaf Ebrahimi// Mapping from VUID string to the corresponding spec text
489*b7893ccfSSadaf Ebrahimitypedef struct _vuid_spec_text_pair {
490*b7893ccfSSadaf Ebrahimi    const char * vuid;
491*b7893ccfSSadaf Ebrahimi    const char * spec_text;
492*b7893ccfSSadaf Ebrahimi} vuid_spec_text_pair;
493*b7893ccfSSadaf Ebrahimi
494*b7893ccfSSadaf Ebrahimistatic const vuid_spec_text_pair vuid_spec_text[] = {
495*b7893ccfSSadaf Ebrahimi"""
496*b7893ccfSSadaf Ebrahimi        self.header_postamble = """};
497*b7893ccfSSadaf Ebrahimi"""
498*b7893ccfSSadaf Ebrahimi        self.spec_url = "https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html"
499*b7893ccfSSadaf Ebrahimi
500*b7893ccfSSadaf Ebrahimi    def dump_txt(self):
501*b7893ccfSSadaf Ebrahimi        print("\n Dumping database to text file: %s" % txt_filename)
502*b7893ccfSSadaf Ebrahimi        with open (txt_filename, 'w') as txt:
503*b7893ccfSSadaf Ebrahimi            txt.write("## VUID Database\n")
504*b7893ccfSSadaf Ebrahimi            txt.write("## Format: VUID_NAME | CHECKED | TEST | TYPE | API/STRUCT | EXTENSION | VUID_TEXT\n##\n")
505*b7893ccfSSadaf Ebrahimi            vuid_list = list(self.vj.all_vuids)
506*b7893ccfSSadaf Ebrahimi            vuid_list.sort()
507*b7893ccfSSadaf Ebrahimi            for vuid in vuid_list:
508*b7893ccfSSadaf Ebrahimi                db_list = self.vj.vuid_db[vuid]
509*b7893ccfSSadaf Ebrahimi                db_list.sort(key=operator.itemgetter('ext')) # sort list to ease diffs of output file
510*b7893ccfSSadaf Ebrahimi                for db_entry in db_list:
511*b7893ccfSSadaf Ebrahimi                    checked = 'N'
512*b7893ccfSSadaf Ebrahimi                    if vuid in self.vs.all_vuids:
513*b7893ccfSSadaf Ebrahimi                        checked = 'Y'
514*b7893ccfSSadaf Ebrahimi                    test = 'None'
515*b7893ccfSSadaf Ebrahimi                    if vuid in self.vt.vuid_to_tests:
516*b7893ccfSSadaf Ebrahimi                        test_list = list(self.vt.vuid_to_tests[vuid])
517*b7893ccfSSadaf Ebrahimi                        test_list.sort()   # sort tests, for diff-ability
518*b7893ccfSSadaf Ebrahimi                        sep = ', '
519*b7893ccfSSadaf Ebrahimi                        test = sep.join(test_list)
520*b7893ccfSSadaf Ebrahimi
521*b7893ccfSSadaf Ebrahimi                    txt.write("%s | %s | %s | %s | %s | %s | %s\n" % (vuid, checked, test, db_entry['type'], db_entry['api'], db_entry['ext'], db_entry['text']))
522*b7893ccfSSadaf Ebrahimi
523*b7893ccfSSadaf Ebrahimi    def dump_csv(self):
524*b7893ccfSSadaf Ebrahimi        print("\n Dumping database to csv file: %s" % csv_filename)
525*b7893ccfSSadaf Ebrahimi        with open (csv_filename, 'w', newline='') as csvfile:
526*b7893ccfSSadaf Ebrahimi            cw = csv.writer(csvfile)
527*b7893ccfSSadaf Ebrahimi            cw.writerow(['VUID_NAME','CHECKED','TEST','TYPE','API/STRUCT','EXTENSION','VUID_TEXT'])
528*b7893ccfSSadaf Ebrahimi            vuid_list = list(self.vj.all_vuids)
529*b7893ccfSSadaf Ebrahimi            vuid_list.sort()
530*b7893ccfSSadaf Ebrahimi            for vuid in vuid_list:
531*b7893ccfSSadaf Ebrahimi                for db_entry in self.vj.vuid_db[vuid]:
532*b7893ccfSSadaf Ebrahimi                    row = [vuid]
533*b7893ccfSSadaf Ebrahimi                    if vuid in self.vs.all_vuids:
534*b7893ccfSSadaf Ebrahimi                        row.append('Y')
535*b7893ccfSSadaf Ebrahimi                    else:
536*b7893ccfSSadaf Ebrahimi                        row.append('N')
537*b7893ccfSSadaf Ebrahimi                    test = 'None'
538*b7893ccfSSadaf Ebrahimi                    if vuid in self.vt.vuid_to_tests:
539*b7893ccfSSadaf Ebrahimi                        sep = ', '
540*b7893ccfSSadaf Ebrahimi                        test = sep.join(self.vt.vuid_to_tests[vuid])
541*b7893ccfSSadaf Ebrahimi                    row.append(test)
542*b7893ccfSSadaf Ebrahimi                    row.append(db_entry['type'])
543*b7893ccfSSadaf Ebrahimi                    row.append(db_entry['api'])
544*b7893ccfSSadaf Ebrahimi                    row.append(db_entry['ext'])
545*b7893ccfSSadaf Ebrahimi                    row.append(db_entry['text'])
546*b7893ccfSSadaf Ebrahimi                    cw.writerow(row)
547*b7893ccfSSadaf Ebrahimi
548*b7893ccfSSadaf Ebrahimi    def dump_html(self):
549*b7893ccfSSadaf Ebrahimi        print("\n Dumping database to html file: %s" % html_filename)
550*b7893ccfSSadaf Ebrahimi        preamble = '<!DOCTYPE html>\n<html>\n<head>\n<style>\ntable, th, td {\n border: 1px solid black;\n border-collapse: collapse; \n}\n</style>\n<body>\n<h2>Valid Usage Database</h2>\n<font size="2" face="Arial">\n<table style="width:100%">\n'
551*b7893ccfSSadaf Ebrahimi        headers = '<tr><th>VUID NAME</th><th>CHECKED</th><th>TEST</th><th>TYPE</th><th>API/STRUCT</th><th>EXTENSION</th><th>VUID TEXT</th></tr>\n'
552*b7893ccfSSadaf Ebrahimi        with open (html_filename, 'w') as hfile:
553*b7893ccfSSadaf Ebrahimi            hfile.write(preamble)
554*b7893ccfSSadaf Ebrahimi            hfile.write(headers)
555*b7893ccfSSadaf Ebrahimi            vuid_list = list(self.vj.all_vuids)
556*b7893ccfSSadaf Ebrahimi            vuid_list.sort()
557*b7893ccfSSadaf Ebrahimi            for vuid in vuid_list:
558*b7893ccfSSadaf Ebrahimi                for db_entry in self.vj.vuid_db[vuid]:
559*b7893ccfSSadaf Ebrahimi                    hfile.write('<tr><th>%s</th>' % vuid)
560*b7893ccfSSadaf Ebrahimi                    checked = '<span style="color:red;">N</span>'
561*b7893ccfSSadaf Ebrahimi                    if vuid in self.vs.all_vuids:
562*b7893ccfSSadaf Ebrahimi                        checked = '<span style="color:limegreen;">Y</span>'
563*b7893ccfSSadaf Ebrahimi                    hfile.write('<th>%s</th>' % checked)
564*b7893ccfSSadaf Ebrahimi                    test = 'None'
565*b7893ccfSSadaf Ebrahimi                    if vuid in self.vt.vuid_to_tests:
566*b7893ccfSSadaf Ebrahimi                        sep = ', '
567*b7893ccfSSadaf Ebrahimi                        test = sep.join(self.vt.vuid_to_tests[vuid])
568*b7893ccfSSadaf Ebrahimi                    hfile.write('<th>%s</th>' % test)
569*b7893ccfSSadaf Ebrahimi                    hfile.write('<th>%s</th>' % db_entry['type'])
570*b7893ccfSSadaf Ebrahimi                    hfile.write('<th>%s</th>' % db_entry['api'])
571*b7893ccfSSadaf Ebrahimi                    hfile.write('<th>%s</th>' % db_entry['ext'])
572*b7893ccfSSadaf Ebrahimi                    hfile.write('<th>%s</th></tr>\n' % db_entry['text'])
573*b7893ccfSSadaf Ebrahimi            hfile.write('</table>\n</body>\n</html>\n')
574*b7893ccfSSadaf Ebrahimi
575*b7893ccfSSadaf Ebrahimi    def export_header(self):
576*b7893ccfSSadaf Ebrahimi        if verbose_mode:
577*b7893ccfSSadaf Ebrahimi            print("\n Exporting header file to: %s" % header_filename)
578*b7893ccfSSadaf Ebrahimi        with open (header_filename, 'w') as hfile:
579*b7893ccfSSadaf Ebrahimi            hfile.write(self.header_version)
580*b7893ccfSSadaf Ebrahimi            hfile.write(self.header_preamble)
581*b7893ccfSSadaf Ebrahimi            vuid_list = list(self.vj.all_vuids)
582*b7893ccfSSadaf Ebrahimi            vuid_list.sort()
583*b7893ccfSSadaf Ebrahimi            cmd_dict = {}
584*b7893ccfSSadaf Ebrahimi            for vuid in vuid_list:
585*b7893ccfSSadaf Ebrahimi                db_entry = self.vj.vuid_db[vuid][0]
586*b7893ccfSSadaf Ebrahimi                db_text = db_entry['text'].strip(' ')
587*b7893ccfSSadaf Ebrahimi                hfile.write('    {"%s", "%s (%s#%s)"},\n' % (vuid, db_text, self.spec_url, vuid))
588*b7893ccfSSadaf Ebrahimi                # For multiply-defined VUIDs, include versions with extension appended
589*b7893ccfSSadaf Ebrahimi                if len(self.vj.vuid_db[vuid]) > 1:
590*b7893ccfSSadaf Ebrahimi                    for db_entry in self.vj.vuid_db[vuid]:
591*b7893ccfSSadaf Ebrahimi                        hfile.write('    {"%s[%s]", "%s (%s#%s)"},\n' % (vuid, db_entry['ext'].strip(' '), db_text, self.spec_url, vuid))
592*b7893ccfSSadaf Ebrahimi                if 'commandBuffer must be in the recording state' in db_text:
593*b7893ccfSSadaf Ebrahimi                    cmd_dict[vuid] = db_text
594*b7893ccfSSadaf Ebrahimi            hfile.write(self.header_postamble)
595*b7893ccfSSadaf Ebrahimi
596*b7893ccfSSadaf Ebrahimi            # Generate the information for validating recording state VUID's
597*b7893ccfSSadaf Ebrahimi            cmd_prefix = 'prefix##'
598*b7893ccfSSadaf Ebrahimi            cmd_regex = re.compile(r'VUID-vk(Cmd|End)(\w+)')
599*b7893ccfSSadaf Ebrahimi            cmd_vuid_vector = ['    "VUID_Undefined"']
600*b7893ccfSSadaf Ebrahimi            cmd_name_vector = [ '    "Command_Undefined"' ]
601*b7893ccfSSadaf Ebrahimi            cmd_enum = ['    ' + cmd_prefix + 'NONE = 0']
602*b7893ccfSSadaf Ebrahimi
603*b7893ccfSSadaf Ebrahimi            cmd_ordinal = 1
604*b7893ccfSSadaf Ebrahimi            for vuid, db_text in sorted(cmd_dict.items()):
605*b7893ccfSSadaf Ebrahimi                cmd_match = cmd_regex.match(vuid)
606*b7893ccfSSadaf Ebrahimi                if cmd_match.group(1) == "End":
607*b7893ccfSSadaf Ebrahimi                    end = "END"
608*b7893ccfSSadaf Ebrahimi                else:
609*b7893ccfSSadaf Ebrahimi                    end = ""
610*b7893ccfSSadaf Ebrahimi                cmd_name_vector.append('    "vk'+ cmd_match.group(1) + cmd_match.group(2) + '"')
611*b7893ccfSSadaf Ebrahimi                cmd_name = cmd_prefix + end + cmd_match.group(2).upper()
612*b7893ccfSSadaf Ebrahimi                cmd_enum.append('    {} = {}'.format(cmd_name, cmd_ordinal))
613*b7893ccfSSadaf Ebrahimi                cmd_ordinal += 1
614*b7893ccfSSadaf Ebrahimi                cmd_vuid_vector.append('    "{}"'.format(vuid))
615*b7893ccfSSadaf Ebrahimi
616*b7893ccfSSadaf Ebrahimi            hfile.write('\n// Defines to allow creating "must be recording" meta data\n')
617*b7893ccfSSadaf Ebrahimi            cmd_enum.append('    {}RANGE_SIZE = {}'.format(cmd_prefix, cmd_ordinal))
618*b7893ccfSSadaf Ebrahimi            cmd_enum_string = '#define VUID_CMD_ENUM_LIST(prefix)\\\n' + ',\\\n'.join(cmd_enum) + '\n\n'
619*b7893ccfSSadaf Ebrahimi            hfile.write(cmd_enum_string)
620*b7893ccfSSadaf Ebrahimi            cmd_name_list_string = '#define VUID_CMD_NAME_LIST\\\n' + ',\\\n'.join(cmd_name_vector) + '\n\n'
621*b7893ccfSSadaf Ebrahimi            hfile.write(cmd_name_list_string)
622*b7893ccfSSadaf Ebrahimi            vuid_vector_string = '#define VUID_MUST_BE_RECORDING_LIST\\\n' + ',\\\n'.join(cmd_vuid_vector) + '\n'
623*b7893ccfSSadaf Ebrahimi            hfile.write(vuid_vector_string)
624*b7893ccfSSadaf Ebrahimi
625*b7893ccfSSadaf Ebrahimidef main(argv):
626*b7893ccfSSadaf Ebrahimi    global verbose_mode
627*b7893ccfSSadaf Ebrahimi    global txt_filename
628*b7893ccfSSadaf Ebrahimi    global csv_filename
629*b7893ccfSSadaf Ebrahimi    global html_filename
630*b7893ccfSSadaf Ebrahimi
631*b7893ccfSSadaf Ebrahimi    run_consistency = False
632*b7893ccfSSadaf Ebrahimi    report_unimplemented = False
633*b7893ccfSSadaf Ebrahimi    get_vuid_status = ''
634*b7893ccfSSadaf Ebrahimi    txt_out = False
635*b7893ccfSSadaf Ebrahimi    csv_out = False
636*b7893ccfSSadaf Ebrahimi    html_out = False
637*b7893ccfSSadaf Ebrahimi    header_out = False
638*b7893ccfSSadaf Ebrahimi    show_summary = False
639*b7893ccfSSadaf Ebrahimi
640*b7893ccfSSadaf Ebrahimi    if (1 > len(argv)):
641*b7893ccfSSadaf Ebrahimi        printHelp()
642*b7893ccfSSadaf Ebrahimi        sys.exit()
643*b7893ccfSSadaf Ebrahimi
644*b7893ccfSSadaf Ebrahimi    # Parse script args
645*b7893ccfSSadaf Ebrahimi    json_filename = argv[0]
646*b7893ccfSSadaf Ebrahimi    i = 1
647*b7893ccfSSadaf Ebrahimi    while (i < len(argv)):
648*b7893ccfSSadaf Ebrahimi        arg = argv[i]
649*b7893ccfSSadaf Ebrahimi        i = i + 1
650*b7893ccfSSadaf Ebrahimi        if (arg == '-c'):
651*b7893ccfSSadaf Ebrahimi            run_consistency = True
652*b7893ccfSSadaf Ebrahimi        elif (arg == '-vuid'):
653*b7893ccfSSadaf Ebrahimi            get_vuid_status = argv[i]
654*b7893ccfSSadaf Ebrahimi            i = i + 1
655*b7893ccfSSadaf Ebrahimi        elif (arg == '-todo'):
656*b7893ccfSSadaf Ebrahimi            report_unimplemented = True
657*b7893ccfSSadaf Ebrahimi        elif (arg == '-text'):
658*b7893ccfSSadaf Ebrahimi            txt_out = True
659*b7893ccfSSadaf Ebrahimi            # Set filename if supplied, else use default
660*b7893ccfSSadaf Ebrahimi            if i < len(argv) and not argv[i].startswith('-'):
661*b7893ccfSSadaf Ebrahimi                txt_filename = argv[i]
662*b7893ccfSSadaf Ebrahimi                i = i + 1
663*b7893ccfSSadaf Ebrahimi        elif (arg == '-csv'):
664*b7893ccfSSadaf Ebrahimi            csv_out = True
665*b7893ccfSSadaf Ebrahimi            # Set filename if supplied, else use default
666*b7893ccfSSadaf Ebrahimi            if i < len(argv) and not argv[i].startswith('-'):
667*b7893ccfSSadaf Ebrahimi                csv_filename = argv[i]
668*b7893ccfSSadaf Ebrahimi                i = i + 1
669*b7893ccfSSadaf Ebrahimi        elif (arg == '-html'):
670*b7893ccfSSadaf Ebrahimi            html_out = True
671*b7893ccfSSadaf Ebrahimi            # Set filename if supplied, else use default
672*b7893ccfSSadaf Ebrahimi            if i < len(argv) and not argv[i].startswith('-'):
673*b7893ccfSSadaf Ebrahimi                html_filename = argv[i]
674*b7893ccfSSadaf Ebrahimi                i = i + 1
675*b7893ccfSSadaf Ebrahimi        elif (arg == '-export_header'):
676*b7893ccfSSadaf Ebrahimi            header_out = True
677*b7893ccfSSadaf Ebrahimi        elif (arg in ['-verbose']):
678*b7893ccfSSadaf Ebrahimi            verbose_mode = True
679*b7893ccfSSadaf Ebrahimi        elif (arg in ['-summary']):
680*b7893ccfSSadaf Ebrahimi            show_summary = True
681*b7893ccfSSadaf Ebrahimi        elif (arg in ['-help', '-h']):
682*b7893ccfSSadaf Ebrahimi            printHelp()
683*b7893ccfSSadaf Ebrahimi            sys.exit()
684*b7893ccfSSadaf Ebrahimi        else:
685*b7893ccfSSadaf Ebrahimi            print("Unrecognized argument: %s\n" % arg)
686*b7893ccfSSadaf Ebrahimi            printHelp()
687*b7893ccfSSadaf Ebrahimi            sys.exit()
688*b7893ccfSSadaf Ebrahimi
689*b7893ccfSSadaf Ebrahimi    result = 0 # Non-zero result indicates an error case
690*b7893ccfSSadaf Ebrahimi
691*b7893ccfSSadaf Ebrahimi    # Parse validusage json
692*b7893ccfSSadaf Ebrahimi    val_json = ValidationJSON(json_filename)
693*b7893ccfSSadaf Ebrahimi    val_json.read()
694*b7893ccfSSadaf Ebrahimi    exp_json = len(val_json.explicit_vuids)
695*b7893ccfSSadaf Ebrahimi    imp_json = len(val_json.implicit_vuids)
696*b7893ccfSSadaf Ebrahimi    all_json = len(val_json.all_vuids)
697*b7893ccfSSadaf Ebrahimi    if verbose_mode:
698*b7893ccfSSadaf Ebrahimi        print("Found %d unique error vuids in validusage.json file." % all_json)
699*b7893ccfSSadaf Ebrahimi        print("  %d explicit" % exp_json)
700*b7893ccfSSadaf Ebrahimi        print("  %d implicit" % imp_json)
701*b7893ccfSSadaf Ebrahimi        if len(val_json.duplicate_vuids) > 0:
702*b7893ccfSSadaf Ebrahimi            print("%d VUIDs appear in validusage.json more than once." % len(val_json.duplicate_vuids))
703*b7893ccfSSadaf Ebrahimi            for vuid in val_json.duplicate_vuids:
704*b7893ccfSSadaf Ebrahimi                print("  %s" % vuid)
705*b7893ccfSSadaf Ebrahimi                for ext in val_json.vuid_db[vuid]:
706*b7893ccfSSadaf Ebrahimi                    print("    with extension: %s" % ext['ext'])
707*b7893ccfSSadaf Ebrahimi
708*b7893ccfSSadaf Ebrahimi    # Parse layer source files
709*b7893ccfSSadaf Ebrahimi    val_source = ValidationSource(layer_source_files)
710*b7893ccfSSadaf Ebrahimi    val_source.parse()
711*b7893ccfSSadaf Ebrahimi    exp_checks = len(val_source.explicit_vuids)
712*b7893ccfSSadaf Ebrahimi    imp_checks = len(val_source.implicit_vuids)
713*b7893ccfSSadaf Ebrahimi    all_checks = len(val_source.vuid_count_dict.keys())
714*b7893ccfSSadaf Ebrahimi    if verbose_mode:
715*b7893ccfSSadaf Ebrahimi        print("Found %d unique vuid checks in layer source code." % all_checks)
716*b7893ccfSSadaf Ebrahimi        print("  %d explicit" % exp_checks)
717*b7893ccfSSadaf Ebrahimi        print("  %d implicit" % imp_checks)
718*b7893ccfSSadaf Ebrahimi        print("  %d unassigned" % len(val_source.unassigned_vuids))
719*b7893ccfSSadaf Ebrahimi        print("  %d checks are implemented more that once" % val_source.duplicated_checks)
720*b7893ccfSSadaf Ebrahimi
721*b7893ccfSSadaf Ebrahimi    # Parse test files
722*b7893ccfSSadaf Ebrahimi    val_tests = ValidationTests(test_source_files)
723*b7893ccfSSadaf Ebrahimi    val_tests.parse()
724*b7893ccfSSadaf Ebrahimi    exp_tests = len(val_tests.explicit_vuids)
725*b7893ccfSSadaf Ebrahimi    imp_tests = len(val_tests.implicit_vuids)
726*b7893ccfSSadaf Ebrahimi    all_tests = len(val_tests.all_vuids)
727*b7893ccfSSadaf Ebrahimi    if verbose_mode:
728*b7893ccfSSadaf Ebrahimi        print("Found %d unique error vuids in test source code." % all_tests)
729*b7893ccfSSadaf Ebrahimi        print("  %d explicit" % exp_tests)
730*b7893ccfSSadaf Ebrahimi        print("  %d implicit" % imp_tests)
731*b7893ccfSSadaf Ebrahimi        print("  %d unassigned" % len(val_tests.unassigned_vuids))
732*b7893ccfSSadaf Ebrahimi
733*b7893ccfSSadaf Ebrahimi    # Process stats
734*b7893ccfSSadaf Ebrahimi    if show_summary:
735*b7893ccfSSadaf Ebrahimi        print("\nValidation Statistics (using validusage.json version %s)" % val_json.apiversion)
736*b7893ccfSSadaf Ebrahimi        print("  VUIDs defined in JSON file:  %04d explicit, %04d implicit, %04d total." % (exp_json, imp_json, all_json))
737*b7893ccfSSadaf Ebrahimi        print("  VUIDs checked in layer code: %04d explicit, %04d implicit, %04d total." % (exp_checks, imp_checks, all_checks))
738*b7893ccfSSadaf Ebrahimi        print("  VUIDs tested in layer tests: %04d explicit, %04d implicit, %04d total." % (exp_tests, imp_tests, all_tests))
739*b7893ccfSSadaf Ebrahimi
740*b7893ccfSSadaf Ebrahimi        print("\nVUID check coverage")
741*b7893ccfSSadaf Ebrahimi        print("  Explicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * exp_checks / exp_json), exp_checks, exp_json))
742*b7893ccfSSadaf Ebrahimi        print("  Implicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * imp_checks / imp_json), imp_checks, imp_json))
743*b7893ccfSSadaf Ebrahimi        print("  Overall VUIDs checked:  %.1f%% (%d checked vs %d defined)" % ((100.0 * all_checks / all_json), all_checks, all_json))
744*b7893ccfSSadaf Ebrahimi
745*b7893ccfSSadaf Ebrahimi        print("\nVUID test coverage")
746*b7893ccfSSadaf Ebrahimi        print("  Explicit VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * exp_tests / exp_checks), exp_tests, exp_checks))
747*b7893ccfSSadaf Ebrahimi        print("  Implicit VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * imp_tests / imp_checks), imp_tests, imp_checks))
748*b7893ccfSSadaf Ebrahimi        print("  Overall VUIDs tested:  %.1f%% (%d tested vs %d checks)" % ((100.0 * all_tests / all_checks), all_tests, all_checks))
749*b7893ccfSSadaf Ebrahimi
750*b7893ccfSSadaf Ebrahimi    # Report status of a single VUID
751*b7893ccfSSadaf Ebrahimi    if len(get_vuid_status) > 1:
752*b7893ccfSSadaf Ebrahimi        print("\n\nChecking status of <%s>" % get_vuid_status);
753*b7893ccfSSadaf Ebrahimi        if get_vuid_status not in val_json.all_vuids:
754*b7893ccfSSadaf Ebrahimi            print('  Not a valid VUID string.')
755*b7893ccfSSadaf Ebrahimi        else:
756*b7893ccfSSadaf Ebrahimi            if get_vuid_status in val_source.explicit_vuids:
757*b7893ccfSSadaf Ebrahimi                print('  Implemented!')
758*b7893ccfSSadaf Ebrahimi                line_list = val_source.vuid_count_dict[get_vuid_status]['file_line']
759*b7893ccfSSadaf Ebrahimi                for line in line_list:
760*b7893ccfSSadaf Ebrahimi                    print('    => %s' % line)
761*b7893ccfSSadaf Ebrahimi            elif get_vuid_status in val_source.implicit_vuids:
762*b7893ccfSSadaf Ebrahimi                print('  Implemented! (Implicit)')
763*b7893ccfSSadaf Ebrahimi                line_list = val_source.vuid_count_dict[get_vuid_status]['file_line']
764*b7893ccfSSadaf Ebrahimi                for line in line_list:
765*b7893ccfSSadaf Ebrahimi                    print('    => %s' % line)
766*b7893ccfSSadaf Ebrahimi            else:
767*b7893ccfSSadaf Ebrahimi                print('  Not implemented.')
768*b7893ccfSSadaf Ebrahimi            if get_vuid_status in val_tests.all_vuids:
769*b7893ccfSSadaf Ebrahimi                print('  Has a test!')
770*b7893ccfSSadaf Ebrahimi                test_list = val_tests.vuid_to_tests[get_vuid_status]
771*b7893ccfSSadaf Ebrahimi                for test in test_list:
772*b7893ccfSSadaf Ebrahimi                    print('    => %s' % test)
773*b7893ccfSSadaf Ebrahimi            else:
774*b7893ccfSSadaf Ebrahimi                print('  Not tested.')
775*b7893ccfSSadaf Ebrahimi
776*b7893ccfSSadaf Ebrahimi    # Report unimplemented explicit VUIDs
777*b7893ccfSSadaf Ebrahimi    if report_unimplemented:
778*b7893ccfSSadaf Ebrahimi        unim_explicit = val_json.explicit_vuids - val_source.explicit_vuids
779*b7893ccfSSadaf Ebrahimi        print("\n\n%d explicit VUID checks remain unimplemented:" % len(unim_explicit))
780*b7893ccfSSadaf Ebrahimi        ulist = list(unim_explicit)
781*b7893ccfSSadaf Ebrahimi        ulist.sort()
782*b7893ccfSSadaf Ebrahimi        for vuid in ulist:
783*b7893ccfSSadaf Ebrahimi            print("  => %s" % vuid)
784*b7893ccfSSadaf Ebrahimi
785*b7893ccfSSadaf Ebrahimi    # Consistency tests
786*b7893ccfSSadaf Ebrahimi    if run_consistency:
787*b7893ccfSSadaf Ebrahimi        print("\n\nRunning consistency tests...")
788*b7893ccfSSadaf Ebrahimi        con = Consistency(val_json.all_vuids, val_source.all_vuids, val_tests.all_vuids)
789*b7893ccfSSadaf Ebrahimi        ok = con.undef_vuids_in_layer_code()
790*b7893ccfSSadaf Ebrahimi        ok &= con.undef_vuids_in_tests()
791*b7893ccfSSadaf Ebrahimi        ok &= con.vuids_tested_not_checked()
792*b7893ccfSSadaf Ebrahimi
793*b7893ccfSSadaf Ebrahimi        if ok:
794*b7893ccfSSadaf Ebrahimi            print("  OK! No inconsistencies found.")
795*b7893ccfSSadaf Ebrahimi
796*b7893ccfSSadaf Ebrahimi    # Output database in requested format(s)
797*b7893ccfSSadaf Ebrahimi    db_out = OutputDatabase(val_json, val_source, val_tests)
798*b7893ccfSSadaf Ebrahimi    if txt_out:
799*b7893ccfSSadaf Ebrahimi        db_out.dump_txt()
800*b7893ccfSSadaf Ebrahimi    if csv_out:
801*b7893ccfSSadaf Ebrahimi        db_out.dump_csv()
802*b7893ccfSSadaf Ebrahimi    if html_out:
803*b7893ccfSSadaf Ebrahimi        db_out.dump_html()
804*b7893ccfSSadaf Ebrahimi    if header_out:
805*b7893ccfSSadaf Ebrahimi        db_out.export_header()
806*b7893ccfSSadaf Ebrahimi    return result
807*b7893ccfSSadaf Ebrahimi
808*b7893ccfSSadaf Ebrahimiif __name__ == "__main__":
809*b7893ccfSSadaf Ebrahimi    sys.exit(main(sys.argv[1:]))
810*b7893ccfSSadaf Ebrahimi
811