#!/bin/sh
#
# Regression tester for SRC.
#

# Set the umask for a bit of defensiveness
umask 0077

# Needs to not be a subdirectory of here, or git gets confused.  Use
# -u so that src's initialization will be tested.
SANDBOX=$(mktemp -u /tmp/src_XXXXXXXX)

# Set the PATH to include the current directory, so the repository
# head version of src can always be tested.
PATH="$(pwd)":$PATH

trap "rm -fr $SANDBOX" 0 1 2 15

backend="rcs"
python="python"

while getopts b:p: opt
do
    case $opt in
	b) backend=$OPTARG;;
	p) python=$OPTARG;;
    esac
done
shift $(($OPTIND - 1))

check() {
    case $? in
	0) echo "srctest ($python $backend): $1 succeeded";;
	*) echo "srctest ($python $backend): $1 failed"; exit 1;;
    esac
}

SRCDIR=${PWD}

mkdir $SANDBOX
check "scratch directory creation"

cd $SANDBOX

TESTOPTS="-T $* $backend"

DIFFOPTS="--label Expected --label Actual -u"

SRC="${python} ${SRCDIR}/src"

COLUMNS=73
export COLUMNS

cat >testfile1 <<EOF
Now is the time
EOF
cp testfile1 testrev1

${SRC} $TESTOPTS commit -m "First comment" testfile1 #>/dev/null
check "commit with -m option"

${SRC} $TESTOPTS cat testfile1 | diff -u testfile1 - >/dev/null
check "content check after first commit"

cat >testfile1 <<EOF
Now is the time
for all good men
EOF
cp testfile1 testrev2

cat >testfile4 <<EOF
@@ -1,2 +1,3 @@
 Now is the time
+for all good men
 
EOF

# (read; read; cat) removes header lines containing variable date information
${SRC} $TESTOPTS diff testfile1 | (read discard; read discard; cat) >testfile5
diff -u testfile4 testfile5
check "nonempty diff"


sleep 1	# Force commit to have different timestamp
echo "Second comment" | ${SRC} $TESTOPTS commit - testfile1 >/dev/null
check "commit with -"

${SRC} $TESTOPTS cat testfile1 | diff $DIFFOPTS testfile1 -
check "content check after second commit"

cat >testfile2 <<EOF
= testfile1 ============================================================
2     * 1970-01-02T00:01:00Z Second comment
1     - 1970-01-02T00:00:00Z First comment
EOF

${SRC} $TESTOPTS list testfile1 >testfile3
diff $DIFFOPTS testfile2 testfile3
check "list test"

cat >testfile2 <<EOF
= testfile1 ============================================================
2    | 1970-01-02T00:01:00Z | trunk
Second comment
------------------------------------------------------------------------
1    | 1970-01-02T00:00:00Z | trunk
First comment
------------------------------------------------------------------------
EOF

${SRC} $TESTOPTS log testfile1 >testfile3
diff $DIFFOPTS testfile2 testfile3
check "2-commit log test"

cat >testfile1 <<EOF
Now is the time
for all good men
to come to the aid of foo
EOF
cp testfile1 testrev3

sleep 1	# Force commit to have different timestamp
cat >testfile4 <<EOF
'Third' comment

Multiline test.

EOF
${SRC} $TESTOPTS commit -f testfile4 testfile1 >/dev/null
check "commit with -f"

cat >testfile4 <<EOF
= testfile1 ============================================================
3    | 1970-01-02T00:02:00Z | trunk
'Third' comment

Multiline test.
------------------------------------------------------------------------
2    | 1970-01-02T00:01:00Z | trunk
Second comment
------------------------------------------------------------------------
1    | 1970-01-02T00:00:00Z | trunk
First comment
------------------------------------------------------------------------
EOF

${SRC} $TESTOPTS log testfile1 >testfile5
diff $DIFFOPTS testfile4 testfile5
check "3-commit log test"

cat >testfile6 <<EOF
= testfile1 ============================================================
src: testfile1 has no 5 revision
EOF

${SRC} $TESTOPTS list 5 testfile1 >testfile7 2>&1
diff $DIFFOPTS testfile6 testfile7
check "oob revision spec check"

for rev in 1 2 3
do
    ${SRC} $TESTOPTS checkout $rev testfile1 >/dev/null
    check "revision $rev checkout test"
    diff $DIFFOPTS testrev${rev} testfile1
    check "revision $rev content test"
done

