blob: 9636dee74644a7fefe894cbfbd7cbe6b3d1a1728 [file] [log] [blame]
Tobin Ehlis35308dd2016-10-31 13:27:36 -06001#!/usr/bin/env python3
Shannon McPherson9a4ae982019-01-07 16:05:25 -07002# Copyright (c) 2015-2019 The Khronos Group Inc.
3# Copyright (c) 2015-2019 Valve Corporation
4# Copyright (c) 2015-2019 LunarG, Inc.
5# Copyright (c) 2015-2019 Google Inc.
Tobin Ehlis35308dd2016-10-31 13:27:36 -06006#
7# Licensed under the Apache License, Version 2.0 (the "License");
8# you may not use this file except in compliance with the License.
9# You may obtain a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16# See the License for the specific language governing permissions and
17# limitations under the License.
18#
19# Author: Tobin Ehlis <tobine@google.com>
Dave Houltoncacef472018-05-29 13:00:42 -060020# Author: Dave Houlton <daveh@lunarg.com>
Shannon McPherson3ea65132018-12-05 10:37:39 -070021# Author: Shannon McPherson <shannon@lunarg.com>
Tobin Ehlis35308dd2016-10-31 13:27:36 -060022
23import argparse
24import os
25import sys
Dave Houltoncacef472018-05-29 13:00:42 -060026import operator
Tobin Ehlis35308dd2016-10-31 13:27:36 -060027import platform
Dave Houltoncacef472018-05-29 13:00:42 -060028import json
29import re
30import csv
31import html
Dave Houlton729c7822018-11-19 11:52:23 -070032import time
Dave Houltoncacef472018-05-29 13:00:42 -060033from collections import defaultdict
Tobin Ehlis35308dd2016-10-31 13:27:36 -060034
Dave Houltoncacef472018-05-29 13:00:42 -060035verbose_mode = False
36txt_db = False
37csv_db = False
38html_db = False
39txt_filename = "validation_error_database.txt"
40csv_filename = "validation_error_database.csv"
41html_filename = "validation_error_database.html"
Dave Houlton407df732018-08-06 17:58:24 -060042header_filename = "../layers/vk_validation_error_messages.h"
Dave Houltoncacef472018-05-29 13:00:42 -060043test_file = '../tests/layer_validation_tests.cpp'
44vuid_prefixes = ['VUID-', 'UNASSIGNED-']
Tobin Ehlis35308dd2016-10-31 13:27:36 -060045
Dave Houltoncacef472018-05-29 13:00:42 -060046# Hard-coded flags that could be command line args, if we decide that's useful
47# replace KHR vuids with non-KHR during consistency checking
48dealias_khr = True
49ignore_unassigned = True # These are not found in layer code unless they appear explicitly (most don't), so produce false positives
50
Mark Lobodzinski05849f02017-06-21 14:44:14 -060051generated_layer_source_directories = [
52'build',
53'dbuild',
54'release',
Jasper St. Pierref5addf32019-01-18 13:56:42 -080055'../build/Vulkan-ValidationLayers/'
Mark Lobodzinski05849f02017-06-21 14:44:14 -060056]
57generated_layer_source_files = [
Mark Lobodzinskid4950072017-08-01 13:02:20 -060058'parameter_validation.cpp',
Mark Lobodzinski09fa2d42017-07-21 10:16:53 -060059'object_tracker.cpp',
Mark Lobodzinski05849f02017-06-21 14:44:14 -060060]
Tobin Ehlis35308dd2016-10-31 13:27:36 -060061layer_source_files = [
Shannon McPherson9a4ae982019-01-07 16:05:25 -070062'../layers/buffer_validation.cpp',
Shannon McPherson23d97212019-02-18 13:39:42 -070063'../layers/core_dispatch.cpp',
Mark Lobodzinskie3787b42017-06-21 13:41:00 -060064'../layers/core_validation.cpp',
65'../layers/descriptor_sets.cpp',
Mark Lobodzinskid4950072017-08-01 13:02:20 -060066'../layers/parameter_validation_utils.cpp',
Mark Lobodzinskib2de97f2017-07-06 15:28:11 -060067'../layers/object_tracker_utils.cpp',
Mark Lobodzinskie3787b42017-06-21 13:41:00 -060068'../layers/shader_validation.cpp',
Shannon McPherson9a4ae982019-01-07 16:05:25 -070069'../layers/stateless_validation.h'
Tobin Ehlis35308dd2016-10-31 13:27:36 -060070]
Tobin Ehlis35308dd2016-10-31 13:27:36 -060071
Dave Houlton407df732018-08-06 17:58:24 -060072# This needs to be updated as new extensions roll in
Dave Houltoncacef472018-05-29 13:00:42 -060073khr_aliases = {
74 'VUID-vkBindBufferMemory2KHR-device-parameter' : 'VUID-vkBindBufferMemory2-device-parameter',
75 'VUID-vkBindBufferMemory2KHR-pBindInfos-parameter' : 'VUID-vkBindBufferMemory2-pBindInfos-parameter',
76 'VUID-vkBindImageMemory2KHR-device-parameter' : 'VUID-vkBindImageMemory2-device-parameter',
77 'VUID-vkBindImageMemory2KHR-pBindInfos-parameter' : 'VUID-vkBindImageMemory2-pBindInfos-parameter',
78 'VUID-vkCmdDispatchBaseKHR-commandBuffer-parameter' : 'VUID-vkCmdDispatchBase-commandBuffer-parameter',
79 'VUID-vkCmdSetDeviceMaskKHR-commandBuffer-parameter' : 'VUID-vkCmdSetDeviceMask-commandBuffer-parameter',
80 'VUID-vkCreateDescriptorUpdateTemplateKHR-device-parameter' : 'VUID-vkCreateDescriptorUpdateTemplate-device-parameter',
81 'VUID-vkCreateDescriptorUpdateTemplateKHR-pDescriptorUpdateTemplate-parameter' : 'VUID-vkCreateDescriptorUpdateTemplate-pDescriptorUpdateTemplate-parameter',
82 'VUID-vkCreateSamplerYcbcrConversionKHR-device-parameter' : 'VUID-vkCreateSamplerYcbcrConversion-device-parameter',
83 'VUID-vkCreateSamplerYcbcrConversionKHR-pYcbcrConversion-parameter' : 'VUID-vkCreateSamplerYcbcrConversion-pYcbcrConversion-parameter',
84 'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parameter' : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parameter',
85 'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parent' : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parent',
86 'VUID-vkDestroyDescriptorUpdateTemplateKHR-device-parameter' : 'VUID-vkDestroyDescriptorUpdateTemplate-device-parameter',
87 'VUID-vkDestroySamplerYcbcrConversionKHR-device-parameter' : 'VUID-vkDestroySamplerYcbcrConversion-device-parameter',
88 'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parameter' : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parameter',
89 'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parent' : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parent',
90 'VUID-vkEnumeratePhysicalDeviceGroupsKHR-instance-parameter' : 'VUID-vkEnumeratePhysicalDeviceGroups-instance-parameter',
91 'VUID-vkEnumeratePhysicalDeviceGroupsKHR-pPhysicalDeviceGroupProperties-parameter' : 'VUID-vkEnumeratePhysicalDeviceGroups-pPhysicalDeviceGroupProperties-parameter',
92 'VUID-vkGetBufferMemoryRequirements2KHR-device-parameter' : 'VUID-vkGetBufferMemoryRequirements2-device-parameter',
93 'VUID-vkGetDescriptorSetLayoutSupportKHR-device-parameter' : 'VUID-vkGetDescriptorSetLayoutSupport-device-parameter',
94 'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-device-parameter' : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-device-parameter',
95 'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-pPeerMemoryFeatures-parameter' : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-pPeerMemoryFeatures-parameter',
96 'VUID-vkGetImageMemoryRequirements2KHR-device-parameter' : 'VUID-vkGetImageMemoryRequirements2-device-parameter',
97 'VUID-vkGetImageSparseMemoryRequirements2KHR-device-parameter' : 'VUID-vkGetImageSparseMemoryRequirements2-device-parameter',
98 'VUID-vkGetImageSparseMemoryRequirements2KHR-pSparseMemoryRequirements-parameter' : 'VUID-vkGetImageSparseMemoryRequirements2-pSparseMemoryRequirements-parameter',
99 'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-physicalDevice-parameter',
100 'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-physicalDevice-parameter',
101 'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-physicalDevice-parameter',
102 'VUID-vkGetPhysicalDeviceFeatures2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceFeatures2-physicalDevice-parameter',
103 'VUID-vkGetPhysicalDeviceFormatProperties2KHR-format-parameter' : 'VUID-vkGetPhysicalDeviceFormatProperties2-format-parameter',
104 'VUID-vkGetPhysicalDeviceFormatProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceFormatProperties2-physicalDevice-parameter',
105 'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-physicalDevice-parameter',
106 'VUID-vkGetPhysicalDeviceMemoryProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceMemoryProperties2-physicalDevice-parameter',
107 'VUID-vkGetPhysicalDeviceProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceProperties2-physicalDevice-parameter',
108 'VUID-vkGetPhysicalDeviceQueueFamilyProperties2KHR-pQueueFamilyProperties-parameter' : 'VUID-vkGetPhysicalDeviceQueueFamilyProperties2-pQueueFamilyProperties-parameter',
109 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-pProperties-parameter' : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-pProperties-parameter',
110 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-physicalDevice-parameter',
111 'VUID-vkTrimCommandPoolKHR-commandPool-parameter' : 'VUID-vkTrimCommandPool-commandPool-parameter',
112 'VUID-vkTrimCommandPoolKHR-commandPool-parent' : 'VUID-vkTrimCommandPool-commandPool-parent',
113 'VUID-vkTrimCommandPoolKHR-device-parameter' : 'VUID-vkTrimCommandPool-device-parameter',
114 'VUID-vkTrimCommandPoolKHR-flags-zerobitmask' : 'VUID-vkTrimCommandPool-flags-zerobitmask',
115 'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorSet-parameter' : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorSet-parameter',
116 'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parameter' : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parameter',
117 'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parent' : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parent',
118 'VUID-vkUpdateDescriptorSetWithTemplateKHR-device-parameter' : 'VUID-vkUpdateDescriptorSetWithTemplate-device-parameter',
119 'VUID-vkCreateDescriptorUpdateTemplateKHR-pCreateInfo-parameter' : 'VUID-vkCreateDescriptorUpdateTemplate-pCreateInfo-parameter',
120 'VUID-vkCreateSamplerYcbcrConversionKHR-pCreateInfo-parameter' : 'VUID-vkCreateSamplerYcbcrConversion-pCreateInfo-parameter',
121 'VUID-vkGetBufferMemoryRequirements2KHR-pInfo-parameter' : 'VUID-vkGetBufferMemoryRequirements2-pInfo-parameter',
122 'VUID-vkGetBufferMemoryRequirements2KHR-pMemoryRequirements-parameter' : 'VUID-vkGetBufferMemoryRequirements2-pMemoryRequirements-parameter',
123 'VUID-vkGetDescriptorSetLayoutSupportKHR-pCreateInfo-parameter' : 'VUID-vkGetDescriptorSetLayoutSupport-pCreateInfo-parameter',
124 'VUID-vkGetDescriptorSetLayoutSupportKHR-pSupport-parameter' : 'VUID-vkGetDescriptorSetLayoutSupport-pSupport-parameter',
125 'VUID-vkGetImageMemoryRequirements2KHR-pInfo-parameter' : 'VUID-vkGetImageMemoryRequirements2-pInfo-parameter',
126 'VUID-vkGetImageMemoryRequirements2KHR-pMemoryRequirements-parameter' : 'VUID-vkGetImageMemoryRequirements2-pMemoryRequirements-parameter',
127 'VUID-vkGetImageSparseMemoryRequirements2KHR-pInfo-parameter' : 'VUID-vkGetImageSparseMemoryRequirements2-pInfo-parameter',
128 'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-pExternalBufferInfo-parameter' : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-pExternalBufferInfo-parameter',
129 'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-pExternalBufferProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-pExternalBufferProperties-parameter',
130 'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-pExternalFenceInfo-parameter' : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-pExternalFenceInfo-parameter',
131 'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-pExternalFenceProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-pExternalFenceProperties-parameter',
132 'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-pExternalSemaphoreInfo-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-pExternalSemaphoreInfo-parameter',
133 'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-pExternalSemaphoreProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-pExternalSemaphoreProperties-parameter',
134 'VUID-vkGetPhysicalDeviceFeatures2KHR-pFeatures-parameter' : 'VUID-vkGetPhysicalDeviceFeatures2-pFeatures-parameter',
135 'VUID-vkGetPhysicalDeviceFormatProperties2KHR-pFormatProperties-parameter' : 'VUID-vkGetPhysicalDeviceFormatProperties2-pFormatProperties-parameter',
136 'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-pImageFormatInfo-parameter' : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-pImageFormatInfo-parameter',
137 'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-pImageFormatProperties-parameter' : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-pImageFormatProperties-parameter',
138 'VUID-vkGetPhysicalDeviceMemoryProperties2KHR-pMemoryProperties-parameter' : 'VUID-vkGetPhysicalDeviceMemoryProperties2-pMemoryProperties-parameter',
139 'VUID-vkGetPhysicalDeviceProperties2KHR-pProperties-parameter' : 'VUID-vkGetPhysicalDeviceProperties2-pProperties-parameter',
140 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-pFormatInfo-parameter' : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-pFormatInfo-parameter' }
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600141
Dave Houltoncacef472018-05-29 13:00:42 -0600142def printHelp():
143 print ("Usage:")
144 print (" python vk_validation_stats.py <json_file>")
145 print (" [ -c ]")
146 print (" [ -todo ]")
147 print (" [ -vuid <vuid_name> ]")
148 print (" [ -text [ <text_out_filename>] ]")
149 print (" [ -csv [ <csv_out_filename>] ]")
150 print (" [ -html [ <html_out_filename>] ]")
Dave Houlton407df732018-08-06 17:58:24 -0600151 print (" [ -export_header ]")
Dave Houltoncacef472018-05-29 13:00:42 -0600152 print (" [ -verbose ]")
153 print (" [ -help ]")
154 print ("\n The vk_validation_stats script parses validation layer source files to")
155 print (" determine the set of valid usage checks and tests currently implemented,")
156 print (" and generates coverage values by comparing against the full set of valid")
157 print (" usage identifiers in the Vulkan-Headers registry file 'validusage.json'")
158 print ("\nArguments: ")
159 print (" <json-file> (required) registry file 'validusage.json'")
160 print (" -c report consistency warnings")
161 print (" -todo report unimplemented VUIDs")
162 print (" -vuid <vuid_name> report status of individual VUID <vuid_name>")
163 print (" -text [filename] output the error database text to <text_database_filename>,")
164 print (" defaults to 'validation_error_database.txt'")
165 print (" -csv [filename] output the error database in csv to <csv_database_filename>,")
166 print (" defaults to 'validation_error_database.csv'")
167 print (" -html [filename] output the error database in html to <html_database_filename>,")
168 print (" defaults to 'validation_error_database.html'")
Dave Houlton407df732018-08-06 17:58:24 -0600169 print (" -export_header export a new VUID error text header file to <%s>" % header_filename)
Dave Houltoncacef472018-05-29 13:00:42 -0600170 print (" -verbose show your work (to stdout)")
171
172class ValidationJSON:
173 def __init__(self, filename):
174 self.filename = filename
175 self.explicit_vuids = set()
176 self.implicit_vuids = set()
177 self.all_vuids = set()
178 self.vuid_db = defaultdict(list) # Maps VUID string to list of json-data dicts
179 self.apiversion = ""
Dave Houltoncacef472018-05-29 13:00:42 -0600180 self.duplicate_vuids = set()
Dave Houlton407df732018-08-06 17:58:24 -0600181
182 # A set of specific regular expression substitutions needed to clean up VUID text
183 self.regex_dict = {}
184 self.regex_dict[re.compile('<.*?>|&(amp;)+lt;|&(amp;)+gt;')] = ""
185 self.regex_dict[re.compile(r'\\\(codeSize \\over 4\\\)')] = "(codeSize/4)"
Shannon McPherson3ea65132018-12-05 10:37:39 -0700186 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{height}{maxFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of height/maxFragmentDensityTexelSize.height"
187 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{width}{maxFragmentDensityTexelSize_{width}}}\\rceil\\\)')] = "the ceiling of width/maxFragmentDensityTexelSize.width"
188 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{maxFramebufferHeight}{minFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of maxFramebufferHeight/minFragmentDensityTexelSize.height"
189 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{maxFramebufferWidth}{minFragmentDensityTexelSize_{width}}}\\rceil\\\)')] = "the ceiling of maxFramebufferWidth/minFragmentDensityTexelSize.width"
Dave Houlton407df732018-08-06 17:58:24 -0600190 self.regex_dict[re.compile(r'\\\(\\lceil\{\\mathit\{rasterizationSamples} \\over 32}\\rceil\\\)')] = "(rasterizationSamples/32)"
Shannon McPhersonb40f1a22018-10-30 16:45:07 -0600191 self.regex_dict[re.compile(r'\\\(\\textrm\{codeSize} \\over 4\\\)')] = "(codeSize/4)"
Dave Houlton407df732018-08-06 17:58:24 -0600192 # Some fancy punctuation chars that break the Android build...
193 self.regex_dict[re.compile('&#8594;')] = "->" # Arrow char
194 self.regex_dict[re.compile('&#8217;')] = "'" # Left-slanting apostrophe to apostrophe
195 self.regex_dict[re.compile('&#822(0|1);')] = "'" # L/R-slanting quotes to apostrophe
Dave Houltoncacef472018-05-29 13:00:42 -0600196
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600197 def read(self):
Dave Houltoncacef472018-05-29 13:00:42 -0600198 self.json_dict = {}
199 if os.path.isfile(self.filename):
Dave Houlton407df732018-08-06 17:58:24 -0600200 json_file = open(self.filename, 'r', encoding='utf-8')
Dave Houltoncacef472018-05-29 13:00:42 -0600201 self.json_dict = json.load(json_file)
202 json_file.close()
203 if len(self.json_dict) == 0:
204 print("Error: Error loading validusage.json file <%s>" % self.filename)
205 sys.exit(-1)
206 try:
207 version = self.json_dict['version info']
208 validation = self.json_dict['validation']
209 self.apiversion = version['api version']
210 except:
211 print("Error: Failure parsing validusage.json object")
212 sys.exit(-1)
213
214 # Parse vuid from json into local databases
215 for apiname in validation.keys():
216 # print("entrypoint:%s"%apiname)
217 apidict = validation[apiname]
218 for ext in apidict.keys():
219 vlist = apidict[ext]
220 for ventry in vlist:
221 vuid_string = ventry['vuid']
222 if (vuid_string[-5:-1].isdecimal()):
223 self.explicit_vuids.add(vuid_string) # explicit end in 5 numeric chars
224 vtype = 'explicit'
225 else:
226 self.implicit_vuids.add(vuid_string) # otherwise, implicit
227 vtype = 'implicit'
228 vuid_text = ventry['text']
Dave Houlton407df732018-08-06 17:58:24 -0600229 for regex, replacement in self.regex_dict.items():
230 vuid_text = re.sub(regex, replacement, vuid_text) # do regex substitution
231 vuid_text = html.unescape(vuid_text) # anything missed by the regex
232 self.vuid_db[vuid_string].append({'api':apiname, 'ext':ext, 'type':vtype, 'text':vuid_text})
Dave Houltoncacef472018-05-29 13:00:42 -0600233 self.all_vuids = self.explicit_vuids | self.implicit_vuids
234 self.duplicate_vuids = set({v for v in self.vuid_db if len(self.vuid_db[v]) > 1})
Dave Houlton407df732018-08-06 17:58:24 -0600235 if len(self.duplicate_vuids) > 0:
236 print("Warning: duplicate VUIDs found in validusage.json")
237
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600238
239class ValidationSource:
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600240 def __init__(self, source_file_list, generated_source_file_list, generated_source_directories):
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600241 self.source_files = source_file_list
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600242 self.generated_source_files = generated_source_file_list
243 self.generated_source_dirs = generated_source_directories
Dave Houltoncacef472018-05-29 13:00:42 -0600244 self.vuid_count_dict = {} # dict of vuid values to the count of how much they're used, and location of where they're used
245 self.duplicated_checks = 0
246 self.explicit_vuids = set()
247 self.implicit_vuids = set()
248 self.unassigned_vuids = set()
249 self.all_vuids = set()
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600250
251 if len(self.generated_source_files) > 0:
252 qualified_paths = []
253 for source in self.generated_source_files:
254 for build_dir in self.generated_source_dirs:
255 filepath = '../%s/layers/%s' % (build_dir, source)
256 if os.path.isfile(filepath):
257 qualified_paths.append(filepath)
John Zulaufdde04c42018-01-16 15:32:45 -0700258 break
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600259 if len(self.generated_source_files) != len(qualified_paths):
Mark Lobodzinski2d193ac2017-06-27 09:38:15 -0600260 print("Error: Unable to locate one or more of the following source files in the %s directories" % (", ".join(generated_source_directories)))
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600261 print(self.generated_source_files)
Dave Houltoncacef472018-05-29 13:00:42 -0600262 print("Failed to locate one or more codegen files in layer source code - cannot proceed.")
John Zulaufdde04c42018-01-16 15:32:45 -0700263 exit(1)
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600264 else:
265 self.source_files.extend(qualified_paths)
266
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600267 def parse(self):
Dave Houltoncacef472018-05-29 13:00:42 -0600268 prepend = None
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600269 for sf in self.source_files:
Tobin Ehlis3d1f2bd2016-12-22 11:19:15 -0700270 line_num = 0
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600271 with open(sf) as f:
272 for line in f:
Tobin Ehlis3d1f2bd2016-12-22 11:19:15 -0700273 line_num = line_num + 1
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600274 if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
275 continue
Dave Houltoncacef472018-05-29 13:00:42 -0600276 # Find vuid strings
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100277 if prepend is not None:
Dave Houltoncacef472018-05-29 13:00:42 -0600278 line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
279 prepend = None
280 if any(prefix in line for prefix in vuid_prefixes):
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600281 line_list = line.split()
Dave Houltoncacef472018-05-29 13:00:42 -0600282
283 # 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
284 broken_vuid = line_list[-1].strip('"')
285 if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
286 prepend = line
287 continue
288
289 vuid_list = []
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600290 for str in line_list:
Dave Houltoncacef472018-05-29 13:00:42 -0600291 if any(prefix in str for prefix in vuid_prefixes):
292 vuid_list.append(str.strip(',);{}"'))
293 for vuid in vuid_list:
294 if vuid not in self.vuid_count_dict:
295 self.vuid_count_dict[vuid] = {}
296 self.vuid_count_dict[vuid]['count'] = 1
297 self.vuid_count_dict[vuid]['file_line'] = []
298 else:
299 if self.vuid_count_dict[vuid]['count'] == 1: # only count first time duplicated
300 self.duplicated_checks = self.duplicated_checks + 1
301 self.vuid_count_dict[vuid]['count'] = self.vuid_count_dict[vuid]['count'] + 1
302 self.vuid_count_dict[vuid]['file_line'].append('%s,%d' % (sf, line_num))
303 # Sort vuids by type
304 for vuid in self.vuid_count_dict.keys():
305 if (vuid.startswith('VUID-')):
306 if (vuid[-5:-1].isdecimal()):
307 self.explicit_vuids.add(vuid) # explicit end in 5 numeric chars
308 else:
309 self.implicit_vuids.add(vuid)
310 elif (vuid.startswith('UNASSIGNED-')):
311 self.unassigned_vuids.add(vuid)
312 else:
313 print("Unable to categorize VUID: %s" % vuid)
314 print("Confused while parsing VUIDs in layer source code - cannot proceed. (FIXME)")
315 exit(-1)
316 self.all_vuids = self.explicit_vuids | self.implicit_vuids | self.unassigned_vuids
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600317
318# Class to parse the validation layer test source and store testnames
Dave Houltoncacef472018-05-29 13:00:42 -0600319class ValidationTests:
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600320 def __init__(self, test_file_list, test_group_name=['VkLayerTest', 'VkPositiveLayerTest', 'VkWsiEnabledLayerTest']):
321 self.test_files = test_file_list
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600322 self.test_trigger_txt_list = []
323 for tg in test_group_name:
324 self.test_trigger_txt_list.append('TEST_F(%s' % tg)
Dave Houltoncacef472018-05-29 13:00:42 -0600325 self.explicit_vuids = set()
326 self.implicit_vuids = set()
327 self.unassigned_vuids = set()
328 self.all_vuids = set()
329 #self.test_to_vuids = {} # Map test name to VUIDs tested
330 self.vuid_to_tests = defaultdict(set) # Map VUIDs to set of test names where implemented
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600331
332 # Parse test files into internal data struct
333 def parse(self):
334 # For each test file, parse test names into set
335 grab_next_line = False # handle testname on separate line than wildcard
Tobin Ehlis9a68c982016-12-29 14:51:17 -0700336 testname = ''
Dave Houltoncacef472018-05-29 13:00:42 -0600337 prepend = None
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600338 for test_file in self.test_files:
339 with open(test_file) as tf:
340 for line in tf:
341 if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
342 continue
343
Dave Houltoncacef472018-05-29 13:00:42 -0600344 # if line ends in a broken VUID string, fix that before proceeding
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100345 if prepend is not None:
Dave Houltoncacef472018-05-29 13:00:42 -0600346 line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
347 prepend = None
348 if any(prefix in line for prefix in vuid_prefixes):
349 line_list = line.split()
350
351 # 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
352 broken_vuid = line_list[-1].strip('"')
353 if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
354 prepend = line
355 continue
356
357 if any(ttt in line for ttt in self.test_trigger_txt_list):
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600358 testname = line.split(',')[-1]
359 testname = testname.strip().strip(' {)')
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600360 if ('' == testname):
361 grab_next_line = True
362 continue
Dave Houltoncacef472018-05-29 13:00:42 -0600363 #self.test_to_vuids[testname] = []
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600364 if grab_next_line: # test name on its own line
365 grab_next_line = False
366 testname = testname.strip().strip(' {)')
Dave Houltoncacef472018-05-29 13:00:42 -0600367 #self.test_to_vuids[testname] = []
368 if any(prefix in line for prefix in vuid_prefixes):
369 line_list = re.split('[\s{}[\]()"]+',line)
Tobin Ehlis71f38c12017-01-12 14:26:56 -0700370 for sub_str in line_list:
Dave Houltoncacef472018-05-29 13:00:42 -0600371 if any(prefix in sub_str for prefix in vuid_prefixes):
372 vuid_str = sub_str.strip(',);:"')
373 self.vuid_to_tests[vuid_str].add(testname)
374 #self.test_to_vuids[testname].append(vuid_str)
375 if (vuid_str.startswith('VUID-')):
376 if (vuid_str[-5:-1].isdecimal()):
377 self.explicit_vuids.add(vuid_str) # explicit end in 5 numeric chars
378 else:
379 self.implicit_vuids.add(vuid_str)
380 elif (vuid_str.startswith('UNASSIGNED-')):
381 self.unassigned_vuids.add(vuid_str)
382 else:
383 print("Unable to categorize VUID: %s" % vuid_str)
384 print("Confused while parsing VUIDs in test code - cannot proceed. (FIXME)")
385 exit(-1)
386 self.all_vuids = self.explicit_vuids | self.implicit_vuids | self.unassigned_vuids
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600387
Dave Houltoncacef472018-05-29 13:00:42 -0600388# Class to do consistency checking
389#
390class Consistency:
391 def __init__(self, all_json, all_checks, all_tests):
392 self.valid = all_json
393 self.checks = all_checks
394 self.tests = all_tests
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600395
Dave Houltoncacef472018-05-29 13:00:42 -0600396 if (dealias_khr):
397 dk = set()
398 for vuid in self.checks:
399 if vuid in khr_aliases:
400 dk.add(khr_aliases[vuid])
401 else:
402 dk.add(vuid)
403 self.checks = dk
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600404
Dave Houltoncacef472018-05-29 13:00:42 -0600405 dk = set()
406 for vuid in self.tests:
407 if vuid in khr_aliases:
408 dk.add(khr_aliases[vuid])
409 else:
410 dk.add(vuid)
411 self.tests = dk
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600412
Dave Houltoncacef472018-05-29 13:00:42 -0600413 # Report undefined VUIDs in source code
414 def undef_vuids_in_layer_code(self):
415 undef_set = self.checks - self.valid
416 undef_set.discard('VUID-Undefined') # don't report Undefined
417 if ignore_unassigned:
418 unassigned = set({uv for uv in undef_set if uv.startswith('UNASSIGNED-')})
419 undef_set = undef_set - unassigned
420 if (len(undef_set) > 0):
421 print("\nFollowing VUIDs found in layer code are not defined in validusage.json (%d):" % len(undef_set))
422 undef = list(undef_set)
423 undef.sort()
424 for vuid in undef:
425 print(" %s" % vuid)
426 return False
427 return True
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600428
Dave Houltoncacef472018-05-29 13:00:42 -0600429 # Report undefined VUIDs in tests
430 def undef_vuids_in_tests(self):
431 undef_set = self.tests - self.valid
432 undef_set.discard('VUID-Undefined') # don't report Undefined
433 if ignore_unassigned:
434 unassigned = set({uv for uv in undef_set if uv.startswith('UNASSIGNED-')})
435 undef_set = undef_set - unassigned
436 if (len(undef_set) > 0):
437 ok = False
438 print("\nFollowing VUIDs found in layer tests are not defined in validusage.json (%d):" % len(undef_set))
439 undef = list(undef_set)
440 undef.sort()
441 for vuid in undef:
442 print(" %s" % vuid)
443 return False
444 return True
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600445
Dave Houltoncacef472018-05-29 13:00:42 -0600446 # Report vuids in tests that are not in source
447 def vuids_tested_not_checked(self):
448 undef_set = self.tests - self.checks
449 undef_set.discard('VUID-Undefined') # don't report Undefined
450 if ignore_unassigned:
451 unassigned = set()
452 for vuid in undef_set:
453 if vuid.startswith('UNASSIGNED-'):
454 unassigned.add(vuid)
455 undef_set = undef_set - unassigned
456 if (len(undef_set) > 0):
457 ok = False
458 print("\nFollowing VUIDs found in tests but are not checked in layer code (%d):" % len(undef_set))
459 undef = list(undef_set)
460 undef.sort()
461 for vuid in undef:
462 print(" %s" % vuid)
463 return False
464 return True
465
466 # TODO: Explicit checked VUIDs which have no test
467 # def explicit_vuids_checked_not_tested(self):
468
469
470# Class to output database in various flavors
471#
472class OutputDatabase:
473 def __init__(self, val_json, val_source, val_tests):
474 self.vj = val_json
475 self.vs = val_source
476 self.vt = val_tests
Dave Houlton729c7822018-11-19 11:52:23 -0700477 self.header_version = "/* THIS FILE IS GENERATED - DO NOT EDIT (scripts/vk_validation_stats.py) */"
478 self.header_version += "\n/* Vulkan specification version: %s */" % val_json.apiversion
479 self.header_version += "\n/* Header generated: %s */\n" % time.strftime('%Y-%m-%d %H:%M:%S')
480 self.header_preamble = """
Dave Houlton407df732018-08-06 17:58:24 -0600481/*
482 * Vulkan
483 *
Jasper St. Pierre1948bcc2019-01-18 13:55:20 -0800484 * Copyright (c) 2016-2019 Google Inc.
485 * Copyright (c) 2016-2019 LunarG, Inc.
Dave Houlton407df732018-08-06 17:58:24 -0600486 *
487 * Licensed under the Apache License, Version 2.0 (the "License");
488 * you may not use this file except in compliance with the License.
489 * You may obtain a copy of the License at
490 *
491 * http://www.apache.org/licenses/LICENSE-2.0
492 *
493 * Unless required by applicable law or agreed to in writing, software
494 * distributed under the License is distributed on an "AS IS" BASIS,
495 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
496 * See the License for the specific language governing permissions and
497 * limitations under the License.
498 *
499 * Author: Tobin Ehlis <tobine@google.com>
500 * Author: Dave Houlton <daveh@lunarg.com>
501 */
502
503#pragma once
504
505// Disable auto-formatting for generated file
506// clang-format off
507
Dave Houlton407df732018-08-06 17:58:24 -0600508// Mapping from VUID string to the corresponding spec text
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600509typedef struct _vuid_spec_text_pair {
510 const char * vuid;
511 const char * spec_text;
512} vuid_spec_text_pair;
513
514static const vuid_spec_text_pair vuid_spec_text[] = {
Dave Houlton407df732018-08-06 17:58:24 -0600515"""
516 self.header_postamble = """};
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600517"""
Dave Houlton407df732018-08-06 17:58:24 -0600518 self.spec_url = "https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html"
Dave Houltoncacef472018-05-29 13:00:42 -0600519
520 def dump_txt(self):
521 print("\n Dumping database to text file: %s" % txt_filename)
522 with open (txt_filename, 'w') as txt:
523 txt.write("## VUID Database\n")
524 txt.write("## Format: VUID_NAME | CHECKED | TEST | TYPE | API/STRUCT | EXTENSION | VUID_TEXT\n##\n")
525 vuid_list = list(self.vj.all_vuids)
526 vuid_list.sort()
527 for vuid in vuid_list:
528 db_list = self.vj.vuid_db[vuid]
529 db_list.sort(key=operator.itemgetter('ext')) # sort list to ease diffs of output file
530 for db_entry in db_list:
531 checked = 'N'
532 if vuid in self.vs.all_vuids:
533 checked = 'Y'
534 test = 'None'
535 if vuid in self.vt.vuid_to_tests:
536 test_list = list(self.vt.vuid_to_tests[vuid])
537 test_list.sort() # sort tests, for diff-ability
538 sep = ', '
539 test = sep.join(test_list)
540
541 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']))
542
543 def dump_csv(self):
544 print("\n Dumping database to csv file: %s" % csv_filename)
545 with open (csv_filename, 'w', newline='') as csvfile:
546 cw = csv.writer(csvfile)
547 cw.writerow(['VUID_NAME','CHECKED','TEST','TYPE','API/STRUCT','EXTENSION','VUID_TEXT'])
548 vuid_list = list(self.vj.all_vuids)
549 vuid_list.sort()
550 for vuid in vuid_list:
551 for db_entry in self.vj.vuid_db[vuid]:
552 row = [vuid]
553 if vuid in self.vs.all_vuids:
554 row.append('Y')
555 else:
556 row.append('N')
557 test = 'None'
558 if vuid in self.vt.vuid_to_tests:
559 sep = ', '
560 test = sep.join(self.vt.vuid_to_tests[vuid])
561 row.append(test)
562 row.append(db_entry['type'])
563 row.append(db_entry['api'])
564 row.append(db_entry['ext'])
565 row.append(db_entry['text'])
566 cw.writerow(row)
567
568 def dump_html(self):
569 print("\n Dumping database to html file: %s" % html_filename)
570 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'
571 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'
572 with open (html_filename, 'w') as hfile:
573 hfile.write(preamble)
574 hfile.write(headers)
575 vuid_list = list(self.vj.all_vuids)
576 vuid_list.sort()
577 for vuid in vuid_list:
578 for db_entry in self.vj.vuid_db[vuid]:
579 hfile.write('<tr><th>%s</th>' % vuid)
580 checked = '<span style="color:red;">N</span>'
581 if vuid in self.vs.all_vuids:
582 checked = '<span style="color:limegreen;">Y</span>'
583 hfile.write('<th>%s</th>' % checked)
584 test = 'None'
585 if vuid in self.vt.vuid_to_tests:
586 sep = ', '
587 test = sep.join(self.vt.vuid_to_tests[vuid])
588 hfile.write('<th>%s</th>' % test)
589 hfile.write('<th>%s</th>' % db_entry['type'])
590 hfile.write('<th>%s</th>' % db_entry['api'])
591 hfile.write('<th>%s</th>' % db_entry['ext'])
592 hfile.write('<th>%s</th></tr>\n' % db_entry['text'])
593 hfile.write('</table>\n</body>\n</html>\n')
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600594
Dave Houlton407df732018-08-06 17:58:24 -0600595 def export_header(self):
596 print("\n Exporting header file to: %s" % header_filename)
597 with open (header_filename, 'w') as hfile:
Dave Houlton729c7822018-11-19 11:52:23 -0700598 hfile.write(self.header_version)
Dave Houlton407df732018-08-06 17:58:24 -0600599 hfile.write(self.header_preamble)
600 vuid_list = list(self.vj.all_vuids)
601 vuid_list.sort()
602 for vuid in vuid_list:
603 db_entry = self.vj.vuid_db[vuid][0]
604 hfile.write(' {"%s", "%s (%s#%s)"},\n' % (vuid, db_entry['text'].strip(' '), self.spec_url, vuid))
605 # For multiply-defined VUIDs, include versions with extension appended
606 if len(self.vj.vuid_db[vuid]) > 1:
607 for db_entry in self.vj.vuid_db[vuid]:
608 hfile.write(' {"%s[%s]", "%s (%s#%s)"},\n' % (vuid, db_entry['ext'].strip(' '), db_entry['text'].strip(' '), self.spec_url, vuid))
609 hfile.write(self.header_postamble)
610
Mark Lobodzinskib44c54a2017-06-12 12:02:38 -0600611def main(argv):
Dave Houltoncacef472018-05-29 13:00:42 -0600612 global verbose_mode
613 global txt_filename
614 global csv_filename
615 global html_filename
616
617 run_consistency = False
618 report_unimplemented = False
619 get_vuid_status = ''
620 txt_out = False
621 csv_out = False
622 html_out = False
Dave Houlton407df732018-08-06 17:58:24 -0600623 header_out = False
Dave Houltoncacef472018-05-29 13:00:42 -0600624
625 if (1 > len(argv)):
626 printHelp()
627 sys.exit()
628
629 # Parse script args
630 json_filename = argv[0]
631 i = 1
632 while (i < len(argv)):
633 arg = argv[i]
634 i = i + 1
635 if (arg == '-c'):
636 run_consistency = True
637 elif (arg == '-vuid'):
638 get_vuid_status = argv[i]
639 i = i + 1
640 elif (arg == '-todo'):
641 report_unimplemented = True
Karl Schultz49d66bb2018-07-09 16:24:46 -0600642 elif (arg == '-text'):
Dave Houltoncacef472018-05-29 13:00:42 -0600643 txt_out = True
644 # Set filename if supplied, else use default
645 if i < len(argv) and not argv[i].startswith('-'):
646 txt_filename = argv[i]
647 i = i + 1
648 elif (arg == '-csv'):
649 csv_out = True
650 # Set filename if supplied, else use default
651 if i < len(argv) and not argv[i].startswith('-'):
652 csv_filename = argv[i]
653 i = i + 1
654 elif (arg == '-html'):
655 html_out = True
656 # Set filename if supplied, else use default
657 if i < len(argv) and not argv[i].startswith('-'):
658 html_filename = argv[i]
659 i = i + 1
Dave Houlton407df732018-08-06 17:58:24 -0600660 elif (arg == '-export_header'):
661 header_out = True
Dave Houltoncacef472018-05-29 13:00:42 -0600662 elif (arg in ['-verbose']):
663 verbose_mode = True
664 elif (arg in ['-help', '-h']):
665 printHelp()
666 sys.exit()
667 else:
668 print("Unrecognized argument: %s\n" % arg)
669 printHelp()
670 sys.exit()
671
Tobin Ehlis20e32582016-12-05 14:50:03 -0700672 result = 0 # Non-zero result indicates an error case
Dave Houltoncacef472018-05-29 13:00:42 -0600673
674 # Parse validusage json
675 val_json = ValidationJSON(json_filename)
676 val_json.read()
677 exp_json = len(val_json.explicit_vuids)
678 imp_json = len(val_json.implicit_vuids)
679 all_json = len(val_json.all_vuids)
680 if verbose_mode:
681 print("Found %d unique error vuids in validusage.json file." % all_json)
682 print(" %d explicit" % exp_json)
683 print(" %d implicit" % imp_json)
684 if len(val_json.duplicate_vuids) > 0:
685 print("%d VUIDs appear in validusage.json more than once." % len(val_json.duplicate_vuids))
686 for vuid in val_json.duplicate_vuids:
687 print(" %s" % vuid)
688 for ext in val_json.vuid_db[vuid]:
689 print(" with extension: %s" % ext['ext'])
690
691 # Parse layer source files
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600692 val_source = ValidationSource(layer_source_files, generated_layer_source_files, generated_layer_source_directories)
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600693 val_source.parse()
Dave Houltoncacef472018-05-29 13:00:42 -0600694 exp_checks = len(val_source.explicit_vuids)
695 imp_checks = len(val_source.implicit_vuids)
696 all_checks = len(val_source.vuid_count_dict.keys())
697 if verbose_mode:
698 print("Found %d unique vuid checks in layer source code." % all_checks)
699 print(" %d explicit" % exp_checks)
700 print(" %d implicit" % imp_checks)
701 print(" %d unassigned" % len(val_source.unassigned_vuids))
702 print(" %d checks are implemented more that once" % val_source.duplicated_checks)
703
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600704 # Parse test files
Dave Houltoncacef472018-05-29 13:00:42 -0600705 val_tests = ValidationTests([test_file, ])
706 val_tests.parse()
707 exp_tests = len(val_tests.explicit_vuids)
708 imp_tests = len(val_tests.implicit_vuids)
709 all_tests = len(val_tests.all_vuids)
Mark Lobodzinski060a8e32018-01-08 09:08:06 -0700710 if verbose_mode:
Dave Houltoncacef472018-05-29 13:00:42 -0600711 print("Found %d unique error vuids in test file %s." % (all_tests, test_file))
712 print(" %d explicit" % exp_tests)
713 print(" %d implicit" % imp_tests)
714 print(" %d unassigned" % len(val_tests.unassigned_vuids))
Mike Weiblenfe186122017-02-03 12:44:53 -0700715
Dave Houltoncacef472018-05-29 13:00:42 -0600716 # Process stats
717 print("\nValidation Statistics (using validusage.json version %s)" % val_json.apiversion)
718 print(" VUIDs defined in JSON file: %04d explicit, %04d implicit, %04d total." % (exp_json, imp_json, all_json))
719 print(" VUIDs checked in layer code: %04d explicit, %04d implicit, %04d total." % (exp_checks, imp_checks, all_checks))
720 print(" VUIDs tested in layer tests: %04d explicit, %04d implicit, %04d total." % (exp_tests, imp_tests, all_tests))
721
722 print("\nVUID check coverage")
723 print(" Explicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * exp_checks / exp_json), exp_checks, exp_json))
724 print(" Implicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * imp_checks / imp_json), imp_checks, imp_json))
725 print(" Overall VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * all_checks / all_json), all_checks, all_json))
Mike Weiblenfe186122017-02-03 12:44:53 -0700726
Dave Houltoncacef472018-05-29 13:00:42 -0600727 print("\nVUID test coverage")
728 print(" Explicit VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * exp_tests / exp_checks), exp_tests, exp_checks))
729 print(" Implicit VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * imp_tests / imp_checks), imp_tests, imp_checks))
730 print(" Overall VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * all_tests / all_checks), all_tests, all_checks))
Mike Weiblenfe186122017-02-03 12:44:53 -0700731
Dave Houltoncacef472018-05-29 13:00:42 -0600732 # Report status of a single VUID
733 if len(get_vuid_status) > 1:
734 print("\n\nChecking status of <%s>" % get_vuid_status);
735 if get_vuid_status not in val_json.all_vuids:
736 print(' Not a valid VUID string.')
737 else:
738 if get_vuid_status in val_source.explicit_vuids:
739 print(' Implemented!')
740 line_list = val_source.vuid_count_dict[get_vuid_status]['file_line']
741 for line in line_list:
742 print(' => %s' % line)
Dave Houltonf93bbab2018-06-26 17:21:12 -0600743 elif get_vuid_status in val_source.implicit_vuids:
744 print(' Implemented! (Implicit)')
745 line_list = val_source.vuid_count_dict[get_vuid_status]['file_line']
746 for line in line_list:
747 print(' => %s' % line)
Tobin Ehlis9a68c982016-12-29 14:51:17 -0700748 else:
Dave Houltoncacef472018-05-29 13:00:42 -0600749 print(' Not implemented.')
Dave Houltonf93bbab2018-06-26 17:21:12 -0600750 if get_vuid_status in val_tests.all_vuids:
Dave Houltoncacef472018-05-29 13:00:42 -0600751 print(' Has a test!')
752 test_list = val_tests.vuid_to_tests[get_vuid_status]
753 for test in test_list:
754 print(' => %s' % test)
755 else:
756 print(' Not tested.')
Mike Weiblenfe186122017-02-03 12:44:53 -0700757
Dave Houltoncacef472018-05-29 13:00:42 -0600758 # Report unimplemented explicit VUIDs
759 if report_unimplemented:
760 unim_explicit = val_json.explicit_vuids - val_source.explicit_vuids
761 print("\n\n%d explicit VUID checks remain unimplemented:" % len(unim_explicit))
762 ulist = list(unim_explicit)
763 ulist.sort()
764 for vuid in ulist:
765 print(" => %s" % vuid)
766
767 # Consistency tests
768 if run_consistency:
769 print("\n\nRunning consistency tests...")
770 con = Consistency(val_json.all_vuids, val_source.all_vuids, val_tests.all_vuids)
771 ok = con.undef_vuids_in_layer_code()
772 ok &= con.undef_vuids_in_tests()
773 ok &= con.vuids_tested_not_checked()
774
775 if ok:
776 print(" OK! No inconsistencies found.")
777
778 # Output database in requested format(s)
779 db_out = OutputDatabase(val_json, val_source, val_tests)
780 if txt_out:
781 db_out.dump_txt()
782 if csv_out:
783 db_out.dump_csv()
784 if html_out:
785 db_out.dump_html()
Dave Houlton407df732018-08-06 17:58:24 -0600786 if header_out:
787 db_out.export_header()
Tobin Ehlis20e32582016-12-05 14:50:03 -0700788 return result
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600789
790if __name__ == "__main__":
Mark Lobodzinskib44c54a2017-06-12 12:02:38 -0600791 sys.exit(main(sys.argv[1:]))
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600792