<commit_before>#!/usr/bin/env python3
# Copyright (c) 2015-2016 The Khronos Group Inc.
# Copyright (c) 2015-2016 Valve Corporation
# Copyright (c) 2015-2016 LunarG, Inc.
# Copyright (c) 2015-2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: <NAME> <<EMAIL>>

import argparse
import os
import sys
import vulkan
import platform

# vk_layer_documentation_generate.py overview
# This script is intended to generate documentation based on vulkan layers
#  It parses known validation layer headers for details of the validation checks
#  It parses validation layer source files for specific code where checks are implemented
#  structs in a human-readable txt format, as well as utility functions
#  to print enum values as strings

# NOTE : Initially the script is performing validation of a hand-written document
#  Right now it does 3 checks:
#  1. Verify ENUM codes declared in source are documented
#  2. Verify ENUM codes in document are declared in source
#  3. Verify API function names in document are in the actual API header (vulkan.py)
# Currently script will flag errors in all of these cases

# TODO : Need a formal specification of the syntax for doc generation
#  Initially, these are the basics:
#  1. Validation checks have unique ENUM values defined in validation layer header
#  2. ENUM includes comments for 1-line overview of check and more detailed description
#  3. Actual code implementing checks includes ENUM value in callback
#  4. Code to test checks should include reference to ENUM


# TODO : Need list of known validation layers to use as default input
#  Just a couple of flat lists right now, but may need to make this input file
#  or at least a more dynamic data structure
layer_inputs = { 'draw_state' : {'header' : 'layers/core_validation_error_enums.h',
                                 'source' : 'layers/core_validation.cpp',
                                 'generated' : False,
                                 'error_enum' : 'DRAW_STATE_ERROR'},
                 'shader_checker' : {'header' : 'layers/core_validation_error_enums.h',
                                     'source' : 'layers/core_validation.cpp',
                                     'generated' : False,
                                     'error_enum' : 'SHADER_CHECKER_ERROR'},
                 'mem_tracker' : {'header' : 'layers/core_validation_error_enums.h',
                                  'source' : 'layers/core_validation.cpp',
                                  'generated' : False,
                                  'error_enum' : 'MEM_TRACK_ERROR'},
                 'device_limits' : {'header' : 'layers/core_validation_error_enums.h',
                                    'source' : 'layers/core_validation.cpp',
                                    'generated' : False,
                                    'error_enum' : 'DEV_LIMITS_ERROR',},
                 'object_tracker' : {'header' : 'layers/object_tracker.h',
                                     'source' : 'layers/object_tracker.cpp',
                                     'generated' : False,
                                     'error_enum' : 'OBJECT_TRACK_ERROR',},
                 'threading' : {'header' : 'layers/threading.h',
                                'source' : 'dbuild/layers/threading.cpp',
                                'generated' : True,
                                'error_enum' : 'THREADING_CHECKER_ERROR'},
                 'image' : {'header' : 'layers/image.h',
                            'source' : 'layers/image.cpp',
                            'generated' : False,
                            'error_enum' : 'IMAGE_ERROR',},
                 'swapchain' : {'header' : 'layers/swapchain.h',
                                'source' : 'layers/swapchain.cpp',
                                'generated' : False,
                                'error_enum' : 'SWAPCHAIN_ERROR',},
                 'parameter_validation' : {'header' : 'layers/parameter_validation_utils.h',
                                           'source' : 'layers/parameter_validation.cpp',
                                           'generated' : False,
                                           'error_enum' : 'ErrorCode',},
    }

builtin_headers = [layer_inputs[ln]['header'] for ln in layer_inputs]
builtin_source = [layer_inputs[ln]['source'] for ln in layer_inputs]
builtin_tests = ['tests/layer_validation_tests.cpp', ]

# List of extensions in layers that are included in documentation, but not in vulkan.py API set
layer_extension_functions = ['objTrackGetObjects', 'objTrackGetObjectsOfType']

def handle_args():
    parser = argparse.ArgumentParser(description='Generate layer documenation from source.')
    parser.add_argument('--in_headers', required=False, default=builtin_headers, help='The input layer header files from which code will be generated.')
    parser.add_argument('--in_source', required=False, default=builtin_source, help='The input layer source files from which code will be generated.')
    parser.add_argument('--test_source', required=False, default=builtin_tests, help='The input test source files from which code will be generated.')
    parser.add_argument('--layer_doc', required=False, default='layers/vk_validation_layer_details.md', help='Existing layer document to be validated against actual layers.')
    parser.add_argument('--validate', action='store_true', default=False, help='Validate that there are no mismatches between layer documentation and source. This includes cross-checking the validation checks, and making sure documented Vulkan API calls exist.')
    parser.add_argument('--print_structs', action='store_true', default=False, help='Primarily a debug option that prints out internal data structs used to generate layer docs.')
    parser.add_argument('--print_doc_checks', action='store_true', default=False, help='Primarily a debug option that prints out all of the checks that are documented.')
    return parser.parse_args()