if [ "$backend" = "sccs" ]
then
    echo "srctest ($python $backend): skipping tag creation/deletion/listing checks."
else
    ${SRC} $TESTOPTS tag create sampletag
    check "tag set to default tip revision"

    cat >testfile8 <<EOF
= testfile1 ==========================================================
   3	sampletag
EOF
    ${SRC} $TESTOPTS tag list >testfile9
    diff $DIFFOPTS testfile8 testfile9
    check "tag list check"

    ${SRC} $TESTOPTS tag create basetag 1
    check "tag set to revision 1"

    cat >testfile10 <<EOF
= testfile1 ==========================================================
   1	basetag
   3	sampletag
EOF
    ${SRC} $TESTOPTS tag -l >testfile11
    diff $DIFFOPTS testfile10 testfile11
    check "second tag list check"

    ${SRC} $TESTOPTS tag delete sampletag
    check "tag deletion: sampletag"

    cat >testfile12 <<EOF
= testfile1 ==========================================================
   1	basetag
EOF
    ${SRC} $TESTOPTS tag >testfile13
    diff $DIFFOPTS testfile12 testfile13
    check "tag list check after deletion"

    # Alas, we have to do this or the fast-export regression will fail.
    # We don't know how to be perfectly canonical about tags yet.
    ${SRC} $TESTOPTS tag delete basetag
    check "tag deletion: basetag"
fi

mkdir foo
${SRC} $TESTOPTS fast-export testfile1 >testfile14
cat testfile14 | (cd foo >/dev/null; git init --quiet; git fast-import --quiet)
(cd foo >/dev/null; git fast-export --all) >testfile15
diff $DIFFOPTS testfile14 testfile15
check "fast-export"
rm -fr foo

# There was a point at which fast-export was broken,
# but the test was passing because an empty file
# produced a repo that git dumped as an empty file!  
grep jrh testfile15 >/dev/null
check "fast-export content check"

historify () {
    case $backend in
	rcs) history=.src/$1,v ;;
	sccs) history=SCCS/s.$1 ;;
    esac
}

${SRC} $TESTOPTS move testfile1 newname1
check "move command"
historify newname1
if [ -e newname1 -a -e $history ]
then
    echo "srctest ($python $backend): content move succeeded"
else
    echo "srctest ($python $backend): content move failed"
    exit 1
fi

${SRC} $TESTOPTS copy newname1 newname2
check "copy command"
historify newname2
if [ -e newname2 -a -e $history ]
then
    echo "srctest ($python $backend): content copy succeeded"
else
    echo "srctest ($python $backend): content copy failed"
    exit 1
fi

cat >testfile16 <<EOF
newname1
newname2
EOF
${SRC} $TESTOPTS ls | diff $DIFFOPTS testfile16 -
check "ls"

${SRC} $TESTOPTS commit -m "Another sample" testfile16
${SRC} $TESTOPTS status testfile16 | grep "^=" >/dev/null
check "= status check after first commit"

echo "Add a second line" >>testfile16
${SRC} $TESTOPTS status testfile16 | grep "^M" >/dev/null
check "M status check after modification"

rm testfile16
${SRC} $TESTOPTS status testfile16 | grep "^!" >/dev/null
check "! status check after deletion"

${SRC} $TESTOPTS checkout testfile16
${SRC} $TESTOPTS status testfile16 | grep "^=" >/dev/null
check "= status check after restoration"

historify testfile16
rm -f $history
${SRC} $TESTOPTS status testfile16 | grep "^?" >/dev/null
check "? status check after master deletion"

${SRC} $TESTOPTS amend -m "Amended comment" newname1
check "amend"

${SRC} $TESTOPTS list 3 newname1 | grep "Amended comment" >/dev/null
check "amended comment content"

cat >testfile17 <<EOF
=	newname1
=	newname2
EOF
${SRC} $TESTOPTS status | diff $DIFFOPTS testfile17 - >/dev/null
check "unadorned status command"

if [ "$backend" = "sccs" ]
then
    echo "srctest ($python $backend): skipping tag and branch tests"
else
    # Introduce a test history with some branchiness, so
    # we can test traversal across branch joins. Also has tags.
    cat >.src/sample,v <<EOF
head	1.4;
branch	1.3.1.4.1;
access;
symbols
	GLARB:1.4
	GORP:1.3.1.4
	sample:1.3.1.4.0.1
	muggle:1.3.0.1;
locks
	esr:1.3.1.4.1.5;
