3 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2009, 2010 Dan McMahill
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of version 2 of the GNU General Public License as
7 # published by the Free Software Foundation
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
17 # All rights reserved.
19 # This code was derived from code written by Dan McMahill as part of the
20 # latex-mk testsuite. The original code was covered by a BSD license
21 # but the copyright holder (Dan McMahill) has re-released the code under
24 magic_test_skip
=${PCB_MAGIC_TEST_SKIP:-no}
26 if test "x${magic_test_skip}" = "xyes" ; then
29 The environment variable PCB_MAGIC_TEST_SKIP is set to yes.
30 This causes the testsuite to skip all tests and report no errors.
31 This is used for certain debugging *only*. The primary use is to
32 allow testing of the 'distcheck' target without including the effects
33 of the testsuite. The reason this is useful is that due to minor differences
34 in library versions and perhaps roundoff in different CPU's, the testsuite
35 may falsely report failures on some systems. These reported failures
36 prevent using 'distcheck' for verifying the rest of the build system.
37 These comments only apply to the tests which try to compare image files
50 $0 -- Run pcb regression tests
53 $0 [-d | --debug] [-g | --golden dir] [-r|--regen] [testname1 [testname2[ ...]]]
57 The $0 script is used both for running the pcb regression testsuite
58 as well as maintaining it. The way the test suite works is a number
59 of different layouts are exported using the various export HID's.
61 The resulting output files are examined in various ways to make sure
62 they are correct. The exact details of how they are compared varies.
63 For example, the PNG outputs are compared using tools from the ImageMagick
64 suite while the ASCII centroid and bill of materials files are normalized
65 with awk and then compared with the standard diff utility. The normalization
66 removes things like a comment line which contains the creation date.
70 -d | --debug Enables extra debug output
72 -g | --golden <dir> : Specifies that <dir> should be used for the
77 - The GUI interface is not checked via the regression testsuite.
79 - Currently actions are also not exercised
85 echo "----------------------------------------------------------------------"
88 ##########################################################################
95 if test $do_debug = yes ; then
102 ##########################################################################
104 # command line processing
125 # set the 'golden' directory.
131 # regenerate the 'golden' output files. Use this with caution.
132 # In particular, all differences should be noted and understood.
138 echo "unknown option: $1"
149 if test "X$regen" = "Xyes" && test $# -ne 1; then
150 echo "Please regenerate only one test at a time."
151 echo "This limitation is a safety measure."
155 ##########################################################################
157 # set up various tools
165 top_srcdir
=${top_srcdir:-.}
167 # The pcb wrapper script we want to test
169 # by default we will be running it from $(top_builddir)/tests/outputs/testname
170 # so we need to look 3 levels up and then down to src
171 PCB
=${PCB:-../../../src/pcbtest.sh}
173 # The gerbv executible
174 GERBV
=${GERBV:-gerbv}
175 GERBV_DEFAULT_FLAGS
=${GERBV_DEFAULT_FLAGS:---export=png --window=640x480}
177 # various ImageMagick tools
178 IM_ANIMATE
=${IM_ANIMATE:-animate}
179 IM_COMPARE
=${IM_COMPARE:-compare}
180 IM_COMPOSITE
=${IM_COMPOSITE:-composite}
181 IM_CONVERT
=${IM_CONVERT:-convert}
182 IM_DISPLAY
=${IM_DISPLAY:-display}
183 IM_MONTAGE
=${IM_MONTAGE:-montage}
186 INDIR
=${INDIR:-${srcdir}/inputs}
188 REFDIR
=${REFDIR:-${srcdir}/golden}
193 # the list of tests to run
194 TESTLIST
=${srcdir}/tests.list
196 if test "X$regen" = "Xyes" ; then
200 # create output directory
201 if test ! -d $OUTDIR ; then
203 if test $?
-ne 0 ; then
204 echo "Failed to create output directory ${OUTDIR}"
209 if test -z "$all_tests" ; then
210 if test ! -f ${TESTLIST} ; then
211 echo "ERROR: ($0) Test list $TESTLIST does not exist"
214 all_tests
=`${AWK} 'BEGIN{FS="|"} /^#/{next} {print $1}' ${TESTLIST} | sed 's; ;;g'`
217 if test -z "${all_tests}" ; then
218 echo "$0: No tests specified"
223 # fail/pass/total counts
229 ##########################################################################
238 top_srcdir ${top_srcdir}
250 GERBV_DEFAULT_FLAGS ${GERBV_DEFAULT_FLAGS}
254 IM_ANIMATE ${IM_ANIMATE}
255 IM_COMPARE ${IM_COMPARE}
256 IM_COMPOSITE ${IM_COMPOSITE}
257 IM_CONVERT ${IM_CONVERT}
258 IM_DISPLAY ${IM_DISPLAY}
259 IM_MONTAGE ${IM_MONTAGE}
263 tmpd
=/tmp
/pcb_tests.$$
264 mkdir
-p -m 0700 $tmpd
266 if test $rc -ne 0 ; then
267 echo "$0: ERROR: could not create $tmpd"
271 ##########################################################################
273 # utility functions for comparison
277 # compare_check "test_name" "file1" "file2"
279 # Makes sure that file1 and file2 both exist. If not, mark the current
280 # test as skipped and give an error message
287 if test ! -f "$f1" ; then
288 echo "$0: ${fn}(): $f1 does not exist"
293 if test ! -f "$f2" ; then
294 echo "$0: ${fn}(): $f2 does not exist"
301 ##########################################################################
303 # ASCII file comparison routines
307 # run_diff "file1" "file2"
313 if test $?
-ne 0 ; then return 1 ; fi
317 ##########################################################################
319 # BOM comparison routines
322 # used to remove things like creation date from BOM files
327 /^# Date:/ {print "# Date: today"; next}
328 /^# Author:/ {print "# Author: PCB"; next}
333 # top level function to compare BOM output
337 compare_check
"compare_bom" "$f1" "$f2" ||
return 1
339 # an example BOM file is:
341 # # PcbBOM Version 1.0
342 # # Date: Wed Jun 17 14:41:43 2009 UTC
343 # # Author: Dan McMahill
344 # # Title: Basic BOM/XY Test - PCB BOM
345 # # Quantity, Description, Value, RefDes
346 # # --------------------------------------------
347 # 8,"Standard SMT resistor, capacitor etc","RESC3216N",R90_TOP R180_TOP R270_TOP R0_TOP R270_BOT R180_BOT R90_BOT R0_BOT
348 # 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
349 # 8,"Small outline package, narrow (150mil)","SO8",USO90_TOP USO180_TOP USO270_TOP USO0_TOP USO270_BOT USO180_BOT USO90_BOT USO0_BOT
351 # For comparison, we need to ignore changes in the Date and Author lines.
352 local cf1
=${tmpd}/`basename $f1`-ref
353 local cf2
=${tmpd}/`basename $f2`-out
355 normalize_bom
$f1 $cf1
356 normalize_bom
$f2 $cf2
357 run_diff
$cf1 $cf2 || test_failed
=yes
360 ##########################################################################
362 # X-Y (centroid) comparison routines
365 # used to remove things like creation date from BOM files
370 /^# Date:/ {print "# Date: today"; next}
371 /^# Author:/ {print "# Author: PCB"; next}
379 compare_check
"compare_xy" "$f1" "$f2" ||
return 1
381 local cf1
=${tmpd}/`basename $f1`-ref
382 local cf2
=${tmpd}/`basename $f2`-out
383 normalize_xy
"$f1" "$cf1"
384 normalize_xy
"$f2" "$cf2"
385 run_diff
"$cf1" "$cf2" || test_failed
=yes
388 ##########################################################################
390 # GCODE comparison routines
393 # used to remove things like creation date from gcode files
397 # matches string such as '( Tue Mar 9 17:45:43 2010 )'
398 $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} *\)$/' \
405 compare_check
"compare_gcode" "$f1" "$f2" ||
return 1
407 # For comparison, we need to ignore changes in the Date and Author lines.
408 local cf1
=${tmpd}/`basename $f1`-ref
409 local cf2
=${tmpd}/`basename $f2`-out
411 normalize_gcode
$f1 $cf1
412 normalize_gcode
$f2 $cf2
414 run_diff
"$cf1" "$cf2" || test_failed
=yes
417 ##########################################################################
419 # RS274-X and Excellon comparison
425 compare_check
"compare_rs274x" "$f1" "$f2" ||
return 1
427 # use gerbv to export our reference RS274-X file and our generated
428 # RS274-X file to png. Then we'll use ImageMagick to see
429 # if there are any differences in the resulting files
433 png1
=${pngdir}/${nb}-ref.png
434 png2
=${pngdir}/${nb}-out.png
436 debug
"${GERBV} ${GERBV_DEFAULT_FLAGS} --output=${png1} ${f1}"
437 ${GERBV} ${GERBV_DEFAULT_FLAGS} --output=${png1} ${f1}
439 debug
"${GERBV} ${GERBV_DEFAULT_FLAGS} --output=${png2} ${f2}"
440 ${GERBV} ${GERBV_DEFAULT_FLAGS} --output=${png2} ${f2}
442 compare_image
${png1} ${png2}
450 ##########################################################################
452 # GIF/JPEG/PNG comparison routines
458 compare_check
"compare_image" "$f1" "$f2" ||
return 1
460 # now see if the image files are the same
461 debug
"${IM_COMPARE} -metric MAE ${f1} ${f2} null:"
462 same
=`${IM_COMPARE} -metric MAE ${f1} ${f2} null: 2>&1 | \
463 ${AWK} '{if($1 == 0){print "yes"} else {print "no"}}'`
464 debug
"compare_image(): same = $same"
466 if test "$same" != yes ; then
468 echo "FAILED: See ${errdir}"
470 ${IM_COMPARE} ${f1} ${f2} ${errdir}/compare.png
471 ${IM_COMPOSITE} ${f1} ${f2} -compose difference ${errdir}/composite.png
472 ${IM_CONVERT} ${f1} ${f2} -compose difference -composite -colorspace gray ${errdir}/gray.png
473 cat > ${errdir}/animate.sh
<< EOF
475 ${IM_CONVERT} -label "%f" ${f1} ${f2} miff:- | \
476 ${IM_MONTAGE} - -geometry +0+0 -tile 1x1 miff:- | \
477 ${IM_ANIMATE} -delay 0.5 -loop 0 -
479 chmod a
+x
${errdir}/animate.sh
483 ##########################################################################
485 # The main program loop
488 for t
in $all_tests ; do
494 ######################################################################
496 # extract the details for the test
499 pcb_flags
="${PCB_DEFAULT_FLAGS}"
501 rundir
="${OUTDIR}/${t}"
502 refdir
="${REFDIR}/${t}"
503 errdir
=${rundir}/mismatch
505 # test_name | layout file(s) | [export hid name] | [optional arguments to pcb] | [mismatch]
507 name
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {print $1}'`
508 files
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {print $2}'`
509 hid
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {gsub(/[ \t]*/, ""); print $3}'`
510 args
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {print $4}'`
511 mismatch
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {if($5 == "mismatch"){print "yes"}else{print "no"}}'`
512 out_files
=`grep "^[ \t]*${t}[ \t]*|" $TESTLIST | $AWK 'BEGIN{FS="|"} {print $6}'`
514 if test "X${name}" = "X" ; then
515 echo "ERROR: Specified test ${t} does not appear to exist"
516 skip
=`expr $skip + 1`
520 if test "X${args}" != "X" ; then
524 if test "X${hid}" = "Xgerber" ; then
525 pcb_flags
="--fab-author Fab_Author ${pcb_flags}"
528 ######################################################################
530 # Set up the run directory
533 test -d ${rundir} && rm -fr ${rundir}
535 if test $?
-ne 0 ; then
536 echo "$0: Could not create run directory ${rundir}"
537 skip
=`expr $skip + 1`
542 ######################################################################
544 # check to see if the files we need exist and copy them to the run
551 if test ! -f ${INDIR}/${f} ; then
552 echo "ERROR: File $f specified as part of the $t test does not exist"
555 path_files
="${path_files} ${INDIR}/${f}"
556 cp "${INDIR}/${f}" "${rundir}"
560 if test "$missing_files" = "yes" ; then
561 echo "${t} had missing input files. Skipping test"
562 skip
=`expr $skip + 1`
566 ######################################################################
571 echo "${PCB} -x ${hid} ${pcb_flags} ${path_files}"
572 (cd ${rundir} && ${PCB} -x ${hid} ${pcb_flags} ${files})
575 if test $pcb_rc -ne 0 ; then
576 echo "${PCB} returned ${pcb_rc}. This is a failure."
577 fail
=`expr $fail + 1`
581 # and clean up the input files we'd copied over
586 ######################################################################
591 if test "X$regen" = "Xyes" ; then
592 echo "## -*- makefile -*-" > ${rundir}/Makefile.am
593 echo >> ${rundir}/Makefile.am
594 echo -n "EXTRA_DIST=" >> ${rundir}/Makefile.am
595 for f
in $out_files ; do
596 fn
=`echo $f | sed 's;.*:;;g'`
597 echo " \\" >> ${rundir}/Makefile.am
598 echo -n "\t$fn" >> ${rundir}/Makefile.am
600 echo >> ${rundir}/Makefile.am
602 echo "Regenerated ${t}"
604 # compare the result to our reference file
607 for f
in $out_files ; do
608 debug
"processing $f"
609 # break apart type:fn into the type and file name
610 type=`echo $f | sed 's;:.*;;g'`
611 fn
=`echo $f | sed 's;.*:;;g'`
616 compare_bom
${refdir}/${fn} ${rundir}/${fn}
620 compare_xy
${refdir}/${fn} ${rundir}/${fn}
625 compare_gcode
${refdir}/${fn} ${rundir}/${fn}
630 compare_cnc
${refdir}/${fn} ${rundir}/${fn}
634 compare_rs274x
${refdir}/${fn} ${rundir}/${fn}
639 compare_image
${refdir}/${fn} ${rundir}/${fn}
643 compare_image
${refdir}/${fn} ${rundir}/${fn}
647 compare_image
${refdir}/${fn} ${rundir}/${fn}
652 echo "internal error: $type is not a known file type"
660 if test $test_failed = yes ; then
662 fail
=`expr $fail + 1`
663 elif test $test_skipped = yes ; then
665 skip
=`expr $skip + 1`
668 pass
=`expr $pass + 1`
676 echo "Passed $pass, failed $fail, skipped $skip out of $tot tests."
679 if test $pass -ne $tot ; then