fprime/Autocoders/Python/schema/testSchemas.py

315 lines
11 KiB
Python

import pytest
import os
from lxml import etree
"""
To add tests, go down to the setup function.
"""
class schema_test:
"""
schema_test is a base object for conducting tests on schemas.
"""
def __init__(self, schema_name , schema_path):
"""
Starts object.
schema_name - Name to refer to schema by
schema_path - Path to retrieve RelaxNG schema
"""
self.__schema_name = schema_name
self.__schema_path = schema_path
self.__test_set_list = [] #Creates an empty list of test sets
self.__validate_and_compile()
def __validate_and_compile(self):
"""
Validates and compiles the schemas specified on instantiation.
"""
self.__validate_file(self.__schema_path , "RNG")
#Read schema file
relax_file_handler = file(self.__schema_path , 'r')
#Parse schema file
relax_parsed = etree.parse(relax_file_handler)
#Compile schema file
self.__compiled = etree.RelaxNG(relax_parsed)
#Close schema file
relax_file_handler.close()
def __validate_file(self, file_name , extension):
"""
Ensures file exists and has the proper extension.
"""
if not os.path.exists(file_name):
raise Exception("File does not exist - {}.".format(file_name))
if not file_name.upper().endswith("."+extension.upper()):
raise Exception("File does not end with proper extension {} - {}".format(extension , file_name))
return True
def __get_parsed_relaxng(self, file_path):
'''
Returns root tag assuming file path is correct
'''
#Read schema file
handler = file(file_path , 'r')
#Parse schema file
parsed = etree.parse(handler)
#Close schema file
handler.close()
return parsed
def add_test(self , test_name , xml_path , error_class , parsed_xml = None):
"""
Add test case to object.
test_name - Way of identifiying the test
xml_path - Path to xml test file
error_class - What sort of error that is going to be thrown. If error_class == None, it is assumed that the test will pass without raising exceptions.
parsed_xml - Add the etree of the XML if available.
"""
test_set = (test_name , xml_path , error_class , parsed_xml)
self.__test_set_list.append(test_set)
def parse_and_add_directory(self, list_of_root_tags , directory):
"""
Parses through directory and all subdirectories and adds tests to object test lists
list_of_root_tags - list of root tags to check for
directory - directory to look in
"""
#Check if directory exists and list_of_root_tags isn't empty
if len(list_of_root_tags) == 0:
raise Exception("{} : List of root tags empty in parse_and_add_directory!".format(self.__schema_name))
if not os.path.isdir(directory):
raise Exception("{} : Directory {} does not exist in parse_and_add_directory!".format(self.__schema_name , directory))
for subdir, dirs, files in os.walk(directory):
for file in files:
if file.upper().endswith(".XML"):
try:
new_path = os.path.join(subdir, file)
parsed = self.__get_parsed_relaxng(new_path)
root_tag = parsed.getroot().tag
if root_tag in list_of_root_tags:
self.add_test("Path Added: " + file , new_path , None , parsed_xml = parsed)
except:
pass
def run_all_tests(self):
"""
Runs all the tests consecutivley.
"""
for index in range(len(self.__test_set_list)):
self.run_test(index)
def get_test_amount(self):
"""
Returns the amount of tests in the object.
"""
return len(self.__test_set_list)
def run_test(self, index):
"""
Runs test of index
"""
if index >= len(self.__test_set_list):
raise Exception("Illegal index was accessed")
test_set = self.__test_set_list[index]
xml_parsed = test_set[3]
if not xml_parsed:
self.__validate_file(test_set[1] , "XML")
xml_file_handler = file(test_set[1] , 'r')
xml_parsed = etree.parse(xml_file_handler)
xml_file_handler.close()
if test_set[2]:
with pytest.raises(test_set[2]) as excinfo:
self.__compiled.assert_(xml_parsed)
if excinfo:
print "Schema " + self.__schema_name + " failed validating the current file."
print "\n"
print test_set[0] + " raised the wrong exception or passed, when fail was expected (Exception " + str(test_set[2]) + "."
print "File path - " + test_set[1]
print excinfo
print "\n"
raise
else:
try:
self.__compiled.assert_(xml_parsed)
except:
print "Schema " + self.__schema_name + " failed validating the current file."
print "\n"
print test_set[0] + " raised an exception but was supposed to pass."
print "File path - " + test_set[1]
print "\n"
raise
def print_header(self):
"""
Prints a header string for a schema_test object.
"""
print("\nTesting {} - {}\n".format(self.__schema_name , self.__schema_path))
def setup():
"""
Sets up and returns test_list, which is a set of schema_test objects.
"""
test_list = []
#Create schema object
topology_test = schema_test("Topology" , "ISF/topology_schema.rng")
component_test = schema_test("Component" , "ISF/component_schema.rng")
command_test = schema_test("Command" , "ISF/command_schema.rng")
parameter_test = schema_test("Parameter" , "ISF/parameters_schema.rng")
channel_test = schema_test("Channel" , "ISF/channel_schema.rng")
interface_test = schema_test("Interface" , "ISF/interface_schema.rng")
serializable_test = schema_test("Serializable" , "ISF/serializable_schema.rng")
event_test = schema_test("Event" , "ISF/event_schema.rng")
#Declare schema tests
channel_test.add_test("All working" , "sample_XML_files/channel/allWorking.xml" , None)
channel_test.add_test("High Orange string instead of number" , "sample_XML_files/channel/colorString.xml" , AssertionError)
channel_test.add_test("Missing comments" , "sample_XML_files/channel/missingComments.xml" , AssertionError)
channel_test.add_test("Missing data type" , "sample_XML_files/channel/missingDataType.xml" , AssertionError)
channel_test.add_test("Missing enum" , "sample_XML_files/channel/missingEnum.xml" , AssertionError)
command_test.add_test("All working" , "sample_XML_files/command/allWorking.xml" , None)
command_test.add_test("Command size is negative" , "sample_XML_files/command/negativeCommandSize.xml" , AssertionError)
command_test.add_test("Enum missing when type ENUM is specified" , "sample_XML_files/command/missingEnum.xml" , AssertionError)
command_test.add_test("Kind not sync nor async" , "sample_XML_files/command/kindMixed.xml" , AssertionError)
command_test.add_test("String size not defined" , "sample_XML_files/command/noStringSize.xml" , AssertionError)
component_test.add_test("Base all working" , "sample_XML_files/component/baseAllWorking.xml" , None)
component_test.add_test("Complex all working" , "sample_XML_files/component/complexAllWorking.xml" , None)
component_test.add_test("No ports" , "sample_XML_files/component/noPorts.xml" , AssertionError)
component_test.add_test("<Interface> tag instead of <internal_interface> tag" , "sample_XML_files/component/interfaceOnly.xml" , AssertionError)
event_test.add_test("All working" , "sample_XML_files/event/allWorking.xml" , None)
event_test.add_test("Event throttle negative" , "sample_XML_files/event/negativeThrottle.xml" , AssertionError)
event_test.add_test("Formot string missing" , "sample_XML_files/event/missingFormatString.xml" , AssertionError)
event_test.add_test("Severity not valid" , "sample_XML_files/event/unknownSeverity.xml" , AssertionError)
interface_test.add_test("All working" , "sample_XML_files/interface/allWorking.xml" , None)
interface_test.add_test("Multiple return tags" , "sample_XML_files/interface/multipleReturns.xml" , AssertionError)
interface_test.add_test("No ENUM in return type ENUM" , "sample_XML_files/interface/noEnumInReturn.xml" , AssertionError)
interface_test.add_test("No return tags" , "sample_XML_files/interface/noReturns.xml" , None)
interface_test.add_test("Priority attribute is a string" , "sample_XML_files/interface/stringPriority.xml" , AssertionError)
parameter_test.add_test("All working" , "sample_XML_files/parameter/allWorking.xml" , None)
parameter_test.add_test("Float in native integer type default attribute" , "sample_XML_files/parameter/floatInInt.xml" , AssertionError)
parameter_test.add_test("Negative in unsigned 8 bit default attribute" , "sample_XML_files/parameter/negativeInUnsigned.xml" , AssertionError)
parameter_test.add_test("No size attribute for string type attribute" , "sample_XML_files/parameter/noStringSize.xml" , AssertionError)
parameter_test.add_test("String in 32 bit float attribute" , "sample_XML_files/parameter/stringInFloat.xml" , AssertionError)
serializable_test.add_test("All working" , "sample_XML_files/serializable/allWorking.xml" , None)
serializable_test.add_test("Multiple members tags" , "sample_XML_files/serializable/multipleMembers.xml" , AssertionError)
serializable_test.add_test("No members tag" , "sample_XML_files/serializable/noMembers.xml" , AssertionError)
serializable_test.add_test("No name in root" , "sample_XML_files/serializable/noName.xml" , AssertionError)
serializable_test.add_test("No type in member" , "sample_XML_files/serializable/noType.xml" , AssertionError)
topology_test.add_test("All working" , "sample_XML_files/topology/allWorking.xml" , None)
topology_test.add_test("Negative connection number." , "sample_XML_files/topology/negativeConnectionNumber.xml" , AssertionError)
topology_test.add_test("No Imports" , "sample_XML_files/topology/noImports.xml" , None)
topology_test.add_test("No connections made" , "sample_XML_files/topology/noConnections.xml" , AssertionError)
topology_test.add_test("No instances" , "sample_XML_files/topology/noInstances.xml" , AssertionError)
topology_test.add_test("No types" , "sample_XML_files/topology/noTypes.xml" , AssertionError)
#Add more schema tests
channel_test.parse_and_add_directory(["telemetry"] , '../test')
command_test.parse_and_add_directory(["commands"] , '../test')
component_test.parse_and_add_directory(["component"] , '../test')
event_test.parse_and_add_directory(["events"] , '../test')
interface_test.parse_and_add_directory(["interface" , "port"] , '../test')
parameter_test.parse_and_add_directory(["parameters"] , '../test')
serializable_test.parse_and_add_directory(["serializable"] , '../test')
topology_test.parse_and_add_directory(["deployment" , "assembly"] , '../test')
#Add schemas to test_list
test_list.append(topology_test)
test_list.append(component_test)
test_list.append(command_test)
test_list.append(parameter_test)
test_list.append(channel_test)
test_list.append(interface_test)
test_list.append(serializable_test)
test_list.append(event_test)
return test_list
def get_test_list():
test_list = setup()
out = []
for test_obj in test_list:
tl = test_obj.get_test_amount()
for ti in range(tl):
out.append((test_obj.run_test , ti))
return out
@pytest.fixture(scope="module", params=get_test_list())
def current_test(request):
return request.param
def tests_all(current_test):
func = current_test[0]
index = current_test[1]
func(index)
if __name__ == "__main__":
test_list = setup()
for test in test_list:
test.print_header()
test.run_all_tests()