diff --git a/scripts/test_klippy.py b/scripts/test_klippy.py new file mode 100644 index 00000000..f70095b5 --- /dev/null +++ b/scripts/test_klippy.py @@ -0,0 +1,138 @@ +# Regression test helper script +# +# Copyright (C) 2018 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU GPLv3 license. +import sys, os, optparse, logging, subprocess + + +###################################################################### +# Test cases +###################################################################### + +class error(Exception): + pass + +class TestCase: + def __init__(self, fname, dictdir, tempdir): + self.fname = fname + self.dictdir = dictdir + self.tempdir = tempdir + def relpath(self, fname, rel='test'): + if rel == 'dict': + reldir = self.dictdir + elif rel == 'temp': + reldir = self.tempdir + else: + reldir = os.path.dirname(self.fname) + return os.path.join(reldir, fname) + def parse_test(self): + # Parse file into test cases + config_fname = gcode_fname = dict_fname = None + should_fail = multi_tests = False + gcode = [] + f = open(self.fname, 'rb') + for line in f: + cpos = line.find('#') + if cpos >= 0: + line = line[:cpos] + parts = line.strip().split() + if not parts: + continue + if parts[0] == "CONFIG": + if config_fname is not None: + # Multiple tests in same file + if not multi_tests: + multi_tests = True + self.launch_test(config_fname, dict_fname, + gcode_fname, gcode, should_fail) + config_fname = self.relpath(parts[1]) + if multi_tests: + self.launch_test(config_fname, dict_fname, + gcode_fname, gcode, should_fail) + elif parts[0] == "DICTIONARY": + dict_fname = self.relpath(parts[1], 'dict') + elif parts[0] == "GCODE": + gcode_fname = self.relpath(parts[1]) + elif parts[0] == "SHOULD_FAIL": + should_fail = True + else: + gcode.append(line) + f.close() + if not multi_tests: + self.launch_test(config_fname, dict_fname, + gcode_fname, gcode, should_fail) + def launch_test(self, config_fname, dict_fname, gcode_fname, gcode, + should_fail): + gcode_is_temp = False + if gcode_fname is None: + gcode_fname = self.relpath("_test_.gcode", 'temp') + gcode_is_temp = True + f = open(gcode_fname, 'wb') + f.write('\n'.join(gcode)) + f.close() + elif gcode: + raise error("Can't specify both a gcode file and gcode commands") + if config_fname is None: + raise error("config file not specified") + if dict_fname is None: + raise error("data dictionary file not specified") + # Call klippy + sys.stderr.write("\n Starting %s (%s)\n" % ( + self.fname, os.path.basename(config_fname))) + args = [sys.executable, './klippy/klippy.py', config_fname, + '-i', gcode_fname, '-o', '/dev/null', + '-d', dict_fname + ] + res = subprocess.call(args) + if should_fail: + if not res: + raise error("Test failed to raise and error") + else: + if res: + raise error("Error during test") + # Do cleanup + if gcode_is_temp: + os.unlink(gcode_fname) + def run(self): + try: + self.parse_test() + except error as e: + return str(e) + except Exception: + logging.exception("Unhandled exception during test run") + return "internal error" + return "success" + + +###################################################################### +# Startup +###################################################################### + +def main(): + # Parse args + usage = "%prog [options] " + opts = optparse.OptionParser(usage) + opts.add_option("-d", "--dictdir", dest="dictdir", default=".", + help="directory for dictionary files") + opts.add_option("-t", "--tempdir", dest="tempdir", default=".", + help="directory for temporary files") + options, args = opts.parse_args() + if len(args) < 1: + opts.error("Incorrect number of arguments") + logging.basicConfig(level=logging.DEBUG) + dictdir = options.dictdir + tempdir = options.tempdir + + # Run each test + for fname in args: + tc = TestCase(fname, dictdir, tempdir) + res = tc.run() + if res != 'success': + sys.stderr.write("\n\nTest case %s FAILED (%s)!\n\n" % (fname, res)) + sys.exit(-1) + + sys.stderr.write("\n All %d test cases passed\n" % (len(args),)) + +if __name__ == '__main__': + main() diff --git a/scripts/travis-build.sh b/scripts/travis-build.sh index 1fe45f1e..f65c50f6 100755 --- a/scripts/travis-build.sh +++ b/scripts/travis-build.sh @@ -39,6 +39,5 @@ mkdir -p ${HOSTDIR} echo "travis_fold:start:klippy" echo "=============== Test invoke klippy" -$PYTHON klippy/klippy.py config/example.cfg -i /dev/null -o ${HOSTDIR}/output -v -d ${DICTDIR}/atmega2560-16mhz.dict -$PYTHON klippy/parsedump.py ${DICTDIR}/atmega2560-16mhz.dict ${HOSTDIR}/output > ${HOSTDIR}/output-parsed +$PYTHON scripts/test_klippy.py -d ${DICTDIR} test/klippy/*.test echo "travis_fold:end:klippy" diff --git a/test/klippy/cartesian.test b/test/klippy/cartesian.test new file mode 100644 index 00000000..42b00ca7 --- /dev/null +++ b/test/klippy/cartesian.test @@ -0,0 +1,4 @@ +# Test case for basic cartesian movement +CONFIG ../../config/example.cfg +DICTIONARY atmega2560-16mhz.dict +GCODE move.gcode diff --git a/test/klippy/corexy.test b/test/klippy/corexy.test new file mode 100644 index 00000000..6e43bdf8 --- /dev/null +++ b/test/klippy/corexy.test @@ -0,0 +1,4 @@ +# Test case for basic corexy movement +CONFIG ../../config/example-corexy.cfg +DICTIONARY atmega2560-16mhz.dict +GCODE move.gcode diff --git a/test/klippy/delta.test b/test/klippy/delta.test new file mode 100644 index 00000000..0cd132b1 --- /dev/null +++ b/test/klippy/delta.test @@ -0,0 +1,33 @@ +# Test case for basic movement on delta printers +CONFIG ../../config/example-delta.cfg +DICTIONARY atmega2560-16mhz.dict + +# Start by homing the printer. Also tests Z moves. +G28 + +# Perform an XY+Z move with infintesimal XY component +G1 x0 y0 z15 + +# Perform an XY move along Y axis (aligned with rear tower) +G1 x0 y5 z15 + +# Perform an XY+Z move along Y axis +G1 x0 y-5 z10 + +# Perform a Z move +G1 x0 y-5 z15 + +# Perform an XY move across all three towers +G1 x2 y2 z10 + +# Perform an XY+Z move with tiny Z movement +G1 x2 y-10 z10.1 + +# Move to far away position +G1 x140 y0 + +# Move to extreme position +G1 x145 y0 + +# Move to another extreme position +G1 x145 y5 diff --git a/test/klippy/move.gcode b/test/klippy/move.gcode new file mode 100644 index 00000000..30e2a02c --- /dev/null +++ b/test/klippy/move.gcode @@ -0,0 +1,22 @@ +; Simple movement tests + +; Start by homing the printer. +G28 +G1 F6000 + +; Z / X / Y moves +G1 Z1 +G1 X1 +G1 Y1 + +; diagonal moves +G1 X0 Y0 +G1 X1 Z2 +G1 X0 Y1 Z1 + +; extrude only moves +G1 E1 +G1 E0 + +; regular extrude move +G1 X0 Y0 E.01 diff --git a/test/klippy/out_of_bounds.test b/test/klippy/out_of_bounds.test new file mode 100644 index 00000000..5375ea7e --- /dev/null +++ b/test/klippy/out_of_bounds.test @@ -0,0 +1,8 @@ +# Test that basic bounds checks work +CONFIG ../../config/example.cfg +DICTIONARY atmega2560-16mhz.dict +SHOULD_FAIL + +# Home the printer, and then attempt to move to an obviously bad location +G28 +G1 Y9999 diff --git a/test/klippy/printers.test b/test/klippy/printers.test new file mode 100644 index 00000000..0f315ac3 --- /dev/null +++ b/test/klippy/printers.test @@ -0,0 +1,40 @@ +# Basic sanity checks on the example printer config files +GCODE move.gcode + +# Printers using the atmega2560 +DICTIONARY atmega2560-16mhz.dict +CONFIG ../../config/generic-einsy-rambo.cfg +CONFIG ../../config/generic-mini-rambo.cfg +CONFIG ../../config/generic-rambo.cfg +CONFIG ../../config/generic-ramps.cfg +CONFIG ../../config/generic-rumba.cfg +CONFIG ../../config/printer-anycubic-i3-mega-2017.cfg +CONFIG ../../config/printer-anycubic-kossel-2016.cfg +CONFIG ../../config/printer-creality-cr10s-2017.cfg +CONFIG ../../config/printer-lulzbot-taz6-2017.cfg +CONFIG ../../config/printer-makergear-m2-2012.cfg +CONFIG ../../config/printer-seemecnc-rostock-max-v2-2015.cfg +CONFIG ../../config/printer-wanhao-duplicator-i3-plus-2017.cfg + +# Printers using the atmega1284p +DICTIONARY atmega1284p.dict +CONFIG ../../config/generic-melzi.cfg +CONFIG ../../config/printer-anet-a8-2017.cfg +CONFIG ../../config/printer-anet-e10-2018.cfg +CONFIG ../../config/printer-creality-cr10-2017.cfg +CONFIG ../../config/printer-creality-cr10mini-2017.cfg +CONFIG ../../config/printer-creality-ender3-2018.cfg +CONFIG ../../config/printer-tronxy-x5s-2018.cfg +CONFIG ../../config/printer-wanhao-duplicator-i3-v2.1-2017.cfg + +# Printers using the at90usb1286 +DICTIONARY at90usb1286.dict +CONFIG ../../config/generic-printrboard.cfg + +# Printers using the sam3x8e +DICTIONARY sam3x8e.dict +CONFIG ../../config/generic-radds.cfg + +# Printers using the lpc176x +DICTIONARY lpc176x.dict +CONFIG ../../config/generic-smoothieboard.cfg