testcases/lib: Add test.sh test library + docs.

* Add test.sh test library

* Add documentation into test-writing-guidelines

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
diff --git a/doc/test-writing-guidelines.txt b/doc/test-writing-guidelines.txt
index 3e51a00..c79f914 100644
--- a/doc/test-writing-guidelines.txt
+++ b/doc/test-writing-guidelines.txt
@@ -42,6 +42,9 @@
 1.3 Coding style
 ~~~~~~~~~~~~~~~~
 
+1.3.1 C coding style
+^^^^^^^^^^^^^^^^^^^^
+
 LTP adopted Linux kernel coding style. If you aren't familiar with its rules
 locate 'linux/Documentation/CodingStyle' in the kernel sources and read it,
 it's a well written introduction.
@@ -52,7 +55,27 @@
 NOTE: If checkpatch does not report any problems, the code still may be wrong
       as the tool only looks for common mistakes.
 
-TODO: bash code coding style?
+1.3.2 Shell coding style
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+When writing testcases in shell write in portable shell only, it's a good idea
+to try to run the test using alternative shell (alternative to bash, for
+example dash) too.
+
+Here are some common sense style rules for shell
+
+* Keep lines under 80 chars
+
+* Use tabs for indentation
+
+* Keep things simple, avoid unnecessary shubshells
+
+* Don't do confusing things (i.e. don't name your functions like common shell
+  commands, etc.)
+
+* Quote variables
+
+* Be consistent
 
 1.4 Commenting code
 ~~~~~~~~~~~~~~~~~~~
@@ -648,6 +671,99 @@
 	}
 -------------------------------------------------------------------------------
 
+2.3 Writing a testcase in shell
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+LTP supports testcases to be written in a portable shell too.
+
+There is a shell library modeled closely to the C interface (the source is
+located at 'testcases/lib/test.sh') and is installed to the same directory as
+the rest of the LTP test binaries.
+
+WARNING: All identifiers starting with TST_ or tst_ are reserved for the
+         'test.sh' library.
+
+2.3.1 Basic shell test structure
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+[source,sh]
+-------------------------------------------------------------------------------
+#!/bin/sh
+#
+# This is a basic test for true shell buildin
+#
+
+TCID=true01
+TST_TOTAL=1
+. test.sh
+
+true
+ret=$?
+
+if [ $ret -eq 0 ]; then
+	tst_resm TPASS "true returned 0"
+else
+	tst_resm TFAIL "true rturned $ret"
+fi
+
+tst_exit
+-------------------------------------------------------------------------------
+
+TIP: To execute this test the 'test.sh' library must be in '$PATH'. If you are
+     executing the test from a git checkout you can run it as
+     'PATH="$PATH:../../lib" ./foo01.sh'
+
+WARNING: Do not forget to add the 'tst_exit' at the end of the test,
+         otherwise the test return value would be the return value of last
+	 executed command.
+
+2.3.2 Basic test interface
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Following functions similar to the LTP C intearface are available.
+
+* tst_resm()
+* tst_brkm()
+* tst_exit()
+* tst_require_root()
+* tst_tmpdir()
+* tst_rmdir()
+
+There is one more function called 'tst_check_cmds()' that gets unspecified
+number of parameters and asserts that each parameter is a name of an
+executable in '$PATH' and exits the test with 'TCONF' on first missing.
+
+2.3.3 Cleanup
+^^^^^^^^^^^^^
+
+Due to differencies in C and shell, the cleanup callback is done using a
+'TST_CLEANUP' shell variable that, if not empty, is evaluated before the test
+exits (either after calling 'tst_exit()' or 'tst_brkm()'). See example below.
+
+[source,sh]
+-------------------------------------------------------------------------------
+#!/bin/sh
+#
+# Test cleanup example
+#
+
+TCID=true01
+TST_TOTAL=1
+. test.sh
+
+cleanup()
+{
+	tst_rmdir
+}
+
+tst_tmpdir
+TST_CLEANUP=cleanup
+
+# Do the test here
+
+tst_exit
+-------------------------------------------------------------------------------
+
 3. Test Contribution Checklist
 ------------------------------
 
diff --git a/testcases/lib/test.sh b/testcases/lib/test.sh
new file mode 100644
index 0000000..b857dc4
--- /dev/null
+++ b/testcases/lib/test.sh
@@ -0,0 +1,128 @@
+#!/bin/sh
+#
+# Copyright (c) Linux Test Project, 2014
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Written by Cyril Hrubis <chrubis@suse.cz>
+#
+# This is a LTP test library for shell.
+#
+
+export LTP_RET_VAL=0
+export LTP_TST_CNT=1
+
+# Exit values map
+tst_flag2mask()
+{
+	case "$1" in
+	TPASS) return 0;;
+	TFAIL) return 1;;
+	TBROK) return 2;;
+	TWARN) return 4;;
+	TRETR) return 8;;
+	TINFO) return 16;;
+	TCONF) return 32;;
+	*) tst_brkm TBROK "Invalid resm type '$1'";;
+	esac
+}
+
+tst_resm()
+{
+	tst_flag2mask "$1"
+	local mask=$?
+	LTP_RET_VAL=$((LTP_RET_VAL|mask))
+
+	echo "$TCID $LTP_TST_CNT $1 : $2"
+
+	case "$1" in
+	TPASS|TFAIL)
+	LTP_TST_CNT=$((LTP_TST_CNT+1));;
+	esac
+}
+
+tst_brkm()
+{
+	case "$1" in
+	TFAIL) ;;
+	TBROK) ;;
+	TCONF) ;;
+	TRETR) ;;
+	*) tst_brkm TBROK "Invalid tst_brkm type '$1'";;
+	esac
+
+	tst_resm "$1" "$2"
+	tst_exit
+}
+
+tst_require_root()
+{
+	if [ "$(id -ru)" != 0 ]; then
+		tst_brkm TCONF "Must be super/root for this test!"
+	fi
+}
+
+tst_exit()
+{
+	if [ -n "$TST_CLEANUP" ]; then
+		$TST_CLEANUP
+	fi
+
+	# Mask out TRETR, TINFO and TCONF
+	exit $((LTP_RET_VAL & ~(8 | 16 | 32)))
+}
+
+tst_tmpdir()
+{
+	if [ -z "$TMPDIR" ]; then
+		export TMPDIR="/tmp"
+	fi
+
+	TST_TMPDIR=$(mktemp -d "$TMPDIR/$TCID.XXXXXXXXXX")
+
+	cd "$TST_TMPDIR"
+}
+
+tst_rmdir()
+{
+	cd "$LTPROOT"
+	rm -r "$TST_TMPDIR"
+}
+
+#
+# Checks if coomands passed as arguments exists
+#
+tst_check_cmds()
+{
+	for cmd in $*; do
+		if ! command -v $cmd > /dev/null 2>&1; then
+			tst_brkm TCONF "'$cmd' not found"
+		fi
+	done
+}
+
+# Check that test name is set
+if [ -z "$TCID" ]; then
+	tst_brkm TBROK "TCID is not defined"
+fi
+
+if [ -z "$TST_TOTAL" ]; then
+	tst_brkm TBROK "TST_TOTAL is not defined"
+fi
+
+# Setup LTPROOT, default to current directory if not set
+if [ -z "$LTPROOT" ]; then
+	export LTPROOT="$PWD"
+fi