# Little helper class for coloring cmd line output
class bcolors:

    def __init__(self):
        self.GREEN = '\033[0;32m'
        self.RED = '\033[0;31m'
        self.YELLOW = '\033[1;33m'
        self.ENDC = '\033[0m'
        if 'Linux' != platform.system():
            self.GREEN = ''
            self.RED = ''
            self.YELLOW = ''
            self.ENDC = ''

    def green(self):
        return self.GREEN

    def red(self):
        return self.RED

    def yellow(self):
        return self.YELLOW

    def endc(self):
        return self.ENDC

# Class to parse the validation layer test source and store testnames
class TestParser:
    def __init__(self, test_file_list, test_group_name=['VkLayerTest', 'VkWsiEnabledLayerTest']):
        self.test_files = test_file_list
        self.tests_set = set()
        self.test_trigger_txt_list = []
        for tg in test_group_name:
            self.test_trigger_txt_list.append('TEST_F(%s' % tg)
            #print('Test trigger test list: %s' % (self.test_trigger_txt_list))

    # Parse test files into internal data struct
    def parse(self):
        # For each test file, parse test names into set
        grab_next_line = False # handle testname on separate line than wildcard
        for test_file in self.test_files:
            with open(test_file) as tf:
                for line in tf:
                    if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
                        continue

                    if True in [ttt in line for ttt in self.test_trigger_txt_list]:
                        #print('Test wildcard in line: %s' % (line))
                        testname = line.split(',')[-1]
                        testname = testname.strip().strip(' {)')
                        #print('Inserting test: "%s"' % (testname))
                        if ('' == testname):
                            grab_next_line = True
                            continue
                        self.tests_set.add(testname)
                    if grab_next_line: # test name on its own line
                        grab_next_line = False
                        testname = testname.strip().strip(' {)')<commit_msg>tests: Add postive test group to validatelayerdoc script<commit_after>#!/usr/bin/env python3
# Copyright (c) 2015-2016 The Khronos Group Inc.
# Copyright (c) 2015-2016 Valve Corporation
# Copyright (c) 2015-2016 LunarG, Inc.
# Copyright (c) 2015-2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: <NAME> <<EMAIL>>

import argparse
import os
import sys
import vulkan
import platform

# vk_layer_documentation_generate.py overview
# This script is intended to generate documentation based on vulkan layers
#  It parses known validation layer headers for details of the validation checks
#  It parses validation layer source files for specific code where checks are implemented
#  structs in a human-readable txt format, as well as utility functions
#  to print enum values as strings

# NOTE : Initially the script is performing validation of a hand-written document
#  Right now it does 3 checks:
#  1. Verify ENUM codes declared in source are documented
#  2. Verify ENUM codes in document are declared in source
#  3. Verify API function names in document are in the actual API header (vulkan.py)
# Currently script will flag errors in all of these cases

# TODO : Need a formal specification of the syntax for doc generation
#  Initially, these are the basics:
#  1. Validation checks have unique ENUM values defined in validation layer header
#  2. ENUM includes comments for 1-line overview of check and more detailed description
#  3. Actual code implementing checks includes ENUM value in callback
#  4. Code to test checks should include reference to ENUM


# TODO : Need list of known validation layers to use as default input
#  Just a couple of flat lists right now, but may need to make this input file
#  or at least a more dynamic data structure
layer_inputs = { 'draw_state' : {'header' : 'layers/core_validation_error_enums.h',
                                 'source' : 'layers/core_validation.cpp',
                                 'generated' : False,
                                 'error_enum' : 'DRAW_STATE_ERROR'},
                 'shader_checker' : {'header' : 'layers/core_validation_error_enums.h',
                                     'source' : 'layers/core_validation.cpp',
                                     'generated' : False,
                                     'error_enum' : 'SHADER_CHECKER_ERROR'},
                 'mem_tracker' : {'header' : 'layers/core_validation_error_enums.h',
                                  'source' : 'layers/core_validation.cpp',
                                  'generated' : False,
                                  'error_enum' : 'MEM_TRACK_ERROR'},
                 'device_limits' : {'header' : 'layers/core_validation_error_enums.h',
                                    'source' : 'layers/core_validation.cpp',
                                    'generated' : False,
                                    'error_enum' : 'DEV_LIMITS_ERROR',},
                 'object_tracker' : {'header' : 'layers/object_tracker.h',
                                     'source' : 'layers/object_tracker.cpp',
                                     'generated' : False,
                                     'error_enum' : 'OBJECT_TRACK_ERROR',},
                 'threading' : {'header' : 'layers/threading.h',
                                'source' : 'dbuild/layers/threading.cpp',
                                'generated' : True,
                                'error_enum' : 'THREADING_CHECKER_ERROR'},
                 'image' : {'header' : 'layers/image.h',
                            'source' : 'layers/image.cpp',
                            'generated' : False,
                            'error_enum' : 'IMAGE_ERROR',},
                 'swapchain' : {'header' : 'layers/swapchain.h',
                                'source' : 'layers/swapchain.cpp',
                                'generated' : False,
                                'error_enum' : 'SWAPCHAIN_ERROR',},
                 'parameter_validation' : {'header' : 'layers/parameter_validation_utils.h',
                                           'source' : 'layers/parameter_validation.cpp',
                                           'generated' : False,
                                           'error_enum' : 'ErrorCode',},
    }

