From 6c24566d35e4857377ca56716df5f8892b76833b Mon Sep 17 00:00:00 2001 From: Viktor Kreschenski Date: Tue, 22 Oct 2019 15:49:18 +0200 Subject: [PATCH 1/2] Implemented unit tests for osi comment compliance and corrected typo for enum Fog. --- .travis.yml | 3 +- osi_environment.proto | 2 +- test_cases.py | 290 ---------------------- test_cases_doc.py | 39 --- tests/__init__.py | 0 tests/test_comment_type.py | 255 +++++++++++++++++++ tests/test_doxygen_output.py | 51 ++++ tests/test_invalid_comment.py | 29 +++ tests/test_invalid_enum.py | 155 ++++++++++++ tests/test_invalid_html.py | 262 ++++++++++++++++++++ tests/test_invalid_message.py | 391 ++++++++++++++++++++++++++++++ tests/test_invalid_punctuation.py | 18 ++ tests/test_invalid_tabs.py | 19 ++ tests/test_newline.py | 21 ++ tests/test_non_ascii.py | 23 ++ 15 files changed, 1226 insertions(+), 332 deletions(-) delete mode 100644 test_cases.py delete mode 100644 test_cases_doc.py create mode 100644 tests/__init__.py create mode 100644 tests/test_comment_type.py create mode 100644 tests/test_doxygen_output.py create mode 100644 tests/test_invalid_comment.py create mode 100644 tests/test_invalid_enum.py create mode 100644 tests/test_invalid_html.py create mode 100644 tests/test_invalid_message.py create mode 100644 tests/test_invalid_punctuation.py create mode 100644 tests/test_invalid_tabs.py create mode 100644 tests/test_newline.py create mode 100644 tests/test_non_ascii.py diff --git a/.travis.yml b/.travis.yml index efc21cec4..f24643405 100644 --- a/.travis.yml +++ b/.travis.yml @@ -72,7 +72,6 @@ script: - cmake -D CMAKE_PREFIX_PATH:PATH=${DEPS_DIR}/protobuf/install -D CMAKE_INSTALL_PREFIX:PATH=${TESTINST_DIR} .. - cmake --build . - cd .. - - python test_cases.py - python setup.py build - python setup.py sdist - cd build @@ -87,7 +86,7 @@ script: - echo "GENERATE_TREEVIEW = YES" >> Doxyfile - doxygen - cd .. - - python test_cases_doc.py + - python -m unittest discover tests - mv VERSION.SAVED VERSION - sh convert-to-proto3.sh - mkdir -p build3 diff --git a/osi_environment.proto b/osi_environment.proto index 32e54e97c..31fc5cf12 100644 --- a/osi_environment.proto +++ b/osi_environment.proto @@ -140,7 +140,7 @@ message EnvironmentalConditions { // Visibility is unknown (must not be used in ground truth). // - FOG_UNKOWN = 0; + FOG_UNKNOWN = 0; // Other (unspecified but known) fog intensity. // diff --git a/test_cases.py b/test_cases.py deleted file mode 100644 index 5fb09bf9a..000000000 --- a/test_cases.py +++ /dev/null @@ -1,290 +0,0 @@ -import sys -import unicodedata -import re -from glob import * - -state = 0 - -for file in glob("*.*"): - with open(file, "rt") as fin: - i = 0 - isEnum = False - enumName = "" - noMessage = 0 - noComment = 0 - hasBrief = False - hasNewLine = True - htmlblock = False - saveStatement = "" - - for line in fin: - i = i + 1 - hasNewLine = line.endswith("\n") - - # -------------------------------------------------------------- - # Test case 1 is checking if there are illegal tabulators in the code - if line.find("\t") != -1: - print(file + " in line " + str(i) + ": not permitted tab found") - state = 1 - - # -------------------------------------------------------------- - # Test case 2 is checking if there is an "Umlaut" etc. - if (sys.version_info >= (3, 0)): - if line != unicodedata.normalize('NFKD', line).encode('ASCII', 'ignore').decode(): - print(file + " in line " + str(i) + ": a none ASCII char is present") - state = 1 - else: - if line != unicodedata.normalize('NFKD', unicode(line, 'ISO-8859-1')).encode('ASCII', 'ignore'): - print(file + " in line " + str(i) + ": a none ASCII char is present") - state = 1 - - if file.find(".proto") != -1: - # -------------------------------------------------------------- - # Test case 3 is checking if there are more than the two allowed '/' - if line.find("///") != -1: - print(file + " in line " + str(i) + ": not permitted use of '///' ") - state = 1 - - # -------------------------------------------------------------- - # Test case 4 is checking if there is an other type of comment - if line.find("/*") != -1: - print(file + " in line " + str(i) + ": not permitted use of '/*' ") - state = 1 - - # -------------------------------------------------------------- - # Test case 5 is checking if there is an other type of comment - if line.find("*/") != -1: - print(file + " in line " + str(i) + ": not permitted use of '*/' ") - state = 1 - - # -------------------------------------------------------------- - # Test case 9 is checking if there is '__' - if line.find("__") != -1: - print(file + " in line " + str(i) + ": not permitted use of '__' ") - state = 1 - - # -------------------------------------------------------------- - # Divide statement and comment. Concatenate multi line statements. - - # Search for comment ("//"). - matchComment = re.search("//", line) - if matchComment is not None: - statement = line[:matchComment.start()] - comment = line[matchComment.end():] - else: - statement = line - comment = "" - - # Add part of the statement from last line. - statement = saveStatement + " " + statement - saveStatement = "" - - # New line is not necessary. Remove for a better output. - statement = statement.replace("\n", "") - comment = comment.replace("\n", "") - - # Is statement complete - matchSep = re.search(r"[{};]", statement) - if matchSep is None: - saveStatement = statement - statement = "" - else: - saveStatement = statement[matchSep.end():] - statement = statement[:matchSep.end()] - - # -------------------------------------------------------------- - # Test case 6-8 camelcase for enums and check enum name? - - # . - if isEnum is True: - matchName = re.search(r"\b\w[\S:]+\b", statement) - if matchName is not None: - checkName = statement[matchName.start():matchName.end()] - # Test case 6: Check correct name - if checkName.find(enumName) != 0: - print(file + " in line " + str(i) + ": enum type wrong. '"+checkName+"' should start with '"+enumName+"'") - state = 1 - # Test case 7: Check upper case - elif checkName != checkName.upper(): - print(file + " in line " + str(i) + ": enum type wrong. '"+checkName+"' should use upper case") - state = 1 - - # Search for "enum". - matchEnum = re.search(r"\benum\b", statement) - if matchEnum is not None: - isEnum = True - endOfLine = statement[matchEnum.end():] - matchName = re.search(r"\b\w[\S]*\b", endOfLine) - if matchName is not None: - # Test case 8: Check name - no special char - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b",endOfLine[matchName.start():matchName.end()]) - if matchNameConv is None: - print(file + " in line " + str(i) + ": enum name wrong. '"+endOfLine[matchName.start():matchName.end()]+"'") - state = 1 - enumName = convert(endOfLine[matchName.start():matchName.end()])+"_" - - # Search for a closing brace. - matchClosingBrace = re.search("}", statement) - if isEnum is True and matchClosingBrace is not None: - isEnum = False - enumName = "" - - def convert(name): - s1 = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', name) - return re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', s1).upper() - - # -------------------------------------------------------------- - # Test case 10-12,18 check message name, field type and field name - # - # Check (nested) messages - - if isEnum is False: - # Check if not inside an enum. - - # Search for "message". - matchMessage = re.search(r"\bmessage\b", statement) - if matchMessage is not None: - # a new message or a new nested message - noMessage += 1 - endOfLine = statement[matchMessage.end():] - matchName = re.search(r"\b\w[\S]*\b", endOfLine) - if matchName is not None: - # Test case 10: Check name - no special char - - # start with a capital letter - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b",endOfLine[matchName.start():matchName.end()]) - if matchNameConv is None: - print(file + " in line " + str(i) + ": message name wrong. '"+endOfLine[matchName.start():matchName.end()]+"'") - state = 1 - elif re.search(r"\bextend\b", statement) is not None: - # treat extend as message - noMessage += 1 - else: - # Check field names - if noMessage > 0: - matchName = re.search(r"\b\w[\S]*\b\s*=", statement) - if matchName is not None: - checkName = statement[matchName.start():matchName.end()-1] - # Test case 11: Check lowercase letters for field names - if checkName != checkName.lower(): - print(file + " in line " + str(i) + ": field name wrong. '"+checkName+"' should use lower case") - state = 1 - # Check field message type (remove field name) - type = statement.replace(checkName, "") - matchName = re.search(r"\b\w[\S\.]*\s*=", type) - if matchName is not None: - checkType = " "+type[matchName.start():matchName.end()-1]+" " - # Test case 12: Check nested message type - matchNameConv = re.search(r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]",checkType) - if matchNameConv is None: - print(file + " in line " + str(i) + ": field message type wrong. Check: '"+checkType+"'") - state = 1 - - if re.search(r"\boptional\b",type) is None and re.search(r"\brepeated\b",type) is None: - # Test 18 has every field the multiplicity "repeated" or "optional" - print(file + " in line " + str(i) + ": field multiplicity (\"optional\" or \"repeated\") is missing. Check: '"+statement+"'") - state = 1 - - # Search for a closing brace. - matchClosingBrace = re.search("}", statement) - if noMessage > 0 and matchClosingBrace is not None: - noMessage -= 1 - - # -------------------------------------------------------------- - # Test case 13-17 is checking comment - if matchComment is not None: - noComment += 1; - if comment.find("\\brief") != -1: - hasBrief = True; - elif len(saveStatement) == 0: - # Test case 13 is checking if comment is min. 2 lines - if noComment == 1: - print(file + " in line " + str(i-1) + ": short comment - min. 2 lines.") - state = 1 - if re.search(r"\bmessage\b", statement) is not None or re.search(r"\bextend\b", statement) is not None: - if hasBrief == False: - # Test case 14 each message and extend has a \brief comment - print(file + " in line " + str(i-1) + ": \\brief section in comment is missing for: '"+statement+"'") - state = 1 - elif hasBrief == True: - # Test case 15 only message and extend has a \brief comment - print(file + " in line " + str(i-1) + ": \\brief section in comment is not necessary for: '"+statement+"'") - state = 1 - - if re.search(r"\bmessage\b", statement) is not None or re.search(r"\bextend\b", statement) is not None or re.search(r"\benum\b", statement) is not None: - if noComment == 0: - # Test case 16 every message, extend or enum has a comment - print(file + " in line " + str(i) + ": comment is missing for: '"+statement+"'") - state = 1 - - if noMessage > 0 or isEnum == True: - if statement.find(";") != -1: - if noComment == 0: - # Test case 17 every statement has a comment - print(file + " in line " + str(i) + ": comment is missing for: '"+statement+"'") - state = 1 - - - noComment = 0 - hasBrief = False - - # -------------------------------------------------------------- - # Test case 20 is checking comment and html tags - if matchComment is not None: - htmlComment = "" - htmlFreeComment = comment - if htmlblock is False: - matchHTMLOnly = re.search(r"\\htmlonly", comment) - if matchHTMLOnly is not None: - - htmlComment = comment[matchHTMLOnly.end():] - htmlFreeComment = comment[:matchHTMLOnly.start()] - htmlblock = True - else: - htmlComment = comment - htmlFreeComment = "" - - if htmlblock is True: - matchEndHTMLOnly = re.search(r"\\endhtmlonly", htmlComment) - if matchEndHTMLOnly is not None: - htmlFreeComment = htmlFreeComment+htmlComment[matchEndHTMLOnly.end():] - htmlComment = htmlComment[:matchEndHTMLOnly.start()] - htmlblock = False - - #if htmlFreeComment.find("<") != -1: - # Test case 20 html tags only in htmlonly sections --> no error - #print(file + " in line " + str(i) + ": doxygen comment html tag found (use htmlonly if possible): '"+htmlFreeComment+"'") - ##state = 1 - if htmlComment.find("\\") != -1: - # Test case 23 html tags only in htmlonly sections - print(file + " in line " + str(i) + ": doxygen comment \\.. reference found: '"+htmlComment+"'") - #state = 1 - if htmlComment.find("#") != -1: - # Test case 24 html tags only in htmlonly sections - print(file + " in line " + str(i) + ": doxygen comment #.. reference found: '"+htmlComment+"'") - #state = 1 - - elif htmlblock is True: - # Test case 22 html tags only in htmlonly sections without end html only - print(file + " in line " + str(i-1) + ": doxygen comment html section without endhtmlonly") - htmlblock = False - #state = 1 - - - # -------------------------------------------------------------- - # Test case 21 is checking comment and html tags - if matchComment is not None: - if comment.find("@") != -1: - # Test case 21 html tags only in htmlonly sections - print(file + " in line " + str(i) + ": @ tag found (please replace with \\): '"+htmlFreeComment+"'") - state = 1 - - # -------------------------------------------------------------- - # Next Test 25 - - - # Test case 19 last line must end with a new line. - if hasNewLine == False: - print(file + " has no new line at the end of the file.") - state = 1 - -sys.exit(state) diff --git a/test_cases_doc.py b/test_cases_doc.py deleted file mode 100644 index 74cc5f715..000000000 --- a/test_cases_doc.py +++ /dev/null @@ -1,39 +0,0 @@ -import sys -import unicodedata -import re -from glob import * - -state = 0 - -for file in glob("doc/html/*.htm*"): - with open(file, "rt") as fin: - i = 0 - - for line in fin: - i = i + 1 - - # -------------------------------------------------------------- - # Test case 1 is checking if there are illegal hash chars in the - # documentation. -> doxygen link not found. - matchHash = re.search(r"([\s>]|^)#\w(\S)*",line) - if matchHash is not None: - print(file + " in line " + str(i) + ": not permitted hash found. Search for: '"+line[matchHash.start():matchHash.end()]) - state = 1 - - # -------------------------------------------------------------- - # Test case 2 is checking if there are slash triplets in the - # documentation. -> doxygen didn't interpret something properly. - matchHash = re.search(r"([\s>]|^)///\s*",line) - if matchHash is not None: - print(file + " in line " + str(i) + ": not permitted slash triplet found. Search for: '"+line[matchHash.start():matchHash.end()]) - state = 1 - - # -------------------------------------------------------------- - # Test case 3 is checking if there are backslash triplets in the - # documentation. -> doxygen didn't interpret something properly. - matchHash = re.search(r"([\s>]|^)\\\\\\\s*",line) - if matchHash is not None: - print(file + " in line " + str(i) + ": not permitted slash triplet found. Search for: '"+line[matchHash.start():matchHash.end()]) - state = 1 - -sys.exit(state) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_comment_type.py b/tests/test_comment_type.py new file mode 100644 index 000000000..96ad618c6 --- /dev/null +++ b/tests/test_comment_type.py @@ -0,0 +1,255 @@ +import sys +import unicodedata +import re +from glob import * +import unittest + + +class TestCommentType(unittest.TestCase): + ''' Test class for mandatory new line. ''' + + def test_brief_necessity(self): + ''' Test the necessity of "brief" comment. ''' + + for file in glob("*.proto"): + with open(file, "rt") as fin: + i = 0 + noMessage = 0 + noComment = 0 + hasBrief = False + saveStatement = "" + + for line in fin: + i += 1 + + # Divide statement and comment. Concatenate multi line statements. + + # Search for comment ("//"). + matchComment = re.search("//", line) + + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + statement = statement.strip() + # Test to check if '\\brief' is appended in comment section for short comments. + if matchComment is not None: + noComment += 1; + if comment.find("\\brief") != -1: + hasBrief = True + + elif len(saveStatement) == 0: + if re.search(r"\bmessage\b", statement) is not None or re.search(r"\bextend\b",statement) is not None: + self.assertTrue(hasBrief, file + " in line " + str(i - 1) + ": \\brief section in comment is missing for: '" + statement + "'") + + elif hasBrief: + self.assertFalse(hasBrief, file + " in line " + str(i - 1) + ": \\brief section in comment is not necessary for: '" + statement + "'") + + noComment = 0 + hasBrief = False + + + + def test_min_two_lines(self): + ''' Test to check if short comment is of minimum two lines. ''' + + for file in glob("*.proto"): + with open(file, "rt") as fin: + i = 0 + isEnum = False + noMessage = 0 + noComment = 0 + hasBrief = False + saveStatement = "" + + for line in fin: + i += 1 + + # Divide statement and comment. Concatenate multi line statements. + + # Search for comment ("//"). + matchComment = re.search("//", line) + + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + # Test to check if '\\brief' is appended in comment section for short comments. + if matchComment is not None: + noComment += 1; + if comment.find("\\brief") != -1: + hasBrief = True + + elif len(saveStatement) == 0: + self.assertNotEqual(noComment, 1, file + " in line " + str(i - 1) + ": short comment - min. 2 lines.") + noComment = 0 + hasBrief = False + + + def test_comment_existence(self): + ''' Test to check if every message, extend , statement or enum has a comment. ''' + + for file in glob("*.proto"): + + with open(file, "rt") as fin: + i = 0 + isEnum = False + noMessage = 0 + noComment = 0 + hasBrief = False + saveStatement = "" + + for line in fin: + i += 1 + + # Divide statement and comment. Concatenate multi line statements. + + # Search for comment ("//"). + matchComment = re.search("//", line) + + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + + if isEnum is False: + # Check if not inside an enum. + + # Search for "message". + matchMessage = re.search(r"\bmessage\b", statement) + if matchMessage is not None: + # a new message or a new nested message + noMessage += 1 + endOfLine = statement[matchMessage.end():] + matchName = re.search(r"\b\w[\S]*\b", endOfLine) + if matchName is not None: + # Test case 10: Check name - no special char - + # start with a capital letter + matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b",endOfLine[matchName.start():matchName.end()]) + + elif re.search(r"\bextend\b", statement) is not None: + # treat extend as message + noMessage += 1 + else: + # Check field names + if noMessage > 0: + matchName = re.search(r"\b\w[\S]*\b\s*=", statement) + if matchName is not None: + checkName = statement[matchName.start():matchName.end()-1] + + # Check field message type (remove field name) + type = statement.replace(checkName, "") + matchName = re.search(r"\b\w[\S\.]*\s*=", type) + if matchName is not None: + checkType = " "+type[matchName.start():matchName.end()-1]+" " + # Test case 12: Check nested message type + matchNameConv = re.search(r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]",checkType) + + # Search for a closing brace. + matchClosingBrace = re.search("}", statement) + if noMessage > 0 and matchClosingBrace is not None: + noMessage -= 1 + + + # Test to check if '\\brief' is appended in comment section for short comments. + if matchComment is not None: + noComment += 1 + if comment.find("\\brief") != -1: + hasBrief = True + + elif len(saveStatement) == 0: + + statement = statement.strip() + + if re.search(r"\bmessage\b", statement) is not None or re.search(r"\bextend\b",statement) is not None or re.search(r"\benum\b", statement) is not None: + + self.assertNotEqual(noComment, 0, file + " in line " + str(i - 1) + ": comment is missing for: '" + statement + "'") + + if noMessage > 0 or isEnum == True: + if statement.find(";") != -1: + self.assertNotEqual(noComment, 0, file + " in line " + str(i) + ": comment is missing for: '" + statement + "'") + + noComment = 0 + hasBrief = False + + # Search for "enum". + matchEnum = re.search(r"\benum\b", statement) + + if matchEnum is not None: + isEnum = True + endOfLine = statement[matchEnum.end():] + matchName = re.search(r"\b\w[\S]*\b", endOfLine) + if matchName is not None: + # Test to ensure no special characters are in ENUM name. + matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) + enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + + # Search for a closing brace. + matchClosingBrace = re.search("}", statement) + if isEnum is True and matchClosingBrace is not None: + isEnum = False + enumName = "" + + def convert(self, name): + s1 = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', name) + return re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', s1).upper() \ No newline at end of file diff --git a/tests/test_doxygen_output.py b/tests/test_doxygen_output.py new file mode 100644 index 000000000..b6a1a9cba --- /dev/null +++ b/tests/test_doxygen_output.py @@ -0,0 +1,51 @@ +import sys +import unicodedata +import re +from glob import * +import unittest + + +class TestDoxygenOutput(unittest.TestCase): + """ Test class for the doxygen output. """ + + def test_hash(self): + ''' Test case is checking if there are illegal hash chars in the documentation. -> doxygen link not found. ''' + for file in glob("doc/html/*.htm*"): + with open(file, "rt") as fin: + i = 0 + + for line in fin: + i += 1 + matchHash = re.search(r"([\s>]|^)#\w(\S)*", line) + + if matchHash is not None: + self.assertIsNone(matchHash, file + " in line " + str(i) + ": not permitted hash found. Search for: '"+ line[matchHash.start():matchHash.end()]) + + + def test_slash_triplet(self): + ''' Test case is checking if there are slash triplets in the documentation. -> doxygen didn't interpret something properly. ''' + + for file in glob("doc/html/*.htm*"): + with open(file, "rt") as fin: + i = 0 + + for line in fin: + i += 1 + matchHash = re.search(r"([\s>]|^)///\s*",line) + + if matchHash is not None: + self.assertIsNone(matchHash, file + " in line " + str(i) + ": not permitted slash triplet found. Search for: '"+line[matchHash.start():matchHash.end()]) + + + def test_backslash_triplet(self): + ''' Test case is checking if there are backslash triplets in the documentation. -> doxygen didn't interpret something properly. ''' + for file in glob("doc/html/*.htm*"): + with open(file, "rt") as fin: + i = 0 + + for line in fin: + i += 1 + matchHash = re.search(r"([\s>]|^)\\\\\\\s*",line) + + if matchHash is not None: + self.assertIsNone(matchHash, file + " in line " + str(i) + ": not permitted backslash triplet found. Search for: '"+line[matchHash.start():matchHash.end()]) diff --git a/tests/test_invalid_comment.py b/tests/test_invalid_comment.py new file mode 100644 index 000000000..32eda856c --- /dev/null +++ b/tests/test_invalid_comment.py @@ -0,0 +1,29 @@ +import sys +import unicodedata +import re +from glob import * +import unittest + +class TestInvalidCommentType(unittest.TestCase): + """Test class for invalid comment types""" + + def test_triple_slash(self): + ''' Test to check if more than two forward slash('/') are present in comment section of proto file. ''' + for file in glob("*.proto"): + with open(file, "rt") as fin: + i = 0 + + for line in fin: + i += 1 + self.assertEqual(line.find("///"), -1, file + " in line " + str(i) + ": not permitted use of '///' ") + + def test_comments_invalid_syntax(self): + ''' Test to check if comments are given using invalid syntax '/*' or '*/' ''' + for file in glob("*.proto"): + with open(file, "rt") as fin: + i = 0 + + for line in fin: + i += 1 + self.assertEqual(line.find("/*"), -1, file + " in line " + str(i) + ": not permitted use of '/*' ") + self.assertEqual(line.find("*/"), -1, file + " in line " + str(i) + ": not permitted use of '*/' ") \ No newline at end of file diff --git a/tests/test_invalid_enum.py b/tests/test_invalid_enum.py new file mode 100644 index 000000000..3bab9b6e4 --- /dev/null +++ b/tests/test_invalid_enum.py @@ -0,0 +1,155 @@ +import sys +import unicodedata +import re +from glob import * +import unittest + +class TestInvalidEnum(unittest.TestCase): + ''' Test class to check invalid enum ''' + + def test_correct_enum_name(self): + ''' Test if enum name is correct. ''' + for file in glob("*.proto"): + with open(file, "rt") as fin: + i = 0 + isEnum = False + enumName = "" + saveStatement = "" + + for line in fin: + i += 1 + + # Divide statement and comment. Concatenate multi line statements. + + # Search for comment ("//"). + matchComment = re.search("//", line) + + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + # This section will check camelcase for enums and check enum name? + + if isEnum is True: + matchName = re.search(r"\b\w[\S:]+\b", statement) + + if matchName is not None: + checkName = statement[matchName.start():matchName.end()] + + # Test to check correct ENUM name. + self.assertEqual(checkName.find(enumName), 0, file + " in line " + str(i) + ": enum type wrong. '" + checkName + "' should start with '" + enumName + "'") + + # Test to check ENUM type is in captial letters/upper case. + self.assertEqual(checkName, checkName.upper(), file + " in line " + str(i) + ": enum type wrong. '" + checkName + "' should use upper case") + + + # Search for "enum". + matchEnum = re.search(r"\benum\b", statement) + + if matchEnum is not None: + isEnum = True + endOfLine = statement[matchEnum.end():] + matchName = re.search(r"\b\w[\S]*\b", endOfLine) + if matchName is not None: + # Test to ensure no special characters are in ENUM name. + matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) + enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + + # Search for a closing brace. + matchClosingBrace = re.search("}", statement) + if isEnum is True and matchClosingBrace is not None: + isEnum = False + enumName = "" + + + def test_invalid_enum(self): + ''' Test invalid enum definition. ''' + for file in glob("*.proto"): + with open(file, "rt") as fin: + i = 0 + isEnum = False + enumName = "" + saveStatement = "" + + for line in fin: + i += 1 + + # Divide statement and comment. Concatenate multi line statements. + + # Search for comment ("//"). + matchComment = re.search("//", line) + + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + # This section will check camelcase for enums and check enum name? + + if isEnum is True: + matchName = re.search(r"\b\w[\S:]+\b", statement) + + if matchName is not None: + checkName = statement[matchName.start():matchName.end()] + + # Search for "enum". + matchEnum = re.search(r"\benum\b", statement) + + if matchEnum is not None: + isEnum = True + endOfLine = statement[matchEnum.end():] + matchName = re.search(r"\b\w[\S]*\b", endOfLine) + if matchName is not None: + # Test to ensure no special characters are in ENUM name. + matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) + self.assertIsNotNone(matchNameConv, file + " in line " + str(i) + ": enum name wrong. '" + endOfLine[matchName.start():matchName.end()] + "'") + enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + + # Search for a closing brace. + matchClosingBrace = re.search("}", statement) + if isEnum is True and matchClosingBrace is not None: + isEnum = False + enumName = "" + + def convert(self, name): + s1 = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', name) + return re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', s1).upper() \ No newline at end of file diff --git a/tests/test_invalid_html.py b/tests/test_invalid_html.py new file mode 100644 index 000000000..ea6554b1c --- /dev/null +++ b/tests/test_invalid_html.py @@ -0,0 +1,262 @@ +import sys +import unicodedata +import re +from glob import * +import unittest + + +class TestInvalidHtml(unittest.TestCase): + """ Test class for invalid html comment. """ + + def test_invalid_slash(self): + ''' Test case to check invalid slash in htmlonly sections ''' + for file in glob("*.*"): + with open(file, "rt") as fin: + i = 0 + htmlblock = False + saveStatement = "" + + for line in fin: + i += 1 + + # Search for comment ("//"). + matchComment = re.search("//", line) + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + # Test case is checking comment and html tags + if matchComment is not None: + htmlComment = "" + htmlFreeComment = comment + if htmlblock is False: + matchHTMLOnly = re.search(r"\\htmlonly", comment) + if matchHTMLOnly is not None: + + htmlComment = comment[matchHTMLOnly.end():] + htmlFreeComment = comment[:matchHTMLOnly.start()] + htmlblock = True + else: + htmlComment = comment + htmlFreeComment = "" + + if htmlblock is True: + matchEndHTMLOnly = re.search(r"\\endhtmlonly", htmlComment) + if matchEndHTMLOnly is not None: + htmlFreeComment = htmlFreeComment + htmlComment[matchEndHTMLOnly.end():] + htmlComment = htmlComment[:matchEndHTMLOnly.start()] + htmlblock = False + + # Test case to check html tags only in htmlonly sections + self.assertEqual(htmlComment.find("\\"), -1, file + " in line " + str(i) + ": doxygen comment \\.. reference found: '" + htmlComment + "'") + + + def test_invalid_hash(self): + ''' Test case to check invalid # in htmlonly sections ''' + for file in glob("*.*"): + with open(file, "rt") as fin: + i = 0 + htmlblock = False + saveStatement = "" + + for line in fin: + i += 1 + + # Search for comment ("//"). + matchComment = re.search("//", line) + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + # Test case is checking comment and html tags + if matchComment is not None: + htmlComment = "" + htmlFreeComment = comment + if htmlblock is False: + matchHTMLOnly = re.search(r"\\htmlonly", comment) + if matchHTMLOnly is not None: + + htmlComment = comment[matchHTMLOnly.end():] + htmlFreeComment = comment[:matchHTMLOnly.start()] + htmlblock = True + else: + htmlComment = comment + htmlFreeComment = "" + + if htmlblock is True: + matchEndHTMLOnly = re.search(r"\\endhtmlonly", htmlComment) + if matchEndHTMLOnly is not None: + htmlFreeComment = htmlFreeComment + htmlComment[matchEndHTMLOnly.end():] + htmlComment = htmlComment[:matchEndHTMLOnly.start()] + htmlblock = False + + self.assertEqual(htmlComment.find("#"), -1, file + " in line " + str(i) + ": doxygen comment #.. reference found: '" + htmlComment + "'") + + + def test_invalid_at(self): + ''' Test case to check invalid @ in comments ''' + for file in glob("*.*"): + with open(file, "rt") as fin: + i = 0 + htmlblock = False + saveStatement = "" + + for line in fin: + i += 1 + + # Search for comment ("//"). + matchComment = re.search("//", line) + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + # Test case is checking comment and html tags + if matchComment is not None: + htmlComment = "" + htmlFreeComment = comment + if htmlblock is False: + matchHTMLOnly = re.search(r"\\htmlonly", comment) + if matchHTMLOnly is not None: + + htmlComment = comment[matchHTMLOnly.end():] + htmlFreeComment = comment[:matchHTMLOnly.start()] + htmlblock = True + else: + htmlComment = comment + htmlFreeComment = "" + + if htmlblock is True: + matchEndHTMLOnly = re.search(r"\\endhtmlonly", htmlComment) + if matchEndHTMLOnly is not None: + htmlFreeComment = htmlFreeComment + htmlComment[matchEndHTMLOnly.end():] + htmlComment = htmlComment[:matchEndHTMLOnly.start()] + htmlblock = False + + self.assertEqual(comment.find("@"), -1, file + " in line " + str(i) + ": @ tag found (please replace with \\): '" + htmlFreeComment + "'") + + + def test_no_endhtmlonly(self): + ''' Test case to check no \endhtmlonly in comments ''' + for file in glob("*.*"): + with open(file, "rt") as fin: + i = 0 + htmlblock = False + saveStatement = "" + + for line in fin: + i += 1 + + # Search for comment ("//"). + matchComment = re.search("//", line) + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + # Test case is checking comment and html tags + if matchComment is not None: + htmlComment = "" + htmlFreeComment = comment + if htmlblock is False: + matchHTMLOnly = re.search(r"\\htmlonly", comment) + if matchHTMLOnly is not None: + + htmlComment = comment[matchHTMLOnly.end():] + htmlFreeComment = comment[:matchHTMLOnly.start()] + htmlblock = True + else: + htmlComment = comment + htmlFreeComment = "" + + if htmlblock is True: + matchEndHTMLOnly = re.search(r"\\endhtmlonly", htmlComment) + + if matchEndHTMLOnly is not None: + htmlFreeComment = htmlFreeComment + htmlComment[matchEndHTMLOnly.end():] + htmlComment = htmlComment[:matchEndHTMLOnly.start()] + htmlblock = False + + elif htmlblock: + self.assertFalse(htmlblock, file + " in line " + str(i - 1) + ": doxygen comment html section without endhtmlonly") + htmlblock = False + + \ No newline at end of file diff --git a/tests/test_invalid_message.py b/tests/test_invalid_message.py new file mode 100644 index 000000000..9b4760d84 --- /dev/null +++ b/tests/test_invalid_message.py @@ -0,0 +1,391 @@ +import sys +import unicodedata +import re +from glob import * +import unittest + + +class TestInvalidMessage(unittest.TestCase): + """ Test class for invalid html comment. """ + + def test_message_name(self): + ''' Test to check if message name have any special character. It should not have any special character. ''' + + for file in glob("*.proto"): + with open(file, "rt") as fin: + i = 0 + isEnum = False + enumName = "" + noMessage = 0 + saveStatement = "" + + for line in fin: + i += 1 + + # Divide statement and comment. Concatenate multi line statements. + # Search for comment ("//"). + matchComment = re.search("//", line) + + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + if isEnum is False: + # Check if not inside an enum. + + # Search for "message". + matchMessage = re.search(r"\bmessage\b", statement) + if matchMessage is not None: + # a new message or a new nested message + noMessage += 1 + endOfLine = statement[matchMessage.end():] + matchName = re.search(r"\b\w[\S]*\b", endOfLine) + if matchName is not None: + # Test to check if message name have any special character. It should not have any special character. + # Message should always start with special character. + matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b",endOfLine[matchName.start():matchName.end()]) + self.assertIsNotNone(matchNameConv, file + " in line " + str(i - 1) + ": message name wrong. '" + endOfLine[matchName.start():matchName.end()] + "'") + + # Search for "enum". + matchEnum = re.search(r"\benum\b", statement) + + if matchEnum is not None: + isEnum = True + endOfLine = statement[matchEnum.end():] + matchName = re.search(r"\b\w[\S]*\b", endOfLine) + if matchName is not None: + # Test to check presence of invalid special characters + matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) + enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + + # Search for a closing brace. + matchClosingBrace = re.search("}", statement) + if isEnum is True and matchClosingBrace is not None: + isEnum = False + enumName = "" + + + def test_field_name(self): + ''' Test to check if field names are in lower case. ''' + + for file in glob("*.proto"): + with open(file, "rt") as fin: + i = 0 + isEnum = False + enumName = "" + noMessage = 0 + saveStatement = "" + + for line in fin: + i += 1 + + # Divide statement and comment. Concatenate multi line statements. + + # Search for comment ("//"). + matchComment = re.search("//", line) + + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + if isEnum is False: + # Check if not inside an enum. + + # Search for "message". + matchMessage = re.search(r"\bmessage\b", statement) + if matchMessage is not None: + # a new message or a new nested message + noMessage += 1 + endOfLine = statement[matchMessage.end():] + matchName = re.search(r"\b\w[\S]*\b", endOfLine) + if matchName is not None: + matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b",endOfLine[matchName.start():matchName.end()]) + + elif re.search(r"\bextend\b", statement) is not None: + # treat extend as message + noMessage += 1 + else: + # Check field names + if noMessage > 0: + matchName = re.search(r"\b\w[\S]*\b\s*=", statement) + + if matchName is not None: + checkName = statement[matchName.start():matchName.end() - 1] + self.assertEqual(checkName, checkName.lower(), file + " in line " + str(i) + ": field name wrong. '" + checkName + "' should use lower case") + type = statement.replace(checkName, "") + matchName = re.search(r"\b\w[\S\.]*\s*=", type) + + if matchName is not None: + checkType = " " + type[matchName.start():matchName.end() - 1] + " " + # Test to check nested message type + matchNameConv = re.search(r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]",checkType) + + # Search for a closing brace. + matchClosingBrace = re.search("}", statement) + if noMessage > 0 and matchClosingBrace is not None: + noMessage -= 1 + + # Search for "enum". + matchEnum = re.search(r"\benum\b", statement) + + if matchEnum is not None: + isEnum = True + endOfLine = statement[matchEnum.end():] + matchName = re.search(r"\b\w[\S]*\b", endOfLine) + if matchName is not None: + # Test to check presence of invalid special characters + matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) + enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + + # Search for a closing brace. + matchClosingBrace = re.search("}", statement) + if isEnum is True and matchClosingBrace is not None: + isEnum = False + enumName = "" + + def test_field_type(self): + ''' Test to check nested message type. ''' + + for file in glob("*.proto"): + with open(file, "rt") as fin: + i = 0 + isEnum = False + enumName = "" + noMessage = 0 + saveStatement = "" + + for line in fin: + i += 1 + + # Divide statement and comment. Concatenate multi line statements. + + # Search for comment ("//"). + matchComment = re.search("//", line) + + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + if isEnum is False: + # Check if not inside an enum. + + # Search for "message". + matchMessage = re.search(r"\bmessage\b", statement) + if matchMessage is not None: + # a new message or a new nested message + noMessage += 1 + endOfLine = statement[matchMessage.end():] + matchName = re.search(r"\b\w[\S]*\b", endOfLine) + if matchName is not None: + matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b",endOfLine[matchName.start():matchName.end()]) + + elif re.search(r"\bextend\b", statement) is not None: + # treat extend as message + noMessage += 1 + else: + # Check field names + if noMessage > 0: + matchName = re.search(r"\b\w[\S]*\b\s*=", statement) + if matchName is not None: + checkName = statement[matchName.start():matchName.end() - 1] + + # Check field message type (remove field name) + type = statement.replace(checkName, "") + matchName = re.search(r"\b\w[\S\.]*\s*=", type) + if matchName is not None: + checkType = " " + type[matchName.start():matchName.end() - 1] + " " + # Test to check nested message type + matchNameConv = re.search(r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]", checkType) + + checkType = checkType.strip() + self.assertIsNotNone(matchNameConv, file + " in line " + str(i) + ": field message type wrong. Check: '" + checkType + "'") + + # Search for a closing brace. + matchClosingBrace = re.search("}", statement) + if noMessage > 0 and matchClosingBrace is not None: + noMessage -= 1 + + # Search for "enum". + matchEnum = re.search(r"\benum\b", statement) + + if matchEnum is not None: + isEnum = True + endOfLine = statement[matchEnum.end():] + matchName = re.search(r"\b\w[\S]*\b", endOfLine) + if matchName is not None: + # Test to check presence of invalid special characters + matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) + enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + + # Search for a closing brace. + matchClosingBrace = re.search("}", statement) + if isEnum is True and matchClosingBrace is not None: + isEnum = False + enumName = "" + + def test_field_multiplicity(self): + ''' Test to check if every field has the multiplicity "repeated" or "optional". ''' + + for file in glob("*.proto"): + + with open(file, "rt") as fin: + i = 0 + isEnum = False + enumName = "" + noMessage = 0 + saveStatement = "" + + for line in fin: + i += 1 + + # Divide statement and comment. Concatenate multi line statements. + + # Search for comment ("//"). + matchComment = re.search("//", line) + + if matchComment is not None: + statement = line[:matchComment.start()] + comment = line[matchComment.end():] + else: + statement = line + comment = "" + + # Add part of the statement from last line. + statement = saveStatement + " " + statement + saveStatement = "" + + # New line is not necessary. Remove for a better output. + statement = statement.replace("\n", "") + comment = comment.replace("\n", "") + + # Is statement complete + matchSep = re.search(r"[{};]", statement) + if matchSep is None: + saveStatement = statement + statement = "" + else: + saveStatement = statement[matchSep.end():] + statement = statement[:matchSep.end()] + + if isEnum is False: + # Check if not inside an enum. + + # Search for "message". + matchMessage = re.search(r"\bmessage\b", statement) + if matchMessage is not None: + # a new message or a new nested message + noMessage += 1 + endOfLine = statement[matchMessage.end():] + matchName = re.search(r"\b\w[\S]*\b", endOfLine) + if matchName is not None: + matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b",endOfLine[matchName.start():matchName.end()]) + + elif re.search(r"\bextend\b", statement) is not None: + # treat extend as message + noMessage += 1 + + else: + # Check field names + if noMessage > 0: + matchName = re.search(r"\b\w[\S]*\b\s*=", statement) + if matchName is not None: + checkName = statement[matchName.start():matchName.end() - 1] + + # Check field message type (remove field name) + type = statement.replace(checkName, "") + matchName = re.search(r"\b\w[\S\.]*\s*=", type) + if matchName is not None: + checkType = " " + type[matchName.start():matchName.end() - 1] + " " + # Test to check nested message type + matchNameConv = re.search(r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]",checkType) + + statement = statement.strip() + self.assertIsNotNone(re.search(r"\boptional\b", type) is None and re.search(r"\brepeated\b",type), file + " in line " + str(i) + ": field multiplicity (\"optional\" or \"repeated\") is missing. Check: '" + statement + "'") + + # Search for a closing brace. + matchClosingBrace = re.search("}", statement) + if noMessage > 0 and matchClosingBrace is not None: + noMessage -= 1 + + # Search for "enum". + matchEnum = re.search(r"\benum\b", statement) + + if matchEnum is not None: + isEnum = True + endOfLine = statement[matchEnum.end():] + matchName = re.search(r"\b\w[\S]*\b", endOfLine) + if matchName is not None: + # Test to check presence of invalid special characters + matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) + enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + + # Search for a closing brace. + matchClosingBrace = re.search("}", statement) + if isEnum is True and matchClosingBrace is not None: + isEnum = False + enumName = "" + + def convert(self, name): + s1 = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', name) + return re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', s1).upper() + diff --git a/tests/test_invalid_punctuation.py b/tests/test_invalid_punctuation.py new file mode 100644 index 000000000..f7637f478 --- /dev/null +++ b/tests/test_invalid_punctuation.py @@ -0,0 +1,18 @@ +import sys +import unicodedata +import re +from glob import * +import unittest + +class TestInvalidPunctuation(unittest.TestCase): + ''' Test class to check invalid punctuation character '__' ''' + + def test_invalid_punctuation(self): + ''' Test to check invalid punctuation character '__' ''' + for file in glob("*.proto"): + with open(file, "rt") as fin: + i = 0 + + for line in fin: + i += 1 + self.assertEqual(line.find("__"), -1, file + " in line " + str(i) + ": not permitted use of '__' ") diff --git a/tests/test_invalid_tabs.py b/tests/test_invalid_tabs.py new file mode 100644 index 000000000..9bea77c59 --- /dev/null +++ b/tests/test_invalid_tabs.py @@ -0,0 +1,19 @@ +from glob import * +import sys +import unicodedata +import re +import unittest + + +class TestInvalidTabs(unittest.TestCase): + """Test class for invalid tabulators""" + + def test_invalid_tabs(self): + ''' Test to check if invalid tabs exist. ''' + for file in glob("*.*"): + i = 0 + + with open(file, "rt") as fin: + for line in fin: + i += 1 + self.assertEqual(line.find("\t"), -1, file + " in line " + str(i) + ": not permitted tab found") diff --git a/tests/test_newline.py b/tests/test_newline.py new file mode 100644 index 000000000..04d348db0 --- /dev/null +++ b/tests/test_newline.py @@ -0,0 +1,21 @@ +import sys +import unicodedata +import re +from glob import * +import unittest + + +class TestNewLine(unittest.TestCase): + ''' Test class for mandatory new line. ''' + + def test_newline(self): + ''' Test to check last line of file must end with a new line. ''' + for file in glob("*.proto"): + with open(file, "rt") as fin: + hasNewLine = True + + for line in fin: + hasNewLine = line.endswith("\n") + + self.assertTrue(hasNewLine, file + " has no new line at the end of the file.") + \ No newline at end of file diff --git a/tests/test_non_ascii.py b/tests/test_non_ascii.py new file mode 100644 index 000000000..e143f3fde --- /dev/null +++ b/tests/test_non_ascii.py @@ -0,0 +1,23 @@ +import sys +import unicodedata +import re +from glob import * +import unittest + + +class TestNonAscii(unittest.TestCase): + """Class is checking if there is an "Umlaut" or any non ASCII characters are present.""" + + def test_non_ascii(self): + ''' Test if there are any non ASCII characters present like an "Umlaut". ''' + for file in glob("*.*"): + with open(file, "rt") as fin: + i = 0 + + for line in fin: + i += 1 + + if (sys.version_info >= (3, 0)): + self.assertEqual(line, unicodedata.normalize('NFKD', line).encode('ASCII', 'ignore').decode(), file + " in line " + str(i) + ": a none ASCII char is present") + else: + self.assertEqual(line, unicodedata.normalize('NFKD', unicode(line, 'ISO-8859-1')).encode('ASCII', 'ignore'), file + " in line " + str(i) + ": a none ASCII char is present") \ No newline at end of file From b27992621aa4426d7a4ec37623f812c67f2cacc6 Mon Sep 17 00:00:00 2001 From: Viktor Kreschenski Date: Tue, 22 Oct 2019 16:27:13 +0200 Subject: [PATCH 2/2] Test comments only in *.proto files --- tests/test_invalid_html.py | 8 ++++---- tests/test_invalid_tabs.py | 2 +- tests/test_non_ascii.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_invalid_html.py b/tests/test_invalid_html.py index ea6554b1c..3037db788 100644 --- a/tests/test_invalid_html.py +++ b/tests/test_invalid_html.py @@ -10,7 +10,7 @@ class TestInvalidHtml(unittest.TestCase): def test_invalid_slash(self): ''' Test case to check invalid slash in htmlonly sections ''' - for file in glob("*.*"): + for file in glob("*.proto"): with open(file, "rt") as fin: i = 0 htmlblock = False @@ -73,7 +73,7 @@ def test_invalid_slash(self): def test_invalid_hash(self): ''' Test case to check invalid # in htmlonly sections ''' - for file in glob("*.*"): + for file in glob("*.proto"): with open(file, "rt") as fin: i = 0 htmlblock = False @@ -135,7 +135,7 @@ def test_invalid_hash(self): def test_invalid_at(self): ''' Test case to check invalid @ in comments ''' - for file in glob("*.*"): + for file in glob("*.proto"): with open(file, "rt") as fin: i = 0 htmlblock = False @@ -197,7 +197,7 @@ def test_invalid_at(self): def test_no_endhtmlonly(self): ''' Test case to check no \endhtmlonly in comments ''' - for file in glob("*.*"): + for file in glob("*.proto"): with open(file, "rt") as fin: i = 0 htmlblock = False diff --git a/tests/test_invalid_tabs.py b/tests/test_invalid_tabs.py index 9bea77c59..207acc0c1 100644 --- a/tests/test_invalid_tabs.py +++ b/tests/test_invalid_tabs.py @@ -10,7 +10,7 @@ class TestInvalidTabs(unittest.TestCase): def test_invalid_tabs(self): ''' Test to check if invalid tabs exist. ''' - for file in glob("*.*"): + for file in glob("*.proto"): i = 0 with open(file, "rt") as fin: diff --git a/tests/test_non_ascii.py b/tests/test_non_ascii.py index e143f3fde..b6612dd27 100644 --- a/tests/test_non_ascii.py +++ b/tests/test_non_ascii.py @@ -10,7 +10,7 @@ class TestNonAscii(unittest.TestCase): def test_non_ascii(self): ''' Test if there are any non ASCII characters present like an "Umlaut". ''' - for file in glob("*.*"): + for file in glob("*.proto"): with open(file, "rt") as fin: i = 0