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 "$f2" ; 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 cf1
=${tmpd}/`basename $f1`
350 cf2
=${tmpd}/`basename $f2`
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
377 normalize_xy
"$f1" "$cf1"
378 normalize_xy
"$f2" "$cf2"
379 run_diff
"$cf1" "$cf2" || test_failed
=yes
382 ##########################################################################
384 # GCODE comparison routines
387 # used to remove things like creation date from gcode files
392 d == 1 {gsub(/ .* /, "Creation Date and Time"); d = 0;}
393 /^\(Created by G-code exporter\)/ {d=1}
401 compare_check
"compare_gcode" "$f1" "$f2" ||
return 1
403 # For comparison, we need to ignore changes in the Date and Author lines.
404 cf1
=${tmpd}/`basename $f1`
405 cf2
=${tmpd}/`basename $f2`
407 normalize_gcode
$f1 $cf1
408 normalize_gcode
$f2 $cf2
409 run_diff
"$cf1" "$cf2" || test_failed
=yes
412 ##########################################################################
414 # RS274-X and Excellon comparison
420 compare_check
"compare_rs274x" "$f1" "$f2" ||
return 1
422 # use gerbv to export our reference RS274-X file and our generated
423 # RS274-X file to png. Then we'll use ImageMagick to see
424 # if there are any differences in the resulting files
428 png1
=${pngdir}/${nb}-ref.png
429 png2
=${pngdir}/${nb}-out.png
431 debug
"${GERBV} ${GERBV_DEFAULT_FLAGS} --output=${png1} ${f1}"
432 ${GERBV} ${GERBV_DEFAULT_FLAGS} --output=${png1} ${f1}
434 debug
"${GERBV} ${GERBV_DEFAULT_FLAGS} --output=${png2} ${f2}"
435 ${GERBV} ${GERBV_DEFAULT_FLAGS} --output=${png2} ${f2}
437 compare_image
${png1} ${png2}
445 ##########################################################################
447 # GIF/JPEG/PNG comparison routines
453 compare_check
"compare_image" "$f1" "$f2" ||
return 1
455 # now see if the image files are the same
456 debug
"${IM_COMPARE} -metric MAE ${f1} ${f2} null:"
457 same
=`${IM_COMPARE} -metric MAE ${f1} ${f2} null: 2>&1 | \
458 ${AWK} '{if($1 == 0){print "yes"} else {print "no"}}'`
459 debug
"compare_image(): same = $same"
461 if test "$same" != yes ; then
463 echo "FAILED: See ${errdir}"
465 ${IM_COMPARE} ${f1} ${f2} ${errdir}/compare.png
466 ${IM_COMPOSITE} ${f1} ${f2} -compose difference ${errdir}/composite.png
467 ${IM_CONVERT} ${f1} ${f2} -compose difference -composite -colorspace gray ${errdir}/gray.png
468 cat > ${errdir}/animate.sh
<< EOF
470 ${IM_CONVERT} -label "%f" ${f1} ${f2} miff:- | \
471 ${IM_MONTAGE} - -geometry +0+0 -tile 1x1 miff:- | \
472 ${IM_ANIMATE} -delay 0.5 -loop 0 -
474 chmod a
+x
${errdir}/animate.sh
478 ##########################################################################
480 # The main program loop
483 for t
in $all_tests ; do
489 ######################################################################
491 # extract the details for the test
494 pcb_flags
="${PCB_DEFAULT_FLAGS}"
496 rundir
="${OUTDIR}/${t}"
497 refdir
="${REFDIR}/${t}"
498 errdir
=${rundir}/mismatch
500 # test_name | layout file(s) | [export hid name] | [optional arguments to pcb] | [mismatch]
502 name
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {print $1}'`
503 files
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {print $2}'`
504 hid
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {gsub(/[ \t]*/, ""); print $3}'`
505 args
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {print $4}'`
506 mismatch
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {if($5 == "mismatch"){print "yes"}else{print "no"}}'`
507 out_files
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {print $6}'`
509 if test "X${name}" = "X" ; then
510 echo "ERROR: Specified test ${t} does not appear to exist"
511 skip
=`expr $skip + 1`
515 if test "X${args}" != "X" ; then
519 if test "X${hid}" = "Xgerber" ; then
520 pcb_flags
="--fab-author Fab_Author ${pcb_flags}"
523 ######################################################################
525 # Set up the run directory
528 test -d ${rundir} && rm -fr ${rundir}
530 if test $?
-ne 0 ; then
531 echo "$0: Could not create run directory ${rundir}"
532 skip
=`expr $skip + 1`
537 ######################################################################
539 # check to see if the files we need exist and copy them to the run
546 if test ! -f ${INDIR}/${f} ; then
547 echo "ERROR: File $f specified as part of the $t test does not exist"
550 path_files
="${path_files} ${INDIR}/${f}"
551 cp "${INDIR}/${f}" "${rundir}"
555 if test "$missing_files" = "yes" ; then
556 echo "${t} had missing input files. Skipping test"
557 skip
=`expr $skip + 1`
561 ######################################################################
566 echo "${PCB} -x ${hid} ${pcb_flags} ${path_files}"
567 (cd ${rundir} && ${PCB} -x ${hid} ${pcb_flags} ${files})
570 if test $pcb_rc -ne 0 ; then
571 echo "${PCB} returned ${pcb_rc}. This is a failure."
572 fail
=`expr $fail + 1`
576 # and clean up the input files we'd copied over
581 ######################################################################
586 if test "X$regen" = "Xyes" ; then
587 echo "Regenerated ${t}"
589 # compare the result to our reference file
592 for f
in $out_files ; do
593 debug
"processing $f"
594 # break apart type:fn into the type and file name
595 type=`echo $f | sed 's;:.*;;g'`
596 fn
=`echo $f | sed 's;.*:;;g'`
601 compare_bom
${refdir}/${fn} ${rundir}/${fn}
605 compare_xy
${refdir}/${fn} ${rundir}/${fn}
610 compare_gcode
${refdir}/${fn} ${rundir}/${fn}
615 compare_cnc
${refdir}/${fn} ${rundir}/${fn}
619 compare_rs274x
${refdir}/${fn} ${rundir}/${fn}
624 compare_image
${refdir}/${fn} ${rundir}/${fn}
628 compare_image
${refdir}/${fn} ${rundir}/${fn}
632 compare_image
${refdir}/${fn} ${rundir}/${fn}
637 echo "internal error: $type is not a known file type"
645 if test $test_failed = yes ; then
647 fail
=`expr $fail + 1`
648 elif test $test_skipped = yes ; then
650 skip
=`expr $skip + 1`
653 pass
=`expr $pass + 1`
661 echo "Passed $pass, failed $fail, skipped $skip out of $tot tests."
664 if test $pass -ne $tot ; then