summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/Common85
-rwxr-xr-xtest/dbg_meas54
-rwxr-xr-xtest/del_frame97
-rwxr-xr-xtest/del_vec70
-rwxr-xr-xtest/floor40
-rwxr-xr-xtest/frame_ref149
-rwxr-xr-xtest/iprint101
-rwxr-xr-xtest/keys134
-rwxr-xr-xtest/meas_qual232
-rwxr-xr-xtest/structure111
-rwxr-xr-xtest/tsort137
11 files changed, 1210 insertions, 0 deletions
diff --git a/test/Common b/test/Common
new file mode 100755
index 0000000..271064b
--- /dev/null
+++ b/test/Common
@@ -0,0 +1,85 @@
+#!/bin/sh
+#
+# Common - Elements shared by all regression tests for fped
+#
+# Written 2010, 2011 by Werner Almesberger
+# Copyright 2010, 2011 Werner Almesberger
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+
+
+fped()
+{
+ echo -n "$1: " 1>&2
+ shift
+ cat >_in
+ $VALGRIND ${FPED:-../fped} -T _in "$@" >_out 2>&1 || {
+ echo FAILED "($SCRIPT)" 1>&2
+ cat _out
+ rm -f _in _out
+ exit 1
+ }
+ rm -f _in
+}
+
+
+fped_dump()
+{
+ fped "$@" -T -T
+}
+
+
+fped_fail()
+{
+ echo -n "$1: " 1>&2
+ shift
+ cat >_in
+ $VALGRIND ${FPED:-../fped} -T _in "$@" >_out 2>&1 && {
+ echo FAILED "($SCRIPT)" 1>&2
+ cat _out
+ rm -f _in _out
+ exit 1
+ }
+ rm -f _in
+}
+
+
+expect()
+{
+ diff -u - "$@" _out >_diff || {
+ echo FAILED "($SCRIPT)" 1>&2
+ cat _diff 1>&2
+ rm -f _out _diff
+ exit 1
+ }
+ echo PASSED 1>&2
+ rm -f _out _diff
+ passed=`expr ${passed:-0} + 1`
+}
+
+
+expect_grep()
+{
+ grep "$1" <_out >_tmp || exit 1
+ mv _tmp _out
+ shift
+ expect "$@"
+}
+
+
+expect_sed()
+{
+ sed "$1" <_out >_tmp || exit 1
+ mv _tmp _out
+ shift
+ expect "$@"
+}
+
+
+if [ ! -z "$CWD_PREFIX" -a ! -z "$FPED" -a "$FPED" = "${FPED#/}" ]; then
+ FPED="$CWD_PREFIX/$FPED"
+fi
diff --git a/test/dbg_meas b/test/dbg_meas
new file mode 100755
index 0000000..87312d8
--- /dev/null
+++ b/test/dbg_meas
@@ -0,0 +1,54 @@
+#!/bin/sh
+. ./Common
+
+###############################################################################
+
+fped "%meas: print mm (default)" <<EOF
+a: vec @(0mm, 0mm)
+b: vec @(3mm, 4mm)
+meas a >> b /* work-around to simplify grammar */
+m: meas a >> b
+%meas m
+EOF
+expect <<EOF
+5
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "%meas: print mil" <<EOF
+unit mil
+a: vec @(0mm, 0mm)
+b: vec @(2.54mm, 0mm)
+meas a >> b /* work-around to simplify grammar */
+m: meas a >> b
+%meas m
+EOF
+expect <<EOF
+100
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_fail "%meas: invalid ID" <<EOF
+%meas m
+EOF
+expect <<EOF
+1: unknown object "m" near "m"
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_fail "%meas: measurement not instantiated" <<EOF
+a: vec @(0mm, 0mm)
+loop i = 1, 0
+b: vec @(i*1mm, 0mm)
+meas a >> b /* work-around to simplify grammar */
+m: meas a >> b
+%meas m
+EOF
+expect <<EOF
+measurement "m" was not instantiated
+EOF
+
+###############################################################################
diff --git a/test/del_frame b/test/del_frame
new file mode 100755
index 0000000..25ad2f1
--- /dev/null
+++ b/test/del_frame
@@ -0,0 +1,97 @@
+#!/bin/sh
+. ./Common
+
+###############################################################################
+
+fped_fail "delete frame: can't self-destruct" <<EOF
+frame f {
+ %del f
+}
+EOF
+expect <<EOF
+3: a frame can't delete itself near "}"
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "delete frame: content disappears" <<EOF
+frame f {
+ vec @(0mm, 0mm)
+}
+
+%del f
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+package "_"
+unit mm
+
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "delete frame: references disappear" <<EOF
+frame f {
+ vec @(0mm, 0mm)
+}
+
+frame f @
+
+%del f
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+package "_"
+unit mm
+
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "delete frame: measurements disappear" <<EOF
+frame f {
+ v: vec @(0mm, 0mm)
+}
+
+frame f @
+meas f.v -> f.v
+
+%del f
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+package "_"
+unit mm
+
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "delete frame: measurements with qualifiers disappear" <<EOF
+frame f {
+ v: vec @(0mm, 0mm)
+}
+
+frame g { frame f @ }
+
+frame g @
+meas g/f.v -> f.v
+
+%del g
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+frame f {
+ v: vec @(0mm, 0mm)
+}
+
+package "_"
+unit mm
+
+EOF
+
+###############################################################################
diff --git a/test/del_vec b/test/del_vec
new file mode 100755
index 0000000..8bb35bb
--- /dev/null
+++ b/test/del_vec
@@ -0,0 +1,70 @@
+#!/bin/sh
+. ./Common
+
+###############################################################################
+
+fped_dump "delete vector: it disappears" <<EOF
+v: vec @(0mm, 0mm)
+%del v
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+package "_"
+unit mm
+
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "delete vector: references disappear" <<EOF
+v: vec @(0mm, 0mm)
+line v v
+%del v
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+package "_"
+unit mm
+
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "delete vector: measurements disappear (same frame)" <<EOF
+v: vec @(0mm, 0mm)
+meas v -> v
+%del v
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+package "_"
+unit mm
+
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "delete vector: measurements disappear (other frame)" <<EOF
+frame f {
+ v: vec @(0mm, 0mm)
+}
+frame f @
+meas f.v -> f.v
+%del f.v
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+frame f {
+}
+
+package "_"
+unit mm
+
+frame f @
+EOF
+
+###############################################################################
diff --git a/test/floor b/test/floor
new file mode 100755
index 0000000..e0c399b
--- /dev/null
+++ b/test/floor
@@ -0,0 +1,40 @@
+#!/bin/sh
+. ./Common
+
+###############################################################################
+
+fped "floor: 4.7mm" <<EOF
+%print floor(4.7mm)
+EOF
+expect <<EOF
+4mm
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "floor: -1.2m" <<EOF
+%print floor(-1.2)
+EOF
+expect <<EOF
+-2
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "floor: round 7 mil (0.1778 mm) to two digits in mm" <<EOF
+%print floor(7mil/0.01mm+0.5)*0.01mm
+EOF
+expect <<EOF
+0.18mm
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "floor: round 12 mil (0.3048 mm) to two digits in mm" <<EOF
+%print floor(12mil/0.01mm+0.5)*0.01mm
+EOF
+expect <<EOF
+0.3mm
+EOF
+
+###############################################################################
diff --git a/test/frame_ref b/test/frame_ref
new file mode 100755
index 0000000..85ef8e9
--- /dev/null
+++ b/test/frame_ref
@@ -0,0 +1,149 @@
+#!/bin/sh
+. ./Common
+
+###############################################################################
+
+fped_dump "frame reference: \"frame\" (origin)" <<EOF
+frame f {}
+frame f @
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+frame f {
+}
+
+package "_"
+unit mm
+
+frame f @
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "frame reference: \"%frame\" (current frame origin)" <<EOF
+frame f {}
+%frame f @
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+frame f {
+}
+
+package "_"
+unit mm
+
+frame f @
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "frame reference: \"%frame\" (current frame vector)" <<EOF
+frame f {}
+v: vec @(0mm, 0mm)
+%frame f v
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+frame f {
+}
+
+package "_"
+unit mm
+
+v: vec @(0mm, 0mm)
+frame f .
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "frame reference: \"%frame\" (other frame origin)" <<EOF
+frame f {}
+frame g {}
+%frame f g.@
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+frame f {
+}
+
+frame g {
+ frame f @
+}
+
+package "_"
+unit mm
+
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "frame reference: \"%frame\" (other frame base)" <<EOF
+frame f {}
+frame g {
+ v: vec @(0mm, 0mm)
+}
+%frame f g.v
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+frame f {
+}
+
+frame g {
+ v: vec @(0mm, 0mm)
+ frame f .
+}
+
+package "_"
+unit mm
+
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_fail "frame reference: \"%frame\" (cycle)" <<EOF
+frame f {
+}
+
+frame g {
+ frame f @
+}
+
+%frame g f.@
+EOF
+expect <<EOF
+8: frame "g" is a parent of "f" near "@"
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "frame reference: \"%frame\" (out-of-order)" <<EOF
+frame f {
+}
+
+frame g {
+}
+
+%frame g f.@
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+frame g {
+}
+
+frame f {
+ frame g @
+}
+
+package "_"
+unit mm
+
+EOF
+
+###############################################################################
diff --git a/test/iprint b/test/iprint
new file mode 100755
index 0000000..84c1ca2
--- /dev/null
+++ b/test/iprint
@@ -0,0 +1,101 @@
+#!/bin/sh
+. ./Common
+
+###############################################################################
+
+fped "iprint: loop" <<EOF
+loop x = 1, 3
+%iprint x
+EOF
+expect <<EOF
+1
+2
+3
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "iprint: two tables (independent)" <<EOF
+table { a } { 1 } { 2 }
+table { b } { 3 } { 4 }
+
+%iprint a*10+b
+EOF
+expect <<EOF
+13
+14
+23
+24
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "iprint: two tables (2nd references 1st)" <<EOF
+table { a } { 1 } { 2 }
+table { b } { 3+a } { 4+a }
+
+%iprint a*10+b
+EOF
+expect <<EOF
+14
+15
+25
+26
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "iprint: two tables (1st references 2nd)" <<EOF
+table { a } { 1+b } { 2+b }
+table { b } { 3 } { 4 }
+
+%iprint a*10+b
+EOF
+expect <<EOF
+43
+54
+53
+64
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "iprint: inside frame (global variable)" <<EOF
+frame foo {
+ %iprint n
+}
+
+loop n = 1, 2
+frame foo @
+EOF
+expect <<EOF
+1
+2
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "iprint: inside frame (local variable) " <<EOF
+frame foo {
+ set n1 = n+1
+ %iprint n1
+}
+
+loop n = 1, 2
+frame foo @
+EOF
+expect <<EOF
+2
+3
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_fail "iprint: undefined variable" <<EOF
+%iprint foo
+EOF
+expect <<EOF
+undefined variable "foo"
+EOF
+
+###############################################################################
diff --git a/test/keys b/test/keys
new file mode 100755
index 0000000..77a4314
--- /dev/null
+++ b/test/keys
@@ -0,0 +1,134 @@
+#!/bin/sh
+. ./Common
+
+###############################################################################
+
+fped "keys: tables, master before slave" <<EOF
+table { a, eng } { 1, "one" } { 2, "two" }
+table { ?a, ger } { 1, "eins" } { 2, "zwei" }
+
+%iprint eng
+%iprint ger
+EOF
+expect <<EOF
+one
+eins
+two
+zwei
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "keys: tables, master after slave" <<EOF
+table { ?a, eng } { 1, "one" } { 2, "two" }
+table { a, spa } { 1, "uno" } { 2, "dos" }
+
+%iprint eng
+%iprint spa
+EOF
+expect <<EOF
+one
+uno
+two
+dos
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_fail "keys: tables, slaves without master" <<EOF
+table { ?a, eng } { 1, "one" } { 2, "two" }
+table { ?a, lat } { 1, "unum" } { 2, "duo" }
+
+%iprint eng
+%iprint lat
+EOF
+expect <<EOF
+undefined variable "a"
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_fail "keys: tables, both masters" <<EOF
+table { a, eng } { 1, "one" } { 2, "two" }
+table { a, lat } { 1, "unum" } { 2, "duo" }
+
+%iprint eng
+%iprint lat
+EOF
+expect <<EOF
+2: duplicate variable "a" near "a"
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "keys: master is single variable, slave is table" <<EOF
+set n = 2
+table { ?n, square } { 1, 1 } { 2, 4 } { 3, 9 } { 4, 16 }
+
+%iprint square
+EOF
+expect <<EOF
+4
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "keys: master is table, slave is single variable" <<EOF
+table { n, cube } { 1, 1 } { 2, 8 } { 3, 27 } { 4, 64 }
+set ?n = 3
+
+%iprint cube
+EOF
+expect <<EOF
+27
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "keys: master is loop, slave is table" <<EOF
+loop n = 1, 3
+table { ?n, sqr } { 1, 1 } { 2, 4 } { 3, 9 } { 4, 16 }
+
+%iprint sqr
+EOF
+expect <<EOF
+1
+4
+9
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "keys: two keys" <<EOF
+table { a, an } { 1, "one" } { 2, "two" }
+table { b, bn } { 3, "three" } { 4, "four" } { 5, "five" }
+table { ?a, ?b, sum }
+ { 1, 3, "four" }
+ { 2, 4, "six" }
+ { 3, 4, "seven" }
+
+%iprint sum
+EOF
+expect <<EOF
+four
+six
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "keys: key set by outer frame" <<EOF
+frame tab {
+ table { sqrt, ?n } { 1, 1 } { 2, 4 } { 3, 9 } { 4, 16 } { 5, 25 }
+ %iprint sqrt
+}
+
+table { n } { 25 } { 9 }
+
+frame tab @
+EOF
+expect <<EOF
+5
+3
+EOF
+
+###############################################################################
diff --git a/test/meas_qual b/test/meas_qual
new file mode 100755
index 0000000..cad9931
--- /dev/null
+++ b/test/meas_qual
@@ -0,0 +1,232 @@
+#!/bin/sh
+. ./Common
+
+###############################################################################
+
+fped_dump "qualified measurements: no qualifier" <<EOF
+frame c { v: vec @(0mm, 0mm) }
+frame b { frame c @ }
+frame a { frame b @ }
+frame a @
+meas c.v >> c.v
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+frame c {
+ v: vec @(0mm, 0mm)
+}
+
+frame b {
+ frame c @
+}
+
+frame a {
+ frame b @
+}
+
+package "_"
+unit mm
+
+frame a @
+meas c.v >> c.v
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "qualified measurements: fully qualified" <<EOF
+frame c { v: vec @(0mm, 0mm) }
+frame b { frame c @ }
+frame a { frame b @ }
+frame a @
+meas a/b/c.v >> c.v
+EOF
+expect_grep '^meas' <<EOF
+meas a/b/c.v >> c.v
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "qualified measurements: partially qualified" <<EOF
+frame c { v: vec @(0mm, 0mm) }
+frame b { frame c @ }
+frame a { frame b @ }
+frame a @
+meas a/c.v >> c.v
+EOF
+expect_grep '^meas' <<EOF
+meas a/c.v >> c.v
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "qualified measurements: wrong order" <<EOF
+frame c { v: vec @(0mm, 0mm) }
+frame b { frame c @ }
+frame a { frame b @ }
+frame a @
+meas b/a/c.v >> c.v
+EOF
+expect_grep 'warning' <<EOF
+5: warning: not all qualifiers can be reached near "v"
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "qualified measurements: unlinked frame" <<EOF
+frame c { v: vec @(0mm, 0mm) }
+frame b { frame c @ }
+frame a { frame b @ }
+frame x {}
+frame a @
+frame x @
+meas a/c.v >> x/c.v
+EOF
+expect_grep 'warning' <<EOF
+7: warning: not all qualifiers can be reached near "v"
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_fail "qualified measurements: duplicate qualifier" <<EOF
+frame c { v: vec @(0mm, 0mm) }
+frame b { frame c @ }
+frame a { frame b @ }
+frame a @
+meas b/b/c.v >> c.v
+EOF
+expect <<EOF
+5: duplicate qualifier "b" near "v"
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "qualified measurements: \"macro\" unqualified" <<EOF
+frame x {
+ a: vec @(0mm, 0mm)
+ b: vec .(d, 0mm)
+}
+frame a {
+ set d = 2mm
+ frame x @
+}
+frame b {
+ set d = 3mm
+ frame x @
+}
+frame a @
+vec @(1mm, 0mm)
+frame b .
+meas x.a >> x.b /* dummy */
+m: meas x.a >> x.b
+%meas m
+EOF
+expect <<EOF
+4
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "qualified measurements: \"macro\" qualified (a)" <<EOF
+frame x {
+ a: vec @(0mm, 0mm)
+ b: vec .(d, 0mm)
+}
+frame a {
+ set d = 2mm
+ frame x @
+}
+frame b {
+ set d = 3mm
+ frame x @
+}
+frame a @
+vec @(1mm, 0mm)
+frame b .
+meas x.a >> x.b /* dummy */
+m: meas a/x.a >> a/x.b
+%meas m
+EOF
+expect <<EOF
+2
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "qualified measurements: \"macro\" qualified (b)" <<EOF
+frame x {
+ a: vec @(0mm, 0mm)
+ b: vec .(d, 0mm)
+}
+frame a {
+ set d = 2mm
+ frame x @
+}
+frame b {
+ set d = 3mm
+ frame x @
+}
+frame a @
+vec @(1mm, 0mm)
+frame b .
+meas x.a >> x.b /* dummy */
+m: meas b/x.a >> b/x.b
+%meas m
+EOF
+expect <<EOF
+3
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "qualified measurements: \"macro\" qualified (a/b)" <<EOF
+frame x {
+ a: vec @(0mm, 0mm)
+ b: vec .(d, 0mm)
+}
+frame a {
+ set d = 2mm
+ frame x @
+}
+frame b {
+ set d = 3mm
+ frame x @
+}
+frame a @
+vec @(1mm, 0mm)
+frame b .
+meas x.a >> x.b /* dummy */
+m: meas a/x.a >> b/x.b
+%meas m
+EOF
+expect <<EOF
+4
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "qualified measurements: \"macro\" qualified (b/a)" <<EOF
+frame x {
+ a: vec @(0mm, 0mm)
+ b: vec .(d, 0mm)
+}
+frame a {
+ set d = 2mm
+ frame x @
+}
+frame b {
+ set d = 3mm
+ frame x @
+}
+frame a @
+vec @(1mm, 0mm)
+frame b .
+meas x.a >> x.b /* dummy */
+m: meas b/x.a >> a/x.b
+%meas m
+EOF
+expect <<EOF
+1
+EOF
+
+###############################################################################
diff --git a/test/structure b/test/structure
new file mode 100755
index 0000000..bcb124b
--- /dev/null
+++ b/test/structure
@@ -0,0 +1,111 @@
+#!/bin/sh
+. ./Common
+
+###############################################################################
+
+fped_dump "structure: empty file" <<EOF
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+package "_"
+unit mm
+
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "structure: just an empty frame definition" <<EOF
+frame foo {
+}
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+frame foo {
+}
+
+package "_"
+unit mm
+
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "structure: just the package name" <<EOF
+package "hello"
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+package "hello"
+unit mm
+
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "structure: just the unit" <<EOF
+unit mil
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+package "_"
+unit mil
+
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "structure: just one root frame item" <<EOF
+vec @(1mm, 1mm)
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+package "_"
+unit mm
+
+__0: vec @(1mm, 1mm)
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_dump "structure: frame plus measurement" <<EOF
+frame f {
+ a: vec @(0mm, 0mm)
+ b: vec @(1mm, 1mm)
+}
+frame f @
+meas f.a -> f.b
+EOF
+expect <<EOF
+/* MACHINE-GENERATED ! */
+
+frame f {
+ a: vec @(0mm, 0mm)
+ b: vec @(1mm, 1mm)
+}
+
+package "_"
+unit mm
+
+frame f @
+meas f.a -> f.b
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_fail "structure: measurement in frame" <<EOF
+frame f {
+ a: vec @(0mm, 0mm)
+ b: vec @(1mm, 1mm)
+ meas f.a -> f.b
+}
+EOF
+expect <<EOF
+4: syntax error near "meas"
+EOF
+
+###############################################################################
diff --git a/test/tsort b/test/tsort
new file mode 100755
index 0000000..a4b4108
--- /dev/null
+++ b/test/tsort
@@ -0,0 +1,137 @@
+#!/bin/sh
+. ./Common
+
+###############################################################################
+
+fped "tsort: total order" <<EOF
+%tsort {
+ a b
+ a c
+ a d
+ b c
+ b d
+ c d
+}
+EOF
+expect <<EOF
+a
+b
+c
+d
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "tsort: partial order change (1)" <<EOF
+%tsort {
+ a b
+ a c
+ a d
+ d b
+}
+EOF
+expect <<EOF
+a
+c
+d
+b
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "tsort: partial order change (2)" <<EOF
+%tsort {
+ b c
+ c d
+ a b
+}
+EOF
+expect <<EOF
+a
+b
+c
+d
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "tsort: old order differs from resolution order" <<EOF
+%tsort {
+ +a +b +c +d
+ a c
+ a b
+ a d
+}
+EOF
+expect <<EOF
+a
+b
+c
+d
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "tsort: order change due to priority" <<EOF
+%tsort {
+ a b
+ a c 1
+ a d
+}
+EOF
+expect <<EOF
+a
+c
+b
+d
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "tsort: priority accumulation without decay" <<EOF
+%tsort {
+ +a +b +c +d
+ a b 1
+ a d 1
+}
+EOF
+expect <<EOF
+a
+b
+d
+c
+EOF
+
+#------------------------------------------------------------------------------
+
+fped "tsort: priority accumulation with decay" <<EOF
+%tsort {
+ +a -b +c +d
+ a b 1
+ a d 1
+}
+EOF
+expect <<EOF
+a
+b
+c
+d
+EOF
+
+#------------------------------------------------------------------------------
+
+fped_fail "tsort: cycle" <<EOF
+%tsort {
+ a b
+ b a
+}
+EOF
+expect_sed '/Aborted/d' <<EOF
+cycle detected in partial order
+EOF
+
+# The "Aborted" can be reported with or without "(core dumped)", and sometimes
+# not at all. So we just remove it. We already know that tsort has detected
+# the problem.
+
+###############################################################################