Add CRC validator (#5857)

* Adds crc validation checks

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

* Fixes invalid CRCs

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

* Changes test to smoke suite

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

* excludes some test data from the validator

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

* uses pathlib instead of os.path

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

* fixes wrong path to test scripts

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

* Escape not needed

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
Esteban Papp
2021-11-30 15:07:57 -08:00
committed by GitHub
parent 858885dca9
commit fb6e6e339f
21 changed files with 130 additions and 35 deletions
@@ -181,4 +181,6 @@ EXCLUDED_VALIDATION_PATTERNS = [
'restricted/*/Tools/*RemoteControl',
'*/user/Cache/*',
'*/user/log/*',
'*/user/log_test_1/*',
'*/user/log_test_2/*',
]
@@ -0,0 +1,47 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
import unittest
from unittest.mock import patch, mock_open
from commit_validation.tests.mocks.mock_commit import MockCommit
from commit_validation.validators.crc_validator import CrcValidator
class CrcValidatorTests(unittest.TestCase):
@patch('builtins.open', mock_open(read_data='This file does not contain an AZ_CRC macro'))
def test_fileWithNoCrc_passes(self):
commit = MockCommit(files=['/someCppFile.cpp'])
error_list = []
self.assertTrue(CrcValidator().run(commit, error_list))
self.assertEqual(len(error_list), 0, f"Unexpected errors: {error_list}")
@patch('builtins.open', mock_open(read_data='This file contains an invalid CRC macro AZ_CRC("My string", 0xabcdef00)'))
def test_fileWithInvalidCrc_fails(self):
commit = MockCommit(files=['/someCppFile.cpp'])
error_list = []
self.assertFalse(CrcValidator().run(commit, error_list))
self.assertNotEqual(len(error_list), 0, f"Errors were expected but none were returned.")
@patch('builtins.open', mock_open(read_data='This file contains a valid CRC macro AZ_CRC("My string", 0x18fbd270)'))
def test_fileWithValidCrc_fails(self):
commit = MockCommit(files=['/someCppFile.cpp'])
error_list = []
self.assertTrue(CrcValidator().run(commit, error_list))
self.assertEqual(len(error_list), 0, f"Unexpected errors: {error_list}")
@patch('builtins.open', mock_open(read_data='This file contains an invalid CRC macro AZ_CRC("My string", 0xabcdef00)'))
def test_fileExtensionIgnored_passes(self):
commit = MockCommit(files=['/someCppFile.somerandomextension'])
error_list = []
self.assertTrue(CrcValidator().run(commit, error_list))
self.assertEqual(len(error_list), 0, f"Unexpected errors: {error_list}")
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,48 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
import binascii
import fnmatch
import pathlib
import re
from typing import Type, List
from commit_validation.commit_validation import Commit, CommitValidator, SOURCE_FILE_EXTENSIONS, EXCLUDED_VALIDATION_PATTERNS, VERBOSE
class CrcValidator(CommitValidator):
"""A file-level validator that makes sure a file does not contain an invalid CRC"""
def run(self, commit: Commit, errors: List[str]) -> bool:
for file_name in commit.get_files():
for pattern in EXCLUDED_VALIDATION_PATTERNS:
if fnmatch.fnmatch(file_name, pattern):
if VERBOSE: print(f'{file_name}::{self.__class__.__name__} SKIPPED - Validation pattern excluded on path.')
break
else:
if pathlib.Path(file_name).suffix.lower() not in SOURCE_FILE_EXTENSIONS:
if VERBOSE: print(f'{file_name}::{self.__class__.__name__} SKIPPED - File excluded based on extension.')
continue
with open(file_name, mode='r', encoding='utf8') as fh:
fileContents = fh.read()
matchesFound = re.findall(r'AZ_CRC\("([^"]+)",([^)]*)\)', fileContents)
for element in matchesFound:
stringInCode = element[0]
valueInCode = element[1].strip()
expectedValue = "{0:#0{1}x}".format(binascii.crc32(stringInCode.lower().encode('utf8')), 10)
if expectedValue != valueInCode:
error_message = str(f'{file_name}::{self.__class__.__name__} FAILED - Source file contains a CRC mismatch!\n'
f' AZ_CRC("{stringInCode}", {valueInCode}), expected value {expectedValue}')
if VERBOSE: print(error_message)
errors.append(error_message)
return (not errors)
def get_validator() -> Type[CrcValidator]:
"""Returns the validator class for this module"""
return CrcValidator