builtin_headers = [layer_inputs[ln]['header'] for ln in layer_inputs]
builtin_source = [layer_inputs[ln]['source'] for ln in layer_inputs]
builtin_tests = ['tests/layer_validation_tests.cpp', ]

# List of extensions in layers that are included in documentation, but not in vulkan.py API set
layer_extension_functions = ['objTrackGetObjects', 'objTrackGetObjectsOfType']

def handle_args():
    parser = argparse.ArgumentParser(description='Generate layer documenation from source.')
    parser.add_argument('--in_headers', required=False, default=builtin_headers, help='The input layer header files from which code will be generated.')
    parser.add_argument('--in_source', required=False, default=builtin_source, help='The input layer source files from which code will be generated.')
    parser.add_argument('--test_source', required=False, default=builtin_tests, help='The input test source files from which code will be generated.')
    parser.add_argument('--layer_doc', required=False, default='layers/vk_validation_layer_details.md', help='Existing layer document to be validated against actual layers.')
    parser.add_argument('--validate', action='store_true', default=False, help='Validate that there are no mismatches between layer documentation and source. This includes cross-checking the validation checks, and making sure documented Vulkan API calls exist.')
    parser.add_argument('--print_structs', action='store_true', default=False, help='Primarily a debug option that prints out internal data structs used to generate layer docs.')
    parser.add_argument('--print_doc_checks', action='store_true', default=False, help='Primarily a debug option that prints out all of the checks that are documented.')
    return parser.parse_args()

# Little helper class for coloring cmd line output
class bcolors:

    def __init__(self):
        self.GREEN = '\033[0;32m'
        self.RED = '\033[0;31m'
        self.YELLOW = '\033[1;33m'
        self.ENDC = '\033[0m'
        if 'Linux' != platform.system():
            self.GREEN = ''
            self.RED = ''
            self.YELLOW = ''
            self.ENDC = ''

    def green(self):
        return self.GREEN

    def red(self):
        return self.RED

    def yellow(self):
        return self.YELLOW

    def endc(self):
        return self.ENDC

# Class to parse the validation layer test source and store testnames
class TestParser:
    def __init__(self, test_file_list, test_group_name=['VkLayerTest', 'VkPositiveLayerTest', 'VkWsiEnabledLayerTest']):
        self.test_files = test_file_list
        self.tests_set = set()
        self.test_trigger_txt_list = []
        for tg in test_group_name:
            self.test_trigger_txt_list.append('TEST_F(%s' % tg)
            #print('Test trigger test list: %s' % (self.test_trigger_txt_list))

    # Parse test files into internal data struct
    def parse(self):
        # For each test file, parse test names into set
        grab_next_line = False # handle testname on separate line than wildcard
        for test_file in self.test_files:
            with open(test_file) as tf:
                for line in tf:
                    if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
                        continue

                    if True in [ttt in line for ttt in self.test_trigger_txt_list]:
                        #print('Test wildcard in line: %s' % (line))
                        testname = line.split(',')[-1]
                        testname = testname.strip().strip(' {)')
                        #print('Inserting test: "%s"' % (testname))
                        if ('' == testname):
                            grab_next_line = True
                            continue
                        self.tests_set.add(testname)
                    if grab_next_line: # test name on its own line
                        grab_next_line = False
                        testname = testname.strip().strip(' {)')
{'fraction_non_alphanumeric': 0.09234466186062479, 'fraction_numerical': 0.00789564023343632, 'mean_word_length': 2.1624751221277365, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 42, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4421555', 'n_tokens_mistral': 4611, 'n_tokens_neox': 4438, 'n_words': 1480}