3 # $Id: run_tests.sh,v 1.8 2009/02/17 00:42:31 danmc Exp $
5 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2009, 2010 Dan McMahill
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of version 2 of the GNU General Public License as
9 # published by the Free Software Foundation
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
19 # All rights reserved.
21 # This code was derived from code written by Dan McMahill as part of the
22 # latex-mk testsuite. The original code was covered by a BSD license
23 # but the copyright holder (Dan McMahill) has re-released the code under
26 magic_test_skip
=${PCB_MAGIC_TEST_SKIP:-no}
28 if test "x${magic_test_skip}" = "xyes" ; then
31 The environment variable PCB_MAGIC_TEST_SKIP is set to yes.
32 This causes the testsuite to skip all tests and report no errors.
33 This is used for certain debugging *only*. The primary use is to
34 allow testing of the 'distcheck' target without including the effects
35 of the testsuite. The reason this is useful is that due to minor differences
36 in library versions and perhaps roundoff in different CPU's, the testsuite
37 may falsely report failures on some systems. These reported failures
38 prevent using 'distcheck' for verifying the rest of the build system.
39 These comments only apply to the tests which try to compare image files
52 $0 -- Run pcb regression tests
55 $0 [-d | --debug] [-g | --golden dir] [-r|--regen] [testname1 [testname2[ ...]]]
59 The $0 script is used both for running the pcb regression testsuite
60 as well as maintaining it. The way the test suite works is a number
61 of different layouts are exported using the various export HID's.
63 The resulting output files are examined in various ways to make sure
64 they are correct. The exact details of how they are compared varies.
65 For example, the PNG outputs are compared using tools from the ImageMagick
66 suite while the ASCII centroid and bill of materials files are normalized
67 with awk and then compared with the standard diff utility. The normalization
68 removes things like a comment line which contains the creation date.
72 -d | --debug Enables extra debug output
74 -g | --golden <dir> : Specifies that <dir> should be used for the
79 - The GUI interface is not checked via the regression testsuite.
81 - Currently actions are also not exercised
87 echo "----------------------------------------------------------------------"
90 ##########################################################################
97 if test $do_debug = yes ; then
104 ##########################################################################
106 # command line processing
127 # set the 'golden' directory.
133 # regenerate the 'golden' output files. Use this with caution.
134 # In particular, all differences should be noted and understood.
140 echo "unknown option: $1"
151 ##########################################################################
153 # set up various tools
161 top_srcdir
=${top_srcdir:-.}
163 # The pcb wrapper script we want to test
165 # by default we will be running it from $(top_builddir)/tests/outputs/testname
166 # so we need to look 3 levels up and then down to src
167 PCB
=${PCB:-../../../src/pcbtest.sh}
169 # The gerbv executible
170 GERBV
=${GERBV:-gerbv}
171 GERBV_DEFAULT_FLAGS
=${GERBV_DEFAULT_FLAGS:---export=png --window=640x480}
173 # various ImageMagick tools
174 IM_ANIMATE
=${IM_ANIMATE:-animate}
175 IM_COMPARE
=${IM_COMPARE:-compare}
176 IM_COMPOSITE
=${IM_COMPOSITE:-composite}
177 IM_CONVERT
=${IM_CONVERT:-convert}
178 IM_DISPLAY
=${IM_DISPLAY:-display}
179 IM_MONTAGE
=${IM_MONTAGE:-montage}
182 INDIR
=${INDIR:-${srcdir}/inputs}
184 REFDIR
=${REFDIR:-${srcdir}/golden}
189 # the list of tests to run
190 TESTLIST
=${srcdir}/tests.list
192 if test "X$regen" = "Xyes" ; then
196 # create output directory
197 if test ! -d $OUTDIR ; then
199 if test $?
-ne 0 ; then
200 echo "Failed to create output directory ${OUTDIR}"
205 if test -z "$all_tests" ; then
206 if test ! -f ${TESTLIST} ; then
207 echo "ERROR: ($0) Test list $TESTLIST does not exist"
210 all_tests
=`${AWK} 'BEGIN{FS="|"} /^#/{next} {print $1}' ${TESTLIST} | sed 's; ;;g'`
213 if test -z "${all_tests}" ; then
214 echo "$0: No tests specified"
219 # fail/pass/total counts
225 ##########################################################################
234 top_srcdir ${top_srcdir}
246 GERBV_DEFAULT_FLAGS ${GERBV_DEFAULT_FLAGS}
250 IM_ANIMATE ${IM_ANIMATE}
251 IM_COMPARE ${IM_COMPARE}
252 IM_COMPOSITE ${IM_COMPOSITE}
253 IM_CONVERT ${IM_CONVERT}
254 IM_DISPLAY ${IM_DISPLAY}
255 IM_MONTAGE ${IM_MONTAGE}
259 tmpd
=/tmp
/pcb_tests.$$
260 mkdir
-p -m 0700 $tmpd
262 if test $rc -ne 0 ; then
263 echo "$0: ERROR: could not create $tmpd"
267 ##########################################################################
269 # utility functions for comparison
273 # compare_check "test_name" "file1" "file2"
275 # Makes sure that file1 and file2 both exist. If not, mark the current
276 # test as skipped and give an error message
283 if test ! -f "$f1" ; then
284 echo "$0: ${fn}(): $f1 does not exist"
289 if test ! -f "$f2" ; then
290 echo "$0: ${fn}(): $f2 does not exist"
297 ##########################################################################
299 # ASCII file comparison routines
303 # run_diff "file1" "file2"
309 if test $?
-ne 0 ; then return 1 ; fi
313 ##########################################################################
315 # BOM comparison routines
318 # used to remove things like creation date from BOM files
323 /^# Date:/ {print "# Date: today"; next}
324 /^# Author:/ {print "# Author: PCB"; next}
329 # top level function to compare BOM output
333 compare_check
"compare_bom" "$f1" "$f2" ||
return 1
335 # an example BOM file is:
338 # # PcbBOM Version 1.0
339 # # Date: Wed Jun 17 14:41:43 2009 UTC
340 # # Author: Dan McMahill
341 # # Title: Basic BOM/XY Test - PCB BOM
342 # # Quantity, Description, Value, RefDes
343 # # --------------------------------------------
344 # 8,"Standard SMT resistor, capacitor etc","RESC3216N",R90_TOP R180_TOP R270_TOP R0_TOP R270_BOT R180_BOT R90_BOT R0_BOT
345 # 8,"Dual in-line package, narrow (300 mil)","DIP8",UDIP90_TOP UDIP180_TOP UDIP270_TOP UDIP0_TOP UDIP270_BOT UDIP180_BOT UDIP90_BOT UDIP0_BOT
346 # 8,"Small outline package, narrow (150mil)","SO8",USO90_TOP USO180_TOP USO270_TOP USO0_TOP USO270_BOT USO180_BOT USO90_BOT USO0_BOT
348 # For comparison, we need to ignore changes in the Date and Author lines.
349 local cf1
=${tmpd}/`basename $f1`-ref
350 local cf2
=${tmpd}/`basename $f2`-out
352 normalize_bom
$f1 $cf1
353 normalize_bom
$f2 $cf2
354 run_diff
$cf1 $cf2 || test_failed
=yes
357 ##########################################################################
359 # X-Y (centroid) comparison routines
362 # used to remove things like creation date from BOM files
367 /^# Date:/ {print "# Date: today"; next}
368 /^# Author:/ {print "# Author: PCB"; next}
376 compare_check
"compare_xy" "$f1" "$f2" ||
return 1
378 local cf1
=${tmpd}/`basename $f1`-ref
379 local cf2
=${tmpd}/`basename $f2`-out
380 normalize_xy
"$f1" "$cf1"
381 normalize_xy
"$f2" "$cf2"
382 run_diff
"$cf1" "$cf2" || test_failed
=yes
385 ##########################################################################
387 # GCODE comparison routines
390 # used to remove things like creation date from gcode files
394 # matches string such as '( Tue Mar 9 17:45:43 2010 )'
395 $AWK --posix '!/^\( *[A-Z][a-z]{2} [A-Z][a-z]{2} [0123 ][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4} *\)$/' \
402 compare_check
"compare_gcode" "$f1" "$f2" ||
return 1
404 # For comparison, we need to ignore changes in the Date and Author lines.
405 local cf1
=${tmpd}/`basename $f1`-ref
406 local cf2
=${tmpd}/`basename $f2`-out
408 normalize_gcode
$f1 $cf1
409 normalize_gcode
$f2 $cf2
411 run_diff
"$cf1" "$cf2" || test_failed
=yes
414 ##########################################################################
416 # RS274-X and Excellon comparison
422 compare_check
"compare_rs274x" "$f1" "$f2" ||
return 1
424 # use gerbv to export our reference RS274-X file and our generated
425 # RS274-X file to png. Then we'll use ImageMagick to see
426 # if there are any differences in the resulting files
430 png1
=${pngdir}/${nb}-ref.png
431 png2
=${pngdir}/${nb}-out.png
433 debug
"${GERBV} ${GERBV_DEFAULT_FLAGS} --output=${png1} ${f1}"
434 ${GERBV} ${GERBV_DEFAULT_FLAGS} --output=${png1} ${f1}
436 debug
"${GERBV} ${GERBV_DEFAULT_FLAGS} --output=${png2} ${f2}"
437 ${GERBV} ${GERBV_DEFAULT_FLAGS} --output=${png2} ${f2}
439 compare_image
${png1} ${png2}
447 ##########################################################################
449 # GIF/JPEG/PNG comparison routines
455 compare_check
"compare_image" "$f1" "$f2" ||
return 1
457 # now see if the image files are the same
458 debug
"${IM_COMPARE} -metric MAE ${f1} ${f2} null:"
459 same
=`${IM_COMPARE} -metric MAE ${f1} ${f2} null: 2>&1 | \
460 ${AWK} '{if($1 == 0){print "yes"} else {print "no"}}'`
461 debug
"compare_image(): same = $same"
463 if test "$same" != yes ; then
465 echo "FAILED: See ${errdir}"
467 ${IM_COMPARE} ${f1} ${f2} ${errdir}/compare.png
468 ${IM_COMPOSITE} ${f1} ${f2} -compose difference ${errdir}/composite.png
469 ${IM_CONVERT} ${f1} ${f2} -compose difference -composite -colorspace gray ${errdir}/gray.png
470 cat > ${errdir}/animate.sh
<< EOF
472 ${IM_CONVERT} -label "%f" ${f1} ${f2} miff:- | \
473 ${IM_MONTAGE} - -geometry +0+0 -tile 1x1 miff:- | \
474 ${IM_ANIMATE} -delay 0.5 -loop 0 -
476 chmod a
+x
${errdir}/animate.sh
480 ##########################################################################
482 # The main program loop
485 for t
in $all_tests ; do
491 ######################################################################
493 # extract the details for the test
496 pcb_flags
="${PCB_DEFAULT_FLAGS}"
498 rundir
="${OUTDIR}/${t}"
499 refdir
="${REFDIR}/${t}"
500 errdir
=${rundir}/mismatch
502 # test_name | layout file(s) | [export hid name] | [optional arguments to pcb] | [mismatch]
504 name
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {print $1}'`
505 files
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {print $2}'`
506 hid
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {gsub(/[ \t]*/, ""); print $3}'`
507 args
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {print $4}'`
508 mismatch
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {if($5 == "mismatch"){print "yes"}else{print "no"}}'`
509 out_files
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {print $6}'`
511 if test "X${name}" = "X" ; then
512 echo "ERROR: Specified test ${t} does not appear to exist"
513 skip
=`expr $skip + 1`
517 if test "X${args}" != "X" ; then
521 if test "X${hid}" = "Xgerber" ; then
522 pcb_flags
="--fab-author Fab_Author ${pcb_flags}"
525 ######################################################################
527 # Set up the run directory
530 test -d ${rundir} && rm -fr ${rundir}
532 if test $?
-ne 0 ; then
533 echo "$0: Could not create run directory ${rundir}"
534 skip
=`expr $skip + 1`
539 ######################################################################
541 # check to see if the files we need exist and copy them to the run
548 if test ! -f ${INDIR}/${f} ; then
549 echo "ERROR: File $f specified as part of the $t test does not exist"
552 path_files
="${path_files} ${INDIR}/${f}"
553 cp "${INDIR}/${f}" "${rundir}"
557 if test "$missing_files" = "yes" ; then
558 echo "${t} had missing input files. Skipping test"
559 skip
=`expr $skip + 1`
563 ######################################################################
568 echo "${PCB} -x ${hid} ${pcb_flags} ${path_files}"
569 (cd ${rundir} && ${PCB} -x ${hid} ${pcb_flags} ${files})
572 if test $pcb_rc -ne 0 ; then
573 echo "${PCB} returned ${pcb_rc}. This is a failure."
574 fail
=`expr $fail + 1`
578 # and clean up the input files we'd copied over
583 ######################################################################
588 if test "X$regen" = "Xyes" ; then
589 echo "Regenerated ${t}"
591 # compare the result to our reference file
594 for f
in $out_files ; do
595 debug
"processing $f"
596 # break apart type:fn into the type and file name
597 type=`echo $f | sed 's;:.*;;g'`
598 fn
=`echo $f | sed 's;.*:;;g'`
603 compare_bom
${refdir}/${fn} ${rundir}/${fn}
607 compare_xy
${refdir}/${fn} ${rundir}/${fn}
612 compare_gcode
${refdir}/${fn} ${rundir}/${fn}
617 compare_cnc
${refdir}/${fn} ${rundir}/${fn}
621 compare_rs274x
${refdir}/${fn} ${rundir}/${fn}
626 compare_image
${refdir}/${fn} ${rundir}/${fn}
630 compare_image
${refdir}/${fn} ${rundir}/${fn}
634 compare_image
${refdir}/${fn} ${rundir}/${fn}
639 echo "internal error: $type is not a known file type"
647 if test $test_failed = yes ; then
649 fail
=`expr $fail + 1`
650 elif test $test_skipped = yes ; then
652 skip
=`expr $skip + 1`
655 pass
=`expr $pass + 1`
663 echo "Passed $pass, failed $fail, skipped $skip out of $tot tests."
666 if test $pass -ne $tot ; then