From 5d35aef265483eca4f84d576427d898536be68e4 Mon Sep 17 00:00:00 2001 From: Olof Svensson Date: Wed, 25 Sep 2013 08:45:05 +0200 Subject: [PATCH 01/17] move to opid14 users --- eu.esrf.test/global_script_esrf/dawn_global_startup.py | 2 +- eu.esrf.test/src/analysis.py | 4 ++-- eu.esrf.test/src/script_jenkins | 7 +++---- eu.esrf.test/src/test_variables.py | 5 ++++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/eu.esrf.test/global_script_esrf/dawn_global_startup.py b/eu.esrf.test/global_script_esrf/dawn_global_startup.py index 0cb943f..797d93e 100644 --- a/eu.esrf.test/global_script_esrf/dawn_global_startup.py +++ b/eu.esrf.test/global_script_esrf/dawn_global_startup.py @@ -1,4 +1,4 @@ -DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1004_jonathan/workspace" +DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1004_opid14/workspace" DAWN_SUITE_WORKSPACE="suite_test_single_workspace" USE_ATTACH=False diff --git a/eu.esrf.test/src/analysis.py b/eu.esrf.test/src/analysis.py index dc48744..27cf236 100755 --- a/eu.esrf.test/src/analysis.py +++ b/eu.esrf.test/src/analysis.py @@ -7,10 +7,10 @@ listing = os.listdir(logpath) time= time.strftime('%d_%m_%y(%H:%M)',time.localtime()) -#logfile = open("/scisoft/jenkins/ub1004_jonathan/workspace/Dawn_squish_tests/squish_tst_"+time+".txt", "a") + for infile in sorted(listing): - #f = open('/scisoft/jenkins/ub1004_jonathan/workspace/Dawn_squish_tests/log/'+infile) + f = open(os.path.join(logpath,infile)) strData = f.read() f.close() diff --git a/eu.esrf.test/src/script_jenkins b/eu.esrf.test/src/script_jenkins index 85c6090..f2a85a4 100755 --- a/eu.esrf.test/src/script_jenkins +++ b/eu.esrf.test/src/script_jenkins @@ -1,11 +1,10 @@ #!/bin/sh Xvfb :2 & export DISPLAY=:2 -export PATH=/sware/isdd/soft/java/v7u17/linux_x64/jdk1.7.0_17/bin:$PATH -cd /scisoft/jenkins/ub1004_jonathan/squish-4.2.3-java-linux64/bin/ -./squishserver &>/$WORKSPACE/serverlog +cd /scisoft/jenkins/ub1004_opid14/squish-4.2.3-java-linux64/bin/ +./squishserver & >/$WORKSPACE/serverlog sleep 1 -/scisoft/jenkins/ub1004_jonathan/squish-4.2.3-java-linux64/bin/squishrunner --testsuite /scisoft/jenkins/ub1004_jonathan/workspace/Dawn_squish_tests/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/$1_squishlog +/scisoft/jenkins/ub1004_opid14/squish-4.2.3-java-linux64/bin/squishrunner --testsuite /scisoft/jenkins/ub1004_opid14/workspace/Dawn_squish_tests_production/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/$1_squishlog var1=$(ps -aef |grep squishserver | grep -v grep | awk '{ print $2; }' | head -1) kill -9 $var1 var2=$(ps -aef |grep Xvfb | grep -v grep | awk '{ print $2; }' | head -1) diff --git a/eu.esrf.test/src/test_variables.py b/eu.esrf.test/src/test_variables.py index 0a5de4b..53a7ceb 100755 --- a/eu.esrf.test/src/test_variables.py +++ b/eu.esrf.test/src/test_variables.py @@ -10,7 +10,7 @@ def check_variable(testSuiteName): path_global_script=os.path.join(os.environ['WORKSPACE'],'org.dawnsci.squishtests',testSuiteName,'shared/scripts') if os.path.exists(path_global_script)== True: shutil.rmtree(path_global_script) - shutil.copytree('/scisoft/jenkins/ub1004_jonathan/workspace/Dawn_squish_tests/eu.esrf.test/global_script_esrf',path_global_script) + shutil.copytree('/scisoft/jenkins/ub1004_opid14/workspace/Dawn_squish_tests/eu.esrf.test/global_script_esrf',path_global_script) def setup_log(): path_log=os.path.join(os.environ['WORKSPACE'] +'/log/') @@ -23,4 +23,7 @@ def setup_log(): check_variable(testSuiteName) for tst in queue[testSuiteName]: os.chdir(os.path.join(os.environ['WORKSPACE'],'eu.esrf.test/src')) + print '***************************' + print (os.path.join(os.environ['WORKSPACE'],'eu.esrf.test/src')) + print ("./script_jenkins "+testSuiteName+" "+queue[testSuiteName][tst]) os.popen("./script_jenkins "+testSuiteName+" "+queue[testSuiteName][tst], "r").read() From 522fc6dce51bb23846d3398f4ede74cada41721b Mon Sep 17 00:00:00 2001 From: Olof Svensson Date: Wed, 25 Sep 2013 14:01:54 +0200 Subject: [PATCH 02/17] change ub1004 to ub1204 on scrip_jenkins --- eu.esrf.test/src/script_jenkins | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eu.esrf.test/src/script_jenkins b/eu.esrf.test/src/script_jenkins index f2a85a4..7e44f99 100755 --- a/eu.esrf.test/src/script_jenkins +++ b/eu.esrf.test/src/script_jenkins @@ -1,10 +1,10 @@ #!/bin/sh Xvfb :2 & export DISPLAY=:2 -cd /scisoft/jenkins/ub1004_opid14/squish-4.2.3-java-linux64/bin/ +cd /scisoft/jenkins/ub1204_opid14/squish-4.2.3-java-linux64/bin/ ./squishserver & >/$WORKSPACE/serverlog sleep 1 -/scisoft/jenkins/ub1004_opid14/squish-4.2.3-java-linux64/bin/squishrunner --testsuite /scisoft/jenkins/ub1004_opid14/workspace/Dawn_squish_tests_production/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/$1_squishlog +/scisoft/jenkins/ub1204_opid14/squish-4.2.3-java-linux64/bin/squishrunner --testsuite /scisoft/jenkins/ub1204_opid14/workspace/Dawn_squish_tests_production/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/$1_squishlog var1=$(ps -aef |grep squishserver | grep -v grep | awk '{ print $2; }' | head -1) kill -9 $var1 var2=$(ps -aef |grep Xvfb | grep -v grep | awk '{ print $2; }' | head -1) From c5b5a693a1b15015bf0bcdde5a79ef1c71174070 Mon Sep 17 00:00:00 2001 From: Olof Svensson Date: Wed, 25 Sep 2013 14:17:23 +0200 Subject: [PATCH 03/17] change ub1004 to ub1204 in test_variable and dawn global startup --- eu.esrf.test/global_script_esrf/dawn_global_startup.py | 2 +- eu.esrf.test/src/test_variables.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eu.esrf.test/global_script_esrf/dawn_global_startup.py b/eu.esrf.test/global_script_esrf/dawn_global_startup.py index 797d93e..f58b56c 100644 --- a/eu.esrf.test/global_script_esrf/dawn_global_startup.py +++ b/eu.esrf.test/global_script_esrf/dawn_global_startup.py @@ -1,4 +1,4 @@ -DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1004_opid14/workspace" +DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1204_opid14/workspace" DAWN_SUITE_WORKSPACE="suite_test_single_workspace" USE_ATTACH=False diff --git a/eu.esrf.test/src/test_variables.py b/eu.esrf.test/src/test_variables.py index 53a7ceb..917544f 100755 --- a/eu.esrf.test/src/test_variables.py +++ b/eu.esrf.test/src/test_variables.py @@ -10,7 +10,7 @@ def check_variable(testSuiteName): path_global_script=os.path.join(os.environ['WORKSPACE'],'org.dawnsci.squishtests',testSuiteName,'shared/scripts') if os.path.exists(path_global_script)== True: shutil.rmtree(path_global_script) - shutil.copytree('/scisoft/jenkins/ub1004_opid14/workspace/Dawn_squish_tests/eu.esrf.test/global_script_esrf',path_global_script) + shutil.copytree('/scisoft/jenkins/ub1204_opid14/workspace/Dawn_squish_tests/eu.esrf.test/global_script_esrf',path_global_script) def setup_log(): path_log=os.path.join(os.environ['WORKSPACE'] +'/log/') From a8ad5b98d51629c5b40f718516597aea0c607211 Mon Sep 17 00:00:00 2001 From: Olof Svensson Date: Wed, 25 Sep 2013 14:43:15 +0200 Subject: [PATCH 04/17] test --- eu.esrf.test/src/test_variables.py | 1 + 1 file changed, 1 insertion(+) diff --git a/eu.esrf.test/src/test_variables.py b/eu.esrf.test/src/test_variables.py index 917544f..238f2ec 100755 --- a/eu.esrf.test/src/test_variables.py +++ b/eu.esrf.test/src/test_variables.py @@ -1,5 +1,6 @@ #!/usr/bin/python2.6 import os,shutil + #only one queue allowed for one suite_test_case queue = {'suite_workflows_general': {'tst_case2':'tst_open_examples'}} #queue.update({'suite_usecases_general':{'tst_case':'tst_hdf5_large_tree'}}) From 1c9b84f98beeb58e069cbcbd9f57cf65ab2ad272 Mon Sep 17 00:00:00 2001 From: Olof Svensson Date: Wed, 25 Sep 2013 14:45:59 +0200 Subject: [PATCH 05/17] change tests --- eu.esrf.test/src/test_variables.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eu.esrf.test/src/test_variables.py b/eu.esrf.test/src/test_variables.py index 238f2ec..5b81467 100755 --- a/eu.esrf.test/src/test_variables.py +++ b/eu.esrf.test/src/test_variables.py @@ -2,9 +2,9 @@ import os,shutil #only one queue allowed for one suite_test_case -queue = {'suite_workflows_general': {'tst_case2':'tst_open_examples'}} +#queue = {'suite_workflows_general': {'tst_case2':'tst_open_examples'}} #queue.update({'suite_usecases_general':{'tst_case':'tst_hdf5_large_tree'}}) -queue.update({'suite_workflows_bignexus':{'tst_case':'tst_slicedata_dbrowsing'}}) +queue({'suite_workflows_bignexus':{'tst_case':'tst_slicedata_dbrowsing'}}) #queue['suite_workflows_bignexus'] = {'tst_case':'tst_slicedata_dexplore'} def check_variable(testSuiteName): From df25e134046cc4a4bd4ac086958cc1a3c33d5342 Mon Sep 17 00:00:00 2001 From: Olof Svensson Date: Wed, 25 Sep 2013 14:52:41 +0200 Subject: [PATCH 06/17] test change v1.01 --- eu.esrf.test/src/test_variables.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eu.esrf.test/src/test_variables.py b/eu.esrf.test/src/test_variables.py index 5b81467..7f2d874 100755 --- a/eu.esrf.test/src/test_variables.py +++ b/eu.esrf.test/src/test_variables.py @@ -1,10 +1,10 @@ #!/usr/bin/python2.6 import os,shutil - +queue = {'suite_usecases_general':{'tst_case':'tst_hdf5_large_tree'}} #only one queue allowed for one suite_test_case #queue = {'suite_workflows_general': {'tst_case2':'tst_open_examples'}} #queue.update({'suite_usecases_general':{'tst_case':'tst_hdf5_large_tree'}}) -queue({'suite_workflows_bignexus':{'tst_case':'tst_slicedata_dbrowsing'}}) +#queue.update({'suite_workflows_bignexus':{'tst_case':'tst_slicedata_dbrowsing'}}) #queue['suite_workflows_bignexus'] = {'tst_case':'tst_slicedata_dexplore'} def check_variable(testSuiteName): From cad020359b1e4063a31da68a691af57ee1656fe5 Mon Sep 17 00:00:00 2001 From: Olof Svensson Date: Wed, 25 Sep 2013 16:30:49 +0200 Subject: [PATCH 07/17] change to a generic workspace path --- eu.esrf.test/src/script_jenkins | 2 +- eu.esrf.test/src/test_variables.py | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/eu.esrf.test/src/script_jenkins b/eu.esrf.test/src/script_jenkins index 7e44f99..c518b82 100755 --- a/eu.esrf.test/src/script_jenkins +++ b/eu.esrf.test/src/script_jenkins @@ -4,7 +4,7 @@ export DISPLAY=:2 cd /scisoft/jenkins/ub1204_opid14/squish-4.2.3-java-linux64/bin/ ./squishserver & >/$WORKSPACE/serverlog sleep 1 -/scisoft/jenkins/ub1204_opid14/squish-4.2.3-java-linux64/bin/squishrunner --testsuite /scisoft/jenkins/ub1204_opid14/workspace/Dawn_squish_tests_production/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/$1_squishlog +/scisoft/jenkins/ub1204_opid14/squish-4.2.3-java-linux64/bin/squishrunner --testsuite $3/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/$1_squishlog var1=$(ps -aef |grep squishserver | grep -v grep | awk '{ print $2; }' | head -1) kill -9 $var1 var2=$(ps -aef |grep Xvfb | grep -v grep | awk '{ print $2; }' | head -1) diff --git a/eu.esrf.test/src/test_variables.py b/eu.esrf.test/src/test_variables.py index 7f2d874..13ff090 100755 --- a/eu.esrf.test/src/test_variables.py +++ b/eu.esrf.test/src/test_variables.py @@ -11,7 +11,8 @@ def check_variable(testSuiteName): path_global_script=os.path.join(os.environ['WORKSPACE'],'org.dawnsci.squishtests',testSuiteName,'shared/scripts') if os.path.exists(path_global_script)== True: shutil.rmtree(path_global_script) - shutil.copytree('/scisoft/jenkins/ub1204_opid14/workspace/Dawn_squish_tests/eu.esrf.test/global_script_esrf',path_global_script) + #shutil.copytree('/scisoft/jenkins/ub1204_opid14/workspace/Dawn_squish_tests/eu.esrf.test/global_script_esrf',path_global_script) + shutil.copytree(os.path.join(os.environ['WORKSPACE'] +'/eu.esrf.test/global_script_esrf') ,path_global_script) def setup_log(): path_log=os.path.join(os.environ['WORKSPACE'] +'/log/') @@ -24,7 +25,4 @@ def setup_log(): check_variable(testSuiteName) for tst in queue[testSuiteName]: os.chdir(os.path.join(os.environ['WORKSPACE'],'eu.esrf.test/src')) - print '***************************' - print (os.path.join(os.environ['WORKSPACE'],'eu.esrf.test/src')) - print ("./script_jenkins "+testSuiteName+" "+queue[testSuiteName][tst]) - os.popen("./script_jenkins "+testSuiteName+" "+queue[testSuiteName][tst], "r").read() + os.popen("./script_jenkins "+testSuiteName+" "+queue[testSuiteName][tst]+" "+os.environ['WORKSPACE'], "r").read() From 42bda31b249cdd2234ac6c49f77c20bb8f5b4f2a Mon Sep 17 00:00:00 2001 From: Operator account ID23 Date: Wed, 23 Oct 2013 15:30:20 +0200 Subject: [PATCH 08/17] install squish form a clean workspace --- .../global_script_esrf/dawn_global_startup.py | 7 +- .../dawn_global_startup.py~ | 160 +++++++++++++++++ eu.esrf.test/src/script_jenkins | 42 ++++- eu.esrf.test/src/script_jenkins~ | 13 ++ eu.esrf.test/src/test_variables.py | 5 +- eu.esrf.test/src/test_variables.py~ | 27 +++ org.dawb.test/.classpath | 7 - org.dawb.test/.gitignore | 8 - org.dawb.test/.project | 28 --- .../org.eclipse.core.resources.prefs | 2 - .../.settings/org.eclipse.core.runtime.prefs | 2 - .../.settings/org.eclipse.jdt.core.prefs | 8 - org.dawb.test/META-INF/MANIFEST.MF | 40 ----- org.dawb.test/build.properties | 4 - org.dawb.test/dawb.headless.test.launch | 42 ----- .../dawnsci.user.interface.test.launch | 40 ----- .../src/org/dawb/test/Activator.java | 59 ------- .../src/org/dawb/test/HeadlessTest.java | 32 ---- .../src/org/dawb/test/TestUtils.java | 45 ----- .../src/org/dawb/test/UserInterfaceTest.java | 30 ---- .../shared/scripts/dawn_constants.py | 20 +++ .../shared/scripts/dawn_global_plot_tests.py | 34 ++++ .../scripts/dawn_global_python_setup.py | 157 +++++++++++++++++ .../shared/scripts/dawn_global_startup.py | 160 +++++++++++++++++ .../shared/scripts/dawn_global_startup.py~ | 160 +++++++++++++++++ .../shared/scripts/dawn_slider_utils.py | 28 +++ .../shared/scripts/use_case_utils.py | 165 ++++++++++++++++++ .../failedImages/failed_1.png | Bin 0 -> 30027 bytes .../failedImages/failed_2.png | Bin 0 -> 29126 bytes .../failedImages/failed_3.png | Bin 0 -> 24670 bytes .../shared/scripts/dawn_constants.py | 20 +++ .../shared/scripts/dawn_global_plot_tests.py | 34 ++++ .../scripts/dawn_global_python_setup.py | 157 +++++++++++++++++ .../shared/scripts/dawn_global_startup.py | 160 +++++++++++++++++ .../shared/scripts/dawn_slider_utils.py | 28 +++ .../shared/scripts/use_case_utils.py | 165 ++++++++++++++++++ .../failedImages/failed_1.png | Bin 0 -> 14745 bytes .../failedImages/failed_2.png | Bin 0 -> 14783 bytes .../failedImages/failed_3.png | Bin 0 -> 14814 bytes .../shared/scripts/dawn_constants.py | 20 +++ .../shared/scripts/dawn_global_plot_tests.py | 34 ++++ .../scripts/dawn_global_python_setup.py | 157 +++++++++++++++++ .../shared/scripts/dawn_global_startup.py | 160 +++++++++++++++++ .../shared/scripts/dawn_global_startup.py~ | 160 +++++++++++++++++ .../shared/scripts/dawn_slider_utils.py | 28 +++ .../shared/scripts/use_case_utils.py | 165 ++++++++++++++++++ squishinstall.sh | 64 +++++++ squishinstall.sh~ | 64 +++++++ 48 files changed, 2383 insertions(+), 358 deletions(-) create mode 100644 eu.esrf.test/global_script_esrf/dawn_global_startup.py~ create mode 100755 eu.esrf.test/src/script_jenkins~ create mode 100755 eu.esrf.test/src/test_variables.py~ delete mode 100644 org.dawb.test/.classpath delete mode 100644 org.dawb.test/.gitignore delete mode 100644 org.dawb.test/.project delete mode 100644 org.dawb.test/.settings/org.eclipse.core.resources.prefs delete mode 100644 org.dawb.test/.settings/org.eclipse.core.runtime.prefs delete mode 100644 org.dawb.test/.settings/org.eclipse.jdt.core.prefs delete mode 100644 org.dawb.test/META-INF/MANIFEST.MF delete mode 100644 org.dawb.test/build.properties delete mode 100644 org.dawb.test/dawb.headless.test.launch delete mode 100644 org.dawb.test/dawnsci.user.interface.test.launch delete mode 100644 org.dawb.test/src/org/dawb/test/Activator.java delete mode 100644 org.dawb.test/src/org/dawb/test/HeadlessTest.java delete mode 100644 org.dawb.test/src/org/dawb/test/TestUtils.java delete mode 100644 org.dawb.test/src/org/dawb/test/UserInterfaceTest.java create mode 100644 org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_constants.py create mode 100644 org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_plot_tests.py create mode 100644 org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_python_setup.py create mode 100644 org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_startup.py create mode 100644 org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_startup.py~ create mode 100644 org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_slider_utils.py create mode 100644 org.dawnsci.squishtests/suite_usecases_general/shared/scripts/use_case_utils.py create mode 100644 org.dawnsci.squishtests/suite_usecases_general/tst_hdf5_large_tree/failedImages/failed_1.png create mode 100644 org.dawnsci.squishtests/suite_usecases_general/tst_hdf5_large_tree/failedImages/failed_2.png create mode 100644 org.dawnsci.squishtests/suite_usecases_general/tst_hdf5_large_tree/failedImages/failed_3.png create mode 100644 org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/dawn_constants.py create mode 100644 org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/dawn_global_plot_tests.py create mode 100644 org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/dawn_global_python_setup.py create mode 100644 org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/dawn_global_startup.py create mode 100644 org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/dawn_slider_utils.py create mode 100644 org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/use_case_utils.py create mode 100644 org.dawnsci.squishtests/suite_workflows_bignexus/tst_slicedata_dbrowsing/failedImages/failed_1.png create mode 100644 org.dawnsci.squishtests/suite_workflows_bignexus/tst_slicedata_dbrowsing/failedImages/failed_2.png create mode 100644 org.dawnsci.squishtests/suite_workflows_bignexus/tst_slicedata_dbrowsing/failedImages/failed_3.png create mode 100644 org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_constants.py create mode 100644 org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_plot_tests.py create mode 100644 org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_python_setup.py create mode 100644 org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py create mode 100644 org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py~ create mode 100644 org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_slider_utils.py create mode 100644 org.dawnsci.squishtests/suite_workflows_general/shared/scripts/use_case_utils.py create mode 100755 squishinstall.sh create mode 100755 squishinstall.sh~ diff --git a/eu.esrf.test/global_script_esrf/dawn_global_startup.py b/eu.esrf.test/global_script_esrf/dawn_global_startup.py index f58b56c..a546bcd 100644 --- a/eu.esrf.test/global_script_esrf/dawn_global_startup.py +++ b/eu.esrf.test/global_script_esrf/dawn_global_startup.py @@ -1,12 +1,13 @@ -DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1204_opid14/workspace" +import os, shutil +from datetime import datetime +DAWN_WORKSPACE_ROOT=os.path.join(os.environ['WORKSPACE'],"dawn_workspace") DAWN_SUITE_WORKSPACE="suite_test_single_workspace" USE_ATTACH=False testSettings.logScreenshotOnFail = True testSettings.logScreenshotOnError = True -import os, shutil -from datetime import datetime + def startDAWNSuiteWorkspace(): diff --git a/eu.esrf.test/global_script_esrf/dawn_global_startup.py~ b/eu.esrf.test/global_script_esrf/dawn_global_startup.py~ new file mode 100644 index 0000000..30c7ddf --- /dev/null +++ b/eu.esrf.test/global_script_esrf/dawn_global_startup.py~ @@ -0,0 +1,160 @@ +DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1204_opid23/dawn_workspace" +DAWN_SUITE_WORKSPACE="suite_test_single_workspace" +USE_ATTACH=False + +testSettings.logScreenshotOnFail = True +testSettings.logScreenshotOnError = True + +import os, shutil +from datetime import datetime + +def startDAWNSuiteWorkspace(): + + # We start each test in a new workspace + cwd = os.getcwd() + parent_path, test_name = os.path.split(cwd) + suite_name = os.path.basename(parent_path) + workspace = "%s/%s/%s" % (DAWN_WORKSPACE_ROOT, suite_name, DAWN_SUITE_WORKSPACE) + + start = datetime.now() + startApplication("dawn -consoleLog -data %s" % workspace, "", -1, 90) + end = datetime.now() + + test.log("Application took " + str(end-start) + " to start") + + window = waitForObject(":Workbench Window") + window.setMaximized(True) + # Let any setup items continue (e.g. Jython interpreter setup) + # XXX This is a hack because we don't have a better way to determine if + # the GUI is fully started + snooze(1.0) + test.passes("startOrAttachToDAWNOnly: Success") + + try: + #find should fail fast if no welcome screen + findObject(":Welcome_CTabItem") + dismissWelcomScreen() + except: + pass + + +def startOrAttachToDAWNOnly(clean_workspace=True): + if USE_ATTACH: + attachToApplication("attachable_dawn") + else: + # We start each test in a new workspace + cwd = os.getcwd() + parent_path, test_name = os.path.split(cwd) + suite_name = os.path.basename(parent_path) + workparent = os.path.join(DAWN_WORKSPACE_ROOT, suite_name, test_name) + workspace = os.path.join(workparent, 'workspace') + osgi_user_area = os.path.join(workparent, 'osgi_user_area') + osgi_configuration_area = os.path.join(workparent, 'osgi_configuration_area') + if clean_workspace: + try: + shutil.rmtree(workparent) + except OSError: + # Ignore error here, check below + # that directory is gone + pass + snooze(1) + test.verify(not os.path.exists(workparent), "startOrAttachToDAWNOnly: Workspace is clean") + + start = datetime.now() + startApplication("dawn -consoleLog -data %s -user %s -configuration %s -name %s-%s" % + (workspace, osgi_user_area, osgi_configuration_area, suite_name, test_name), "", -1, 90) + end = datetime.now() + test.log("Application took " + str(end-start) + " to start") + + window = waitForObject(":Workbench Window") + window.setMaximized(True) + # Let any setup items continue (e.g. Jython interpreter setup) + # XXX This is a hack because we don't have a better way to determine if + # the GUI is fully started + snooze(1.0) + test.passes("startOrAttachToDAWNOnly: Success") + +def dismissWelcomScreen(): + clickTab(waitForObject(":Welcome_CTabItem"), 10, 10, 0, Button.Button3) + activateItem(waitForObjectItem(":Pop Up Menu", "Close")) + test.passes("dismissWelcomScreen: Success") + +def startOrAttachToDAWN(): + startOrAttachToDAWNOnly() + dismissWelcomScreen() + test.passes("startOrAttachToDAWN: Success") + +def closeDAWN(): + closeWindow(":Workbench Window") + clickButton(waitForObject(":Confirm Exit.OK_Button")) + test.passes("closeDAWN: Success") + +def closeOrDetachFromDAWN(): + if USE_ATTACH: + # nothing to do + pass + else: + closeDAWN() + test.passes("closeOrDetachFromDAWN: Success") + +def openPerspective(perspectiveName): + waitForObject(":Workbench Window") + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Open Perspective")) + activateItem(waitForObjectItem(":Open Perspective_Menu", "Other...")) + mouseClick(waitForObject("{caption='%s' column='0' container=':Open Perspective_Table' type='com.froglogic.squish.swt.TableCell'}" % perspectiveName), 5, 5, 0, Button.Button1) + mouseClick(waitForObject(":Open Perspective.OK_Button")) + # Opening a perspective can (more than most) kick off things in the background + # This background processing can make the workbench window appear fully ready + # but the perspective isn't. Therefore we snooze a few seconds to let everything + # catchup + waitForObject(":Workbench Window") + snooze(3.0) + waitForObject(":Workbench Window") + test.passes("openPerspective: %s" % perspectiveName) + +def openView(viewName, matchOpen=False): + ''' Open the view named viewName. If matchOpen is true, will assume that an open view with + viewName in the title bar of the view is the expected one and only activate it ''' + waitForObject(":Workbench Window") + if matchOpen: + viewRealObjectName = "{caption='%s' type='org.eclipse.swt.custom.CTabItem' window=':Workbench Window'}" % viewName; + if object.exists(viewRealObjectName): + mouseClick(waitForObject(viewRealObjectName)) + test.passes("openView (matchOpen): %s" % viewName) + return + + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Show View")) + activateItem(waitForObjectItem(":Show View_Menu", "Other...")) + type(waitForObject(":Show View_Text"), viewName) + mouseClick(waitForObjectItem(":Show View_Tree", viewName)) + mouseClick(waitForObject(":Show View.OK_Button")) + waitForObject(":Workbench Window") + test.passes("openView: %s" % viewName) + + + +def getErrorItems(): + ''' Return the Java Array that contains the list of entries in the Error Log ''' + openView("Error Log", True) + errorTree = waitForObject(":Error Log_Tree") + return errorTree.getItems() + +def openAndClearErrorLog(): + ''' Open and clear the Eclipse Error Log. Use getErrorItems() first to find out if there is + anything in them ''' + if getErrorItems().length > 0: + snooze(2) + mouseClick(waitForObject(":Delete Log_ToolItem")) + clickButton(waitForObject(":Confirm Delete.OK_Button")) + +def verifyAndClearErrorLog(): + ''' Verifies that the error log is empty and clears it if not ''' + if getErrorItems().length > 0: + test.fail("Items are in error log view (if this test fails, see console output as -consoleLog is on)") + mouseClick(waitForObject(":Delete Log_ToolItem")) + clickButton(waitForObject(":Confirm Delete.OK_Button")) + else: + # provide a less verbose message when the test just passed + test.passes("No items are in error log view") diff --git a/eu.esrf.test/src/script_jenkins b/eu.esrf.test/src/script_jenkins index c518b82..fbc0c32 100755 --- a/eu.esrf.test/src/script_jenkins +++ b/eu.esrf.test/src/script_jenkins @@ -1,12 +1,44 @@ -#!/bin/sh -Xvfb :2 & -export DISPLAY=:2 -cd /scisoft/jenkins/ub1204_opid14/squish-4.2.3-java-linux64/bin/ +#!/usr/bin/env bash +xvfbFound=false +i=0 +x=0 +for inode in $(ls /tmp/.X*-lock) +do + owner=$(ls -al $inode | grep -v grep | awk '{ print $3; }') + echo $inode "belong to" $owner + array[$i]=$(echo "$inode" | tr -d [:alpha:] | tr -d [:punct:]) + if [ "$USER" = "$owner" ];then + xvfbFound=true + var=$(echo "$inode" | tr -d [:alpha:] | tr -d [:punct:]) + break; + fi + let i++ +done +if $xvfbFound ; then + echo "availaible display @ "$var " for " $USER +else + var1=${#array[@]} + for (( c=0; c/$WORKSPACE/serverlog sleep 1 -/scisoft/jenkins/ub1204_opid14/squish-4.2.3-java-linux64/bin/squishrunner --testsuite $3/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/$1_squishlog +/$WORKSPACE/squish/bin/squishrunner --testsuite $WORKSPACE/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/$1_squishlog var1=$(ps -aef |grep squishserver | grep -v grep | awk '{ print $2; }' | head -1) kill -9 $var1 var2=$(ps -aef |grep Xvfb | grep -v grep | awk '{ print $2; }' | head -1) kill -9 $var2 + diff --git a/eu.esrf.test/src/script_jenkins~ b/eu.esrf.test/src/script_jenkins~ new file mode 100755 index 0000000..f56a58f --- /dev/null +++ b/eu.esrf.test/src/script_jenkins~ @@ -0,0 +1,13 @@ +#!/bin/sh +Xvfb :8 -screen 0 1024x768x16 & +export DISPLAY=:8 +export PATH=/sware/isdd/soft/java/v7u17/linux_x64/jdk1.7.0_40/bin:$PATH +cd /$WORKSPACE/squish/bin/ +./squishserver & >/$WORKSPACE/serverlog +sleep 1 +/$WORKSPACE/squish/bin/squishrunner --testsuite $WORKSPACE/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/$1_squishlog +var1=$(ps -aef |grep squishserver | grep -v grep | awk '{ print $2; }' | head -1) +kill -9 $var1 +var2=$(ps -aef |grep Xvfb | grep -v grep | awk '{ print $2; }' | head -1) +kill -9 $var2 + diff --git a/eu.esrf.test/src/test_variables.py b/eu.esrf.test/src/test_variables.py index 13ff090..48789e9 100755 --- a/eu.esrf.test/src/test_variables.py +++ b/eu.esrf.test/src/test_variables.py @@ -1,6 +1,6 @@ #!/usr/bin/python2.6 import os,shutil -queue = {'suite_usecases_general':{'tst_case':'tst_hdf5_large_tree'}} +queue = {'suite_workflows_general': {'tst_case':'tst_open_examples'}} #only one queue allowed for one suite_test_case #queue = {'suite_workflows_general': {'tst_case2':'tst_open_examples'}} #queue.update({'suite_usecases_general':{'tst_case':'tst_hdf5_large_tree'}}) @@ -11,7 +11,6 @@ def check_variable(testSuiteName): path_global_script=os.path.join(os.environ['WORKSPACE'],'org.dawnsci.squishtests',testSuiteName,'shared/scripts') if os.path.exists(path_global_script)== True: shutil.rmtree(path_global_script) - #shutil.copytree('/scisoft/jenkins/ub1204_opid14/workspace/Dawn_squish_tests/eu.esrf.test/global_script_esrf',path_global_script) shutil.copytree(os.path.join(os.environ['WORKSPACE'] +'/eu.esrf.test/global_script_esrf') ,path_global_script) def setup_log(): @@ -25,4 +24,4 @@ def setup_log(): check_variable(testSuiteName) for tst in queue[testSuiteName]: os.chdir(os.path.join(os.environ['WORKSPACE'],'eu.esrf.test/src')) - os.popen("./script_jenkins "+testSuiteName+" "+queue[testSuiteName][tst]+" "+os.environ['WORKSPACE'], "r").read() + os.popen("./script_jenkins "+testSuiteName+" "+queue[testSuiteName][tst], "r").read() diff --git a/eu.esrf.test/src/test_variables.py~ b/eu.esrf.test/src/test_variables.py~ new file mode 100755 index 0000000..3167e08 --- /dev/null +++ b/eu.esrf.test/src/test_variables.py~ @@ -0,0 +1,27 @@ +#!/usr/bin/python2.6 +import os,shutil +queue = {'suite_usecases_general':{'tst_case':'tst_hdf5_large_tree'}} +#only one queue allowed for one suite_test_case +#queue = {'suite_workflows_general': {'tst_case2':'tst_open_examples'}} +#queue.update({'suite_usecases_general':{'tst_case':'tst_hdf5_large_tree'}}) +#queue.update({'suite_workflows_bignexus':{'tst_case':'tst_slicedata_dbrowsing'}}) +#queue['suite_workflows_bignexus'] = {'tst_case':'tst_slicedata_dexplore'} + +def check_variable(testSuiteName): + path_global_script=os.path.join(os.environ['WORKSPACE'],'org.dawnsci.squishtests',testSuiteName,'shared/scripts') + if os.path.exists(path_global_script)== True: + shutil.rmtree(path_global_script) + shutil.copytree(os.path.join(os.environ['WORKSPACE'] +'/eu.esrf.test/global_script_esrf') ,path_global_script) + +def setup_log(): + path_log=os.path.join(os.environ['WORKSPACE'] +'/log/') + if os.path.exists(path_log)== True: + shutil.rmtree(path_log) + os.mkdir(path_log) + +setup_log() +for testSuiteName in queue.keys(): + check_variable(testSuiteName) + for tst in queue[testSuiteName]: + os.chdir(os.path.join(os.environ['WORKSPACE'],'eu.esrf.test/src')) + os.popen("./script_jenkins "+testSuiteName+" "+queue[testSuiteName][tst], "r").read() diff --git a/org.dawb.test/.classpath b/org.dawb.test/.classpath deleted file mode 100644 index ad32c83..0000000 --- a/org.dawb.test/.classpath +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/org.dawb.test/.gitignore b/org.dawb.test/.gitignore deleted file mode 100644 index e68265f..0000000 --- a/org.dawb.test/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Ignores that are common to all Eclipse GDA plugin projects -/@dot -/@dot.log -/bin -/build.xml -/javaCompiler...args - -# Ignores that are specific to this Eclipse project diff --git a/org.dawb.test/.project b/org.dawb.test/.project deleted file mode 100644 index 1d92ef0..0000000 --- a/org.dawb.test/.project +++ /dev/null @@ -1,28 +0,0 @@ - - - org.dawb.test - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - - org.eclipse.pde.PluginNature - org.eclipse.jdt.core.javanature - - diff --git a/org.dawb.test/.settings/org.eclipse.core.resources.prefs b/org.dawb.test/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 4824b80..0000000 --- a/org.dawb.test/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,2 +0,0 @@ -eclipse.preferences.version=1 -encoding/=UTF-8 diff --git a/org.dawb.test/.settings/org.eclipse.core.runtime.prefs b/org.dawb.test/.settings/org.eclipse.core.runtime.prefs deleted file mode 100644 index c522e1f..0000000 --- a/org.dawb.test/.settings/org.eclipse.core.runtime.prefs +++ /dev/null @@ -1,2 +0,0 @@ -eclipse.preferences.version=1 -line.separator=\n diff --git a/org.dawb.test/.settings/org.eclipse.jdt.core.prefs b/org.dawb.test/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index d127976..0000000 --- a/org.dawb.test/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,8 +0,0 @@ -#Tue Jan 18 13:59:31 CET 2011 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.dawb.test/META-INF/MANIFEST.MF b/org.dawb.test/META-INF/MANIFEST.MF deleted file mode 100644 index 5a876d7..0000000 --- a/org.dawb.test/META-INF/MANIFEST.MF +++ /dev/null @@ -1,40 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: Test -Bundle-SymbolicName: org.dawb.test -Bundle-Version: 1.1.0.qualifier -Bundle-Activator: org.dawb.test.Activator -Bundle-Vendor: ESRF -Require-Bundle: org.eclipse.ui, - org.eclipse.core.runtime, - org.dawb.common.python;bundle-version="0.8.2", - org.dawb.common.ui;bundle-version="0.8.2", - org.dawb.common.util;bundle-version="0.8.2", - org.dawb.fable.extensions;bundle-version="0.8.2", - org.dawb.fable.framework.navigator;bundle-version="0.8.2", - org.dawb.fable.framework.toolbox;bundle-version="0.8.2", - org.dawb.fable.framework.ui;bundle-version="0.8.2", - org.dawb.fable.framework.ui.texteditor, - org.dawb.fable.imageviewer;bundle-version="0.8.2", - org.dawb.fable.python;bundle-version="0.8.2", - org.dawb.gda.extensions;bundle-version="0.8.2", - org.dawb.hdf5;bundle-version="0.8.2", - org.dawb.hdf5.editor;bundle-version="0.8.2", - org.dawb.jep, - org.dawb.jlchart;bundle-version="0.8.2", - org.dawb.jmol;bundle-version="0.8.2", - org.dawb.passerelle.actors;bundle-version="0.8.2", - org.dawb.passerelle.common;bundle-version="0.8.2", - org.dawb.pydev.extensions;bundle-version="0.8.2", - org.dawb.workbench.ui;bundle-version="0.8.2", - org.dawb.workbench.ui.test;bundle-version="0.8.2", - org.dawb.workbench.examples;bundle-version="0.8.2", - org.dawb.workbench.jmx;bundle-version="0.8.2", - org.junit, - org.dawb.passerelle.actors.test;bundle-version="0.8.2", - org.dawb.fable.imageviewer.test;bundle-version="0.8.2" -Bundle-RequiredExecutionEnvironment: JavaSE-1.6 -Bundle-ActivationPolicy: lazy -Import-Package: org.eclipse.core.resources, - org.junit, - org.junit.runner diff --git a/org.dawb.test/build.properties b/org.dawb.test/build.properties deleted file mode 100644 index 34d2e4d..0000000 --- a/org.dawb.test/build.properties +++ /dev/null @@ -1,4 +0,0 @@ -source.. = src/ -output.. = bin/ -bin.includes = META-INF/,\ - . diff --git a/org.dawb.test/dawb.headless.test.launch b/org.dawb.test/dawb.headless.test.launch deleted file mode 100644 index a24c9cc..0000000 --- a/org.dawb.test/dawb.headless.test.launch +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/org.dawb.test/dawnsci.user.interface.test.launch b/org.dawb.test/dawnsci.user.interface.test.launch deleted file mode 100644 index 591b488..0000000 --- a/org.dawb.test/dawnsci.user.interface.test.launch +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/org.dawb.test/src/org/dawb/test/Activator.java b/org.dawb.test/src/org/dawb/test/Activator.java deleted file mode 100644 index 92d3cad..0000000 --- a/org.dawb.test/src/org/dawb/test/Activator.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2012 European Synchrotron Radiation Facility, - * Diamond Light Source Ltd. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.dawb.test; - -import org.eclipse.ui.plugin.AbstractUIPlugin; -import org.osgi.framework.BundleContext; - -/** - * The activator class controls the plug-in life cycle - */ -public class Activator extends AbstractUIPlugin { - - // The plug-in ID - public static final String PLUGIN_ID = "org.dawb.workbench.application.test"; //$NON-NLS-1$ - - // The shared instance - private static Activator plugin; - - /** - * The constructor - */ - public Activator() { - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) - */ - public void start(BundleContext context) throws Exception { - super.start(context); - plugin = this; - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) - */ - public void stop(BundleContext context) throws Exception { - plugin = null; - super.stop(context); - } - - /** - * Returns the shared instance - * - * @return the shared instance - */ - public static Activator getDefault() { - return plugin; - } - -} diff --git a/org.dawb.test/src/org/dawb/test/HeadlessTest.java b/org.dawb.test/src/org/dawb/test/HeadlessTest.java deleted file mode 100644 index 839d2bf..0000000 --- a/org.dawb.test/src/org/dawb/test/HeadlessTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2012 European Synchrotron Radiation Facility, - * Diamond Light Source Ltd. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.dawb.test; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite.SuiteClasses; - -/** - * Just a collection of suites - * @author gerring - * - */ -@RunWith(org.junit.runners.Suite.class) -@SuiteClasses({ - - - org.dawb.hdf5.Suite.class, - org.dawb.passerelle.actors.test.Suite.class, - - // Run last as has memory leak - org.dawb.common.python.test.Suite.class - -}) -public class HeadlessTest { -} diff --git a/org.dawb.test/src/org/dawb/test/TestUtils.java b/org.dawb.test/src/org/dawb/test/TestUtils.java deleted file mode 100644 index 593e006..0000000 --- a/org.dawb.test/src/org/dawb/test/TestUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2012 European Synchrotron Radiation Facility, - * Diamond Light Source Ltd. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.dawb.test; - -import org.osgi.framework.Bundle; - -public class TestUtils { - - /** - * - * @param relPath = to pluging - * @return - */ - public static String getAbsolutePath(final Bundle bundle, final String relPath) { - String dir = cleanPath(bundle.getLocation()); - return dir+relPath; - } - - - public static String cleanPath(String loc) { - - // Remove reference:file: from the start. TODO find a better way, - // and test that this works on windows (it might have ///) - if (loc.startsWith("reference:file:")){ - loc = loc.substring(15); - } else if (loc.startsWith("file:")) { - loc = loc.substring(5); - } else { - return loc; - } - - loc = loc.replace("//", "/"); - loc = loc.replace("\\\\", "\\"); - - return loc; - } - -} diff --git a/org.dawb.test/src/org/dawb/test/UserInterfaceTest.java b/org.dawb.test/src/org/dawb/test/UserInterfaceTest.java deleted file mode 100644 index 36b11af..0000000 --- a/org.dawb.test/src/org/dawb/test/UserInterfaceTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2012 European Synchrotron Radiation Facility, - * Diamond Light Source Ltd. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.dawb.test; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite.SuiteClasses; - -/** - * Just a collection of suites - * @author gerring - * - */ -@RunWith(org.junit.runners.Suite.class) -@SuiteClasses({ - - org.dawb.workbench.ui.editors.test.Suite.class, - fable.imageviewer.tests.gui.Suite.class, - org.dawb.passerelle.actors.test.ui.Suite.class - -}) -public class UserInterfaceTest { - // Run this as a junit plugin test and all the links will be satisfied. -} diff --git a/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_constants.py b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_constants.py new file mode 100644 index 0000000..654448e --- /dev/null +++ b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_constants.py @@ -0,0 +1,20 @@ + + +class dawn_constants: + + TOOL_X = 30 + TOOL_Y = 8 + TOOL_MIN_WIDTH = 500 + + METALMIX_0_MIN = "0.0" + METALMIX_0_MAX ="600.0" + + METALMIX_0_DMIN = "-300.0" + METALMIX_0_DMAX = "300.0" + + METALMIX_1_MIN = "0.0" + METALMIX_1_MAX ="800.0" + + METALMIX_1_DMIN = "-400.0" + METALMIX_1_DMAX = "400.0" + \ No newline at end of file diff --git a/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_plot_tests.py b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_plot_tests.py new file mode 100644 index 0000000..0174c68 --- /dev/null +++ b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_plot_tests.py @@ -0,0 +1,34 @@ +def check_plotted_trace_name_yval(configObj,name,ymax,ymin): + #configObj from conOb = waitForObject(":Configure Settings..._ToolItem") configure + #settings tool item + snooze(1) + mouseClick(configObj, 11, 14, 0, Button.Button1) + clickTab(waitForObject(":Configure Graph Settings.Axes_TabItem")) + + mouseClick(waitForObjectItem(":Select Axis_Combo", "(Y-Axis)"), 0, 0, 0, Button.NoButton) + snooze(1)#added snooze since these boxes may be disabled so need to use find rather than wait for + widget = findObject(":Change Settings.Maximum_Text") + test.verify(widget.text == ymax,"Check Y Axis Maximum Expected: " + ymax + " Actual: "+ widget.text) + widget= findObject("{leftWidget=':Change Settings.Minimum: _Label' type='org.eclipse.swt.widgets.Text'}") + test.verify(widget.text == ymin,"Check Y Axis Minimum Expected: " + ymin + " Actual: "+ widget.text) + + clickTab(waitForObject(":Configure Graph Settings.Traces_TabItem")) + widget = waitForObject(":Select Trace_Combo") + test.verify(widget.text == name, "Check Trace Name Expected: " + name + " Actual: "+ widget.text) + + clickButton(waitForObject(":Configure Graph Settings.OK_Button")) + +def check_plotted_traces_names(configObj, nameList): + + mouseClick(configObj) + clickTab(waitForObject(":Configure Graph Settings.Traces_TabItem")) + wid = waitForObject(":Select Trace_Combo") + chil = object.children(wid) + + test.verify(len(chil)==len(nameList), "Combo List length Expected: " +str(len(nameList)) +"Actual: "+ str(len(chil))) + + for i in range(len(chil)): + test.verify(chil[i].text == nameList[i], "Trace names Expected: " + nameList[i] + " Actual: "+ chil[i].text) + + clickButton(waitForObject(":Configure Graph Settings.OK_Button")) + \ No newline at end of file diff --git a/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_python_setup.py b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_python_setup.py new file mode 100644 index 0000000..2055bf0 --- /dev/null +++ b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_python_setup.py @@ -0,0 +1,157 @@ +EPD_FREE_LOCATIONS=[ + 'C:\\Python27\\python.exe', + 'C:\\Python26\\python.exe', + 'C:\\scratch\\epd_free\\python.exe', + '/home/tester/epd_free/bin/python', + '/scratch/epd_free/bin/python'] + +# Add in the current home directory as a place to look for EPD +# free. This doesn't really apply to the test vm machines +# but it can make local development of the tests easier +import os +home = os.getenv("HOME") +if home is not None: + EPD_FREE_LOCATIONS.append("%s/epd_free/bin/python" % home) + + + +def openPyDevConsole(type="Python"): + ''' Open a PyDev console waiting for the console to be fully open. + WARNING: This code probably does not cope with opening two consoles + at the same time and may not wait long enough for the second console''' + # Explanation of the warning. The wait depends on certain events in the console. But + # we don't have a great way to detect that those events we are waiting on aren't in + # the previously launched console. What is probably needed is additional code + # to detect the names of the existing consoles so that the new one can be detected + mouseClick(waitForObject(":Open Console_ToolItem")) + activateItem(waitForObjectItem(":Pop Up Menu", "5 PyDev Console")) + clickButton(waitForObject(":%s console_Button" % type)) + clickButton(waitForObject(":OK_Button")) + + # This is a bit difficult to know when we are fully ready, so we wait + # for these two events to happen. + waitForObject(":Clear Console_ToolItem") + waitForPrompt() + + # Finally activate the console so text can be sent to it + # we do that by clicking in it + mouseClick(waitForObject(":PyDev Console"), 252, 66, 0, Button.Button1) + +def typeInConsole(text, object_name=":PyDev Console", prompt=">>> ", timeout=20000): + type(waitForObject(object_name), text) + typeReturnAndWaitForPrompt(object_name=object_name, prompt=prompt, timeout=timeout) + +def typeReturnAndWaitForPrompt(object_name=":PyDev Console", prompt=">>> ", timeout=20000): + type(waitForObject(object_name), "") + waitForPrompt(object_name=object_name, prompt=prompt, timeout=timeout) + +def waitForPrompt(object_name=":PyDev Console", prompt=">>> ", timeout=20000): + '''Wait for the prompt on the interactive console''' + console_object=waitForObject(object_name) + if not waitFor('console_object.text.endswith("%s")' % (prompt), timeout): + raise LookupError + +def _finishPythonSetup(): + clickButton(waitForObject(":Selection needed.OK_Button")) + + # All done, close preferences + clickButton(waitForObject(":Preferences.OK_Button")) + # It can take a while to configure interpreter, so wait until + # the workbench window is ready again + # On windows vm this can take forever! So wait 300 seconds + waitForObject(":Workbench Window", 300000) + +def setupEPDPython(): + waitForObject(":Workbench Window") + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Preferences")) + expand(waitForObjectItem(":Preferences_Tree", "PyDev")) + mouseClick(waitForObjectItem(":Preferences_Tree", "Interpreter - Python")) + mouseClick(waitForObject(":Preferences.New..._Button")) + type(waitForObject(":Select interpreter.Interpreter Name: _Text"), "EPD Free Python") + found = False + for loc in EPD_FREE_LOCATIONS: + if os.path.exists(loc): + type(waitForObject(":Select interpreter.Interpreter Executable: _Text"), "") + type(waitForObject(":Select interpreter.Interpreter Executable: _Text"), loc) + if len(waitForObject(":Select interpreter Error Message_Text").text) == 0: + # found a good one + test.verify(True, "setupEPDPython: Using %s as EPD Free Python" % loc) + found = True + break + if found: + clickButton(waitForObject(":Select interpreter.OK_Button")) + _finishPythonSetup() + else: + test.passes("setupEPDPython: No installed EPD found, deferring to setupPython") + # We failed to find installed EPD, so try and install it now + clickButton(waitForObject(":Select interpreter.Cancel_Button")) + clickButton(waitForObject(":Preferences.Cancel_Button")) + setupPython(installEPD=True) + test.passes("setupEPDPython: Success") + + +def setupPython(allowInstallEPD=False, installEPD=False, installEPDPath=None): + waitForObject(":Workbench Window") + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Preferences")) + expand(waitForObjectItem(":Preferences_Tree", "PyDev")) + mouseClick(waitForObjectItem(":Preferences_Tree", "Interpreter - Python")) + clickButton(waitForObject(":Preferences.Auto Config_Button")) + + # Wait for auto config list to come up + autoError = waitForObject(":Unable to auto-configure..OK_Button", 100) + if (autoError!=None): + clickButton(autoError) + clickButton(waitForObject(":Preferences.New..._Button")) + type(waitForObject(":Select interpreter.Interpreter Name: _Text"), "EPD Free Python") + type(waitForObject(":Select interpreter.Interpreter Executable: _Text"), "C:\\Python26\\python.exe") + clickButton(waitForObject(":Select interpreter.OK_Button")) + clickButton(waitForObject(":Selection needed.OK_Button")) + clickButton(waitForObject(":Preferences.OK_Button", 120000)) + return + + # Wait for auto config list to come up + multiOptions = waitFor('object.exists(":ListDialog_Shell")', 20000) + multiOptions = multiOptions and object.exists(":Select Interpreter Available_Caption") + multiOptions = multiOptions and object.exists(":Select Interpreter Available_Table") + if multiOptions: + availableList = object.children(waitForObject(":Select Interpreter Available_Table")) + if installEPD: + allowedList = filter(lambda x: "EPD" in x.text and "select to install" in x.text, availableList) + else: + allowedList = filter(lambda x: "select to install" not in x.text, availableList) + + test.verify(len(allowedList) == 1, "setupPython: Filter to one available Python to Auto Config") + + clickItem(waitForObject(":Select Interpreter Available_Table"), "%d/0" % allowedList[0].row, 5, 5) + clickButton(waitForObject(":Select Interpreter Available_OK_Button")) + + # In the case that there is no Python autofound, allow install of EPD + # This only applies if the selection interpreter list dialog isn't shown + elif allowInstallEPD and waitFor('object.exists(":Enthought EPD Free Installer_Label")', 20000): + installEPD = True + + if installEPD: + test.verify(object.exists(":Enthought EPD Free Installer_Label"), "setupPython: Enthought Installer Wizard open (if this fails it is because the Enthought wizard didn't open)") + test.verify(object.exists(":I accept the terms of the license agreement_Button"), "setupPython: License agreement open") + clickButton(waitForObject(":I accept the terms of the license agreement_Button", 1)) + clickButton(waitForObject(":Next >_Button")) + + if installEPDPath is not None: + type(waitForObject(":Install to:_Text"), installEPDPath) + clickButton(waitForObject(":Close wizard automatically on successful installation._Button")) + clickButton(waitForObject(":Finish_Button")) + # Wait up to 5 minutes for the wizard to finish + # There is a case here to add event driven check so that if there + # is an unexpected failure we don't wait so long + waitForObject(":Selection needed.OK_Button", 300000) + + _finishPythonSetup() + test.passes("setupPython: Success") + +def getPythonLocation(): + for loc in EPD_FREE_LOCATIONS: + if os.path.exists(loc): + return loc + return None diff --git a/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_startup.py b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_startup.py new file mode 100644 index 0000000..30c7ddf --- /dev/null +++ b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_startup.py @@ -0,0 +1,160 @@ +DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1204_opid23/dawn_workspace" +DAWN_SUITE_WORKSPACE="suite_test_single_workspace" +USE_ATTACH=False + +testSettings.logScreenshotOnFail = True +testSettings.logScreenshotOnError = True + +import os, shutil +from datetime import datetime + +def startDAWNSuiteWorkspace(): + + # We start each test in a new workspace + cwd = os.getcwd() + parent_path, test_name = os.path.split(cwd) + suite_name = os.path.basename(parent_path) + workspace = "%s/%s/%s" % (DAWN_WORKSPACE_ROOT, suite_name, DAWN_SUITE_WORKSPACE) + + start = datetime.now() + startApplication("dawn -consoleLog -data %s" % workspace, "", -1, 90) + end = datetime.now() + + test.log("Application took " + str(end-start) + " to start") + + window = waitForObject(":Workbench Window") + window.setMaximized(True) + # Let any setup items continue (e.g. Jython interpreter setup) + # XXX This is a hack because we don't have a better way to determine if + # the GUI is fully started + snooze(1.0) + test.passes("startOrAttachToDAWNOnly: Success") + + try: + #find should fail fast if no welcome screen + findObject(":Welcome_CTabItem") + dismissWelcomScreen() + except: + pass + + +def startOrAttachToDAWNOnly(clean_workspace=True): + if USE_ATTACH: + attachToApplication("attachable_dawn") + else: + # We start each test in a new workspace + cwd = os.getcwd() + parent_path, test_name = os.path.split(cwd) + suite_name = os.path.basename(parent_path) + workparent = os.path.join(DAWN_WORKSPACE_ROOT, suite_name, test_name) + workspace = os.path.join(workparent, 'workspace') + osgi_user_area = os.path.join(workparent, 'osgi_user_area') + osgi_configuration_area = os.path.join(workparent, 'osgi_configuration_area') + if clean_workspace: + try: + shutil.rmtree(workparent) + except OSError: + # Ignore error here, check below + # that directory is gone + pass + snooze(1) + test.verify(not os.path.exists(workparent), "startOrAttachToDAWNOnly: Workspace is clean") + + start = datetime.now() + startApplication("dawn -consoleLog -data %s -user %s -configuration %s -name %s-%s" % + (workspace, osgi_user_area, osgi_configuration_area, suite_name, test_name), "", -1, 90) + end = datetime.now() + test.log("Application took " + str(end-start) + " to start") + + window = waitForObject(":Workbench Window") + window.setMaximized(True) + # Let any setup items continue (e.g. Jython interpreter setup) + # XXX This is a hack because we don't have a better way to determine if + # the GUI is fully started + snooze(1.0) + test.passes("startOrAttachToDAWNOnly: Success") + +def dismissWelcomScreen(): + clickTab(waitForObject(":Welcome_CTabItem"), 10, 10, 0, Button.Button3) + activateItem(waitForObjectItem(":Pop Up Menu", "Close")) + test.passes("dismissWelcomScreen: Success") + +def startOrAttachToDAWN(): + startOrAttachToDAWNOnly() + dismissWelcomScreen() + test.passes("startOrAttachToDAWN: Success") + +def closeDAWN(): + closeWindow(":Workbench Window") + clickButton(waitForObject(":Confirm Exit.OK_Button")) + test.passes("closeDAWN: Success") + +def closeOrDetachFromDAWN(): + if USE_ATTACH: + # nothing to do + pass + else: + closeDAWN() + test.passes("closeOrDetachFromDAWN: Success") + +def openPerspective(perspectiveName): + waitForObject(":Workbench Window") + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Open Perspective")) + activateItem(waitForObjectItem(":Open Perspective_Menu", "Other...")) + mouseClick(waitForObject("{caption='%s' column='0' container=':Open Perspective_Table' type='com.froglogic.squish.swt.TableCell'}" % perspectiveName), 5, 5, 0, Button.Button1) + mouseClick(waitForObject(":Open Perspective.OK_Button")) + # Opening a perspective can (more than most) kick off things in the background + # This background processing can make the workbench window appear fully ready + # but the perspective isn't. Therefore we snooze a few seconds to let everything + # catchup + waitForObject(":Workbench Window") + snooze(3.0) + waitForObject(":Workbench Window") + test.passes("openPerspective: %s" % perspectiveName) + +def openView(viewName, matchOpen=False): + ''' Open the view named viewName. If matchOpen is true, will assume that an open view with + viewName in the title bar of the view is the expected one and only activate it ''' + waitForObject(":Workbench Window") + if matchOpen: + viewRealObjectName = "{caption='%s' type='org.eclipse.swt.custom.CTabItem' window=':Workbench Window'}" % viewName; + if object.exists(viewRealObjectName): + mouseClick(waitForObject(viewRealObjectName)) + test.passes("openView (matchOpen): %s" % viewName) + return + + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Show View")) + activateItem(waitForObjectItem(":Show View_Menu", "Other...")) + type(waitForObject(":Show View_Text"), viewName) + mouseClick(waitForObjectItem(":Show View_Tree", viewName)) + mouseClick(waitForObject(":Show View.OK_Button")) + waitForObject(":Workbench Window") + test.passes("openView: %s" % viewName) + + + +def getErrorItems(): + ''' Return the Java Array that contains the list of entries in the Error Log ''' + openView("Error Log", True) + errorTree = waitForObject(":Error Log_Tree") + return errorTree.getItems() + +def openAndClearErrorLog(): + ''' Open and clear the Eclipse Error Log. Use getErrorItems() first to find out if there is + anything in them ''' + if getErrorItems().length > 0: + snooze(2) + mouseClick(waitForObject(":Delete Log_ToolItem")) + clickButton(waitForObject(":Confirm Delete.OK_Button")) + +def verifyAndClearErrorLog(): + ''' Verifies that the error log is empty and clears it if not ''' + if getErrorItems().length > 0: + test.fail("Items are in error log view (if this test fails, see console output as -consoleLog is on)") + mouseClick(waitForObject(":Delete Log_ToolItem")) + clickButton(waitForObject(":Confirm Delete.OK_Button")) + else: + # provide a less verbose message when the test just passed + test.passes("No items are in error log view") diff --git a/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_startup.py~ b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_startup.py~ new file mode 100644 index 0000000..3f0af65 --- /dev/null +++ b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_global_startup.py~ @@ -0,0 +1,160 @@ +DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1204_opid23/" +DAWN_SUITE_WORKSPACE="suite_test_single_workspace" +USE_ATTACH=False + +testSettings.logScreenshotOnFail = True +testSettings.logScreenshotOnError = True + +import os, shutil +from datetime import datetime + +def startDAWNSuiteWorkspace(): + + # We start each test in a new workspace + cwd = os.getcwd() + parent_path, test_name = os.path.split(cwd) + suite_name = os.path.basename(parent_path) + workspace = "%s/%s/%s" % (DAWN_WORKSPACE_ROOT, suite_name, DAWN_SUITE_WORKSPACE) + + start = datetime.now() + startApplication("dawn -consoleLog -data %s" % workspace, "", -1, 90) + end = datetime.now() + + test.log("Application took " + str(end-start) + " to start") + + window = waitForObject(":Workbench Window") + window.setMaximized(True) + # Let any setup items continue (e.g. Jython interpreter setup) + # XXX This is a hack because we don't have a better way to determine if + # the GUI is fully started + snooze(1.0) + test.passes("startOrAttachToDAWNOnly: Success") + + try: + #find should fail fast if no welcome screen + findObject(":Welcome_CTabItem") + dismissWelcomScreen() + except: + pass + + +def startOrAttachToDAWNOnly(clean_workspace=True): + if USE_ATTACH: + attachToApplication("attachable_dawn") + else: + # We start each test in a new workspace + cwd = os.getcwd() + parent_path, test_name = os.path.split(cwd) + suite_name = os.path.basename(parent_path) + workparent = os.path.join(DAWN_WORKSPACE_ROOT, suite_name, test_name) + workspace = os.path.join(workparent, 'workspace') + osgi_user_area = os.path.join(workparent, 'osgi_user_area') + osgi_configuration_area = os.path.join(workparent, 'osgi_configuration_area') + if clean_workspace: + try: + shutil.rmtree(workparent) + except OSError: + # Ignore error here, check below + # that directory is gone + pass + snooze(1) + test.verify(not os.path.exists(workparent), "startOrAttachToDAWNOnly: Workspace is clean") + + start = datetime.now() + startApplication("dawn -consoleLog -data %s -user %s -configuration %s -name %s-%s" % + (workspace, osgi_user_area, osgi_configuration_area, suite_name, test_name), "", -1, 90) + end = datetime.now() + test.log("Application took " + str(end-start) + " to start") + + window = waitForObject(":Workbench Window") + window.setMaximized(True) + # Let any setup items continue (e.g. Jython interpreter setup) + # XXX This is a hack because we don't have a better way to determine if + # the GUI is fully started + snooze(1.0) + test.passes("startOrAttachToDAWNOnly: Success") + +def dismissWelcomScreen(): + clickTab(waitForObject(":Welcome_CTabItem"), 10, 10, 0, Button.Button3) + activateItem(waitForObjectItem(":Pop Up Menu", "Close")) + test.passes("dismissWelcomScreen: Success") + +def startOrAttachToDAWN(): + startOrAttachToDAWNOnly() + dismissWelcomScreen() + test.passes("startOrAttachToDAWN: Success") + +def closeDAWN(): + closeWindow(":Workbench Window") + clickButton(waitForObject(":Confirm Exit.OK_Button")) + test.passes("closeDAWN: Success") + +def closeOrDetachFromDAWN(): + if USE_ATTACH: + # nothing to do + pass + else: + closeDAWN() + test.passes("closeOrDetachFromDAWN: Success") + +def openPerspective(perspectiveName): + waitForObject(":Workbench Window") + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Open Perspective")) + activateItem(waitForObjectItem(":Open Perspective_Menu", "Other...")) + mouseClick(waitForObject("{caption='%s' column='0' container=':Open Perspective_Table' type='com.froglogic.squish.swt.TableCell'}" % perspectiveName), 5, 5, 0, Button.Button1) + mouseClick(waitForObject(":Open Perspective.OK_Button")) + # Opening a perspective can (more than most) kick off things in the background + # This background processing can make the workbench window appear fully ready + # but the perspective isn't. Therefore we snooze a few seconds to let everything + # catchup + waitForObject(":Workbench Window") + snooze(3.0) + waitForObject(":Workbench Window") + test.passes("openPerspective: %s" % perspectiveName) + +def openView(viewName, matchOpen=False): + ''' Open the view named viewName. If matchOpen is true, will assume that an open view with + viewName in the title bar of the view is the expected one and only activate it ''' + waitForObject(":Workbench Window") + if matchOpen: + viewRealObjectName = "{caption='%s' type='org.eclipse.swt.custom.CTabItem' window=':Workbench Window'}" % viewName; + if object.exists(viewRealObjectName): + mouseClick(waitForObject(viewRealObjectName)) + test.passes("openView (matchOpen): %s" % viewName) + return + + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Show View")) + activateItem(waitForObjectItem(":Show View_Menu", "Other...")) + type(waitForObject(":Show View_Text"), viewName) + mouseClick(waitForObjectItem(":Show View_Tree", viewName)) + mouseClick(waitForObject(":Show View.OK_Button")) + waitForObject(":Workbench Window") + test.passes("openView: %s" % viewName) + + + +def getErrorItems(): + ''' Return the Java Array that contains the list of entries in the Error Log ''' + openView("Error Log", True) + errorTree = waitForObject(":Error Log_Tree") + return errorTree.getItems() + +def openAndClearErrorLog(): + ''' Open and clear the Eclipse Error Log. Use getErrorItems() first to find out if there is + anything in them ''' + if getErrorItems().length > 0: + snooze(2) + mouseClick(waitForObject(":Delete Log_ToolItem")) + clickButton(waitForObject(":Confirm Delete.OK_Button")) + +def verifyAndClearErrorLog(): + ''' Verifies that the error log is empty and clears it if not ''' + if getErrorItems().length > 0: + test.fail("Items are in error log view (if this test fails, see console output as -consoleLog is on)") + mouseClick(waitForObject(":Delete Log_ToolItem")) + clickButton(waitForObject(":Confirm Delete.OK_Button")) + else: + # provide a less verbose message when the test just passed + test.passes("No items are in error log view") diff --git a/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_slider_utils.py b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_slider_utils.py new file mode 100644 index 0000000..ccab1b9 --- /dev/null +++ b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/dawn_slider_utils.py @@ -0,0 +1,28 @@ +def check_slider_position(slider, position, tollerence): + range = slider.getMaximum()-slider.getMinimum() + pos = slider.getSelection()-slider.getMinimum() + + proportion = float(pos)/float(range) + print "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", position, proportion, range, pos + test.verify((abs(position - proportion) < tollerence), "Slider not in expected position, expected %f and got %f" %(position, proportion)) + + +def slide_to_propotion(slider, proportion): + # get the bounds of the slider + bounds = slider.bounds + width = bounds.width-30 # minus the width of the slider gizmo + + range = slider.getMaximum()-slider.getMinimum() + start_position = slider.getSelection()-slider.getMinimum() + + scale = float(width)/float(range) + + end_position = width*proportion + end_position = end_position - start_position*scale+15 + + mouseDrag(slider, start_position*scale+15, 5, end_position, 5, Modifier.None, Button.Button1) + + # then check the position to make sure we are in the right place + #check_slider_position(slider,proportion,0.1) + + diff --git a/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/use_case_utils.py b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/use_case_utils.py new file mode 100644 index 0000000..5763a9d --- /dev/null +++ b/org.dawnsci.squishtests/suite_usecases_general/shared/scripts/use_case_utils.py @@ -0,0 +1,165 @@ +source(findFile("scripts", "dawn_constants.py")) + +import os +import shutil + + +def createProject(projectName, projectType="Workflow Project"): + + activateItem(waitForObjectItem(":_Menu", "File")) + activateItem(waitForObjectItem(":File_Menu", "New")) + activateItem(waitForObjectItem(":New_Menu_2", "Project...")) + type(waitForObject(":_Text"), projectType) + mouseClick(waitForObjectItem(":_Tree", projectType), 59, 10, 0, Button.Button1) + clickButton(waitForObject(":Next >_Button")) + mouseClick(waitForObject(":Project name:_Text"), 48, 3, 0, Button.Button1) + type(waitForObject(":Project name:_Text"), projectName) + clickButton(waitForObject(":Finish_Button_2")) + snooze(1) + +# All these arguments = bad but not sure how to do his as not python expert. +def openExample(frag, project="data", folder="examples", subfolder=None, subsubfolder=None): + + expand(waitForObjectItem(":Project Explorer_Tree", project)) + expand(waitForObjectItem(":Project Explorer_Tree", folder)) + children = object.children(waitForObjectItem(":Project Explorer_Tree", folder)) + + if (subfolder is not None): + expand(waitForObjectItem(":Project Explorer_Tree", subfolder)) + children = object.children(waitForObjectItem(":Project Explorer_Tree", subfolder)) + + if (subsubfolder is not None): + expand(waitForObjectItem(":Project Explorer_Tree", subsubfolder)) + children = object.children(waitForObjectItem(":Project Explorer_Tree", subsubfolder)) + + for child in children: + if frag in child.text: + doubleClick(child, 5, 5, 0, Button.Button1) + +''' +Checks if file can be selected from example data. +Tries to select each directory as the locations are processed. +''' +def checkExample(frag, project="data", folder="examples", subfolder=None, subsubfolder=None): + + expand(waitForObjectItem(":Project Explorer_Tree", project)) + + children = select(folder) + + if (subfolder is not None): + children = select(subfolder) + + if (subsubfolder is not None): + children = select(subsubfolder) + + for child in children: + if frag in child.text: + return True + + return False + +def select(name): + selection = waitForObjectItem(":Project Explorer_Tree", name) + expand(selection) + mouseClick(selection, 5, 5, 0, Button.Button1) + return object.children(waitForObjectItem(":Project Explorer_Tree", name)) + +def openExternalFile(name): + + path = findFile("testdata", name) + path = os.path.abspath(path) + activateItem(waitForObjectItem(":_Menu", "File")) + activateItem(waitForObjectItem(":File_Menu", "Open File...")) + chooseFile(waitForObject(":SWT"), path) + +''' +Adds an external file to the project. +''' +def addExternalFile(fileName, suiteName, testName, project, subdir): + + path = findFile("testdata", fileName) + path = os.path.abspath(path) + + # Path to workspace is something like: + # /scratch/workspace/suite_conversion/tst_image_stack_tiffs/workspace/data + # or + # C:\scratch\workspace\suite_conversion\tst_image_stack_tiffs\workspace\data + shutil.copyfile(path, "/scratch/workspace/"+suiteName+"/"+testName+"/workspace/"+project+"/"+subdir+"/"+fileName) + mouseClick(waitForObjectItem(":Project Explorer_Tree", project)) + type(waitForObject(":Project Explorer_Tree"), "") + + +def chooseSlice(): + + vals = dawn_constants + mouseClick(waitForObjectItem(":Data_Table_2", "1/0"), 8, 12, 0, Button.Button1) + + mouseClick(waitForObject(":Slice as line plots_ToolItem"), 12, 14, 0, Button.Button1) + mouseClick(waitForObjectItem(":Data_Table_3", "0/2"), 13, 24, 0, Button.Button1) + mouseDrag(waitForObject(":Data_Scale"), 18, 22, 20, 0, Modifier.None, Button.Button1) + mouseClick(waitForObject(":XY plotting tools_ToolItem_2"), vals.TOOL_X, vals.TOOL_Y, 0, Button.Button1) + +factory = None + +def getPlottingSystem(name): + + global factory + if factory is not None: + return factory.getPlottingSystem(name) + + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Show View")) + activateItem(waitForObjectItem(":Show View_Menu", "Other...")) + type(waitForObject(":Show View_Text"), "Plotting Systems") + mouseClick(waitForObjectItem(":Show View_Tree", "Plotting Systems")) + clickButton(waitForObject(":Show View.OK_Button")) + waitForObject(":Plotting Systems_CTabItem") + plotButton = waitForObject(":Plotting Systems.Refresh_RefreshButton") + + factoryClass = plotButton.getClass().getClassLoader().loadClass("org.dawnsci.plotting.api.PlottingFactory") + + factory = factoryClass.newInstance() + system = factory.getPlottingSystem(name) + + # Close gallery + snooze(1) + try: + clickTab(waitForObject(":Plotting Systems_CTabItem"), 18, 11, 0, Button.Button1) + mouseClick(waitForObject(":Plotting Systems_CTabCloseBox", 1000)) + except: + print "Could not close gallery" + + snooze(1) + + return system + +def getScreenPosition(plottingSystem,x,y): + outX = None + outY = None + + axes = plottingSystem.getAxes() + + if axes.get(0).isYAxis(): + outY = axes.get(0).getValuePosition(y) + outX = axes.get(1).getValuePosition(x) + elif axes.get(1).isYAxis(): + outY = axes.get(1).getValuePosition(y) + outX = axes.get(0).getValuePosition(x) + + return outX,outY + +def dragSash(sash, dx, dy): + screenPoint = sash.toDisplay(sash.getBounds().width/2,sash.getBounds().height/2) + startDrag(sash, sash.getBounds().width/2, sash.getBounds().height/2); +# mousePress(waitForObject(":_Sash"), 5, 316, Button.Button1); + mouseMove(screenPoint.x - dx, screenPoint.y -dy) + snooze(1) + dropOn(sash, sash.getBounds().width/2, sash.getBounds().height/2,DnD.DropDefault); + +def dragToolToConstWidth(toolTab,sash): + current_width = toolTab.getControl().getBounds().width + + if (current_width < dawn_constants.TOOL_MIN_WIDTH): + dx = dawn_constants.TOOL_MIN_WIDTH - current_width + dragSash(sash, dx, 0) + diff --git a/org.dawnsci.squishtests/suite_usecases_general/tst_hdf5_large_tree/failedImages/failed_1.png b/org.dawnsci.squishtests/suite_usecases_general/tst_hdf5_large_tree/failedImages/failed_1.png new file mode 100644 index 0000000000000000000000000000000000000000..ec2d95494b1be908beebca15c797e1b5e6c72fdc GIT binary patch literal 30027 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 literal 0 HcmV?d00001 diff --git a/org.dawnsci.squishtests/suite_usecases_general/tst_hdf5_large_tree/failedImages/failed_3.png b/org.dawnsci.squishtests/suite_usecases_general/tst_hdf5_large_tree/failedImages/failed_3.png new file mode 100644 index 0000000000000000000000000000000000000000..5e3abce70c48231b05a0497edf0e3863b78076c1 GIT binary patch literal 24670 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

bqV=Pg_r9uc z7=R(6;<)4z7kQCq83eq3THj~6yp0dcz%~UwbtflrUj5ZY&;+dr=p4mw8^t5hIxL*V zcQR?~ zwDs&wn}6Vmj64lCzdYK%TMU1!_#f_`oLgZ{)`EV&I8WuBO6OU=dxoRagqn=&Mqd*1ACST2$Rw6^ zt2QPCIzM9mv11@scB9WXr=FtbK50GJIpN&mU$}n%T z`Q;mbuS))NRQ&^uf03a5SKXNlO!~%W+?wK_C3%0+_yZB55E@v*?C&`6YuRb5&xmLG zcS?bHLLw}g6RY^}oco`adj-MYMm;&1cj#|v^$$J2bETaM(@(7oi+|=rYA{iy7l0>! z;SU!9YAom_T>gR_x56YIQwo?TI{r^2o>IgmMUOAs-TWPhacjXP!8Xsm-EI>iW{$rR z`2Rq%jj(k%0-j}i2mUfWfB3~H#Mg>+NyN1 zEw%NGBO4)qrxZad)VSPeW$FF;wq96#F3X~IwTDz{^WS0QZu$0%2JAi)mmR8dj7#wk z@ZbtPZF$PDPQhZ9w!u5CQGXC^p+XiuzX%lLx{=oP^zhQ@ivD+cH6rMKnA;j<0h`k< zm46`-siHb-MQ1VOGkeecue`sQXZSn^;VcBwhe45hP{vn6CI3#b@3F) zI~1u1Jd&Q!o%&k-f#NEX(@h5$K%jyxT3`SMC<2_U6Y2VrcJaTh@y7{x=4?NC;(KmU_^RXPTyq?)zwe6u z#PJLrZrzfn=eFApiL`(j+<$r58Jd#Z4k^Stkt%^fJ%y3^LTzmqXPc{^M+xoGOu4(B ziT#cE^CjWc6zDtubtU{uRna?s3Mgzv*`fM;)0{lPRRkvm1N$~bmfdSCgD!zgXGls+8nfV!##B0LTa|~tX42e$O~x93Q|WaspcX?h$>LTsNlm@hR^Vl?I?frd z6HR!!p$7mtEDT<6I@$4J79%y@NGDd~(1LfeLx`*U4gDajzcKLS8QRVuX1SSWulRoN0Vq-LQ$wJ=SZ7Iu zp%<`4Pbzb!YHVD|BU9TwXJ%_;=d-)JUk882Ge$k9x{GRK0NiE$a42NI^(~06{P3J5KLqXJ z?icB_C|EvTUo^&Wn139W<|(bM<6#`{2kUIBT?&xQBkrVnzgzYo%Ei+%09YzHIm7lB zH#zMh&!;7-R^-uYLmM@RS-sI$FGNWc1()M$hB#46e>-4 zd|FF*mu>kU09ZMk6m-FrTukF#lp%e1Cz$FV%&P z7C1W(Bs?fvvC41Ax~8kA4z;;HQ%6F!`@JFk_?XqGf04L`l%d-0LJZt1C`!p5j#!Yo__pRsxE7NbT+fswu66buL+{oYc;7(2uKsugw|OwOr;&jJy5v(VSPiiw^IbSv*UB$yu~4}NK`xP$wvAEmGZp0YcUV< z3yIZ}G-T_iBVB$P!t~t|&sNw#@JQDrO&8VtI6G zOL=eH^0ESj*POlyw@6qA%}&IBEXtQO9lx$iUK>-{f9REdoTX8joU@^HW!*MDnDi`0fG+_#<){R**wN1}*Pq9YRRhL9Ky$Dko z2C{gek;o}Yj5eowaX{Afg3v^q=}#VNL5;JGHMhq?6R1*06P=hZpBX*_$>I07;YlTE z3T}t))Z?Ceb_8#14V+xu(BV3bAKu=;*mx#Jle-}+CzzZC|S42d? zZdAXjE^OdWlE14g6v4>9q)v3>f1CW*H9Xu|09O5z-vu}+%Kksd>VJ>?=5ySkZ16vB zS^bk;tiPLNG62yo(Ps*3p@B$-`eY&}&%&i;7=TLw78G=uD z|3y%p+G+GvxbLJ3^ZmZ1=s;S`TpdMA&$A(Ve$C+k0J>XxS+GQR9jNT1{mwS|-I9~@ zIovUrU;Wh&fS$Do>A41pNp&J&Jt1k#y+>aGpmSt@v4>nw1b>5jk1)S51uh5W8()0? z(P-*t?fGlJDd++B(iez?d22)_|G1HyO#zEb{aVS_;sOCc0>V=h=WZvYfIz7@gqF1} zfGp{X+ALmwG9zb0tY3|j=zP`=S-vF8DIbqVBz*mE5y@52t_$8cO-25NY&k)RIDQ1b z__a_&o&h$_z@+t#oC~pR*lI3J2xee7MN%q%B^P4nOY};|wz*^}LmmBJtqLQ&r+bDt ztYL6ig8}fxxDYyrjV>)2L@xNa&0aUqQ{17R*kAxY?u7nObv2l1^O6D#_g*sycba`= z!UP1~$NgAECNBN-d{g7$Bp7r_feh^Q0t76?2a-5w!V#qiAv$LSxZ9(MH~W|sIuAWSMWgt2n^z~`q|Z+uw(YS6$YBFN z(6PG1$X6b(Lf;21vFZLk)%Njs%c?5CTERWWC#T|Sdz=n(_&S*cG|uy%Aon++xKbh~ z+M?{WH1>7$fshbF?v0KG#YtqtnZFUtdBah`RBT)*RzV2S=y?t_kyn2>DYNE{AGcQG z$*nq8X)3LSWh*Iny&D=p4y+(_Cnwqj;bdDfQ3inWUx%114qs;ZN<>iRtj9p}YW~|p z;&Y%?x;%PFGWQeF#?e5k6hLYIB5fS&&f7ZvtFj`UB$620Z7x{_7P-$%AQr4E#{ow)%! zyb)kJu$VftsOX0|!n}Q)^Mw*J+n^6K@-N?e3pQqEY=2PMa6#H`S@Z@h77QeL%L#hR zy_5e;)b0^N(Xjze30Zk@16Iu&(D7myyQ~y(#ZD!=8eOLIxDEA;kztAu_wFbQ@&heo ziuLnKI{Zq^v#F@HdDbk3m=Tb!I$vKpWnSy@H+aT}k*}$WE1|{dS!UE=Z`BjgURHQ@ zCGD9#LJ@cRSOt{t6~w+4SLdWXb^g}cqLETL=QvE8)tdsTqc}+H!riYDH6hVNlTM`u zd(Zevf6hhj5vyqZt+`JfhIKX*=qsx^xx-+f85NjY>)kjF@*`{g=7j_GTNhhkp+e_9 zL?;cz>@?Xq&FOk zHDGg>7(HPLJ&M=a|D=AAHq}!l;}~uUqVWu3ABNQfB81GzOw9|i>q9~%0K(YJLsNm& z^+|Tb1A1?Mgj1kfn^xE*L_QtFM~1Fo?S;>)gixW*`3Mk`=x#h4LJfz~w#TI){9UV8~75!Qp69}Uy@OC0d3NM&$({8*{;%R?s6rf#KFATI-72tBcVRY-WWl^Kcq6^4NXJ?vz` zu)`Yt3dilz&w8QS<~?ae%l!-HwO$)ZY#2-7fB`eu3Km4ZxgFD)nwBV&c^LJ#z)Qe7_Gm6huBNS(hEV=7W- ztnc&K`N@jVQ!yb=+egEl&KgU+B4FIf;lrY(kJ6wKb0SC4dMukM0lV04{pqm>kY)9K zU?J{pu+9;fxu;U%dPCw7I_sdWsA_&GxDq6O7*!^xGuWBxxo--1wk zX_bDb+xA(}YNABK?P=T7u!Yda&xsXKyJuemT^H3`Xy$IM1~~-I9^I-9H|4;ezJ=Dn z`AS^IBF3k%3yoR#oOj1gn$ zx{NaMqUe`tBVW@5h(EYDNuP&4m|4sTr?FctWNH&%*ugcTw4t)FBogEz{_by%l zUK6)=gmLgpdIzX|_A;5P3z@w(*o&eSuP>#l4XtMH0O z=?}xWGg4OvPe>I$Xv)8MTjVS|1_1T#8nvSHaWf#aCeACfa2dgB{teR&GgM;Gv;gxu&^BAcD)TaAA z<0(m#4o!`5U7deX5Oh0ENDQ}Z52!^vWKe^p*Q{V3S{!?dm3C=o-4S<})oCR4cW<8- zITLj|$U*4IH*(kaUJDm$$kDHB)0bUn-;agyQ_b?)lj zJHVl#(c@gXlvn4rFP6UdFnYgC_t3;(xcI@)`3#0r8+Fi!X+tl$=N9pWE%V(>``)CX zK4eW4Zc4Kj?rA4$jT)mZ2am)SEftE144aRcF|vnz1dp`zz3w+CV~RZJ97Rj5yuF}T zPAXEE*LcnZ z`&EMso&HM-f1yQXQM!3=mm|RMet@wFDxJ}|Ue^hC1PxbJ3lbo8!BxQ0&gZ0%zO+Jj zO|PqnQXrXe&JhQo3VsE3OyZAQ@|H-5yoM!p#F62z2OupT0Od8-*_f zQndOj!MuomD>VUQ2CgDLn@0t{w@sjJqA61SY?UP@fGGRP%5|dxcs9BO5K)IwFZ+I# z0qouKdveA1Zwh=mzPadoR|jpi_Vn2=RwOTtzgL`Pzau$-2Tx9$|EopAe_5~kSJlS< zmu~bH1}Y!1ZDP)pAjXGKbk9-Q6LOWlZZ@ROkHPyTKHTe@al`C~u?-{MUso#63j)r> z2nV#ACdT@js4y{?)oAafgACT>lWb!x! zaQMR9gyr?>W|w2=g)`kc;iI7V&X#-?JP5^m(W+#w zW;rNyCOss8>ehW>Rd`ivx@QSvrX2i$YB#sxsTDP!rP^Qg^yB49^Mstj;$v~Sfu*os zK)sq9Fw$4RQ@f1MeL=YG_1;tBr{FX3WdR;U{Ew_@qzs@bIFy4}rKKEQSxuys(A#5v zO`(47P|Ym#8)F~;Yqd*fWo(=C-Sm)c&(?IC*oIm_EFJFk;%)se53ktU2+c56o~>nN zDgXte-Ff+elWXl&ciz-eB9A1UxDl=XDzI2wa!NQ6_4im=GCmYZGN zMHN6HaKZO?Wf-ywGwNr%`1A65H!#mH-5Gw}>az$J31k?G;vUFG^O#~r#Ps|1#h;tO zwP!=qR1YP-G(4~xM-L7bJ=ZQ>t9TK6r>I*@08UcV7Z%vnPTWA-w_Cl z3@!Y+xBtK}%sFL=-o8uD#WI72O>2tfI?SljWRnhqMxO<_61{ex9Xu zE^B__D4(Nm^OsLqsTaa%<@dU2)NWW{9l$F;VcOz(2XzV`OC-c-2Vw^`4SNQ6aVbCp z=POK)o?D%yLs={1IHBkhcYzDy4J^V&mKqFWLj{7RM%j-m3+|1hCG1ivCq%ca&ZOy7 zGlDAy;ELhJ9>5pLZt()tkjBpsEj%sgtNbRJ;jgSC!)r>uDjIbD+?(BJcU`3zAbNd( zZ&S8x0*uGp&E*`5lY6oJjk$&;rF5pVBJQImk(T^8C9n{8V9r4o)+AVbnAjgkUls6k z6+}Mwv~4HCl`6w;5bqf`qJguwhapOGN|5@So3e5`nl0TFl9$uVs}1`sxS6BsWSm)X z-nHbRb;m;CeuaRigAe^k4$)aa)P-TRF*uP#taIF!Rg;nVzuLLdsHT!E93F|H!6qW3 zASw~MVE{$c5TZsBVIU&gVP6HrQ4tZL0TWrmL!faW8fnIb$f6)>6PAb|5k%rL#F37e zW|2WaARdqeFc^))!f4gWAN1vRKPL6CR;% zQ<`v^p2_{uUQIr)Zdxpjc9Y*(`}+3wUHQ3KANLaPVuYmQTwV5dqD^O6&rx>!?e$Nu zkQyYFw33ZJqe92C?!dx87!Oz&A?W$$gr|qQgO9qmYHPJp#)??tPf?s8f7!thjf!BW zv*_M-3B-3?x%=I8dOef|P5nEokxjEPA<_FH%5sHS=Y zseik4%Eac(;yMjRfZUDt*xncDc_oF*c6(N+vYzWsq6#-y6bUd9Nl4WEN;=a=x3y~L+>n3v#;X&fv>u6e#JNAjhp7r z7Ob7>OcUBUnGD9M_lhbop}GrGgOj-Q(4Tu&66xWGtwWqvT}S&F@-8nd%9khFn?5c1 zMwEHp_0hrAen*?*@e1>)I)1J zU0>zjuOq`361q%!bd`OP0*~pmN>CVV4|-lv3nAUx8+b=HddIz#NTMz=RZg@SZz$ki zZtRBg-A$Tq&K)NHVuM{0gMx16O&cq7Vk|{s;9FJH(=qT=xL7RGY7Ms{`A=jH#ZQR1 zcV-ele*1E@N(2Yg3Jdq|v!5zW35!tN4;?WP#4%mhHZw?LTH~*0D;X_&594kWy{f57 z!AYcyPT_TnPg3&pq>xUxMQv#)C@B;eJRaq@DIobp6@7KYl?1Qaef8+DZhk4gbc$cX zvX^M_f5@s&o%%<>d%IiRCVZTy;tqE88-%>%Ql`}@8S|$tH>sqg)q_-lg%J($3#ThAG#tPv5F&~)eKWuO0?I9WNqXk7c z4e6W~Qyz~tpYyxbvDd22ROCCIE8HcaSU2znXB?ON9>%Y6A)1oe>RtFZUB?sIcWq&< zWnlW%Ble5zIyY3m=XwoK+?Y*rsEZ78pY9voTWCZsNy9TL-8`IIkM%Vt?SXw3bB+d& zJ#Vz}A}mb?;6H`;O3@B&Ck;fs3wM93=PFS7-A)vvUw`Zy>5?D`834@n`9_ zZ)X69qhK;wR(@~8PTt~0%Ek3WL(?JuipT9|j^$`FohqFCnUpaF`=O(W*-x8hS9l6q zf{KN@vfTI1mGm0ApTLG$`Z0b-+m9Sp2%J3gI6OG7rh(`1_Z=>EMr6V&B;jBQitf|zkTgkWkC8_7BL@_B`}wBghTstDi=;r9gHfO&QP3KGJz0}$ zxqyAd^b=G@?aVUN($yc~{nTYU{7UaGv=i5A}iwMfPEB;b_utZRLMLg8tfW zKWyZESyaCPiTdBaAA_7^0;5+7`!-@z^$5xEGhHmG`QN~=C3E!A^_CX-{efZ;AjSeZ z0ihO)Rj$&F?_=haAXp4G=mOeg^86GxMG2AR2U-t$tf{N9wERxVqyr-c=-B&Uv|qjU z&RJ(|TVI-yy7}u#!>byc;bbimf~>p19>?3rtvvzV5BjE!dZy@Nqz(ip_N&N=v1FK{ z;3-Z&ctEGrW^+1Xz%?B2=XYO0e%vbt`=u|IcTPzvSI*E?d$4o45wBMDR}-m0ML|IV zMNPpIRn3n1B0D$=ocab*5x%kL7s%bWwiqKPH`>A&Lyc%FYi-wXoVne~{<=whC>^s4 zX5Y#C_Cc|~-g!h3u2n&Y@DilVz)^L+We#$3hCR4#O71CJre;gS^5#Fn0AOvm1Q_!* zXj8$2hckbu-Or}aOtM+>_rtzt)ND`vTvyW{&UtG9r6UwyyGgUX;;**?YR8f_w2)j@ zV1Nmhbq>rju%)x_l*U7#F97=m?!(L%?OP(ff$Ex*uY}U2U#f!Uc!1`>mbdT@nsdz@ zMyw}d`Xiza7r@~@iA(?B$TDHaeCl&HAECpr-Eqx k_uual_") + waitForPrompt(object_name=object_name, prompt=prompt, timeout=timeout) + +def waitForPrompt(object_name=":PyDev Console", prompt=">>> ", timeout=20000): + '''Wait for the prompt on the interactive console''' + console_object=waitForObject(object_name) + if not waitFor('console_object.text.endswith("%s")' % (prompt), timeout): + raise LookupError + +def _finishPythonSetup(): + clickButton(waitForObject(":Selection needed.OK_Button")) + + # All done, close preferences + clickButton(waitForObject(":Preferences.OK_Button")) + # It can take a while to configure interpreter, so wait until + # the workbench window is ready again + # On windows vm this can take forever! So wait 300 seconds + waitForObject(":Workbench Window", 300000) + +def setupEPDPython(): + waitForObject(":Workbench Window") + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Preferences")) + expand(waitForObjectItem(":Preferences_Tree", "PyDev")) + mouseClick(waitForObjectItem(":Preferences_Tree", "Interpreter - Python")) + mouseClick(waitForObject(":Preferences.New..._Button")) + type(waitForObject(":Select interpreter.Interpreter Name: _Text"), "EPD Free Python") + found = False + for loc in EPD_FREE_LOCATIONS: + if os.path.exists(loc): + type(waitForObject(":Select interpreter.Interpreter Executable: _Text"), "") + type(waitForObject(":Select interpreter.Interpreter Executable: _Text"), loc) + if len(waitForObject(":Select interpreter Error Message_Text").text) == 0: + # found a good one + test.verify(True, "setupEPDPython: Using %s as EPD Free Python" % loc) + found = True + break + if found: + clickButton(waitForObject(":Select interpreter.OK_Button")) + _finishPythonSetup() + else: + test.passes("setupEPDPython: No installed EPD found, deferring to setupPython") + # We failed to find installed EPD, so try and install it now + clickButton(waitForObject(":Select interpreter.Cancel_Button")) + clickButton(waitForObject(":Preferences.Cancel_Button")) + setupPython(installEPD=True) + test.passes("setupEPDPython: Success") + + +def setupPython(allowInstallEPD=False, installEPD=False, installEPDPath=None): + waitForObject(":Workbench Window") + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Preferences")) + expand(waitForObjectItem(":Preferences_Tree", "PyDev")) + mouseClick(waitForObjectItem(":Preferences_Tree", "Interpreter - Python")) + clickButton(waitForObject(":Preferences.Auto Config_Button")) + + # Wait for auto config list to come up + autoError = waitForObject(":Unable to auto-configure..OK_Button", 100) + if (autoError!=None): + clickButton(autoError) + clickButton(waitForObject(":Preferences.New..._Button")) + type(waitForObject(":Select interpreter.Interpreter Name: _Text"), "EPD Free Python") + type(waitForObject(":Select interpreter.Interpreter Executable: _Text"), "C:\\Python26\\python.exe") + clickButton(waitForObject(":Select interpreter.OK_Button")) + clickButton(waitForObject(":Selection needed.OK_Button")) + clickButton(waitForObject(":Preferences.OK_Button", 120000)) + return + + # Wait for auto config list to come up + multiOptions = waitFor('object.exists(":ListDialog_Shell")', 20000) + multiOptions = multiOptions and object.exists(":Select Interpreter Available_Caption") + multiOptions = multiOptions and object.exists(":Select Interpreter Available_Table") + if multiOptions: + availableList = object.children(waitForObject(":Select Interpreter Available_Table")) + if installEPD: + allowedList = filter(lambda x: "EPD" in x.text and "select to install" in x.text, availableList) + else: + allowedList = filter(lambda x: "select to install" not in x.text, availableList) + + test.verify(len(allowedList) == 1, "setupPython: Filter to one available Python to Auto Config") + + clickItem(waitForObject(":Select Interpreter Available_Table"), "%d/0" % allowedList[0].row, 5, 5) + clickButton(waitForObject(":Select Interpreter Available_OK_Button")) + + # In the case that there is no Python autofound, allow install of EPD + # This only applies if the selection interpreter list dialog isn't shown + elif allowInstallEPD and waitFor('object.exists(":Enthought EPD Free Installer_Label")', 20000): + installEPD = True + + if installEPD: + test.verify(object.exists(":Enthought EPD Free Installer_Label"), "setupPython: Enthought Installer Wizard open (if this fails it is because the Enthought wizard didn't open)") + test.verify(object.exists(":I accept the terms of the license agreement_Button"), "setupPython: License agreement open") + clickButton(waitForObject(":I accept the terms of the license agreement_Button", 1)) + clickButton(waitForObject(":Next >_Button")) + + if installEPDPath is not None: + type(waitForObject(":Install to:_Text"), installEPDPath) + clickButton(waitForObject(":Close wizard automatically on successful installation._Button")) + clickButton(waitForObject(":Finish_Button")) + # Wait up to 5 minutes for the wizard to finish + # There is a case here to add event driven check so that if there + # is an unexpected failure we don't wait so long + waitForObject(":Selection needed.OK_Button", 300000) + + _finishPythonSetup() + test.passes("setupPython: Success") + +def getPythonLocation(): + for loc in EPD_FREE_LOCATIONS: + if os.path.exists(loc): + return loc + return None diff --git a/org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/dawn_global_startup.py b/org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/dawn_global_startup.py new file mode 100644 index 0000000..797d93e --- /dev/null +++ b/org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/dawn_global_startup.py @@ -0,0 +1,160 @@ +DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1004_opid14/workspace" +DAWN_SUITE_WORKSPACE="suite_test_single_workspace" +USE_ATTACH=False + +testSettings.logScreenshotOnFail = True +testSettings.logScreenshotOnError = True + +import os, shutil +from datetime import datetime + +def startDAWNSuiteWorkspace(): + + # We start each test in a new workspace + cwd = os.getcwd() + parent_path, test_name = os.path.split(cwd) + suite_name = os.path.basename(parent_path) + workspace = "%s/%s/%s" % (DAWN_WORKSPACE_ROOT, suite_name, DAWN_SUITE_WORKSPACE) + + start = datetime.now() + startApplication("dawn -consoleLog -data %s" % workspace, "", -1, 90) + end = datetime.now() + + test.log("Application took " + str(end-start) + " to start") + + window = waitForObject(":Workbench Window") + window.setMaximized(True) + # Let any setup items continue (e.g. Jython interpreter setup) + # XXX This is a hack because we don't have a better way to determine if + # the GUI is fully started + snooze(1.0) + test.passes("startOrAttachToDAWNOnly: Success") + + try: + #find should fail fast if no welcome screen + findObject(":Welcome_CTabItem") + dismissWelcomScreen() + except: + pass + + +def startOrAttachToDAWNOnly(clean_workspace=True): + if USE_ATTACH: + attachToApplication("attachable_dawn") + else: + # We start each test in a new workspace + cwd = os.getcwd() + parent_path, test_name = os.path.split(cwd) + suite_name = os.path.basename(parent_path) + workparent = os.path.join(DAWN_WORKSPACE_ROOT, suite_name, test_name) + workspace = os.path.join(workparent, 'workspace') + osgi_user_area = os.path.join(workparent, 'osgi_user_area') + osgi_configuration_area = os.path.join(workparent, 'osgi_configuration_area') + if clean_workspace: + try: + shutil.rmtree(workparent) + except OSError: + # Ignore error here, check below + # that directory is gone + pass + snooze(1) + test.verify(not os.path.exists(workparent), "startOrAttachToDAWNOnly: Workspace is clean") + + start = datetime.now() + startApplication("dawn -consoleLog -data %s -user %s -configuration %s -name %s-%s" % + (workspace, osgi_user_area, osgi_configuration_area, suite_name, test_name), "", -1, 90) + end = datetime.now() + test.log("Application took " + str(end-start) + " to start") + + window = waitForObject(":Workbench Window") + window.setMaximized(True) + # Let any setup items continue (e.g. Jython interpreter setup) + # XXX This is a hack because we don't have a better way to determine if + # the GUI is fully started + snooze(1.0) + test.passes("startOrAttachToDAWNOnly: Success") + +def dismissWelcomScreen(): + clickTab(waitForObject(":Welcome_CTabItem"), 10, 10, 0, Button.Button3) + activateItem(waitForObjectItem(":Pop Up Menu", "Close")) + test.passes("dismissWelcomScreen: Success") + +def startOrAttachToDAWN(): + startOrAttachToDAWNOnly() + dismissWelcomScreen() + test.passes("startOrAttachToDAWN: Success") + +def closeDAWN(): + closeWindow(":Workbench Window") + clickButton(waitForObject(":Confirm Exit.OK_Button")) + test.passes("closeDAWN: Success") + +def closeOrDetachFromDAWN(): + if USE_ATTACH: + # nothing to do + pass + else: + closeDAWN() + test.passes("closeOrDetachFromDAWN: Success") + +def openPerspective(perspectiveName): + waitForObject(":Workbench Window") + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Open Perspective")) + activateItem(waitForObjectItem(":Open Perspective_Menu", "Other...")) + mouseClick(waitForObject("{caption='%s' column='0' container=':Open Perspective_Table' type='com.froglogic.squish.swt.TableCell'}" % perspectiveName), 5, 5, 0, Button.Button1) + mouseClick(waitForObject(":Open Perspective.OK_Button")) + # Opening a perspective can (more than most) kick off things in the background + # This background processing can make the workbench window appear fully ready + # but the perspective isn't. Therefore we snooze a few seconds to let everything + # catchup + waitForObject(":Workbench Window") + snooze(3.0) + waitForObject(":Workbench Window") + test.passes("openPerspective: %s" % perspectiveName) + +def openView(viewName, matchOpen=False): + ''' Open the view named viewName. If matchOpen is true, will assume that an open view with + viewName in the title bar of the view is the expected one and only activate it ''' + waitForObject(":Workbench Window") + if matchOpen: + viewRealObjectName = "{caption='%s' type='org.eclipse.swt.custom.CTabItem' window=':Workbench Window'}" % viewName; + if object.exists(viewRealObjectName): + mouseClick(waitForObject(viewRealObjectName)) + test.passes("openView (matchOpen): %s" % viewName) + return + + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Show View")) + activateItem(waitForObjectItem(":Show View_Menu", "Other...")) + type(waitForObject(":Show View_Text"), viewName) + mouseClick(waitForObjectItem(":Show View_Tree", viewName)) + mouseClick(waitForObject(":Show View.OK_Button")) + waitForObject(":Workbench Window") + test.passes("openView: %s" % viewName) + + + +def getErrorItems(): + ''' Return the Java Array that contains the list of entries in the Error Log ''' + openView("Error Log", True) + errorTree = waitForObject(":Error Log_Tree") + return errorTree.getItems() + +def openAndClearErrorLog(): + ''' Open and clear the Eclipse Error Log. Use getErrorItems() first to find out if there is + anything in them ''' + if getErrorItems().length > 0: + snooze(2) + mouseClick(waitForObject(":Delete Log_ToolItem")) + clickButton(waitForObject(":Confirm Delete.OK_Button")) + +def verifyAndClearErrorLog(): + ''' Verifies that the error log is empty and clears it if not ''' + if getErrorItems().length > 0: + test.fail("Items are in error log view (if this test fails, see console output as -consoleLog is on)") + mouseClick(waitForObject(":Delete Log_ToolItem")) + clickButton(waitForObject(":Confirm Delete.OK_Button")) + else: + # provide a less verbose message when the test just passed + test.passes("No items are in error log view") diff --git a/org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/dawn_slider_utils.py b/org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/dawn_slider_utils.py new file mode 100644 index 0000000..ccab1b9 --- /dev/null +++ b/org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/dawn_slider_utils.py @@ -0,0 +1,28 @@ +def check_slider_position(slider, position, tollerence): + range = slider.getMaximum()-slider.getMinimum() + pos = slider.getSelection()-slider.getMinimum() + + proportion = float(pos)/float(range) + print "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", position, proportion, range, pos + test.verify((abs(position - proportion) < tollerence), "Slider not in expected position, expected %f and got %f" %(position, proportion)) + + +def slide_to_propotion(slider, proportion): + # get the bounds of the slider + bounds = slider.bounds + width = bounds.width-30 # minus the width of the slider gizmo + + range = slider.getMaximum()-slider.getMinimum() + start_position = slider.getSelection()-slider.getMinimum() + + scale = float(width)/float(range) + + end_position = width*proportion + end_position = end_position - start_position*scale+15 + + mouseDrag(slider, start_position*scale+15, 5, end_position, 5, Modifier.None, Button.Button1) + + # then check the position to make sure we are in the right place + #check_slider_position(slider,proportion,0.1) + + diff --git a/org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/use_case_utils.py b/org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/use_case_utils.py new file mode 100644 index 0000000..5763a9d --- /dev/null +++ b/org.dawnsci.squishtests/suite_workflows_bignexus/shared/scripts/use_case_utils.py @@ -0,0 +1,165 @@ +source(findFile("scripts", "dawn_constants.py")) + +import os +import shutil + + +def createProject(projectName, projectType="Workflow Project"): + + activateItem(waitForObjectItem(":_Menu", "File")) + activateItem(waitForObjectItem(":File_Menu", "New")) + activateItem(waitForObjectItem(":New_Menu_2", "Project...")) + type(waitForObject(":_Text"), projectType) + mouseClick(waitForObjectItem(":_Tree", projectType), 59, 10, 0, Button.Button1) + clickButton(waitForObject(":Next >_Button")) + mouseClick(waitForObject(":Project name:_Text"), 48, 3, 0, Button.Button1) + type(waitForObject(":Project name:_Text"), projectName) + clickButton(waitForObject(":Finish_Button_2")) + snooze(1) + +# All these arguments = bad but not sure how to do his as not python expert. +def openExample(frag, project="data", folder="examples", subfolder=None, subsubfolder=None): + + expand(waitForObjectItem(":Project Explorer_Tree", project)) + expand(waitForObjectItem(":Project Explorer_Tree", folder)) + children = object.children(waitForObjectItem(":Project Explorer_Tree", folder)) + + if (subfolder is not None): + expand(waitForObjectItem(":Project Explorer_Tree", subfolder)) + children = object.children(waitForObjectItem(":Project Explorer_Tree", subfolder)) + + if (subsubfolder is not None): + expand(waitForObjectItem(":Project Explorer_Tree", subsubfolder)) + children = object.children(waitForObjectItem(":Project Explorer_Tree", subsubfolder)) + + for child in children: + if frag in child.text: + doubleClick(child, 5, 5, 0, Button.Button1) + +''' +Checks if file can be selected from example data. +Tries to select each directory as the locations are processed. +''' +def checkExample(frag, project="data", folder="examples", subfolder=None, subsubfolder=None): + + expand(waitForObjectItem(":Project Explorer_Tree", project)) + + children = select(folder) + + if (subfolder is not None): + children = select(subfolder) + + if (subsubfolder is not None): + children = select(subsubfolder) + + for child in children: + if frag in child.text: + return True + + return False + +def select(name): + selection = waitForObjectItem(":Project Explorer_Tree", name) + expand(selection) + mouseClick(selection, 5, 5, 0, Button.Button1) + return object.children(waitForObjectItem(":Project Explorer_Tree", name)) + +def openExternalFile(name): + + path = findFile("testdata", name) + path = os.path.abspath(path) + activateItem(waitForObjectItem(":_Menu", "File")) + activateItem(waitForObjectItem(":File_Menu", "Open File...")) + chooseFile(waitForObject(":SWT"), path) + +''' +Adds an external file to the project. +''' +def addExternalFile(fileName, suiteName, testName, project, subdir): + + path = findFile("testdata", fileName) + path = os.path.abspath(path) + + # Path to workspace is something like: + # /scratch/workspace/suite_conversion/tst_image_stack_tiffs/workspace/data + # or + # C:\scratch\workspace\suite_conversion\tst_image_stack_tiffs\workspace\data + shutil.copyfile(path, "/scratch/workspace/"+suiteName+"/"+testName+"/workspace/"+project+"/"+subdir+"/"+fileName) + mouseClick(waitForObjectItem(":Project Explorer_Tree", project)) + type(waitForObject(":Project Explorer_Tree"), "") + + +def chooseSlice(): + + vals = dawn_constants + mouseClick(waitForObjectItem(":Data_Table_2", "1/0"), 8, 12, 0, Button.Button1) + + mouseClick(waitForObject(":Slice as line plots_ToolItem"), 12, 14, 0, Button.Button1) + mouseClick(waitForObjectItem(":Data_Table_3", "0/2"), 13, 24, 0, Button.Button1) + mouseDrag(waitForObject(":Data_Scale"), 18, 22, 20, 0, Modifier.None, Button.Button1) + mouseClick(waitForObject(":XY plotting tools_ToolItem_2"), vals.TOOL_X, vals.TOOL_Y, 0, Button.Button1) + +factory = None + +def getPlottingSystem(name): + + global factory + if factory is not None: + return factory.getPlottingSystem(name) + + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Show View")) + activateItem(waitForObjectItem(":Show View_Menu", "Other...")) + type(waitForObject(":Show View_Text"), "Plotting Systems") + mouseClick(waitForObjectItem(":Show View_Tree", "Plotting Systems")) + clickButton(waitForObject(":Show View.OK_Button")) + waitForObject(":Plotting Systems_CTabItem") + plotButton = waitForObject(":Plotting Systems.Refresh_RefreshButton") + + factoryClass = plotButton.getClass().getClassLoader().loadClass("org.dawnsci.plotting.api.PlottingFactory") + + factory = factoryClass.newInstance() + system = factory.getPlottingSystem(name) + + # Close gallery + snooze(1) + try: + clickTab(waitForObject(":Plotting Systems_CTabItem"), 18, 11, 0, Button.Button1) + mouseClick(waitForObject(":Plotting Systems_CTabCloseBox", 1000)) + except: + print "Could not close gallery" + + snooze(1) + + return system + +def getScreenPosition(plottingSystem,x,y): + outX = None + outY = None + + axes = plottingSystem.getAxes() + + if axes.get(0).isYAxis(): + outY = axes.get(0).getValuePosition(y) + outX = axes.get(1).getValuePosition(x) + elif axes.get(1).isYAxis(): + outY = axes.get(1).getValuePosition(y) + outX = axes.get(0).getValuePosition(x) + + return outX,outY + +def dragSash(sash, dx, dy): + screenPoint = sash.toDisplay(sash.getBounds().width/2,sash.getBounds().height/2) + startDrag(sash, sash.getBounds().width/2, sash.getBounds().height/2); +# mousePress(waitForObject(":_Sash"), 5, 316, Button.Button1); + mouseMove(screenPoint.x - dx, screenPoint.y -dy) + snooze(1) + dropOn(sash, sash.getBounds().width/2, sash.getBounds().height/2,DnD.DropDefault); + +def dragToolToConstWidth(toolTab,sash): + current_width = toolTab.getControl().getBounds().width + + if (current_width < dawn_constants.TOOL_MIN_WIDTH): + dx = dawn_constants.TOOL_MIN_WIDTH - current_width + dragSash(sash, dx, 0) + diff --git a/org.dawnsci.squishtests/suite_workflows_bignexus/tst_slicedata_dbrowsing/failedImages/failed_1.png b/org.dawnsci.squishtests/suite_workflows_bignexus/tst_slicedata_dbrowsing/failedImages/failed_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d4e72deff0bd6b02cb9d28562dccfec745457bb7 GIT binary patch literal 14745 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 DETq`n literal 0 HcmV?d00001 diff --git a/org.dawnsci.squishtests/suite_workflows_bignexus/tst_slicedata_dbrowsing/failedImages/failed_2.png b/org.dawnsci.squishtests/suite_workflows_bignexus/tst_slicedata_dbrowsing/failedImages/failed_2.png new file mode 100644 index 0000000000000000000000000000000000000000..9bfe3597c11f0591c7acd82774be09457315aee3 GIT binary patch literal 14783 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 L(5F?OM11>SHtRi; literal 0 HcmV?d00001 diff --git a/org.dawnsci.squishtests/suite_workflows_bignexus/tst_slicedata_dbrowsing/failedImages/failed_3.png b/org.dawnsci.squishtests/suite_workflows_bignexus/tst_slicedata_dbrowsing/failedImages/failed_3.png new file mode 100644 index 0000000000000000000000000000000000000000..a149044b12b36bd6c61a8a535b4d16f067e28617 GIT binary patch literal 14814 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") + waitForPrompt(object_name=object_name, prompt=prompt, timeout=timeout) + +def waitForPrompt(object_name=":PyDev Console", prompt=">>> ", timeout=20000): + '''Wait for the prompt on the interactive console''' + console_object=waitForObject(object_name) + if not waitFor('console_object.text.endswith("%s")' % (prompt), timeout): + raise LookupError + +def _finishPythonSetup(): + clickButton(waitForObject(":Selection needed.OK_Button")) + + # All done, close preferences + clickButton(waitForObject(":Preferences.OK_Button")) + # It can take a while to configure interpreter, so wait until + # the workbench window is ready again + # On windows vm this can take forever! So wait 300 seconds + waitForObject(":Workbench Window", 300000) + +def setupEPDPython(): + waitForObject(":Workbench Window") + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Preferences")) + expand(waitForObjectItem(":Preferences_Tree", "PyDev")) + mouseClick(waitForObjectItem(":Preferences_Tree", "Interpreter - Python")) + mouseClick(waitForObject(":Preferences.New..._Button")) + type(waitForObject(":Select interpreter.Interpreter Name: _Text"), "EPD Free Python") + found = False + for loc in EPD_FREE_LOCATIONS: + if os.path.exists(loc): + type(waitForObject(":Select interpreter.Interpreter Executable: _Text"), "") + type(waitForObject(":Select interpreter.Interpreter Executable: _Text"), loc) + if len(waitForObject(":Select interpreter Error Message_Text").text) == 0: + # found a good one + test.verify(True, "setupEPDPython: Using %s as EPD Free Python" % loc) + found = True + break + if found: + clickButton(waitForObject(":Select interpreter.OK_Button")) + _finishPythonSetup() + else: + test.passes("setupEPDPython: No installed EPD found, deferring to setupPython") + # We failed to find installed EPD, so try and install it now + clickButton(waitForObject(":Select interpreter.Cancel_Button")) + clickButton(waitForObject(":Preferences.Cancel_Button")) + setupPython(installEPD=True) + test.passes("setupEPDPython: Success") + + +def setupPython(allowInstallEPD=False, installEPD=False, installEPDPath=None): + waitForObject(":Workbench Window") + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Preferences")) + expand(waitForObjectItem(":Preferences_Tree", "PyDev")) + mouseClick(waitForObjectItem(":Preferences_Tree", "Interpreter - Python")) + clickButton(waitForObject(":Preferences.Auto Config_Button")) + + # Wait for auto config list to come up + autoError = waitForObject(":Unable to auto-configure..OK_Button", 100) + if (autoError!=None): + clickButton(autoError) + clickButton(waitForObject(":Preferences.New..._Button")) + type(waitForObject(":Select interpreter.Interpreter Name: _Text"), "EPD Free Python") + type(waitForObject(":Select interpreter.Interpreter Executable: _Text"), "C:\\Python26\\python.exe") + clickButton(waitForObject(":Select interpreter.OK_Button")) + clickButton(waitForObject(":Selection needed.OK_Button")) + clickButton(waitForObject(":Preferences.OK_Button", 120000)) + return + + # Wait for auto config list to come up + multiOptions = waitFor('object.exists(":ListDialog_Shell")', 20000) + multiOptions = multiOptions and object.exists(":Select Interpreter Available_Caption") + multiOptions = multiOptions and object.exists(":Select Interpreter Available_Table") + if multiOptions: + availableList = object.children(waitForObject(":Select Interpreter Available_Table")) + if installEPD: + allowedList = filter(lambda x: "EPD" in x.text and "select to install" in x.text, availableList) + else: + allowedList = filter(lambda x: "select to install" not in x.text, availableList) + + test.verify(len(allowedList) == 1, "setupPython: Filter to one available Python to Auto Config") + + clickItem(waitForObject(":Select Interpreter Available_Table"), "%d/0" % allowedList[0].row, 5, 5) + clickButton(waitForObject(":Select Interpreter Available_OK_Button")) + + # In the case that there is no Python autofound, allow install of EPD + # This only applies if the selection interpreter list dialog isn't shown + elif allowInstallEPD and waitFor('object.exists(":Enthought EPD Free Installer_Label")', 20000): + installEPD = True + + if installEPD: + test.verify(object.exists(":Enthought EPD Free Installer_Label"), "setupPython: Enthought Installer Wizard open (if this fails it is because the Enthought wizard didn't open)") + test.verify(object.exists(":I accept the terms of the license agreement_Button"), "setupPython: License agreement open") + clickButton(waitForObject(":I accept the terms of the license agreement_Button", 1)) + clickButton(waitForObject(":Next >_Button")) + + if installEPDPath is not None: + type(waitForObject(":Install to:_Text"), installEPDPath) + clickButton(waitForObject(":Close wizard automatically on successful installation._Button")) + clickButton(waitForObject(":Finish_Button")) + # Wait up to 5 minutes for the wizard to finish + # There is a case here to add event driven check so that if there + # is an unexpected failure we don't wait so long + waitForObject(":Selection needed.OK_Button", 300000) + + _finishPythonSetup() + test.passes("setupPython: Success") + +def getPythonLocation(): + for loc in EPD_FREE_LOCATIONS: + if os.path.exists(loc): + return loc + return None diff --git a/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py b/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py new file mode 100644 index 0000000..30c7ddf --- /dev/null +++ b/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py @@ -0,0 +1,160 @@ +DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1204_opid23/dawn_workspace" +DAWN_SUITE_WORKSPACE="suite_test_single_workspace" +USE_ATTACH=False + +testSettings.logScreenshotOnFail = True +testSettings.logScreenshotOnError = True + +import os, shutil +from datetime import datetime + +def startDAWNSuiteWorkspace(): + + # We start each test in a new workspace + cwd = os.getcwd() + parent_path, test_name = os.path.split(cwd) + suite_name = os.path.basename(parent_path) + workspace = "%s/%s/%s" % (DAWN_WORKSPACE_ROOT, suite_name, DAWN_SUITE_WORKSPACE) + + start = datetime.now() + startApplication("dawn -consoleLog -data %s" % workspace, "", -1, 90) + end = datetime.now() + + test.log("Application took " + str(end-start) + " to start") + + window = waitForObject(":Workbench Window") + window.setMaximized(True) + # Let any setup items continue (e.g. Jython interpreter setup) + # XXX This is a hack because we don't have a better way to determine if + # the GUI is fully started + snooze(1.0) + test.passes("startOrAttachToDAWNOnly: Success") + + try: + #find should fail fast if no welcome screen + findObject(":Welcome_CTabItem") + dismissWelcomScreen() + except: + pass + + +def startOrAttachToDAWNOnly(clean_workspace=True): + if USE_ATTACH: + attachToApplication("attachable_dawn") + else: + # We start each test in a new workspace + cwd = os.getcwd() + parent_path, test_name = os.path.split(cwd) + suite_name = os.path.basename(parent_path) + workparent = os.path.join(DAWN_WORKSPACE_ROOT, suite_name, test_name) + workspace = os.path.join(workparent, 'workspace') + osgi_user_area = os.path.join(workparent, 'osgi_user_area') + osgi_configuration_area = os.path.join(workparent, 'osgi_configuration_area') + if clean_workspace: + try: + shutil.rmtree(workparent) + except OSError: + # Ignore error here, check below + # that directory is gone + pass + snooze(1) + test.verify(not os.path.exists(workparent), "startOrAttachToDAWNOnly: Workspace is clean") + + start = datetime.now() + startApplication("dawn -consoleLog -data %s -user %s -configuration %s -name %s-%s" % + (workspace, osgi_user_area, osgi_configuration_area, suite_name, test_name), "", -1, 90) + end = datetime.now() + test.log("Application took " + str(end-start) + " to start") + + window = waitForObject(":Workbench Window") + window.setMaximized(True) + # Let any setup items continue (e.g. Jython interpreter setup) + # XXX This is a hack because we don't have a better way to determine if + # the GUI is fully started + snooze(1.0) + test.passes("startOrAttachToDAWNOnly: Success") + +def dismissWelcomScreen(): + clickTab(waitForObject(":Welcome_CTabItem"), 10, 10, 0, Button.Button3) + activateItem(waitForObjectItem(":Pop Up Menu", "Close")) + test.passes("dismissWelcomScreen: Success") + +def startOrAttachToDAWN(): + startOrAttachToDAWNOnly() + dismissWelcomScreen() + test.passes("startOrAttachToDAWN: Success") + +def closeDAWN(): + closeWindow(":Workbench Window") + clickButton(waitForObject(":Confirm Exit.OK_Button")) + test.passes("closeDAWN: Success") + +def closeOrDetachFromDAWN(): + if USE_ATTACH: + # nothing to do + pass + else: + closeDAWN() + test.passes("closeOrDetachFromDAWN: Success") + +def openPerspective(perspectiveName): + waitForObject(":Workbench Window") + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Open Perspective")) + activateItem(waitForObjectItem(":Open Perspective_Menu", "Other...")) + mouseClick(waitForObject("{caption='%s' column='0' container=':Open Perspective_Table' type='com.froglogic.squish.swt.TableCell'}" % perspectiveName), 5, 5, 0, Button.Button1) + mouseClick(waitForObject(":Open Perspective.OK_Button")) + # Opening a perspective can (more than most) kick off things in the background + # This background processing can make the workbench window appear fully ready + # but the perspective isn't. Therefore we snooze a few seconds to let everything + # catchup + waitForObject(":Workbench Window") + snooze(3.0) + waitForObject(":Workbench Window") + test.passes("openPerspective: %s" % perspectiveName) + +def openView(viewName, matchOpen=False): + ''' Open the view named viewName. If matchOpen is true, will assume that an open view with + viewName in the title bar of the view is the expected one and only activate it ''' + waitForObject(":Workbench Window") + if matchOpen: + viewRealObjectName = "{caption='%s' type='org.eclipse.swt.custom.CTabItem' window=':Workbench Window'}" % viewName; + if object.exists(viewRealObjectName): + mouseClick(waitForObject(viewRealObjectName)) + test.passes("openView (matchOpen): %s" % viewName) + return + + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Show View")) + activateItem(waitForObjectItem(":Show View_Menu", "Other...")) + type(waitForObject(":Show View_Text"), viewName) + mouseClick(waitForObjectItem(":Show View_Tree", viewName)) + mouseClick(waitForObject(":Show View.OK_Button")) + waitForObject(":Workbench Window") + test.passes("openView: %s" % viewName) + + + +def getErrorItems(): + ''' Return the Java Array that contains the list of entries in the Error Log ''' + openView("Error Log", True) + errorTree = waitForObject(":Error Log_Tree") + return errorTree.getItems() + +def openAndClearErrorLog(): + ''' Open and clear the Eclipse Error Log. Use getErrorItems() first to find out if there is + anything in them ''' + if getErrorItems().length > 0: + snooze(2) + mouseClick(waitForObject(":Delete Log_ToolItem")) + clickButton(waitForObject(":Confirm Delete.OK_Button")) + +def verifyAndClearErrorLog(): + ''' Verifies that the error log is empty and clears it if not ''' + if getErrorItems().length > 0: + test.fail("Items are in error log view (if this test fails, see console output as -consoleLog is on)") + mouseClick(waitForObject(":Delete Log_ToolItem")) + clickButton(waitForObject(":Confirm Delete.OK_Button")) + else: + # provide a less verbose message when the test just passed + test.passes("No items are in error log view") diff --git a/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py~ b/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py~ new file mode 100644 index 0000000..3f0af65 --- /dev/null +++ b/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py~ @@ -0,0 +1,160 @@ +DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1204_opid23/" +DAWN_SUITE_WORKSPACE="suite_test_single_workspace" +USE_ATTACH=False + +testSettings.logScreenshotOnFail = True +testSettings.logScreenshotOnError = True + +import os, shutil +from datetime import datetime + +def startDAWNSuiteWorkspace(): + + # We start each test in a new workspace + cwd = os.getcwd() + parent_path, test_name = os.path.split(cwd) + suite_name = os.path.basename(parent_path) + workspace = "%s/%s/%s" % (DAWN_WORKSPACE_ROOT, suite_name, DAWN_SUITE_WORKSPACE) + + start = datetime.now() + startApplication("dawn -consoleLog -data %s" % workspace, "", -1, 90) + end = datetime.now() + + test.log("Application took " + str(end-start) + " to start") + + window = waitForObject(":Workbench Window") + window.setMaximized(True) + # Let any setup items continue (e.g. Jython interpreter setup) + # XXX This is a hack because we don't have a better way to determine if + # the GUI is fully started + snooze(1.0) + test.passes("startOrAttachToDAWNOnly: Success") + + try: + #find should fail fast if no welcome screen + findObject(":Welcome_CTabItem") + dismissWelcomScreen() + except: + pass + + +def startOrAttachToDAWNOnly(clean_workspace=True): + if USE_ATTACH: + attachToApplication("attachable_dawn") + else: + # We start each test in a new workspace + cwd = os.getcwd() + parent_path, test_name = os.path.split(cwd) + suite_name = os.path.basename(parent_path) + workparent = os.path.join(DAWN_WORKSPACE_ROOT, suite_name, test_name) + workspace = os.path.join(workparent, 'workspace') + osgi_user_area = os.path.join(workparent, 'osgi_user_area') + osgi_configuration_area = os.path.join(workparent, 'osgi_configuration_area') + if clean_workspace: + try: + shutil.rmtree(workparent) + except OSError: + # Ignore error here, check below + # that directory is gone + pass + snooze(1) + test.verify(not os.path.exists(workparent), "startOrAttachToDAWNOnly: Workspace is clean") + + start = datetime.now() + startApplication("dawn -consoleLog -data %s -user %s -configuration %s -name %s-%s" % + (workspace, osgi_user_area, osgi_configuration_area, suite_name, test_name), "", -1, 90) + end = datetime.now() + test.log("Application took " + str(end-start) + " to start") + + window = waitForObject(":Workbench Window") + window.setMaximized(True) + # Let any setup items continue (e.g. Jython interpreter setup) + # XXX This is a hack because we don't have a better way to determine if + # the GUI is fully started + snooze(1.0) + test.passes("startOrAttachToDAWNOnly: Success") + +def dismissWelcomScreen(): + clickTab(waitForObject(":Welcome_CTabItem"), 10, 10, 0, Button.Button3) + activateItem(waitForObjectItem(":Pop Up Menu", "Close")) + test.passes("dismissWelcomScreen: Success") + +def startOrAttachToDAWN(): + startOrAttachToDAWNOnly() + dismissWelcomScreen() + test.passes("startOrAttachToDAWN: Success") + +def closeDAWN(): + closeWindow(":Workbench Window") + clickButton(waitForObject(":Confirm Exit.OK_Button")) + test.passes("closeDAWN: Success") + +def closeOrDetachFromDAWN(): + if USE_ATTACH: + # nothing to do + pass + else: + closeDAWN() + test.passes("closeOrDetachFromDAWN: Success") + +def openPerspective(perspectiveName): + waitForObject(":Workbench Window") + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Open Perspective")) + activateItem(waitForObjectItem(":Open Perspective_Menu", "Other...")) + mouseClick(waitForObject("{caption='%s' column='0' container=':Open Perspective_Table' type='com.froglogic.squish.swt.TableCell'}" % perspectiveName), 5, 5, 0, Button.Button1) + mouseClick(waitForObject(":Open Perspective.OK_Button")) + # Opening a perspective can (more than most) kick off things in the background + # This background processing can make the workbench window appear fully ready + # but the perspective isn't. Therefore we snooze a few seconds to let everything + # catchup + waitForObject(":Workbench Window") + snooze(3.0) + waitForObject(":Workbench Window") + test.passes("openPerspective: %s" % perspectiveName) + +def openView(viewName, matchOpen=False): + ''' Open the view named viewName. If matchOpen is true, will assume that an open view with + viewName in the title bar of the view is the expected one and only activate it ''' + waitForObject(":Workbench Window") + if matchOpen: + viewRealObjectName = "{caption='%s' type='org.eclipse.swt.custom.CTabItem' window=':Workbench Window'}" % viewName; + if object.exists(viewRealObjectName): + mouseClick(waitForObject(viewRealObjectName)) + test.passes("openView (matchOpen): %s" % viewName) + return + + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Show View")) + activateItem(waitForObjectItem(":Show View_Menu", "Other...")) + type(waitForObject(":Show View_Text"), viewName) + mouseClick(waitForObjectItem(":Show View_Tree", viewName)) + mouseClick(waitForObject(":Show View.OK_Button")) + waitForObject(":Workbench Window") + test.passes("openView: %s" % viewName) + + + +def getErrorItems(): + ''' Return the Java Array that contains the list of entries in the Error Log ''' + openView("Error Log", True) + errorTree = waitForObject(":Error Log_Tree") + return errorTree.getItems() + +def openAndClearErrorLog(): + ''' Open and clear the Eclipse Error Log. Use getErrorItems() first to find out if there is + anything in them ''' + if getErrorItems().length > 0: + snooze(2) + mouseClick(waitForObject(":Delete Log_ToolItem")) + clickButton(waitForObject(":Confirm Delete.OK_Button")) + +def verifyAndClearErrorLog(): + ''' Verifies that the error log is empty and clears it if not ''' + if getErrorItems().length > 0: + test.fail("Items are in error log view (if this test fails, see console output as -consoleLog is on)") + mouseClick(waitForObject(":Delete Log_ToolItem")) + clickButton(waitForObject(":Confirm Delete.OK_Button")) + else: + # provide a less verbose message when the test just passed + test.passes("No items are in error log view") diff --git a/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_slider_utils.py b/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_slider_utils.py new file mode 100644 index 0000000..ccab1b9 --- /dev/null +++ b/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_slider_utils.py @@ -0,0 +1,28 @@ +def check_slider_position(slider, position, tollerence): + range = slider.getMaximum()-slider.getMinimum() + pos = slider.getSelection()-slider.getMinimum() + + proportion = float(pos)/float(range) + print "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", position, proportion, range, pos + test.verify((abs(position - proportion) < tollerence), "Slider not in expected position, expected %f and got %f" %(position, proportion)) + + +def slide_to_propotion(slider, proportion): + # get the bounds of the slider + bounds = slider.bounds + width = bounds.width-30 # minus the width of the slider gizmo + + range = slider.getMaximum()-slider.getMinimum() + start_position = slider.getSelection()-slider.getMinimum() + + scale = float(width)/float(range) + + end_position = width*proportion + end_position = end_position - start_position*scale+15 + + mouseDrag(slider, start_position*scale+15, 5, end_position, 5, Modifier.None, Button.Button1) + + # then check the position to make sure we are in the right place + #check_slider_position(slider,proportion,0.1) + + diff --git a/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/use_case_utils.py b/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/use_case_utils.py new file mode 100644 index 0000000..5763a9d --- /dev/null +++ b/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/use_case_utils.py @@ -0,0 +1,165 @@ +source(findFile("scripts", "dawn_constants.py")) + +import os +import shutil + + +def createProject(projectName, projectType="Workflow Project"): + + activateItem(waitForObjectItem(":_Menu", "File")) + activateItem(waitForObjectItem(":File_Menu", "New")) + activateItem(waitForObjectItem(":New_Menu_2", "Project...")) + type(waitForObject(":_Text"), projectType) + mouseClick(waitForObjectItem(":_Tree", projectType), 59, 10, 0, Button.Button1) + clickButton(waitForObject(":Next >_Button")) + mouseClick(waitForObject(":Project name:_Text"), 48, 3, 0, Button.Button1) + type(waitForObject(":Project name:_Text"), projectName) + clickButton(waitForObject(":Finish_Button_2")) + snooze(1) + +# All these arguments = bad but not sure how to do his as not python expert. +def openExample(frag, project="data", folder="examples", subfolder=None, subsubfolder=None): + + expand(waitForObjectItem(":Project Explorer_Tree", project)) + expand(waitForObjectItem(":Project Explorer_Tree", folder)) + children = object.children(waitForObjectItem(":Project Explorer_Tree", folder)) + + if (subfolder is not None): + expand(waitForObjectItem(":Project Explorer_Tree", subfolder)) + children = object.children(waitForObjectItem(":Project Explorer_Tree", subfolder)) + + if (subsubfolder is not None): + expand(waitForObjectItem(":Project Explorer_Tree", subsubfolder)) + children = object.children(waitForObjectItem(":Project Explorer_Tree", subsubfolder)) + + for child in children: + if frag in child.text: + doubleClick(child, 5, 5, 0, Button.Button1) + +''' +Checks if file can be selected from example data. +Tries to select each directory as the locations are processed. +''' +def checkExample(frag, project="data", folder="examples", subfolder=None, subsubfolder=None): + + expand(waitForObjectItem(":Project Explorer_Tree", project)) + + children = select(folder) + + if (subfolder is not None): + children = select(subfolder) + + if (subsubfolder is not None): + children = select(subsubfolder) + + for child in children: + if frag in child.text: + return True + + return False + +def select(name): + selection = waitForObjectItem(":Project Explorer_Tree", name) + expand(selection) + mouseClick(selection, 5, 5, 0, Button.Button1) + return object.children(waitForObjectItem(":Project Explorer_Tree", name)) + +def openExternalFile(name): + + path = findFile("testdata", name) + path = os.path.abspath(path) + activateItem(waitForObjectItem(":_Menu", "File")) + activateItem(waitForObjectItem(":File_Menu", "Open File...")) + chooseFile(waitForObject(":SWT"), path) + +''' +Adds an external file to the project. +''' +def addExternalFile(fileName, suiteName, testName, project, subdir): + + path = findFile("testdata", fileName) + path = os.path.abspath(path) + + # Path to workspace is something like: + # /scratch/workspace/suite_conversion/tst_image_stack_tiffs/workspace/data + # or + # C:\scratch\workspace\suite_conversion\tst_image_stack_tiffs\workspace\data + shutil.copyfile(path, "/scratch/workspace/"+suiteName+"/"+testName+"/workspace/"+project+"/"+subdir+"/"+fileName) + mouseClick(waitForObjectItem(":Project Explorer_Tree", project)) + type(waitForObject(":Project Explorer_Tree"), "") + + +def chooseSlice(): + + vals = dawn_constants + mouseClick(waitForObjectItem(":Data_Table_2", "1/0"), 8, 12, 0, Button.Button1) + + mouseClick(waitForObject(":Slice as line plots_ToolItem"), 12, 14, 0, Button.Button1) + mouseClick(waitForObjectItem(":Data_Table_3", "0/2"), 13, 24, 0, Button.Button1) + mouseDrag(waitForObject(":Data_Scale"), 18, 22, 20, 0, Modifier.None, Button.Button1) + mouseClick(waitForObject(":XY plotting tools_ToolItem_2"), vals.TOOL_X, vals.TOOL_Y, 0, Button.Button1) + +factory = None + +def getPlottingSystem(name): + + global factory + if factory is not None: + return factory.getPlottingSystem(name) + + activateItem(waitForObjectItem(":_Menu", "Window")) + activateItem(waitForObjectItem(":Window_Menu", "Show View")) + activateItem(waitForObjectItem(":Show View_Menu", "Other...")) + type(waitForObject(":Show View_Text"), "Plotting Systems") + mouseClick(waitForObjectItem(":Show View_Tree", "Plotting Systems")) + clickButton(waitForObject(":Show View.OK_Button")) + waitForObject(":Plotting Systems_CTabItem") + plotButton = waitForObject(":Plotting Systems.Refresh_RefreshButton") + + factoryClass = plotButton.getClass().getClassLoader().loadClass("org.dawnsci.plotting.api.PlottingFactory") + + factory = factoryClass.newInstance() + system = factory.getPlottingSystem(name) + + # Close gallery + snooze(1) + try: + clickTab(waitForObject(":Plotting Systems_CTabItem"), 18, 11, 0, Button.Button1) + mouseClick(waitForObject(":Plotting Systems_CTabCloseBox", 1000)) + except: + print "Could not close gallery" + + snooze(1) + + return system + +def getScreenPosition(plottingSystem,x,y): + outX = None + outY = None + + axes = plottingSystem.getAxes() + + if axes.get(0).isYAxis(): + outY = axes.get(0).getValuePosition(y) + outX = axes.get(1).getValuePosition(x) + elif axes.get(1).isYAxis(): + outY = axes.get(1).getValuePosition(y) + outX = axes.get(0).getValuePosition(x) + + return outX,outY + +def dragSash(sash, dx, dy): + screenPoint = sash.toDisplay(sash.getBounds().width/2,sash.getBounds().height/2) + startDrag(sash, sash.getBounds().width/2, sash.getBounds().height/2); +# mousePress(waitForObject(":_Sash"), 5, 316, Button.Button1); + mouseMove(screenPoint.x - dx, screenPoint.y -dy) + snooze(1) + dropOn(sash, sash.getBounds().width/2, sash.getBounds().height/2,DnD.DropDefault); + +def dragToolToConstWidth(toolTab,sash): + current_width = toolTab.getControl().getBounds().width + + if (current_width < dawn_constants.TOOL_MIN_WIDTH): + dx = dawn_constants.TOOL_MIN_WIDTH - current_width + dragSash(sash, dx, 0) + diff --git a/squishinstall.sh b/squishinstall.sh new file mode 100755 index 0000000..74ddbbf --- /dev/null +++ b/squishinstall.sh @@ -0,0 +1,64 @@ +#!/bin/bash +set -o posix # posix mode so that error setting inherit to subshells +set -eux # error, unset and echo + + +# Options +export AUT_NAME=dawn +export AUT_DIR=/sware/isdd/soft/dawn/beamline/linux_x64/dawn +echo "WORKSPACE", ${WORKSPACE:="./WORKSPACE"} +echo "AUT_NAME=${AUT_NAME}" +echo "DISPLAY", ${DISPLAY:=":0.0"}\ + +export JREDIR=/sware/isdd/soft/java/v7u40/linux_x64/jdk1.7.0_40/jre + + +# Install squish in the Guest, $1 should be guest's JRE directory, $2 the aut name, $3 aut directory +# Sets SQUISHDIR (essentially as return) +function install_squish() +{ + echo "`date +"%a %d/%b/%Y %H:%M:%S"` install_squish start" + local jredir=$1 + local aut_name=$2 + local aut_dir=$3 + local java="${jredir}/bin/java" + + unzip -q -d $WORKSPACE/tempsquish /scisoft/jenkins/Squish_SourceFiles/squish.zip + : Remove version from folder name + mv $WORKSPACE/tempsquish/* $WORKSPACE/squish + rmdir $WORKSPACE/tempsquish + + ## Setup squish + # This is essentially the command that is run by the UI setup in Squish to create the magic squishrt.jar + SQUISHDIR="$WORKSPACE/squish" + local squishserver="$SQUISHDIR/bin/squishserver" + java_version=`"$java" -version 2>&1 | grep 'java version' | sed '-es,[^"]*"\([^"]*\)",\1,'` + echo "`date +"%a %d/%b/%Y %H:%M:%S"` install_squish FixMethod" + "$java" \ + -classpath "${SQUISHDIR}/lib/squishjava.jar:${SQUISHDIR}/lib/bcel.jar" \ + com.froglogic.squish.awt.FixMethod \ + "${jredir}/lib/rt.jar:${SQUISHDIR}/lib/squishjava.jar" \ + "${SQUISHDIR}/lib/squishrt.jar" + + cp "/scisoft/sware_isdd/src/squish/.squish-3-license" ~/.squish-3-license + $squishserver --config setJavaVM "$java" + $squishserver --config setJavaVersion "$java_version" + $squishserver --config setJavaHookMethod "jvm" + $squishserver --config setLibJVM "`find $jredir -name libjvm.so | head -1`" + $squishserver --config addAUT "$aut_name" "$aut_dir" + $squishserver --config setAUTTimeout 120 + echo "`date +"%a %d/%b/%Y %H:%M:%S"` install_squish end" +} + +: Setup Squish +if !([ -d "$WORKSPACE/squish" ]); + then + install_squish $JREDIR $AUT_NAME $AUT_DIR + else + echo "*****************************" + echo "************ALREADY EXIST*****************" + echo "*****************************" +fi + + + diff --git a/squishinstall.sh~ b/squishinstall.sh~ new file mode 100755 index 0000000..9f1122a --- /dev/null +++ b/squishinstall.sh~ @@ -0,0 +1,64 @@ +#!/bin/bash +set -o posix # posix mode so that error setting inherit to subshells +set -eux # error, unset and echo + + +# Options +export AUT_NAME=dawn +export AUT_DIR=/sware/isdd/soft/dawn/beamline/linux_x64/dawn +echo "WORKSPACE", ${WORKSPACE:="./WORKSPACE"} +echo "AUT_NAME=${AUT_NAME}" +echo "DISPLAY", ${DISPLAY:=":0.0"}\ + +export JREDIR=/sware/isdd/soft/java/v7u40/linux_x64/jdk1.7.0_40/jre + + +# Install squish in the Guest, $1 should be guest's JRE directory, $2 the aut name, $3 aut directory +# Sets SQUISHDIR (essentially as return) +function install_squish() +{ + echo "`date +"%a %d/%b/%Y %H:%M:%S"` install_squish start" + local jredir=$1 + local aut_name=$2 + local aut_dir=$3 + local java="${jredir}/bin/java" + + unzip -q -d $WORKSPACE/tempsquish $WORKSPACE/squish.zip + : Remove version from folder name + mv $WORKSPACE/tempsquish/* $WORKSPACE/squish + rmdir $WORKSPACE/tempsquish + + ## Setup squish + # This is essentially the command that is run by the UI setup in Squish to create the magic squishrt.jar + SQUISHDIR="$WORKSPACE/squish" + local squishserver="$SQUISHDIR/bin/squishserver" + java_version=`"$java" -version 2>&1 | grep 'java version' | sed '-es,[^"]*"\([^"]*\)",\1,'` + echo "`date +"%a %d/%b/%Y %H:%M:%S"` install_squish FixMethod" + "$java" \ + -classpath "${SQUISHDIR}/lib/squishjava.jar:${SQUISHDIR}/lib/bcel.jar" \ + com.froglogic.squish.awt.FixMethod \ + "${jredir}/lib/rt.jar:${SQUISHDIR}/lib/squishjava.jar" \ + "${SQUISHDIR}/lib/squishrt.jar" + + cp "/scisoft/sware_isdd/src/squish/.squish-3-license" ~/.squish-3-license + $squishserver --config setJavaVM "$java" + $squishserver --config setJavaVersion "$java_version" + $squishserver --config setJavaHookMethod "jvm" + $squishserver --config setLibJVM "`find $jredir -name libjvm.so | head -1`" + $squishserver --config addAUT "$aut_name" "$aut_dir" + $squishserver --config setAUTTimeout 120 + echo "`date +"%a %d/%b/%Y %H:%M:%S"` install_squish end" +} + +: Setup Squish +if !([ -d "$WORKSPACE/squish" ]); + then + install_squish $JREDIR $AUT_NAME $AUT_DIR + else + echo "*****************************" + echo "************ALREADY EXIST*****************" + echo "*****************************" +fi + + + From 69200d394d1c53fee44dd9e5be33427ae92bef6a Mon Sep 17 00:00:00 2001 From: Operator account ID23 Date: Wed, 23 Oct 2013 15:32:20 +0200 Subject: [PATCH 09/17] make dawn_workspace dir --- dawn_workspace/test | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 dawn_workspace/test diff --git a/dawn_workspace/test b/dawn_workspace/test new file mode 100644 index 0000000..e69de29 From d66608b4c4dbb4b02f4bbc90e348f70d2290c682 Mon Sep 17 00:00:00 2001 From: Operator account ID23 Date: Fri, 15 Nov 2013 13:53:30 +0100 Subject: [PATCH 10/17] -add unit test. -re-factoring the folder. --- dawn_workspace/test | 0 .../global_script_esrf/dawn_global_startup.py | 2 +- .../dawn_global_startup.py~ | 7 +- .../squishinstall.sh | 0 eu.esrf.test/src/scriptFunction | 36 + eu.esrf.test/src/scriptFunction~ | 37 + eu.esrf.test/src/script_jenkins | 38 +- eu.esrf.test/src/script_jenkins~ | 14 +- .../src/shunit2-2.1.6/doc/CHANGES-2.1.txt | 214 ++++ eu.esrf.test/src/shunit2-2.1.6/doc/LGPL-2.1 | 504 ++++++++ .../src/shunit2-2.1.6/doc/README.html | 540 +++++++++ eu.esrf.test/src/shunit2-2.1.6/doc/README.txt | 214 ++++ .../shunit2-2.1.6/doc/RELEASE_NOTES-2.1.0.txt | 104 ++ .../shunit2-2.1.6/doc/RELEASE_NOTES-2.1.1.txt | 88 ++ .../shunit2-2.1.6/doc/RELEASE_NOTES-2.1.2.txt | 83 ++ .../shunit2-2.1.6/doc/RELEASE_NOTES-2.1.3.txt | 84 ++ .../shunit2-2.1.6/doc/RELEASE_NOTES-2.1.4.txt | 100 ++ .../shunit2-2.1.6/doc/RELEASE_NOTES-2.1.5.txt | 128 ++ .../shunit2-2.1.6/doc/RELEASE_NOTES-2.1.6.txt | 112 ++ eu.esrf.test/src/shunit2-2.1.6/doc/TODO.txt | 13 + .../shunit2-2.1.6/doc/coding_standards.txt | 74 ++ .../src/shunit2-2.1.6/doc/contributors.txt | 14 + .../src/shunit2-2.1.6/doc/design_doc.txt | 34 + .../src/shunit2-2.1.6/doc/rst2html.css | 292 +++++ .../src/shunit2-2.1.6/doc/shunit2.html | 880 ++++++++++++++ .../src/shunit2-2.1.6/doc/shunit2.txt | 562 +++++++++ .../shunit2-2.1.6/examples/equality_test.sh | 10 + .../src/shunit2-2.1.6/examples/lineno_test.sh | 16 + .../src/shunit2-2.1.6/examples/math.inc | 17 + .../src/shunit2-2.1.6/examples/math_test.sh | 27 + .../src/shunit2-2.1.6/examples/mkdir_test.sh | 89 ++ .../src/shunit2-2.1.6/examples/party_test.sh | 17 + eu.esrf.test/src/shunit2-2.1.6/lib/shflags | 1011 ++++++++++++++++ eu.esrf.test/src/shunit2-2.1.6/lib/shlib | 39 + eu.esrf.test/src/shunit2-2.1.6/lib/versions | 227 ++++ eu.esrf.test/src/shunit2-2.1.6/src/shunit2 | 1048 +++++++++++++++++ .../src/shunit2-2.1.6/src/shunit2_test.sh | 124 ++ .../shunit2-2.1.6/src/shunit2_test_asserts.sh | 209 ++++ .../src/shunit2_test_failures.sh | 89 ++ .../shunit2-2.1.6/src/shunit2_test_helpers | 177 +++ .../shunit2-2.1.6/src/shunit2_test_macros.sh | 249 ++++ .../shunit2-2.1.6/src/shunit2_test_misc.sh | 165 +++ .../src/shunit2_test_standalone.sh | 41 + eu.esrf.test/src/test_variables.py | 4 +- eu.esrf.test/src/test_variables.py~ | 5 +- .../unitest/.nfs00000000f3a989da00000106 | 38 + eu.esrf.test/unitest/unitest.sh | 37 + eu.esrf.test/unitest/unitest.sh~ | 37 + .../shared/scripts/dawn_global_startup.py | 7 +- .../shared/scripts/dawn_global_startup.py~ | 7 +- squishinstall.sh~ | 64 - 51 files changed, 7816 insertions(+), 112 deletions(-) delete mode 100644 dawn_workspace/test rename squishinstall.sh => eu.esrf.test/squishinstall.sh (100%) create mode 100755 eu.esrf.test/src/scriptFunction create mode 100755 eu.esrf.test/src/scriptFunction~ create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/CHANGES-2.1.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/LGPL-2.1 create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/README.html create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/README.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.0.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.1.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.2.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.3.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.4.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.5.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.6.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/TODO.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/coding_standards.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/contributors.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/design_doc.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/rst2html.css create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/shunit2.html create mode 100755 eu.esrf.test/src/shunit2-2.1.6/doc/shunit2.txt create mode 100755 eu.esrf.test/src/shunit2-2.1.6/examples/equality_test.sh create mode 100755 eu.esrf.test/src/shunit2-2.1.6/examples/lineno_test.sh create mode 100755 eu.esrf.test/src/shunit2-2.1.6/examples/math.inc create mode 100755 eu.esrf.test/src/shunit2-2.1.6/examples/math_test.sh create mode 100755 eu.esrf.test/src/shunit2-2.1.6/examples/mkdir_test.sh create mode 100755 eu.esrf.test/src/shunit2-2.1.6/examples/party_test.sh create mode 100755 eu.esrf.test/src/shunit2-2.1.6/lib/shflags create mode 100755 eu.esrf.test/src/shunit2-2.1.6/lib/shlib create mode 100755 eu.esrf.test/src/shunit2-2.1.6/lib/versions create mode 100755 eu.esrf.test/src/shunit2-2.1.6/src/shunit2 create mode 100755 eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test.sh create mode 100755 eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_asserts.sh create mode 100755 eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_failures.sh create mode 100755 eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_helpers create mode 100755 eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_macros.sh create mode 100755 eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_misc.sh create mode 100755 eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_standalone.sh create mode 100755 eu.esrf.test/unitest/.nfs00000000f3a989da00000106 create mode 100755 eu.esrf.test/unitest/unitest.sh create mode 100755 eu.esrf.test/unitest/unitest.sh~ delete mode 100755 squishinstall.sh~ diff --git a/dawn_workspace/test b/dawn_workspace/test deleted file mode 100644 index e69de29..0000000 diff --git a/eu.esrf.test/global_script_esrf/dawn_global_startup.py b/eu.esrf.test/global_script_esrf/dawn_global_startup.py index a546bcd..b8114de 100644 --- a/eu.esrf.test/global_script_esrf/dawn_global_startup.py +++ b/eu.esrf.test/global_script_esrf/dawn_global_startup.py @@ -1,6 +1,6 @@ import os, shutil from datetime import datetime -DAWN_WORKSPACE_ROOT=os.path.join(os.environ['WORKSPACE'],"dawn_workspace") +DAWN_WORKSPACE_ROOT=os.path.join(os.environ['WORKSPACE'],"eu.esrf.test/dawn_workspace") DAWN_SUITE_WORKSPACE="suite_test_single_workspace" USE_ATTACH=False diff --git a/eu.esrf.test/global_script_esrf/dawn_global_startup.py~ b/eu.esrf.test/global_script_esrf/dawn_global_startup.py~ index 30c7ddf..a546bcd 100644 --- a/eu.esrf.test/global_script_esrf/dawn_global_startup.py~ +++ b/eu.esrf.test/global_script_esrf/dawn_global_startup.py~ @@ -1,12 +1,13 @@ -DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1204_opid23/dawn_workspace" +import os, shutil +from datetime import datetime +DAWN_WORKSPACE_ROOT=os.path.join(os.environ['WORKSPACE'],"dawn_workspace") DAWN_SUITE_WORKSPACE="suite_test_single_workspace" USE_ATTACH=False testSettings.logScreenshotOnFail = True testSettings.logScreenshotOnError = True -import os, shutil -from datetime import datetime + def startDAWNSuiteWorkspace(): diff --git a/squishinstall.sh b/eu.esrf.test/squishinstall.sh similarity index 100% rename from squishinstall.sh rename to eu.esrf.test/squishinstall.sh diff --git a/eu.esrf.test/src/scriptFunction b/eu.esrf.test/src/scriptFunction new file mode 100755 index 0000000..d378c8a --- /dev/null +++ b/eu.esrf.test/src/scriptFunction @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +xvfbFound=false +foundDisplay=false +i=0 +x=0 +typeFile=".X*-lock" #pattern to only select Xvfb tmp file +findDisplayNumber(){ +for inode in $(ls $1/$typeFile) +do + owner=$(ls -al $inode | grep -v grep | awk '{ print $3; }') + array[$i]=$(echo "$inode" | tr -d [:alpha:] | tr -d [:punct:]) #make a list of all the display number for, in another case find a free number + if [ "$USER" = "$owner" ];then + xvfbFound=true + var=$(echo "$inode" | tr -d [:alpha:] | tr -d [:punct:]) + echo $var #return the availaible display for the logged user + break; + fi + let i++ +done +if [ $xvfbFound=="false" ]; then #if no display found + var1=${#array[@]} + for (( c=0; c/$WORKSPACE/serverlog sleep 1 -/$WORKSPACE/squish/bin/squishrunner --testsuite $WORKSPACE/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/$1_squishlog +#run the test (with $1 corresponding at the testsuite and $2 corresponding at the testcase) +/$WORKSPACE/squish/bin/squishrunner --testsuite $WORKSPACE/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/#$1_squishlog var1=$(ps -aef |grep squishserver | grep -v grep | awk '{ print $2; }' | head -1) kill -9 $var1 var2=$(ps -aef |grep Xvfb | grep -v grep | awk '{ print $2; }' | head -1) diff --git a/eu.esrf.test/src/script_jenkins~ b/eu.esrf.test/src/script_jenkins~ index f56a58f..7d3d76d 100755 --- a/eu.esrf.test/src/script_jenkins~ +++ b/eu.esrf.test/src/script_jenkins~ @@ -1,13 +1,19 @@ -#!/bin/sh -Xvfb :8 -screen 0 1024x768x16 & -export DISPLAY=:8 +#!/usr/bin/env bash + +source scriptFunction +var=$(findDisplayNumber /tmp/) #the argument is the path to yours temp files. + + +Xvfb :$var -screen 0 1024x768x16 & #create a display +export DISPLAY=:$var export PATH=/sware/isdd/soft/java/v7u17/linux_x64/jdk1.7.0_40/bin:$PATH cd /$WORKSPACE/squish/bin/ ./squishserver & >/$WORKSPACE/serverlog sleep 1 -/$WORKSPACE/squish/bin/squishrunner --testsuite $WORKSPACE/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/$1_squishlog +/$WORKSPACE/squish/bin/squishrunner --testsuite $WORKSPACE/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/#$1_squishlog var1=$(ps -aef |grep squishserver | grep -v grep | awk '{ print $2; }' | head -1) kill -9 $var1 var2=$(ps -aef |grep Xvfb | grep -v grep | awk '{ print $2; }' | head -1) kill -9 $var2 + diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/CHANGES-2.1.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/CHANGES-2.1.txt new file mode 100755 index 0000000..14764b1 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/CHANGES-2.1.txt @@ -0,0 +1,214 @@ +Changes in shUnit2 2.1.X +======================== + +Changes with 2.1.6 +------------------ + +Removed all references to the DocBook documentation. + +Simplified the 'src' structure. + +Fixed error message in fail() that stated wrong number of required arguments. + +Updated lib/versions. + +Fixed bug in _shunit_mktempDir() where a failure occurred when the 'od' command was not present in /usr/bin. + +Renamed shunit_tmpDir variable to SHUNIT_TMPDIR to closer match the standard +TMPDIR variable. + +Added support for calling shunit2 as an executable, in addition to the existing +method of sourcing it in as a library. This allows users to keep tests working +despite the location of the shunit2 executable being different for each OS +distribution. + +Issue #14: Improved handling of some strange chars (e.g. single and double +quotes) in messages. + +Issue# 27: Fixed error message for assertSame(). + +Issue# 25: Added check and error message to user when phantom functions are +written to a partition mounted with noexec. + +Issue# 11: Added support for defining functions like 'function someFunction()'. + + +Changes with 2.1.5 +------------------ + +Issue# 1: Fixed bug pointed out by R Bernstein in the trap code where certain +types of exit conditions did not generate the ending report. + +Issue# 2: Added assertNotEquals() assert. + +Issue# 3: Moved check for unset variables out of shUnit2 into the unit tests. +Testing poorly written software blows up if this check is in, but it is only +interesting for shUnit2 itself. Added shunit_test_output.sh unit test for this. +Some shells still do not catch such errors properly (e.g. Bourne shell and BASH +2.x). + +Added new custom assert in test_helpers to check for output to STDOUT, and none +to STDERR. + +Replaced fatal message in the temp directory creation with a _shunit_fatal() +function call. + +Fixed test_output unit test so it works now that the 'set -u' stuff was removed +for Issue# 3. + +Flushed out the coding standards in the README.txt a bit more, and brought the +shunit2 code up to par with the documented standards. + +Issue# 4: Completely changed the reporting output to be a closer match for +JUnit and PyUnit. As a result, tests are counted separately from assertions. + +Provide public shunit_tmpDir variable that can be used by unit test scripts that +need automated and guaranteed cleanup. + +Issue# 7: Fixed duplicated printing of messages passed to asserts. + +Per code review, fixed wording of failSame() and failNotSame() messages. + +Replaced version_info.sh with versions library and made appropriate changes in +other scripts to use it. + +Added gen_test_results.sh to make releases easier. + +Fixed bugs in shlib_relToAbsPath() in shlib. + +Converted DocBook documentation to reStructuredText for easier maintenance. The +DocBook documentation is now considered obsolete, and will be removed in a +future release. + +Issue# 5: Fixed the documentation around the usage of failures. + +Issue# 9: Added unit tests and updated documentation to demonstrate the +requirement of quoting values twice when macros are used. This is due to how +shell parses arguments. + +When an invalid number of arguments is passed to a function, the invalid number +is returned to the user so they are more aware of what the cause might be. + + +Changes with 2.1.4 +------------------ + +Removed the _shunit_functionExists() function as it was dead code. + +Fixed zsh version number check in version_info. + +Fixed bug in last resort temporary directory creation. + +Fixed off-by-one in exit value for scripts caught by the trap handler. + +Added argument count error checking to all functions. + +Added mkdir_test.sh example. + +Moved src/test into src/shell to better match structure used with shFlags. + +Fixed problem where null values were not handled properly under ksh. + +Added support for outputting line numbers as part of assert messages. + +Started documenting the coding standards, and changed some variable names as a +result. + +Improved zsh version and option checks. + +Renamed the __SHUNIT_VERSION variable to SHUNIT_VERSION. + + +Changes with 2.1.3 +------------------ + +Added some explicit variable defaults, even though the variables are set, as +they sometimes behave strange when the script is canceled. + +Additional workarounds for zsh compatibility. + +shUnit2 now exits with a non-zero exit code if any of the tests failed. This was +done for automated testing frameworks. Tests that were skipped are not +considered failures, and do not affect the exit code. + +Changed detection of STDERR output in unit tests. + + +Changes with 2.1.2 +------------------ + +Unset additional variables that were missed. + +Added checks and workarounds to improve zsh compatibility. + +Added some argument count checks ``assertEquals()``, ``assertNull()``, and +``assertSame()`` + + +Changes with 2.1.1 +------------------ + +Fixed bug where ``fail()`` was not honoring skipping. + +Fixed problem with ``docs-docbook-prep`` target that prevented it from working. +(Thanks to Bryan Larsen for pointing this out.) + +Changed the test in ``assertFalse()`` so that any non-zero value registers as +false. (Credits to Bryan Larsen) + +Major fiddling to bring more in line with `JUnit `. Asserts +give better output when no message is given, and failures now just fail. + +It was pointed out that the simple 'failed' message for a failed assert was not +only insufficient, it was nonstandard (when compared to JUnit) and didn't +provide the user with an expected vs actual result. The code was revised +somewhat to bring closer into alignment with JUnit (v4.3.1 specifically) so +that it feels more "normal". (Credits to Richard Jensen) + +As part of the JUnit realignment, it was noticed that fail*() functions in +JUnit don't actually do any comparisons themselves. They only generate a +failure message. Updated the code to match. + +Added self-testing unit tests. Kinda horkey, but they did find bugs during the +JUnit realignment. + +Fixed the code for returning from asserts as the return was being called before +the unsetting of variables occurred. (Credits to Mathias Goldau) + +The assert(True|False)() functions now accept an integer value for a +conditional test. A value of '0' is considered 'true', while any non-zero value +is considered 'false'. + +All public functions now fill use default values to work properly with the '-x' +shell debugging flag. + +Fixed the method of percent calculation for the report to get achieve better +accuracy. + + +Changes with 2.1.0 (since 2.0.1) +-------------------------------- + +This release is a branch of the 2.0.1 release. + +Moving to `reStructured Text `_ for +the documentation. + +Fixed problem with ``fail()``. The failure message was not properly printed. + +Fixed the ``Makefile`` so that the DocBook XML and XSLT files would be +downloaded before parsing can continue. + +Renamed the internal ``__SHUNIT_TRUE`` and ``__SHUNIT_FALSE`` variables to +``SHUNIT_TRUE`` and ``SHUNIT_FALSE`` so that unit tests can "use" them. + +Added support for test "skipping". If skipping is turned on with the +``startSkip()`` function, ``assert`` and ``fail`` functions will return +immediately, and the skip will be recorded. + +The report output format was changed to include the percentage for each test +result, rather than just those successful. + + +.. $Revision: 326 $ +.. vim:fileencoding=latin1:ft=text:spell:tw=80 diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/LGPL-2.1 b/eu.esrf.test/src/shunit2-2.1.6/doc/LGPL-2.1 new file mode 100755 index 0000000..b1e3f5a --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/LGPL-2.1 @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/README.html b/eu.esrf.test/src/shunit2-2.1.6/doc/README.html new file mode 100755 index 0000000..b7b4672 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/README.html @@ -0,0 +1,540 @@ + + + + + + +shUnit2 2.1.x README + + + +

+ + diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/README.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/README.txt new file mode 100755 index 0000000..2d8d534 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/README.txt @@ -0,0 +1,214 @@ +==================== +shUnit2 2.1.x README +==================== + +code.google.com +=============== + +This project is stored on code.google.com as http://code.google.com/p/shunit2/. +All releases as of 2.1.4 and full source are available there. Documentation is +included as part of the source and each release. Source code is stored in +Subversion and can be accessed using the following information. + +Browse the code in a web browser: + +- http://code.google.com/p/shunit2/source/browse +- svn > trunk > source > 2.1 + +Check out the code locally :: + + $ svn checkout http://shunit2.googlecode.com/svn/trunk/ shflags-read-only + + +SourceForge +=========== + +DEPRECATED + +This project is stored on SourceForge as http://sf.net/projects/shunit2. The +source code is stored in Subversion and can be accessed using the following +information. + +Check out the code locally :: + + $ svn co https://shunit2.svn.sourceforge.net/svnroot/shunit2/trunk/source/2.1 shunit2 + +Browse the code in a web browser: + +- http://shunit2.svn.sourceforge.net/viewvc/shunit2/trunk/source/2.1/ +- http://shunit2.svn.sourceforge.net/svnroot/shunit2/trunk/source/2.1/ + + +Making a release +================ + +For these steps, it is assumed we are working with release 2.0.0. + +Steps: + +- write release notes +- update version +- finish changelog +- check all the code in +- tag the release +- export the release +- create tarball +- md5sum the tarball and sign with gpg +- update website +- post to SourceForge and Freshmeat + +Write Release Notes +------------------- + +This should be pretty self explanatory. Use one of the release notes from a +previous release as an example. + +The versions of the various platforms and shells are included when the +master unit test script is run, or when ``bin/gen_test_results.sh`` is +used. To determine the versions of the installed shells by hand, use the +``lib/versions`` script. + +Alternatively, do the following: + ++-------+---------+-----------------------------------------------------------+ +| Shell | OS | Notes | ++=======+=========+===========================================================+ +| bash | | ``$ bash --version`` | ++-------+---------+-----------------------------------------------------------+ +| dash | Linux | ``$ dpkg -l |grep dash`` | ++-------+---------+-----------------------------------------------------------+ +| ksh | | ``$ ksh --version`` | +| | | -or- | +| | | ``$ echo 'echo $KSH_VERSION' |ksh`` | +| +---------+-----------------------------------------------------------+ +| | Cygwin | see pdksh | +| +---------+-----------------------------------------------------------+ +| | Solaris | ``$ strings /usr/bin/ksh |grep 'Version'`` | ++-------+---------+-----------------------------------------------------------+ +| pdksh | | ``$ strings /bin/pdksh |grep 'PD KSH'`` | +| +---------+-----------------------------------------------------------+ +| | Cygwin | look in the downloaded Cygwin directory | ++-------+---------+-----------------------------------------------------------+ +| sh | Solaris | not possible | ++-------+---------+-----------------------------------------------------------+ +| zsh | | ``$ zsh --version`` | ++-------+---------+-----------------------------------------------------------+ + +Update Version +-------------- + +Edit ``src/shell/shunit2`` and change the version number in the comment, as well +as in the ``SHUNIT_VERSION`` variable. + +Finish Documentation +-------------------- + +Make sure that any remaining changes get put into the ``CHANGES-X.X.txt`` file. + +Finish writing the ``RELEASE_NOTES-X.X.X.txt``. If necessary, run it +through the **fmt** command to make it pretty (hopefully it is already). :: + + $ fmt -w 80 RELEASE_NOTES-2.0.0.txt >RELEASE_NOTES-2.0.0.txt.new + $ mv RELEASE_NOTES-2.0.0.txt.new RELEASE_NOTES-2.0.0.txt + +We want to have an up-to-date version of the documentation in the release, so +we'd better build it. :: + + $ pwd + .../shunit2/source/2.1 + $ cd doc + $ RST2HTML_OPTS='--stylesheet-path=rst2html.css' + $ rst2html ${RST2HTML_OPTS} shunit2.txt >shunit2.html + $ rst2html ${RST2HTML_OPTS} README.txt >README.html + +Check In All the Code +--------------------- + +This step is pretty self-explanatory :: + + $ pwd + .../shunit2/source/2.0 + $ svn ci -m "finalizing release" + +Tag the Release +--------------- +:: + + $ pwd + .../shunit2/source + $ ls + 2.0 2.1 + $ svn cp -m "Release 2.0.0" 2.0 https://shunit2.googlecode.com/svn/tags/source/2.0.0 + +Export the Release +------------------ +:: + + $ pwd + .../shunit2/builds + $ svn export https://shunit2.googlecode.com/svn/tags/source/2.0.0 shunit2-2.0.0 + +Create Tarball +-------------- +:: + + $ tar cfz ../releases/shunit2-2.0.0.tgz shunit2-2.0.0 + +Sign the Tarball with gpg +------------------------- +:: + + $ cd ../releases + $ gpg --default-key kate.ward@forestent.com --detach-sign shunit2-2.0.0.tgz + +Update Website +-------------- + +Again, pretty self-explanatory. Make sure to copy the GPG signature file. Once +that is done, make sure to tag the website so we can go back in time if needed. +:: + + $ pwd + .../shunit2 + $ ls + source website + $ svn cp -m "Release 2.0.0" \ + website https://shunit2.googlecode.com/svn/tags/website/20060916 + +Now, update the website. It too is held in Subversion, so **ssh** into the web +server and use ``svn up`` to grab the latest version. + +Post to code.google.com and Freshmeat +------------------------------------- + +- http://code.google.com/p/shunit2/ +- http://freshmeat.net/ + + +Related Documentation +===================== + +Docbook: + http://www.docbook.org/ + +Docbook XML + docbook-xml-4.4.zip: + http://www.docbook.org/xml/4.4/docbook-xml-4.4.zip + http://www.oasis-open.org/docbook/xml/4.4/docbook-xml-4.4.zip + docbook-xml-4.5.zip: + http://www.docbook.org/xml/4.5/docbook-xml-4.5.zip +Docbook XSL + docbook-xsl-1.71.0.tar.bz2: + http://prdownloads.sourceforge.net/docbook/docbook-xsl-1.71.0.tar.bz2?download + docbook-xsl-1.71.1.tar.bz2: + http://downloads.sourceforge.net/docbook/docbook-xsl-1.71.1.tar.bz2?use_mirror=puzzle +JUnit: + http://www.junit.org/ +reStructuredText: + http://docutils.sourceforge.net/docs/user/rst/quickstart.html + +.. generate HTML using rst2html from Docutils of +.. http://docutils.sourceforge.net/ +.. +.. vim:fileencoding=latin1:ft=rst:spell:tw=80 +.. $Revision: 310 $ diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.0.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.0.txt new file mode 100755 index 0000000..9aba387 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.0.txt @@ -0,0 +1,104 @@ +Release Notes for shUnit2 2.1.0 +=============================== + +This release was branched from shUnit2 2.0.1. It mostly adds new functionality, +but there are couple of bugs fixed from the previous release. + +See the ``CHANGES-2.1.rst`` file for a full list of changes. + + +Tested Platforms +---------------- + +This list of platforms comes from the latest version of log4sh as shUnit2 is +used in the testing of log4sh on each of these platforms. + +Cygwin + +- bash 3.2.9(10) +- pdksh 5.2.14 + +Linux + +- bash 3.1.17(1), 3.2.10(1) +- dash 0.5.3 +- ksh 1993-12-28 +- pdksh 5.2.14 +- zsh 4.3.2 (does not work) + +Mac OS X 10.4.8 (Darwin 8.8) + +- bash 2.05b.0(1) +- ksh 1993-12-28 + +Solaris 8 U3 (x86) + +- /bin/sh +- bash 2.03.0(1) +- ksh M-11/16/88i + +Solaris 10 U2 (sparc) + +- /bin/sh +- bash 3.00.16(1) +- ksh M-11/16/88i + +Solaris 10 U2 (x86) + +- /bin/sh +- bash 3.00.16(1) +- ksh M-11/16/88i + + +New Features +------------ + +Test skipping + + Support added for test "skipping". A skip mode can be enabled so that + subsequent ``assert`` and ``fail`` functions that are called will be recorded + as "skipped" rather than as "passed" or "failed". This functionality can be + used such that when a set of tests makes sense on one platform but not on + another, they can be effectively disabled without altering the total number + of tests. + + One example might be when something is supported under ``bash``, but not + under a standard Bourne shell. + + New functions: ``startSkipping()``, ``endSkipping``, ``isSkipping`` + + +Changes and Enhancements +------------------------ + +Moving to the use of `reStructured Text +`_ for documentation. It is easy to +read and edit in textual form, but converts nicely to HTML. + +The report format has changed. Rather than including a simple "success" +percentage at the end, a percentage is given for each type of test. + + +Bug Fixes +--------- + +The ``fail()`` function did not output the optional failure message. + +Fixed the ``Makefile`` so that the DocBook XML and XSLT files would be +downloaded before documentation parsing will continue. + + +Deprecated Features +------------------- + +None. + + +Known Bugs and Issues +--------------------- + +None. + + +.. $Revision: 273 $ +.. vim:fileencoding=latin1:spell:syntax=rst:textwidth=80 diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.1.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.1.txt new file mode 100755 index 0000000..4c61005 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.1.txt @@ -0,0 +1,88 @@ +Release Notes for shUnit2 2.1.1 +=============================== + +This is mainly a bug fix release, but it also incorporates a realignment with +the JUnit 4 code. Asserts now provide better failure messages, and the failure +functions no longer perform tests. + +See the ``CHANGES-2.1.txt`` file for a full list of changes. + + +Tested Platforms +---------------- + +This list of platforms comes from the latest version of log4sh as shUnit2 is +used in the testing of log4sh on each of these platforms. + +Cygwin + +- bash 3.2.15(13) +- pdksh 5.2.14 + +Linux + +- bash 3.1.17(1), 3.2.10(1) +- dash 0.5.3 +- ksh 1993-12-28 +- pdksh 5.2.14 +- zsh 4.3.2 (does not work) + +Mac OS X 10.4.9 (Darwin 8.9.1) + +- bash 2.05b.0(1) +- ksh 1993-12-28 + +Solaris 8 U3 (x86) + +- /bin/sh +- bash 2.03.0(1) +- ksh M-11/16/88i + +Solaris 10 U2 (sparc, x86) + +- /bin/sh +- bash 3.00.16(1) +- ksh M-11/16/88i + + +New Features +------------ + +None. + + +Changes and Enhancements +------------------------ + +The internal test in ``assertFalse()`` now accepts any non-zero value as false. + +The ``assertTrue()`` and ``assertFalse()`` functions now accept an integer value +for a conditional test. A value of '0' is considered 'true', while any non-zero +value is considered 'false'. + +Self-testing unit tests were added. + + +Bug Fixes +--------- + +The ``fail()`` assert now honors skipping. + +The ``docs-docbook-prep`` target now works properly. + +All asserts now properly unset their variables. + + +Deprecated Features +------------------- + +None. + + +Known Bugs and Issues +--------------------- + +Functions do not properly test for an invalid number of arguments. + + +.. vim:fileencoding=latin1:ft=rst:spell:textwidth=80 diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.2.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.2.txt new file mode 100755 index 0000000..5492984 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.2.txt @@ -0,0 +1,83 @@ +Release Notes for shUnit2 2.1.2 +=============================== + +This release adds initial support for the zsh shell. Due to some differences +with this shell as compared with others, some special checks have been added, +and there are some extra requirements necessary when this shell is to be used. + +To use zsh with shUnit2, the following two requirements must be met: +* The ``shwordsplit`` option must be set. +* The ``function_argzero`` option must be unset. + +Please read the Shell Errata section of the documentation for guidance on how +to meet these requirements. + + +See the ``CHANGES-2.1.txt`` file for a full list of changes. + + +Tested Platforms +---------------- + +This list of platforms comes from the latest version of log4sh as shUnit2 is +used in the testing of log4sh on each of these platforms. + +Linux + +- bash 3.1.17(1), 3.2.25(1) +- dash 0.5.4 +- ksh 1993-12-28 +- pdksh 5.2.14 +- zsh 4.2.5, 4.3.4 + +Mac OS X 10.4.11 (Darwin 8.11.1) + +- bash 2.05b.0(1) +- ksh 1993-12-28 +- zsh 4.2.3 + +Solaris 10 U3 (x86) + +- /bin/sh +- bash 3.00.16(1) +- ksh M-11/16/88i +- zsh 4.2.1 + + +New Features +------------ + +Support for the zsh shell. + + +Changes and Enhancements +------------------------ + +Added some argument count checks. + + +Bug Fixes +--------- + +None. + + +Deprecated Features +------------------- + +None. + + +Known Bugs and Issues +--------------------- + +Functions do not properly test for an invalid number of arguments. + +ksh and pdksh do not pass null arguments (i.e. empty strings as '') properly, +and as such checks do not work properly. + +zsh requires the ``shwordsplit`` option to be set, and the ``function_argzero`` +option to be unset for proper operation. + + +.. vim:fileencoding=latin1:ft=rst:spell:textwidth=80 diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.3.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.3.txt new file mode 100755 index 0000000..7d1c9f6 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.3.txt @@ -0,0 +1,84 @@ +Release Notes for shUnit2 2.1.3 +=============================== + +This release is minor feature release. It improves support for zsh (although it +still isn't what it could be) and adds automated testing framework support by +returning a non-zero exit when tests fail. + +To use zsh with shUnit2, the following two requirements must be met: +* The ``shwordsplit`` option must be set. +* The ``function_argzero`` option must be unset. + +Please read the Shell Errata section of the documentation for guidance on how +to meet these requirements. + +See the ``CHANGES-2.1.txt`` file for a full list of changes. + + +Tested Platforms +---------------- + +Cygwin + +- bash 3.2.33(18) +- pdksh 5.2.14 + +Linux + +- bash 3.2.33(1) +- dash 0.5.4 +- ksh 1993-12-28 +- pdksh 5.2.14 +- zsh 4.3.4 + +Mac OS X 10.5.2 (Darwin 9.2.2) + +- bash 3.2.17(1) +- ksh 1993-12-28 +- zsh 4.3.4 + +Solaris 11 x86 (Nevada 77) + +- /bin/sh +- bash 3.2.25(1) +- ksh M-11/16/88i +- zsh 4.3.4 + + +New Features +------------ + +None. + + +Changes and Enhancements +------------------------ + +Support for automated testing frameworks. + + +Bug Fixes +--------- + +Fixed some issues with zsh support. + + +Deprecated Features +------------------- + +None. + + +Known Bugs and Issues +--------------------- + +Functions do not properly test for an invalid number of arguments. + +ksh and pdksh do not pass null arguments (i.e. empty strings as '') properly, +and as such checks do not work properly. + +zsh requires the ``shwordsplit`` option to be set, and the ``function_argzero`` +option to be unset for proper operation. + + +.. vim:fileencoding=latin1:ft=rst:spell:textwidth=80 diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.4.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.4.txt new file mode 100755 index 0000000..007b5c3 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.4.txt @@ -0,0 +1,100 @@ +Release Notes for shUnit2 2.1.4 +=============================== + +This release contains lots of bug fixes and changes. Mostly, it fixes zsh +support in zsh 3.0, and the handling of null values in ksh. + +To use zsh with shUnit2, the following requirement must be met: + +- The ``shwordsplit`` option must be set. + +Please read the Shell Errata section of the documentation for guidance on how +to meet these requirements. + +See the ``CHANGES-2.1.txt`` file for a full list of changes. + + +Tested Platforms +---------------- + +Cygwin + +- bash 3.2.39(19) +- pdksh 5.2.14 +- zsh 4.3.4 + +Linux (Ubuntu Dapper 6.06) + +- bash 3.1.17(1) +- pdksh 5.2.14 +- zsh 4.2.5 + +Linux (Ubuntu Hardy 8.04) + +- bash 3.2.39(1) +- dash 0.5.4 +- ksh 1993-12-28 +- pdksh 5.2.14 +- zsh 4.3.4 + +Mac OS X 10.5.4 (Darwin 9.4.0) + +- bash 3.2.17(1) +- ksh 1993-12-28 +- zsh 4.3.4 + +Solaris 9 U6 x86 + +- /bin/sh +- bash 2.05.0(1) +- ksh M-11/16/88i +- zsh 3.0.8 + +Solaris 11 x86 (Nevada 77) + +- /bin/sh +- bash 3.2.25(1) +- ksh M-11/16/88i +- zsh 4.3.4 + + +New Features +------------ + +Support added to output assert source line number as part of assert messages. + + +Changes and Enhancements +------------------------ + +Support for automated testing frameworks. + +Added argument count error checking to all functions. + + +Bug Fixes +--------- + +Fixed some issues with ksh and zsh support. + +Fixed off-by-one of exit value in trap handler. + +Fixed handling of null values under ksh. + +Fixed bug in last resort temporary directory creation. + + +Deprecated Features +------------------- + +None. + + +Known Bugs and Issues +--------------------- + +zsh requires the ``shwordsplit`` option to be set. + +Line numbers in assert messages do not work properly with Bash 2.x. + +.. vim:fileencoding=latin1:ft=rst:spell:tw=80 diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.5.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.5.txt new file mode 100755 index 0000000..d9f26ce --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.5.txt @@ -0,0 +1,128 @@ +Release Notes for shUnit2 2.1.5 +=============================== + +This release contains several bug fixes and changes. Additionally, it includes +a rewrite of the test output to better match JUnit and PyUnit. + +This version also includes a slightly expanded set of coding standards by which +shUnit2 is coded. It should help anyone reading the code to better understand +it. + + + +Please read the Shell Errata section of the documentation for guidance on how +to meet these requirements. + +See the ``CHANGES-2.1.txt`` file for a full list of changes. + + +Tested Platforms +---------------- + +Cygwin + +- bash 3.2.39(20) +- ksh (sym-link to pdksh) +- pdksh 5.2.14 +- zsh 4.3.4 + +Linux (Ubuntu Dapper 6.06) + +- bash 3.1.17(1) +- ksh M-1993-12-28 +- pdksh 5.2.14-99/07/13.2 +- zsh 4.2.5 + +Linux (Ubuntu Hardy 8.04) + +- bash 3.2.39(1) +- dash 0.5.4 +- ksh M-1993-12-28 +- pdksh 5.2.14-99/07/13.2 +- zsh 4.3.4 + +Mac OS X 10.5.4 (Darwin 9.4.0) + +- bash 3.2.17(1) +- ksh M-1993-12-28 +- zsh 4.3.4 + +Solaris 9 U6 x86 + +- /bin/sh +- bash 2.05.0(1) +- ksh M-11/16/88i +- zsh 3.0.8 + +Solaris 11 x86 (Nevada 77) + +- /bin/sh +- bash 3.2.25(1) +- ksh M-11/16/88i +- zsh 4.3.4 + + +New Features +------------ + +Support added for output assert source line number as part of assert messages. + +Issue #2: Added assertNotEquals() assert. + +Provided a public ``shunit_tmpDir`` variable that can be used by unit test +scripts that need automated and guaranteed cleanup. + + +Changes and Enhancements +------------------------ + +Issue #3: Removed the check for unset variables as shUnit2 should not expect +scripts being tested to be clean. + +Issue #4: Rewrote the test summary. It is now greatly simplified and much more +script friendly. + +Issue #5: Fixed the documentation around the usage of failures. + +Issue #9: Added unit tests and improved documentation around the use of macros. + +Code updated to meet documented coding standards. + +Improved code reuse of ``_shunit_exit()`` and ``_shunit_fatal()`` functions. + +All output except shUnit2 error messages now goes to STDOUT. + +Converted DocBook documentation to reStructuredText for easier maintenance. + + +Bug Fixes +--------- + +Issue #1: Fixed bug in rap code where certain types of exit conditions did not +generate the ending report. + +Issue #7: Fixed duplicated printing of messages passed to asserts. + +Fixed bugs in ``shlib_relToAbsPath()`` in ``shlib``. + + +Deprecated Features +------------------- + +None. + + +Known Bugs and Issues +--------------------- + +Zsh requires the ``shwordsplit`` option to be set. See the documentation for +examples of how to do this. + +Line numbers in assert messages do not work properly with BASH 2.x. + +The Bourne shell of Solaris, BASH 2.x, and Zsh 3.0.x do not properly catch the +SIGTERM signal. As such, shell interpreter failures due to such things as +unbound variables cannot be caught. (See ``shunit_test_misc.sh``) + + +.. vim:fileencoding=latin1:ft=rst:spell:tw=80 diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.6.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.6.txt new file mode 100755 index 0000000..50087fe --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.6.txt @@ -0,0 +1,112 @@ +Release Notes for shUnit2 2.1.6 +=============================== + +This release contains bug fixes and changes. It is also the first release to +support running shunit2 as a standalone program. + +Please read the Shell Errata section of the documentation for guidance on how +to meet these requirements. + +See the ``CHANGES-2.1.txt`` file for a full list of changes. + +New Features +------------ + +Support for running shUnit2 as a standalone program. This makes it possible for +users to execute their unit tests in a manner that is not dependent on the +location an OS distribution maintainer chose to place shUnit2 in the file +system. + +Added support for functions defined like 'function someFunction()'. + +Changes and Enhancements +------------------------ + +Renamed the public ``shunit_tmpDir`` variable to ``SHUNIT_TMPDIR`` to be more +consistent with the ``TMPDIR`` variable. + +Bug Fixes +--------- + +Fixed issue where shunit2 would fail on some distributions when creating a +temporary directory because the **od** command was not present. + +Deprecated Features +------------------- + +None. + +Known Bugs and Issues +--------------------- + +Zsh requires the ``shwordsplit`` option to be set. See the documentation for +examples of how to do this. + +Line numbers in assert messages do not work properly with BASH 2.x. + +The Bourne shell of Solaris, BASH 2.x, and Zsh 3.0.x do not properly catch the +SIGTERM signal. As such, shell interpreter failures due to such things as +unbound variables cannot be caught. (See ``shunit_test_misc.sh``) + +Tested Platforms +---------------- + +Cygwin 1.7.9 (Windows XP SP2) + +- bash 4.1.10(4) +- dash 0.5.6.1 +- ksh (sym-link to pdksh) +- pdksh 5.2.14 +- zsh 4.3.11 + +Linux (Ubuntu Dapper 6.06.2 LTS) + +- bash 3.1.17(1) +- dash 0.5.3 +- ksh (sym-link to pdksh) +- pdksh 5.2.14-99/07/13.2 +- zsh 4.2.5 + +Linux (Ubuntu Hardy 8.04.4 LTS) + +- bash 3.2.39(1) +- dash 0.5.4 +- ksh M-1993-12-28 +- pdksh 5.2.14-99/07/13.2 +- zsh 4.3.4 + +Linux (Ubuntu Lucid 10.04.2 LTS) + +- bash 4.1.5(1) +- dash 0.5.5.1 +- ksh JM-93t+-2009-05-01 +- pdksh 5.2.14-99/07/13.2 +- zsh 4.3.10 + +Mac OS X 10.6.7 + +- bash 3.2.48(1) +- ksh M-1993-12-28 +- zsh 4.3.9 + +Solaris 8 U7 x86 + +- /bin/sh +- bash 2.03.0(1) +- ksh M-11/16/88i +- zsh 3.0.6 + +Solaris 9 U6 x86 + +- /bin/sh +- bash 2.05.0(1) +- ksh M-11/16/88i +- zsh 3.0.8 + +OpenSolaris 2009.06(snv_111b) x86 + +- /bin/sh +- bash 3.2.25(1) +- ksh 2008-11-04 + +.. vim:fileencoding=latin1:ft=rst:spell:tw=80 diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/TODO.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/TODO.txt new file mode 100755 index 0000000..f917cee --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/TODO.txt @@ -0,0 +1,13 @@ +Make it possible to execute a single test by passing the name of the test on +the command line + +Add support for '--randomize-order' so that the test order is randomized to +check for dependencies (which shouldn't be there) between tests. + +--debug option to display point in source code (line number and such) where the +problem showed up. + +assertTrue() just gives 'ASSERT:', nothing else :-(. others too? +upd: assertNull() will give message passed, but nothing else useful :-( + +$Revision: 228 $ diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/coding_standards.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/coding_standards.txt new file mode 100755 index 0000000..651f40d --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/coding_standards.txt @@ -0,0 +1,74 @@ +Coding Standards +================ + +Variable and Function Names +--------------------------- + +All shUnit2 specific constants, variables, and functions will be prefixed +appropriately with 'shunit'. This is to distinguish usage in the shUnit2 code +from users own scripts so that the shell name space remains predictable to +users. The exceptions here are the standard ``assertEquals``, etc. functions. + +All non-builtin constants and variables will be surrouned with squiggle +brackets, e.g. '${shunit_someVariable}' to improve code readability. + +Due to some shells not supporting local variables in functions, care in the +naming and use of variables, both public and private, is very important. +Accidental overriding of the variables can occur easily if care is not taken as +all variables are technically global variables in some shells. + ++----------------------------------+---------------------------+ +| *type* | *sample* | ++==================================+===========================+ +| global public constant | ``SHUNIT_TRUE`` | ++----------------------------------+---------------------------+ +| global private constant | ``__SHUNIT_SHELL_FLAGS`` | ++----------------------------------+---------------------------+ +| global public variable | not used | ++----------------------------------+---------------------------+ +| global private variable | ``__shunit_someVariable`` | ++----------------------------------+---------------------------+ +| global macro | ``_SHUNIT_SOME_MACRO_`` | ++----------------------------------+---------------------------+ +| public function | ``assertEquals`` | ++----------------------------------+---------------------------+ +| public function, local variable | ``shunit_someVariable_`` | ++----------------------------------+---------------------------+ +| private function | ``_shunit_someFunction`` | ++----------------------------------+---------------------------+ +| private function, local variable | ``_shunit_someVariable_`` | ++----------------------------------+---------------------------+ + +Where it makes sense, variables can have the first letter of the second and +later words capitalized. For example, the local variable name for the total +number of test cases seen might be ``shunit_totalTestsSeen_``. + +Local Variable Cleanup +---------------------- + +As many shells do not support local variables, no support for cleanup of +variables is present either. As such, all variables local to a function must be +cleared up with the ``unset`` command at the end of each function. + +Indentation +----------- + +Code block indentation is two (2) spaces, and tabs may not be used. :: + + if [ -z 'some string' ]; then + someFunction + fi + +Lines of code should be no longer than 80 characters unless absolutely +necessary. When lines are wrapped using the backslash character '\', subsequent +lines should be indented with four (4) spaces so as to differentiate from the +standard spacing of two characters. Tabs may *not* be used. :: + + for x in some set of very long set of arguments that make for a very long \ + that extends much too long for one line + do + echo ${x} + done + +.. vim:fileencoding=latin1:ft=rst:spell:tw=80 +.. $Revision: 301 $ diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/contributors.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/contributors.txt new file mode 100755 index 0000000..97c7d09 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/contributors.txt @@ -0,0 +1,14 @@ +The original author of shunit2 is Kate Ward. The following people have +contributed in some way or another to shunit2. + +Bryan Larsen +Kevin Van Horn +Maciej Bliziński +Mario Sparada +Mathias Goldau +Richard Jensen +Rob Holland +Rocky Bernstein +wood4321 (of code.google.com) + +$Revision: 313 $ diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/design_doc.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/design_doc.txt new file mode 100755 index 0000000..7ac8002 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/design_doc.txt @@ -0,0 +1,34 @@ +Design Doc for shUnit + +shUnit is based upon JUnit. The initial ideas for the script came from the book +"Pragmatic Unit Testing - In Java with JUnit" by Andrew Hunt and David Thomas. + +The script was written to perform unit testing for log4sh. log4sh had grown +enough that it was becoming difficult to easily test and and verify that the +tests passed for the many different operating systems on which it was being +used. + +The functions in shUnit are meant to match those in JUnit as much as possible +where shell allows. In the initial version, there will be no concept of +exceptions (as normal POSIX shell has no concept of them) but attempts to trap +problems will be done. + +Programatic Standards: + +* SHUNIT_TRUE - public global constant +* __SHUNIT_SHELL_FLAGS - private global constant +* __shunit_oldShellFlags - private global variable + +* assertEquals - public unit test function +* shunit_publicFunc - public shUnit function; can be called from parent unit + test script +* _shunit_privateFunc - private shUnit function; should not be called from + parent script. meant for internal use by shUnit + +* _su_myVar - variable inside a public function. prefixing with '_su_' to + reduce the chances that a variable outside of shUnit will be overridden. +* _su__myVar - variable inside a private function. prefixing with '_su__' to + reduce the chances that a variable in a shUnit public function, or a variable + outside of shUnit will be overridden. + +$Revision: 4 $ diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/rst2html.css b/eu.esrf.test/src/shunit2-2.1.6/doc/rst2html.css new file mode 100755 index 0000000..01983a5 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/rst2html.css @@ -0,0 +1,292 @@ +/* +:Author: David Goodger +:Contact: goodger@users.sourceforge.net +:Date: $Date: 2007-04-11 11:48:16 +0100 (Wed, 11 Apr 2007) $ +:Revision: $Revision: 2791 $ +:Copyright: This stylesheet has been placed in the public domain. +:Modified by: Kate Ward + +Default cascading style sheet for the HTML output of Docutils. + +See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to +customize this style sheet. +*/ + +/* used to remove borders from tables and images */ +.borderless, table.borderless td, table.borderless th { + border: 0 } + +table.borderless td, table.borderless th { + /* Override padding for "table.docutils td" with "! important". + The right padding separates the table cells. */ + padding: 0 0.5em 0 0 ! important } + +.first { + /* Override more specific margin styles with "! important". */ + margin-top: 0 ! important } + +.last, .with-subtitle { + margin-bottom: 0 ! important } + +.hidden { + display: none } + +a.toc-backref { + text-decoration: none ; + color: black } + +blockquote.epigraph { + margin: 2em 5em ; } + +dl.docutils dd { + margin-bottom: 0.5em } + +/* Uncomment (and remove this text!) to get bold-faced definition list terms +dl.docutils dt { + font-weight: bold } +*/ + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.admonition, div.attention, div.caution, div.danger, div.error, +div.hint, div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.admonition p.admonition-title, div.hint p.admonition-title, +div.important p.admonition-title, div.note p.admonition-title, +div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +/* Uncomment (and remove this text!) to get reduced vertical space in + compound paragraphs. +div.compound .compound-first, div.compound .compound-middle { + margin-bottom: 0.5em } + +div.compound .compound-last, div.compound .compound-middle { + margin-top: 0.5em } +*/ + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em ; + margin-right: 2em } + +div.footer, div.header { + clear: both; + font-size: smaller } + +div.line-block { + display: block ; + margin-top: 1em ; + margin-bottom: 1em } + +div.line-block div.line-block { + margin-top: 0 ; + margin-bottom: 0 ; + margin-left: 1.5em } + +div.sidebar { + margin-left: 1em ; + border: medium outset ; + padding: 1em ; + background-color: #ffffee ; + width: 40% ; + float: right ; + clear: right } + +div.sidebar p.rubric { + font-family: sans-serif ; + font-size: medium } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, +h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { + margin-top: 0.4em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr.docutils { + width: 75% } + +img.align-left { + clear: left } + +img.align-right { + clear: right } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.attribution { + text-align: right ; + margin-left: 50% } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.rubric { + font-weight: bold ; + font-size: larger ; + color: maroon ; + text-align: center } + +p.sidebar-title { + font-family: sans-serif ; + font-weight: bold ; + font-size: larger } + +p.sidebar-subtitle { + font-family: sans-serif ; + font-weight: bold } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font-family: serif ; + font-size: 100% } + +pre.literal-block, pre.doctest-block { + margin-left: 2em ; + margin-right: 2em ; + background-color: #eeeeee } + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option { + white-space: nowrap } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +span.section-subtitle { + /* font-size relative to parent (h1..h6 element) */ + font-size: 80% } + +table.citation { + border-left: solid 1px gray; + margin-left: 1px } + +table.docinfo { + margin: 2em 4em } + +/* +table.docutils { + margin-top: 0.5em ; + margin-bottom: 0.5em } +*/ + +table.footnote { + border-left: solid 1px black; + margin-left: 1px ; + font-size: 80% } + } + +table.docutils td, table.docutils th, +table.docinfo td, table.docinfo th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +table.docutils th.field-name, table.docinfo th.docinfo-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap ; + padding-left: 0 } + +h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, +h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { + font-size: 100% } + +/* +tt.docutils { + background-color: #eeeeee } +*/ + +ul.auto-toc { + list-style-type: none } + +/* customizations by kward */ + +h1 { font-size: 133%; border-top:1px solid #CCCCFF; } +h1.title { font-size: 150%; border-top:0px; padding-top: 1em; } +/* div.document { font-size: 90% } */ diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/shunit2.html b/eu.esrf.test/src/shunit2-2.1.6/doc/shunit2.html new file mode 100755 index 0000000..c5aa336 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/shunit2.html @@ -0,0 +1,880 @@ + + + + + + +shUnit2 2.1.x Documentation + + + +
+

shUnit2 2.1.x Documentation

+ +
+

Abstract

+

shUnit2 is a xUnit unit test framework for Bourne based shell scripts, and it +is designed to work in a similar manner to JUnit, PyUnit, etc.. If you have +ever had the desire to write a unit test for a shell script, shUnit2 can do the +job.

+ +
+
+

Introduction

+

shUnit2 was originally developed to provide a consistent testing solution for +log4sh, a shell based logging framework similar to log4j. During the +development of that product, a repeated problem of having things work just fine +under one shell (/bin/bash on Linux to be specific), and then not working +under another shell (/bin/sh on Solaris) kept coming up. Although several +simple tests were run, they were not adequate and did not catch some corner +cases. The decision was finally made to write a proper unit test framework after +multiple brown-bag releases were made. Research was done to look for an +existing product that met the testing requirements, but no adequate product was +found.

+

Tested Operating Systems (varies over time)

+
    +
  • Cygwin
  • +
  • FreeBSD (user supported)
  • +
  • Linux (Gentoo, Ubuntu)
  • +
  • Mac OS X
  • +
  • Solaris 8, 9, 10 (inc. OpenSolaris)
  • +
+

Tested Shells

+
    +
  • Bourne Shell (sh)
  • +
  • BASH - GNU Bourne Again SHell (bash)
  • +
  • DASH (dash)
  • +
  • Korn Shell (ksh)
  • +
  • pdksh - Public Domain Korn Shell (pdksh)
  • +
  • zsh - Zsh (zsh) (since 2.1.2) please see the Zsh shell errata for more +information
  • +
+

See the appropriate Release Notes for this release +(doc/RELEASE_NOTES-X.X.X.txt) for the list of actual versions tested.

+
+

Credits / Contributors

+

A list of contributors to shUnit2 can be found in the source archive in +doc/contributors.txt. Many thanks go out to all those who have contributed +to make this a better tool.

+

shUnit2 is the original product of many hours of work by Kate Ward, the primary +author of the code. For other products by her, look up log4sh or shFlags, or +visit her website at http://forestent.com/.

+
+
+

Feedback

+

Feedback is most certainly welcome for this document. Send your additions, +comments and criticisms to the shunit2-users@google.com mailing list.

+
+
+
+

Quickstart

+

This section will give a very quick start to running unit tests with shUnit2. +More information is located in later sections.

+

Here is a quick sample script to show how easy it is to write a unit test in +shell. Note: the script as it stands expects that you are running it from the +``examples`` directory.

+
+#! /bin/sh
+# file: examples/equality_test.sh
+
+testEquality()
+{
+  assertEquals 1 1
+}
+
+# load shunit2
+. ../src/shell/shunit2
+
+

Running the unit test should give results similar to the following.

+
+testEquality
+
+Ran 1 test.
+
+OK
+
+

W00t! You've just run your first successful unit test. So, what just happened? +Quite a bit really, and it all happened simply by sourcing the shunit2 +library. The basic functionality for the script above goes like this:

+
    +
  • When shUnit2 is sourced, it will walk through any functions defined whose +namestart with the string test and add those to an internal list of tests +to execute. Once a list of test functions to be run has been determined, +shunit2 will go to work.
  • +
  • Before any tests are executed, shUnit2 again looks for a function, this time +one named oneTimeSetUp(). If it exists, it will be run. This function is +normally used to setup the environment for all tests to be run. Things like +creating directories for output or setting environment variables are good to +place here. Just so you know, you can also declare a corresponding function +named oneTimeTearDown() function that does the same thing, but once all +the tests have been completed. It is good for removing temporary directories, +etc.
  • +
  • shUnit2 is now ready to run tests. Before doing so though, it again looks for +another function that might be declared, one named setUp(). If the +function exists, it will be run before each test. It is good for resetting the +environment so that each test starts with a clean slate. At this stage, the +first test is finally run. The success of the test is recorded for a report +that will be generated later. After the test is run, shUnit2 looks for a final +function that might be declared, one named tearDown(). If it exists, it +will be run after each test. It is a good place for cleaning up after each +test, maybe doing things like removing files that were created, or removing +directories. This set of steps, setUp() > test() > tearDown(), is +repeated for all of the available tests.
  • +
  • Once all the work is done, shUnit2 will generate the nice report you saw +above. A summary of all the successes and failures will be given so that you +know how well your code is doing.
  • +
+

We should now try adding a test that fails. Change your unit test to look like +this.

+
+#! /bin/sh
+# file: examples/party_test.sh
+
+testEquality()
+{
+  assertEquals 1 1
+}
+
+testPartyLikeItIs1999()
+{
+  year=`date '+%Y'`
+  assertEquals "It's not 1999 :-(" \
+      '1999' "${year}"
+}
+
+# load shunit2
+. ../src/shell/shunit2
+
+

So, what did you get? I guess it told you that this isn't 1999. Bummer, eh? +Hopefully, you noticed a couple of things that were different about the second +test. First, we added an optional message that the user will see if the assert +fails. Second, we did comparisons of strings instead of integers as in the first +test. It doesn't matter whether you are testing for equality of strings or +integers. Both work equally well with shUnit2.

+

Hopefully, this is enough to get you started with unit testing. If you want a +ton more examples, take a look at the tests provided with log4sh or shFlags. +Both provide excellent examples of more advanced usage. shUnit2 was after all +written to help with the unit testing problems that log4sh had.

+
+
+

Function Reference

+
+

General Info

+

Any string values passed should be properly quoted -- they should must be +surrounded by single-quote (') or double-quote (") characters -- so that the +shell will properly parse them.

+
+
+

Asserts

+
+
assertEquals [message] expected actual
+
Asserts that expected and actual are equal to one another. The expected +and actual values can be either strings or integer values as both will be +treated as strings. The message is optional, and must be quoted.
+
assertNotEquals [message] expected actual
+
Asserts that unexpected and actual are not equal to one another. The +unexpected and actual values can be either strings or integer values as +both will be treaded as strings. The message is optional, and must be +quoted.
+
assertSame [message] expected actual
+
This function is functionally equivalent to assertEquals.
+
assertNotSame [message] unexpected actual
+
This function is functionally equivalent to assertNotEquals.
+
assertNull [message] value
+
Asserts that value is null, or in shell terms, a zero-length string. The +value must be a string as an integer value does not translate into a +zero-length string. The message is optional, and must be quoted.
+
assertNotNull [message] value
+
Asserts that value is not null, or in shell terms, a non-empty string. The +value may be a string or an integer as the later will be parsed as a +non-empty string value. The message is optional, and must be quoted.
+
assertTrue [message] condition
+

Asserts that a given shell test condition is true. The condition can be as +simple as a shell true value (the value 0 -- equivalent to +${SHUNIT_TRUE}), or a more sophisticated shell conditional expression. The +message is optional, and must be quoted.

+

A sophisticated shell conditional expression is equivalent to what the if +or while shell built-ins would use (more specifically, what the test +command would use). Testing for example whether some value is greater than +another value can be done this way.

+
+assertTrue "[ 34 -gt 23 ]"
+
+

Testing for the ability to read a file can also be done. This particular test +will fail.

+
+assertTrue 'test failed' "[ -r /some/non-existant/file' ]"
+
+

As the expressions are standard shell test expressions, it is possible to +string multiple expressions together with -a and -o in the standard +fashion. This test will succeed as the entire expression evaluates to true.

+
+assertTrue 'test failed' '[ 1 -eq 1 -a 2 -eq 2 ]'
+
+

One word of warning: be very careful with your quoting as shell is not the +most forgiving of bad quoting, and things will fail in strange ways.

+
+
assertFalse [message] condition
+

Asserts that a given shell test condition is false. The condition can be +as simple as a shell false value (the value 1 -- equivalent to +${SHUNIT_FALSE}), or a more sophisticated shell conditional expression. +The message is optional, and must be quoted.

+

For examples of more sophisticated expressions, see ``assertTrue``.

+
+
+
+
+

Failures

+

Just to clarify, failures do not test the various arguments against one +another. Failures simply fail, optionally with a message, and that is all they +do. If you need to test arguments against one another, use asserts.

+

If all failures do is fail, why might one use them? There are times when you may +have some very complicated logic that you need to test, and the simple asserts +provided are simply not adequate. You can do your own validation of the code, +use an assertTrue ${SHUNIT_TRUE} if your own tests succeeded, and use a +failure to record a failure.

+
+
fail [message]
+
Fails the test immediately. The message is optional, and must be quoted.
+
failNotEquals [message] unexpected actual
+

Fails the test immediately, reporting that the unexpected and actual +values are not equal to one another. The message is optional, and must be +quoted.

+

Note: no actual comparison of unexpected and actual is done.

+
+
failSame [message] expected actual
+

Fails the test immediately, reporting that the expected and actual values +are the same. The message is optional, and must be quoted.

+

Note: no actual comparison of expected and actual is done.

+
+
failNotSame [message] expected actual
+

Fails the test immediately, reporting that the expected and actual values +are not the same. The message is optional, and must be quoted.

+

Note: no actual comparison of expected and actual is done.

+
+
+
+
+

Setup/Teardown

+
+
oneTimeSetUp
+

This function can be be optionally overridden by the user in their test suite.

+

If this function exists, it will be called once before any tests are run. It +is useful to prepare a common environment for all tests.

+
+
oneTimeTearDown
+

This function can be be optionally overridden by the user in their test suite.

+

If this function exists, it will be called once after all tests are completed. +It is useful to clean up the environment after all tests.

+
+
setUp
+

This function can be be optionally overridden by the user in their test suite.

+

If this function exists, it will be called before each test is run. It is +useful to reset the environment before each test.

+
+
tearDown
+

This function can be be optionally overridden by the user in their test suite.

+

If this function exists, it will be called after each test completes. It is +useful to clean up the environment after each test.

+
+
+
+
+

Skipping

+
+
startSkipping
+
This function forces the remaining assert and fail functions to be +"skipped", i.e. they will have no effect. Each function skipped will be +recorded so that the total of asserts and fails will not be altered.
+
endSkipping
+
This function returns calls to the assert and fail functions to their +default behavior, i.e. they will be called.
+
isSkipping
+
This function returns the current state of skipping. It can be compared +against ${SHUNIT_TRUE} or ${SHUNIT_FALSE} if desired.
+
+
+
+

Suites

+

The default behavior of shUnit2 is that all tests will be found dynamically. If +you have a specific set of tests you want to run, or you don't want to use the +standard naming scheme of prefixing your tests with test, these functions +are for you. Most users will never use them though.

+
+
suite
+

This function can be optionally overridden by the user in their test suite.

+

If this function exists, it will be called when shunit2 is sourced. If it +does not exist, shUnit2 will search the parent script for all functions +beginning with the word test, and they will be added dynamically to the +test suite.

+
+
suite_addTest name
+
This function adds a function named name to the list of tests scheduled for +execution as part of this test suite. This function should only be called from +within the suite() function.
+
+
+
+
+

Advanced Usage

+

This section covers several advanced usage topics.

+
+

Some constants you can use

+

There are several constants provided by shUnit2 as variables that might be of +use to you.

+

Predefined

+ ++++ + + + + + + + + + + + + + + + + + +
SHUNIT_VERSIONThe version of shUnit2 you are running.
SHUNIT_TRUEStandard shell true value (the integer value 0).
SHUNIT_FALSEStandard shell false value (the integer value 1).
SHUNIT_ERRORThe integer value 2.
SHUNIT_TMPDIRPath to temporary directory that will be automatically +cleaned up upon exit of shUnit2.
+

User defined

+ ++++ + + + + + +
SHUNIT_PARENTThe filename of the shell script containing the tests. This +is needed specifically for Zsh support.
+
+
+

Error handling

+

The constants values SHUNIT_TRUE, SHUNIT_FALSE, and SHUNIT_ERROR are +returned from nearly every function to indicate the success or failure of the +function. Additionally the variable flags_error is filled with a detailed +error message if any function returns with a SHUNIT_ERROR value.

+
+
+

Including Line Numbers in Asserts (Macros)

+

If you include lots of assert statements in an individual test function, it can +become difficult to determine exactly which assert was thrown unless your +messages are unique. To help somewhat, line numbers can be included in the +assert messages. To enable this, a special shell "macro" must be used rather +than the standard assert calls. Shell doesn't actually have macros; the name is +used here as the operation is similar to a standard macro.

+

For example, to include line numbers for a assertEquals() function call, +replace the assertEquals() with ${_ASSERT_EQUALS_}.

+

Example -- Asserts with and without line numbers

+
+#! /bin/sh
+# file: examples/lineno_test.sh
+
+testLineNo()
+{
+  # this assert will have line numbers included (e.g. "ASSERT:[123] ...")
+  echo "ae: ${_ASSERT_EQUALS_}"
+  ${_ASSERT_EQUALS_} 'not equal' 1 2
+
+  # this assert will not have line numbers included (e.g. "ASSERT: ...")
+  assertEquals 'not equal' 1 2
+}
+
+# load shunit2
+. ../src/shell/shunit2
+
+

Notes:

+
    +
  1. Due to how shell parses command-line arguments, all strings used with macros +should be quoted twice. Namely, single-quotes must be converted to +single-double-quotes, and vice-versa. If the string being passed is +absolutely for sure not empty, the extra quoting is not necessary.

    +

    Normal assertEquals call.

    +
    +assertEquals 'some message' 'x' ''
    +
    +

    Macro _ASSERT_EQUALS_ call. Note the extra quoting around the message +and the null value.

    +
    +_ASSERT_EQUALS_ '"some message"' 'x' '""'
    +
    +
  2. +
  3. Line numbers are not supported in all shells. If a shell does not support +them, no errors will be thrown. Supported shells include: bash (>=3.0), +ksh, pdksh, and zsh.

    +
  4. +
+
+
+

Test Skipping

+

There are times where the test code you have written is just not applicable to +the system you are running on. This section describes how to skip these tests +but maintain the total test count.

+

Probably the easiest example would be shell code that is meant to run under the +bash shell, but the unit test is running under the Bourne shell. There are +things that just won't work. The following test code demonstrates two sample +functions, one that will be run under any shell, and the another that will run +only under the bash shell.

+

Example -- math include

+
+# available as examples/math.inc
+
+add_generic()
+{
+  num_a=$1
+  num_b=$2
+
+  expr $1 + $2
+}
+
+add_bash()
+{
+  num_a=$1
+  num_b=$2
+
+  echo $(($1 + $2))
+}
+
+

And here is a corresponding unit test that correctly skips the add_bash() +function when the unit test is not running under the bash shell.

+

Example -- math unit test

+
+#! /bin/sh
+# available as examples/math_test.sh
+
+testAdding()
+{
+  result=`add_generic 1 2`
+  assertEquals \
+      "the result of '${result}' was wrong" \
+      3 "${result}"
+
+  # disable non-generic tests
+  [ -z "${BASH_VERSION:-}" ] && startSkipping
+
+  result=`add_bash 1 2`
+  assertEquals \
+      "the result of '${result}' was wrong" \
+      3 "${result}"
+}
+
+oneTimeSetUp()
+{
+  # load include to test
+  . ./math.inc
+}
+
+# load and run shUnit2
+. ../src/shell/shunit2
+
+

Running the above test under the bash shell will result in the following +output.

+
+$ /bin/bash math_test.sh
+testAdding
+
+Ran 1 test.
+
+OK
+
+

But, running the test under any other Unix shell will result in the following +output.

+
+$ /bin/ksh math_test.sh
+testAdding
+
+Ran 1 test.
+
+OK (skipped=1)
+
+

As you can see, the total number of tests has not changed, but the report +indicates that some tests were skipped.

+

Skipping can be controlled with the following functions: startSkipping(), +stopSkipping(), and isSkipping(). Once skipping is enabled, it will +remain enabled until the end of the current test function call, after which +skipping is disabled.

+
+
+
+

Appendix

+
+

Getting help

+

For help, please send requests to either the shunit2-users@googlegroups.com +mailing list (archives available on the web at +http://groups.google.com/group/shunit2-users) or directly to +Kate Ward <kate dot ward at forestent dot com>.

+
+
+

Zsh

+

For compatibility with Zsh, there is one requirement that must be met -- the +shwordsplit option must be set. There are three ways to accomplish this.

+
    +
  1. In the unit-test script, add the following shell code snippet before sourcing +the shunit2 library.

    +
    +setopt shwordsplit
    +
    +
  2. +
  3. When invoking zsh from either the command-line or as a script with +#!, add the -y parameter.

    +
    +#! /bin/zsh -y
    +
    +
  4. +
  5. When invoking zsh from the command-line, add -o shwordsplit -- as +parameters before the script name.

    +
    +$ zsh -o shwordsplit -- some_script
    +
    +
  6. +
+ + + + + +
+
+
+ + diff --git a/eu.esrf.test/src/shunit2-2.1.6/doc/shunit2.txt b/eu.esrf.test/src/shunit2-2.1.6/doc/shunit2.txt new file mode 100755 index 0000000..fec1b53 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/doc/shunit2.txt @@ -0,0 +1,562 @@ +=========================== +shUnit2 2.1.x Documentation +=========================== + +Abstract +======== + +shUnit2_ is a xUnit_ unit test framework for Bourne based shell scripts, and it +is designed to work in a similar manner to JUnit_, PyUnit_, etc.. If you have +ever had the desire to write a unit test for a shell script, shUnit2 can do the +job. + +.. contents:: Table of Contents + :depth: 2 + +Introduction +============ + +shUnit2 was originally developed to provide a consistent testing solution for +log4sh_, a shell based logging framework similar to log4j_. During the +development of that product, a repeated problem of having things work just fine +under one shell (``/bin/bash`` on Linux to be specific), and then not working +under another shell (``/bin/sh`` on Solaris) kept coming up. Although several +simple tests were run, they were not adequate and did not catch some corner +cases. The decision was finally made to write a proper unit test framework after +multiple brown-bag releases were made. *Research was done to look for an +existing product that met the testing requirements, but no adequate product was +found.* + +Tested Operating Systems (varies over time) + +- Cygwin +- FreeBSD (user supported) +- Linux (Gentoo, Ubuntu) +- Mac OS X +- Solaris 8, 9, 10 (inc. OpenSolaris) + +Tested Shells + +- Bourne Shell (**sh**) +- BASH - GNU Bourne Again SHell (**bash**) +- DASH (**dash**) +- Korn Shell (**ksh**) +- pdksh - Public Domain Korn Shell (**pdksh**) +- zsh - Zsh (**zsh**) (since 2.1.2) *please see the Zsh shell errata for more + information* + +See the appropriate Release Notes for this release +(``doc/RELEASE_NOTES-X.X.X.txt``) for the list of actual versions tested. + +Credits / Contributors +---------------------- + +A list of contributors to shUnit2 can be found in the source archive in +``doc/contributors.txt``. Many thanks go out to all those who have contributed +to make this a better tool. + +shUnit2 is the original product of many hours of work by Kate Ward, the primary +author of the code. For other products by her, look up log4sh_ or shFlags_, or +visit her website at http://forestent.com/. + +Feedback +-------- + +Feedback is most certainly welcome for this document. Send your additions, +comments and criticisms to the shunit2-users@google.com mailing list. + +Quickstart +========== + +This section will give a very quick start to running unit tests with shUnit2. +More information is located in later sections. + +Here is a quick sample script to show how easy it is to write a unit test in +shell. *Note: the script as it stands expects that you are running it from the +``examples`` directory.* :: + + #! /bin/sh + # file: examples/equality_test.sh + + testEquality() + { + assertEquals 1 1 + } + + # load shunit2 + . ../src/shell/shunit2 + +Running the unit test should give results similar to the following. :: + + testEquality + + Ran 1 test. + + OK + +W00t! You've just run your first successful unit test. So, what just happened? +Quite a bit really, and it all happened simply by sourcing the ``shunit2`` +library. The basic functionality for the script above goes like this: + +- When shUnit2 is sourced, it will walk through any functions defined whose + namestart with the string ``test`` and add those to an internal list of tests + to execute. Once a list of test functions to be run has been determined, + shunit2 will go to work. +- Before any tests are executed, shUnit2 again looks for a function, this time + one named ``oneTimeSetUp()``. If it exists, it will be run. This function is + normally used to setup the environment for all tests to be run. Things like + creating directories for output or setting environment variables are good to + place here. Just so you know, you can also declare a corresponding function + named ``oneTimeTearDown()`` function that does the same thing, but once all + the tests have been completed. It is good for removing temporary directories, + etc. +- shUnit2 is now ready to run tests. Before doing so though, it again looks for + another function that might be declared, one named ``setUp()``. If the + function exists, it will be run before each test. It is good for resetting the + environment so that each test starts with a clean slate. At this stage, the + first test is finally run. The success of the test is recorded for a report + that will be generated later. After the test is run, shUnit2 looks for a final + function that might be declared, one named ``tearDown()``. If it exists, it + will be run after each test. It is a good place for cleaning up after each + test, maybe doing things like removing files that were created, or removing + directories. This set of steps, ``setUp()`` > ``test()`` > ``tearDown()``, is + repeated for all of the available tests. +- Once all the work is done, shUnit2 will generate the nice report you saw + above. A summary of all the successes and failures will be given so that you + know how well your code is doing. + +We should now try adding a test that fails. Change your unit test to look like +this. :: + + #! /bin/sh + # file: examples/party_test.sh + + testEquality() + { + assertEquals 1 1 + } + + testPartyLikeItIs1999() + { + year=`date '+%Y'` + assertEquals "It's not 1999 :-(" \ + '1999' "${year}" + } + + # load shunit2 + . ../src/shell/shunit2 + +So, what did you get? I guess it told you that this isn't 1999. Bummer, eh? +Hopefully, you noticed a couple of things that were different about the second +test. First, we added an optional message that the user will see if the assert +fails. Second, we did comparisons of strings instead of integers as in the first +test. It doesn't matter whether you are testing for equality of strings or +integers. Both work equally well with shUnit2. + +Hopefully, this is enough to get you started with unit testing. If you want a +ton more examples, take a look at the tests provided with log4sh_ or shFlags_. +Both provide excellent examples of more advanced usage. shUnit2 was after all +written to help with the unit testing problems that log4sh_ had. + +Function Reference +================== + +General Info +------------ + +Any string values passed should be properly quoted -- they should must be +surrounded by single-quote (') or double-quote (") characters -- so that the +shell will properly parse them. + +Asserts +------- + +``assertEquals [message] expected actual`` + Asserts that *expected* and *actual* are equal to one another. The *expected* + and *actual* values can be either strings or integer values as both will be + treated as strings. The *message* is optional, and must be quoted. + +``assertNotEquals [message] expected actual`` + Asserts that *unexpected* and *actual* are not equal to one another. The + *unexpected* and *actual* values can be either strings or integer values as + both will be treaded as strings. The *message* is optional, and must be + quoted. + +``assertSame [message] expected actual`` + This function is functionally equivalent to ``assertEquals``. + +``assertNotSame [message] unexpected actual`` + This function is functionally equivalent to ``assertNotEquals``. + +``assertNull [message] value`` + Asserts that *value* is *null*, or in shell terms, a zero-length string. The + *value* must be a string as an integer value does not translate into a + zero-length string. The *message* is optional, and must be quoted. + +``assertNotNull [message] value`` + Asserts that *value* is *not null*, or in shell terms, a non-empty string. The + *value* may be a string or an integer as the later will be parsed as a + non-empty string value. The *message* is optional, and must be quoted. + +``assertTrue [message] condition`` + Asserts that a given shell test *condition* is *true*. The condition can be as + simple as a shell *true* value (the value ``0`` -- equivalent to + ``${SHUNIT_TRUE}``), or a more sophisticated shell conditional expression. The + *message* is optional, and must be quoted. + + A sophisticated shell conditional expression is equivalent to what the **if** + or **while** shell built-ins would use (more specifically, what the **test** + command would use). Testing for example whether some value is greater than + another value can be done this way. :: + + assertTrue "[ 34 -gt 23 ]" + + Testing for the ability to read a file can also be done. This particular test + will fail. :: + + assertTrue 'test failed' "[ -r /some/non-existant/file' ]" + + As the expressions are standard shell **test** expressions, it is possible to + string multiple expressions together with ``-a`` and ``-o`` in the standard + fashion. This test will succeed as the entire expression evaluates to *true*. + :: + + assertTrue 'test failed' '[ 1 -eq 1 -a 2 -eq 2 ]' + + *One word of warning: be very careful with your quoting as shell is not the + most forgiving of bad quoting, and things will fail in strange ways.* + +``assertFalse [message] condition`` + Asserts that a given shell test *condition* is *false*. The condition can be + as simple as a shell *false* value (the value ``1`` -- equivalent to + ``${SHUNIT_FALSE}``), or a more sophisticated shell conditional expression. + The *message* is optional, and must be quoted. + + *For examples of more sophisticated expressions, see ``assertTrue``.* + +Failures +-------- + +Just to clarify, failures **do not** test the various arguments against one +another. Failures simply fail, optionally with a message, and that is all they +do. If you need to test arguments against one another, use asserts. + +If all failures do is fail, why might one use them? There are times when you may +have some very complicated logic that you need to test, and the simple asserts +provided are simply not adequate. You can do your own validation of the code, +use an ``assertTrue ${SHUNIT_TRUE}`` if your own tests succeeded, and use a +failure to record a failure. + +``fail [message]`` + Fails the test immediately. The *message* is optional, and must be quoted. + +``failNotEquals [message] unexpected actual`` + Fails the test immediately, reporting that the *unexpected* and *actual* + values are not equal to one another. The *message* is optional, and must be + quoted. + + *Note: no actual comparison of unexpected and actual is done.* + +``failSame [message] expected actual`` + Fails the test immediately, reporting that the *expected* and *actual* values + are the same. The *message* is optional, and must be quoted. + + *Note: no actual comparison of expected and actual is done.* + +``failNotSame [message] expected actual`` + Fails the test immediately, reporting that the *expected* and *actual* values + are not the same. The *message* is optional, and must be quoted. + + *Note: no actual comparison of expected and actual is done.* + +Setup/Teardown +-------------- + +``oneTimeSetUp`` + This function can be be optionally overridden by the user in their test suite. + + If this function exists, it will be called once before any tests are run. It + is useful to prepare a common environment for all tests. + +``oneTimeTearDown`` + This function can be be optionally overridden by the user in their test suite. + + If this function exists, it will be called once after all tests are completed. + It is useful to clean up the environment after all tests. + +``setUp`` + This function can be be optionally overridden by the user in their test suite. + + If this function exists, it will be called before each test is run. It is + useful to reset the environment before each test. + +``tearDown`` + This function can be be optionally overridden by the user in their test suite. + + If this function exists, it will be called after each test completes. It is + useful to clean up the environment after each test. + +Skipping +-------- + +``startSkipping`` + This function forces the remaining *assert* and *fail* functions to be + "skipped", i.e. they will have no effect. Each function skipped will be + recorded so that the total of asserts and fails will not be altered. + +``endSkipping`` + This function returns calls to the *assert* and *fail* functions to their + default behavior, i.e. they will be called. + +``isSkipping`` + This function returns the current state of skipping. It can be compared + against ``${SHUNIT_TRUE}`` or ``${SHUNIT_FALSE}`` if desired. + +Suites +------ + +The default behavior of shUnit2 is that all tests will be found dynamically. If +you have a specific set of tests you want to run, or you don't want to use the +standard naming scheme of prefixing your tests with ``test``, these functions +are for you. Most users will never use them though. + +``suite`` + This function can be optionally overridden by the user in their test suite. + + If this function exists, it will be called when ``shunit2`` is sourced. If it + does not exist, shUnit2 will search the parent script for all functions + beginning with the word ``test``, and they will be added dynamically to the + test suite. + +``suite_addTest name`` + This function adds a function named *name* to the list of tests scheduled for + execution as part of this test suite. This function should only be called from + within the ``suite()`` function. + +Advanced Usage +============== + +This section covers several advanced usage topics. + +Some constants you can use +-------------------------- + +There are several constants provided by shUnit2 as variables that might be of +use to you. + +Predefined + +================== =========================================================== +``SHUNIT_VERSION`` The version of shUnit2 you are running. +``SHUNIT_TRUE`` Standard shell *true* value (the integer value 0). +``SHUNIT_FALSE`` Standard shell *false* value (the integer value 1). +``SHUNIT_ERROR`` The integer value 2. +``SHUNIT_TMPDIR`` Path to temporary directory that will be automatically + cleaned up upon exit of shUnit2. +================== =========================================================== + +User defined + +================== =========================================================== +``SHUNIT_PARENT`` The filename of the shell script containing the tests. This + is needed specifically for Zsh support. +================== =========================================================== + +Error handling +-------------- + +The constants values ``SHUNIT_TRUE``, ``SHUNIT_FALSE``, and ``SHUNIT_ERROR`` are +returned from nearly every function to indicate the success or failure of the +function. Additionally the variable ``flags_error`` is filled with a detailed +error message if any function returns with a ``SHUNIT_ERROR`` value. + +Including Line Numbers in Asserts (Macros) +------------------------------------------ + +If you include lots of assert statements in an individual test function, it can +become difficult to determine exactly which assert was thrown unless your +messages are unique. To help somewhat, line numbers can be included in the +assert messages. To enable this, a special shell "macro" must be used rather +than the standard assert calls. *Shell doesn't actually have macros; the name is +used here as the operation is similar to a standard macro.* + +For example, to include line numbers for a ``assertEquals()`` function call, +replace the ``assertEquals()`` with ``${_ASSERT_EQUALS_}``. + +Example�--�Asserts with and without line numbers :: + + #! /bin/sh + # file: examples/lineno_test.sh + + testLineNo() + { + # this assert will have line numbers included (e.g. "ASSERT:[123] ...") + echo "ae: ${_ASSERT_EQUALS_}" + ${_ASSERT_EQUALS_} 'not equal' 1 2 + + # this assert will not have line numbers included (e.g. "ASSERT: ...") + assertEquals 'not equal' 1 2 + } + + # load shunit2 + . ../src/shell/shunit2 + +Notes: + +#. Due to how shell parses command-line arguments, all strings used with macros + should be quoted twice. Namely, single-quotes must be converted to + single-double-quotes, and vice-versa. If the string being passed is + absolutely for sure not empty, the extra quoting is not necessary. + + Normal ``assertEquals`` call. :: + + assertEquals 'some message' 'x' '' + + Macro ``_ASSERT_EQUALS_`` call. Note the extra quoting around the *message* + and the *null* value. :: + + _ASSERT_EQUALS_ '"some message"' 'x' '""' + +#. Line numbers are not supported in all shells. If a shell does not support + them, no errors will be thrown. Supported shells include: **bash** (>=3.0), + **ksh**, **pdksh**, and **zsh**. + +Test Skipping +------------- + +There are times where the test code you have written is just not applicable to +the system you are running on. This section describes how to skip these tests +but maintain the total test count. + +Probably the easiest example would be shell code that is meant to run under the +**bash** shell, but the unit test is running under the Bourne shell. There are +things that just won't work. The following test code demonstrates two sample +functions, one that will be run under any shell, and the another that will run +only under the **bash** shell. + +Example�-- math include :: + + # available as examples/math.inc + + add_generic() + { + num_a=$1 + num_b=$2 + + expr $1 + $2 + } + + add_bash() + { + num_a=$1 + num_b=$2 + + echo $(($1 + $2)) + } + +And here is a corresponding unit test that correctly skips the ``add_bash()`` +function when the unit test is not running under the **bash** shell. + +Example�-- math unit test :: + + #! /bin/sh + # available as examples/math_test.sh + + testAdding() + { + result=`add_generic 1 2` + assertEquals \ + "the result of '${result}' was wrong" \ + 3 "${result}" + + # disable non-generic tests + [ -z "${BASH_VERSION:-}" ] && startSkipping + + result=`add_bash 1 2` + assertEquals \ + "the result of '${result}' was wrong" \ + 3 "${result}" + } + + oneTimeSetUp() + { + # load include to test + . ./math.inc + } + + # load and run shUnit2 + . ../src/shell/shunit2 + +Running the above test under the **bash** shell will result in the following +output. :: + + $ /bin/bash math_test.sh + testAdding + + Ran 1 test. + + OK + +But, running the test under any other Unix shell will result in the following +output. :: + + $ /bin/ksh math_test.sh + testAdding + + Ran 1 test. + + OK (skipped=1) + +As you can see, the total number of tests has not changed, but the report +indicates that some tests were skipped. + +Skipping can be controlled with the following functions: ``startSkipping()``, +``stopSkipping()``, and ``isSkipping()``. Once skipping is enabled, it will +remain enabled until the end of the current test function call, after which +skipping is disabled. + +Appendix +======== + +Getting help +------------ + +For help, please send requests to either the shunit2-users@googlegroups.com +mailing list (archives available on the web at +http://groups.google.com/group/shunit2-users) or directly to +Kate Ward . + +Zsh +--- + +For compatibility with Zsh, there is one requirement that must be met -- the +``shwordsplit`` option must be set. There are three ways to accomplish this. + +#. In the unit-test script, add the following shell code snippet before sourcing + the ``shunit2`` library. :: + + setopt shwordsplit + +#. When invoking **zsh** from either the command-line or as a script with + ``#!``, add the ``-y`` parameter. :: + + #! /bin/zsh -y + +#. When invoking **zsh** from the command-line, add ``-o shwordsplit --`` as + parameters before the script name. :: + + $ zsh -o shwordsplit -- some_script + +.. _log4sh: http://log4sh.sourceforge.net/ +.. _log4j: http://logging.apache.org/ +.. _JUnit: http://www.junit.org/ +.. _PyUnit: http://pyunit.sourceforge.net/ +.. _shFlags: http://shflags.googlecode.com/ +.. _shUnit2: http://shunit2.googlecode.com/ +.. _xUnit: http://en.wikipedia.org/wiki/XUnit + +.. generate HTML using rst2html from Docutils of +.. http://docutils.sourceforge.net/ +.. +.. vim:fileencoding=latin1:ft=rst:spell:sts=2:sw=2:tw=80 +.. $Revision: 233 $ diff --git a/eu.esrf.test/src/shunit2-2.1.6/examples/equality_test.sh b/eu.esrf.test/src/shunit2-2.1.6/examples/equality_test.sh new file mode 100755 index 0000000..e0d68a5 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/examples/equality_test.sh @@ -0,0 +1,10 @@ +#! /bin/sh +# file: examples/equality_test.sh + +testEquality() +{ + assertEquals 1 1 +} + +# load shunit2 +. ../src/shunit2 diff --git a/eu.esrf.test/src/shunit2-2.1.6/examples/lineno_test.sh b/eu.esrf.test/src/shunit2-2.1.6/examples/lineno_test.sh new file mode 100755 index 0000000..9c05f1e --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/examples/lineno_test.sh @@ -0,0 +1,16 @@ +#! /bin/sh +# file: examples/lineno_test.sh + +testLineNo() +{ + # this assert will have line numbers included (e.g. "ASSERT:[123] ...") if + # they are supported. + echo "_ASSERT_EQUALS_ macro value: ${_ASSERT_EQUALS_}" + ${_ASSERT_EQUALS_} 'not equal' 1 2 + + # this assert will not have line numbers included (e.g. "ASSERT: ...") + assertEquals 'not equal' 1 2 +} + +# load shunit2 +. ../src/shunit2 diff --git a/eu.esrf.test/src/shunit2-2.1.6/examples/math.inc b/eu.esrf.test/src/shunit2-2.1.6/examples/math.inc new file mode 100755 index 0000000..4097106 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/examples/math.inc @@ -0,0 +1,17 @@ +# available as examples/math.inc + +add_generic() +{ + num_a=$1 + num_b=$2 + + expr $1 + $2 +} + +add_bash() +{ + num_a=$1 + num_b=$2 + + echo $(($1 + $2)) +} diff --git a/eu.esrf.test/src/shunit2-2.1.6/examples/math_test.sh b/eu.esrf.test/src/shunit2-2.1.6/examples/math_test.sh new file mode 100755 index 0000000..41be5ff --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/examples/math_test.sh @@ -0,0 +1,27 @@ +#! /bin/sh +# available as examples/math_test.sh + +testAdding() +{ + result=`add_generic 1 2` + assertEquals \ + "the result of '${result}' was wrong" \ + 3 "${result}" + + # disable non-generic tests + [ -z "${BASH_VERSION:-}" ] && startSkipping + + result=`add_bash 1 2` + assertEquals \ + "the result of '${result}' was wrong" \ + 3 "${result}" +} + +oneTimeSetUp() +{ + # load include to test + . ./math.inc +} + +# load and run shUnit2 +. ../src/shunit2 diff --git a/eu.esrf.test/src/shunit2-2.1.6/examples/mkdir_test.sh b/eu.esrf.test/src/shunit2-2.1.6/examples/mkdir_test.sh new file mode 100755 index 0000000..28d8d94 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/examples/mkdir_test.sh @@ -0,0 +1,89 @@ +#!/bin/sh +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# Example unit test for the mkdir command. +# +# There are times when an existing shell script needs to be tested. In this +# example, we will test several aspects of the the mkdir command, but the +# techniques could be used for any existing shell script. + +#----------------------------------------------------------------------------- +# suite tests +# + +testMissingDirectoryCreation() +{ + ${mkdirCmd} "${testDir}" >${stdoutF} 2>${stderrF} + rtrn=$? + th_assertTrueWithNoOutput ${rtrn} "${stdoutF}" "${stderrF}" + + assertTrue 'directory missing' "[ -d '${testDir}' ]" +} + +testExistingDirectoryCreationFails() +{ + # create a directory to test against + ${mkdirCmd} "${testDir}" + + # test for expected failure while trying to create directory that exists + ${mkdirCmd} "${testDir}" >${stdoutF} 2>${stderrF} + rtrn=$? + assertFalse 'expecting return code of 1 (false)' ${rtrn} + assertNull 'unexpected output to stdout' "`cat ${stdoutF}`" + assertNotNull 'expected error message to stderr' "`cat ${stderrF}`" + + assertTrue 'directory missing' "[ -d '${testDir}' ]" +} + +testRecursiveDirectoryCreation() +{ + testDir2="${testDir}/test2" + + ${mkdirCmd} -p "${testDir2}" >${stdoutF} 2>${stderrF} + rtrn=$? + th_assertTrueWithNoOutput ${rtrn} "${stdoutF}" "${stderrF}" + + assertTrue 'first directory missing' "[ -d '${testDir}' ]" + assertTrue 'second directory missing' "[ -d '${testDir2}' ]" +} + +#----------------------------------------------------------------------------- +# suite functions +# + +th_assertTrueWithNoOutput() +{ + th_return_=$1 + th_stdout_=$2 + th_stderr_=$3 + + assertFalse 'unexpected output to STDOUT' "[ -s '${th_stdout_}' ]" + assertFalse 'unexpected output to STDERR' "[ -s '${th_stderr_}' ]" + + unset th_return_ th_stdout_ th_stderr_ +} + +oneTimeSetUp() +{ + outputDir="${SHUNIT_TMPDIR}/output" + mkdir "${outputDir}" + stdoutF="${outputDir}/stdout" + stderrF="${outputDir}/stderr" + + mkdirCmd='mkdir' # save command name in variable to make future changes easy + testDir="${SHUNIT_TMPDIR}/some_test_dir" +} + +tearDown() +{ + rm -fr "${testDir}" +} + +# load and run shUnit2 +[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 +. ../src/shunit2 diff --git a/eu.esrf.test/src/shunit2-2.1.6/examples/party_test.sh b/eu.esrf.test/src/shunit2-2.1.6/examples/party_test.sh new file mode 100755 index 0000000..5ca2583 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/examples/party_test.sh @@ -0,0 +1,17 @@ +#! /bin/sh +# file: examples/party_test.sh + +testEquality() +{ + assertEquals 1 1 +} + +testPartyLikeItIs1999() +{ + year=`date '+%Y'` + assertEquals "It's not 1999 :-(" \ + '1999' "${year}" +} + +# load shunit2 +. ../src/shunit2 diff --git a/eu.esrf.test/src/shunit2-2.1.6/lib/shflags b/eu.esrf.test/src/shunit2-2.1.6/lib/shflags new file mode 100755 index 0000000..d09867e --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/lib/shflags @@ -0,0 +1,1011 @@ +# $Id: shflags 138 2010-03-18 00:25:34Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# shFlags -- Advanced command-line flag library for Unix shell scripts. +# http://code.google.com/p/shflags/ +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# This module implements something like the google-gflags library available +# from http://code.google.com/p/google-gflags/. +# +# FLAG TYPES: This is a list of the DEFINE_*'s that you can do. All flags take +# a name, default value, help-string, and optional 'short' name (one-letter +# name). Some flags have other arguments, which are described with the flag. +# +# DEFINE_string: takes any input, and intreprets it as a string. +# +# DEFINE_boolean: typically does not take any argument: say --myflag to set +# FLAGS_myflag to true, or --nomyflag to set FLAGS_myflag to false. +# Alternately, you can say +# --myflag=true or --myflag=t or --myflag=0 or +# --myflag=false or --myflag=f or --myflag=1 +# Passing an option has the same affect as passing the option once. +# +# DEFINE_float: takes an input and intreprets it as a floating point number. As +# shell does not support floats per-se, the input is merely validated as +# being a valid floating point value. +# +# DEFINE_integer: takes an input and intreprets it as an integer. +# +# SPECIAL FLAGS: There are a few flags that have special meaning: +# --help (or -?) prints a list of all the flags in a human-readable fashion +# --flagfile=foo read flags from foo. (not implemented yet) +# -- as in getopt(), terminates flag-processing +# +# EXAMPLE USAGE: +# +# -- begin hello.sh -- +# #! /bin/sh +# . ./shflags +# DEFINE_string name 'world' "somebody's name" n +# FLAGS "$@" || exit $? +# eval set -- "${FLAGS_ARGV}" +# echo "Hello, ${FLAGS_name}." +# -- end hello.sh -- +# +# $ ./hello.sh -n Kate +# Hello, Kate. +# +# NOTE: Not all systems include a getopt version that supports long flags. On +# these systems, only short flags are recognized. + +#============================================================================== +# shFlags +# +# Shared attributes: +# flags_error: last error message +# flags_return: last return value +# +# __flags_longNames: list of long names for all flags +# __flags_shortNames: list of short names for all flags +# __flags_boolNames: list of boolean flag names +# +# __flags_opts: options parsed by getopt +# +# Per-flag attributes: +# FLAGS_: contains value of flag named 'flag_name' +# __flags__default: the default flag value +# __flags__help: the flag help string +# __flags__short: the flag short name +# __flags__type: the flag type +# +# Notes: +# - lists of strings are space separated, and a null value is the '~' char. + +# return if FLAGS already loaded +[ -n "${FLAGS_VERSION:-}" ] && return 0 +FLAGS_VERSION='1.0.4pre' + +# return values +FLAGS_TRUE=0 +FLAGS_FALSE=1 +FLAGS_ERROR=2 + +# reserved flag names +FLAGS_RESERVED='ARGC ARGV ERROR FALSE HELP PARENT RESERVED TRUE VERSION' + +_flags_debug() { echo "flags:DEBUG $@" >&2; } +_flags_warn() { echo "flags:WARN $@" >&2; } +_flags_error() { echo "flags:ERROR $@" >&2; } +_flags_fatal() { echo "flags:FATAL $@" >&2; } + +# specific shell checks +if [ -n "${ZSH_VERSION:-}" ]; then + setopt |grep "^shwordsplit$" >/dev/null + if [ $? -ne ${FLAGS_TRUE} ]; then + _flags_fatal 'zsh shwordsplit option is required for proper zsh operation' + exit ${FLAGS_ERROR} + fi + if [ -z "${FLAGS_PARENT:-}" ]; then + _flags_fatal "zsh does not pass \$0 through properly. please declare' \ +\"FLAGS_PARENT=\$0\" before calling shFlags" + exit ${FLAGS_ERROR} + fi +fi + +# +# constants +# + +# getopt version +__FLAGS_GETOPT_VERS_STD=0 +__FLAGS_GETOPT_VERS_ENH=1 +__FLAGS_GETOPT_VERS_BSD=2 + +getopt >/dev/null 2>&1 +case $? in + 0) __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD} ;; # bsd getopt + 2) + # TODO(kward): look into '-T' option to test the internal getopt() version + if [ "`getopt --version`" = '-- ' ]; then + __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD} + else + __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_ENH} + fi + ;; + *) + _flags_fatal 'unable to determine getopt version' + exit ${FLAGS_ERROR} + ;; +esac + +# getopt optstring lengths +__FLAGS_OPTSTR_SHORT=0 +__FLAGS_OPTSTR_LONG=1 + +__FLAGS_NULL='~' + +# flag info strings +__FLAGS_INFO_DEFAULT='default' +__FLAGS_INFO_HELP='help' +__FLAGS_INFO_SHORT='short' +__FLAGS_INFO_TYPE='type' + +# flag lengths +__FLAGS_LEN_SHORT=0 +__FLAGS_LEN_LONG=1 + +# flag types +__FLAGS_TYPE_NONE=0 +__FLAGS_TYPE_BOOLEAN=1 +__FLAGS_TYPE_FLOAT=2 +__FLAGS_TYPE_INTEGER=3 +__FLAGS_TYPE_STRING=4 + +# set the constants readonly +__flags_constants=`set |awk -F= '/^FLAGS_/ || /^__FLAGS_/ {print $1}'` +for __flags_const in ${__flags_constants}; do + # skip certain flags + case ${__flags_const} in + FLAGS_HELP) continue ;; + FLAGS_PARENT) continue ;; + esac + # set flag readonly + if [ -z "${ZSH_VERSION:-}" ]; then + readonly ${__flags_const} + else # handle zsh + case ${ZSH_VERSION} in + [123].*) readonly ${__flags_const} ;; + *) readonly -g ${__flags_const} ;; # declare readonly constants globally + esac + fi +done +unset __flags_const __flags_constants + +# +# internal variables +# + +__flags_boolNames=' ' # space separated list of boolean flag names +__flags_longNames=' ' # space separated list of long flag names +__flags_shortNames=' ' # space separated list of short flag names + +__flags_columns='' # screen width in columns +__flags_opts='' # temporary storage for parsed getopt flags + +#------------------------------------------------------------------------------ +# private functions +# + +# Define a flag. +# +# Calling this function will define the following info variables for the +# specified flag: +# FLAGS_flagname - the name for this flag (based upon the long flag name) +# __flags__default - the default value +# __flags_flagname_help - the help string +# __flags_flagname_short - the single letter alias +# __flags_flagname_type - the type of flag (one of __FLAGS_TYPE_*) +# +# Args: +# _flags__type: integer: internal type of flag (__FLAGS_TYPE_*) +# _flags__name: string: long flag name +# _flags__default: default flag value +# _flags__help: string: help string +# _flags__short: string: (optional) short flag name +# Returns: +# integer: success of operation, or error +_flags_define() +{ + if [ $# -lt 4 ]; then + flags_error='DEFINE error: too few arguments' + flags_return=${FLAGS_ERROR} + _flags_error "${flags_error}" + return ${flags_return} + fi + + _flags_type_=$1 + _flags_name_=$2 + _flags_default_=$3 + _flags_help_=$4 + _flags_short_=${5:-${__FLAGS_NULL}} + + _flags_return_=${FLAGS_TRUE} + + # TODO(kward): check for validity of the flag name (e.g. dashes) + + # check whether the flag name is reserved + echo " ${FLAGS_RESERVED} " |grep " ${_flags_name_} " >/dev/null + if [ $? -eq 0 ]; then + flags_error="flag name (${_flags_name_}) is reserved" + _flags_return_=${FLAGS_ERROR} + fi + + # require short option for getopt that don't support long options + if [ ${_flags_return_} -eq ${FLAGS_TRUE} \ + -a ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} \ + -a "${_flags_short_}" = "${__FLAGS_NULL}" ] + then + flags_error="short flag required for (${_flags_name_}) on this platform" + _flags_return_=${FLAGS_ERROR} + fi + + # check for existing long name definition + if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then + if _flags_itemInList "${_flags_name_}" \ + ${__flags_longNames} ${__flags_boolNames} + then + flags_error="flag name ([no]${_flags_name_}) already defined" + _flags_warn "${flags_error}" + _flags_return_=${FLAGS_FALSE} + fi + fi + + # check for existing short name definition + if [ ${_flags_return_} -eq ${FLAGS_TRUE} \ + -a "${_flags_short_}" != "${__FLAGS_NULL}" ] + then + if _flags_itemInList "${_flags_short_}" ${__flags_shortNames}; then + flags_error="flag short name (${_flags_short_}) already defined" + _flags_warn "${flags_error}" + _flags_return_=${FLAGS_FALSE} + fi + fi + + # handle default value. note, on several occasions the 'if' portion of an + # if/then/else contains just a ':' which does nothing. a binary reversal via + # '!' is not done because it does not work on all shells. + if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then + case ${_flags_type_} in + ${__FLAGS_TYPE_BOOLEAN}) + if _flags_validateBoolean "${_flags_default_}"; then + case ${_flags_default_} in + true|t|0) _flags_default_=${FLAGS_TRUE} ;; + false|f|1) _flags_default_=${FLAGS_FALSE} ;; + esac + else + flags_error="invalid default flag value '${_flags_default_}'" + _flags_return_=${FLAGS_ERROR} + fi + ;; + + ${__FLAGS_TYPE_FLOAT}) + if _flags_validateFloat "${_flags_default_}"; then + : + else + flags_error="invalid default flag value '${_flags_default_}'" + _flags_return_=${FLAGS_ERROR} + fi + ;; + + ${__FLAGS_TYPE_INTEGER}) + if _flags_validateInteger "${_flags_default_}"; then + : + else + flags_error="invalid default flag value '${_flags_default_}'" + _flags_return_=${FLAGS_ERROR} + fi + ;; + + ${__FLAGS_TYPE_STRING}) ;; # everything in shell is a valid string + + *) + flags_error="unrecognized flag type '${_flags_type_}'" + _flags_return_=${FLAGS_ERROR} + ;; + esac + fi + + if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then + # store flag information + eval "FLAGS_${_flags_name_}='${_flags_default_}'" + eval "__flags_${_flags_name_}_${__FLAGS_INFO_TYPE}=${_flags_type_}" + eval "__flags_${_flags_name_}_${__FLAGS_INFO_DEFAULT}=\ +\"${_flags_default_}\"" + eval "__flags_${_flags_name_}_${__FLAGS_INFO_HELP}=\"${_flags_help_}\"" + eval "__flags_${_flags_name_}_${__FLAGS_INFO_SHORT}='${_flags_short_}'" + + # append flag name(s) to list of names + __flags_longNames="${__flags_longNames}${_flags_name_} " + __flags_shortNames="${__flags_shortNames}${_flags_short_} " + [ ${_flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] && \ + __flags_boolNames="${__flags_boolNames}no${_flags_name_} " + fi + + flags_return=${_flags_return_} + unset _flags_default_ _flags_help_ _flags_name_ _flags_return_ _flags_short_ \ + _flags_type_ + [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}" + return ${flags_return} +} + +# Return valid getopt options using currently defined list of long options. +# +# This function builds a proper getopt option string for short (and long) +# options, using the current list of long options for reference. +# +# Args: +# _flags_optStr: integer: option string type (__FLAGS_OPTSTR_*) +# Output: +# string: generated option string for getopt +# Returns: +# boolean: success of operation (always returns True) +_flags_genOptStr() +{ + _flags_optStrType_=$1 + + _flags_opts_='' + + for _flags_flag_ in ${__flags_longNames}; do + _flags_type_=`_flags_getFlagInfo ${_flags_flag_} ${__FLAGS_INFO_TYPE}` + case ${_flags_optStrType_} in + ${__FLAGS_OPTSTR_SHORT}) + _flags_shortName_=`_flags_getFlagInfo \ + ${_flags_flag_} ${__FLAGS_INFO_SHORT}` + if [ "${_flags_shortName_}" != "${__FLAGS_NULL}" ]; then + _flags_opts_="${_flags_opts_}${_flags_shortName_}" + # getopt needs a trailing ':' to indicate a required argument + [ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \ + _flags_opts_="${_flags_opts_}:" + fi + ;; + + ${__FLAGS_OPTSTR_LONG}) + _flags_opts_="${_flags_opts_:+${_flags_opts_},}${_flags_flag_}" + # getopt needs a trailing ':' to indicate a required argument + [ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \ + _flags_opts_="${_flags_opts_}:" + ;; + esac + done + + echo "${_flags_opts_}" + unset _flags_flag_ _flags_opts_ _flags_optStrType_ _flags_shortName_ \ + _flags_type_ + return ${FLAGS_TRUE} +} + +# Returns flag details based on a flag name and flag info. +# +# Args: +# string: long flag name +# string: flag info (see the _flags_define function for valid info types) +# Output: +# string: value of dereferenced flag variable +# Returns: +# integer: one of FLAGS_{TRUE|FALSE|ERROR} +_flags_getFlagInfo() +{ + _flags_name_=$1 + _flags_info_=$2 + + _flags_nameVar_="__flags_${_flags_name_}_${_flags_info_}" + _flags_strToEval_="_flags_value_=\"\${${_flags_nameVar_}:-}\"" + eval "${_flags_strToEval_}" + if [ -n "${_flags_value_}" ]; then + flags_return=${FLAGS_TRUE} + else + # see if the _flags_name_ variable is a string as strings can be empty... + # note: the DRY principle would say to have this function call itself for + # the next three lines, but doing so results in an infinite loop as an + # invalid _flags_name_ will also not have the associated _type variable. + # Because it doesn't (it will evaluate to an empty string) the logic will + # try to find the _type variable of the _type variable, and so on. Not so + # good ;-) + _flags_typeVar_="__flags_${_flags_name_}_${__FLAGS_INFO_TYPE}" + _flags_strToEval_="_flags_type_=\"\${${_flags_typeVar_}:-}\"" + eval "${_flags_strToEval_}" + if [ "${_flags_type_}" = "${__FLAGS_TYPE_STRING}" ]; then + flags_return=${FLAGS_TRUE} + else + flags_return=${FLAGS_ERROR} + flags_error="invalid flag name (${_flags_nameVar_})" + fi + fi + + echo "${_flags_value_}" + unset _flags_info_ _flags_name_ _flags_strToEval_ _flags_type_ _flags_value_ \ + _flags_nameVar_ _flags_typeVar_ + [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}" + return ${flags_return} +} + +# check for presense of item in a list. passed a string (e.g. 'abc'), this +# function will determine if the string is present in the list of strings (e.g. +# ' foo bar abc '). +# +# Args: +# _flags__str: string: string to search for in a list of strings +# unnamed: list: list of strings +# Returns: +# boolean: true if item is in the list +_flags_itemInList() +{ + _flags_str_=$1 + shift + + echo " ${*:-} " |grep " ${_flags_str_} " >/dev/null + if [ $? -eq 0 ]; then + flags_return=${FLAGS_TRUE} + else + flags_return=${FLAGS_FALSE} + fi + + unset _flags_str_ + return ${flags_return} +} + +# Returns the width of the current screen. +# +# Output: +# integer: width in columns of the current screen. +_flags_columns() +{ + if [ -z "${__flags_columns}" ]; then + # determine the value and store it + if eval stty size >/dev/null 2>&1; then + # stty size worked :-) + set -- `stty size` + __flags_columns=$2 + elif eval tput cols >/dev/null 2>&1; then + set -- `tput cols` + __flags_columns=$1 + else + __flags_columns=80 # default terminal width + fi + fi + echo ${__flags_columns} +} + +# Validate a boolean. +# +# Args: +# _flags__bool: boolean: value to validate +# Returns: +# bool: true if the value is a valid boolean +_flags_validateBoolean() +{ + _flags_bool_=$1 + + flags_return=${FLAGS_TRUE} + case "${_flags_bool_}" in + true|t|0) ;; + false|f|1) ;; + *) flags_return=${FLAGS_FALSE} ;; + esac + + unset _flags_bool_ + return ${flags_return} +} + +# Validate a float. +# +# Args: +# _flags__float: float: value to validate +# Returns: +# bool: true if the value is a valid float +_flags_validateFloat() +{ + _flags_float_=$1 + + if _flags_validateInteger ${_flags_float_}; then + flags_return=${FLAGS_TRUE} + else + flags_return=${FLAGS_TRUE} + case ${_flags_float_} in + -*) # negative floats + _flags_test_=`expr -- "${_flags_float_}" :\ + '\(-[0-9][0-9]*\.[0-9][0-9]*\)'` + ;; + *) # positive floats + _flags_test_=`expr -- "${_flags_float_}" :\ + '\([0-9][0-9]*\.[0-9][0-9]*\)'` + ;; + esac + [ "${_flags_test_}" != "${_flags_float_}" ] && flags_return=${FLAGS_FALSE} + fi + + unset _flags_float_ _flags_test_ + return ${flags_return} +} + +# Validate an integer. +# +# Args: +# _flags__integer: interger: value to validate +# Returns: +# bool: true if the value is a valid integer +_flags_validateInteger() +{ + _flags_int_=$1 + + flags_return=${FLAGS_TRUE} + case ${_flags_int_} in + -*) # negative ints + _flags_test_=`expr -- "${_flags_int_}" : '\(-[0-9][0-9]*\)'` + ;; + *) # positive ints + _flags_test_=`expr -- "${_flags_int_}" : '\([0-9][0-9]*\)'` + ;; + esac + [ "${_flags_test_}" != "${_flags_int_}" ] && flags_return=${FLAGS_FALSE} + + unset _flags_int_ _flags_test_ + return ${flags_return} +} + +# Parse command-line options using the standard getopt. +# +# Note: the flag options are passed around in the global __flags_opts so that +# the formatting is not lost due to shell parsing and such. +# +# Args: +# @: varies: command-line options to parse +# Returns: +# integer: a FLAGS success condition +_flags_getoptStandard() +{ + flags_return=${FLAGS_TRUE} + _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}` + + # check for spaces in passed options + for _flags_opt_ in "$@"; do + # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06 + _flags_match_=`echo "x${_flags_opt_}x" |sed 's/ //g'` + if [ "${_flags_match_}" != "x${_flags_opt_}x" ]; then + flags_error='the available getopt does not support spaces in options' + flags_return=${FLAGS_ERROR} + break + fi + done + + if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then + __flags_opts=`getopt ${_flags_shortOpts_} $@ 2>&1` + _flags_rtrn_=$? + if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then + _flags_warn "${__flags_opts}" + flags_error='unable to parse provided options with getopt.' + flags_return=${FLAGS_ERROR} + fi + fi + + unset _flags_match_ _flags_opt_ _flags_rtrn_ _flags_shortOpts_ + return ${flags_return} +} + +# Parse command-line options using the enhanced getopt. +# +# Note: the flag options are passed around in the global __flags_opts so that +# the formatting is not lost due to shell parsing and such. +# +# Args: +# @: varies: command-line options to parse +# Returns: +# integer: a FLAGS success condition +_flags_getoptEnhanced() +{ + flags_return=${FLAGS_TRUE} + _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}` + _flags_boolOpts_=`echo "${__flags_boolNames}" \ + |sed 's/^ *//;s/ *$//;s/ /,/g'` + _flags_longOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_LONG}` + + __flags_opts=`getopt \ + -o ${_flags_shortOpts_} \ + -l "${_flags_longOpts_},${_flags_boolOpts_}" \ + -- "$@" 2>&1` + _flags_rtrn_=$? + if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then + _flags_warn "${__flags_opts}" + flags_error='unable to parse provided options with getopt.' + flags_return=${FLAGS_ERROR} + fi + + unset _flags_boolOpts_ _flags_longOpts_ _flags_rtrn_ _flags_shortOpts_ + return ${flags_return} +} + +# Dynamically parse a getopt result and set appropriate variables. +# +# This function does the actual conversion of getopt output and runs it through +# the standard case structure for parsing. The case structure is actually quite +# dynamic to support any number of flags. +# +# Args: +# argc: int: original command-line argument count +# @: varies: output from getopt parsing +# Returns: +# integer: a FLAGS success condition +_flags_parseGetopt() +{ + _flags_argc_=$1 + shift + + flags_return=${FLAGS_TRUE} + + if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then + set -- $@ + else + # note the quotes around the `$@' -- they are essential! + eval set -- "$@" + fi + + # provide user with number of arguments to shift by later + # NOTE: the FLAGS_ARGC variable is obsolete as of 1.0.3 because it does not + # properly give user access to non-flag arguments mixed in between flag + # arguments. Its usage was replaced by FLAGS_ARGV, and it is being kept only + # for backwards compatibility reasons. + FLAGS_ARGC=`expr $# - 1 - ${_flags_argc_}` + + # handle options. note options with values must do an additional shift + while true; do + _flags_opt_=$1 + _flags_arg_=${2:-} + _flags_type_=${__FLAGS_TYPE_NONE} + _flags_name_='' + + # determine long flag name + case "${_flags_opt_}" in + --) shift; break ;; # discontinue option parsing + + --*) # long option + _flags_opt_=`expr -- "${_flags_opt_}" : '--\(.*\)'` + _flags_len_=${__FLAGS_LEN_LONG} + if _flags_itemInList "${_flags_opt_}" ${__flags_longNames}; then + _flags_name_=${_flags_opt_} + else + # check for negated long boolean version + if _flags_itemInList "${_flags_opt_}" ${__flags_boolNames}; then + _flags_name_=`expr -- "${_flags_opt_}" : 'no\(.*\)'` + _flags_type_=${__FLAGS_TYPE_BOOLEAN} + _flags_arg_=${__FLAGS_NULL} + fi + fi + ;; + + -*) # short option + _flags_opt_=`expr -- "${_flags_opt_}" : '-\(.*\)'` + _flags_len_=${__FLAGS_LEN_SHORT} + if _flags_itemInList "${_flags_opt_}" ${__flags_shortNames}; then + # yes. match short name to long name. note purposeful off-by-one + # (too high) with awk calculations. + _flags_pos_=`echo "${__flags_shortNames}" \ + |awk 'BEGIN{RS=" ";rn=0}$0==e{rn=NR}END{print rn}' \ + e=${_flags_opt_}` + _flags_name_=`echo "${__flags_longNames}" \ + |awk 'BEGIN{RS=" "}rn==NR{print $0}' rn="${_flags_pos_}"` + fi + ;; + esac + + # die if the flag was unrecognized + if [ -z "${_flags_name_}" ]; then + flags_error="unrecognized option (${_flags_opt_})" + flags_return=${FLAGS_ERROR} + break + fi + + # set new flag value + [ ${_flags_type_} -eq ${__FLAGS_TYPE_NONE} ] && \ + _flags_type_=`_flags_getFlagInfo \ + "${_flags_name_}" ${__FLAGS_INFO_TYPE}` + case ${_flags_type_} in + ${__FLAGS_TYPE_BOOLEAN}) + if [ ${_flags_len_} -eq ${__FLAGS_LEN_LONG} ]; then + if [ "${_flags_arg_}" != "${__FLAGS_NULL}" ]; then + eval "FLAGS_${_flags_name_}=${FLAGS_TRUE}" + else + eval "FLAGS_${_flags_name_}=${FLAGS_FALSE}" + fi + else + _flags_strToEval_="_flags_val_=\ +\${__flags_${_flags_name_}_${__FLAGS_INFO_DEFAULT}}" + eval "${_flags_strToEval_}" + if [ ${_flags_val_} -eq ${FLAGS_FALSE} ]; then + eval "FLAGS_${_flags_name_}=${FLAGS_TRUE}" + else + eval "FLAGS_${_flags_name_}=${FLAGS_FALSE}" + fi + fi + ;; + + ${__FLAGS_TYPE_FLOAT}) + if _flags_validateFloat "${_flags_arg_}"; then + eval "FLAGS_${_flags_name_}='${_flags_arg_}'" + else + flags_error="invalid float value (${_flags_arg_})" + flags_return=${FLAGS_ERROR} + break + fi + ;; + + ${__FLAGS_TYPE_INTEGER}) + if _flags_validateInteger "${_flags_arg_}"; then + eval "FLAGS_${_flags_name_}='${_flags_arg_}'" + else + flags_error="invalid integer value (${_flags_arg_})" + flags_return=${FLAGS_ERROR} + break + fi + ;; + + ${__FLAGS_TYPE_STRING}) + eval "FLAGS_${_flags_name_}='${_flags_arg_}'" + ;; + esac + + # handle special case help flag + if [ "${_flags_name_}" = 'help' ]; then + if [ ${FLAGS_help} -eq ${FLAGS_TRUE} ]; then + flags_help + flags_error='help requested' + flags_return=${FLAGS_FALSE} + break + fi + fi + + # shift the option and non-boolean arguements out. + shift + [ ${_flags_type_} != ${__FLAGS_TYPE_BOOLEAN} ] && shift + done + + # give user back non-flag arguments + FLAGS_ARGV='' + while [ $# -gt 0 ]; do + FLAGS_ARGV="${FLAGS_ARGV:+${FLAGS_ARGV} }'$1'" + shift + done + + unset _flags_arg_ _flags_len_ _flags_name_ _flags_opt_ _flags_pos_ \ + _flags_strToEval_ _flags_type_ _flags_val_ + return ${flags_return} +} + +#------------------------------------------------------------------------------ +# public functions +# + +# A basic boolean flag. Boolean flags do not take any arguments, and their +# value is either 1 (false) or 0 (true). For long flags, the false value is +# specified on the command line by prepending the word 'no'. With short flags, +# the presense of the flag toggles the current value between true and false. +# Specifying a short boolean flag twice on the command results in returning the +# value back to the default value. +# +# A default value is required for boolean flags. +# +# For example, lets say a Boolean flag was created whose long name was 'update' +# and whose short name was 'x', and the default value was 'false'. This flag +# could be explicitly set to 'true' with '--update' or by '-x', and it could be +# explicitly set to 'false' with '--noupdate'. +DEFINE_boolean() { _flags_define ${__FLAGS_TYPE_BOOLEAN} "$@"; } + +# Other basic flags. +DEFINE_float() { _flags_define ${__FLAGS_TYPE_FLOAT} "$@"; } +DEFINE_integer() { _flags_define ${__FLAGS_TYPE_INTEGER} "$@"; } +DEFINE_string() { _flags_define ${__FLAGS_TYPE_STRING} "$@"; } + +# Parse the flags. +# +# Args: +# unnamed: list: command-line flags to parse +# Returns: +# integer: success of operation, or error +FLAGS() +{ + # define a standard 'help' flag if one isn't already defined + [ -z "${__flags_help_type:-}" ] && \ + DEFINE_boolean 'help' false 'show this help' 'h' + + # parse options + if [ $# -gt 0 ]; then + if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then + _flags_getoptStandard "$@" + else + _flags_getoptEnhanced "$@" + fi + flags_return=$? + else + # nothing passed; won't bother running getopt + __flags_opts='--' + flags_return=${FLAGS_TRUE} + fi + + if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then + _flags_parseGetopt $# "${__flags_opts}" + flags_return=$? + fi + + [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_fatal "${flags_error}" + return ${flags_return} +} + +# This is a helper function for determining the `getopt` version for platforms +# where the detection isn't working. It simply outputs debug information that +# can be included in a bug report. +# +# Args: +# none +# Output: +# debug info that can be included in a bug report +# Returns: +# nothing +flags_getoptInfo() +{ + # platform info + _flags_debug "uname -a: `uname -a`" + _flags_debug "PATH: ${PATH}" + + # shell info + if [ -n "${BASH_VERSION:-}" ]; then + _flags_debug 'shell: bash' + _flags_debug "BASH_VERSION: ${BASH_VERSION}" + elif [ -n "${ZSH_VERSION:-}" ]; then + _flags_debug 'shell: zsh' + _flags_debug "ZSH_VERSION: ${ZSH_VERSION}" + fi + + # getopt info + getopt >/dev/null + _flags_getoptReturn=$? + _flags_debug "getopt return: ${_flags_getoptReturn}" + _flags_debug "getopt --version: `getopt --version 2>&1`" + + unset _flags_getoptReturn +} + +# Returns whether the detected getopt version is the enhanced version. +# +# Args: +# none +# Output: +# none +# Returns: +# bool: true if getopt is the enhanced version +flags_getoptIsEnh() +{ + test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} +} + +# Returns whether the detected getopt version is the standard version. +# +# Args: +# none +# Returns: +# bool: true if getopt is the standard version +flags_getoptIsStd() +{ + test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD} +} + +# This is effectively a 'usage()' function. It prints usage information and +# exits the program with ${FLAGS_FALSE} if it is ever found in the command line +# arguments. Note this function can be overridden so other apps can define +# their own --help flag, replacing this one, if they want. +# +# Args: +# none +# Returns: +# integer: success of operation (always returns true) +flags_help() +{ + if [ -n "${FLAGS_HELP:-}" ]; then + echo "${FLAGS_HELP}" >&2 + else + echo "USAGE: ${FLAGS_PARENT:-$0} [flags] args" >&2 + fi + if [ -n "${__flags_longNames}" ]; then + echo 'flags:' >&2 + for flags_name_ in ${__flags_longNames}; do + flags_flagStr_='' + flags_boolStr_='' + + flags_default_=`_flags_getFlagInfo \ + "${flags_name_}" ${__FLAGS_INFO_DEFAULT}` + flags_help_=`_flags_getFlagInfo \ + "${flags_name_}" ${__FLAGS_INFO_HELP}` + flags_short_=`_flags_getFlagInfo \ + "${flags_name_}" ${__FLAGS_INFO_SHORT}` + flags_type_=`_flags_getFlagInfo \ + "${flags_name_}" ${__FLAGS_INFO_TYPE}` + + [ "${flags_short_}" != "${__FLAGS_NULL}" ] \ + && flags_flagStr_="-${flags_short_}" + + if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ]; then + [ "${flags_short_}" != "${__FLAGS_NULL}" ] \ + && flags_flagStr_="${flags_flagStr_}," + [ ${flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] \ + && flags_boolStr_='[no]' + flags_flagStr_="${flags_flagStr_}--${flags_boolStr_}${flags_name_}:" + fi + + case ${flags_type_} in + ${__FLAGS_TYPE_BOOLEAN}) + if [ ${flags_default_} -eq ${FLAGS_TRUE} ]; then + flags_defaultStr_='true' + else + flags_defaultStr_='false' + fi + ;; + ${__FLAGS_TYPE_FLOAT}|${__FLAGS_TYPE_INTEGER}) + flags_defaultStr_=${flags_default_} ;; + ${__FLAGS_TYPE_STRING}) flags_defaultStr_="'${flags_default_}'" ;; + esac + flags_defaultStr_="(default: ${flags_defaultStr_})" + + flags_helpStr_=" ${flags_flagStr_} ${flags_help_} ${flags_defaultStr_}" + flags_helpStrLen_=`expr -- "${flags_helpStr_}" : '.*'` + flags_columns_=`_flags_columns` + if [ ${flags_helpStrLen_} -lt ${flags_columns_} ]; then + echo "${flags_helpStr_}" >&2 + else + echo " ${flags_flagStr_} ${flags_help_}" >&2 + # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06 + # because it doesn't like empty strings when used in this manner. + flags_emptyStr_="`echo \"x${flags_flagStr_}x\" \ + |awk '{printf "%"length($0)-2"s", ""}'`" + flags_helpStr_=" ${flags_emptyStr_} ${flags_defaultStr_}" + flags_helpStrLen_=`expr -- "${flags_helpStr_}" : '.*'` + if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD} \ + -o ${flags_helpStrLen_} -lt ${flags_columns_} ]; then + # indented to match help string + echo "${flags_helpStr_}" >&2 + else + # indented four from left to allow for longer defaults as long flag + # names might be used too, making things too long + echo " ${flags_defaultStr_}" >&2 + fi + fi + done + fi + + unset flags_boolStr_ flags_default_ flags_defaultStr_ flags_emptyStr_ \ + flags_flagStr_ flags_help_ flags_helpStr flags_helpStrLen flags_name_ \ + flags_columns_ flags_short_ flags_type_ + return ${FLAGS_TRUE} +} + +# Reset shflags back to an uninitialized state. +# +# Args: +# none +# Returns: +# nothing +flags_reset() +{ + for flags_name_ in ${__flags_longNames}; do + flags_strToEval_="unset FLAGS_${flags_name_}" + for flags_type_ in \ + ${__FLAGS_INFO_DEFAULT} \ + ${__FLAGS_INFO_HELP} \ + ${__FLAGS_INFO_SHORT} \ + ${__FLAGS_INFO_TYPE} + do + flags_strToEval_=\ +"${flags_strToEval_} __flags_${flags_name_}_${flags_type_}" + done + eval ${flags_strToEval_} + done + + # reset internal variables + __flags_boolNames=' ' + __flags_longNames=' ' + __flags_shortNames=' ' + + unset flags_name_ flags_type_ flags_strToEval_ +} diff --git a/eu.esrf.test/src/shunit2-2.1.6/lib/shlib b/eu.esrf.test/src/shunit2-2.1.6/lib/shlib new file mode 100755 index 0000000..b5d5779 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/lib/shlib @@ -0,0 +1,39 @@ +# $Id: shlib 14 2007-02-18 19:43:41Z sfsetse $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License). +# Author: kate.ward@forestent.com (Kate Ward) +# +# Library of shell functions. + +# Convert a relative path into it's absolute equivalent. +# +# This function will automatically prepend the current working directory if the +# path is not already absolute. It then removes all parent references (../) to +# reconstruct the proper absolute path. +# +# Args: +# shlib_path_: string: relative path +# Outputs: +# string: absolute path +shlib_relToAbsPath() +{ + shlib_path_=$1 + + # prepend current directory to relative paths + echo "${shlib_path_}" |grep '^/' >/dev/null 2>&1 \ + || shlib_path_="`pwd`/${shlib_path_}" + + # clean up the path. if all seds supported true regular expressions, then + # this is what it would be: + shlib_old_=${shlib_path_} + while true; do + shlib_new_=`echo "${shlib_old_}" |sed 's/[^/]*\/\.\.\/*//g;s/\/\.\//\//'` + [ "${shlib_old_}" = "${shlib_new_}" ] && break + shlib_old_=${shlib_new_} + done + echo "${shlib_new_}" + + unset shlib_path_ shlib_old_ shlib_new_ +} diff --git a/eu.esrf.test/src/shunit2-2.1.6/lib/versions b/eu.esrf.test/src/shunit2-2.1.6/lib/versions new file mode 100755 index 0000000..b874d80 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/lib/versions @@ -0,0 +1,227 @@ +#! /bin/sh +# $Id: versions 100 2008-11-15 20:24:03Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# This library provides reusable functions that determine actual names and +# versions of installed shells and the OS. The library can also be run as a +# script if set execuatable. + +ARGV0=`basename "$0"` +LSB_RELEASE='/etc/lsb-release' +VERSIONS_SHELLS="/bin/bash /bin/dash /bin/ksh /bin/pdksh /bin/sh /bin/zsh" + +TRUE=0 +FALSE=1 +ERROR=2 + +__versions_haveStrings=${ERROR} + +#------------------------------------------------------------------------------ +# functions +# + +versions_osName() +{ + os_name_='unrecognized' + os_system_=`uname -s` + case ${os_system_} in + CYGWIN_NT-*) os_name_='Cygwin' ;; + Darwin) os_name_='Mac OS X' ;; + FreeBSD) os_name_='FreeBSD' ;; + Linux) os_name_='Linux' ;; + SunOS) + if grep 'OpenSolaris' /etc/release >/dev/null; then + os_name_='OpenSolaris' + else + os_name_='Solaris' + fi + ;; + esac + echo ${os_name_} + unset os_name_ os_system_ +} + +versions_osVersion() +{ + os_version_='unrecognized' + os_system_=`uname -s` + os_release_=`uname -r` + case ${os_system_} in + CYGWIN_NT-*) + os_version_=`expr "${os_release_}" : '\([0-9]*\.[0-9]\.[0-9]*\).*'` + ;; + Darwin) + major_='10' + sub_=`echo ${os_release_} |sed 's/^[0-9]*\.\([0-9]*\)\.[0-9]*$/\1/'` + case ${os_release_} in + 8.*) minor_='4' ;; + 9.*) minor_='5' ;; + 10.*) minor_='6' ;; + *) minor_='X'; sub_='X' ;; + esac + os_version_="${major_}.${minor_}.${sub_}" + ;; + FreeBSD) + os_version_=`expr "${os_release_}" : '\([0-9]*\.[0-9]*\)-.*'` + ;; + Linux) + if [ -r "${LSB_RELEASE}" ]; then + if grep -q 'DISTRIB_ID=Ubuntu' "${LSB_RELEASE}"; then + os_version_=`cat "${LSB_RELEASE}" \ + |awk -F= '$1~/DISTRIB_DESCRIPTION/{print $2}' \ + |sed 's/"//g;s/ /-/g'` + fi + elif [ -r '/etc/redhat-release' ]; then + os_version_=`cat /etc/redhat-release` + fi + ;; + SunOS) + if grep 'OpenSolaris' /etc/release >/dev/null; then + os_version_=`grep 'OpenSolaris' /etc/release |awk '{print $2"("$3")"}'` + else + major_=`echo ${os_release_} |sed 's/[0-9]*\.\([0-9]*\)/\1/'` + minor_=`grep Solaris /etc/release |sed 's/[^u]*\(u[0-9]*\).*/\1/'` + os_version_="${major_}${minor_}" + fi + ;; + esac + echo ${os_version_} + unset os_name_ os_release_ os_version_ major_ minor_ sub_ +} + +versions_shellVersion() +{ + shell_=$1 + + if [ ! -x "${shell_}" ]; then + echo 'not installed' + return + fi + + version_='' + case ${shell_} in + */sh) + # TODO(kward): fix this + ## this could be one of any number of shells. try until one fits. + #version_=`versions_shell_bash ${shell_}` + ## dash cannot be self determined yet + #[ -z "${version_}" ] && version_=`versions_shell_ksh ${shell_}` + ## pdksh is covered in versions_shell_ksh() + #[ -z "${version_}" ] && version_=`versions_shell_zsh ${shell_}` + ;; + */bash) version_=`versions_shell_bash ${shell_}` ;; + */dash) + # simply assuming Ubuntu Linux until somebody comes up with a better + # test. the following test will return an empty string if dash is not + # installed. + version_=`versions_shell_dash` + ;; + */ksh) version_=`versions_shell_ksh ${shell_}` ;; + */pdksh) version_=`versions_shell_pdksh ${shell_}` ;; + */zsh) version_=`versions_shell_zsh ${shell_}` ;; + *) version_='invalid' + esac + + echo ${version_:-unknown} + unset shell_ version_ +} + +versions_shell_bash() +{ + $1 --version 2>&1 |grep 'GNU bash' |sed 's/.*version \([^ ]*\).*/\1/' +} + +versions_shell_dash() +{ + eval dpkg >/dev/null 2>&1 + [ $? -eq 127 ] && return # return if dpkg not found + + dpkg -l |grep ' dash ' |awk '{print $3}' +} + +versions_shell_ksh() +{ + versions_shell_=$1 + + # see if --version gives a result + versions_version_=`${versions_shell_} --version 2>&1 \ + |sed 's/.*\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\).*/\1/'` + + # --version didn't work... look into the binary + if [ $? -ne ${TRUE} ]; then + _versions_have_strings + versions_version_=`strings ${versions_shell_} 2>&1 \ + |grep Version \ + |sed 's/^.*Version \(.*\)$/\1/;s/ s+ \$$//;s/ /-/g'` + [ -z "${versions_version_}" ] \ + && versions_version_=`versions_shell_pdksh ${versions_shell_}` + fi + + echo ${versions_version_} + + unset versions_shell_ versions_version_ +} + +versions_shell_pdksh() +{ + _versions_have_strings + strings $1 2>&1 \ + |grep 'PD KSH' \ + |sed -e 's/.*PD KSH \(.*\)/\1/;s/ /-/g' +} + +versions_shell_zsh() +{ + versions_shell_=$1 + + versions_version_=`${versions_shell_} --version 2>&1 |awk '{print $2}'` + + if [ $? -ne ${TRUE} ]; then + versions_version_=`echo 'echo ${ZSH_VERSION}' |${versions_shell_}` + fi + + echo ${versions_version_} + + unset versions_shell_ versions_version_ +} + +# Determine if the 'strings' binary installed. +_versions_have_strings() +{ + [ ${__versions_haveStrings} -ne ${ERROR} ] && return + eval strings /dev/null >/dev/null 2>&1 + if [ $? -eq 0 ]; then + __versions_haveStrings=${TRUE} + else + echo 'WARN: strings not installed. try installing binutils?' >&2 + __versions_haveStrings=${FALSE} + fi +} + +#------------------------------------------------------------------------------ +# main +# + +versions_main() +{ + # treat unset variables as an error + set -u + + os_name=`versions_osName` + os_version=`versions_osVersion` + echo "os: ${os_name} version: ${os_version}" + + for shell in ${VERSIONS_SHELLS}; do + shell_version=`versions_shellVersion ${shell}` + echo "shell: ${shell} version: ${shell_version}" + done +} + +if [ "${ARGV0}" = 'versions' ]; then + versions_main "$@" +fi diff --git a/eu.esrf.test/src/shunit2-2.1.6/src/shunit2 b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2 new file mode 100755 index 0000000..8862ffd --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2 @@ -0,0 +1,1048 @@ +#! /bin/sh +# $Id: shunit2 335 2011-05-01 20:10:33Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# shUnit2 -- Unit testing framework for Unix shell scripts. +# http://code.google.com/p/shunit2/ +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 is a xUnit based unit test framework for Bourne shell scripts. It is +# based on the popular JUnit unit testing framework for Java. + +# return if shunit already loaded +[ -n "${SHUNIT_VERSION:-}" ] && exit 0 + +SHUNIT_VERSION='2.1.6' + +SHUNIT_TRUE=0 +SHUNIT_FALSE=1 +SHUNIT_ERROR=2 + +# enable strict mode by default +SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} + +_shunit_warn() { echo "shunit2:WARN $@" >&2; } +_shunit_error() { echo "shunit2:ERROR $@" >&2; } +_shunit_fatal() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; } + +# specific shell checks +if [ -n "${ZSH_VERSION:-}" ]; then + setopt |grep "^shwordsplit$" >/dev/null + if [ $? -ne ${SHUNIT_TRUE} ]; then + _shunit_fatal 'zsh shwordsplit option is required for proper operation' + fi + if [ -z "${SHUNIT_PARENT:-}" ]; then + _shunit_fatal "zsh does not pass \$0 through properly. please declare \ +\"SHUNIT_PARENT=\$0\" before calling shUnit2" + fi +fi + +# +# constants +# + +__SHUNIT_ASSERT_MSG_PREFIX='ASSERT:' +__SHUNIT_MODE_SOURCED='sourced' +__SHUNIT_MODE_STANDALONE='standalone' +__SHUNIT_PARENT=${SHUNIT_PARENT:-$0} + +# set the constants readonly +shunit_constants_=`set |grep '^__SHUNIT_' |cut -d= -f1` +echo "${shunit_constants_}" |grep '^Binary file' >/dev/null && \ + shunit_constants_=`set |grep -a '^__SHUNIT_' |cut -d= -f1` +for shunit_constant_ in ${shunit_constants_}; do + shunit_ro_opts_='' + case ${ZSH_VERSION:-} in + '') ;; # this isn't zsh + [123].*) ;; # early versions (1.x, 2.x, 3.x) + *) shunit_ro_opts_='-g' ;; # all later versions. declare readonly globally + esac + readonly ${shunit_ro_opts_} ${shunit_constant_} +done +unset shunit_constant_ shunit_constants_ shunit_ro_opts_ + +# variables +__shunit_lineno='' # line number of executed test +__shunit_mode=${__SHUNIT_MODE_SOURCED} # operating mode +__shunit_reportGenerated=${SHUNIT_FALSE} # is report generated +__shunit_script='' # filename of unittest script (standalone mode) +__shunit_skip=${SHUNIT_FALSE} # is skipping enabled +__shunit_suite='' # suite of tests to execute + +# counts of tests +__shunit_testSuccess=${SHUNIT_TRUE} +__shunit_testsTotal=0 +__shunit_testsPassed=0 +__shunit_testsFailed=0 + +# counts of asserts +__shunit_assertsTotal=0 +__shunit_assertsPassed=0 +__shunit_assertsFailed=0 +__shunit_assertsSkipped=0 + +# macros +_SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' + +#----------------------------------------------------------------------------- +# assert functions +# + +# Assert that two values are equal to one another. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertEquals() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertEquals() requires two or three arguments; $# given" + _shunit_error "1: ${1:+$1} 2: ${2:+$2} 3: ${3:+$3}${4:+ 4: $4}" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_expected_=$1 + shunit_actual_=$2 + + shunit_return=${SHUNIT_TRUE} + if [ "${shunit_expected_}" = "${shunit_actual_}" ]; then + _shunit_assertPass + else + failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" + shunit_return=${SHUNIT_FALSE} + fi + + unset shunit_message_ shunit_expected_ shunit_actual_ + return ${shunit_return} +} +_ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' + +# Assert that two values are not equal to one another. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotEquals() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertNotEquals() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_expected_=$1 + shunit_actual_=$2 + + shunit_return=${SHUNIT_TRUE} + if [ "${shunit_expected_}" != "${shunit_actual_}" ]; then + _shunit_assertPass + else + failSame "${shunit_message_}" "$@" + shunit_return=${SHUNIT_FALSE} + fi + + unset shunit_message_ shunit_expected_ shunit_actual_ + return ${shunit_return} +} +_ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' + +# Assert that a value is null (i.e. an empty string) +# +# Args: +# message: string: failure message [optional] +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNull() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "assertNull() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + assertTrue "${shunit_message_}" "[ -z '$1' ]" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' + +# Assert that a value is not null (i.e. a non-empty string) +# +# Args: +# message: string: failure message [optional] +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotNull() +{ + ${_SHUNIT_LINENO_} + if [ $# -gt 2 ]; then # allowing 0 arguments as $1 might actually be null + _shunit_error "assertNotNull() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_actual_=`_shunit_escapeCharactersInString "${1:-}"` + test -n "${shunit_actual_}" + assertTrue "${shunit_message_}" $? + shunit_return=$? + + unset shunit_actual_ shunit_message_ + return ${shunit_return} +} +_ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' + +# Assert that two values are the same (i.e. equal to one another). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertSame() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + assertEquals "${shunit_message_}" "$1" "$2" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' + +# Assert that two values are not the same (i.e. not equal to one another). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertNotSame() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_:-}$1" + shift + fi + assertNotEquals "${shunit_message_}" "$1" "$2" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' + +# Assert that a value or shell test condition is true. +# +# In shell, a value of 0 is true and a non-zero value is false. Any integer +# value passed can thereby be tested. +# +# Shell supports much more complicated tests though, and a means to support +# them was needed. As such, this function tests that conditions are true or +# false through evaluation rather than just looking for a true or false. +# +# The following test will succeed: +# assertTrue 0 +# assertTrue "[ 34 -gt 23 ]" +# The folloing test will fail with a message: +# assertTrue 123 +# assertTrue "test failed" "[ -r '/non/existant/file' ]" +# +# Args: +# message: string: failure message [optional] +# condition: string: integer value or shell conditional statement +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertTrue() +{ + ${_SHUNIT_LINENO_} + if [ $# -gt 2 ]; then + _shunit_error "assertTrue() takes one two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_condition_=$1 + + # see if condition is an integer, i.e. a return value + shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` + shunit_return=${SHUNIT_TRUE} + if [ -z "${shunit_condition_}" ]; then + # null condition + shunit_return=${SHUNIT_FALSE} + elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] + then + # possible return value. treating 0 as true, and non-zero as false. + [ ${shunit_condition_} -ne 0 ] && shunit_return=${SHUNIT_FALSE} + else + # (hopefully) a condition + ( eval ${shunit_condition_} ) >/dev/null 2>&1 + [ $? -ne 0 ] && shunit_return=${SHUNIT_FALSE} + fi + + # record the test + if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then + _shunit_assertPass + else + _shunit_assertFail "${shunit_message_}" + fi + + unset shunit_message_ shunit_condition_ shunit_match_ + return ${shunit_return} +} +_ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' + +# Assert that a value or shell test condition is false. +# +# In shell, a value of 0 is true and a non-zero value is false. Any integer +# value passed can thereby be tested. +# +# Shell supports much more complicated tests though, and a means to support +# them was needed. As such, this function tests that conditions are true or +# false through evaluation rather than just looking for a true or false. +# +# The following test will succeed: +# assertFalse 1 +# assertFalse "[ 'apples' = 'oranges' ]" +# The folloing test will fail with a message: +# assertFalse 0 +# assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" +# +# Args: +# message: string: failure message [optional] +# condition: string: integer value or shell conditional statement +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertFalse() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "assertFalse() quires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_condition_=$1 + + # see if condition is an integer, i.e. a return value + shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` + shunit_return=${SHUNIT_TRUE} + if [ -z "${shunit_condition_}" ]; then + # null condition + shunit_return=${SHUNIT_FALSE} + elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] + then + # possible return value. treating 0 as true, and non-zero as false. + [ ${shunit_condition_} -eq 0 ] && shunit_return=${SHUNIT_FALSE} + else + # (hopefully) a condition + ( eval ${shunit_condition_} ) >/dev/null 2>&1 + [ $? -eq 0 ] && shunit_return=${SHUNIT_FALSE} + fi + + # record the test + if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then + _shunit_assertPass + else + _shunit_assertFail "${shunit_message_}" + fi + + unset shunit_message_ shunit_condition_ shunit_match_ + return ${shunit_return} +} +_ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' + +#----------------------------------------------------------------------------- +# failure functions +# + +# Records a test failure. +# +# Args: +# message: string: failure message [optional] +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +fail() +{ + ${_SHUNIT_LINENO_} + if [ $# -gt 1 ]; then + _shunit_error "fail() requires zero or one arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 1 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + + _shunit_assertFail "${shunit_message_}" + + unset shunit_message_ + return ${SHUNIT_FALSE} +} +_FAIL_='eval fail --lineno "${LINENO:-}"' + +# Records a test failure, stating two values were not equal. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failNotEquals() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failNotEquals() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_expected_=$1 + shunit_actual_=$2 + + _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" + + unset shunit_message_ shunit_expected_ shunit_actual_ + return ${SHUNIT_FALSE} +} +_FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' + +# Records a test failure, stating two values should have been the same. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failSame() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + + _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected not same" + + unset shunit_message_ + return ${SHUNIT_FALSE} +} +_FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' + +# Records a test failure, stating two values were not equal. +# +# This is functionally equivalent to calling failNotEquals(). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failNotSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failNotEquals() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + failNotEquals "${shunit_message_}" "$1" "$2" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' + +#----------------------------------------------------------------------------- +# skipping functions +# + +# Force remaining assert and fail functions to be "skipped". +# +# This function forces the remaining assert and fail functions to be "skipped", +# i.e. they will have no effect. Each function skipped will be recorded so that +# the total of asserts and fails will not be altered. +# +# Args: +# None +startSkipping() +{ + __shunit_skip=${SHUNIT_TRUE} +} + +# Resume the normal recording behavior of assert and fail calls. +# +# Args: +# None +endSkipping() +{ + __shunit_skip=${SHUNIT_FALSE} +} + +# Returns the state of assert and fail call skipping. +# +# Args: +# None +# Returns: +# boolean: (TRUE/FALSE constant) +isSkipping() +{ + return ${__shunit_skip} +} + +#----------------------------------------------------------------------------- +# suite functions +# + +# Stub. This function should contains all unit test calls to be made. +# +# DEPRECATED (as of 2.1.0) +# +# This function can be optionally overridden by the user in their test suite. +# +# If this function exists, it will be called when shunit2 is sourced. If it +# does not exist, shunit2 will search the parent script for all functions +# beginning with the word 'test', and they will be added dynamically to the +# test suite. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Adds a function name to the list of tests schedule for execution. +# +# This function should only be called from within the suite() function. +# +# Args: +# function: string: name of a function to add to current unit test suite +suite_addTest() +{ + shunit_func_=${1:-} + + __shunit_suite="${__shunit_suite:+${__shunit_suite} }${shunit_func_}" + __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1` + + unset shunit_func_ +} + +# Stub. This function will be called once before any tests are run. +# +# Common one-time environment preparation tasks shared by all tests can be +# defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Stub. This function will be called once after all tests are finished. +# +# Common one-time environment cleanup tasks shared by all tests can be defined +# here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Stub. This function will be called before each test is run. +# +# Common environment preparation tasks shared by all tests can be defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#setUp() { :; } + +# Note: see _shunit_mktempFunc() for actual implementation +# Stub. This function will be called after each test is run. +# +# Common environment cleanup tasks shared by all tests can be defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +#------------------------------------------------------------------------------ +# internal shUnit2 functions +# + +# Create a temporary directory to store various run-time files in. +# +# This function is a cross-platform temporary directory creation tool. Not all +# OSes have the mktemp function, so one is included here. +# +# Args: +# None +# Outputs: +# string: the temporary directory that was created +_shunit_mktempDir() +{ + # try the standard mktemp function + ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ) && return + + # the standard mktemp didn't work. doing our own. + if [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then + _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 "${_shunit_file_}" +#! /bin/sh +exit ${SHUNIT_TRUE} +EOF + chmod +x "${_shunit_file_}" + done + + unset _shunit_file_ +} + +# Final cleanup function to leave things as we found them. +# +# Besides removing the temporary directory, this function is in charge of the +# final exit code of the unit test. The exit code is based on how the script +# was ended (e.g. normal exit, or via Ctrl-C). +# +# Args: +# name: string: name of the trap called (specified when trap defined) +_shunit_cleanup() +{ + _shunit_name_=$1 + + case ${_shunit_name_} in + EXIT) _shunit_signal_=0 ;; + INT) _shunit_signal_=2 ;; + TERM) _shunit_signal_=15 ;; + *) + _shunit_warn "unrecognized trap value (${_shunit_name_})" + _shunit_signal_=0 + ;; + esac + + # do our work + rm -fr "${__shunit_tmpDir}" + + # exit for all non-EXIT signals + if [ ${_shunit_name_} != 'EXIT' ]; then + _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" + # disable EXIT trap + trap 0 + # add 128 to signal and exit + exit `expr ${_shunit_signal_} + 128` + elif [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ] ; then + _shunit_assertFail 'Unknown failure encountered running a test' + _shunit_generateReport + exit ${SHUNIT_ERROR} + fi + + unset _shunit_name_ _shunit_signal_ +} + +# The actual running of the tests happens here. +# +# Args: +# None +_shunit_execSuite() +{ + for _shunit_test_ in ${__shunit_suite}; do + __shunit_testSuccess=${SHUNIT_TRUE} + + # disable skipping + endSkipping + + # execute the per-test setup function + setUp + + # execute the test + echo "${_shunit_test_}" + eval ${_shunit_test_} + + # execute the per-test tear-down function + tearDown + + # update stats + if [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then + __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1` + else + __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1` + fi + done + + unset _shunit_test_ +} + +# Generates the user friendly report with appropriate OK/FAILED message. +# +# Args: +# None +# Output: +# string: the report of successful and failed tests, as well as totals. +_shunit_generateReport() +{ + _shunit_ok_=${SHUNIT_TRUE} + + # if no exit code was provided one, determine an appropriate one + [ ${__shunit_testsFailed} -gt 0 \ + -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ] \ + && _shunit_ok_=${SHUNIT_FALSE} + + echo + if [ ${__shunit_testsTotal} -eq 1 ]; then + echo "Ran ${__shunit_testsTotal} test." + else + echo "Ran ${__shunit_testsTotal} tests." + fi + + _shunit_failures_='' + _shunit_skipped_='' + [ ${__shunit_assertsFailed} -gt 0 ] \ + && _shunit_failures_="failures=${__shunit_assertsFailed}" + [ ${__shunit_assertsSkipped} -gt 0 ] \ + && _shunit_skipped_="skipped=${__shunit_assertsSkipped}" + + if [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then + _shunit_msg_='OK' + [ -n "${_shunit_skipped_}" ] \ + && _shunit_msg_="${_shunit_msg_} (${_shunit_skipped_})" + else + _shunit_msg_="FAILED (${_shunit_failures_}" + [ -n "${_shunit_skipped_}" ] \ + && _shunit_msg_="${_shunit_msg_},${_shunit_skipped_}" + _shunit_msg_="${_shunit_msg_})" + fi + + echo + echo ${_shunit_msg_} + __shunit_reportGenerated=${SHUNIT_TRUE} + + unset _shunit_failures_ _shunit_msg_ _shunit_ok_ _shunit_skipped_ +} + +# Test for whether a function should be skipped. +# +# Args: +# None +# Returns: +# boolean: whether the test should be skipped (TRUE/FALSE constant) +_shunit_shouldSkip() +{ + [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE} + _shunit_assertSkip +} + +# Records a successful test. +# +# Args: +# None +_shunit_assertPass() +{ + __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` + __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` +} + +# Records a test failure. +# +# Args: +# message: string: failure message to provide user +_shunit_assertFail() +{ + _shunit_msg_=$1 + + __shunit_testSuccess=${SHUNIT_FALSE} + __shunit_assertsFailed=`expr ${__shunit_assertsFailed} + 1` + __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` + echo "${__SHUNIT_ASSERT_MSG_PREFIX}${_shunit_msg_}" + + unset _shunit_msg_ +} + +# Records a skipped test. +# +# Args: +# None +_shunit_assertSkip() +{ + __shunit_assertsSkipped=`expr ${__shunit_assertsSkipped} + 1` + __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` +} + +# Prepare a script filename for sourcing. +# +# Args: +# script: string: path to a script to source +# Returns: +# string: filename prefixed with ./ (if necessary) +_shunit_prepForSourcing() +{ + _shunit_script_=$1 + case "${_shunit_script_}" in + /*|./*) echo "${_shunit_script_}" ;; + *) echo "./${_shunit_script_}" ;; + esac + unset _shunit_script_ +} + +# Escape a character in a string. +# +# Args: +# c: string: unescaped character +# s: string: to escape character in +# Returns: +# string: with escaped character(s) +_shunit_escapeCharInStr() +{ + [ -n "$2" ] || return # no point in doing work on an empty string + + # Note: using shorter variable names to prevent conflicts with + # _shunit_escapeCharactersInString(). + _shunit_c_=$1 + _shunit_s_=$2 + + + # escape the character + echo ''${_shunit_s_}'' |sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' + + unset _shunit_c_ _shunit_s_ +} + +# Escape a character in a string. +# +# Args: +# str: string: to escape characters in +# Returns: +# string: with escaped character(s) +_shunit_escapeCharactersInString() +{ + [ -n "$1" ] || return # no point in doing work on an empty string + + _shunit_str_=$1 + + # Note: using longer variable names to prevent conflicts with + # _shunit_escapeCharInStr(). + for _shunit_char_ in '"' '$' "'" '`'; do + _shunit_str_=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"` + done + + echo "${_shunit_str_}" + unset _shunit_char_ _shunit_str_ +} + +# Extract list of functions to run tests against. +# +# Args: +# script: string: name of script to extract functions from +# Returns: +# string: of function names +_shunit_extractTestFunctions() +{ + _shunit_script_=$1 + + # extract the lines with test function names, strip of anything besides the + # function name, and output everything on a single line. + _shunit_regex_='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)' + egrep "${_shunit_regex_}" "${_shunit_script_}" \ + |sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \ + |xargs + + unset _shunit_regex_ _shunit_script_ +} + +#------------------------------------------------------------------------------ +# main +# + +# determine the operating mode +if [ $# -eq 0 ]; then + __shunit_script=${__SHUNIT_PARENT} + __shunit_mode=${__SHUNIT_MODE_SOURCED} +else + __shunit_script=$1 + [ -r "${__shunit_script}" ] || \ + _shunit_fatal "unable to read from ${__shunit_script}" + __shunit_mode=${__SHUNIT_MODE_STANDALONE} +fi + +# create a temporary storage location +__shunit_tmpDir=`_shunit_mktempDir` + +# provide a public temporary directory for unit test scripts +# TODO(kward): document this +SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" +mkdir "${SHUNIT_TMPDIR}" + +# setup traps to clean up after ourselves +trap '_shunit_cleanup EXIT' 0 +trap '_shunit_cleanup INT' 2 +trap '_shunit_cleanup TERM' 15 + +# create phantom functions to work around issues with Cygwin +_shunit_mktempFunc +PATH="${__shunit_tmpDir}:${PATH}" + +# make sure phantom functions are executable. this will bite if /tmp (or the +# current $TMPDIR) points to a path on a partition that was mounted with the +# 'noexec' option. the noexec command was created with _shunit_mktempFunc(). +noexec 2>/dev/null || _shunit_fatal \ + 'please declare TMPDIR with path on partition with exec permission' + +# we must manually source the tests in standalone mode +if [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then + . "`_shunit_prepForSourcing \"${__shunit_script}\"`" +fi + +# execute the oneTimeSetUp function (if it exists) +oneTimeSetUp + +# execute the suite function defined in the parent test script +# deprecated as of 2.1.0 +suite + +# if no suite function was defined, dynamically build a list of functions +if [ -z "${__shunit_suite}" ]; then + shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` + for shunit_func_ in ${shunit_funcs_}; do + suite_addTest ${shunit_func_} + done +fi +unset shunit_func_ shunit_funcs_ + +# execute the tests +_shunit_execSuite + +# execute the oneTimeTearDown function (if it exists) +oneTimeTearDown + +# generate the report +_shunit_generateReport + +# that's it folks +[ ${__shunit_testsFailed} -eq 0 ] +exit $? diff --git a/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test.sh b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test.sh new file mode 100755 index 0000000..f5a0ff8 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test.sh @@ -0,0 +1,124 @@ +#! /bin/sh +# $Id: shunit2_test.sh 322 2011-04-24 00:09:45Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 unit test suite runner. +# +# This script runs all the unit tests that can be found, and generates a nice +# report of the tests. + +MY_NAME=`basename $0` +MY_PATH=`dirname $0` + +PREFIX='shunit2_test_' +SHELLS='/bin/sh /bin/bash /bin/dash /bin/ksh /bin/pdksh /bin/zsh' +TESTS='' +for test in ${PREFIX}[a-z]*.sh; do + TESTS="${TESTS} ${test}" +done + +# load common unit test functions +. ../lib/versions +. ./shunit2_test_helpers + +usage() +{ + echo "usage: ${MY_NAME} [-e key=val ...] [-s shell(s)] [-t test(s)]" +} + +env='' + +# process command line flags +while getopts 'e:hs:t:' opt; do + case ${opt} in + e) # set an environment variable + key=`expr "${OPTARG}" : '\([^=]*\)='` + val=`expr "${OPTARG}" : '[^=]*=\(.*\)'` + if [ -z "${key}" -o -z "${val}" ]; then + usage + exit 1 + fi + eval "${key}='${val}'" + export ${key} + env="${env:+${env} }${key}" + ;; + h) usage; exit 0 ;; # output help + s) shells=${OPTARG} ;; # list of shells to run + t) tests=${OPTARG} ;; # list of tests to run + *) usage; exit 1 ;; + esac +done +shift `expr ${OPTIND} - 1` + +# fill shells and/or tests +shells=${shells:-${SHELLS}} +tests=${tests:-${TESTS}} + +# error checking +if [ -z "${tests}" ]; then + th_error 'no tests found to run; exiting' + exit 1 +fi + +cat <&1; ) + done +done diff --git a/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_asserts.sh b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_asserts.sh new file mode 100755 index 0000000..1f8040d --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_asserts.sh @@ -0,0 +1,209 @@ +#! /bin/sh +# $Id: shunit2_test_asserts.sh 312 2011-03-14 22:41:29Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 unit test for assert functions + +# load test helpers +. ./shunit2_test_helpers + +#------------------------------------------------------------------------------ +# suite tests +# + +commonEqualsSame() +{ + fn=$1 + + ( ${fn} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'equal' $? "${stdoutF}" "${stderrF}" + + ( ${fn} "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'equal; with msg' $? "${stdoutF}" "${stderrF}" + + ( ${fn} 'abc def' 'abc def' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'equal with spaces' $? "${stdoutF}" "${stderrF}" + + ( ${fn} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'not equal' $? "${stdoutF}" "${stderrF}" + + ( ${fn} '' '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'null values' $? "${stdoutF}" "${stderrF}" + + ( ${fn} arg1 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( ${fn} arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +commonNotEqualsSame() +{ + fn=$1 + + ( ${fn} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not same' $? "${stdoutF}" "${stderrF}" + + ( ${fn} "${MSG}" 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not same, with msg' $? "${stdoutF}" "${stderrF}" + + ( ${fn} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}" + + ( ${fn} '' '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}" + + ( ${fn} arg1 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( ${fn} arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +testAssertEquals() +{ + commonEqualsSame 'assertEquals' +} + +testAssertNotEquals() +{ + commonNotEqualsSame 'assertNotEquals' +} + +testAssertSame() +{ + commonEqualsSame 'assertSame' +} + +testAssertNotSame() +{ + commonNotEqualsSame 'assertNotSame' +} + +testAssertNull() +{ + ( assertNull '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'null' $? "${stdoutF}" "${stderrF}" + + ( assertNull "${MSG}" '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'null, with msg' $? "${stdoutF}" "${stderrF}" + + ( assertNull 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'not null' $? "${stdoutF}" "${stderrF}" + + ( assertNull >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( assertNull arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +testAssertNotNull() +{ + ( assertNotNull 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not null' $? "${stdoutF}" "${stderrF}" + + ( assertNotNull "${MSG}" 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not null, with msg' $? "${stdoutF}" "${stderrF}" + + ( assertNotNull 'x"b' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not null, with double-quote' $? \ + "${stdoutF}" "${stderrF}" + + ( assertNotNull "x'b" >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not null, with single-quote' $? \ + "${stdoutF}" "${stderrF}" + + ( assertNotNull 'x$b' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not null, with dollar' $? \ + "${stdoutF}" "${stderrF}" + + ( assertNotNull 'x`b' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not null, with backtick' $? \ + "${stdoutF}" "${stderrF}" + + ( assertNotNull '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'null' $? "${stdoutF}" "${stderrF}" + + # there is no test for too few arguments as $1 might actually be null + + ( assertNotNull arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +testAssertTrue() +{ + ( assertTrue 0 >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'true' $? "${stdoutF}" "${stderrF}" + + ( assertTrue "${MSG}" 0 >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'true, with msg' $? "${stdoutF}" "${stderrF}" + + ( assertTrue '[ 0 -eq 0 ]' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'true condition' $? "${stdoutF}" "${stderrF}" + + ( assertTrue 1 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'false' $? "${stdoutF}" "${stderrF}" + + ( assertTrue '[ 0 -eq 1 ]' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'false condition' $? "${stdoutF}" "${stderrF}" + + ( assertTrue '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'null' $? "${stdoutF}" "${stderrF}" + + ( assertTrue >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( assertTrue arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +testAssertFalse() +{ + ( assertFalse 1 >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'false' $? "${stdoutF}" "${stderrF}" + + ( assertFalse "${MSG}" 1 >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'false, with msg' $? "${stdoutF}" "${stderrF}" + + ( assertFalse '[ 0 -eq 1 ]' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'false condition' $? "${stdoutF}" "${stderrF}" + + ( assertFalse 0 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'true' $? "${stdoutF}" "${stderrF}" + + ( assertFalse '[ 0 -eq 0 ]' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'true condition' $? "${stdoutF}" "${stderrF}" + + ( assertFalse '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'true condition' $? "${stdoutF}" "${stderrF}" + + ( assertFalse >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( assertFalse arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +#------------------------------------------------------------------------------ +# suite functions +# + +oneTimeSetUp() +{ + tmpDir="${__shunit_tmpDir}/output" + mkdir "${tmpDir}" + stdoutF="${tmpDir}/stdout" + stderrF="${tmpDir}/stderr" + + MSG='This is a test message' +} + +# load and run shUnit2 +[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 +. ${TH_SHUNIT} diff --git a/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_failures.sh b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_failures.sh new file mode 100755 index 0000000..4aec943 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_failures.sh @@ -0,0 +1,89 @@ +#! /bin/sh +# $Id: shunit2_test_failures.sh 286 2008-11-24 21:42:34Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 unit test for failure functions + +# load common unit-test functions +. ./shunit2_test_helpers + +#----------------------------------------------------------------------------- +# suite tests +# + +testFail() +{ + ( fail >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'fail' $? "${stdoutF}" "${stderrF}" + + ( fail "${MSG}" >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'fail with msg' $? "${stdoutF}" "${stderrF}" + + ( fail arg1 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +testFailNotEquals() +{ + ( failNotEquals 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}" + + ( failNotEquals "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'same with msg' $? "${stdoutF}" "${stderrF}" + + ( failNotEquals 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'not same' $? "${stdoutF}" "${stderrF}" + + ( failNotEquals '' '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}" + + ( failNotEquals >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( failNotEquals arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +testFailSame() +{ + ( failSame 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}" + + ( failSame "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'same with msg' $? "${stdoutF}" "${stderrF}" + + ( failSame 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'not same' $? "${stdoutF}" "${stderrF}" + + ( failSame '' '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}" + + ( failSame >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( failSame arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +#----------------------------------------------------------------------------- +# suite functions +# + +oneTimeSetUp() +{ + tmpDir="${__shunit_tmpDir}/output" + mkdir "${tmpDir}" + stdoutF="${tmpDir}/stdout" + stderrF="${tmpDir}/stderr" + + MSG='This is a test message' +} + +# load and run shUnit2 +[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 +. ${TH_SHUNIT} diff --git a/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_helpers b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_helpers new file mode 100755 index 0000000..82a0eef --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_helpers @@ -0,0 +1,177 @@ +# $Id: shunit2_test_helpers 286 2008-11-24 21:42:34Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 unit test common functions + +# treat unset variables as an error when performing parameter expansion +set -u + +# set shwordsplit for zsh +[ -n "${ZSH_VERSION:-}" ] && setopt shwordsplit + +# +# constants +# + +# path to shUnit2 library. can be overridden by setting SHUNIT_INC +TH_SHUNIT=${SHUNIT_INC:-./shunit2} + +# configure debugging. set the DEBUG environment variable to any +# non-empty value to enable debug output, or TRACE to enable trace +# output. +TRACE=${TRACE:+'th_trace '} +[ -n "${TRACE}" ] && DEBUG=1 +[ -z "${TRACE}" ] && TRACE=':' + +DEBUG=${DEBUG:+'th_debug '} +[ -z "${DEBUG}" ] && DEBUG=':' + +# +# variables +# + +th_RANDOM=0 + +# +# functions +# + +# message functions +th_trace() { echo "${MY_NAME}:TRACE $@" >&2; } +th_debug() { echo "${MY_NAME}:DEBUG $@" >&2; } +th_info() { echo "${MY_NAME}:INFO $@" >&2; } +th_warn() { echo "${MY_NAME}:WARN $@" >&2; } +th_error() { echo "${MY_NAME}:ERROR $@" >&2; } +th_fatal() { echo "${MY_NAME}:FATAL $@" >&2; } + +# output subtest name +th_subtest() { echo " $@" >&2; } + +# generate a random number +th_generateRandom() +{ + tfgr_random=${th_RANDOM} + + while [ "${tfgr_random}" = "${th_RANDOM}" ]; do + if [ -n "${RANDOM:-}" ]; then + # $RANDOM works + tfgr_random=${RANDOM}${RANDOM}${RANDOM}$$ + elif [ -r '/dev/urandom' ]; then + tfgr_random=`od -vAn -N4 -tu4 "${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_EQUALS_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_EQUALS_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_EQUALS_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testAssertNotEquals() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_NOT_EQUALS_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NOT_EQUALS_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_NOT_EQUALS_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NOT_EQUALS_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testSame() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_SAME_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_SAME_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_SAME_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_SAME_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testNotSame() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_NOT_SAME_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NOT_SAME_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_NOT_SAME_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NOT_SAME_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testNull() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_NULL_} 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NULL_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_NULL_} '"some msg"' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NULL_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testNotNull() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_NOT_NULL_} '' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NOT_NULL_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_NOT_NULL_} '"some msg"' '""' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NOT_NULL_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stdoutF}" "${stderrF}" >&2 +} + +testAssertTrue() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_TRUE_} ${SHUNIT_FALSE} >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_TRUE_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + + ( ${_ASSERT_TRUE_} '"some msg"' ${SHUNIT_FALSE} >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_TRUE_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testAssertFalse() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_FALSE_} ${SHUNIT_TRUE} >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_FALSE_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_FALSE_} '"some msg"' ${SHUNIT_TRUE} >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_FALSE_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testFail() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_FAIL_} >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_FAIL_} '"some msg"' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testFailNotEquals() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_FAIL_NOT_EQUALS_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_NOT_EQUALS_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_FAIL_NOT_EQUALS_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_NOT_EQUALS_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testFailSame() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_FAIL_SAME_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_SAME_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_FAIL_SAME_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_SAME_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testFailNotSame() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_FAIL_NOT_SAME_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_NOT_SAME_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_FAIL_NOT_SAME_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_NOT_SAME_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +#------------------------------------------------------------------------------ +# suite functions +# + +oneTimeSetUp() +{ + tmpDir="${__shunit_tmpDir}/output" + mkdir "${tmpDir}" + stdoutF="${tmpDir}/stdout" + stderrF="${tmpDir}/stderr" +} + +# load and run shUnit2 +[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 +. ${TH_SHUNIT} diff --git a/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_misc.sh b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_misc.sh new file mode 100755 index 0000000..e3be229 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_misc.sh @@ -0,0 +1,165 @@ +#! /bin/sh +# $Id: shunit2_test_misc.sh 322 2011-04-24 00:09:45Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 unit tests of miscellaneous things + +# load test helpers +. ./shunit2_test_helpers + +#------------------------------------------------------------------------------ +# suite tests +# + +# Note: the test script is prefixed with '#' chars so that shUnit2 does not +# incorrectly interpret the embedded functions as real functions. +testUnboundVariable() +{ + sed 's/^#//' >"${unittestF}" <"${stdoutF}" 2>"${stderrF}" ) + assertFalse 'expected a non-zero exit value' $? + grep '^ASSERT:Unknown failure' "${stdoutF}" >/dev/null + assertTrue 'assert message was not generated' $? + grep '^Ran [0-9]* test' "${stdoutF}" >/dev/null + assertTrue 'test count message was not generated' $? + grep '^FAILED' "${stdoutF}" >/dev/null + assertTrue 'failure message was not generated' $? +} + +testIssue7() +{ + ( assertEquals 'Some message.' 1 2 >"${stdoutF}" 2>"${stderrF}" ) + diff "${stdoutF}" - >/dev/null < but was:<2> +EOF + rtrn=$? + assertEquals ${SHUNIT_TRUE} ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testPrepForSourcing() +{ + assertEquals '/abc' `_shunit_prepForSourcing '/abc'` + assertEquals './abc' `_shunit_prepForSourcing './abc'` + assertEquals './abc' `_shunit_prepForSourcing 'abc'` +} + +testEscapeCharInStr() +{ + actual=`_shunit_escapeCharInStr '\' ''` + assertEquals '' "${actual}" + assertEquals 'abc\\' `_shunit_escapeCharInStr '\' 'abc\'` + assertEquals 'abc\\def' `_shunit_escapeCharInStr '\' 'abc\def'` + assertEquals '\\def' `_shunit_escapeCharInStr '\' '\def'` + + actual=`_shunit_escapeCharInStr '"' ''` + assertEquals '' "${actual}" + assertEquals 'abc\"' `_shunit_escapeCharInStr '"' 'abc"'` + assertEquals 'abc\"def' `_shunit_escapeCharInStr '"' 'abc"def'` + assertEquals '\"def' `_shunit_escapeCharInStr '"' '"def'` + + actual=`_shunit_escapeCharInStr '$' ''` + assertEquals '' "${actual}" + assertEquals 'abc\$' `_shunit_escapeCharInStr '$' 'abc$'` + assertEquals 'abc\$def' `_shunit_escapeCharInStr '$' 'abc$def'` + assertEquals '\$def' `_shunit_escapeCharInStr '$' '$def'` + +# actual=`_shunit_escapeCharInStr "'" ''` +# assertEquals '' "${actual}" +# assertEquals "abc\\'" `_shunit_escapeCharInStr "'" "abc'"` +# assertEquals "abc\\'def" `_shunit_escapeCharInStr "'" "abc'def"` +# assertEquals "\\'def" `_shunit_escapeCharInStr "'" "'def"` + +# # must put the backtick in a variable so the shell doesn't misinterpret it +# # while inside a backticked sequence (e.g. `echo '`'` would fail). +# backtick='`' +# actual=`_shunit_escapeCharInStr ${backtick} ''` +# assertEquals '' "${actual}" +# assertEquals '\`abc' \ +# `_shunit_escapeCharInStr "${backtick}" ${backtick}'abc'` +# assertEquals 'abc\`' \ +# `_shunit_escapeCharInStr "${backtick}" 'abc'${backtick}` +# assertEquals 'abc\`def' \ +# `_shunit_escapeCharInStr "${backtick}" 'abc'${backtick}'def'` +} + +testEscapeCharInStr_specialChars() +{ + # make sure our forward slash doesn't upset sed + assertEquals '/' `_shunit_escapeCharInStr '\' '/'` + + # some shells escape these differently + #assertEquals '\\a' `_shunit_escapeCharInStr '\' '\a'` + #assertEquals '\\b' `_shunit_escapeCharInStr '\' '\b'` +} + +# Test the various ways of declaring functions. +# +# Prefixing (then stripping) with comment symbol so these functions aren't +# treated as real functions by shUnit2. +testExtractTestFunctions() +{ + f="${tmpD}/extract_test_functions" + sed 's/^#//' <"${f}" +#testABC() { echo 'ABC'; } +#test_def() { +# echo 'def' +#} +#testG3 () +#{ +# echo 'G3' +#} +#function test4() { echo '4'; } +# test5() { echo '5'; } +#some_test_function() { echo 'some func'; } +#func_with_test_vars() { +# testVariable=1234 +#} +EOF + + actual=`_shunit_extractTestFunctions "${f}"` + assertEquals 'testABC test_def testG3 test4 test5' "${actual}" +} + +#------------------------------------------------------------------------------ +# suite functions +# + +setUp() +{ + for f in ${expectedF} ${stdoutF} ${stderrF}; do + cp /dev/null ${f} + done + rm -fr "${tmpD}" + mkdir "${tmpD}" +} + +oneTimeSetUp() +{ + tmpD="${SHUNIT_TMPDIR}/tmp" + expectedF="${SHUNIT_TMPDIR}/expected" + stdoutF="${SHUNIT_TMPDIR}/stdout" + stderrF="${SHUNIT_TMPDIR}/stderr" + unittestF="${SHUNIT_TMPDIR}/unittest" +} + +# load and run shUnit2 +[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 +. ${TH_SHUNIT} diff --git a/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_standalone.sh b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_standalone.sh new file mode 100755 index 0000000..6df64b3 --- /dev/null +++ b/eu.esrf.test/src/shunit2-2.1.6/src/shunit2_test_standalone.sh @@ -0,0 +1,41 @@ +#! /bin/sh +# $Id: shunit2_test_standalone.sh 303 2010-05-03 13:11:27Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2010 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 unit test for standalone operation. +# +# This unit test is purely to test that calling shunit2 directly, while passing +# the name of a unit test script, works. When run, this script determines if it +# is running as a standalone program, and calls main() if it is. + +ARGV0=`basename "$0"` + +# load test helpers +. ./shunit2_test_helpers + +#------------------------------------------------------------------------------ +# suite tests +# + +testStandalone() +{ + assertTrue ${SHUNIT_TRUE} +} + +#------------------------------------------------------------------------------ +# main +# + +main() +{ + ${TH_SHUNIT} "${ARGV0}" +} + +# are we running as a standalone? +if [ "${ARGV0}" = 'shunit2_test_standalone.sh' ]; then + if [ $# -gt 0 ]; then main "$@"; else main; fi +fi diff --git a/eu.esrf.test/src/test_variables.py b/eu.esrf.test/src/test_variables.py index 48789e9..07b4d38 100755 --- a/eu.esrf.test/src/test_variables.py +++ b/eu.esrf.test/src/test_variables.py @@ -6,7 +6,8 @@ #queue.update({'suite_usecases_general':{'tst_case':'tst_hdf5_large_tree'}}) #queue.update({'suite_workflows_bignexus':{'tst_case':'tst_slicedata_dbrowsing'}}) #queue['suite_workflows_bignexus'] = {'tst_case':'tst_slicedata_dexplore'} - + + def check_variable(testSuiteName): path_global_script=os.path.join(os.environ['WORKSPACE'],'org.dawnsci.squishtests',testSuiteName,'shared/scripts') if os.path.exists(path_global_script)== True: @@ -20,6 +21,7 @@ def setup_log(): os.mkdir(path_log) setup_log() +#launch all the tests for testSuiteName in queue.keys(): check_variable(testSuiteName) for tst in queue[testSuiteName]: diff --git a/eu.esrf.test/src/test_variables.py~ b/eu.esrf.test/src/test_variables.py~ index 3167e08..53a463b 100755 --- a/eu.esrf.test/src/test_variables.py~ +++ b/eu.esrf.test/src/test_variables.py~ @@ -1,12 +1,13 @@ #!/usr/bin/python2.6 import os,shutil -queue = {'suite_usecases_general':{'tst_case':'tst_hdf5_large_tree'}} +queue = {'suite_workflows_general': {'tst_case':'tst_open_examples'}} #only one queue allowed for one suite_test_case #queue = {'suite_workflows_general': {'tst_case2':'tst_open_examples'}} #queue.update({'suite_usecases_general':{'tst_case':'tst_hdf5_large_tree'}}) #queue.update({'suite_workflows_bignexus':{'tst_case':'tst_slicedata_dbrowsing'}}) #queue['suite_workflows_bignexus'] = {'tst_case':'tst_slicedata_dexplore'} - + + def check_variable(testSuiteName): path_global_script=os.path.join(os.environ['WORKSPACE'],'org.dawnsci.squishtests',testSuiteName,'shared/scripts') if os.path.exists(path_global_script)== True: diff --git a/eu.esrf.test/unitest/.nfs00000000f3a989da00000106 b/eu.esrf.test/unitest/.nfs00000000f3a989da00000106 new file mode 100755 index 0000000..dd4e368 --- /dev/null +++ b/eu.esrf.test/unitest/.nfs00000000f3a989da00000106 @@ -0,0 +1,38 @@ + #! /usr/bin/env sh + +### unitTest.sh ### + +source ../script_jenkins + + +function testTmpinFolder () { + val=$(findTmpFile tmpFile/.X*-lock) + assertEquals '0' $val +} + +function testdisplaynumber () { + #val1=$(findFreeDisplayNumber) + assertEquals '0' '0' +} + + +setUp(){ +mkdir 'tmpFile' +chmod -R 775 tmpFile +cd tmpFile +touch .X0-lock +touch .X1-lock +touch .X4-lock +cd .. +ssh -X opid23@ub1204 + +} + +tearDown(){ +rm -rf tmpFile + +} +. "../shunit2-2.1.6/src/shunit2" + + + diff --git a/eu.esrf.test/unitest/unitest.sh b/eu.esrf.test/unitest/unitest.sh new file mode 100755 index 0000000..10bd625 --- /dev/null +++ b/eu.esrf.test/unitest/unitest.sh @@ -0,0 +1,37 @@ + #! /usr/bin/env sh +echo $WORKSPACE/eu.esrf.test/src/scriptFunction +### unitTest.sh ### + +#source /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/scriptFunction +source $WORKSPACE/eu.esrf.test/src/scriptFunction +#test the function findDisplayNumber with a temp file belonged to the user +function testWithTmp () { + mkdir 'tmpFile' + chmod -R 775 tmpFile + cd tmpFile + touch .X2-lock + cd .. + ssh opid29@ub1204 "touch $WORKSPACE/eu.esrf.test/unitest/tmpFile/.X0-lock;touch $WORKSPACE/eu.esrf.test/unitest/tmpFile/.X1-lock;touch $WORKSPACE/eu.esrf.test/unitest/tmpFile/.X4-lock;" + val=$(findDisplayNumber tmpFile/) + rm -rf tmpFile + assertEquals '2' $val +} + +#test the function findDisplayNumber with no temp file belonged to the user +function testwithNoTmp () { + mkdir 'tmpFile' + chmod -R 775 tmpFile + cd tmpFile + cd .. + ssh opid29@ub1204 "touch $WORKSPACE/eu.esrf.test/unitest/tmpFile/.X0-lock;touch $WORKSPACE/eu.esrf.test/unitest/tmpFile/.X1-lock;touch $WORKSPACE/eu.esrf.test/unitest/tmpFile/.X2-lock;touch $WORKSPACE/eu.esrf.test/unitest/tmpFile/.X4-lock" + val1=$(findDisplayNumber tmpFile/) + rm -rf tmpFile + assertEquals '3' $val1 +} + + + +. "$WORKSPACE/eu.esrf.test/src/shunit2-2.1.6/src/shunit2" + + + diff --git a/eu.esrf.test/unitest/unitest.sh~ b/eu.esrf.test/unitest/unitest.sh~ new file mode 100755 index 0000000..b58e9dd --- /dev/null +++ b/eu.esrf.test/unitest/unitest.sh~ @@ -0,0 +1,37 @@ + #! /usr/bin/env sh +echo $WORKSPACE/eu.esrf.test/src/scriptFunction +### unitTest.sh ### + +#source /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/scriptFunction +source $WORKSPACE/eu.esrf.test/src/scriptFunction +#test the function findDisplayNumber with a temp file belonged to the user +function testWithTmp () { + mkdir 'tmpFile' + chmod -R 775 tmpFile + cd tmpFile + touch .X2-lock + cd .. + ssh opid29@ub1204 "touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X0-lock;touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X1-lock;touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X4-lock;" + val=$(findDisplayNumber tmpFile/) + rm -rf tmpFile + assertEquals '2' $val +} + +#test the function findDisplayNumber with no temp file belonged to the user +function testwithNoTmp () { + mkdir 'tmpFile' + chmod -R 775 tmpFile + cd tmpFile + cd .. + ssh opid29@ub1204 "touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X0-lock;touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X1-lock;touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X2-lock;touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X4-lock" + val1=$(findDisplayNumber tmpFile/) + rm -rf tmpFile + assertEquals '3' $val1 +} + + + +. "$WORKSPACE/eu.esrf.test/src/shunit2-2.1.6/src/shunit2" + + + diff --git a/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py b/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py index 30c7ddf..b8114de 100644 --- a/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py +++ b/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py @@ -1,12 +1,13 @@ -DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1204_opid23/dawn_workspace" +import os, shutil +from datetime import datetime +DAWN_WORKSPACE_ROOT=os.path.join(os.environ['WORKSPACE'],"eu.esrf.test/dawn_workspace") DAWN_SUITE_WORKSPACE="suite_test_single_workspace" USE_ATTACH=False testSettings.logScreenshotOnFail = True testSettings.logScreenshotOnError = True -import os, shutil -from datetime import datetime + def startDAWNSuiteWorkspace(): diff --git a/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py~ b/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py~ index 3f0af65..a546bcd 100644 --- a/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py~ +++ b/org.dawnsci.squishtests/suite_workflows_general/shared/scripts/dawn_global_startup.py~ @@ -1,12 +1,13 @@ -DAWN_WORKSPACE_ROOT="/scisoft/jenkins/ub1204_opid23/" +import os, shutil +from datetime import datetime +DAWN_WORKSPACE_ROOT=os.path.join(os.environ['WORKSPACE'],"dawn_workspace") DAWN_SUITE_WORKSPACE="suite_test_single_workspace" USE_ATTACH=False testSettings.logScreenshotOnFail = True testSettings.logScreenshotOnError = True -import os, shutil -from datetime import datetime + def startDAWNSuiteWorkspace(): diff --git a/squishinstall.sh~ b/squishinstall.sh~ deleted file mode 100755 index 9f1122a..0000000 --- a/squishinstall.sh~ +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -set -o posix # posix mode so that error setting inherit to subshells -set -eux # error, unset and echo - - -# Options -export AUT_NAME=dawn -export AUT_DIR=/sware/isdd/soft/dawn/beamline/linux_x64/dawn -echo "WORKSPACE", ${WORKSPACE:="./WORKSPACE"} -echo "AUT_NAME=${AUT_NAME}" -echo "DISPLAY", ${DISPLAY:=":0.0"}\ - -export JREDIR=/sware/isdd/soft/java/v7u40/linux_x64/jdk1.7.0_40/jre - - -# Install squish in the Guest, $1 should be guest's JRE directory, $2 the aut name, $3 aut directory -# Sets SQUISHDIR (essentially as return) -function install_squish() -{ - echo "`date +"%a %d/%b/%Y %H:%M:%S"` install_squish start" - local jredir=$1 - local aut_name=$2 - local aut_dir=$3 - local java="${jredir}/bin/java" - - unzip -q -d $WORKSPACE/tempsquish $WORKSPACE/squish.zip - : Remove version from folder name - mv $WORKSPACE/tempsquish/* $WORKSPACE/squish - rmdir $WORKSPACE/tempsquish - - ## Setup squish - # This is essentially the command that is run by the UI setup in Squish to create the magic squishrt.jar - SQUISHDIR="$WORKSPACE/squish" - local squishserver="$SQUISHDIR/bin/squishserver" - java_version=`"$java" -version 2>&1 | grep 'java version' | sed '-es,[^"]*"\([^"]*\)",\1,'` - echo "`date +"%a %d/%b/%Y %H:%M:%S"` install_squish FixMethod" - "$java" \ - -classpath "${SQUISHDIR}/lib/squishjava.jar:${SQUISHDIR}/lib/bcel.jar" \ - com.froglogic.squish.awt.FixMethod \ - "${jredir}/lib/rt.jar:${SQUISHDIR}/lib/squishjava.jar" \ - "${SQUISHDIR}/lib/squishrt.jar" - - cp "/scisoft/sware_isdd/src/squish/.squish-3-license" ~/.squish-3-license - $squishserver --config setJavaVM "$java" - $squishserver --config setJavaVersion "$java_version" - $squishserver --config setJavaHookMethod "jvm" - $squishserver --config setLibJVM "`find $jredir -name libjvm.so | head -1`" - $squishserver --config addAUT "$aut_name" "$aut_dir" - $squishserver --config setAUTTimeout 120 - echo "`date +"%a %d/%b/%Y %H:%M:%S"` install_squish end" -} - -: Setup Squish -if !([ -d "$WORKSPACE/squish" ]); - then - install_squish $JREDIR $AUT_NAME $AUT_DIR - else - echo "*****************************" - echo "************ALREADY EXIST*****************" - echo "*****************************" -fi - - - From 207f91a3c33e5f009910aacc18efbda507a39b6e Mon Sep 17 00:00:00 2001 From: Operator account ID23 Date: Mon, 18 Nov 2013 10:21:35 +0100 Subject: [PATCH 11/17] fix bug --- eu.esrf.test/src/scriptFunction | 1 + 1 file changed, 1 insertion(+) diff --git a/eu.esrf.test/src/scriptFunction b/eu.esrf.test/src/scriptFunction index d378c8a..2400709 100755 --- a/eu.esrf.test/src/scriptFunction +++ b/eu.esrf.test/src/scriptFunction @@ -31,6 +31,7 @@ if [ $xvfbFound=="false" ]; then #if no display found done if [ $foundDisplay=="false" ]; then var=$x + echo $var fi fi } From a0e1aa9afe527b0514ec4bb0e82dd25cf18d8a62 Mon Sep 17 00:00:00 2001 From: Operator account ID23 Date: Mon, 18 Nov 2013 11:35:48 +0100 Subject: [PATCH 12/17] fix bug --- eu.esrf.test/src/scriptFunction | 40 +++++++++++++++++---------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/eu.esrf.test/src/scriptFunction b/eu.esrf.test/src/scriptFunction index 2400709..2fdb320 100755 --- a/eu.esrf.test/src/scriptFunction +++ b/eu.esrf.test/src/scriptFunction @@ -1,37 +1,39 @@ #!/usr/bin/env bash xvfbFound=false -foundDisplay=false i=0 x=0 typeFile=".X*-lock" #pattern to only select Xvfb tmp file findDisplayNumber(){ for inode in $(ls $1/$typeFile) -do - owner=$(ls -al $inode | grep -v grep | awk '{ print $3; }') - array[$i]=$(echo "$inode" | tr -d [:alpha:] | tr -d [:punct:]) #make a list of all the display number for, in another case find a free number - if [ "$USER" = "$owner" ];then - xvfbFound=true - var=$(echo "$inode" | tr -d [:alpha:] | tr -d [:punct:]) - echo $var #return the availaible display for the logged user - break; - fi - let i++ -done -if [ $xvfbFound=="false" ]; then #if no display found + do + owner=$(ls -al $inode | grep -v grep | awk '{ print $3; }') + array[$i]=$(echo "$inode" | tr -d [:alpha:] | tr -d [:punct:]) #make a list of all the display number for, in another case find a free number + if [ "$USER" = "$owner" ];then + xvfbFound=true + var=$(echo "$inode" | tr -d [:alpha:] | tr -d [:punct:]) + echo $var #return the availaible display for the logged user + break; + fi + let i++ + done + +if ! $xvfbFound ; then #if no display found var1=${#array[@]} for (( c=0; c Date: Mon, 18 Nov 2013 14:05:17 +0100 Subject: [PATCH 13/17] regresive tst --- eu.esrf.test/src/scriptFunction | 11 ++++++++++- eu.esrf.test/unitest/unitest.sh | 22 +++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/eu.esrf.test/src/scriptFunction b/eu.esrf.test/src/scriptFunction index 2fdb320..3a11db0 100755 --- a/eu.esrf.test/src/scriptFunction +++ b/eu.esrf.test/src/scriptFunction @@ -3,7 +3,10 @@ xvfbFound=false i=0 x=0 typeFile=".X*-lock" #pattern to only select Xvfb tmp file +path=/tmp/.X*-lock findDisplayNumber(){ +if [ -f "$1/.X0-lock" ]; #if no display root +then for inode in $(ls $1/$typeFile) do owner=$(ls -al $inode | grep -v grep | awk '{ print $3; }') @@ -24,7 +27,7 @@ if ! $xvfbFound ; then #if no display found if [ $x -ne ${array[$c]} ];then var=$x xvfbFound=true - echo $var #if no display is already created, this function will return a free number display + echo $var #if no display is already created, this function will return a free number display break; fi let x++ @@ -36,4 +39,10 @@ if ! $xvfbFound ; echo $var fi + + +else +var=0 +echo $var +fi } diff --git a/eu.esrf.test/unitest/unitest.sh b/eu.esrf.test/unitest/unitest.sh index 10bd625..e200578 100755 --- a/eu.esrf.test/unitest/unitest.sh +++ b/eu.esrf.test/unitest/unitest.sh @@ -18,7 +18,7 @@ function testWithTmp () { } #test the function findDisplayNumber with no temp file belonged to the user -function testwithNoTmp () { +function testwithNoTmpUser () { mkdir 'tmpFile' chmod -R 775 tmpFile cd tmpFile @@ -29,6 +29,26 @@ function testwithNoTmp () { assertEquals '3' $val1 } +function testwithOneTmpbelongRoot () { + mkdir 'tmpFile' + chmod -R 775 tmpFile + cd tmpFile + cd .. + ssh opid29@ub1204 "touch $WORKSPACE/eu.esrf.test/unitest/tmpFile/.X0-lock" + val1=$(findDisplayNumber tmpFile/) + rm -rf tmpFile + assertEquals '1' $val1 +} + +function testwithEmptyFolder () { + mkdir 'tmpFile' + chmod -R 775 tmpFile + cd tmpFile + cd .. + val1=$(findDisplayNumber tmpFile/) + rm -rf tmpFile + assertEquals '0' $val1 +} . "$WORKSPACE/eu.esrf.test/src/shunit2-2.1.6/src/shunit2" From d38c0af36642f8a0f01da2cf62985dfa3672d389 Mon Sep 17 00:00:00 2001 From: Operator account ID23 Date: Wed, 4 Dec 2013 08:54:26 +0100 Subject: [PATCH 14/17] change path to Dawn from beamline to nightly --- eu.esrf.test/squishinstall.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eu.esrf.test/squishinstall.sh b/eu.esrf.test/squishinstall.sh index 74ddbbf..647df07 100755 --- a/eu.esrf.test/squishinstall.sh +++ b/eu.esrf.test/squishinstall.sh @@ -5,7 +5,7 @@ set -eux # error, unset and echo # Options export AUT_NAME=dawn -export AUT_DIR=/sware/isdd/soft/dawn/beamline/linux_x64/dawn +export AUT_DIR=/scisoft/jenkins/dawn/master_nightly/linux_x64/dawn/dawn echo "WORKSPACE", ${WORKSPACE:="./WORKSPACE"} echo "AUT_NAME=${AUT_NAME}" echo "DISPLAY", ${DISPLAY:=":0.0"}\ From 8b7098a470093c006a7d3f9e0bf0395da0ad6164 Mon Sep 17 00:00:00 2001 From: Operator account ID23 Date: Wed, 4 Dec 2013 09:13:24 +0100 Subject: [PATCH 15/17] fix bug --- eu.esrf.test/squishinstall.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eu.esrf.test/squishinstall.sh b/eu.esrf.test/squishinstall.sh index 647df07..8ec6d44 100755 --- a/eu.esrf.test/squishinstall.sh +++ b/eu.esrf.test/squishinstall.sh @@ -5,7 +5,7 @@ set -eux # error, unset and echo # Options export AUT_NAME=dawn -export AUT_DIR=/scisoft/jenkins/dawn/master_nightly/linux_x64/dawn/dawn +export AUT_DIR=/scisoft/jenkins/dawn/master_nightly/linux_x64/dawn echo "WORKSPACE", ${WORKSPACE:="./WORKSPACE"} echo "AUT_NAME=${AUT_NAME}" echo "DISPLAY", ${DISPLAY:=":0.0"}\ From 672fe18333cd251971fbb65bb027723a200a96d5 Mon Sep 17 00:00:00 2001 From: Operator account ID23 Date: Wed, 4 Dec 2013 13:28:14 +0100 Subject: [PATCH 16/17] rm some useless files --- .../dawn_global_startup.py~ | 161 ------------------ eu.esrf.test/src/scriptFunction~ | 37 ---- eu.esrf.test/src/script_jenkins~ | 19 --- eu.esrf.test/src/test_variables.py~ | 28 --- eu.esrf.test/unitest/unitest.sh~ | 37 ---- 5 files changed, 282 deletions(-) delete mode 100644 eu.esrf.test/global_script_esrf/dawn_global_startup.py~ delete mode 100755 eu.esrf.test/src/scriptFunction~ delete mode 100755 eu.esrf.test/src/script_jenkins~ delete mode 100755 eu.esrf.test/src/test_variables.py~ delete mode 100755 eu.esrf.test/unitest/unitest.sh~ diff --git a/eu.esrf.test/global_script_esrf/dawn_global_startup.py~ b/eu.esrf.test/global_script_esrf/dawn_global_startup.py~ deleted file mode 100644 index a546bcd..0000000 --- a/eu.esrf.test/global_script_esrf/dawn_global_startup.py~ +++ /dev/null @@ -1,161 +0,0 @@ -import os, shutil -from datetime import datetime -DAWN_WORKSPACE_ROOT=os.path.join(os.environ['WORKSPACE'],"dawn_workspace") -DAWN_SUITE_WORKSPACE="suite_test_single_workspace" -USE_ATTACH=False - -testSettings.logScreenshotOnFail = True -testSettings.logScreenshotOnError = True - - - -def startDAWNSuiteWorkspace(): - - # We start each test in a new workspace - cwd = os.getcwd() - parent_path, test_name = os.path.split(cwd) - suite_name = os.path.basename(parent_path) - workspace = "%s/%s/%s" % (DAWN_WORKSPACE_ROOT, suite_name, DAWN_SUITE_WORKSPACE) - - start = datetime.now() - startApplication("dawn -consoleLog -data %s" % workspace, "", -1, 90) - end = datetime.now() - - test.log("Application took " + str(end-start) + " to start") - - window = waitForObject(":Workbench Window") - window.setMaximized(True) - # Let any setup items continue (e.g. Jython interpreter setup) - # XXX This is a hack because we don't have a better way to determine if - # the GUI is fully started - snooze(1.0) - test.passes("startOrAttachToDAWNOnly: Success") - - try: - #find should fail fast if no welcome screen - findObject(":Welcome_CTabItem") - dismissWelcomScreen() - except: - pass - - -def startOrAttachToDAWNOnly(clean_workspace=True): - if USE_ATTACH: - attachToApplication("attachable_dawn") - else: - # We start each test in a new workspace - cwd = os.getcwd() - parent_path, test_name = os.path.split(cwd) - suite_name = os.path.basename(parent_path) - workparent = os.path.join(DAWN_WORKSPACE_ROOT, suite_name, test_name) - workspace = os.path.join(workparent, 'workspace') - osgi_user_area = os.path.join(workparent, 'osgi_user_area') - osgi_configuration_area = os.path.join(workparent, 'osgi_configuration_area') - if clean_workspace: - try: - shutil.rmtree(workparent) - except OSError: - # Ignore error here, check below - # that directory is gone - pass - snooze(1) - test.verify(not os.path.exists(workparent), "startOrAttachToDAWNOnly: Workspace is clean") - - start = datetime.now() - startApplication("dawn -consoleLog -data %s -user %s -configuration %s -name %s-%s" % - (workspace, osgi_user_area, osgi_configuration_area, suite_name, test_name), "", -1, 90) - end = datetime.now() - test.log("Application took " + str(end-start) + " to start") - - window = waitForObject(":Workbench Window") - window.setMaximized(True) - # Let any setup items continue (e.g. Jython interpreter setup) - # XXX This is a hack because we don't have a better way to determine if - # the GUI is fully started - snooze(1.0) - test.passes("startOrAttachToDAWNOnly: Success") - -def dismissWelcomScreen(): - clickTab(waitForObject(":Welcome_CTabItem"), 10, 10, 0, Button.Button3) - activateItem(waitForObjectItem(":Pop Up Menu", "Close")) - test.passes("dismissWelcomScreen: Success") - -def startOrAttachToDAWN(): - startOrAttachToDAWNOnly() - dismissWelcomScreen() - test.passes("startOrAttachToDAWN: Success") - -def closeDAWN(): - closeWindow(":Workbench Window") - clickButton(waitForObject(":Confirm Exit.OK_Button")) - test.passes("closeDAWN: Success") - -def closeOrDetachFromDAWN(): - if USE_ATTACH: - # nothing to do - pass - else: - closeDAWN() - test.passes("closeOrDetachFromDAWN: Success") - -def openPerspective(perspectiveName): - waitForObject(":Workbench Window") - activateItem(waitForObjectItem(":_Menu", "Window")) - activateItem(waitForObjectItem(":Window_Menu", "Open Perspective")) - activateItem(waitForObjectItem(":Open Perspective_Menu", "Other...")) - mouseClick(waitForObject("{caption='%s' column='0' container=':Open Perspective_Table' type='com.froglogic.squish.swt.TableCell'}" % perspectiveName), 5, 5, 0, Button.Button1) - mouseClick(waitForObject(":Open Perspective.OK_Button")) - # Opening a perspective can (more than most) kick off things in the background - # This background processing can make the workbench window appear fully ready - # but the perspective isn't. Therefore we snooze a few seconds to let everything - # catchup - waitForObject(":Workbench Window") - snooze(3.0) - waitForObject(":Workbench Window") - test.passes("openPerspective: %s" % perspectiveName) - -def openView(viewName, matchOpen=False): - ''' Open the view named viewName. If matchOpen is true, will assume that an open view with - viewName in the title bar of the view is the expected one and only activate it ''' - waitForObject(":Workbench Window") - if matchOpen: - viewRealObjectName = "{caption='%s' type='org.eclipse.swt.custom.CTabItem' window=':Workbench Window'}" % viewName; - if object.exists(viewRealObjectName): - mouseClick(waitForObject(viewRealObjectName)) - test.passes("openView (matchOpen): %s" % viewName) - return - - activateItem(waitForObjectItem(":_Menu", "Window")) - activateItem(waitForObjectItem(":Window_Menu", "Show View")) - activateItem(waitForObjectItem(":Show View_Menu", "Other...")) - type(waitForObject(":Show View_Text"), viewName) - mouseClick(waitForObjectItem(":Show View_Tree", viewName)) - mouseClick(waitForObject(":Show View.OK_Button")) - waitForObject(":Workbench Window") - test.passes("openView: %s" % viewName) - - - -def getErrorItems(): - ''' Return the Java Array that contains the list of entries in the Error Log ''' - openView("Error Log", True) - errorTree = waitForObject(":Error Log_Tree") - return errorTree.getItems() - -def openAndClearErrorLog(): - ''' Open and clear the Eclipse Error Log. Use getErrorItems() first to find out if there is - anything in them ''' - if getErrorItems().length > 0: - snooze(2) - mouseClick(waitForObject(":Delete Log_ToolItem")) - clickButton(waitForObject(":Confirm Delete.OK_Button")) - -def verifyAndClearErrorLog(): - ''' Verifies that the error log is empty and clears it if not ''' - if getErrorItems().length > 0: - test.fail("Items are in error log view (if this test fails, see console output as -consoleLog is on)") - mouseClick(waitForObject(":Delete Log_ToolItem")) - clickButton(waitForObject(":Confirm Delete.OK_Button")) - else: - # provide a less verbose message when the test just passed - test.passes("No items are in error log view") diff --git a/eu.esrf.test/src/scriptFunction~ b/eu.esrf.test/src/scriptFunction~ deleted file mode 100755 index ba7e68c..0000000 --- a/eu.esrf.test/src/scriptFunction~ +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash -xvfbFound=false -foundDisplay=false -i=0 -x=0 -typeFile=".X*-lock" #pattern to only select Xvfb tmp file -findDisplayNumber(){ - -for inode in $(ls $1/$typeFile) -do - owner=$(ls -al $inode | grep -v grep | awk '{ print $3; }') - array[$i]=$(echo "$inode" | tr -d [:alpha:] | tr -d [:punct:]) #make a list of all the display number for, in another case find a free number - if [ "$USER" = "$owner" ];then - xvfbFound=true - var=$(echo "$inode" | tr -d [:alpha:] | tr -d [:punct:]) - echo $var #return the availaible display for the logged user - break; - fi - let i++ -done -if [ $xvfbFound=="false" ]; then #if no display found - var1=${#array[@]} - for (( c=0; c/$WORKSPACE/serverlog -sleep 1 -/$WORKSPACE/squish/bin/squishrunner --testsuite $WORKSPACE/org.dawnsci.squishtests/$1/ --testcase $2/ --useWaitFor>>/$WORKSPACE/log/#$1_squishlog -var1=$(ps -aef |grep squishserver | grep -v grep | awk '{ print $2; }' | head -1) -kill -9 $var1 -var2=$(ps -aef |grep Xvfb | grep -v grep | awk '{ print $2; }' | head -1) -kill -9 $var2 - - diff --git a/eu.esrf.test/src/test_variables.py~ b/eu.esrf.test/src/test_variables.py~ deleted file mode 100755 index 53a463b..0000000 --- a/eu.esrf.test/src/test_variables.py~ +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/python2.6 -import os,shutil -queue = {'suite_workflows_general': {'tst_case':'tst_open_examples'}} -#only one queue allowed for one suite_test_case -#queue = {'suite_workflows_general': {'tst_case2':'tst_open_examples'}} -#queue.update({'suite_usecases_general':{'tst_case':'tst_hdf5_large_tree'}}) -#queue.update({'suite_workflows_bignexus':{'tst_case':'tst_slicedata_dbrowsing'}}) -#queue['suite_workflows_bignexus'] = {'tst_case':'tst_slicedata_dexplore'} - - -def check_variable(testSuiteName): - path_global_script=os.path.join(os.environ['WORKSPACE'],'org.dawnsci.squishtests',testSuiteName,'shared/scripts') - if os.path.exists(path_global_script)== True: - shutil.rmtree(path_global_script) - shutil.copytree(os.path.join(os.environ['WORKSPACE'] +'/eu.esrf.test/global_script_esrf') ,path_global_script) - -def setup_log(): - path_log=os.path.join(os.environ['WORKSPACE'] +'/log/') - if os.path.exists(path_log)== True: - shutil.rmtree(path_log) - os.mkdir(path_log) - -setup_log() -for testSuiteName in queue.keys(): - check_variable(testSuiteName) - for tst in queue[testSuiteName]: - os.chdir(os.path.join(os.environ['WORKSPACE'],'eu.esrf.test/src')) - os.popen("./script_jenkins "+testSuiteName+" "+queue[testSuiteName][tst], "r").read() diff --git a/eu.esrf.test/unitest/unitest.sh~ b/eu.esrf.test/unitest/unitest.sh~ deleted file mode 100755 index b58e9dd..0000000 --- a/eu.esrf.test/unitest/unitest.sh~ +++ /dev/null @@ -1,37 +0,0 @@ - #! /usr/bin/env sh -echo $WORKSPACE/eu.esrf.test/src/scriptFunction -### unitTest.sh ### - -#source /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/scriptFunction -source $WORKSPACE/eu.esrf.test/src/scriptFunction -#test the function findDisplayNumber with a temp file belonged to the user -function testWithTmp () { - mkdir 'tmpFile' - chmod -R 775 tmpFile - cd tmpFile - touch .X2-lock - cd .. - ssh opid29@ub1204 "touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X0-lock;touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X1-lock;touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X4-lock;" - val=$(findDisplayNumber tmpFile/) - rm -rf tmpFile - assertEquals '2' $val -} - -#test the function findDisplayNumber with no temp file belonged to the user -function testwithNoTmp () { - mkdir 'tmpFile' - chmod -R 775 tmpFile - cd tmpFile - cd .. - ssh opid29@ub1204 "touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X0-lock;touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X1-lock;touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X2-lock;touch /scisoft/jenkins/ub1204_opid23_test/dawn-test/eu.esrf.test/src/Tests/tmpFile/.X4-lock" - val1=$(findDisplayNumber tmpFile/) - rm -rf tmpFile - assertEquals '3' $val1 -} - - - -. "$WORKSPACE/eu.esrf.test/src/shunit2-2.1.6/src/shunit2" - - - From ad15e2ff5b787a5c00db09ee8ac33c8ff64dadbc Mon Sep 17 00:00:00 2001 From: Operator account ID23 Date: Wed, 4 Dec 2013 13:29:35 +0100 Subject: [PATCH 17/17] remove file --- .../global_scripts/dawn_global_startup.py~ | 160 ------------------ 1 file changed, 160 deletions(-) delete mode 100644 eu.esrf.test/global_scripts/dawn_global_startup.py~ diff --git a/eu.esrf.test/global_scripts/dawn_global_startup.py~ b/eu.esrf.test/global_scripts/dawn_global_startup.py~ deleted file mode 100644 index 595019a..0000000 --- a/eu.esrf.test/global_scripts/dawn_global_startup.py~ +++ /dev/null @@ -1,160 +0,0 @@ -DAWN_WORKSPACE_ROOT="/workspace" -DAWN_SUITE_WORKSPACE="suite_test_single_workspace" -USE_ATTACH=False - -testSettings.logScreenshotOnFail = True -testSettings.logScreenshotOnError = True - -import os, shutil -from datetime import datetime - -def startDAWNSuiteWorkspace(): - - # We start each test in a new workspace - cwd = os.getcwd() - parent_path, test_name = os.path.split(cwd) - suite_name = os.path.basename(parent_path) - workspace = "%s/%s/%s" % (DAWN_WORKSPACE_ROOT, suite_name, DAWN_SUITE_WORKSPACE) - - start = datetime.now() - startApplication("dawn -consoleLog -data %s" % workspace, "", -1, 90) - end = datetime.now() - - test.log("Application took " + str(end-start) + " to start") - - window = waitForObject(":Workbench Window") - window.setMaximized(True) - # Let any setup items continue (e.g. Jython interpreter setup) - # XXX This is a hack because we don't have a better way to determine if - # the GUI is fully started - snooze(1.0) - test.passes("startOrAttachToDAWNOnly: Success") - - try: - #find should fail fast if no welcome screen - findObject(":Welcome_CTabItem") - dismissWelcomScreen() - except: - pass - - -def startOrAttachToDAWNOnly(clean_workspace=True): - if USE_ATTACH: - attachToApplication("attachable_dawn") - else: - # We start each test in a new workspace - cwd = os.getcwd() - parent_path, test_name = os.path.split(cwd) - suite_name = os.path.basename(parent_path) - workparent = os.path.join(DAWN_WORKSPACE_ROOT, suite_name, test_name) - workspace = os.path.join(workparent, 'workspace') - osgi_user_area = os.path.join(workparent, 'osgi_user_area') - osgi_configuration_area = os.path.join(workparent, 'osgi_configuration_area') - if clean_workspace: - try: - shutil.rmtree(workparent) - except OSError: - # Ignore error here, check below - # that directory is gone - pass - snooze(1) - test.verify(not os.path.exists(workparent), "startOrAttachToDAWNOnly: Workspace is clean") - - start = datetime.now() - startApplication("dawn -consoleLog -data %s -user %s -configuration %s -name %s-%s" % - (workspace, osgi_user_area, osgi_configuration_area, suite_name, test_name), "", -1, 90) - end = datetime.now() - test.log("Application took " + str(end-start) + " to start") - - window = waitForObject(":Workbench Window") - window.setMaximized(True) - # Let any setup items continue (e.g. Jython interpreter setup) - # XXX This is a hack because we don't have a better way to determine if - # the GUI is fully started - snooze(1.0) - test.passes("startOrAttachToDAWNOnly: Success") - -def dismissWelcomScreen(): - clickTab(waitForObject(":Welcome_CTabItem"), 10, 10, 0, Button.Button3) - activateItem(waitForObjectItem(":Pop Up Menu", "Close")) - test.passes("dismissWelcomScreen: Success") - -def startOrAttachToDAWN(): - startOrAttachToDAWNOnly() - dismissWelcomScreen() - test.passes("startOrAttachToDAWN: Success") - -def closeDAWN(): - closeWindow(":Workbench Window") - clickButton(waitForObject(":Confirm Exit.OK_Button")) - test.passes("closeDAWN: Success") - -def closeOrDetachFromDAWN(): - if USE_ATTACH: - # nothing to do - pass - else: - closeDAWN() - test.passes("closeOrDetachFromDAWN: Success") - -def openPerspective(perspectiveName): - waitForObject(":Workbench Window") - activateItem(waitForObjectItem(":_Menu", "Window")) - activateItem(waitForObjectItem(":Window_Menu", "Open Perspective")) - activateItem(waitForObjectItem(":Open Perspective_Menu", "Other...")) - mouseClick(waitForObject("{caption='%s' column='0' container=':Open Perspective_Table' type='com.froglogic.squish.swt.TableCell'}" % perspectiveName), 5, 5, 0, Button.Button1) - mouseClick(waitForObject(":Open Perspective.OK_Button")) - # Opening a perspective can (more than most) kick off things in the background - # This background processing can make the workbench window appear fully ready - # but the perspective isn't. Therefore we snooze a few seconds to let everything - # catchup - waitForObject(":Workbench Window") - snooze(3.0) - waitForObject(":Workbench Window") - test.passes("openPerspective: %s" % perspectiveName) - -def openView(viewName, matchOpen=False): - ''' Open the view named viewName. If matchOpen is true, will assume that an open view with - viewName in the title bar of the view is the expected one and only activate it ''' - waitForObject(":Workbench Window") - if matchOpen: - viewRealObjectName = "{caption='%s' type='org.eclipse.swt.custom.CTabItem' window=':Workbench Window'}" % viewName; - if object.exists(viewRealObjectName): - mouseClick(waitForObject(viewRealObjectName)) - test.passes("openView (matchOpen): %s" % viewName) - return - - activateItem(waitForObjectItem(":_Menu", "Window")) - activateItem(waitForObjectItem(":Window_Menu", "Show View")) - activateItem(waitForObjectItem(":Show View_Menu", "Other...")) - type(waitForObject(":Show View_Text"), viewName) - mouseClick(waitForObjectItem(":Show View_Tree", viewName)) - mouseClick(waitForObject(":Show View.OK_Button")) - waitForObject(":Workbench Window") - test.passes("openView: %s" % viewName) - - - -def getErrorItems(): - ''' Return the Java Array that contains the list of entries in the Error Log ''' - openView("Error Log", True) - errorTree = waitForObject(":Error Log_Tree") - return errorTree.getItems() - -def openAndClearErrorLog(): - ''' Open and clear the Eclipse Error Log. Use getErrorItems() first to find out if there is - anything in them ''' - if getErrorItems().length > 0: - snooze(2) - mouseClick(waitForObject(":Delete Log_ToolItem")) - clickButton(waitForObject(":Confirm Delete.OK_Button")) - -def verifyAndClearErrorLog(): - ''' Verifies that the error log is empty and clears it if not ''' - if getErrorItems().length > 0: - test.fail("Items are in error log view (if this test fails, see console output as -consoleLog is on)") - mouseClick(waitForObject(":Delete Log_ToolItem")) - clickButton(waitForObject(":Confirm Delete.OK_Button")) - else: - # provide a less verbose message when the test just passed - test.passes("No items are in error log view")
+

shUnit2 2.1.x README

+ +
+

code.google.com

+

This project is stored on code.google.com as http://code.google.com/p/shunit2/. +All releases as of 2.1.4 and full source are available there. Documentation is +included as part of the source and each release. Source code is stored in +Subversion and can be accessed using the following information.

+

Browse the code in a web browser:

+ +

Check out the code locally

+
+$ svn checkout http://shunit2.googlecode.com/svn/trunk/ shflags-read-only
+
+
+
+

SourceForge

+

DEPRECATED

+

This project is stored on SourceForge as http://sf.net/projects/shunit2. The +source code is stored in Subversion and can be accessed using the following +information.

+

Check out the code locally

+
+$ svn co https://shunit2.svn.sourceforge.net/svnroot/shunit2/trunk/source/2.1 shunit2
+
+

Browse the code in a web browser:

+ +
+
+

Making a release

+

For these steps, it is assumed we are working with release 2.0.0.

+

Steps:

+
    +
  • write release notes
  • +
  • update version
  • +
  • finish changelog
  • +
  • check all the code in
  • +
  • tag the release
  • +
  • export the release
  • +
  • create tarball
  • +
  • md5sum the tarball and sign with gpg
  • +
  • update website
  • +
  • post to SourceForge and Freshmeat
  • +
+
+

Write Release Notes

+

This should be pretty self explanatory. Use one of the release notes from a +previous release as an example.

+

The versions of the various platforms and shells are included when the +master unit test script is run, or when bin/gen_test_results.sh is +used. To determine the versions of the installed shells by hand, use the +lib/versions script.

+

Alternatively, do the following:

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ShellOSNotes
bash $ bash --version
dashLinux$ dpkg -l |grep dash
ksh $ ksh --version +-or- +$ echo 'echo $KSH_VERSION' |ksh
Cygwinsee pdksh
Solaris$ strings /usr/bin/ksh |grep 'Version'
pdksh $ strings /bin/pdksh |grep 'PD KSH'
Cygwinlook in the downloaded Cygwin directory
shSolarisnot possible
zsh $ zsh --version
+
+
+

Update Version

+

Edit src/shell/shunit2 and change the version number in the comment, as well +as in the SHUNIT_VERSION variable.

+
+
+

Finish Documentation

+

Make sure that any remaining changes get put into the CHANGES-X.X.txt file.

+

Finish writing the RELEASE_NOTES-X.X.X.txt. If necessary, run it +through the fmt command to make it pretty (hopefully it is already).

+
+$ fmt -w 80 RELEASE_NOTES-2.0.0.txt >RELEASE_NOTES-2.0.0.txt.new
+$ mv RELEASE_NOTES-2.0.0.txt.new RELEASE_NOTES-2.0.0.txt
+
+

We want to have an up-to-date version of the documentation in the release, so +we'd better build it.

+
+$ pwd
+.../shunit2/source/2.1
+$ cd doc
+$ RST2HTML_OPTS='--stylesheet-path=rst2html.css'
+$ rst2html ${RST2HTML_OPTS} shunit2.txt >shunit2.html
+$ rst2html ${RST2HTML_OPTS} README.txt >README.html
+
+
+
+

Check In All the Code

+

This step is pretty self-explanatory

+
+$ pwd
+.../shunit2/source/2.0
+$ svn ci -m "finalizing release"
+
+
+
+

Tag the Release

+
+$ pwd
+.../shunit2/source
+$ ls
+2.0  2.1
+$ svn cp -m "Release 2.0.0" 2.0 https://shunit2.googlecode.com/svn/tags/source/2.0.0
+
+
+
+

Export the Release

+
+$ pwd
+.../shunit2/builds
+$ svn export https://shunit2.googlecode.com/svn/tags/source/2.0.0 shunit2-2.0.0
+
+
+
+

Create Tarball

+
+$ tar cfz ../releases/shunit2-2.0.0.tgz shunit2-2.0.0
+
+
+
+

Sign the Tarball with gpg

+
+$ cd ../releases
+$ gpg --default-key kate.ward@forestent.com --detach-sign shunit2-2.0.0.tgz
+
+
+
+

Update Website

+

Again, pretty self-explanatory. Make sure to copy the GPG signature file. Once +that is done, make sure to tag the website so we can go back in time if needed.

+
+$ pwd
+.../shunit2
+$ ls
+source  website
+$ svn cp -m "Release 2.0.0" \
+website https://shunit2.googlecode.com/svn/tags/website/20060916
+
+

Now, update the website. It too is held in Subversion, so ssh into the web +server and use svn up to grab the latest version.

+
+
+

Post to code.google.com and Freshmeat

+ +
+
+ +