138 lines
5.6 KiB
Python
Executable File
138 lines
5.6 KiB
Python
Executable File
#!/usr/bin/python3
|
|
# Lexesis - A language agnostic lexical analyser generator
|
|
# Copyright © 2016-2017 Thomas Avé, Robin Jadoul
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining
|
|
# a copy of this software and associated documentation files (the "Software"),
|
|
# to deal in the Software without restriction, including without limitation
|
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
# and/or sell copies of the Software, and to permit persons to whom the
|
|
# Software is furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included
|
|
# in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
import unittest, subprocess, filecmp, argparse, os.path, os, shutil
|
|
|
|
REFERENCE_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "tests")
|
|
|
|
REGEXES_DATA = [ # (regexes, should be accepted)
|
|
([r"[a-zA-Z0-9]*"], True),
|
|
([r"[a-dD-F9-0]*"], True),
|
|
([r"a", r"a|b"], True),
|
|
([r"a|b", r"a"], True),
|
|
|
|
([r"[[]", r"[]]", r"[]-[]", r"[][-]"], True),
|
|
([r"[^^]", r"[^]-[]", r"[^][-]"], True),
|
|
([r"[ ^]", r"[ ^-X ]", r"[]-^]"], True),
|
|
([r"[^-X]", r"[^][]"], True),
|
|
([r"[-]", r"[]-]"], True),
|
|
([r"[^-]", "[^]]", r"[^-]", r"[^-^]"], True),
|
|
([r"[^--]", r"[--]"], True),
|
|
([r"[^]"], False),
|
|
([r"[]"], False),
|
|
|
|
([r"\r", r"\n", r"\f", r"\v", r"\a", r"\t", r"\b", r"\s", r" "], True),
|
|
([r"\\", r"\*", r"\+", r"\|", r"\(", r"\)", r"\[", r"\[", r"\?", r"\."], True),
|
|
|
|
([r".", r"a*", r"a+", r"a?", r"(ab)*", r"a|b"], True),
|
|
([r"(a|b)*", r"(a|b)+", r"a**", r"a??", r"(ab)?"], True),
|
|
([r"("], False),
|
|
([r")"], False),
|
|
([r"["], False),
|
|
([r"]"], False),
|
|
([r"(test(a)qwerty"], False),
|
|
([r"test(a)qwerty)"], False),
|
|
([r"ab|"], False),
|
|
([r"|ab"], False),
|
|
([r"ab(c|)de"], False),
|
|
([r"ab(|c)de"], False),
|
|
|
|
([r""], False),
|
|
([r"()"], False),
|
|
([r"(?)"], False),
|
|
([r"((ab)c()de)"], False),
|
|
([r"|"], False),
|
|
([r"(|)"], False),
|
|
([r"?"], False),
|
|
([r"*"], False),
|
|
([r"(*)"], False),
|
|
([r"+"], False),
|
|
([r"(+)"], False),
|
|
]
|
|
|
|
EXAMPLE_TESTS = { #Mapping from test name to executable and number of available test input files
|
|
"keywords" : ("examples/keywords/keywords", 2),
|
|
"highlighter": ("examples/SyntaxHighlighter/highlighter", 8),
|
|
"leopard": ("examples/leopard/leopard", 8),
|
|
}
|
|
|
|
def make_pipeline_test(regexes, should_accept, idx):
|
|
def test(self):
|
|
p = subprocess.Popen([os.path.join(args.builddir, "src", "Lexesis-test"), "test_%s" % idx, data_dir], stdin=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
|
p.communicate(bytes("\n".join(regexes) + "\n", "utf-8"))
|
|
|
|
if should_accept:
|
|
self.assertEqual(0, p.returncode)
|
|
|
|
self.assertTrue(filecmp.cmp(os.path.join(REFERENCE_DIR, "test_%s.re" % idx), os.path.join(data_dir, "test_%s.re" % idx)), "The regex for testcase %s is incorrect" % idx)
|
|
self.assertTrue(filecmp.cmp(os.path.join(REFERENCE_DIR, "test_%s.enfa" % idx), os.path.join(data_dir, "test_%s.enfa" % idx)), "The eNFA for testcase %s is incorrect" % idx)
|
|
self.assertTrue(filecmp.cmp(os.path.join(REFERENCE_DIR, "test_%s.mssc" % idx), os.path.join(data_dir, "test_%s.mssc" % idx)), "The mssc'd DFA for testcase %s is incorrect" % idx)
|
|
self.assertTrue(filecmp.cmp(os.path.join(REFERENCE_DIR, "test_%s.min" % idx), os.path.join(data_dir, "test_%s.min" % idx)), "The minimized DFA for testcase %s is incorrect" % idx)
|
|
else:
|
|
self.assertNotEqual(0, p.returncode)
|
|
|
|
return test
|
|
|
|
def make_functional_test(name, prog, idx):
|
|
def test(self):
|
|
inpath = os.path.join(REFERENCE_DIR, "%s_%s.in" % (name, idx))
|
|
infile = open(inpath)
|
|
outpath = os.path.join(data_dir, "%s_%s.out" % (name, idx))
|
|
outfile = open(outpath, "w")
|
|
checkpath = os.path.join(REFERENCE_DIR, "%s_%s.exp" % (name, idx))
|
|
|
|
p = subprocess.Popen([prog], stdin=infile, stdout=outfile)
|
|
p.communicate()
|
|
|
|
infile.close()
|
|
outfile.close()
|
|
|
|
self.assertTrue(filecmp.cmp(checkpath, outpath), "Testcase %s for example program %s failed" % (idx, name))
|
|
|
|
return test
|
|
|
|
class Tests(unittest.TestCase):
|
|
pass
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--builddir", metavar="builddir", default=os.path.join(os.path.abspath(os.path.dirname(__file__)), "build"), required=False)
|
|
args = parser.parse_args()
|
|
|
|
data_dir = os.path.join(args.builddir, "test_data")
|
|
try:
|
|
shutil.rmtree(data_dir)
|
|
except Exception as err:
|
|
pass
|
|
os.mkdir(data_dir)
|
|
|
|
for i, (regexes, should_accept) in enumerate(REGEXES_DATA):
|
|
t = make_pipeline_test(regexes, should_accept, i)
|
|
setattr(Tests, "test_%s" % i, t)
|
|
|
|
for test, (prog, num) in EXAMPLE_TESTS.items():
|
|
for i in range(num):
|
|
t = make_functional_test(test, os.path.join(args.builddir, prog), i)
|
|
setattr(Tests, "test_%s_%s" % (test, i), t)
|
|
|
|
unittest.main()
|