comment	@# @;
expand	@b@;


1.4
date	2014.11.11.03.26.53;	author esr;	state Exp;
branches;
next	1.3;

1.3
date	2014.11.10.23.48.49;	author esr;	state Exp;
branches
	1.3.1.1;
next	1.2;

1.2
date	2014.11.10.23.48.11;	author esr;	state Exp;
branches;
next	1.1;

1.1
date	2014.11.10.23.47.08;	author esr;	state Exp;
branches;
next	;

1.3.1.1
date	2014.11.11.04.23.47;	author esr;	state Exp;
branches;
next	1.3.1.2;

1.3.1.2
date	2014.11.11.06.39.47;	author esr;	state Exp;
branches;
next	1.3.1.3;

1.3.1.3
date	2014.11.11.06.48.00;	author esr;	state Exp;
branches;
next	1.3.1.4;

1.3.1.4
date	2014.11.12.03.36.45;	author esr;	state Exp;
branches
	1.3.1.4.1.1;
next	;

1.3.1.4.1.1
date	2014.11.13.04.04.55;	author esr;	state Exp;
branches;
next	1.3.1.4.1.2;

1.3.1.4.1.2
date	2014.11.13.04.23.04;	author esr;	state Exp;
branches;
next	1.3.1.4.1.3;

1.3.1.4.1.3
date	2014.11.13.04.26.23;	author esr;	state Exp;
branches;
next	1.3.1.4.1.4;

1.3.1.4.1.4
date	2014.11.13.04.30.39;	author esr;	state Exp;
branches;
next	1.3.1.4.1.5;

1.3.1.4.1.5
date	2014.11.13.04.31.02;	author esr;	state Exp;
branches;
next	;


desc
@@


1.4
log
@On a branch?
@
text
@Now is the time
For all good men.
To come to the aid of foo.
This should be branch text.
@


1.3
log
@Third comment.
@
text
@d4 1
@


1.3.1.1
log
@Totally unfubared.
@
text
@a3 2

Again, this should be branch text.
@


1.3.1.2
log
@Still utterly fubar
@
text
@d5 1
a5 1
Yet again, this should be branch text.
@


1.3.1.3
log
@Totally chenille.
@
text
@a5 2

Revision 7.
@


1.3.1.4
log
@Utterly fubar
@
text
@d4 4
a7 2
This should be branch text.
Try a comment with a hyphen.
@


1.3.1.4.1.1
log
@All fixed up.
@
text
@a5 1
Test of commit comments.
@


1.3.1.4.1.2
log
@It' all good.
@
text
@a6 1
Glotch.
@


1.3.1.4.1.3
log
@No good.
@
text
@a7 1
Random modification.
@


1.3.1.4.1.4
log
@That's good.
@
text
@a4 1
jjjj
d7 1
@


1.3.1.4.1.5
log
@I see you
@
text
@d5 1
a5 1
jjjjjjjjkkk
@


1.2
log
@Second comment.
@
text
@d3 1
@


1.1
log
@First comment.
@
text
@d2 1
@
EOF

cat >sampledot <<EOF
digraph {
	1 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">1</font></td><td>First comment.</td></tr></table>>];
	1 -> 2;
	2 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">2</font></td><td>Second comment.</td></tr></table>>];
	2 -> 3;
	3 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">3</font></td><td>Third comment.</td></tr></table>>];
	3 -> 4;
	4 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">4</font></td><td>On a branch?</td></tr></table>>];
	"trunk" [shape=oval,width=2];
	"4" -> "trunk" [style=dotted];
	3 -> 5;
	5 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">5</font></td><td>Totally unfubared.</td></tr></table>>];
	5 -> 6;
	6 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">6</font></td><td>Still utterly fubar</td></tr></table>>];
	6 -> 7;
	7 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">7</font></td><td>Totally chenille.</td></tr></table>>];
	7 -> 8;
	8 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">8</font></td><td>Utterly fubar</td></tr></table>>];
	"muggle" [shape=oval,width=2];
	"8" -> "muggle" [style=dotted];
	8 -> 9;
	9 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">9</font></td><td>All fixed up.</td></tr></table>>];
	9 -> 10;
	10 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">10</font></td><td>It' all good.</td></tr></table>>];
	10 -> 11;
	11 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">11</font></td><td>No good.</td></tr></table>>];
	11 -> 12;
	12 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">12</font></td><td>That's good.</td></tr></table>>];
	12 -> 13;
	13 [shape=box,width=5,label=<<table cellspacing="0" border="0" cellborder="0"><tr><td><font color="blue">13</font></td><td>I see you</td></tr></table>>];
	"sample" [shape=oval,width=2];
	"13" -> "sample" [style=dotted];
	{rank=same; "GLARB"; "4"}
	"GLARB" -> "4" [style=dotted];
	{rank=same; "GORP"; "8"}
	"GORP" -> "8" [style=dotted];
}
EOF

    ${SRC} $TESTOPTS visualize sample >tryit
    diff $DIFFOPTS sampledot tryit
    check "dot visualization"

    cat >statuslog <<EOF
