summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/cals/test
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/cals/test
Initial commit
Diffstat (limited to 'macros/latex/contrib/cals/test')
-rw-r--r--macros/latex/contrib/cals/test/README15
-rw-r--r--macros/latex/contrib/cals/test/cell/test_10_create.chk45
-rw-r--r--macros/latex/contrib/cals/test/cell/test_10_create.tex22
-rw-r--r--macros/latex/contrib/cals/test/cell/test_20_colwidth.chk10
-rw-r--r--macros/latex/contrib/cals/test/cell/test_20_colwidth.tex9
-rw-r--r--macros/latex/contrib/cals/test/cell/test_30_decor.chk38
-rw-r--r--macros/latex/contrib/cals/test/cell/test_30_decor.tex29
-rw-r--r--macros/latex/contrib/cals/test/cell/test_40_width.chk26
-rw-r--r--macros/latex/contrib/cals/test/cell/test_40_width.tex15
-rw-r--r--macros/latex/contrib/cals/test/cell/test_50_hooks.chk4
-rw-r--r--macros/latex/contrib/cals/test/cell/test_50_hooks.tex12
-rw-r--r--macros/latex/contrib/cals/test/colsep/test_10_outone.chk62
-rw-r--r--macros/latex/contrib/cals/test/colsep/test_10_outone.tex57
-rw-r--r--macros/latex/contrib/cals/test/colsep/test_20_row.chk91
-rw-r--r--macros/latex/contrib/cals/test/colsep/test_20_row.tex55
-rw-r--r--macros/latex/contrib/cals/test/decoration/test_10_withwidth2.chk7
-rw-r--r--macros/latex/contrib/cals/test/decoration/test_10_withwidth2.tex32
-rw-r--r--macros/latex/contrib/cals/test/decoration/test_20_withcolor2.chk4
-rw-r--r--macros/latex/contrib/cals/test/decoration/test_20_withcolor2.tex23
-rw-r--r--macros/latex/contrib/cals/test/decoration/test_30_halfwidth.chk3
-rw-r--r--macros/latex/contrib/cals/test/decoration/test_30_halfwidth.tex9
-rw-r--r--macros/latex/contrib/cals/test/decoration/test_50_maxwidth.chk9
-rw-r--r--macros/latex/contrib/cals/test/decoration/test_50_maxwidth.tex28
-rw-r--r--macros/latex/contrib/cals/test/decoration/test_60_row.chk54
-rw-r--r--macros/latex/contrib/cals/test/decoration/test_60_row.tex65
-rw-r--r--macros/latex/contrib/cals/test/decoration/test_70_align.chk8
-rw-r--r--macros/latex/contrib/cals/test/decoration/test_70_align.tex15
-rw-r--r--macros/latex/contrib/cals/test/llt/test_10_cons_rot.chk23
-rw-r--r--macros/latex/contrib/cals/test/llt/test_10_cons_rot.tex23
-rw-r--r--macros/latex/contrib/cals/test/llt/test_20_snoc_decons.chk14
-rw-r--r--macros/latex/contrib/cals/test/llt/test_20_snoc_decons.tex18
-rw-r--r--macros/latex/contrib/cals/test/llt/test_30_all.chk24
-rw-r--r--macros/latex/contrib/cals/test/llt/test_30_all.tex26
-rw-r--r--macros/latex/contrib/cals/test/regression/test_010_wrongbreak.chk7
-rw-r--r--macros/latex/contrib/cals/test/regression/test_010_wrongbreak.tex33
-rw-r--r--macros/latex/contrib/cals/test/regression/test_020_wrongnobreak.chk11
-rw-r--r--macros/latex/contrib/cals/test/regression/test_020_wrongnobreak.tex21
-rw-r--r--macros/latex/contrib/cals/test/regression/test_030_spanbreak.chk11
-rw-r--r--macros/latex/contrib/cals/test/regression/test_030_spanbreak.tex32
-rw-r--r--macros/latex/contrib/cals/test/regression/test_040_rowheight.chk3
-rw-r--r--macros/latex/contrib/cals/test/regression/test_040_rowheight.tex40
-rw-r--r--macros/latex/contrib/cals/test/regression/test_050_leftskip_rowspan.chk2
-rw-r--r--macros/latex/contrib/cals/test/regression/test_050_leftskip_rowspan.tex24
-rw-r--r--macros/latex/contrib/cals/test/regression/test_060_alignment.chk106
-rw-r--r--macros/latex/contrib/cals/test/regression/test_060_alignment.tex37
-rw-r--r--macros/latex/contrib/cals/test/regression/test_065_alignment.chk45
-rw-r--r--macros/latex/contrib/cals/test/regression/test_065_alignment.tex25
-rw-r--r--macros/latex/contrib/cals/test/regression/test_070_clean_backup_row.chk1
-rw-r--r--macros/latex/contrib/cals/test/regression/test_070_clean_backup_row.tex18
-rw-r--r--macros/latex/contrib/cals/test/regression/test_075_vstraddled_retain_rowsep.chk14
-rw-r--r--macros/latex/contrib/cals/test/regression/test_075_vstraddled_retain_rowsep.tex38
-rw-r--r--macros/latex/contrib/cals/test/regression/test_080_never_pagebreak_in_float.chk4
-rw-r--r--macros/latex/contrib/cals/test/regression/test_080_never_pagebreak_in_float.tex46
-rw-r--r--macros/latex/contrib/cals/test/regression/test_085_allow_table_in_colspan.chk0
-rw-r--r--macros/latex/contrib/cals/test/regression/test_085_allow_table_in_colspan.tex32
-rw-r--r--macros/latex/contrib/cals/test/rowsep/test_10_waitrule.chk47
-rw-r--r--macros/latex/contrib/cals/test/rowsep/test_10_waitrule.tex68
-rw-r--r--macros/latex/contrib/cals/test/rowsep/test_15_waitover.chk36
-rw-r--r--macros/latex/contrib/cals/test/rowsep/test_15_waitover.tex51
-rw-r--r--macros/latex/contrib/cals/test/rowsep/test_20_pack.chk38
-rw-r--r--macros/latex/contrib/cals/test/rowsep/test_20_pack.tex32
-rw-r--r--macros/latex/contrib/cals/test/rowsep/test_30_jointwo.chk29
-rw-r--r--macros/latex/contrib/cals/test/rowsep/test_30_jointwo.tex34
-rw-r--r--macros/latex/contrib/cals/test/rowsep/test_35_joinone.chk16
-rw-r--r--macros/latex/contrib/cals/test/rowsep/test_35_joinone.tex27
-rw-r--r--macros/latex/contrib/cals/test/rowsep/test_40_construct.chk21
-rw-r--r--macros/latex/contrib/cals/test/rowsep/test_40_construct.tex36
-rw-r--r--macros/latex/contrib/cals/test/span/test_10_queue.chk5
-rw-r--r--macros/latex/contrib/cals/test/span/test_10_queue.tex10
-rw-r--r--macros/latex/contrib/cals/test/span/test_20_decor.chk84
-rw-r--r--macros/latex/contrib/cals/test/span/test_20_decor.tex31
-rw-r--r--macros/latex/contrib/cals/test/span/test_30_iftlrb.chk16
-rw-r--r--macros/latex/contrib/cals/test/span/test_30_iftlrb.tex15
-rw-r--r--macros/latex/contrib/cals/test/span/test_40_lr_queue.chk14
-rw-r--r--macros/latex/contrib/cals/test/span/test_40_lr_queue.tex28
-rw-r--r--macros/latex/contrib/cals/test/span/test_50_dimen.chk38
-rw-r--r--macros/latex/contrib/cals/test/span/test_50_dimen.tex40
-rw-r--r--macros/latex/contrib/cals/test/span/test_60_content.chk16
-rw-r--r--macros/latex/contrib/cals/test/span/test_60_content.tex15
-rw-r--r--macros/latex/contrib/cals/test/span/test_70_intercept.chk16
-rw-r--r--macros/latex/contrib/cals/test/span/test_70_intercept.tex28
-rw-r--r--macros/latex/contrib/cals/test/span/test_80_marker.chk20
-rw-r--r--macros/latex/contrib/cals/test/span/test_80_marker.tex35
-rw-r--r--macros/latex/contrib/cals/test/support/LatexTest.py163
-rw-r--r--macros/latex/contrib/cals/test/support/run_tests.py67
-rw-r--r--macros/latex/contrib/cals/test/table/test_10_ifbreak.chk22
-rw-r--r--macros/latex/contrib/cals/test/table/test_10_ifbreak.tex53
-rw-r--r--macros/latex/contrib/cals/test/table/test_20_dispatch.chk56
-rw-r--r--macros/latex/contrib/cals/test/table/test_20_dispatch.tex65
-rw-r--r--macros/latex/contrib/cals/test/table/test_30_issue_rowsep.chk110
-rw-r--r--macros/latex/contrib/cals/test/table/test_30_issue_rowsep.tex52
-rw-r--r--macros/latex/contrib/cals/test/table/test_40_issuerow.chk28
-rw-r--r--macros/latex/contrib/cals/test/table/test_40_issuerow.tex25
-rw-r--r--macros/latex/contrib/cals/test/table/test_50_row.chk102
-rw-r--r--macros/latex/contrib/cals/test/table/test_50_row.tex44
-rw-r--r--macros/latex/contrib/cals/test/table/test_60_whitespace.chk2
-rw-r--r--macros/latex/contrib/cals/test/table/test_60_whitespace.tex21
-rw-r--r--macros/latex/contrib/cals/test/table/test_70_lrskip.chk30
-rw-r--r--macros/latex/contrib/cals/test/table/test_70_lrskip.tex22
-rw-r--r--macros/latex/contrib/cals/test/template.txt34
-rw-r--r--macros/latex/contrib/cals/test/visual_tables/test_10_simple_2x2_with_parbreak.chk0
-rw-r--r--macros/latex/contrib/cals/test/visual_tables/test_10_simple_2x2_with_parbreak.pngbin0 -> 29731 bytes
-rw-r--r--macros/latex/contrib/cals/test/visual_tables/test_10_simple_2x2_with_parbreak.tex11
-rw-r--r--macros/latex/contrib/cals/test/visual_tables/test_20_thead_tfoot.chk0
-rw-r--r--macros/latex/contrib/cals/test/visual_tables/test_20_thead_tfoot.pngbin0 -> 36579 bytes
-rw-r--r--macros/latex/contrib/cals/test/visual_tables/test_20_thead_tfoot.tex20
-rw-r--r--macros/latex/contrib/cals/test/visual_tables/test_30_tbreak.chk0
-rw-r--r--macros/latex/contrib/cals/test/visual_tables/test_30_tbreak.pngbin0 -> 40690 bytes
-rw-r--r--macros/latex/contrib/cals/test/visual_tables/test_30_tbreak.tex27
-rw-r--r--macros/latex/contrib/cals/test/visual_tables/test_40_span.chk0
-rw-r--r--macros/latex/contrib/cals/test/visual_tables/test_40_span.pngbin0 -> 42576 bytes
-rw-r--r--macros/latex/contrib/cals/test/visual_tables/test_40_span.tex52
112 files changed, 3277 insertions, 0 deletions
diff --git a/macros/latex/contrib/cals/test/README b/macros/latex/contrib/cals/test/README
new file mode 100644
index 0000000000..a6c837b7e3
--- /dev/null
+++ b/macros/latex/contrib/cals/test/README
@@ -0,0 +1,15 @@
+Unit tests for the CALS package. Usage:
+
+$ export TEXINPUTS=`pwd`/../dev:
+$ mkdir tmp
+$ python support/run_tests.py
+ or, to execute a subset of the tests,
+$ python support/run_tests.py cell/test_10
+
+Expect that the tests in the directory "visual_tables" fail.
+Depending on the OS and TeX distro version, the font drawing
+might look different.
+17 Nov 2014: the tests in "visual_tables" are disabled.
+
+Probably I need to package the unit testing code as a separate
+package and publish an article about it.
diff --git a/macros/latex/contrib/cals/test/cell/test_10_create.chk b/macros/latex/contrib/cals/test/cell/test_10_create.chk
new file mode 100644
index 0000000000..e30f50c4cd
--- /dev/null
+++ b/macros/latex/contrib/cals/test/cell/test_10_create.chk
@@ -0,0 +1,45 @@
+> \boxXX=
+\vbox(40.0+0.0)x200.0
+.\glue 14.0
+.\glue 0.0 plus -1.0
+.\glue(\parskip) 0.0 plus 1.0
+.\glue(\baselineskip) 6.0
+.\hbox(3.0+2.0)x200.0, glue set 174.0fil
+..\glue(\leftskip) 12.0
+..\rule(3.0+2.0)x1.0
+..\penalty 10000
+..\glue(\parfillskip) 0.0 plus 1.0fil
+..\glue(\rightskip) 13.0
+.\glue 0.0 plus 1.0fil
+.\glue 15.0
+> \boxXX=
+\vbox(-60.0+0.0)x200.0
+.\glue -100.0
+.\glue 14.0
+.\glue 0.0 plus -1.0
+.\glue(\parskip) 0.0 plus 1.0
+.\glue(\baselineskip) 6.0
+.\hbox(3.0+2.0)x200.0, glue set 174.0fil
+..\glue(\leftskip) 12.0
+..\rule(3.0+2.0)x1.0
+..\penalty 10000
+..\glue(\parfillskip) 0.0 plus 1.0fil
+..\glue(\rightskip) 13.0
+.\glue 0.0 plus 1.0fil
+.\glue 15.0
+%
+% Zero width
+%
+> \boxXX=
+\vbox(50.0+0.0)x200.0
+.\glue 0.0
+.\glue 0.0 plus -1.0
+.\glue(\parskip) 0.0 plus 1.0
+.\glue(\lineskip) 0.0
+.\hbox(50.0+0.0)x200.0
+..\rule(50.0+0.0)x200.0
+..\penalty 10000
+..\glue(\parfillskip) 0.0 plus 1.0fil
+..\glue(\rightskip) 0.0
+.\glue 0.0 plus 1.0fil
+.\glue 0.0
diff --git a/macros/latex/contrib/cals/test/cell/test_10_create.tex b/macros/latex/contrib/cals/test/cell/test_10_create.tex
new file mode 100644
index 0000000000..6692b6e614
--- /dev/null
+++ b/macros/latex/contrib/cals/test/cell/test_10_create.tex
@@ -0,0 +1,22 @@
+\cals@paddingL=12pt \relax
+\cals@paddingR=13pt \relax
+\setlength{\cals@paddingT}{14pt}
+\setlength{\cals@paddingB}{15pt}
+
+\cals@paddingD=1pt \relax
+\setlength{\baselineskip}{10pt}
+
+\def\cals@celll@end{}
+
+\setbox0=\cals@cell{200pt}{0pt}{\noindent \vrule height3pt depth2pt width1pt}
+\showbox0
+
+\setbox0=\cals@cell{200pt}{100pt}{\noindent \vrule height3pt depth2pt width1pt}
+\showbox0
+
+%
+% Zero width makes exact size
+%
+\cals@setpadding{}\cals@setcellprevdepth{}
+\setbox0=\cals@cell{200pt}{0pt}{\noindent \vrule height50pt depth0pt width200pt}
+\showbox0
diff --git a/macros/latex/contrib/cals/test/cell/test_20_colwidth.chk b/macros/latex/contrib/cals/test/cell/test_20_colwidth.chk
new file mode 100644
index 0000000000..9bc5c27f1c
--- /dev/null
+++ b/macros/latex/contrib/cals/test/cell/test_20_colwidth.chk
@@ -0,0 +1,10 @@
+> \cals@colwidths=macro:
+->{100pt}{200pt}.
+> \llt@car=macro:
+->100pt.
+> \cals@colwidths=macro:
+->{200pt}{100pt}.
+> \llt@car=macro:
+->200pt.
+> \cals@colwidths=macro:
+->{100pt}{200pt}.
diff --git a/macros/latex/contrib/cals/test/cell/test_20_colwidth.tex b/macros/latex/contrib/cals/test/cell/test_20_colwidth.tex
new file mode 100644
index 0000000000..ec8a1f3f9a
--- /dev/null
+++ b/macros/latex/contrib/cals/test/cell/test_20_colwidth.tex
@@ -0,0 +1,9 @@
+\def\x{200pt}
+\colwidths{{100pt}{\x}}
+\show\cals@colwidths
+\llt@rot\cals@colwidths
+\show\llt@car
+\show\cals@colwidths
+\llt@rot\cals@colwidths
+\show\llt@car
+\show\cals@colwidths
diff --git a/macros/latex/contrib/cals/test/cell/test_30_decor.chk b/macros/latex/contrib/cals/test/cell/test_30_decor.chk
new file mode 100644
index 0000000000..6b6be1d2cf
--- /dev/null
+++ b/macros/latex/contrib/cals/test/cell/test_30_decor.chk
@@ -0,0 +1,38 @@
+> \boxXX=
+\hbox(0.0+0.0)x100.0
+.\pdfcolorstack 0 push {1 0 0 rg 1 0 0 RG}
+.\rule(*+0.0)x100.0
+.\pdfcolorstack 0 pop
+.\glue -100.0
+.\glue 100.0
+> \cals@lastWidth=\relax.
+%
+%
+> \boxXX=
+\hbox(0.0+0.0)x300.0
+.\pdfcolorstack 0 push {1 0 0 rg 1 0 0 RG}
+.\rule(*+0.0)x100.0
+.\pdfcolorstack 0 pop
+.\glue -100.0
+.\glue 100.0
+.\pdfcolorstack 0 push {0 1 0 rg 0 1 0 RG}
+.\rule(*+0.0)x200.0
+.\pdfcolorstack 0 pop
+.\glue -200.0
+.\glue -1.0
+.\rule(*+0.0)x2.0
+.\glue -1.0
+.\glue 200.0
+> \cals@current@rs@above=macro:
+->{{100pt}{0pt}{2pt}\relax }.
+> \cals@current@rs@below=macro:
+->{{100pt}{0pt}{2pt}\relax }.
+> \cals@lastWidth=macro:
+->4pt.
+%
+%
+%
+> \cals@current@rs@above=macro:
+->{{100pt}{0pt}{2pt}\relax }{{200pt}{2pt}{4pt}{3pt}}.
+> \cals@current@rs@below=macro:
+->{{100pt}{0pt}{2pt}\relax }{{200pt}{2pt}{4pt}{5pt}}.
diff --git a/macros/latex/contrib/cals/test/cell/test_30_decor.tex b/macros/latex/contrib/cals/test/cell/test_30_decor.tex
new file mode 100644
index 0000000000..ee65891a60
--- /dev/null
+++ b/macros/latex/contrib/cals/test/cell/test_30_decor.tex
@@ -0,0 +1,29 @@
+\def\cals@framecs@width{0pt}
+\def\cals@cs@width{1pt}
+\def\cals@bgcolor{red}
+
+\let\cals@borderL=\relax
+\let\cals@borderR=\relax
+\let\cals@borderT=\relax
+\let\cals@borderB=\relax
+
+\colwidths{{100pt}{200pt}}
+\cals@decor@begin
+
+\cell{aaaa}
+\showbox\cals@current@cs
+\show\cals@lastWidth
+\def\cals@borderL{2pt}
+\def\cals@borderT{3pt}
+\def\cals@borderR{4pt}
+\def\cals@borderB{5pt}
+\def\cals@bgcolor{green}
+\cell{b}
+\showbox\cals@current@cs
+\show\cals@current@rs@above
+\show\cals@current@rs@below
+\show\cals@lastWidth
+
+\cals@decor@end\cals@borderR
+\show\cals@current@rs@above
+\show\cals@current@rs@below
diff --git a/macros/latex/contrib/cals/test/cell/test_40_width.chk b/macros/latex/contrib/cals/test/cell/test_40_width.chk
new file mode 100644
index 0000000000..b3af972f4a
--- /dev/null
+++ b/macros/latex/contrib/cals/test/cell/test_40_width.chk
@@ -0,0 +1,26 @@
+> \boxXX=
+\hbox(20.0+0.0)x300.0
+.\vbox(0.0+0.0)x100.0
+..\glue 0.0
+..\glue 0.0 plus -1.0
+..\glue 0.0 plus 1.0fil
+..\glue 0.0
+.\vbox(20.0+0.0)x200.0
+..\glue 0.0
+..\glue 0.0 plus -1.0
+..\rule(20.0+0.0)x300.0
+..\glue 0.0 plus 1.0fil
+..\glue 0.0
+> \boxXX=
+\hbox(20.0+0.0)x300.0
+.\vbox(20.0+0.0)x100.0, glue set 20.0fil
+..\glue 0.0
+..\glue 0.0 plus -1.0
+..\glue 0.0 plus 1.0fil
+..\glue 0.0
+.\vbox(20.0+0.0)x200.0
+..\glue 0.0
+..\glue 0.0 plus -1.0
+..\rule(20.0+0.0)x300.0
+..\glue 0.0 plus 1.0fil
+..\glue 0.0
diff --git a/macros/latex/contrib/cals/test/cell/test_40_width.tex b/macros/latex/contrib/cals/test/cell/test_40_width.tex
new file mode 100644
index 0000000000..0f3816cfd9
--- /dev/null
+++ b/macros/latex/contrib/cals/test/cell/test_40_width.tex
@@ -0,0 +1,15 @@
+%
+% Force width if force major
+%
+\begin{calstable}
+\cals@setpadding{}
+\cals@setcellprevdepth{}
+\colwidths{{100pt}{200pt}}
+\brow
+\cell{}
+\cell{\hrule width300pt height20pt depth0pt}
+\showbox\cals@current@row
+\cals@reheight@cells\cals@current@row
+\showbox\cals@current@row
+\erow
+\end{calstable}
diff --git a/macros/latex/contrib/cals/test/cell/test_50_hooks.chk b/macros/latex/contrib/cals/test/cell/test_50_hooks.chk
new file mode 100644
index 0000000000..7ab3e2dbc3
--- /dev/null
+++ b/macros/latex/contrib/cals/test/cell/test_50_hooks.chk
@@ -0,0 +1,4 @@
+> the letter A.
+> the letter B.
+> the letter C.
+> the letter D.
diff --git a/macros/latex/contrib/cals/test/cell/test_50_hooks.tex b/macros/latex/contrib/cals/test/cell/test_50_hooks.tex
new file mode 100644
index 0000000000..21ef65f571
--- /dev/null
+++ b/macros/latex/contrib/cals/test/cell/test_50_hooks.tex
@@ -0,0 +1,12 @@
+\begin{calstable}
+\colwidths{{100pt}}
+\brow
+\def\cals@AtBeginCell{\show A}
+\def\cals@AtEndCell{\show B}
+\cell{a}
+\def\cals@AtBeginCell{\show C}
+\def\cals@AtEndCell{\show D}
+\nullcell{ltb}
+\nullcell{rtb}\spancontent{b}
+\erow
+\end{calstable}
diff --git a/macros/latex/contrib/cals/test/colsep/test_10_outone.chk b/macros/latex/contrib/cals/test/colsep/test_10_outone.chk
new file mode 100644
index 0000000000..40befd43b3
--- /dev/null
+++ b/macros/latex/contrib/cals/test/colsep/test_10_outone.chk
@@ -0,0 +1,62 @@
+%
+% test1
+%
+> \cals@lastLeftWidth=macro:
+->0pt.
+> \boxXX=
+\hbox(0.0+0.0)x0.0
+%
+% test2
+%
+> \cals@lastLeftWidth=macro:
+->4pt.
+> \boxXX=
+\hbox(0.0+0.0)x50.0
+.\pdfcolorstack 0 push {1 0 0 rg 1 0 0 RG}
+.\rule(*+0.0)x50.0
+.\pdfcolorstack 0 pop
+.\glue -50.0
+.\glue -2.0
+.\rule(*+0.0)x4.0
+.\glue -2.0
+.\glue 50.0
+%
+% test3
+%
+> \cals@lastLeftWidth=macro:
+->2pt.
+> \boxXX=
+\hbox(0.0+0.0)x100.0
+.\pdfcolorstack 0 push {0 1 0 rg 0 1 0 RG}
+.\rule(*+0.0)x100.0
+.\pdfcolorstack 0 pop
+.\glue -100.0
+.\glue -1.0
+.\rule(*+0.0)x2.0
+.\glue -1.0
+.\glue 100.0
+%
+% test4
+%
+> \boxXX=
+\hbox(0.0+0.0)x0.0
+.\glue -1.0
+.\rule(*+0.0)x2.0
+.\glue -1.0
+%
+% test5
+%
+> \boxXX=
+\hbox(0.0+0.0)x300.0
+.\glue 300.0
+%
+% test6
+%
+> \boxXX=
+\hbox(0.0+0.0)x0.0
+.\glue 0.0
+%
+% test7
+%
+> \boxXX=
+\hbox(0.0+0.0)x0.0
diff --git a/macros/latex/contrib/cals/test/colsep/test_10_outone.tex b/macros/latex/contrib/cals/test/colsep/test_10_outone.tex
new file mode 100644
index 0000000000..fec00899ac
--- /dev/null
+++ b/macros/latex/contrib/cals/test/colsep/test_10_outone.tex
@@ -0,0 +1,57 @@
+%
+%
+\def\cals@cs@width{2pt}
+\def\cals@bgcolor{green}
+
+%
+% cals@cs@outone:
+% #1: cell width
+% #2: left border width
+% #3: background color
+%
+%
+% test1: everything disabled
+%
+\setbox0=\hbox{\cals@cs@outOne\relax{0pt}{}%
+\show\cals@lastLeftWidth
+}
+\showbox0
+
+%
+% test2: everything specified
+%
+\setbox0=\hbox{\cals@cs@outOne{50pt}{4pt}{red}%
+\show\cals@lastLeftWidth
+}
+\showbox0
+%
+% test3: use defaults for everything
+%
+\setbox0=\hbox{\cals@cs@outOne{100pt}\relax\relax%
+\show\cals@lastLeftWidth
+}
+\showbox0
+%
+% test4: background color ignored if no cell width
+%
+\setbox0=\hbox{\cals@cs@outOne\relax{2pt}{green}}
+\showbox0
+%
+% test5: defaults are no colors, no borders
+%
+\def\cals@cs@width{0pt}
+\def\cals@bgcolor{}
+\setbox0=\hbox{\cals@cs@outOne{300pt}\relax\relax}
+\showbox0
+%
+% test6: cell width: 0pt != \relax
+%
+\setbox0=\hbox{\cals@cs@outOne{0pt}{0pt}{}}
+\showbox0
+
+%
+% test7: only \relax
+% (Bug hunting for a space)
+%
+\setbox0=\hbox{\cals@cs@outOne\relax\relax\relax}
+\showbox0
diff --git a/macros/latex/contrib/cals/test/colsep/test_20_row.chk b/macros/latex/contrib/cals/test/colsep/test_20_row.chk
new file mode 100644
index 0000000000..01e57020f1
--- /dev/null
+++ b/macros/latex/contrib/cals/test/colsep/test_20_row.chk
@@ -0,0 +1,91 @@
+%
+% Test 1
+%
+> \boxXX=
+\hbox(0.0+0.0)x210.0
+% first cell
+.\pdfcolorstack 0 push {0 1 0 rg 0 1 0 RG}
+.\rule(*+0.0)x100.0
+.\pdfcolorstack 0 pop
+.\glue -100.0
+.\glue -1.5
+.\rule(*+0.0)x3.0
+.\glue -1.5
+.\glue 100.0
+% second cell
+.\pdfcolorstack 0 push {1 0 0 rg 1 0 0 RG}
+.\rule(*+0.0)x110.0
+.\pdfcolorstack 0 pop
+.\glue -110.0
+.\glue -2.5
+.\rule(*+0.0)x5.0
+.\glue -2.5
+.\glue 110.0
+% right frame
+.\glue -3.0
+.\rule(*+0.0)x6.0
+.\glue -3.0
+%
+% Test2 (no columns, only frame border)
+%
+> \boxXX=
+\hbox(0.0+0.0)x0.0
+.\glue -1.0
+.\rule(*+0.0)x2.0
+.\glue -1.0
+%
+% Test3 (defaults are used)
+%
+> \boxXX=
+\hbox(0.0+0.0)x250.0
+% first cell
+.\pdfcolorstack 0 push {0 g 0 G}
+.\rule(*+0.0)x120.0
+.\pdfcolorstack 0 pop
+.\glue -120.0
+.\glue -1.0
+.\rule(*+0.0)x2.0
+.\glue -1.0
+.\glue 120.0
+% second cell
+.\pdfcolorstack 0 push {0 g 0 G}
+.\rule(*+0.0)x130.0
+.\pdfcolorstack 0 pop
+.\glue -130.0
+.\glue -0.5
+.\rule(*+0.0)x1.0
+.\glue -0.5
+.\glue 130.0
+% right frame
+.\glue -1.0
+.\rule(*+0.0)x2.0
+.\glue -1.0
+%
+% Test 4: frame width is bigger as user-specified
+%
+> \boxXX=
+\hbox(0.0+0.0)x100.0
+.\glue -1.5
+.\rule(*+0.0)x3.0
+.\glue -1.5
+.\glue 100.0
+.\glue -2.0
+.\rule(*+0.0)x4.0
+.\glue -2.0
+> \boxXX=
+\hbox(0.0+0.0)x100.0
+.\glue -1.5
+.\rule(*+0.0)x3.0
+.\glue -1.5
+.\glue 100.0
+.\glue -2.0
+.\rule(*+0.0)x4.0
+.\glue -2.0
+%
+% Bug hunting for a space
+%
+> \boxXX=
+\hbox(0.0+0.0)x0.0
+.\glue -5.0
+.\rule(*+0.0)x10.0
+.\glue -5.0
diff --git a/macros/latex/contrib/cals/test/colsep/test_20_row.tex b/macros/latex/contrib/cals/test/colsep/test_20_row.tex
new file mode 100644
index 0000000000..db97970dd3
--- /dev/null
+++ b/macros/latex/contrib/cals/test/colsep/test_20_row.tex
@@ -0,0 +1,55 @@
+\def\cals@cs@width{1pt}
+\def\cals@framecs@width{2pt}
+\def\cals@bgcolor{black}
+
+%
+% Normal use
+%
+\cals@csrow@begin
+\def\rborder{4pt}
+\cals@csrow@nextcell{100pt}{3pt}\rborder{green}
+\def\rborder{6pt}
+\cals@csrow@nextcell{110pt}{5pt}\rborder{red}
+\cals@csrow@end
+\showbox\cals@current@cs
+
+%
+% What happens if we have no columns (should never happen)
+%
+\cals@csrow@begin
+\cals@csrow@end
+\showbox\cals@current@cs
+
+%
+% Defaults are used
+%
+\cals@csrow@begin
+\cals@csrow@nextcell{120pt}\relax\relax\relax
+\cals@csrow@nextcell{130pt}\relax\relax\relax
+\cals@csrow@end
+\showbox\cals@current@cs
+
+%
+% test: left frame is bigger as the user-specified width:
+% we should not use the maximal width, but drop the default.
+% (The first run is not for the test, but for comparation.)
+%
+\def\rborder{4pt}
+\def\cals@framecs@width{2pt}
+\cals@csrow@begin
+\cals@csrow@nextcell{100pt}{3pt}\rborder{}
+\cals@csrow@end
+\showbox\cals@current@cs
+\def\cals@framecs@width{10pt}
+\cals@csrow@begin
+\cals@csrow@nextcell{100pt}{3pt}\rborder{}
+\cals@csrow@end
+\showbox\cals@current@cs
+
+%
+% Bug hunting (a space)
+%
+\setbox\cals@current@cs=\hbox{}
+\let\cals@lastWidth=\relax
+\cals@csrow@nextcell\relax\cals@framecs@width\relax\relax
+\showbox\cals@current@cs
diff --git a/macros/latex/contrib/cals/test/decoration/test_10_withwidth2.chk b/macros/latex/contrib/cals/test/decoration/test_10_withwidth2.chk
new file mode 100644
index 0000000000..8921cc46ba
--- /dev/null
+++ b/macros/latex/contrib/cals/test/decoration/test_10_withwidth2.chk
@@ -0,0 +1,7 @@
+user width: 5pt
+no width
+default width: 2pt
+no width
+> \boxXX=
+\hbox(0.0+0.0)x0.0
+.\hbox(0.0+0.0)x0.0
diff --git a/macros/latex/contrib/cals/test/decoration/test_10_withwidth2.tex b/macros/latex/contrib/cals/test/decoration/test_10_withwidth2.tex
new file mode 100644
index 0000000000..40f4832b87
--- /dev/null
+++ b/macros/latex/contrib/cals/test/decoration/test_10_withwidth2.tex
@@ -0,0 +1,32 @@
+\cals@withWidthII{1pt}{5pt}\iftrue
+ \PackageInfo{test}{user width: \cals@width}
+\else
+ \PackageInfo{test}{fail}
+\fi
+
+\def\defaultDimen{2pt}
+\cals@withWidthII\defaultDimen{0pt}\iftrue
+ \PackageInfo{test}{fail}
+\else
+ \PackageInfo{test}{no width}
+\fi
+
+\cals@withWidthII\defaultDimen\relax\iftrue
+ \PackageInfo{test}{default width: \cals@width}
+\else
+ \PackageInfo{test}{fail}
+\fi
+
+\cals@withWidthII{0pt}\relax\iftrue
+ \PackageInfo{test}{fail}
+\else
+ \PackageInfo{test}{no width}
+\fi
+
+%
+% Bug hunting: a space
+%
+\def\cals@default@cs@width{4pt}
+\setbox0=\hbox{\hbox{}%
+\cals@withWidthII\cals@default@cs@width\relax\iftrue \fi}
+\showbox0
diff --git a/macros/latex/contrib/cals/test/decoration/test_20_withcolor2.chk b/macros/latex/contrib/cals/test/decoration/test_20_withcolor2.chk
new file mode 100644
index 0000000000..a959bc92cf
--- /dev/null
+++ b/macros/latex/contrib/cals/test/decoration/test_20_withcolor2.chk
@@ -0,0 +1,4 @@
+user color: blue
+(user) no color
+default color: black
+(default) no color
diff --git a/macros/latex/contrib/cals/test/decoration/test_20_withcolor2.tex b/macros/latex/contrib/cals/test/decoration/test_20_withcolor2.tex
new file mode 100644
index 0000000000..9bb4c78f4d
--- /dev/null
+++ b/macros/latex/contrib/cals/test/decoration/test_20_withcolor2.tex
@@ -0,0 +1,23 @@
+\cals@withColorII{black}{blue}\iftrue
+ \PackageInfo{test}{user color: \cals@color }
+\else
+ \PackageInfo{test}{fail}
+\fi
+
+\cals@withColorII{black}{}\iftrue
+ \PackageInfo{test}{fail}
+\else
+ \PackageInfo{test}{(user) no color}
+\fi
+
+\cals@withColorII{black}\relax\iftrue
+ \PackageInfo{test}{default color: \cals@color}
+\else
+ \PackageInfo{test}{fail}
+\fi
+
+\cals@withColorII{}\relax\iftrue
+ \PackageInfo{test}{fail}
+\else
+ \PackageInfo{test}{(default) no color}
+\fi
diff --git a/macros/latex/contrib/cals/test/decoration/test_30_halfwidth.chk b/macros/latex/contrib/cals/test/decoration/test_30_halfwidth.chk
new file mode 100644
index 0000000000..7f00f1944e
--- /dev/null
+++ b/macros/latex/contrib/cals/test/decoration/test_30_halfwidth.chk
@@ -0,0 +1,3 @@
+half of 200pt: 100.0pt
+half of 0pt: 0.0pt
+half of 100pt: 50.0pt
diff --git a/macros/latex/contrib/cals/test/decoration/test_30_halfwidth.tex b/macros/latex/contrib/cals/test/decoration/test_30_halfwidth.tex
new file mode 100644
index 0000000000..a9aee3cab4
--- /dev/null
+++ b/macros/latex/contrib/cals/test/decoration/test_30_halfwidth.tex
@@ -0,0 +1,9 @@
+\def\cals@width{200pt}
+\cals@halfWidthToDimen0 \cals@width
+\PackageInfo{test}{half of 200pt: \the\dimen0}
+
+\cals@halfWidthToDimen0 {0pt}
+\PackageInfo{test}{half of 0pt: \the\dimen0}
+
+\cals@halfWidthToDimen2{100pt}
+\PackageInfo{test}{half of 100pt: \the\dimen2}
diff --git a/macros/latex/contrib/cals/test/decoration/test_50_maxwidth.chk b/macros/latex/contrib/cals/test/decoration/test_50_maxwidth.chk
new file mode 100644
index 0000000000..33b32e6078
--- /dev/null
+++ b/macros/latex/contrib/cals/test/decoration/test_50_maxwidth.chk
@@ -0,0 +1,9 @@
+10pt vs relax: 10pt
+relax vs 20pt: 20pt
+relax vs relax: \cals@width
+30pt vs 40pt: 40pt
+60pt vs 50pt: 60pt
+70pt vs 70pt: 70pt
+regression, recursion avoid: 50pt
+regression, recursion avoid: 50pt
+regression, recursion avoid: 50pt
diff --git a/macros/latex/contrib/cals/test/decoration/test_50_maxwidth.tex b/macros/latex/contrib/cals/test/decoration/test_50_maxwidth.tex
new file mode 100644
index 0000000000..e3e899c1f8
--- /dev/null
+++ b/macros/latex/contrib/cals/test/decoration/test_50_maxwidth.tex
@@ -0,0 +1,28 @@
+\cals@maxWidth{10pt}\relax
+\PackageInfo{test}{10pt vs relax: \cals@width}
+
+\cals@maxWidth\relax{20pt}
+\PackageInfo{test}{relax vs 20pt: \cals@width}
+
+\cals@maxWidth\relax\relax
+\PackageInfo{test}{relax vs relax: \cals@width}
+
+\cals@maxWidth{30pt}{40pt}
+\PackageInfo{test}{30pt vs 40pt: \cals@width}
+
+\cals@maxWidth{60pt}{50pt}
+\PackageInfo{test}{60pt vs 50pt: \cals@width}
+
+\cals@maxWidth{70pt}{70pt}
+\PackageInfo{test}{70pt vs 70pt: \cals@width}
+
+%
+% Regression test: avoid recursion
+%
+\def\cals@width{50pt}
+\cals@maxWidth{10pt}\cals@width
+\PackageInfo{test}{regression, recursion avoid: \cals@width}
+\cals@maxWidth\cals@width{10pt}
+\PackageInfo{test}{regression, recursion avoid: \cals@width}
+\cals@maxWidth\cals@width\cals@width
+\PackageInfo{test}{regression, recursion avoid: \cals@width}
diff --git a/macros/latex/contrib/cals/test/decoration/test_60_row.chk b/macros/latex/contrib/cals/test/decoration/test_60_row.chk
new file mode 100644
index 0000000000..6c96c188b8
--- /dev/null
+++ b/macros/latex/contrib/cals/test/decoration/test_60_row.chk
@@ -0,0 +1,54 @@
+%
+% Empty row
+%
+> \boxXX=
+\hbox(0.0+0.0)x0.0
+> \cals@current@rs@above=macro:
+->.
+> \cals@current@rs@below=macro:
+->.
+%
+% One cell
+%
+> \boxXX=
+\hbox(0.0+0.0)x100.0
+.\glue 100.0
+> \cals@current@rs@above=macro:
+->{{100pt}{0pt}{0pt}\relax }.
+> \cals@current@rs@below=macro:
+->{{100pt}{0pt}{0pt}\relax }.
+%
+% Two cells, no overrides
+%
+> \boxXX=
+\hbox(0.0+0.0)x300.0
+.\glue 100.0
+.\glue -1.0
+.\rule(*+0.0)x2.0
+.\glue -1.0
+.\glue 200.0
+> \cals@current@rs@above=macro:
+->{{100pt}{0pt}{2pt}\relax }{{200pt}{2pt}{0pt}\relax }.
+> \cals@current@rs@below=macro:
+->{{100pt}{0pt}{2pt}\relax }{{200pt}{2pt}{0pt}\relax }.
+%
+% Two cells, no overrides
+%
+> \boxXX=
+\hbox(0.0+0.0)x300.0
+.\pdfcolorstack 0 push {0 1 0 rg 0 1 0 RG}
+.\rule(*+0.0)x100.0
+.\pdfcolorstack 0 pop
+.\glue -100.0
+.\glue -2.0
+.\rule(*+0.0)x4.0
+.\glue -2.0
+.\glue 100.0
+.\glue -3.0
+.\rule(*+0.0)x6.0
+.\glue -3.0
+.\glue 200.0
+> \cals@current@rs@above=macro:
+->{{100pt}{4pt}{6pt}\relax }{{200pt}{6pt}{0pt}{8pt}}.
+> \cals@current@rs@below=macro:
+->{{100pt}{4pt}{6pt}\relax }{{200pt}{6pt}{0pt}{10pt}}.
diff --git a/macros/latex/contrib/cals/test/decoration/test_60_row.tex b/macros/latex/contrib/cals/test/decoration/test_60_row.tex
new file mode 100644
index 0000000000..0ee4395383
--- /dev/null
+++ b/macros/latex/contrib/cals/test/decoration/test_60_row.tex
@@ -0,0 +1,65 @@
+\def\contentI{\noindent\vrule height10pt depth0pt width30pt\hfil}
+\def\contentII{\noindent\vrule height20pt depth2pt width60pt\hfil}
+
+\def\cals@cs@width{2pt}
+\def\cals@framecs@width{0pt}
+\def\cals@bgcolor{}
+
+\def\wC{100pt}
+\def\wCC{200pt}
+
+%
+% Empty row
+%
+\cals@decor@begin
+\cals@decor@end
+\showbox\cals@current@cs
+\show\cals@current@rs@above
+\show\cals@current@rs@below
+
+%
+% One cell, no overrides
+%
+\cals@decor@begin
+\let\cals@borderL=\relax
+\let\cals@borderR=\relax
+\let\cals@borderT=\relax
+\let\cals@borderB=\relax
+\def\cals@bgcolor{}
+\cals@decor@next\wC{\contentI}
+\cals@decor@end
+\showbox\cals@current@cs
+\show\cals@current@rs@above
+\show\cals@current@rs@below
+
+%
+% Two cells, no overrides
+%
+\cals@decor@begin
+\cals@decor@next\wC{\contentI}
+\cals@decor@next\wCC{\contentII}
+\cals@decor@end
+\showbox\cals@current@cs
+\show\cals@current@rs@above
+\show\cals@current@rs@below
+
+%
+% Two cells, overrides
+%
+\cals@decor@begin
+\def\cals@borderL{4pt}
+\def\cals@borderR{6pt}
+\let\cals@borderT=\relax
+\let\cals@borderB=\relax
+\def\cals@bgcolor{green}
+\cals@decor@next\wC{\contentI}
+\let\cals@borderL=\relax
+\let\cals@borderR=\relax
+\def\cals@borderT{8pt}
+\def\cals@borderB{10pt}
+\def\cals@bgcolor{}
+\cals@decor@next\wCC{\contentII}
+\cals@decor@end
+\showbox\cals@current@cs
+\show\cals@current@rs@above
+\show\cals@current@rs@below
diff --git a/macros/latex/contrib/cals/test/decoration/test_70_align.chk b/macros/latex/contrib/cals/test/decoration/test_70_align.chk
new file mode 100644
index 0000000000..7213fce686
--- /dev/null
+++ b/macros/latex/contrib/cals/test/decoration/test_70_align.chk
@@ -0,0 +1,8 @@
+> 2.0pt plus 1.0fill.
+> 4.0pt plus 1.0fill.
+%
+> 2.0pt plus 1.0fill.
+> 4.0pt.
+%
+> 2.0pt.
+> 4.0pt.
diff --git a/macros/latex/contrib/cals/test/decoration/test_70_align.tex b/macros/latex/contrib/cals/test/decoration/test_70_align.tex
new file mode 100644
index 0000000000..a34b3058e3
--- /dev/null
+++ b/macros/latex/contrib/cals/test/decoration/test_70_align.tex
@@ -0,0 +1,15 @@
+\cals@paddingL=2pt \relax
+\cals@paddingR=4pt \relax
+
+
+\alignC
+\showthe\cals@paddingL
+\showthe\cals@paddingR
+
+\alignR
+\showthe\cals@paddingL
+\showthe\cals@paddingR
+
+\alignL
+\showthe\cals@paddingL
+\showthe\cals@paddingR
diff --git a/macros/latex/contrib/cals/test/llt/test_10_cons_rot.chk b/macros/latex/contrib/cals/test/llt/test_10_cons_rot.chk
new file mode 100644
index 0000000000..e18933034a
--- /dev/null
+++ b/macros/latex/contrib/cals/test/llt/test_10_cons_rot.chk
@@ -0,0 +1,23 @@
+> \lst=macro:
+->{abcd}{efgh}{ijkl}.
+> \lst=macro:
+->{efgh}{ijkl}{abcd}.
+> \llt@car=macro:
+->abcd.
+> \lst=macro:
+->{abcd}{efgh}.
+> \lst=macro:
+->{efgh}{abcd}.
+> \llt@car=macro:
+->abcd.
+> \lst=macro:
+->{abcd}.
+> \lst=macro:
+->{abcd}.
+> \llt@car=macro:
+->abcd.
+> \lst=macro:
+->.
+> \lst=macro:
+->.
+> \llt@car=\relax.
diff --git a/macros/latex/contrib/cals/test/llt/test_10_cons_rot.tex b/macros/latex/contrib/cals/test/llt/test_10_cons_rot.tex
new file mode 100644
index 0000000000..20312cd0ec
--- /dev/null
+++ b/macros/latex/contrib/cals/test/llt/test_10_cons_rot.tex
@@ -0,0 +1,23 @@
+\def\abcd{abcd}
+\def\efgh{efgh}
+\def\ijkl{ijkl}
+\def\rotandshow{
+\show\lst
+\llt@rot{\lst}
+\show\lst
+\show\llt@car}
+
+\def\lst{}
+\llt@cons{\ijkl}{\lst}
+\llt@cons{\efgh}{\lst}
+\llt@cons{\abcd}{\lst}
+\rotandshow
+\def\lst{}
+\llt@cons{\efgh}{\lst}
+\llt@cons{\abcd}{\lst}
+\rotandshow
+\def\lst{}
+\llt@cons{\abcd}{\lst}
+\rotandshow
+\def\lst{}
+\rotandshow
diff --git a/macros/latex/contrib/cals/test/llt/test_20_snoc_decons.chk b/macros/latex/contrib/cals/test/llt/test_20_snoc_decons.chk
new file mode 100644
index 0000000000..10010a8001
--- /dev/null
+++ b/macros/latex/contrib/cals/test/llt/test_20_snoc_decons.chk
@@ -0,0 +1,14 @@
+> \lst=macro:
+->.
+> \lst=macro:
+->{snoc-a}.
+> \lst=macro:
+->{snoc-a}{snoc-b}.
+> \lst=macro:
+->{snoc-b}.
+> \lst=macro:
+->.
+> \lst=macro:
+->{}.
+> \lst=macro:
+->.
diff --git a/macros/latex/contrib/cals/test/llt/test_20_snoc_decons.tex b/macros/latex/contrib/cals/test/llt/test_20_snoc_decons.tex
new file mode 100644
index 0000000000..7a61a785f5
--- /dev/null
+++ b/macros/latex/contrib/cals/test/llt/test_20_snoc_decons.tex
@@ -0,0 +1,18 @@
+\def\lst{}
+\show\lst
+\def\snoca{snoc-a}
+\def\snocb{snoc-b}
+\llt@snoc{\lst}{\snoca}
+\show\lst
+\llt@snoc{\lst}{\snocb}
+\show\lst
+\llt@decons{\lst}
+\show\lst
+\llt@decons{\lst}
+\show\lst
+
+\def\lst{{}{}}
+\llt@decons{\lst}
+\show\lst
+\llt@decons{\lst}
+\show\lst
diff --git a/macros/latex/contrib/cals/test/llt/test_30_all.chk b/macros/latex/contrib/cals/test/llt/test_30_all.chk
new file mode 100644
index 0000000000..37803a2639
--- /dev/null
+++ b/macros/latex/contrib/cals/test/llt/test_30_all.chk
@@ -0,0 +1,24 @@
+> \lst=macro:
+->{\multiply \cals@borderwidthL by 3\relax }{}.
+> \llt@car=macro:
+->.
+> \lst=macro:
+->{item1}{item2}.
+> \llt@car=macro:
+->item3.
+> \lst=macro:
+->.
+> \lst=macro:
+->{bbb}.
+> \lst=macro:
+->{bbb}{ccc}.
+> \lst=macro:
+->{aaa}{bbb}{ccc}.
+> \llt@car=macro:
+->aaa.
+> \lst=macro:
+->{bbb}{ccc}.
+> \llt@car=macro:
+->bbb.
+> \lst=macro:
+->{ccc}{bbb}.
diff --git a/macros/latex/contrib/cals/test/llt/test_30_all.tex b/macros/latex/contrib/cals/test/llt/test_30_all.tex
new file mode 100644
index 0000000000..f683984d24
--- /dev/null
+++ b/macros/latex/contrib/cals/test/llt/test_30_all.tex
@@ -0,0 +1,26 @@
+\def\lst{{\multiply \cals@borderwidthL by 3\relax}{}{}}
+\llt@desnoc{\lst}
+\show\lst
+\show\llt@car
+\def\lst{{item1}{item2}{item3}}
+\llt@desnoc{\lst}
+\show\lst
+\show\llt@car
+
+\def\aaa{aaa}
+\def\bbb{bbb}
+\def\ccc{ccc}
+\def\lst{} % empty list
+\show\lst
+\llt@cons\bbb\lst % \lst -> "{bbb}"
+\show\lst
+\llt@snoc\lst\ccc % \lst -> "{bbb}{ccc}"
+\show\lst
+\llt@cons\aaa\lst % \lst -> "{aaa}{bbb}{ccc}"
+\show\lst
+\llt@decons\lst % \llt@car -> "aaa", \lst -> "{bbb}{ccc}"
+\show\llt@car
+\show\lst
+\llt@rot\lst % \llt@car -> "bbb", \lst -> "{ccc}{bbb}"
+\show\llt@car
+\show\lst
diff --git a/macros/latex/contrib/cals/test/regression/test_010_wrongbreak.chk b/macros/latex/contrib/cals/test/regression/test_010_wrongbreak.chk
new file mode 100644
index 0000000000..86b6c040ea
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_010_wrongbreak.chk
@@ -0,0 +1,7 @@
+> the letter F.
+> the letter O.
+> the letter F.
+> the letter F.
+> the letter O.
+> the letter O.
+> the letter O.
diff --git a/macros/latex/contrib/cals/test/regression/test_010_wrongbreak.tex b/macros/latex/contrib/cals/test/regression/test_010_wrongbreak.tex
new file mode 100644
index 0000000000..cbb6ce278a
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_010_wrongbreak.tex
@@ -0,0 +1,33 @@
+% Wrong behaviour:
+% - page 1: "a"
+% - page 2: thead, tbody1
+% - page 3: thead, tbody2, tbody3
+% Right behaviour:
+% - page 1: "a"
+% - page 2: thead, tbody1, tbody2, tbody3
+%
+%
+\edef\oldoutput{\the\output}
+\output={\immediate\show O%
+\oldoutput}
+\let\oldifbreak=\cals@ifbreak
+\def\cals@ifbreak{%
+\oldifbreak\iftrue \immediate\show T\else \immediate\show F\fi
+\cals@tmp}
+%\tracingoutput=1
+%\tracingpages=1
+%
+%
+%
+a\par
+\dimen0=\pagegoal\relax
+\advance\dimen0 by -\pagetotal\relax
+\advance\dimen0 by -150pt
+\vskip\dimen0\relax
+\begin{calstable}
+\colwidths{{100pt}{100pt}}
+\thead{\brow\cell{thead}\cell{\vrule width10pt height100pt depth0pt}\erow}
+\brow\cell{tbody1}\cell{\vrule width10pt height100pt depth0pt}\erow
+\brow\cell{tbody2}\cell{\vrule width10pt height100pt depth0pt}\erow
+\brow\cell{tbody3}\cell{\vrule width10pt height100pt depth0pt}\erow
+\end{calstable}
diff --git a/macros/latex/contrib/cals/test/regression/test_020_wrongnobreak.chk b/macros/latex/contrib/cals/test/regression/test_020_wrongnobreak.chk
new file mode 100644
index 0000000000..5dae18a237
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_020_wrongnobreak.chk
@@ -0,0 +1,11 @@
+> the letter H.
+> the character 1.
+> the letter O.
+> the letter H.
+> the character 2.
+> the letter O.
+> the letter H.
+> the character 3.
+> the letter O.
+> the letter O.
+> the letter O.
diff --git a/macros/latex/contrib/cals/test/regression/test_020_wrongnobreak.tex b/macros/latex/contrib/cals/test/regression/test_020_wrongnobreak.tex
new file mode 100644
index 0000000000..891c1091ad
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_020_wrongnobreak.tex
@@ -0,0 +1,21 @@
+% I use a penalty to force a run of the output routine.
+% But I was afraid that this penalty prohibites a break.
+
+\edef\oldoutput{\the\output}
+\output={\immediate\show O%
+\oldoutput}
+
+\dimen0=\vsize
+\divide \dimen0 by 3
+\advance \dimen0 by 1cm
+\let\olderow=\erow
+\edef\erow{\ht\cals@current@row=\the\dimen0 \noexpand\olderow}
+%\show\erow
+
+\begin{calstable}
+\colwidths{{100pt}}
+\thead{\brow \cell{aaa} \erow \immediate\show H}
+\brow \cell{bbb} \erow \immediate\show 1
+\brow \cell{ccc} \erow \immediate\show 2
+\brow \cell{ddd} \erow \immediate\show 3
+\end{calstable}
diff --git a/macros/latex/contrib/cals/test/regression/test_030_spanbreak.chk b/macros/latex/contrib/cals/test/regression/test_030_spanbreak.chk
new file mode 100644
index 0000000000..44af9bc224
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_030_spanbreak.chk
@@ -0,0 +1,11 @@
+> the letter H.
+> the character 1.
+> the letter R.
+> the letter O.
+> the letter H.
+> the letter O.
+> the character 2.
+> the character 3.
+> the letter O.
+> the letter O.
+> the letter O.
diff --git a/macros/latex/contrib/cals/test/regression/test_030_spanbreak.tex b/macros/latex/contrib/cals/test/regression/test_030_spanbreak.tex
new file mode 100644
index 0000000000..b04155899a
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_030_spanbreak.tex
@@ -0,0 +1,32 @@
+%
+% Do not break rowspanned cells
+%
+
+%
+% Unfortunately, this test seems does not check it.
+% Probably I should look at \tracingoutput
+%
+
+\edef\oldoutput{\the\output}
+\output={\immediate\show O%
+\oldoutput}
+
+\dimen0=\vsize
+\divide \dimen0 by 3
+\advance \dimen0 by 1cm
+\let\olderow=\erow
+\edef\erow{\ht\cals@current@row=\the\dimen0 \noexpand\olderow}
+%\show\erow
+
+\begin{calstable}
+\colwidths{{100pt}{100pt}}
+\thead{\brow \cell{h1}\cell{h2} \erow \immediate\show H}
+\brow \cell{r0c1}\cell{r0c2} \olderow
+\brow \cell{r1}\nullcell{ltr} \erow \immediate\show 1
+\cals@ifInRspan\iftrue \show R \else \show X \fi
+\brow \cell{r2}\nullcell{lbr}\spancontent{r1+r2} \erow \immediate\show 2
+%
+% Unfortunately yes, this row is orphan
+%
+\brow \cell{r3a}\cell{r3b} \erow \immediate\show 3
+\end{calstable}
diff --git a/macros/latex/contrib/cals/test/regression/test_040_rowheight.chk b/macros/latex/contrib/cals/test/regression/test_040_rowheight.chk
new file mode 100644
index 0000000000..7eb7239253
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_040_rowheight.chk
@@ -0,0 +1,3 @@
+> 30.0pt.
+> 40.0pt.
+> 50.0pt.
diff --git a/macros/latex/contrib/cals/test/regression/test_040_rowheight.tex b/macros/latex/contrib/cals/test/regression/test_040_rowheight.tex
new file mode 100644
index 0000000000..4d028bc491
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_040_rowheight.tex
@@ -0,0 +1,40 @@
+% Initially, re-height of the current row and setting
+% \cals@last@row@height was in '\cals@issue@row'.
+% After implementing row spanning, this actions were moved
+% to \erow. Unfortunately, I forget to move the second action.
+\begin{calstable}
+\cals@setpadding{}
+\cals@setcellprevdepth{}
+\colwidths{{100pt}{100pt}{100pt}}
+
+\thead{%
+\brow
+ \cell{h1}\cell{h2}\cell{h3}
+\erow
+}
+
+\brow
+ \cell{a1}
+ \cell{a2}
+ \cell{a3}
+ \ht\cals@current@row=30pt
+\erow
+\showthe\cals@last@row@height
+
+\brow
+ \cell{b1}
+ \nullcell{ltr}
+ \nullcell{ltr}
+ \ht\cals@current@row=40pt
+\erow
+\showthe\cals@last@row@height
+
+\brow
+ \cell{c1}
+ \nullcell{lbr}\spancontent{s2}
+ \nullcell{lbr}\spancontent{s3}
+ \ht\cals@current@row=50pt
+\erow
+\showthe\cals@last@row@height
+
+\end{calstable}
diff --git a/macros/latex/contrib/cals/test/regression/test_050_leftskip_rowspan.chk b/macros/latex/contrib/cals/test/regression/test_050_leftskip_rowspan.chk
new file mode 100644
index 0000000000..53ba792c3d
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_050_leftskip_rowspan.chk
@@ -0,0 +1,2 @@
+> 210.0pt.
+> 10.0pt.
diff --git a/macros/latex/contrib/cals/test/regression/test_050_leftskip_rowspan.tex b/macros/latex/contrib/cals/test/regression/test_050_leftskip_rowspan.tex
new file mode 100644
index 0000000000..549fd6ac53
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_050_leftskip_rowspan.tex
@@ -0,0 +1,24 @@
+\parindent=0pt
+par1\par
+par2\par
+\leftskip=10pt
+par3\par
+par4\par
+\setbox0=\vbox{%
+\begin{calstable}
+\colwidths{{100pt}}
+\brow
+ \cell{c}
+ \nullcell{ltr}
+\erow
+\brow
+ \cell{c}
+ \nullcell{lbr}\spancontent{c}
+\erow
+\end{calstable}
+}
+\showthe\wd0
+\box0
+par5\par
+par6\par
+\showthe\leftskip
diff --git a/macros/latex/contrib/cals/test/regression/test_060_alignment.chk b/macros/latex/contrib/cals/test/regression/test_060_alignment.chk
new file mode 100644
index 0000000000..7003b6a346
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_060_alignment.chk
@@ -0,0 +1,106 @@
+> \boxXX=
+\vbox(150.0+0.0)x290.0
+.\vbox(0.0+0.0)x290.0
+..\hbox(50.0+0.0)x290.0 []
+.\hbox(0.0+0.0)x290.0
+..\glue 50.0
+..\glue -0.2
+..\rule(0.2+0.2)x240.4
+..\glue -0.2
+..\glue 0.0
+.\hbox(100.0+0.0)x290.0
+..\glue 50.0
+..\vbox(100.0+0.0)x240.0 []
+..\glue 0.0
+.\penalty 10000
+.\vbox(0.0+0.0)x290.0
+..\hbox(50.0+0.0)x290.0 []
+.\hbox(0.0+0.0)x290.0
+..\glue 50.0
+..\glue -0.2
+..\rule(0.2+0.2)x240.4
+..\glue -0.2
+..\glue 0.0
+.\hbox(50.0+0.0)x290.0
+..\glue 50.0
+..\hbox(50.0+0.0)x240.0 []
+..\glue 0.0
+.\penalty 10000
+.\hbox(0.0+0.0)x290.0
+..\glue 50.0
+..\glue -0.2
+..\rule(0.2+0.2)x240.4
+..\glue -0.2
+..\glue 0.0
+%
+%
+> \boxXX=
+\vbox(150.0+0.0)x400.0
+.\vbox(0.0+0.0)x400.0
+..\hbox(50.0+0.0)x400.0, glue set 80.0fil []
+.\hbox(0.0+0.0)x400.0, glue set 80.0fil
+..\glue 0.0 plus 1.0fil
+..\glue -0.2
+..\rule(0.2+0.2)x240.4
+..\glue -0.2
+..\glue 0.0 plus 1.0fil
+.\hbox(100.0+0.0)x400.0, glue set 80.0fil
+..\glue 0.0 plus 1.0fil
+..\vbox(100.0+0.0)x240.0 []
+..\glue 0.0 plus 1.0fil
+.\penalty 10000
+.\vbox(0.0+0.0)x400.0
+..\hbox(50.0+0.0)x400.0, glue set 80.0fil []
+.\hbox(0.0+0.0)x400.0, glue set 80.0fil
+..\glue 0.0 plus 1.0fil
+..\glue -0.2
+..\rule(0.2+0.2)x240.4
+..\glue -0.2
+..\glue 0.0 plus 1.0fil
+.\hbox(50.0+0.0)x400.0, glue set 80.0fil
+..\glue 0.0 plus 1.0fil
+..\hbox(50.0+0.0)x240.0 []
+..\glue 0.0 plus 1.0fil
+.\penalty 10000
+.\hbox(0.0+0.0)x400.0, glue set 80.0fil
+..\glue 0.0 plus 1.0fil
+..\glue -0.2
+..\rule(0.2+0.2)x240.4
+..\glue -0.2
+..\glue 0.0 plus 1.0fil
+%
+%
+> \boxXX=
+\vbox(150.0+0.0)x400.0
+.\vbox(0.0+0.0)x400.0
+..\hbox(50.0+0.0)x400.0, glue set 160.0fil []
+.\hbox(0.0+0.0)x400.0, glue set 160.0fil
+..\glue 0.0 plus 1.0fil
+..\glue -0.2
+..\rule(0.2+0.2)x240.4
+..\glue -0.2
+..\glue 0.0
+.\hbox(100.0+0.0)x400.0, glue set 160.0fil
+..\glue 0.0 plus 1.0fil
+..\vbox(100.0+0.0)x240.0 []
+..\glue 0.0
+.\penalty 10000
+.\vbox(0.0+0.0)x400.0
+..\hbox(50.0+0.0)x400.0, glue set 160.0fil []
+.\hbox(0.0+0.0)x400.0, glue set 160.0fil
+..\glue 0.0 plus 1.0fil
+..\glue -0.2
+..\rule(0.2+0.2)x240.4
+..\glue -0.2
+..\glue 0.0
+.\hbox(50.0+0.0)x400.0, glue set 160.0fil
+..\glue 0.0 plus 1.0fil
+..\hbox(50.0+0.0)x240.0 []
+..\glue 0.0
+.\penalty 10000
+.\hbox(0.0+0.0)x400.0, glue set 160.0fil
+..\glue 0.0 plus 1.0fil
+..\glue -0.2
+..\rule(0.2+0.2)x240.4
+..\glue -0.2
+..\glue 0.0
diff --git a/macros/latex/contrib/cals/test/regression/test_060_alignment.tex b/macros/latex/contrib/cals/test/regression/test_060_alignment.tex
new file mode 100644
index 0000000000..cc649a95b2
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_060_alignment.tex
@@ -0,0 +1,37 @@
+\def\w{\ht\cals@current@row=50pt\relax}
+\def\mktable{%
+\begin{calstable}[n]
+\colwidths{{70pt}{80pt}{90pt}}
+\def\cals@framecs@width{\cals@cs@width}
+\def\cals@framers@width{\cals@rs@width}
+\setlength{\cals@paddingR}{2pt plus1fil}
+\brow \nullcell{ltr} \cell{b} \cell{c} \w \erow
+\brow \nullcell{lrb}\spancontent{a,d} \cell{e} \cell{f} \w \erow
+\brow \cell{g} \cell{h} \cell{i} \w \erow
+\end{calstable}
+}
+
+\showboxdepth=2
+\hsize=400pt
+
+\setbox0=\vbox{%
+\leftskip=50pt\relax
+\mktable}
+\showbox0
+\box0
+
+\begin{center}
+some text\\
+\setbox0=\vbox{%
+\mktable}
+\showbox0
+\box0
+\end{center}
+
+\begin{flushright}
+some text\\
+\setbox0=\vbox{%
+\mktable}
+\showbox0
+\box0
+\end{flushright}
diff --git a/macros/latex/contrib/cals/test/regression/test_065_alignment.chk b/macros/latex/contrib/cals/test/regression/test_065_alignment.chk
new file mode 100644
index 0000000000..082696a904
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_065_alignment.chk
@@ -0,0 +1,45 @@
+> \boxXX=
+\hbox(40.0+0.0)x100.0
+.\vbox(40.0+0.0)x100.0
+..\glue 10.0
+..\glue 0.0 plus -1.0
+..\glue(\parskip) 0.0 plus 1.0
+..\glue(\lineskip) 0.0
+..\hbox(20.0+0.0)x100.0, glue set 80.0fil
+...\glue(\leftskip) 10.0
+...\vbox(20.0+0.0)x0.0
+...\penalty 10000
+...\glue(\parfillskip) 0.0 plus 1.0fil
+...\glue(\rightskip) 10.0
+..\glue 0.0 plus 1.0fil
+..\glue 10.0
+> \boxXX=
+\hbox(40.0+0.0)x100.0
+.\vbox(40.0+0.0)x100.0
+..\glue 10.0
+..\glue 0.0 plus -1.0
+..\glue(\parskip) 0.0 plus 1.0
+..\glue(\lineskip) 0.0
+..\hbox(20.0+0.0)x100.0, glue set 80.0fil
+...\glue(\leftskip) 10.0
+...\vbox(20.0+0.0)x0.0
+...\penalty 10000
+...\glue(\parfillskip) 0.0 plus 1.0fil
+...\glue(\rightskip) 10.0
+..\glue 0.0 plus 1.0fil
+..\glue 10.0
+> \boxXX=
+\hbox(40.0+0.0)x100.0
+.\vbox(40.0+0.0)x100.0
+..\glue 10.0
+..\glue 0.0 plus -1.0
+..\glue(\parskip) 0.0 plus 1.0
+..\glue(\lineskip) 0.0
+..\hbox(20.0+0.0)x100.0, glue set 80.0fil
+...\glue(\leftskip) 10.0
+...\vbox(20.0+0.0)x0.0
+...\penalty 10000
+...\glue(\parfillskip) 0.0 plus 1.0fil
+...\glue(\rightskip) 10.0
+..\glue 0.0 plus 1.0fil
+..\glue 10.0
diff --git a/macros/latex/contrib/cals/test/regression/test_065_alignment.tex b/macros/latex/contrib/cals/test/regression/test_065_alignment.tex
new file mode 100644
index 0000000000..41f0523965
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_065_alignment.tex
@@ -0,0 +1,25 @@
+% Alignment outside a table should not affect alignment inside tanle
+\def\tbl{%
+\begin{calstable}
+\colwidths{{100pt}}
+\def\cals@paddingT{10pt}
+\def\cals@paddingR{10pt}
+\def\cals@paddingB{10pt}
+\def\cals@paddingL{10pt}
+\brow
+\cell{\noindent\vbox to 20pt{}}
+\ht\cals@current@row=40pt
+\showbox\cals@current@row
+\erow
+\end{calstable}
+}
+
+\tbl
+
+\begin{center}
+\tbl
+\end{center}
+
+\begin{flushright}
+\tbl
+\end{flushright}
diff --git a/macros/latex/contrib/cals/test/regression/test_070_clean_backup_row.chk b/macros/latex/contrib/cals/test/regression/test_070_clean_backup_row.chk
new file mode 100644
index 0000000000..e6be40dfbe
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_070_clean_backup_row.chk
@@ -0,0 +1 @@
+> the letter Y.
diff --git a/macros/latex/contrib/cals/test/regression/test_070_clean_backup_row.tex b/macros/latex/contrib/cals/test/regression/test_070_clean_backup_row.tex
new file mode 100644
index 0000000000..8c7e4efa36
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_070_clean_backup_row.tex
@@ -0,0 +1,18 @@
+%
+% Collision of two tables when a table is started in an unexpected moment
+% http://tex.stackexchange.com/questions/167400/fancyhdr-and-cals-vertical-merge-problem
+%
+
+\setbox\cals@backup@row=\hbox{nonsense}
+
+\begin{calstable}
+\colwidths{{90pt}}
+\brow
+\nullcell{ltr}
+\erow
+\brow
+\nullcell{lbr}\spancontent{spanned}
+\erow
+\end{calstable}
+
+\show Y
diff --git a/macros/latex/contrib/cals/test/regression/test_075_vstraddled_retain_rowsep.chk b/macros/latex/contrib/cals/test/regression/test_075_vstraddled_retain_rowsep.chk
new file mode 100644
index 0000000000..19c748f640
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_075_vstraddled_retain_rowsep.chk
@@ -0,0 +1,14 @@
+%
+% Between the 2&3 rows with a vertically straddled cell
+%
+> \cals@last@rs@below=macro:
+->{{100pt}{0pt}{0pt}{0pt}}{{100pt}{0pt}{0pt}{0pt}}.
+> \cals@current@rs@above=macro:
+->{{100pt}{0pt}{0pt}{0pt}}{{100pt}{0pt}{0pt}{0pt}}.
+%
+% Between the first row and the straddled 2&3
+%
+> \cals@last@rs@below=macro:
+->{{100pt}{0.4pt}{0.4pt}{0.4pt}}{{100pt}{0.4pt}{0.4pt}{0.4pt}}.
+> \cals@current@rs@above=macro:
+->{{100pt}{0pt}{0pt}{0pt}}{{100pt}{0pt}{0pt}{0pt}}.
diff --git a/macros/latex/contrib/cals/test/regression/test_075_vstraddled_retain_rowsep.tex b/macros/latex/contrib/cals/test/regression/test_075_vstraddled_retain_rowsep.tex
new file mode 100644
index 0000000000..bf880eec22
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_075_vstraddled_retain_rowsep.tex
@@ -0,0 +1,38 @@
+% http://tex.stackexchange.com/questions/159814/miss-the-bottom-line-of-the-frame-header-of-the-cals-table-on-the-first-page
+
+% The first row should be inside a border, because the rules are
+% switched off after the row is made. However, the straddled rows
+% "forget" about the first row decoration. Fix it.
+
+% Mock
+\renewcommand\cals@rs@joinTwo[3]{\show#2\show#3}
+
+\begin{calstable}
+\colwidths{{100pt}{100pt}}
+\def\cals@borderT{0.4pt}
+\def\cals@borderB{0.4pt}
+\def\cals@borderL{0.4pt}
+\def\cals@borderR{0.4pt}
+
+\brow
+\cell{head1}
+\cell{head2}
+\erow
+
+\def\cals@borderT{0pt}
+\def\cals@borderB{0pt}
+\def\cals@borderL{0pt}
+\def\cals@borderR{0pt}
+
+\brow
+\nullcell{ltr}
+\cell{text 2}
+\erow
+
+\brow
+\nullcell{blr}
+\spancontent{2}
+\cell{text 2}
+\erow
+
+\end{calstable}
diff --git a/macros/latex/contrib/cals/test/regression/test_080_never_pagebreak_in_float.chk b/macros/latex/contrib/cals/test/regression/test_080_never_pagebreak_in_float.chk
new file mode 100644
index 0000000000..97c52cd2d5
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_080_never_pagebreak_in_float.chk
@@ -0,0 +1,4 @@
+> \cals@last@context=the letter n.
+> \cals@last@context=the letter b.
+> \cals@last@context=the letter b.
+> \cals@last@context=the letter b.
diff --git a/macros/latex/contrib/cals/test/regression/test_080_never_pagebreak_in_float.tex b/macros/latex/contrib/cals/test/regression/test_080_never_pagebreak_in_float.tex
new file mode 100644
index 0000000000..49cf27fa38
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_080_never_pagebreak_in_float.tex
@@ -0,0 +1,46 @@
+% Don't break inside a float
+
+% Mock
+\let\issue@orig=\cals@issue@row
+\renewcommand\cals@issue@row{%
+\show\cals@last@context
+\issue@orig}
+
+% Start float at the end of page, so that the table breaking code
+% think it should split over page.
+Start of text\par
+\dimen0=\pagegoal\relax
+\advance\dimen0 by -5cm\relax
+\vskip\dimen0\relax
+here we are\par
+
+\newcommand\www{\ht\cals@current@row=2.5cm}
+
+\vbox{%
+\begin{calstable}
+\colwidths{{0.25in}{1.5in}{1.5in}{1.5in}}
+%
+\brow \cell{}\cell{C1}\cell{C2}\cell{C3} \www\erow
+%
+\brow
+\cell{R}
+\cell{r1c1}
+\cell{r1c2}
+\cell{r1c3}
+\www\erow
+%
+\brow \nullcell{lrt}
+\cell{r2c1}
+\cell{r2c2}
+\cell{r2c3}
+\www\erow
+%
+\brow
+\nullcell{lrb}\spancontent{S}
+\cell{r3c1}
+\cell{r3c2}
+\cell{r3c3}
+\www\erow
+\end{calstable}
+}% vbox
+\end{document}
diff --git a/macros/latex/contrib/cals/test/regression/test_085_allow_table_in_colspan.chk b/macros/latex/contrib/cals/test/regression/test_085_allow_table_in_colspan.chk
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_085_allow_table_in_colspan.chk
diff --git a/macros/latex/contrib/cals/test/regression/test_085_allow_table_in_colspan.tex b/macros/latex/contrib/cals/test/regression/test_085_allow_table_in_colspan.tex
new file mode 100644
index 0000000000..e786e264db
--- /dev/null
+++ b/macros/latex/contrib/cals/test/regression/test_085_allow_table_in_colspan.tex
@@ -0,0 +1,32 @@
+% Allow table in colspan
+% No warnings are expected:
+% You can't use `\\prevdepth' in horizontal mode.
+% Missing $ inserted.
+% etc.
+
+\par
+\begin{calstable}
+\colwidths{{1in}{1in}{1in}{1in}}
+\brow
+\cell{normal}
+\tracingall
+
+\nullcell{ltb}
+\nullcell{rtb}
+\spancontent{
+ xxx\par
+
+ \begin{calstable}
+ \colwidths{{1in}}
+ \brow\cell{inner table}\erow
+ \end{calstable}
+}
+\par
+
+\cell{normal}
+%\tracingall
+%\par
+\erow
+\end{calstable}
+
+\end{document}
diff --git a/macros/latex/contrib/cals/test/rowsep/test_10_waitrule.chk b/macros/latex/contrib/cals/test/rowsep/test_10_waitrule.chk
new file mode 100644
index 0000000000..30e283b630
--- /dev/null
+++ b/macros/latex/contrib/cals/test/rowsep/test_10_waitrule.chk
@@ -0,0 +1,47 @@
+%
+% Empty
+%
+> \boxXX=
+\hbox(0.0+0.0)x0.0
+%
+% One
+%
+> \boxXX=
+\hbox(0.5+0.5)x100.0
+.\glue -1.0
+.\rule(0.5+0.5)x103.0
+.\glue -2.0
+%
+% Several, same width
+%
+> \boxXX=
+\hbox(0.5+0.5)x300.0
+.\glue -1.0
+.\rule(0.5+0.5)x303.0
+.\glue -2.0
+%
+% Mixed
+%
+> \boxXX=
+\hbox(2.5+2.5)x300.0
+.\glue -1.0
+.\rule(0.5+0.5)x103.0
+.\glue -2.0
+.\glue -1.0
+.\rule(1.5+1.5)x103.0
+.\glue -2.0
+.\glue -1.0
+.\rule(2.5+2.5)x103.0
+.\glue -2.0
+%
+% No rule at all
+%
+> \boxXX=
+\hbox(1.0+1.0)x400.0
+.\glue -1.0
+.\rule(1.0+1.0)x103.0
+.\glue -2.0
+.\glue 200.0
+.\glue -1.0
+.\rule(1.0+1.0)x103.0
+.\glue -2.0
diff --git a/macros/latex/contrib/cals/test/rowsep/test_10_waitrule.tex b/macros/latex/contrib/cals/test/rowsep/test_10_waitrule.tex
new file mode 100644
index 0000000000..537b3df741
--- /dev/null
+++ b/macros/latex/contrib/cals/test/rowsep/test_10_waitrule.tex
@@ -0,0 +1,68 @@
+%
+% Testing "waiting" rule
+%
+
+%
+% Empty
+%
+\setbox0=\hbox{%
+\cals@rs@sofar@reset
+\cals@rs@sofar@end
+}
+\showbox0
+
+%
+% One element
+%
+\def\ll{100pt}
+\def\dl{2pt}
+\def\dr{4pt}
+\def\w{1pt}
+\setbox0=\hbox{%
+\cals@rs@sofar@reset
+\cals@rs@sofar@next\ll\dl\dr\w
+\cals@rs@sofar@end
+}
+\showbox0
+
+%
+% Elements of the same width
+%
+\setbox0=\hbox{%
+\cals@rs@sofar@reset
+\cals@rs@sofar@next\ll\dl\dr\w
+\cals@rs@sofar@next\ll\dl\dr\w
+\cals@rs@sofar@next\ll\dl\dr\w
+\cals@rs@sofar@end
+}
+\showbox0
+
+%
+% Elements of different widths
+%
+\setbox0=\hbox{%
+\cals@rs@sofar@reset
+\cals@rs@sofar@next\ll\dl\dr\w
+\def\w{3pt}%
+\cals@rs@sofar@next\ll\dl\dr\w
+\def\w{5pt}%
+\cals@rs@sofar@next\ll\dl\dr\w
+\cals@rs@sofar@end
+}
+\showbox0
+
+%
+% 0pt width=no rule at all
+%
+\setbox0=\hbox{%
+\def\w{2pt}%
+\cals@rs@sofar@reset
+\cals@rs@sofar@next\ll\dl\dr\w
+\def\w{0pt}%
+\cals@rs@sofar@next\ll\dl\dr\w
+\cals@rs@sofar@next\ll\dl\dr\w
+\def\w{2pt}%
+\cals@rs@sofar@next\ll\dl\dr\w
+\cals@rs@sofar@end
+}
+\showbox0
diff --git a/macros/latex/contrib/cals/test/rowsep/test_15_waitover.chk b/macros/latex/contrib/cals/test/rowsep/test_15_waitover.chk
new file mode 100644
index 0000000000..646dd34aaa
--- /dev/null
+++ b/macros/latex/contrib/cals/test/rowsep/test_15_waitover.chk
@@ -0,0 +1,36 @@
+%
+% Same width
+%
+> \boxXX=
+\hbox(1.0+1.0)x100.0
+.\glue -1.0
+.\rule(1.0+1.0)x103.0
+.\glue -2.0
+%
+% Different borders
+%
+> \boxXX=
+\hbox(1.0+1.0)x100.0
+.\glue -3.0
+.\rule(1.0+1.0)x107.0
+.\glue -4.0
+%
+% Different widths
+%
+> \boxXX=
+\hbox(2.0+2.0)x100.0
+.\glue -1.0
+.\rule(1.0+1.0)x103.0
+.\glue -2.0
+.\glue -100.0
+.\glue -1.0
+.\rule(2.0+2.0)x103.0
+.\glue -2.0
+%
+% Different widths, second is 0pt
+%
+> \boxXX=
+\hbox(1.0+1.0)x100.0
+.\glue -1.0
+.\rule(1.0+1.0)x103.0
+.\glue -2.0
diff --git a/macros/latex/contrib/cals/test/rowsep/test_15_waitover.tex b/macros/latex/contrib/cals/test/rowsep/test_15_waitover.tex
new file mode 100644
index 0000000000..b04a81587e
--- /dev/null
+++ b/macros/latex/contrib/cals/test/rowsep/test_15_waitover.tex
@@ -0,0 +1,51 @@
+\def\ll{100pt}
+\def\dl{2pt}
+\def\dr{4pt}
+%
+% Same width and borders
+%
+\def\w{2pt}
+\setbox0=\hbox{%
+\cals@rs@sofar@reset
+\cals@rs@sofar@next\ll\dl\dr\w
+\cals@rs@sofar@over\ll\dl\dr\w
+\cals@rs@sofar@end
+}
+\showbox0
+
+%
+% Same width, bigger borders
+%
+\setbox0=\hbox{%
+\cals@rs@sofar@reset
+\cals@rs@sofar@next\ll\dl\dr\w
+\def\dlII{6pt}%
+\def\drII{8pt}%
+\cals@rs@sofar@over\ll\dlII\drII\w
+\cals@rs@sofar@end
+}
+\showbox0
+
+%
+% Different widths
+%
+\setbox0=\hbox{%
+\cals@rs@sofar@reset
+\cals@rs@sofar@next\ll\dl\dr\w
+\def\wII{4pt}%
+\cals@rs@sofar@over\ll\dl\dr\wII
+\cals@rs@sofar@end
+}
+\showbox0
+
+%
+% Different widths, second is 0pt
+%
+\setbox0=\hbox{%
+\cals@rs@sofar@reset
+\cals@rs@sofar@next\ll\dl\dr\w
+\def\wII{0pt}%
+\cals@rs@sofar@over\ll\dl\dr\wII
+\cals@rs@sofar@end
+}
+\showbox0
diff --git a/macros/latex/contrib/cals/test/rowsep/test_20_pack.chk b/macros/latex/contrib/cals/test/rowsep/test_20_pack.chk
new file mode 100644
index 0000000000..4af37cfac1
--- /dev/null
+++ b/macros/latex/contrib/cals/test/rowsep/test_20_pack.chk
@@ -0,0 +1,38 @@
+%
+% 0pt
+%
+> \tmp=macro:
+->{100pt}{2pt}{4pt}{0pt}.
+> \ll=macro:
+->100pt.
+> \dl=macro:
+->2pt.
+> \dr=macro:
+->4pt.
+> \w=macro:
+->0pt.
+%
+% \relax
+%
+> \tmp=macro:
+->{200pt}{2pt}{4pt}\relax .
+> \ll=macro:
+->200pt.
+> \dl=macro:
+->2pt.
+> \dr=macro:
+->4pt.
+> \w=\relax.
+%
+% User-specified
+%
+> \tmp=macro:
+->{300pt}{0pt}{0pt}{3pt}.
+> \ll=macro:
+->300pt.
+> \dl=macro:
+->0pt.
+> \dr=macro:
+->0pt.
+> \w=macro:
+->3pt.
diff --git a/macros/latex/contrib/cals/test/rowsep/test_20_pack.tex b/macros/latex/contrib/cals/test/rowsep/test_20_pack.tex
new file mode 100644
index 0000000000..9f881ed494
--- /dev/null
+++ b/macros/latex/contrib/cals/test/rowsep/test_20_pack.tex
@@ -0,0 +1,32 @@
+%
+% 0pt for thick
+%
+\cals@rs@pack\tmp{100pt}{2pt}{4pt}{0pt}
+\show\tmp
+\cals@rs@unpack\tmp\ll\dl\dr\w
+\show\ll
+\show\dl
+\show\dr
+\show\w
+
+%
+% Use default think
+%
+\cals@rs@pack\tmp{200pt}{2pt}{4pt}\relax
+\show\tmp
+\cals@rs@unpack\tmp\ll\dl\dr\w
+\show\ll
+\show\dl
+\show\dr
+\show\w
+
+%
+% User-specified thick
+%
+\cals@rs@pack\tmp{300pt}{0pt}{0pt}{3pt}
+\show\tmp
+\cals@rs@unpack\tmp\ll\dl\dr\w
+\show\ll
+\show\dl
+\show\dr
+\show\w
diff --git a/macros/latex/contrib/cals/test/rowsep/test_30_jointwo.chk b/macros/latex/contrib/cals/test/rowsep/test_30_jointwo.chk
new file mode 100644
index 0000000000..644d9520d5
--- /dev/null
+++ b/macros/latex/contrib/cals/test/rowsep/test_30_jointwo.chk
@@ -0,0 +1,29 @@
+%
+% Empty
+%
+> \boxXX=
+\hbox(0.0+0.0)x0.0
+%
+% One element
+%
+> \boxXX=
+\hbox(3.0+3.0)x100.0
+.\glue -1.5
+.\rule(3.0+3.0)x104.0
+.\glue -2.5
+%
+% Several elements
+%
+> \boxXX=
+\hbox(4.0+4.0)x303.0
+.\glue -1.0
+.\rule(3.0+3.0)x103.0
+.\glue -2.0
+.\glue -100.0
+.\glue -2.0
+.\rule(4.0+4.0)x104.0
+.\glue -2.0
+.\glue -1.0
+.\rule(0.5+0.5)x104.0
+.\glue -2.0
+.\glue 102.0
diff --git a/macros/latex/contrib/cals/test/rowsep/test_30_jointwo.tex b/macros/latex/contrib/cals/test/rowsep/test_30_jointwo.tex
new file mode 100644
index 0000000000..e6f1c11734
--- /dev/null
+++ b/macros/latex/contrib/cals/test/rowsep/test_30_jointwo.tex
@@ -0,0 +1,34 @@
+\def\defaultwidth{1pt}
+
+%
+% Empty
+%
+\def\rsI{}
+\def\rsII{}
+\def\mkbox{\setbox0=\hbox{\cals@rs@sofar@reset \cals@rs@joinTwo\defaultwidth\rsI\rsII \cals@rs@sofar@end}}
+\mkbox
+\showbox0
+
+%
+% One element
+%
+\cals@rs@pack\rsI{100pt}{2pt}{4pt}{6pt}
+\cals@rs@pack\rsII{100pt}{3pt}{5pt}{6pt}
+\edef\rsI{{\rsI}}
+\edef\rsII{{\rsII}}
+\mkbox
+\showbox0
+
+%
+% Several elements, with no-line and default
+%
+\cals@rs@pack\frI{100pt}{2pt}{4pt}{6pt}
+\cals@rs@pack\frII{101pt}{2pt}{4pt}\relax
+\cals@rs@pack\frIII{102pt}{2pt}{4pt}{0pt}
+\edef\rsI{{\frI}{\frII}{\frIII}}
+\cals@rs@pack\frI{100pt}{4pt}{4pt}{8pt}
+\cals@rs@pack\frII{101pt}{2pt}{4pt}\relax
+\cals@rs@pack\frIII{102pt}{3pt}{5pt}{0pt}
+\edef\rsII{{\frI}{\frII}{\frIII}}
+\mkbox
+\showbox0
diff --git a/macros/latex/contrib/cals/test/rowsep/test_35_joinone.chk b/macros/latex/contrib/cals/test/rowsep/test_35_joinone.chk
new file mode 100644
index 0000000000..6e24b4c368
--- /dev/null
+++ b/macros/latex/contrib/cals/test/rowsep/test_35_joinone.chk
@@ -0,0 +1,16 @@
+> \boxXX=
+\hbox(0.0+0.0)x0.0
+> \boxXX=
+\hbox(3.0+3.0)x100.0
+.\glue -1.0
+.\rule(3.0+3.0)x103.0
+.\glue -2.0
+> \boxXX=
+\hbox(3.0+3.0)x403.0
+.\glue -1.0
+.\rule(3.0+3.0)x203.0
+.\glue -2.0
+.\glue -1.0
+.\rule(0.5+0.5)x104.0
+.\glue -2.0
+.\glue 102.0
diff --git a/macros/latex/contrib/cals/test/rowsep/test_35_joinone.tex b/macros/latex/contrib/cals/test/rowsep/test_35_joinone.tex
new file mode 100644
index 0000000000..979a3b9950
--- /dev/null
+++ b/macros/latex/contrib/cals/test/rowsep/test_35_joinone.tex
@@ -0,0 +1,27 @@
+\def\defaultwidth{1pt}
+
+%
+% Empty
+%
+\def\rs{}
+\def\mkbox{\setbox0=\hbox{\cals@rs@sofar@reset \cals@rs@joinOne\defaultwidth\rs \cals@rs@sofar@end}}
+\mkbox
+\showbox0
+
+%
+% One element
+%
+\cals@rs@pack\rs{100pt}{2pt}{4pt}{6pt}
+\edef\rs{{\rs}}
+\mkbox
+\showbox0
+
+%
+% Several elements, with no-line and default
+%
+\cals@rs@pack\frI{100pt}{2pt}{4pt}{6pt}
+\cals@rs@pack\frII{101pt}{2pt}{4pt}\relax
+\cals@rs@pack\frIII{102pt}{2pt}{4pt}{0pt}
+\edef\rs{{\frI}{\frI}{\frII}{\frIII}}
+\mkbox
+\showbox0
diff --git a/macros/latex/contrib/cals/test/rowsep/test_40_construct.chk b/macros/latex/contrib/cals/test/rowsep/test_40_construct.chk
new file mode 100644
index 0000000000..0accaf6653
--- /dev/null
+++ b/macros/latex/contrib/cals/test/rowsep/test_40_construct.chk
@@ -0,0 +1,21 @@
+%
+% Empty
+%
+> \cals@current@rs@above=macro:
+->.
+> \cals@current@rs@below=macro:
+->.
+%
+% One element
+%
+> \cals@current@rs@above=macro:
+->{{100pt}{3pt}{5pt}\relax }.
+> \cals@current@rs@below=macro:
+->{{100pt}{3pt}{5pt}{4pt}}.
+%
+% Two elements
+%
+> \cals@current@rs@above=macro:
+->{{100pt}{0pt}{2pt}\relax }{{200pt}{2pt}{8pt}{6pt}}.
+> \cals@current@rs@below=macro:
+->{{100pt}{0pt}{2pt}{4pt}}{{200pt}{2pt}{8pt}\relax }.
diff --git a/macros/latex/contrib/cals/test/rowsep/test_40_construct.tex b/macros/latex/contrib/cals/test/rowsep/test_40_construct.tex
new file mode 100644
index 0000000000..24d895efdb
--- /dev/null
+++ b/macros/latex/contrib/cals/test/rowsep/test_40_construct.tex
@@ -0,0 +1,36 @@
+\def\wNone{0pt}
+\def\wII{2pt}
+\def\wIII{3pt}
+\def\wIV{4pt}
+\def\wV{5pt}
+\def\wVI{6pt}
+\def\wVIII{8pt}
+\def\wC{100pt}
+\def\wCC{200pt}
+
+%
+% Empty
+%
+\cals@rs@spec@begin
+\cals@rs@spec@end\wII
+\show\cals@current@rs@above
+\show\cals@current@rs@below
+
+%
+% One element
+%
+\cals@rs@spec@begin
+\cals@rs@spec@next\wC\wIII\relax\wIV % length, borderT, borderB
+\cals@rs@spec@end\wV
+\show\cals@current@rs@above
+\show\cals@current@rs@below
+
+%
+% Two elements
+%
+\cals@rs@spec@begin
+\cals@rs@spec@next\wC\wNone\relax\wIV
+\cals@rs@spec@next\wCC\wII\wVI\relax
+\cals@rs@spec@end\wVIII
+\show\cals@current@rs@above
+\show\cals@current@rs@below
diff --git a/macros/latex/contrib/cals/test/span/test_10_queue.chk b/macros/latex/contrib/cals/test/span/test_10_queue.chk
new file mode 100644
index 0000000000..252d5cead3
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_10_queue.chk
@@ -0,0 +1,5 @@
+> \cals@spanq@heights=macro:
+->{20.0pt}{40.0pt}.
+> \cals@spanq@heights=macro:
+->{40.0pt}.
+> 20.0pt.
diff --git a/macros/latex/contrib/cals/test/span/test_10_queue.tex b/macros/latex/contrib/cals/test/span/test_10_queue.tex
new file mode 100644
index 0000000000..742dbd8812
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_10_queue.tex
@@ -0,0 +1,10 @@
+\cals@span@height=20pt
+\cals@span@put
+\cals@span@height=40pt
+\cals@span@put
+\show\cals@spanq@heights
+%
+\cals@span@height=0pt
+\cals@span@get
+\show\cals@spanq@heights
+\showthe\cals@span@height
diff --git a/macros/latex/contrib/cals/test/span/test_20_decor.chk b/macros/latex/contrib/cals/test/span/test_20_decor.chk
new file mode 100644
index 0000000000..5044b94ca6
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_20_decor.chk
@@ -0,0 +1,84 @@
+%
+% Test 1
+%
+> \boxXX=
+\hbox(0.0+0.0)x260.0
+% column 1
+.\pdfcolorstack 0 push {1 0 0 rg 1 0 0 RG}
+.\rule(*+0.0)x50.0
+.\pdfcolorstack 0 pop
+.\glue -50.0
+.\glue -4.0
+.\rule(*+0.0)x8.0
+.\glue -4.0
+.\glue 50.0
+% column 2
+.\pdfcolorstack 0 push {1 0 0 rg 1 0 0 RG}
+.\rule(*+0.0)x60.0
+.\pdfcolorstack 0 pop
+.\glue -60.0
+.\glue 60.0
+% column 3
+.\pdfcolorstack 0 push {1 0 0 rg 1 0 0 RG}
+.\rule(*+0.0)x70.0
+.\pdfcolorstack 0 pop
+.\glue -70.0
+.\glue 70.0
+% column 4
+.\pdfcolorstack 0 push {1 0 0 rg 1 0 0 RG}
+.\rule(*+0.0)x80.0
+.\pdfcolorstack 0 pop
+.\glue -80.0
+.\glue 80.0
+.\glue -2.0
+.\rule(*+0.0)x4.0
+.\glue -2.0
+%
+> \cals@current@rs@above=macro:
+->{{50pt}{8pt}{0pt}{2pt}}{{60pt}{0pt}{0pt}{2pt}}{{70pt}{0pt}{0pt}{0pt}}{{80pt}{
+0pt}{4pt}{2pt}}.
+> \cals@current@rs@below=macro:
+->{{50pt}{8pt}{0pt}{6pt}}{{60pt}{0pt}{0pt}{6pt}}{{70pt}{0pt}{0pt}{0pt}}{{80pt}{
+0pt}{4pt}{6pt}}.
+%
+% Test 2
+%
+> \boxXX=
+\hbox(0.0+0.0)x260.0
+% column 1
+.\pdfcolorstack 0 push {0 1 0 rg 0 1 0 RG}
+.\rule(*+0.0)x50.0
+.\pdfcolorstack 0 pop
+.\glue -50.0
+.\glue -3.5
+.\rule(*+0.0)x7.0
+.\glue -3.5
+.\glue 50.0
+% column 2
+.\pdfcolorstack 0 push {0 1 0 rg 0 1 0 RG}
+.\rule(*+0.0)x60.0
+.\pdfcolorstack 0 pop
+.\glue -60.0
+.\glue 60.0
+% column 3
+.\pdfcolorstack 0 push {0 1 0 rg 0 1 0 RG}
+.\rule(*+0.0)x70.0
+.\pdfcolorstack 0 pop
+.\glue -70.0
+.\glue 70.0
+% column 4
+.\pdfcolorstack 0 push {0 1 0 rg 0 1 0 RG}
+.\rule(*+0.0)x80.0
+.\pdfcolorstack 0 pop
+.\glue -80.0
+.\glue 80.0
+.\glue -1.5
+.\rule(*+0.0)x3.0
+.\glue -1.5
+%
+> \cals@current@rs@above=macro:
+->{{50pt}{7pt}{0pt}{1pt}}{{60pt}{0pt}{0pt}{0pt}}{{70pt}{0pt}{0pt}{1pt}}{{80pt}{
+0pt}{3pt}{1pt}}.
+> \cals@current@rs@below=macro:
+->{{50pt}{7pt}{0pt}{5pt}}{{60pt}{0pt}{0pt}{0pt}}{{70pt}{0pt}{0pt}{5pt}}{{80pt}{
+0pt}{3pt}{5pt}}.
diff --git a/macros/latex/contrib/cals/test/span/test_20_decor.tex b/macros/latex/contrib/cals/test/span/test_20_decor.tex
new file mode 100644
index 0000000000..99794bea81
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_20_decor.tex
@@ -0,0 +1,31 @@
+\colwidths{{50pt}{60pt}{70pt}{80pt}}
+
+\def\cals@borderT{2pt}
+\def\cals@borderR{4pt}
+\def\cals@borderB{6pt}
+\def\cals@borderL{8pt}
+\def\cals@bgcolor{red}
+\cals@decor@begin
+\nullcell{ltb}
+\nullcell{tb}
+\nullcell{}
+\nullcell{tbr}
+\cals@decor@end\cals@lastWidth
+\showbox\cals@current@cs
+\show\cals@current@rs@above
+\show\cals@current@rs@below
+
+\def\cals@borderT{1pt}
+\def\cals@borderR{3pt}
+\def\cals@borderB{5pt}
+\def\cals@borderL{7pt}
+\def\cals@bgcolor{green}
+\cals@decor@begin
+\nullcell{ltb}
+\nullcell{}
+\nullcell{tb}
+\nullcell{tbr}
+\cals@decor@end\cals@lastWidth
+\showbox\cals@current@cs
+\show\cals@current@rs@above
+\show\cals@current@rs@below
diff --git a/macros/latex/contrib/cals/test/span/test_30_iftlrb.chk b/macros/latex/contrib/cals/test/span/test_30_iftlrb.chk
new file mode 100644
index 0000000000..372fdc1004
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_30_iftlrb.chk
@@ -0,0 +1,16 @@
+> \cals@span@ifL=macro:
+#1->\iftrue .
+> \cals@span@ifT=macro:
+#1->\iffalse .
+> \cals@span@ifR=macro:
+#1->\iftrue .
+> \cals@span@ifB=macro:
+#1->\iffalse .
+> \cals@span@ifL=macro:
+#1->\iffalse .
+> \cals@span@ifT=macro:
+#1->\iftrue .
+> \cals@span@ifR=macro:
+#1->\iffalse .
+> \cals@span@ifB=macro:
+#1->\iftrue .
diff --git a/macros/latex/contrib/cals/test/span/test_30_iftlrb.tex b/macros/latex/contrib/cals/test/span/test_30_iftlrb.tex
new file mode 100644
index 0000000000..a67bdc93a6
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_30_iftlrb.tex
@@ -0,0 +1,15 @@
+\def\cals@spanq@heights{{0pt}}
+\def\cals@lastWidth{0pt}
+\brow
+
+\nullcell{lr}
+\show\cals@span@ifL
+\show\cals@span@ifT
+\show\cals@span@ifR
+\show\cals@span@ifB
+\def\cals@lastWidth{0pt}
+\nullcell{tb}
+\show\cals@span@ifL
+\show\cals@span@ifT
+\show\cals@span@ifR
+\show\cals@span@ifB
diff --git a/macros/latex/contrib/cals/test/span/test_40_lr_queue.chk b/macros/latex/contrib/cals/test/span/test_40_lr_queue.chk
new file mode 100644
index 0000000000..ca1abf2ce2
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_40_lr_queue.chk
@@ -0,0 +1,14 @@
+> \cals@spanq@heights=macro:
+->.
+> \cals@spanq@heights=macro:
+->{20.0pt}.
+> \cals@spanq@heights=macro:
+->{20.0pt}.
+%
+> 40.0pt.
+> 0.0pt.
+> \cals@spanq@heights=macro:
+->{20.0pt}.
+> 20.0pt.
+> \cals@spanq@heights=macro:
+->.
diff --git a/macros/latex/contrib/cals/test/span/test_40_lr_queue.tex b/macros/latex/contrib/cals/test/span/test_40_lr_queue.tex
new file mode 100644
index 0000000000..a25633a68b
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_40_lr_queue.tex
@@ -0,0 +1,28 @@
+\def\cals@lastWidth{2pt}
+\def\cals@rs@spec@ll{2pt}
+\def\cals@rs@spec@bl{2pt}
+\def\cals@rs@spec@bt{2pt}
+\def\cals@current@rs@above{}
+\def\cals@current@rs@below{}
+%
+\colwidths{{100pt}{200pt}{300pt}}
+%
+\cals@span@height=20pt \relax
+\show\cals@spanq@heights
+\brow\def\cals@lastWidth{0pt}
+\nullcell{tr}
+\show\cals@spanq@heights
+\brow\def\cals@lastWidth{0pt}
+\nullcell{br}
+\show\cals@spanq@heights
+%
+\cals@span@height=40pt \relax
+\showthe\cals@span@height
+\let\cals@borderL=\relax \brow\def\cals@lastWidth{0pt}
+\nullcell{lt}
+\showthe\cals@span@height
+\show\cals@spanq@heights
+\brow\def\cals@lastWidth{0pt}
+\nullcell{bl}
+\showthe\cals@span@height
+\show\cals@spanq@heights
diff --git a/macros/latex/contrib/cals/test/span/test_50_dimen.chk b/macros/latex/contrib/cals/test/span/test_50_dimen.chk
new file mode 100644
index 0000000000..9a079aead0
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_50_dimen.chk
@@ -0,0 +1,38 @@
+> \boxXX=
+\hbox(0.0+0.0)x60.0
+.\vbox(0.0+0.0)x10.0
+..\hbox(0.0+0.0)x10.0
+..\glue 0.0 plus 1.0fil
+.\vbox(0.0+0.0)x20.0
+..\hbox(0.0+0.0)x20.0
+..\glue 0.0 plus 1.0fil
+.\vbox(0.0+0.0)x30.0
+..\hbox(0.0+0.0)x30.0
+..\glue 0.0 plus 1.0fil
+> \cals@spanq@heights=macro:
+->{0.0pt}.
+%
+> \boxXX=
+\hbox(0.0+0.0)x60.0
+.\vbox(0.0+0.0)x10.0
+..\hbox(0.0+0.0)x10.0
+..\glue 0.0 plus 1.0fil
+.\vbox(0.0+0.0)x20.0
+..\hbox(0.0+0.0)x20.0
+..\glue 0.0 plus 1.0fil
+.\vbox(0.0+0.0)x30.0
+..\hbox(0.0+0.0)x30.0
+..\glue 0.0 plus 1.0fil
+> \cals@spanq@heights=macro:
+->{40.0pt}.
+%
+> \boxXX=
+\hbox(0.0+0.0)x0.0
+> \cals@spanq@heights=macro:
+->.
+> 60.0pt.
+> 90.0pt.
+%
+% Bug
+%
+> 60.0pt.
diff --git a/macros/latex/contrib/cals/test/span/test_50_dimen.tex b/macros/latex/contrib/cals/test/span/test_50_dimen.tex
new file mode 100644
index 0000000000..f6e0b28a56
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_50_dimen.tex
@@ -0,0 +1,40 @@
+\colwidths{{10pt}{20pt}{30pt}}
+\cals@last@row@height=1000pt %
+%
+\brow
+\nullcell{tl}
+\nullcell{t}
+\nullcell{tr}
+%\erow
+\cals@last@row@height=40pt %
+\showbox\cals@current@row
+\show\cals@spanq@heights
+
+\brow
+\nullcell{l}
+\nullcell{}
+\nullcell{r}
+%\erow
+\cals@last@row@height=50pt %
+\showbox\cals@current@row
+\show\cals@spanq@heights
+
+
+\brow
+\nullcell{lb}
+\nullcell{b}
+\nullcell{br}
+%\erow
+\showbox\cals@current@row
+\show\cals@spanq@heights
+\showthe\cals@span@width
+\showthe\cals@span@height
+
+%
+% Bug was here
+%
+\brow
+\nullcell{ltb}
+\nullcell{tb}
+\nullcell{btr}
+\showthe\cals@span@width
diff --git a/macros/latex/contrib/cals/test/span/test_60_content.chk b/macros/latex/contrib/cals/test/span/test_60_content.chk
new file mode 100644
index 0000000000..0c523e3b33
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_60_content.chk
@@ -0,0 +1,16 @@
+> \boxXX=
+\hbox(10.0+0.0)x100.0
+.\vbox(10.0+0.0)x100.0
+..\glue -30.0
+..\glue 14.0
+..\glue 0.0 plus -1.0
+..\glue(\parskip) 0.0 plus 1.0
+..\glue(\baselineskip) 6.0
+..\hbox(3.0+2.0)x100.0, glue set 74.0fil
+...\glue(\leftskip) 12.0
+...\rule(3.0+2.0)x1.0
+...\penalty 10000
+...\glue(\parfillskip) 0.0 plus 1.0fil
+...\glue(\rightskip) 13.0
+..\glue 0.0 plus 1.0fil
+..\glue 15.0
diff --git a/macros/latex/contrib/cals/test/span/test_60_content.tex b/macros/latex/contrib/cals/test/span/test_60_content.tex
new file mode 100644
index 0000000000..0bc32f8624
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_60_content.tex
@@ -0,0 +1,15 @@
+\setlength{\cals@paddingL}{12pt}
+\setlength{\cals@paddingR}{13pt}
+\setlength{\cals@paddingT}{14pt}
+\setlength{\cals@paddingB}{15pt}
+
+\setlength{\cals@paddingD}{1pt}
+\setlength{\baselineskip}{10pt}
+
+\setbox\cals@current@row=\hbox{}
+
+\cals@span@width=100pt
+\cals@span@height=30pt
+
+\spancontent{\noindent \vrule height3pt depth2pt width1pt}
+\showbox\cals@current@row
diff --git a/macros/latex/contrib/cals/test/span/test_70_intercept.chk b/macros/latex/contrib/cals/test/span/test_70_intercept.chk
new file mode 100644
index 0000000000..14db368f2c
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_70_intercept.chk
@@ -0,0 +1,16 @@
+% row 1
+> \cals@spanq@heights=macro:
+->{0.0pt}.
+% row 2
+> \cals@spanq@heights=macro:
+->{0.0pt}{0.0pt}.
+> \cals@spanq@heights=macro:
+->{0.0pt}{50.0pt}.
+% row 3
+> \cals@spanq@heights=macro:
+->{50.0pt}{50.0pt}.
+> \cals@spanq@heights=macro:
+->{50.0pt}.
+% row 4
+> \cals@spanq@heights=macro:
+->.
diff --git a/macros/latex/contrib/cals/test/span/test_70_intercept.tex b/macros/latex/contrib/cals/test/span/test_70_intercept.tex
new file mode 100644
index 0000000000..3052794b06
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_70_intercept.tex
@@ -0,0 +1,28 @@
+%
+% Bug hunting / regresion test
+%
+\begin{calstable}
+\colwidths{{50pt}}
+\cals@setpadding{}\cals@setcellprevdepth{}
+
+\brow
+ \cell{\noindent\vrule height50pt depth0pt width10pt}
+ \cell{\noindent\vrule height50pt depth0pt width10pt}
+ \nullcell{tlr}\show\cals@spanq@heights
+ \erow
+\brow
+ \cell{\noindent\vrule height50pt depth0pt width10pt}
+ \nullcell{tlr}\show\cals@spanq@heights
+ \nullcell{lr}\show\cals@spanq@heights
+ \erow
+\brow
+ \cell{\noindent\vrule height50pt depth0pt width10pt}
+ \nullcell{lr}\show\cals@spanq@heights
+ \nullcell{rlb}\spancontent{\noindent\vrule height50pt depth0pt width10pt}\show\cals@spanq@heights
+ \erow
+\brow
+ \cell{\noindent\vrule height50pt depth0pt width10pt}
+ \nullcell{lrb}\spancontent{\noindent\vrule height50pt depth0pt width10pt}\show\cals@spanq@heights
+ \cell{\noindent\vrule height50pt depth0pt width10pt}
+ \erow
+\end{calstable}
diff --git a/macros/latex/contrib/cals/test/span/test_80_marker.chk b/macros/latex/contrib/cals/test/span/test_80_marker.chk
new file mode 100644
index 0000000000..134fccb3bd
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_80_marker.chk
@@ -0,0 +1,20 @@
+% 1
+> \cals@ifInRspan=macro:
+#1->\iffalse .
+> the letter L.
+% 2
+> \cals@ifInRspan=macro:
+#1->\iftrue .
+> the letter X.
+% 3
+> \cals@ifInRspan=macro:
+#1->\iftrue .
+> the letter X.
+% 4
+> \cals@ifInRspan=macro:
+#1->\iftrue .
+> the letter L.
+% 5
+> \cals@ifInRspan=macro:
+#1->\iffalse .
+> the letter L.
diff --git a/macros/latex/contrib/cals/test/span/test_80_marker.tex b/macros/latex/contrib/cals/test/span/test_80_marker.tex
new file mode 100644
index 0000000000..d97f3944b9
--- /dev/null
+++ b/macros/latex/contrib/cals/test/span/test_80_marker.tex
@@ -0,0 +1,35 @@
+\begin{calstable}
+\colwidths{{100pt}{100pt}}
+
+\brow
+\nullcell{ltb}\nullcell{rtb}\spancontent{row1}
+\show\cals@ifInRspan
+\cals@ifLastRspanRow\iftrue \show L \else \show X \fi
+\erow
+
+\brow
+\nullcell{ltr}\cell{r2}
+\show\cals@ifInRspan
+\cals@ifLastRspanRow\iftrue \show L \else \show X \fi
+\erow
+
+\brow
+\nullcell{lbr}\spancontent{r3}\nullcell{ltr}
+\show\cals@ifInRspan
+\cals@ifLastRspanRow\iftrue \show L \else \show X \fi
+\erow
+
+\brow
+\cell{r3}\nullcell{lbr}\spancontent{r4}
+\show\cals@ifInRspan
+\cals@ifLastRspanRow\iftrue \show L \else \show X \fi
+\erow
+
+\brow
+\cell{r4c1}
+\cell{r4c2}
+\show\cals@ifInRspan
+\cals@ifLastRspanRow\iftrue \show L \else \show X \fi
+\erow
+
+\end{calstable}
diff --git a/macros/latex/contrib/cals/test/support/LatexTest.py b/macros/latex/contrib/cals/test/support/LatexTest.py
new file mode 100644
index 0000000000..99a695597b
--- /dev/null
+++ b/macros/latex/contrib/cals/test/support/LatexTest.py
@@ -0,0 +1,163 @@
+# Running a latex
+import unittest, os, shutil, re, glob
+
+settings = None # will be set from the main script
+
+re_macro_start = re.compile(r'''^> \\[^=]+=macro:$''')
+re_box_start = re.compile(r'''^> \\box\d+=''')
+re_some_show = re.compile(r'''^> .*\.$''')
+re_message = re.compile(r'''^! ''')
+re_comment = re.compile(r'''^%[^\r\n]*[\r\n]*''', re.S|re.M)
+
+class LatexTestCase(unittest.TestCase):
+
+ def __init__(self, *ls):
+ unittest.TestCase.__init__(self, *ls)
+ tpl_file = 'template.txt'
+ h = open(tpl_file)
+ self.template = h.read()
+ h.close()
+
+ def get_settings(self):
+ return settings
+
+ def setUp(self):
+ tmp_dir = settings.get_tmp_dir()
+ for fname in os.listdir(tmp_dir):
+ full_name = os.path.join(tmp_dir, fname)
+ os.unlink(full_name)
+
+ def run_latex(self, module, test_name):
+ tmp_dir = settings.get_tmp_dir()
+ src_latex_file = os.path.join(module, test_name + '.tex')
+ tmp_latex_file = os.path.join(tmp_dir, test_name + '.tex')
+ tmp_log_file = os.path.join(tmp_dir, test_name + '.log')
+ #
+ # Create a TeX file from a tempate
+ #
+ h = open(src_latex_file)
+ s = h.read()
+ h.close()
+ s = self.template.replace('##CODE##', s)
+ h = open(tmp_latex_file, 'w')
+ h.write(s)
+ h.close()
+ #
+ # Run LaTeX
+ #
+ cmd = 'cd %s; %s -interaction batchmode %s.tex >/dev/null' % (tmp_dir, settings.get_latex(), test_name)
+ os.system(cmd)
+ return tmp_log_file
+
+ # -------------------------------------------------------
+ # Log-file works
+
+ #
+ # Comparing expected and the got results
+ #
+ def check_log(self, module, test_name, log_file):
+ s_got = self.collect_log(log_file)
+ chk_file = os.path.join(module, test_name + '.chk')
+ h = open(chk_file)
+ s_expected = h.read()
+ h.close()
+ s_expected = re_comment.sub('', s_expected)
+ s_expected = s_expected.strip()
+ s_got = s_got.strip()
+ #
+ # It is convenient to know where exactly start difference
+ #
+ if s_expected != s_got:
+ pos = 0
+ maxpos = min(len(s_expected), len(s_got))
+ while (pos < maxpos) and (s_expected[pos] == s_got[pos]):
+ pos = pos +1
+ s_expected = s_expected[:pos] + '---->' + s_expected[pos:]
+ s_got = s_got[:pos] + '---->' + s_got[pos:]
+ self.assertEqual(s_got, s_expected)
+
+ #
+ # The test case: run latex and check log
+ #
+ def run_test_case(self, module, test_name):
+ log_file = self.run_latex(module, test_name)
+ self.check_log(module, test_name, log_file)
+ self.check_pdf(module, test_name)
+
+ #
+ # Log parsing
+ #
+ def collect_macro(self, h, macro_dump):
+ for l in h:
+ l = l.strip()
+ macro_dump = macro_dump + "\n" + l
+ if (len(l) > 0) and ('.' == l[-1]):
+ break
+ return macro_dump
+
+ def collect_box(self, h, box_dump):
+ box_dump = re.sub('[0-9]+', 'XX', box_dump)
+ for l in h:
+ l = l.strip()
+ if '' == l:
+ break
+ box_dump = box_dump + "\n" + l
+ return box_dump
+
+ def collect_log(self, log_file):
+ s = ''
+ h = open(log_file)
+ for l in h:
+ l = l.strip()
+ if re_macro_start.match(l):
+ macro_dump = self.collect_macro(h, l)
+ s = s + macro_dump + "\n"
+ if re_box_start.match(l):
+ box_dump = self.collect_box(h, l)
+ s = s + box_dump + "\n"
+ if re_some_show.match(l):
+ s = s + l + "\n"
+ if re_message.match(l):
+ if l != '! OK.':
+ s = s + l + "\n"
+ if l.startswith('Package test Info: '):
+ pos = l.index('on input line ')
+ s = s + l[19:pos]
+ s = s.rstrip()
+ s = s + "\n"
+ return s
+
+ # -------------------------------------------------------
+ # Output works
+
+ def check_pdf(self, module, test_name):
+ #
+ # First, check if output testing is required
+ #
+ expected_pngs = glob.glob(os.path.join(module, test_name+'*.png'))
+ if not len(expected_pngs):
+ return
+ expected_pngs = [os.path.basename(x) for x in expected_pngs]
+ #
+ # Generate PNGs and check we got the same number of files
+ #
+ tmp_dir = settings.get_tmp_dir()
+ cmd = "cd %s; convert -density 300x300 %s.pdf %s.png" % (tmp_dir, test_name, test_name)
+ os.system(cmd)
+ got_pngs = glob.glob(os.path.join(tmp_dir, test_name+'*.png'))
+ got_pngs = [os.path.basename(x) for x in got_pngs]
+ self.assertEqual(expected_pngs, got_pngs)
+ #
+ # Compare the PNGs
+ #
+ for png in expected_pngs:
+ expected_png = os.path.join(module, png)
+ got_png = os.path.join(tmp_dir, png)
+ diff_png = os.path.join(tmp_dir, 'diff.png')
+ cmd = "compare compare -metric RMSE %s %s %s 2>%s" % (expected_png, got_png, diff_png, os.path.join(tmp_dir, 'compare-stdout'))
+ os.system(cmd)
+ h = open(os.path.join(tmp_dir, 'compare-stdout'))
+ s = h.read()
+ h.close()
+ s = s.strip()
+ self.assertEqual('0 (0)', s)
diff --git a/macros/latex/contrib/cals/test/support/run_tests.py b/macros/latex/contrib/cals/test/support/run_tests.py
new file mode 100644
index 0000000000..07ee27cd50
--- /dev/null
+++ b/macros/latex/contrib/cals/test/support/run_tests.py
@@ -0,0 +1,67 @@
+import glob, os, new, sys
+import unittest
+import LatexTest
+
+#
+# Settings
+#
+class Settings:
+ def __init__(self):
+ sty_dir = os.path.normpath(os.path.join(os.getcwd(), '..', 'dev'))
+ old_ti = os.getenv('TEXINPUTS', '')
+ os.environ['TEXINPUTS'] = sty_dir + ':' + old_ti
+ def get_tmp_dir(self):
+ return 'tmp'
+ def get_latex(self):
+ return 'pdflatex'
+LatexTest.settings = Settings()
+
+#
+# Collect tests
+#
+filter = None
+if len(sys.argv) > 1:
+ filter = sys.argv[1]
+test_files = glob.glob('*/test_*.tex')
+test_files = [x for x in test_files if 'visual_tables' not in x]
+modules_and_tests = {}
+for fname in test_files:
+ (dir, basename) = os.path.split(fname)
+ if 'tmp' == dir:
+ continue
+ if filter:
+ if filter not in fname:
+ continue
+ modules_and_tests.setdefault(dir, []).append(basename)
+
+#
+# Test function
+#
+def generic_test_func(self, modname, testname):
+ print 'I am a test case with parameters:', self.__class__, modname, testname
+ self.assertEqual(1, 1)
+
+#
+# Create test classes and functions
+#
+test_classes = []
+for module in modules_and_tests.iterkeys():
+ mtname = 'Test' + module.capitalize()
+ cls = new.classobj(mtname, (LatexTest.LatexTestCase,), {})
+ for test_file in modules_and_tests[module]:
+ test_name = os.path.splitext(test_file)[0]
+ def get_test_func(func, module, test_name):
+ def proxied(self):
+ func(self, module, test_name)
+ return proxied
+ setattr(cls, test_name, get_test_func(LatexTest.LatexTestCase.run_test_case, module, test_name))
+ test_classes.append(cls)
+
+#
+# Run the tests
+#
+if __name__ == '__main__':
+ tl = unittest.TestLoader()
+ tests = [tl.loadTestsFromTestCase(x) for x in test_classes]
+ tests = unittest.TestSuite(tests)
+ unittest.TextTestRunner(verbosity=2).run(tests)
diff --git a/macros/latex/contrib/cals/test/table/test_10_ifbreak.chk b/macros/latex/contrib/cals/test/table/test_10_ifbreak.chk
new file mode 100644
index 0000000000..e2b30b0f87
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_10_ifbreak.chk
@@ -0,0 +1,22 @@
+%
+% Test 1
+%
+OK
+%
+% Test 2
+%
+OK
+%
+% Test 3
+%
+OK
+OK
+%
+% Test 4
+%
+OK
+OK
+%
+% Test 5
+%
+OK
diff --git a/macros/latex/contrib/cals/test/table/test_10_ifbreak.tex b/macros/latex/contrib/cals/test/table/test_10_ifbreak.tex
new file mode 100644
index 0000000000..d8af581190
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_10_ifbreak.tex
@@ -0,0 +1,53 @@
+%
+\newbox\cals@current@row % To be removed after defined in cals.sty
+%
+\def\mkcurrow#1{\setbox\cals@current@row=\vbox to #1{a\vfil}%
+ \ht\cals@current@row=#1\relax}
+%\def\mkbakrow#1{\setbox\cals@backup@row=\vbox to #1{a\vfil}}
+\def\mkfoot#1{\def\cals@tfoot@tokens{aaa}\def\cals@tfoot@height{#1}}
+\def\rmfoot{\let\cals@tfoot@tokens=\relax}
+
+\def\ok{\PackageInfo{test}{OK}}
+\def\fail{\PackageInfo{test}{FAIL}}
+
+\let\cals@tbreak@tokens=\relax
+
+%
+% 1: Body, no break
+%
+\def\pagegoal{400pt}
+\def\pagetotal{300pt}
+\mkfoot{50pt}
+\mkcurrow{50pt}
+\let\cals@last@context=b
+\let\cals@current@context=b
+\cals@ifbreak\iftrue \fail \else \ok \fi
+
+%
+% 2: Body, break
+%
+\mkcurrow{60pt}
+\cals@ifbreak\iftrue \ok \else \fail \fi
+
+%
+% 3: No break in head or foot
+%
+\let\cals@current@context=h
+\cals@ifbreak\iftrue \fail \else \ok \fi
+\let\cals@current@context=f
+\cals@ifbreak\iftrue \fail \else \ok \fi
+\let\cals@current@context=b
+
+%
+% 4: No break after the header
+%
+\let\cals@current@context=b
+\cals@ifbreak\iftrue \ok \else \fail \fi
+\let\cals@last@context=h
+\cals@ifbreak\iftrue \fail \else \ok \fi
+
+%
+% 5: User forces a break
+%
+\tbreak{ok}
+\cals@ifbreak\iftrue \ok \else \fail \fi
diff --git a/macros/latex/contrib/cals/test/table/test_20_dispatch.chk b/macros/latex/contrib/cals/test/table/test_20_dispatch.chk
new file mode 100644
index 0000000000..7990c8bc64
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_20_dispatch.chk
@@ -0,0 +1,56 @@
+%
+% Normal table
+%
+> \boxXX=
+\vbox(1020.0+0.0)x220.0
+% Head
+.\vbox(110.0+0.0)x110.0
+..\rule(110.0+0.0)x110.0
+.\vbox(120.0+0.0)x120.0
+..\rule(120.0+0.0)x120.0
+.\vbox(110.0+0.0)x110.0
+..\rule(110.0+0.0)x110.0
+% Body 1 and Body 2
+.\vbox(10.0+0.0)x10.0
+..\rule(10.0+0.0)x10.0
+.\vbox(20.0+0.0)x20.0
+..\rule(20.0+0.0)x20.0
+.\vbox(10.0+0.0)x10.0
+..\rule(10.0+0.0)x10.0
+% Foot 1 and Foot 2
+.\vbox(210.0+0.0)x210.0
+..\rule(210.0+0.0)x210.0
+.\vbox(220.0+0.0)x220.0
+..\rule(220.0+0.0)x220.0
+.\vbox(210.0+0.0)x210.0
+..\rule(210.0+0.0)x210.0
+%
+% A break in a table
+%
+> \boxXX=
+\vbox(470.0+0.0)x210.0
+.\vbox(10.0+0.0)x10.0
+..\rule(10.0+0.0)x10.0
+.\vbox(210.0+0.0)x210.0
+..\rule(210.0+0.0)x210.0
+.\penalty -10000
+.\vbox(110.0+0.0)x110.0
+..\rule(110.0+0.0)x110.0
+.\vbox(120.0+0.0)x120.0
+..\rule(120.0+0.0)x120.0
+.\vbox(20.0+0.0)x20.0
+..\rule(20.0+0.0)x20.0
+%
+% Span
+%
+> \boxXX=
+\vbox(60.0+0.0)x20.0
+.\vbox(10.0+0.0)x10.0
+..\rule(10.0+0.0)x10.0
+.\vbox(30.0+0.0)x20.0
+..\vbox(20.0+0.0)x20.0
+...\rule(20.0+0.0)x20.0
+..\vbox(10.0+0.0)x10.0
+...\rule(10.0+0.0)x10.0
+.\vbox(20.0+0.0)x20.0
+..\rule(20.0+0.0)x20.0
diff --git a/macros/latex/contrib/cals/test/table/test_20_dispatch.tex b/macros/latex/contrib/cals/test/table/test_20_dispatch.tex
new file mode 100644
index 0000000000..4d4910c2e2
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_20_dispatch.tex
@@ -0,0 +1,65 @@
+%
+% Some redefs
+%
+\def\cals@issue@rowsep{\vbox{\hrule width400pt height4pt depth0pt}}
+\def\cals@issue@row{\nointerlineskip \box\cals@current@row}
+
+\def\cals@current@rs@above{rsabove}
+\def\cals@current@rs@below{rsbelow}
+\renewcommand\lastrule{}
+
+\def\somerow#1#2{%
+\setbox\cals@current@row=\vbox{\hrule width#1 height#1 depth0pt}%
+\let\cals@current@context=#2%
+\cals@row@dispatch
+}
+
+\def\bodyrowI{\somerow{10pt}b}
+\def\bodyrowII{\somerow{20pt}b}
+\def\headrowI{\somerow{110pt}h}
+\def\headrowII{\somerow{120pt}h}
+\def\footrowI{\somerow{210pt}f}
+\def\footrowII{\somerow{220pt}f}
+
+%
+% Normal table
+%
+\setbox0=\vbox{%
+\headrowI
+\headrowII
+\headrowI
+\bodyrowI
+\bodyrowII
+\bodyrowI
+\footrowI
+\footrowII
+\footrowI
+}
+\showbox0
+
+%
+% Make a break
+%
+\setbox0=\vbox{%
+\def\cals@thead@tokens{\headrowI\headrowII}
+\def\cals@tfoot@tokens{\footrowI}
+\bodyrowI
+\tbreak{\break}
+\bodyrowII
+}
+\showbox0
+
+%
+% Span
+%
+\setbox0=\vbox{%
+\bodyrowI
+ \let\cals@ifInRspan=\cals@iftrue
+ \let\cals@ifLastRspanRow=\cals@iffalse
+\bodyrowII
+ \let\cals@ifLastRspanRow=\cals@iftrue
+\bodyrowI
+ \let\cals@ifInRspan=\cals@iffalse
+\bodyrowII
+}
+\showbox0
diff --git a/macros/latex/contrib/cals/test/table/test_30_issue_rowsep.chk b/macros/latex/contrib/cals/test/table/test_30_issue_rowsep.chk
new file mode 100644
index 0000000000..b416b189eb
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_30_issue_rowsep.chk
@@ -0,0 +1,110 @@
+%
+% Alone
+%
+> \boxXX=
+\vbox(0.0+0.0)x330.0
+.\hbox(0.0+0.0)x330.0
+..\glue 0.0
+..\glue 210.0
+..\glue -3.0
+..\rule(2.0+2.0)x127.0
+..\glue -4.0
+..\glue 0.0
+%
+% n to h, f, b: exactly the same as "alone"
+%
+> \boxXX=
+\vbox(0.0+0.0)x330.0
+.\hbox(0.0+0.0)x330.0
+..\glue 0.0
+..\glue 210.0
+..\glue -3.0
+..\rule(2.0+2.0)x127.0
+..\glue -4.0
+..\glue 0.0
+> \boxXX=
+\vbox(0.0+0.0)x330.0
+.\hbox(0.0+0.0)x330.0
+..\glue 0.0
+..\glue 210.0
+..\glue -3.0
+..\rule(2.0+2.0)x127.0
+..\glue -4.0
+..\glue 0.0
+> \boxXX=
+\vbox(0.0+0.0)x330.0
+.\hbox(0.0+0.0)x330.0
+..\glue 0.0
+..\glue 210.0
+..\glue -3.0
+..\rule(2.0+2.0)x127.0
+..\glue -4.0
+..\glue 0.0
+%
+% h to h: default width; h to f,b: body separation
+%
+> \boxXX=
+\vbox(0.0+0.0)x330.0
+.\hbox(0.0+0.0)x330.0
+..\glue 0.0
+..\glue -1.0
+% relax-width here
+..\rule(0.5+0.5)x103.0
+..\glue -2.0
+..\glue -2.0
+..\rule(1.0+1.0)x115.0
+..\glue -3.0
+..\glue -110.0
+..\glue -2.0
+% also relax-width
+..\rule(0.5+0.5)x236.0
+..\glue -4.0
+..\glue -120.0
+..\glue -3.0
+..\rule(2.0+2.0)x127.0
+..\glue -4.0
+..\glue 0.0
+%
+% Body separation
+%
+> \boxXX=
+\vbox(0.0+0.0)x330.0
+.\hbox(0.0+0.0)x330.0
+..\glue 0.0
+..\glue -1.0
+% relax-width here
+..\rule(1.5+1.5)x103.0
+..\glue -2.0
+..\glue -2.0
+..\rule(1.0+1.0)x115.0
+..\glue -3.0
+..\glue -110.0
+..\glue -2.0
+% also relax-width
+..\rule(1.5+1.5)x236.0
+..\glue -4.0
+..\glue -120.0
+..\glue -3.0
+..\rule(2.0+2.0)x127.0
+..\glue -4.0
+..\glue 0.0
+> \cals@tmpIII=macro:
+->3pt.
+%
+% f to h and b: never happens, body separation; f to f: default width
+%
+> \cals@tmpIII=macro:
+->3pt.
+> \cals@tmpIII=macro:
+->1pt.
+> \cals@tmpIII=macro:
+->3pt.
+%
+% b to h: never happens, body separation; b to b: default, b to f: body
+%
+> \cals@tmpIII=macro:
+->3pt.
+> \cals@tmpIII=macro:
+->3pt.
+> \cals@tmpIII=macro:
+->1pt.
diff --git a/macros/latex/contrib/cals/test/table/test_30_issue_rowsep.tex b/macros/latex/contrib/cals/test/table/test_30_issue_rowsep.tex
new file mode 100644
index 0000000000..2e33f8ad57
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_30_issue_rowsep.tex
@@ -0,0 +1,52 @@
+\def\cals@framers@width{0pt}
+\def\cals@bodyrs@width{3pt}
+\def\cals@rs@width{1pt}
+
+%
+% Reusable definitions
+%
+\def\frameI{{{100pt}{2pt}{4pt}\relax}{{110pt}{4pt}{6pt}{2pt}}{{120pt}{6pt}{8pt}\relax}}
+\def\frameII{{{100pt}{2pt}{4pt}\relax}{{110pt}{4pt}{6pt}\relax}{{120pt}{6pt}{8pt}{4pt}}}
+\def\update{%
+\toks0=\expandafter{\frameI}%
+\edef\cals@last@rs@below{\the\toks0}%
+\toks0=\expandafter{\frameII}%
+\edef\cals@current@rs@above{\the\toks0}%
+}
+
+%
+% Alone
+%
+\update
+\setbox0=\vbox{\cals@issue@rowsep@alone}
+\showbox0
+
+%
+% Different combinations
+%
+\def\combineII#1#2{%
+\let\cals@last@context=#1%
+\let\cals@current@context=#2%
+\update
+\setbox0=\vbox{\cals@issue@rowsep}}
+\def\combine#1#2{\combineII#1#2\showbox0 }
+
+% n h f b vs h f b
+\combine nh
+\combine nf
+\combine nb
+\combine hh
+\combine hf
+
+%
+% Optimize the rest: do not pollute expected results
+%
+\renewcommand\cals@rs@joinTwo[3]{%
+\show#1}
+\combineII hb
+\combineII fh
+\combineII ff
+\combineII fb
+\combineII bh
+\combineII bf
+\combineII bb
diff --git a/macros/latex/contrib/cals/test/table/test_40_issuerow.chk b/macros/latex/contrib/cals/test/table/test_40_issuerow.chk
new file mode 100644
index 0000000000..470a7f3829
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_40_issuerow.chk
@@ -0,0 +1,28 @@
+> \cals@last@context=the letter b.
+> \cals@last@rs@below=macro:
+->{{200pt}{2pt}{2pt}{7pt}}.
+> \boxXX=
+\vbox(20.0+0.0)x300.0
+.\vbox(0.0+0.0)x10.0
+..\hbox(20.0+0.0)x10.0
+...\glue 0.0
+...\hbox(20.0+0.0)x10.0
+....\rule(*+0.0)x10.0
+...\glue 0.0
+.\hbox(0.0+0.0)x200.0
+..\glue 0.0
+..\glue -1.0
+..\rule(2.0+2.0)x202.0
+..\glue -1.0
+..\glue 0.0
+.\hbox(20.0+0.0)x300.0
+..\glue 0.0
+..\hbox(20.0+0.0)x300.0
+...\vbox(20.0+0.0)x100.0, glue set 10.0fil
+....\rule(10.0+0.0)x100.0
+....\glue 0.0 plus 1.0fil
+...\vbox(20.0+0.0)x200.0
+....\rule(20.0+0.0)x200.0
+....\glue 0.0 plus 1.0fil
+..\glue 0.0
+.\penalty 10000
diff --git a/macros/latex/contrib/cals/test/table/test_40_issuerow.tex b/macros/latex/contrib/cals/test/table/test_40_issuerow.tex
new file mode 100644
index 0000000000..f46144ba3e
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_40_issuerow.tex
@@ -0,0 +1,25 @@
+%
+% vboxes of the row should be of the same height
+%
+\let\cals@last@context=h
+\let\cals@current@context=b
+\def\cals@bodyrs@width{4pt}
+
+\newbox\cals@current@row
+\setbox\cals@current@row=\hbox{%
+ \vbox{\hrule height10pt depth0pt width100pt \vfil}%
+ \vbox{\hrule height20pt depth0pt width200pt \vfil}%
+}
+\cals@reheight@cells\cals@current@row
+
+\newbox\cals@current@cs
+\setbox\cals@current@cs=\hbox{\vrule width10pt depth0pt}
+\ht\cals@current@cs=\ht\cals@current@row
+\def\cals@current@rs@above{{{200pt}{2pt}{2pt}\relax}}
+\def\cals@current@rs@below{{{200pt}{2pt}{2pt}{7pt}}}
+\def\cals@last@rs@below{{{200pt}{2pt}{2pt}\relax}}
+
+\setbox0=\vbox{\cals@issue@row
+\show\cals@last@context
+\show\cals@last@rs@below}
+\showbox0
diff --git a/macros/latex/contrib/cals/test/table/test_50_row.chk b/macros/latex/contrib/cals/test/table/test_50_row.chk
new file mode 100644
index 0000000000..eb34dae652
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_50_row.chk
@@ -0,0 +1,102 @@
+> \cals@last@context=the letter b.
+> \cals@last@rs@below=macro:
+->{{100pt}{0pt}{10pt}{10pt}}{{200pt}{10pt}{20pt}{20pt}}.
+> 20.0pt.
+> \cals@last@context=the letter b.
+> \cals@last@rs@below=macro:
+->{{100pt}{0pt}{30pt}{30pt}}{{200pt}{30pt}{40pt}{40pt}}.
+> 40.0pt.
+%
+% The table
+%
+> \boxXX=
+\vbox(60.0+0.0)x300.0
+%
+% Row 1, colsep
+%
+.\vbox(0.0+0.0)x300.0
+..\hbox(20.0+0.0)x300.0
+...\glue 0.0
+...\hbox(20.0+0.0)x300.0
+....\glue 100.0
+....\glue -5.0
+....\rule(*+0.0)x10.0
+....\glue -5.0
+....\glue 200.0
+....\glue -10.0
+....\rule(*+0.0)x20.0
+....\glue -10.0
+...\glue 0.0
+%
+% Rowsep before row 1
+%
+.\hbox(0.0+0.0)x300.0
+..\glue 0.0
+..\glue 300.0
+..\glue 0.0
+%
+% Row 1
+%
+.\hbox(20.0+0.0)x300.0
+..\glue 0.0
+..\hbox(20.0+0.0)x300.0
+...\vbox(20.0+0.0)x100.0, glue set 10.0fil
+....\rule(10.0+0.0)x100.0
+....\glue 0.0 plus 1.0fil
+...\vbox(20.0+0.0)x200.0
+....\rule(20.0+0.0)x200.0
+....\glue 0.0 plus 1.0fil
+..\glue 0.0
+.\penalty 10000
+% %
+% % Output procesure forcing
+% % 18.11.2016: conditionally
+% %
+% .\glue 0.0
+% .\penalty 10000
+%
+% Row 2, colsep
+%
+.\vbox(0.0+0.0)x300.0
+..\hbox(40.0+0.0)x300.0
+...\glue 0.0
+...\hbox(40.0+0.0)x300.0
+....\glue 100.0
+....\glue -15.0
+....\rule(*+0.0)x30.0
+....\glue -15.0
+....\glue 200.0
+....\glue -20.0
+....\rule(*+0.0)x40.0
+....\glue -20.0
+...\glue 0.0
+%
+% Rowsep between row 1 and row 2
+%
+.\hbox(0.0+0.0)x300.0
+..\glue 0.0
+..\glue 0.0
+..\rule(5.0+5.0)x115.0
+..\glue -15.0
+..\glue -5.0
+..\rule(10.0+10.0)x215.0
+..\glue -10.0
+..\glue -200.0
+..\glue -15.0
+..\rule(5.0+5.0)x235.0
+..\glue -20.0
+..\glue 0.0
+%
+% Row 2
+%
+.\hbox(40.0+0.0)x300.0
+..\glue 0.0
+..\hbox(40.0+0.0)x300.0
+...\vbox(40.0+0.0)x100.0, glue set 10.0fil
+....\rule(30.0+0.0)x100.0
+....\glue 0.0 plus 1.0fil
+...\vbox(40.0+0.0)x200.0
+....\rule(40.0+0.0)x200.0
+....\glue 0.0 plus 1.0fil
+..\glue 0.0
+.\penalty 10000
diff --git a/macros/latex/contrib/cals/test/table/test_50_row.tex b/macros/latex/contrib/cals/test/table/test_50_row.tex
new file mode 100644
index 0000000000..5fa49715de
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_50_row.tex
@@ -0,0 +1,44 @@
+%
+% A smoke test for \row
+%
+\def\mkcell#1{\edef\cals@borderB{#1}\edef\cals@borderR{#1}%
+\cell{\nointerlineskip\noindent\vrule height#1 depth0pt width#1}}
+\def\mkcellI{\mkcell{10pt}}
+\def\mkcellII{\mkcell{20pt}}
+\def\mkcellIII{\mkcell{30pt}}
+\def\mkcellIV{\mkcell{40pt}}
+
+\let\cals@last@context=n
+\let\cals@current@context=b
+
+\def\cals@cs@width{0pt}
+\def\cals@framecs@width{0pt}
+\def\cals@rs@width{10pt}
+\def\cals@framers@width{0pt}
+\def\cals@bodyrs@width{0pt}
+\def\cals@bgcolor{}
+\def\cals@bgcolor{}
+\let\cals@borderL=\relax
+\let\cals@borderR=\relax
+\let\cals@borderT=\relax
+\let\cals@borderB=\relax
+
+\def\cals@ifbreak#1{\iffalse}
+\let\oldend=\cals@celll@end
+\def\cals@celll@end{%
+ \setbox0=\vbox{\hrule height\ht0 depth0pt width\wd0 \vfil}%
+ \oldend}
+
+\colwidths{{100pt}{200pt}}
+
+\setbox0=\vbox{%
+\brow \mkcellI\mkcellII \erow
+\show\cals@last@context
+\show\cals@last@rs@below
+\showthe\cals@last@row@height
+\brow \mkcellIII\mkcellIV \erow
+\show\cals@last@context
+\show\cals@last@rs@below
+\showthe\cals@last@row@height
+}
+\showbox0
diff --git a/macros/latex/contrib/cals/test/table/test_60_whitespace.chk b/macros/latex/contrib/cals/test/table/test_60_whitespace.chk
new file mode 100644
index 0000000000..a5e0c8760a
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_60_whitespace.chk
@@ -0,0 +1,2 @@
+> \boxXX=
+\vbox(0.0+0.0)x0.0
diff --git a/macros/latex/contrib/cals/test/table/test_60_whitespace.tex b/macros/latex/contrib/cals/test/table/test_60_whitespace.tex
new file mode 100644
index 0000000000..55d4ca10ba
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_60_whitespace.tex
@@ -0,0 +1,21 @@
+\def\cals@issue@rowsep@alone{}
+\def\cals@issue@rowsep{}
+\def\cals@issue@row{}
+
+%
+% Check that there are no unneeded whitespace in output
+%
+
+\setbox0=\vbox{
+
+\begin{calstable}
+
+\colwidths{{100pt}{200pt}}
+
+\brow{}
+ \cell{aaaaa} \nullcell{ltb} \nullcell{rtb} \spancontent{bbbbb} \cell{bbbb} \erow{} % ok
+\end{calstable}
+
+}
+
+\showbox0
diff --git a/macros/latex/contrib/cals/test/table/test_70_lrskip.chk b/macros/latex/contrib/cals/test/table/test_70_lrskip.chk
new file mode 100644
index 0000000000..6d2b08afe3
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_70_lrskip.chk
@@ -0,0 +1,30 @@
+> \boxXX=
+\vbox(20.0+0.0)x300.0
+% colsep
+.\vbox(0.0+0.0)x300.0
+..\hbox(20.0+0.0)x300.0
+...\glue 50.0
+...\hbox(20.0+0.0)x100.0
+....\glue 100.0
+...\glue 150.0
+% rowsep
+.\hbox(0.0+0.0)x300.0
+..\glue 50.0
+..\glue 100.0
+..\glue 150.0
+% cell
+.\hbox(20.0+0.0)x300.0
+..\glue 50.0
+..\hbox(20.0+0.0)x100.0
+...\vbox(20.0+0.0)x100.0, glue set 20.0fil
+....\glue 0.0
+....\glue 0.0 plus -1.0
+....\glue 0.0 plus 1.0fil
+....\glue 0.0
+..\glue 150.0
+.\penalty 10000
+% rowsep
+.\hbox(0.0+0.0)x300.0
+..\glue 50.0
+..\glue 100.0
+..\glue 150.0
diff --git a/macros/latex/contrib/cals/test/table/test_70_lrskip.tex b/macros/latex/contrib/cals/test/table/test_70_lrskip.tex
new file mode 100644
index 0000000000..a6d507b738
--- /dev/null
+++ b/macros/latex/contrib/cals/test/table/test_70_lrskip.tex
@@ -0,0 +1,22 @@
+par1\par
+\parindent=0pt
+par2\par
+
+\setbox0=\vbox{%
+\leftskip=50pt
+\rightskip=150pt
+\begin{calstable}
+\cals@setpadding{}
+\cals@setcellprevdepth{}
+\def\borderL{0pt}
+\let\borderR=\borderL
+\let\borderT=\borderL
+\let\borderB=\borderL
+\colwidths{{100pt}}
+\brow \cell{} \ht\cals@current@row=20pt \erow
+\end{calstable}
+}
+\showbox0
+\box0
+par3\par
+par4\par
diff --git a/macros/latex/contrib/cals/test/template.txt b/macros/latex/contrib/cals/test/template.txt
new file mode 100644
index 0000000000..0e75651466
--- /dev/null
+++ b/macros/latex/contrib/cals/test/template.txt
@@ -0,0 +1,34 @@
+\documentclass{minimal}
+\usepackage{color}
+\makeatletter
+\showboxdepth=100
+\showboxbreadth=100
+
+%\iftrue
+\iffalse
+\usepackage{cals}
+\else
+\input{cell.dtx}
+\input{table.dtx}
+\input{span.dtx}
+\input{lltokens.dtx}
+\input{decor.dtx}
+\input{colsep.dtx}
+\input{rowsep.dtx}
+\input{rtl.dtx}
+\fi
+
+% Variables defined inside calstable environment
+\let\cals@thead@tokens=\relax
+\let\cals@tfoot@tokens=\relax
+\let\cals@tbreak@tokens=\relax
+\let\cals@ifInRspan=\cals@iffalse
+\let\cals@ifLastRspanRow=\cals@iftrue
+\let\cals@borderL=\relax
+\let\cals@borderR=\relax
+\let\cals@borderT=\relax
+\let\cals@borderB=\relax
+
+\begin{document}
+##CODE##
+\end{document}
diff --git a/macros/latex/contrib/cals/test/visual_tables/test_10_simple_2x2_with_parbreak.chk b/macros/latex/contrib/cals/test/visual_tables/test_10_simple_2x2_with_parbreak.chk
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/macros/latex/contrib/cals/test/visual_tables/test_10_simple_2x2_with_parbreak.chk
diff --git a/macros/latex/contrib/cals/test/visual_tables/test_10_simple_2x2_with_parbreak.png b/macros/latex/contrib/cals/test/visual_tables/test_10_simple_2x2_with_parbreak.png
new file mode 100644
index 0000000000..242bc2be54
--- /dev/null
+++ b/macros/latex/contrib/cals/test/visual_tables/test_10_simple_2x2_with_parbreak.png
Binary files differ
diff --git a/macros/latex/contrib/cals/test/visual_tables/test_10_simple_2x2_with_parbreak.tex b/macros/latex/contrib/cals/test/visual_tables/test_10_simple_2x2_with_parbreak.tex
new file mode 100644
index 0000000000..0763a13ef0
--- /dev/null
+++ b/macros/latex/contrib/cals/test/visual_tables/test_10_simple_2x2_with_parbreak.tex
@@ -0,0 +1,11 @@
+%
+% Make the same table as in the version 1
+\def\cals@framecs@width{1.2pt }
+\def\cals@framers@width{1.2pt }
+%
+\hrule width\hsize \vskip10pt
+\begin{calstable}
+\colwidths{{60pt}{120pt}}
+\brow \cell{aaa\\a} \cell{bbb} \erow
+\brow \cell{ccc} \cell{ddd\\dg} \erow
+\end{calstable}
diff --git a/macros/latex/contrib/cals/test/visual_tables/test_20_thead_tfoot.chk b/macros/latex/contrib/cals/test/visual_tables/test_20_thead_tfoot.chk
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/macros/latex/contrib/cals/test/visual_tables/test_20_thead_tfoot.chk
diff --git a/macros/latex/contrib/cals/test/visual_tables/test_20_thead_tfoot.png b/macros/latex/contrib/cals/test/visual_tables/test_20_thead_tfoot.png
new file mode 100644
index 0000000000..86f9b2db18
--- /dev/null
+++ b/macros/latex/contrib/cals/test/visual_tables/test_20_thead_tfoot.png
Binary files differ
diff --git a/macros/latex/contrib/cals/test/visual_tables/test_20_thead_tfoot.tex b/macros/latex/contrib/cals/test/visual_tables/test_20_thead_tfoot.tex
new file mode 100644
index 0000000000..86b88dd19a
--- /dev/null
+++ b/macros/latex/contrib/cals/test/visual_tables/test_20_thead_tfoot.tex
@@ -0,0 +1,20 @@
+\def\cbll#1{\cell{\textbf{#1}}}
+%
+\begin{calstable}
+\colwidths{{60pt}{120pt}}
+%
+\thead{Hello from the THead caption!\par
+\brow \cbll{eee} \cbll{fff} \erow
+\brow \cbll{ggg} \cbll{hhh} \erow
+}
+%
+\tfoot{
+\brow \cbll{iii} \cbll{jjj} \erow
+\brow \cbll{kkk} \cbll{lll} \erow
+\lastrule
+I am the TFoot caption\par
+}
+%
+\brow \cell{aaa} \cell{bbb} \erow
+\brow \cell{ccc} \cell{ddd} \erow
+\end{calstable}
diff --git a/macros/latex/contrib/cals/test/visual_tables/test_30_tbreak.chk b/macros/latex/contrib/cals/test/visual_tables/test_30_tbreak.chk
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/macros/latex/contrib/cals/test/visual_tables/test_30_tbreak.chk
diff --git a/macros/latex/contrib/cals/test/visual_tables/test_30_tbreak.png b/macros/latex/contrib/cals/test/visual_tables/test_30_tbreak.png
new file mode 100644
index 0000000000..f53e6498bb
--- /dev/null
+++ b/macros/latex/contrib/cals/test/visual_tables/test_30_tbreak.png
Binary files differ
diff --git a/macros/latex/contrib/cals/test/visual_tables/test_30_tbreak.tex b/macros/latex/contrib/cals/test/visual_tables/test_30_tbreak.tex
new file mode 100644
index 0000000000..ddfbb3b227
--- /dev/null
+++ b/macros/latex/contrib/cals/test/visual_tables/test_30_tbreak.tex
@@ -0,0 +1,27 @@
+\hrule width\hsize \vskip10pt
+
+\begin{calstable}
+\colwidths{{60pt}{120pt}}
+\brow \cell{aaa} \cell{bbb} \erow
+\brow \cell{ccc} \cell{ddd} \erow
+\tbreak{(break)\par}
+\brow \cell{eee} \cell{fff} \erow
+\brow \cell{ggg} \cell{hhh} \erow
+\end{calstable}
+
+\bigskip
+\hrule height5pt depth5pt width180pt
+\bigskip
+
+\def\cbll#1{\cell{\textbf{#1}}}
+\begin{calstable}
+\colwidths{{60pt}{120pt}}
+\thead{\brow\cbll{iii}\cbll{jjj}\erow}
+\tfoot{\brow\cbll{kkk}\cbll{lll}\erow}
+\brow \cell{aaa} \cell{bbb} \erow
+\brow \cell{ccc} \cell{ddd} \erow
+\tbreak{(break)\par}
+\brow \cell{eee} \cell{fff} \erow
+\brow \cell{ggg} \cell{hhh} \erow
+\end{calstable}
+
diff --git a/macros/latex/contrib/cals/test/visual_tables/test_40_span.chk b/macros/latex/contrib/cals/test/visual_tables/test_40_span.chk
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/macros/latex/contrib/cals/test/visual_tables/test_40_span.chk
diff --git a/macros/latex/contrib/cals/test/visual_tables/test_40_span.png b/macros/latex/contrib/cals/test/visual_tables/test_40_span.png
new file mode 100644
index 0000000000..d3f73b584e
--- /dev/null
+++ b/macros/latex/contrib/cals/test/visual_tables/test_40_span.png
Binary files differ
diff --git a/macros/latex/contrib/cals/test/visual_tables/test_40_span.tex b/macros/latex/contrib/cals/test/visual_tables/test_40_span.tex
new file mode 100644
index 0000000000..08568db94e
--- /dev/null
+++ b/macros/latex/contrib/cals/test/visual_tables/test_40_span.tex
@@ -0,0 +1,52 @@
+\hrule width\hsize \vskip10pt
+\begin{calstable}
+\colwidths{{60pt}}
+\brow
+ \cell{a6} % a6
+ \cell{b6} % b6
+ \cell{c6} % c6
+ \cell{d6} % d6
+ \cell{e6} % e6
+ \cell{f6} % f6
+ \erow
+\brow
+ \cell{a5} % a5
+ \nullcell{ltb} % b5
+ \nullcell{tb} % c5
+ \nullcell{rtb}\spancontent{b5, c5, d5} % d5
+ \nullcell{ltr} % e5
+ \cell{f5} % f5
+ \erow
+\brow
+ \cell{a4} % a4
+ \nullcell{ltr} % b4
+ \nullcell{tl} % c4
+ \nullcell{tr} % d4
+ \nullcell{lr} % e4
+ \cell{f4} % f4
+ \erow
+\brow
+ \cell{a3} % a3
+ \nullcell{lr} % b3
+ \nullcell{lb} % c3
+ \nullcell{rb}\spancontent{c3, c4, d3, d4} % d3
+ \nullcell{lrb}\spancontent{e3, e4, e5} % e3
+ \cell{f3} % f3
+ \erow
+\brow
+ \cell{a2} % a2
+ \nullcell{lrb}\spancontent{b2, b3, b4} % b2
+ \nullcell{ltb} % c2
+ \nullcell{tb} % d2
+ \nullcell{tbr} % e2
+ \spancontent{c2, d2, e2}\cell{f2} % f2
+ \erow
+\brow
+ \cell{a1} % a1
+ \cell{b1} % b1
+ \cell{c1} % c1
+ \cell{d1} % d1
+ \cell{e1} % e1
+ \cell{f1} % f1
+ \erow
+\end{calstable}