=	newname1
=	newname2
EOF

    cat >sample.seqlog <<EOF
= sample ===============================================================
6    | 1970-01-02T00:05:00Z | muggle
Still utterly fubar
------------------------------------------------------------------------
5    | 1970-01-02T00:04:00Z | muggle
Totally unfubared.
------------------------------------------------------------------------
4    | 1970-01-02T00:03:00Z | trunk
On a branch?
------------------------------------------------------------------------
3    | 1970-01-02T00:02:00Z | trunk
Third comment.
------------------------------------------------------------------------
2    | 1970-01-02T00:01:00Z | trunk
Second comment.
------------------------------------------------------------------------
EOF

    ${SRC} $TESTOPTS log 6-2 sample >tryit
    diff $DIFFOPTS sample.seqlog tryit
    check "traversal by -"

    cat >sample.branchlog <<EOF
= sample ===============================================================
6    | 1970-01-02T00:05:00Z | muggle
Still utterly fubar
------------------------------------------------------------------------
5    | 1970-01-02T00:04:00Z | muggle
Totally unfubared.
------------------------------------------------------------------------
3    | 1970-01-02T00:02:00Z | trunk
Third comment.
------------------------------------------------------------------------
2    | 1970-01-02T00:01:00Z | trunk
Second comment.
------------------------------------------------------------------------
EOF

    ${SRC} $TESTOPTS log 6..2 sample >tryit
    diff $DIFFOPTS sample.branchlog tryit
    check "traversal by .."

    cat >sample.taglog <<EOF
= sample ===============================================================
4     - 1970-01-02T00:03:00Z On a branch?
EOF

    ${SRC} $TESTOPTS list @GLARB sample >tryit
    diff $DIFFOPTS sample.taglog tryit
    check "named-tag lookup with @"

    ${SRC} $TESTOPTS rename tag GLARB GROTTY sample
    check "tag renaming"

    cat >changes <<EOF
= sample =============================================================
   8	GORP
   4	GROTTY
EOF

    ${SRC} $TESTOPTS tag -l sample >tryit
    diff $DIFFOPTS tryit changes
    check "tag list after rename"

    cat >branchlist <<EOF
= sample =============================================================
   0	trunk
   3	muggle
   8	sample
EOF

    ${SRC} $TESTOPTS branch -l sample >tryit
    check "branch list"

    ${SRC} $TESTOPTS branch -l sample >tryit
    diff $DIFFOPTS branchlist tryit
    check "branch list content"

    cat >branchlog <<EOF
= sample ===============================================================
4     - 1970-01-02T00:03:00Z On a branch?
EOF

    ${SRC} $TESTOPTS list @trunk sample >branchlog
    check "branch name resolution"

    ${SRC} $TESTOPTS list @trunk sample >tryit
    diff $DIFFOPTS branchlog tryit
    check "branch name resolved content"

    cat >statuslog <<EOF
=	newname1
=	newname2
EOF

    ${SRC} $TESTOPTS status newname1 newname2 >tryit
    diff $DIFFOPTS statuslog tryit
    check "status before ignore"

    echo "newname1" >.srcignore

    cat >statuslog <<EOF
I	newname1
=	newname2
EOF

    ${SRC} $TESTOPTS status newname1 newname2 >tryit
    diff $DIFFOPTS statuslog tryit
    check "status after ignore"

    ${SRC} $TESTOPTS branch delete trunk sample
    check "branch delete"

    cat >newlist <<EOF
= sample =============================================================
   0	trunk
   3	muggle
   7	sample
EOF

    ${SRC} $TESTOPTS branch -l sample >tryit
    diff $DIFFOPTS newlist tryit
    check "branch list check after delete"

    cat >newlog <<EOF
= sample ===============================================================
12   | 1970-01-02T00:11:00Z | sample
I see you
------------------------------------------------------------------------
11   | 1970-01-02T00:10:00Z | sample
That's good.
------------------------------------------------------------------------
10   | 1970-01-02T00:09:00Z | sample
No good.
------------------------------------------------------------------------
9    | 1970-01-02T00:08:00Z | sample
It' all good.
------------------------------------------------------------------------
8    | 1970-01-02T00:07:00Z | sample
All fixed up.
------------------------------------------------------------------------
7    | 1970-01-02T00:06:00Z | muggle
Utterly fubar
------------------------------------------------------------------------
6    | 1970-01-02T00:05:00Z | muggle
Totally chenille.
------------------------------------------------------------------------
5    | 1970-01-02T00:04:00Z | muggle
Still utterly fubar
------------------------------------------------------------------------
4    | 1970-01-02T00:03:00Z | muggle
Totally unfubared.
------------------------------------------------------------------------
3    | 1970-01-02T00:02:00Z | trunk
Third comment.
------------------------------------------------------------------------
2    | 1970-01-02T00:01:00Z | trunk
Second comment.
------------------------------------------------------------------------
1    | 1970-01-02T00:00:00Z | trunk
First comment.
------------------------------------------------------------------------
EOF

    ${SRC} $TESTOPTS log sample >tryit 
    diff $DIFFOPTS newlog tryit
    check "content after branch deletion"
fi
  
echo "Random content for numeric file" >23
${SRC} $TESTOPTS commit -m "I don't know why you say goodbye" -- 23 >/dev/null
check "commit of file with numeric name"

cat >randomcontent <<EOF
Random content for numeric file
EOF

${SRC} $TESTOPTS cat -- 23 >tryit
diff $DIFFOPTS randomcontent tryit
check "cat of file with numeric name"

echo "Should not be executable" >exectest
${SRC} $TESTOPTS commit -m "First comment on exectest" exectest >/dev/null
check "first commit of exectest"
chmod a+x exectest
echo "Should be executable" >exectest
${SRC} $TESTOPTS commit -m "Second comment on exectest" exectest >/dev/null
check "second commit of exectest"
ls -l exectest | grep 'x' >/dev/null
check "propagation of exec bit"

# Test for Tom Willemse's multi-commit bug.
echo "test 1" > file1
echo "test 2" > file2
${SRC} $TESTOPTS commit -m "Initial commit" file1 file2 >/dev/null
check "multi-file registration"
echo "test 1 line 2" >> file1
echo "test 2 line 2" >> file2
${SRC} $TESTOPTS commit -m "Second commit" file1 file2 >/dev/null
check "multi-file commit"

# Test the edit logic
cat >modify <<'EOF'
echo "Different first line" >modified$$
cat $1 >>modified$$
mv modified$$ $1
EOF
chmod a+x modify
echo "test 1 line 3" >> file1
EDITOR="./modify" ${SRC} $TESTOPTS commit file1
check "edit logic"

cat >binary <<EOF
This file contains an 0xD3 (Meta-S) after the colon:
EOF
cat >binary.chk <<EOF
This file contains an 0xD3 (Meta-S) after the colon:
Additional content line.
EOF
${SRC} $TESTOPTS commit -m "Test file containing binary byte." binary
echo "Additional content line." >>binary
${SRC} $TESTOPTS commit -m "Binary file after modification." binary
cmp binary binary.chk
check "binary content in checkouts and commits"

if [ "$backend" = "sccs" ]
then
    echo "srctest ($python $backend): skipping binary cat test"
else
    ${SRC} $TESTOPTS cat binary >catted
    cmp binary catted
    check "binary content in cat"
fi

cat >newline <<EOF
This file contains a DOS newline 0x0D after the colon:
EOF
cat >newline.chk <<EOF
This file contains a DOS newline 0x0D after the colon:
Additional content line.
EOF
${SRC} $TESTOPTS commit -m "Test file containing DOS newline." newline
echo "Additional content line." >>newline
${SRC} $TESTOPTS commit -m "DOS newline file after modification." newline
cmp newline newline.chk
check "newline preservation in checkouts and commits"

if [ "$backend" = "sccs" ]
then
    echo "srctest ($python $backend): skipping newline cat test"
else
    ${SRC} $TESTOPTS cat newline >ncatted
    cmp newline ncatted
    check "newline content in cat"
fi

echo "srctest ($python $backend): all tests succeeded"

rm -fr $SANDBOX

# end
