Commit 35b1bdd346b05fec163c959cb8cc27985adb4c74

Authored by Jürgen Knödlseder
1 parent d7f7af88

Add base class unit test to enhance coverage (#1828)

pyext/ctlikelihood.i
@@ -26,9 +26,44 @@ @@ -26,9 +26,44 @@
26 26
27 %{ 27 %{
28 /* Put headers and other declarations here that are needed for compilation */ 28 /* Put headers and other declarations here that are needed for compilation */
  29 +#define SWIG
29 #include "ctlikelihood.hpp" 30 #include "ctlikelihood.hpp"
  31 +
  32 +
  33 +/***********************************************************************//**
  34 + * @class cslikelihood
  35 + *
  36 + * @brief cslikelihood base class
  37 + *
  38 + * This class is a non-abstract C++ implementation of the ctlikelihood base
  39 + * class. It serves as Python base class since Python does not know about
  40 + * abstract classes.
  41 + ***************************************************************************/
  42 +class cslikelihood : public ctlikelihood {
  43 +public:
  44 + // Constructors and destructors
  45 + cslikelihood(const std::string& name, const std::string& version) :
  46 + ctlikelihood(name, version) {}
  47 + cslikelihood(const std::string& name, const std::string& version,
  48 + const GObservations& obs) :
  49 + ctlikelihood(name, version, obs) {}
  50 + cslikelihood(const std::string& name, const std::string& version,
  51 + int argc, char* argv[]) :
  52 + ctlikelihood(name, version, argc, argv){}
  53 + cslikelihood(const cslikelihood& app) : ctlikelihood(app) {}
  54 + virtual ~cslikelihood(void) {}
  55 +
  56 + // Dummy methods (implementation makes this class non-abstract)
  57 + virtual void clear(void) {}
  58 + virtual void run(void) {}
  59 + virtual void save(void) {}
  60 +};
30 %} 61 %}
31 62
  63 +// Include (int ARGC, char **ARGV) typemap to allow passing command line
  64 +// arguments to GApplication constructor
  65 +%include "argcargv.i"
  66 +
32 67
33 /***********************************************************************//** 68 /***********************************************************************//**
34 * @class ctlikelihood 69 * @class ctlikelihood
@@ -54,11 +89,65 @@ public: @@ -54,11 +89,65 @@ public:
54 89
55 // Methods 90 // Methods
56 const GOptimizer* opt(void) const; 91 const GOptimizer* opt(void) const;
  92 +
  93 + // Make methods private in Python by prepending an underscore
  94 + %rename(_evaluate) evaluate;
  95 +
  96 + // Protected methods
  97 + double evaluate(GModelPar& par, const double& value);
  98 +};
  99 +
  100 +
  101 +/***********************************************************************//**
  102 + * @class cslikelihood
  103 + *
  104 + * @brief Base class for likelihood scripts
  105 + *
  106 + * This is the base class from which likelihood scripts should derive.
  107 + ***************************************************************************/
  108 +class cslikelihood : public ctlikelihood {
  109 +public:
  110 + // Constructors and destructors
  111 + cslikelihood(const std::string& name, const std::string& version);
  112 + cslikelihood(const std::string& name, const std::string& version,
  113 + const GObservations& obs);
  114 + cslikelihood(const std::string& name, const std::string& version,
  115 + int ARGC, char **ARGV);
  116 + cslikelihood(const cslikelihood& app);
  117 + virtual ~cslikelihood(void);
  118 +
  119 + // Methods
  120 + virtual void clear(void);
  121 + virtual void run(void);
  122 + virtual void save(void);
57 }; 123 };
58 124
59 125
60 /***********************************************************************//** 126 /***********************************************************************//**
61 - * @brief Likelihood tool Python extensions 127 + * @brief Likelihood tool base class C++ extensions
62 ***************************************************************************/ 128 ***************************************************************************/
63 %extend ctlikelihood { 129 %extend ctlikelihood {
64 } 130 }
  131 +
  132 +
  133 +/***********************************************************************//**
  134 + * @brief Likelihood tool base class Python extensions
  135 + ***************************************************************************/
  136 +%pythoncode %{
  137 +
  138 +# Initialise application by calling the appropriate base class constructor.
  139 +# The function supports either an observation container, or an argument
  140 +# list or no argument as "argv" parameter. The function also writes the
  141 +# header in the log file and switches the date on for logging.
  142 +def _init_cslikelihood(self, argv):
  143 + if len(argv) > 0 and isinstance(argv[0],gammalib.GObservations):
  144 + cslikelihood.__init__(self, self._name, self._version, argv[0])
  145 + elif len(argv) > 0:
  146 + cslikelihood.__init__(self, self._name, self._version, *argv)
  147 + else:
  148 + cslikelihood.__init__(self, self._name, self._version)
  149 + # Set logger properties
  150 + self._log_header()
  151 + self._log.date(True)
  152 +cslikelihood._init_cslikelihood = _init_cslikelihood
  153 +%}
pyext/ctobservation.i
@@ -26,14 +26,49 @@ @@ -26,14 +26,49 @@
26 26
27 %{ 27 %{
28 /* Put headers and other declarations here that are needed for compilation */ 28 /* Put headers and other declarations here that are needed for compilation */
  29 +#define SWIG
29 #include "ctobservation.hpp" 30 #include "ctobservation.hpp"
  31 +
  32 +
  33 +/***********************************************************************//**
  34 + * @class csobservation
  35 + *
  36 + * @brief csobservation base class
  37 + *
  38 + * This class is a non-abstract C++ implementation of the ctobservation base
  39 + * class. It serves as Python base class since Python does not know about
  40 + * abstract classes.
  41 + ***************************************************************************/
  42 +class csobservation : public ctobservation {
  43 +public:
  44 + // Constructors and destructors
  45 + csobservation(const std::string& name, const std::string& version) :
  46 + ctobservation(name, version) {}
  47 + csobservation(const std::string& name, const std::string& version,
  48 + const GObservations& obs) :
  49 + ctobservation(name, version, obs) {}
  50 + csobservation(const std::string& name, const std::string& version,
  51 + int argc, char* argv[]) :
  52 + ctobservation(name, version, argc, argv){}
  53 + csobservation(const csobservation& app) : ctobservation(app) {}
  54 + virtual ~csobservation(void) {}
  55 +
  56 + // Dummy methods (implementation makes this class non-abstract)
  57 + virtual void clear(void) {}
  58 + virtual void run(void) {}
  59 + virtual void save(void) {}
  60 +};
30 %} 61 %}
31 62
  63 +// Include (int ARGC, char **ARGV) typemap to allow passing command line
  64 +// arguments to GApplication constructor
  65 +%include "argcargv.i"
  66 +
32 67
33 /***********************************************************************//** 68 /***********************************************************************//**
34 * @class ctobservation 69 * @class ctobservation
35 * 70 *
36 - * @brief Base class for likelihood tools 71 + * @brief Base class for observation tools
37 ***************************************************************************/ 72 ***************************************************************************/
38 class ctobservation : public ctool { 73 class ctobservation : public ctool {
39 74
@@ -43,7 +78,7 @@ public: @@ -43,7 +78,7 @@ public:
43 ctobservation(const std::string& name, const std::string& version, 78 ctobservation(const std::string& name, const std::string& version,
44 const GObservations& obs); 79 const GObservations& obs);
45 ctobservation(const std::string& name, const std::string& version, 80 ctobservation(const std::string& name, const std::string& version,
46 - int argc, char* argv[]); 81 + int ARGC, char **ARGV);
47 ctobservation(const ctobservation& app); 82 ctobservation(const ctobservation& app);
48 virtual ~ctobservation(void); 83 virtual ~ctobservation(void);
49 84
@@ -66,6 +101,31 @@ public: @@ -66,6 +101,31 @@ public:
66 101
67 102
68 /***********************************************************************//** 103 /***********************************************************************//**
  104 + * @class csobservation
  105 + *
  106 + * @brief Base class for observation scripts
  107 + *
  108 + * This is the base class from which observation scripts should derive.
  109 + ***************************************************************************/
  110 +class csobservation : public ctobservation {
  111 +public:
  112 + // Constructors and destructors
  113 + csobservation(const std::string& name, const std::string& version);
  114 + csobservation(const std::string& name, const std::string& version,
  115 + const GObservations& obs);
  116 + csobservation(const std::string& name, const std::string& version,
  117 + int ARGC, char **ARGV);
  118 + csobservation(const csobservation& app);
  119 + virtual ~csobservation(void);
  120 +
  121 + // Methods
  122 + virtual void clear(void);
  123 + virtual void run(void);
  124 + virtual void save(void);
  125 +};
  126 +
  127 +
  128 +/***********************************************************************//**
69 * @brief Observation tool base class C++ extensions 129 * @brief Observation tool base class C++ extensions
70 ***************************************************************************/ 130 ***************************************************************************/
71 %extend ctobservation { 131 %extend ctobservation {
@@ -76,6 +136,24 @@ public: @@ -76,6 +136,24 @@ public:
76 * @brief Observation tool base class Python extensions 136 * @brief Observation tool base class Python extensions
77 ***************************************************************************/ 137 ***************************************************************************/
78 %pythoncode %{ 138 %pythoncode %{
  139 +
  140 +# Initialise application by calling the appropriate base class constructor.
  141 +# The function supports either an observation container, or an argument
  142 +# list or no argument as "argv" parameter. The function also writes the
  143 +# header in the log file and switches the date on for logging.
  144 +def _init_csobservation(self, argv):
  145 + if len(argv) > 0 and isinstance(argv[0],gammalib.GObservations):
  146 + csobservation.__init__(self, self._name, self._version, argv[0])
  147 + elif len(argv) > 0:
  148 + csobservation.__init__(self, self._name, self._version, *argv)
  149 + else:
  150 + csobservation.__init__(self, self._name, self._version)
  151 + # Set logger properties
  152 + self._log_header()
  153 + self._log.date(True)
  154 +csobservation._init_csobservation = _init_csobservation
  155 +
  156 +# Define an iterator over all observations
79 def _unbinned_observations(self): 157 def _unbinned_observations(self):
80 obs = self._first_unbinned_observation() 158 obs = self._first_unbinned_observation()
81 while obs != None: 159 while obs != None:
pyext/ctool.i
@@ -86,12 +86,12 @@ public: @@ -86,12 +86,12 @@ public:
86 %rename(_time_reference) time_reference; 86 %rename(_time_reference) time_reference;
87 %rename(_get_observations) get_observations; 87 %rename(_get_observations) get_observations;
88 %rename(_setup_observations) setup_observations; 88 %rename(_setup_observations) setup_observations;
  89 + %rename(_setup_models) setup_models;
89 %rename(_create_ebounds) create_ebounds; 90 %rename(_create_ebounds) create_ebounds;
90 %rename(_create_map) create_map; 91 %rename(_create_map) create_map;
91 %rename(_create_cube) create_cube; 92 %rename(_create_cube) create_cube;
92 %rename(_create_cta_obs) create_cta_obs; 93 %rename(_create_cta_obs) create_cta_obs;
93 %rename(_require_inobs) require_inobs; 94 %rename(_require_inobs) require_inobs;
94 - %rename(_require_inobs_nolist) require_inobs_nolist;  
95 %rename(_require_inobs_nocube) require_inobs_nocube; 95 %rename(_require_inobs_nocube) require_inobs_nocube;
96 %rename(_log_observations) log_observations; 96 %rename(_log_observations) log_observations;
97 %rename(_log_models) log_models; 97 %rename(_log_models) log_models;
@@ -128,9 +128,11 @@ public: @@ -128,9 +128,11 @@ public:
128 128
129 // Protected methods that check user parameters 129 // Protected methods that check user parameters
130 void require_inobs(const std::string& method); 130 void require_inobs(const std::string& method);
131 - void require_inobs_nolist(const std::string& method);  
132 void require_inobs_nocube(const std::string& method); 131 void require_inobs_nocube(const std::string& method);
133 132
  133 + // Protected methods that extract user parameters
  134 + GCTARoi get_roi(void);
  135 +
134 // Protected methods for logging 136 // Protected methods for logging
135 void log_observations(const GChatter& chatter, 137 void log_observations(const GChatter& chatter,
136 const GObservations& obs, 138 const GObservations& obs,
@@ -139,9 +141,6 @@ public: @@ -139,9 +141,6 @@ public:
139 const GModels& models, 141 const GModels& models,
140 const std::string& what = "Model"); 142 const std::string& what = "Model");
141 143
142 - // Protected methods that extract user parameters  
143 - GCTARoi get_roi(void);  
144 -  
145 // Protected support methods 144 // Protected support methods
146 void set_response(GObservations& obs); 145 void set_response(GObservations& obs);
147 std::vector<bool> set_edisp(GObservations& obs, const bool& edisp) const; 146 std::vector<bool> set_edisp(GObservations& obs, const bool& edisp) const;
src/ctulimit/ctulimit.par
@@ -38,7 +38,7 @@ eref, r, h, 1.0,,, &quot;Reference energy for differential limit (TeV)&quot; @@ -38,7 +38,7 @@ eref, r, h, 1.0,,, &quot;Reference energy for differential limit (TeV)&quot;
38 emin, r, h, 1.0,,, "Minimum energy for integral flux limit (TeV)" 38 emin, r, h, 1.0,,, "Minimum energy for integral flux limit (TeV)"
39 emax, r, h, 100.0,,, "Maximum energy for integral flux limit (TeV)" 39 emax, r, h, 100.0,,, "Maximum energy for integral flux limit (TeV)"
40 tol, r, h, 1e-5,,, "Computation tolerance" 40 tol, r, h, 1e-5,,, "Computation tolerance"
41 -max_iter, i, h, 50,,, "Maximum number of iterations" 41 +max_iter, i, h, 50,1,1000, "Maximum number of iterations"
42 42
43 # 43 #
44 # Standard parameters 44 # Standard parameters
src/support/ctlikelihood.hpp
@@ -61,15 +61,20 @@ public: @@ -61,15 +61,20 @@ public:
61 // Methods 61 // Methods
62 const GOptimizer* opt(void) const; 62 const GOptimizer* opt(void) const;
63 63
  64 +#ifndef SWIG
  65 +protected:
  66 +#endif
  67 + // Protected methods in C++, public in SWIG interface
  68 + double evaluate(GModelPar& par, const double& value);
  69 +
64 protected: 70 protected:
65 // Protected methods 71 // Protected methods
66 void init_members(void); 72 void init_members(void);
67 void copy_members(const ctlikelihood& app); 73 void copy_members(const ctlikelihood& app);
68 void free_members(void); 74 void free_members(void);
69 - double evaluate(GModelPar& par, const double& value);  
70 75
71 // Protected members 76 // Protected members
72 - GOptimizerLM m_opt; //!< Optimizer 77 + GOptimizerLM m_opt; //!< Optimizer
73 }; 78 };
74 79
75 80
src/support/ctobservation.hpp
@@ -64,9 +64,7 @@ public: @@ -64,9 +64,7 @@ public:
64 // Methods 64 // Methods
65 const GObservations& obs(void) const; 65 const GObservations& obs(void) const;
66 66
67 -#ifdef SWIG  
68 -public:  
69 -#else 67 +#ifndef SWIG
70 protected: 68 protected:
71 #endif 69 #endif
72 // Iterator methods and members 70 // Iterator methods and members
src/support/ctool.cpp
@@ -549,10 +549,10 @@ GEbounds ctool::create_ebounds(void) @@ -549,10 +549,10 @@ GEbounds ctool::create_ebounds(void)
549 file.close(); 549 file.close();
550 std::string msg = "No extension with name \"EBOUNDS\" or" 550 std::string msg = "No extension with name \"EBOUNDS\" or"
551 " \"ENERGYBINS\" found in FITS file" 551 " \"ENERGYBINS\" found in FITS file"
552 - " \""+ebinfile+"\".\n"  
553 - "An \"EBOUNDS\" or \"ENERGYBINS\" extension"  
554 - " is required if the parameter \"ebinalg\""  
555 - " is set to \"FILE\"."; 552 + " \""+ebinfile+"\". An \"EBOUNDS\" or "
  553 + "\"ENERGYBINS\" extension is required if "
  554 + "the parameter \"ebinalg\" is set to "
  555 + "\"FILE\".";
556 throw GException::invalid_value(G_CREATE_EBOUNDS, msg); 556 throw GException::invalid_value(G_CREATE_EBOUNDS, msg);
557 } 557 }
558 } 558 }
@@ -788,6 +788,9 @@ GCTAObservation ctool::create_cta_obs(void) @@ -788,6 +788,9 @@ GCTAObservation ctool::create_cta_obs(void)
788 * 788 *
789 * Throw an exception if the "inobs" parameter is either "NONE" or an empty 789 * Throw an exception if the "inobs" parameter is either "NONE" or an empty
790 * string. 790 * string.
  791 + *
  792 + * @todo This method is only used by csobsinfo, csresmap and csspec. We
  793 + * should try to get rid of it
791 ***************************************************************************/ 794 ***************************************************************************/
792 void ctool::require_inobs(const std::string& method) 795 void ctool::require_inobs(const std::string& method)
793 { 796 {
@@ -810,63 +813,13 @@ void ctool::require_inobs(const std::string&amp; method) @@ -810,63 +813,13 @@ void ctool::require_inobs(const std::string&amp; method)
810 813
811 814
812 /***********************************************************************//** 815 /***********************************************************************//**
813 - * @brief Throws exception if inobs parameter is an event list  
814 - *  
815 - * @param[in] method Method name.  
816 - *  
817 - * Throw an exception if the inobs parameter is an event list.  
818 - ***************************************************************************/  
819 -void ctool::require_inobs_nolist(const std::string& method)  
820 -{  
821 - // Get inobs filename  
822 - GFilename filename = (*this)["inobs"].filename();  
823 -  
824 - // Continue only if we have a FITS file  
825 - if (filename.is_fits()) {  
826 -  
827 - // Signal no list  
828 - bool is_list = false;  
829 -  
830 - // Try loading file as counts cube. If this is successful then  
831 - // throw an exception  
832 - try {  
833 -  
834 - // Load list from file  
835 - GCTAEventList list(filename);  
836 -  
837 - // If we're still alive then signal that we have a list  
838 - is_list = true;  
839 -  
840 - }  
841 -  
842 - // Catch any exceptions  
843 - catch (...) {  
844 - ;  
845 - }  
846 -  
847 - // If we have an event list then throw an exception  
848 - if (is_list) {  
849 - std::string msg = "An event list has been specified for the "  
850 - "\"inobs\" parameter, yet no event list "  
851 - "can be specified as input observation."  
852 - " Instead, specify a counts cube or an "  
853 - "observation definition file.";  
854 - throw GException::invalid_value(method, msg);  
855 - }  
856 -  
857 - } // endif: we had a FITS file  
858 -  
859 - // Return  
860 - return;  
861 -}  
862 -  
863 -  
864 -/***********************************************************************//**  
865 * @brief Throws exception if inobs parameter is a counts cube 816 * @brief Throws exception if inobs parameter is a counts cube
866 * 817 *
867 * @param[in] method Method name. 818 * @param[in] method Method name.
868 * 819 *
869 * Throw an exception if the inobs parameter is a counts cube. 820 * Throw an exception if the inobs parameter is a counts cube.
  821 + *
  822 + * @todo This method is only used by ctobssim. We should try to get rid of it
870 ***************************************************************************/ 823 ***************************************************************************/
871 void ctool::require_inobs_nocube(const std::string& method) 824 void ctool::require_inobs_nocube(const std::string& method)
872 { 825 {
@@ -1542,6 +1495,9 @@ GSkyDir ctool::get_mean_pointing(const GObservations&amp; obs) @@ -1542,6 +1495,9 @@ GSkyDir ctool::get_mean_pointing(const GObservations&amp; obs)
1542 * @brief Get current resident set size (physical memory use) in Bytes 1495 * @brief Get current resident set size (physical memory use) in Bytes
1543 * 1496 *
1544 * @return Physical memory use in Bytes. 1497 * @return Physical memory use in Bytes.
  1498 + *
  1499 + * @todo This method is currently not used and can be removed if we do not
  1500 + * use it
1545 ***************************************************************************/ 1501 ***************************************************************************/
1546 size_t ctool::get_current_rss(void) 1502 size_t ctool::get_current_rss(void)
1547 { 1503 {
test/test_cscript.py 0 → 100755
  1 +#! /usr/bin/env python
  2 +# ==========================================================================
  3 +# This scripts performs unit tests for the cspull script.
  4 +#
  5 +# Copyright (C) 2016 Juergen Knoedlseder
  6 +#
  7 +# This program is free software: you can redistribute it and/or modify
  8 +# it under the terms of the GNU General Public License as published by
  9 +# the Free Software Foundation, either version 3 of the License, or
  10 +# (at your option) any later version.
  11 +#
  12 +# This program is distributed in the hope that it will be useful,
  13 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 +# GNU General Public License for more details.
  16 +#
  17 +# You should have received a copy of the GNU General Public License
  18 +# along with this program. If not, see <http://www.gnu.org/licenses/>.
  19 +#
  20 +# ==========================================================================
  21 +import gammalib
  22 +import ctools
  23 +from testing import test
  24 +
  25 +
  26 +# ================== #
  27 +# cscript_test class #
  28 +# ================== #
  29 +class cscript_test(ctools.cscript):
  30 + """
  31 + Test class for the cscript base class
  32 + """
  33 + # Constructor
  34 + def __init__(self, *argv):
  35 + """
  36 + Constructor
  37 + """
  38 + # Set name
  39 + self._name = 'cscript_test'
  40 + self._version = '1.2.0'
  41 +
  42 + # Initialise observation container from constructor arguments
  43 + self._obs, argv = self._set_input_obs(argv)
  44 +
  45 + # Initialise application by calling the appropriate class constructor
  46 + self._init_cscript(argv)
  47 +
  48 + # Return
  49 + return
  50 +
  51 + # Check is_valid_filename() method
  52 + def _check_is_valid_filename(self, filename):
  53 + return self._is_valid_filename(gammalib.GFilename(filename))
  54 +
  55 + # Check setup_observations() method
  56 + def _check_setup_observations(self, filename, list=True, cube=True):
  57 + self.pars()['inobs'].value(filename)
  58 + obs = gammalib.GObservations()
  59 + self._setup_observations(obs, True, list, cube)
  60 + return
  61 +
  62 + # Check setup_models() method
  63 + def _check_setup_models(self):
  64 + obs = gammalib.GObservations()
  65 + self._setup_models(obs)
  66 + return
  67 +
  68 + # Check create_ebounds() method
  69 + def _check_create_ebounds(self, filename):
  70 + self.pars()['ebinfile'].value(filename)
  71 + return self._create_ebounds()
  72 +
  73 + # Check require_inobs() method
  74 + def _check_require_inobs(self, filename):
  75 + self.pars()['inobs'].value(filename)
  76 + self._require_inobs('_check_require_inobs')
  77 + return
  78 +
  79 + # Check get_roi() method
  80 + def _check_get_roi(self):
  81 + return self._get_roi()
  82 +
  83 + # Check restore_edisp() method
  84 + def _check_restore_edisp(self):
  85 + obs = gammalib.GObservations()
  86 + edisp = [True, True]
  87 + self._restore_edisp(obs, edisp)
  88 + return
  89 +
  90 + # Check set_obs_bounds() method
  91 + def _check_set_obs_bounds(self):
  92 + obs = gammalib.GObservations()
  93 + list = gammalib.GCTAEventList()
  94 + cta = gammalib.GCTAObservation()
  95 + cta.events(list)
  96 + obs.append(cta)
  97 + self._set_obs_bounds(obs)
  98 + return obs.copy()
  99 +
  100 + # Check get_mean_pointing() method
  101 + def _check_get_mean_pointing(self):
  102 + obs = gammalib.GObservations()
  103 + return self._get_mean_pointing(obs)
  104 +
  105 +
  106 +# ======================== #
  107 +# ctobservation_test class #
  108 +# ======================== #
  109 +class ctobservation_test(ctools.csobservation):
  110 + """
  111 + Test class for the ctobservation base class
  112 + """
  113 + # Constructor
  114 + def __init__(self, *argv):
  115 + """
  116 + Constructor
  117 + """
  118 + # Set name
  119 + self._name = 'ctobservation_test'
  120 + self._version = '1.2.0'
  121 +
  122 + # Initialise application by calling the appropriate class constructor
  123 + self._init_csobservation(argv)
  124 +
  125 + # Return
  126 + return
  127 +
  128 +
  129 +# ======================= #
  130 +# ctlikelihood_test class #
  131 +# ======================= #
  132 +class ctlikelihood_test(ctools.cslikelihood):
  133 + """
  134 + Test class for the ctlikelihood base class
  135 + """
  136 + # Constructor
  137 + def __init__(self, *argv):
  138 + """
  139 + Constructor
  140 + """
  141 + # Set name
  142 + self._name = 'ctlikelihood_test'
  143 + self._version = '1.2.0'
  144 +
  145 + # Initialise application by calling the appropriate class constructor
  146 + self._init_cslikelihood(argv)
  147 +
  148 + # Return
  149 + return
  150 +
  151 + # Check evaluate() method
  152 + def _check_evaluate(self, value):
  153 + par = gammalib.GModelPar()
  154 + par.value(2.0)
  155 + par.range(1.0, 3.0)
  156 + return self._evaluate(par, value)
  157 +
  158 +
  159 +# ============================ #
  160 +# Test class for base classes #
  161 +# ============================ #
  162 +class Test(test):
  163 + """
  164 + Test class for base classes
  165 + """
  166 + # Constructor
  167 + def __init__(self):
  168 + """
  169 + Constructor
  170 + """
  171 + # Call base class constructor
  172 + test.__init__(self)
  173 +
  174 + # Create parameter file for cscript_test application
  175 + pars = gammalib.GApplicationPars()
  176 + pars.append(gammalib.GApplicationPar('inobs','f','h','NONE','','',''))
  177 + pars.append(gammalib.GApplicationPar('inmodel','f','h','NONE','','',''))
  178 + pars.append(gammalib.GApplicationPar('ebinalg','s','h','FILE','','',''))
  179 + pars.append(gammalib.GApplicationPar('ebinfile','f','h','NONE','','',''))
  180 + pars.append(gammalib.GApplicationPar('ra','r','h','NONE','','',''))
  181 + pars.append(gammalib.GApplicationPar('dec','r','h','NONE','','',''))
  182 + pars.append(gammalib.GApplicationPar('rad','r','h','1.0','','',''))
  183 + pars.append(gammalib.GApplicationPar('emin','r','h','1.0','','',''))
  184 + pars.append(gammalib.GApplicationPar('emax','r','h','10.0','','',''))
  185 + pars.append_standard()
  186 + pars.save('cscript_test.par')
  187 +
  188 + # Create parameter file for ctobservation_test.par application
  189 + pars = gammalib.GApplicationPars()
  190 + pars.append_standard()
  191 + pars.save('ctobservation_test.par')
  192 +
  193 + # Create parameter file for ctlikelihood_test application
  194 + pars = gammalib.GApplicationPars()
  195 + pars.append_standard()
  196 + pars.save('ctlikelihood_test.par')
  197 +
  198 + # Create energy boundaries file
  199 + ebounds = gammalib.GEbounds(1, gammalib.GEnergy(1.0,'TeV'),
  200 + gammalib.GEnergy(10.0,'TeV'))
  201 + ebounds.save('test_ebinfile_ebounds.fits[EBOUNDS]', True)
  202 + ebounds.save('test_ebinfile_energybins.fits[ENERGYBINS]', True)
  203 + ebounds.save('test_ebinfile_energies.fits[ENERGIES]', True)
  204 +
  205 + # Return
  206 + return
  207 +
  208 + # Set test functions
  209 + def set(self):
  210 + """
  211 + Set all test functions
  212 + """
  213 + # Set test name
  214 + self.name('cscript')
  215 +
  216 + # Append tests
  217 + self.append(self._test_cscript, 'Test cscript base class')
  218 + self.append(self._test_ctobservation, 'Test ctobservation base class')
  219 + self.append(self._test_ctlikelihood, 'Test ctlikelihood base class')
  220 +
  221 + # Return
  222 + return
  223 +
  224 + # Test cscript base class
  225 + def _test_cscript(self):
  226 + """
  227 + Test cscript base class
  228 + """
  229 + # Allocate empty
  230 + empty = cscript_test()
  231 +
  232 + # Test is_valid_filename() method
  233 + self.test_assert(empty._check_is_valid_filename(self._model),
  234 + 'Check model definiton XML file')
  235 + self.test_assert(not empty._check_is_valid_filename(''),
  236 + 'Check empty filename')
  237 + self.test_assert(not empty._check_is_valid_filename('NONE'),
  238 + 'Check "NONE" filename')
  239 +
  240 + # Test setup_observations() for invalid file name
  241 + self.test_try('Check setup_observations() for "NONE"')
  242 + try:
  243 + empty._check_setup_observations('NONE')
  244 + self.test_try_failure('Exception not thrown')
  245 + except ValueError:
  246 + self.test_try_success()
  247 +
  248 + # Test setup_observations() for unacceptable event list
  249 + self.test_try('Check setup_observations() for unacceptable event list')
  250 + try:
  251 + empty._check_setup_observations(self._events, list=False)
  252 + self.test_try_failure('Exception not thrown')
  253 + except ValueError:
  254 + self.test_try_success()
  255 +
  256 + # Test setup_observations() for unacceptable counts cube
  257 + self.test_try('Check setup_observations() for unacceptable counts cube')
  258 + try:
  259 + empty._check_setup_observations(self._cntcube, cube=False)
  260 + self.test_try_failure('Exception not thrown')
  261 + except ValueError:
  262 + self.test_try_success()
  263 +
  264 + # Test setup_models() for invalid model definition file name
  265 + self.test_try('Check setup_models() for invalid model definition file name')
  266 + try:
  267 + empty._check_setup_models()
  268 + self.test_try_failure('Exception not thrown')
  269 + except ValueError:
  270 + self.test_try_success()
  271 +
  272 + # Test create_ebounds() method for "EBOUNDS" extension
  273 + ebounds = empty._check_create_ebounds('test_ebinfile_ebounds.fits')
  274 + self.test_value(ebounds.size(), 1, 'Check number of energy boundaries')
  275 + self.test_value(ebounds.emin().TeV(), 1.0, 'Check minimum energy')
  276 + self.test_value(ebounds.emax().TeV(), 10.0, 'Check maximum energy')
  277 +
  278 + # Test create_ebounds() method for "ENERGYBINS" extension
  279 + ebounds = empty._check_create_ebounds('test_ebinfile_energybins.fits')
  280 + self.test_value(ebounds.size(), 1, 'Check number of energy boundaries')
  281 + self.test_value(ebounds.emin().TeV(), 1.0, 'Check minimum energy')
  282 + self.test_value(ebounds.emax().TeV(), 10.0, 'Check maximum energy')
  283 +
  284 + # Test create_ebounds() method for invalid extension
  285 + self.test_try('Check create_ebounds() method for invalid extension')
  286 + try:
  287 + empty._check_create_ebounds('test_ebinfile_energies.fits')
  288 + self.test_try_failure('Exception not thrown')
  289 + except ValueError:
  290 + self.test_try_success()
  291 +
  292 + # Test require_inobs() method for invalid file name
  293 + self.test_try('Check require_inobs() method for invalid file name')
  294 + try:
  295 + empty._check_require_inobs('NONE')
  296 + self.test_try_failure('Exception not thrown')
  297 + except ValueError:
  298 + self.test_try_success()
  299 +
  300 + # Test get_roi() method
  301 + roi = empty._check_get_roi()
  302 + self.test_assert(not roi.is_valid(), 'Check get_roi() method')
  303 +
  304 + # Test restore_edisp() method for invalid vector size
  305 + #self.test_try('Check restore_edisp() method for invalid vector size')
  306 + #try:
  307 + # empty._check_restore_edisp()
  308 + # self.test_try_failure('Exception not thrown')
  309 + #except ValueError:
  310 + # self.test_try_success()
  311 + #
  312 + # NOTE: This code does not work because of a missing list to
  313 + # integer vector conversion.
  314 +
  315 + # Test set_obs_bounds() method
  316 + obs = empty._check_set_obs_bounds()
  317 + self.test_value(obs.size(), 1, 'Check number of observations')
  318 + self.test_value(obs[0].events().ebounds().size(), 1,
  319 + 'Check number of energy boundaries')
  320 + self.test_value(obs[0].events().ebounds().emin().TeV(), 1.0,
  321 + 'Check minimum energy')
  322 + self.test_value(obs[0].events().ebounds().emax().TeV(), 10.0,
  323 + 'Check maximum energy')
  324 + self.test_value(obs[0].events().roi().radius(), 1.0,
  325 + 'Check RoI radius')
  326 +
  327 + # Test get_mean_pointing() method for empty observation container
  328 + self.test_try('Check get_mean_pointing() method for empty observation '
  329 + 'container')
  330 + try:
  331 + empty._check_get_mean_pointing()
  332 + self.test_try_failure('Exception not thrown')
  333 + except ValueError:
  334 + self.test_try_success()
  335 +
  336 + # Return
  337 + return
  338 +
  339 + # Test ctobservation base class
  340 + def _test_ctobservation(self):
  341 + """
  342 + Test ctobservation base class
  343 + """
  344 + # Allocate empty
  345 + empty = ctobservation_test()
  346 +
  347 + # Test first_unbinned_observation() method
  348 + self.test_assert(empty._first_unbinned_observation() is None,
  349 + 'Check first_unbinned_observation() method')
  350 +
  351 + # Test next_unbinned_observation() method
  352 + self.test_assert(empty._next_unbinned_observation() is None,
  353 + 'Check next_unbinned_observation() method')
  354 +
  355 + # Return
  356 + return
  357 +
  358 + # Test ctlikelihood base class
  359 + def _test_ctlikelihood(self):
  360 + """
  361 + Test ctlikelihood base class
  362 + """
  363 + # Allocate empty
  364 + empty = ctlikelihood_test()
  365 +
  366 + # Test evaluate() method for minimum value violation
  367 + self.test_try('Check evaluate() for minimum value violation')
  368 + try:
  369 + empty._check_evaluate(0.0)
  370 + self.test_try_failure('Exception not thrown')
  371 + except ValueError:
  372 + self.test_try_success()
  373 +
  374 + # Test evaluate() method for maximum value violation
  375 + self.test_try('Check evaluate() for maximum value violation')
  376 + try:
  377 + empty._check_evaluate(4.0)
  378 + self.test_try_failure('Exception not thrown')
  379 + except ValueError:
  380 + self.test_try_success()
  381 +
  382 + # Return
  383 + return
test/test_ctskymap.py
@@ -181,10 +181,10 @@ class Test(test): @@ -181,10 +181,10 @@ class Test(test):
181 skymap['nxpix'] = 200 181 skymap['nxpix'] = 200
182 skymap['nypix'] = 200 182 skymap['nypix'] = 200
183 skymap['binsz'] = 0.02 183 skymap['binsz'] = 0.02
184 - skymap['coordsys'] = 'CEL' 184 + skymap['coordsys'] = 'GAL'
185 skymap['proj'] = 'CAR' 185 skymap['proj'] = 'CAR'
186 - skymap['xref'] = 83.63  
187 - skymap['yref'] = 22.01 186 + skymap['xref'] = 184.5575
  187 + skymap['yref'] = -5.7844
188 skymap['outmap'] = 'ctskymap_py3.fits' 188 skymap['outmap'] = 'ctskymap_py3.fits'
189 skymap['logfile'] = 'ctskymap_py3.log' 189 skymap['logfile'] = 'ctskymap_py3.log'
190 skymap['chatter'] = 4 190 skymap['chatter'] = 4
test/test_ctulimit.py
@@ -111,6 +111,7 @@ class Test(test): @@ -111,6 +111,7 @@ class Test(test):
111 'Check upper limit on energy flux') 111 'Check upper limit on energy flux')
112 112
113 # Check that saving does not nothing 113 # Check that saving does not nothing
  114 + ulimit['logfile'] = 'ctulimit_py0.log'
114 ulimit.logFileOpen() 115 ulimit.logFileOpen()
115 ulimit.save() 116 ulimit.save()
116 117
@@ -157,13 +158,6 @@ class Test(test): @@ -157,13 +158,6 @@ class Test(test):
157 self.test_value(cpy_ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16, 158 self.test_value(cpy_ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16,
158 'Check upper limit on energy flux') 159 'Check upper limit on energy flux')
159 160
160 - # Execute copy of ctulimit tool again, now with a higher chatter  
161 - # level than before  
162 - cpy_ulimit['logfile'] = 'ctulimit_py2.log'  
163 - cpy_ulimit['chatter'] = 3  
164 - cpy_ulimit.logFileOpen() # Needed to get a new log file  
165 - cpy_ulimit.execute()  
166 -  
167 # Check results 161 # Check results
168 self.test_value(cpy_ulimit.diff_ulimit(), 8.86803e-18, 1.0e-21, 162 self.test_value(cpy_ulimit.diff_ulimit(), 8.86803e-18, 1.0e-21,
169 'Check differential upper limit') 163 'Check differential upper limit')
@@ -172,9 +166,6 @@ class Test(test): @@ -172,9 +166,6 @@ class Test(test):
172 self.test_value(cpy_ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16, 166 self.test_value(cpy_ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16,
173 'Check upper limit on energy flux') 167 'Check upper limit on energy flux')
174 168
175 - # Save copy of observation container for later  
176 - obs = cpy_ulimit.obs().copy()  
177 -  
178 # Now clear copy of ctulimit tool 169 # Now clear copy of ctulimit tool
179 cpy_ulimit.clear() 170 cpy_ulimit.clear()
180 171
@@ -186,13 +177,21 @@ class Test(test): @@ -186,13 +177,21 @@ class Test(test):
186 self.test_value(cpy_ulimit.eflux_ulimit(), 0.0, 1.0e-16, 177 self.test_value(cpy_ulimit.eflux_ulimit(), 0.0, 1.0e-16,
187 'Check upper limit on energy flux') 178 'Check upper limit on energy flux')
188 179
189 - # Now set ctulimit tool using the observation container from last  
190 - # time. This should avoid the necessity to recompute the maximum  
191 - # likelihood  
192 - ulimit = ctools.ctulimit(obs) 180 + # Run ctlike to get an initial log-likelihood solution
  181 + like = ctools.ctlike()
  182 + like['inobs'] = self._events
  183 + like['inmodel'] = self._model
  184 + like['caldb'] = self._caldb
  185 + like['irf'] = self._irf
  186 + like.run()
  187 +
  188 + # Now set ctulimit tool using the observation container from the
  189 + # previous run. This should avoid the necessity to recompute the
  190 + # maximum likelihood
  191 + ulimit = ctools.ctulimit(like.obs())
193 ulimit['srcname'] = 'Crab' 192 ulimit['srcname'] = 'Crab'
194 - ulimit['logfile'] = 'ctulimit_py3.log'  
195 - ulimit['chatter'] = 4 193 + ulimit['logfile'] = 'ctulimit_py2.log'
  194 + ulimit['chatter'] = 3
196 195
197 # Execute ctulimit tool 196 # Execute ctulimit tool
198 ulimit.logFileOpen() # Needed to get a new log file 197 ulimit.logFileOpen() # Needed to get a new log file
@@ -207,11 +206,11 @@ class Test(test): @@ -207,11 +206,11 @@ class Test(test):
207 'Check upper limit on energy flux') 206 'Check upper limit on energy flux')
208 207
209 # Test invalid model name 208 # Test invalid model name
  209 + ulimit['srcname'] = 'Weihnachtsstern'
  210 + ulimit['logfile'] = 'ctulimit_py3.log'
  211 + ulimit.logFileOpen()
210 self.test_try('Test invalid model name') 212 self.test_try('Test invalid model name')
211 try: 213 try:
212 - ulimit['srcname'] = 'Weihnachtsstern'  
213 - ulimit['logfile'] = 'ctulimit_py4.log'  
214 - ulimit.logFileOpen()  
215 ulimit.execute() 214 ulimit.execute()
216 self.test_try_failure('Exception not thrown') 215 self.test_try_failure('Exception not thrown')
217 except ValueError: 216 except ValueError:
@@ -219,7 +218,7 @@ class Test(test): @@ -219,7 +218,7 @@ class Test(test):
219 218
220 # Test specification of background model 219 # Test specification of background model
221 ulimit['srcname'] = 'Background' 220 ulimit['srcname'] = 'Background'
222 - ulimit['logfile'] = 'ctulimit_py5.log' 221 + ulimit['logfile'] = 'ctulimit_py4.log'
223 ulimit.logFileOpen() 222 ulimit.logFileOpen()
224 self.test_try('Test invalid model name') 223 self.test_try('Test invalid model name')
225 try: 224 try:
@@ -228,6 +227,18 @@ class Test(test): @@ -228,6 +227,18 @@ class Test(test):
228 except ValueError: 227 except ValueError:
229 self.test_try_success() 228 self.test_try_success()
230 229
  230 + # Test run with too few iterations
  231 + ulimit['srcname'] = 'Crab'
  232 + ulimit['max_iter'] = 1
  233 + ulimit['logfile'] = 'ctulimit_py5.log'
  234 + ulimit.logFileOpen()
  235 + self.test_try('Test ctulimit with too few iterations')
  236 + try:
  237 + ulimit.execute()
  238 + self.test_try_failure('Exception not thrown')
  239 + except ValueError:
  240 + self.test_try_success()
  241 +
231 # Return 242 # Return
232 return 243 return
233 244
test/test_python_cscripts.py
@@ -23,6 +23,7 @@ import sys @@ -23,6 +23,7 @@ import sys
23 import gammalib 23 import gammalib
24 import cscripts 24 import cscripts
25 sys.path.append(os.path.dirname(os.path.abspath(__file__))) 25 sys.path.append(os.path.dirname(os.path.abspath(__file__)))
  26 +import test_cscript
26 import test_cscaldb 27 import test_cscaldb
27 import test_csfindobs 28 import test_csfindobs
28 import test_csinfo 29 import test_csinfo
@@ -105,65 +106,25 @@ def test(installed=False, debug=False): @@ -105,65 +106,25 @@ def test(installed=False, debug=False):
105 os.system('cp -r %s/syspfiles/*.par pfiles/' % (os.environ['CTOOLS'])) 106 os.system('cp -r %s/syspfiles/*.par pfiles/' % (os.environ['CTOOLS']))
106 os.system('chmod u+w pfiles/*') 107 os.system('chmod u+w pfiles/*')
107 108
108 - # Allocate test suite container  
109 - suites = gammalib.GTestSuites('cscripts unit testing')  
110 -  
111 - # Allocate test suites  
112 - suite_cscaldb = test_cscaldb.Test()  
113 - suite_csinfo = test_csinfo.Test()  
114 - suite_cslightcrv = test_cslightcrv.Test()  
115 - suite_csmodelinfo = test_csmodelinfo.Test()  
116 - suite_csmodelmerge = test_csmodelmerge.Test()  
117 - suite_csobs2caldb = test_csobs2caldb.Test()  
118 - suite_csobsdef = test_csobsdef.Test()  
119 - suite_csobsinfo = test_csobsinfo.Test()  
120 - suite_cspull = test_cspull.Test()  
121 - suite_csresmap = test_csresmap.Test()  
122 - suite_csroot2caldb = test_csroot2caldb.Test()  
123 - suite_cssens = test_cssens.Test()  
124 - suite_csspec = test_csspec.Test()  
125 - suite_cstsdist = test_cstsdist.Test()  
126 - suite_cstsmapmerge = test_cstsmapmerge.Test()  
127 - suite_cstsmapsplit = test_cstsmapsplit.Test()  
128 - suite_csworkflow = test_csworkflow.Test()  
129 -  
130 - # Setup unit tests  
131 - suite_cscaldb.set()  
132 - suite_csinfo.set()  
133 - suite_cslightcrv.set()  
134 - suite_csmodelinfo.set()  
135 - suite_csmodelmerge.set()  
136 - suite_csobs2caldb.set()  
137 - suite_csobsdef.set()  
138 - suite_csobsinfo.set()  
139 - suite_cspull.set()  
140 - suite_csresmap.set()  
141 - suite_csroot2caldb.set()  
142 - suite_cssens.set()  
143 - suite_csspec.set()  
144 - suite_cstsdist.set()  
145 - suite_cstsmapmerge.set()  
146 - suite_cstsmapsplit.set()  
147 - suite_csworkflow.set()  
148 -  
149 - # Append tests to container  
150 - suites.append(suite_cscaldb)  
151 - suites.append(suite_csinfo)  
152 - suites.append(suite_cslightcrv)  
153 - suites.append(suite_csmodelinfo)  
154 - suites.append(suite_csmodelmerge)  
155 - suites.append(suite_csobs2caldb)  
156 - suites.append(suite_csobsdef)  
157 - suites.append(suite_csobsinfo)  
158 - suites.append(suite_cspull)  
159 - suites.append(suite_csresmap)  
160 - suites.append(suite_csroot2caldb)  
161 - suites.append(suite_cssens)  
162 - suites.append(suite_csspec)  
163 - suites.append(suite_cstsdist)  
164 - suites.append(suite_cstsmapmerge)  
165 - suites.append(suite_cstsmapsplit)  
166 - suites.append(suite_csworkflow) 109 + # Define list of test suites
  110 + tests = [test_cscript.Test(),
  111 + test_cscaldb.Test(),
  112 + test_csinfo.Test(),
  113 + test_cslightcrv.Test(),
  114 + test_csmodelinfo.Test(),
  115 + test_csmodelmerge.Test(),
  116 + test_csobs2caldb.Test(),
  117 + test_csobsdef.Test(),
  118 + test_csobsinfo.Test(),
  119 + test_cspull.Test(),
  120 + test_csresmap.Test(),
  121 + test_csroot2caldb.Test(),
  122 + test_cssens.Test(),
  123 + test_csspec.Test(),
  124 + test_cstsdist.Test(),
  125 + test_cstsmapmerge.Test(),
  126 + test_cstsmapsplit.Test(),
  127 + test_csworkflow.Test()]
167 128
168 # Append tests for Python 2.6+ (the IACT cscripts depend on the json 129 # Append tests for Python 2.6+ (the IACT cscripts depend on the json
169 # module which is only available since Python 2.6+) 130 # module which is only available since Python 2.6+)
@@ -178,23 +139,19 @@ def test(installed=False, debug=False): @@ -178,23 +139,19 @@ def test(installed=False, debug=False):
178 # impact the environment variable in the parent shell. 139 # impact the environment variable in the parent shell.
179 del os.environ['VHEFITS'] 140 del os.environ['VHEFITS']
180 141
181 - # Allocate test suites  
182 - suite_csfindobs = test_csfindobs.Test()  
183 - suite_csiactcopy = test_csiactcopy.Test()  
184 - suite_csiactdata = test_csiactdata.Test()  
185 - suite_csiactobs = test_csiactobs.Test()  
186 -  
187 - # Setup unit tests  
188 - suite_csfindobs.set()  
189 - suite_csiactcopy.set()  
190 - suite_csiactdata.set()  
191 - suite_csiactobs.set()  
192 -  
193 - # Append tests to container  
194 - suites.append(suite_csfindobs)  
195 - suites.append(suite_csiactcopy)  
196 - suites.append(suite_csiactdata)  
197 - suites.append(suite_csiactobs) 142 + # Append IACT script tests to list of test suites
  143 + tests.extend([test_csfindobs.Test(),
  144 + test_csiactcopy.Test(),
  145 + test_csiactdata.Test(),
  146 + test_csiactobs.Test()])
  147 +
  148 + # Allocate test suite container
  149 + suites = gammalib.GTestSuites('cscripts unit testing')
  150 +
  151 + # Set test suites and append them to suite container
  152 + for suite in tests:
  153 + suite.set()
  154 + suites.append(suite)
198 155
199 # Run test suite 156 # Run test suite
200 success = suites.run() 157 success = suites.run()
test/test_python_ctools.py
@@ -99,65 +99,32 @@ def test(installed=False): @@ -99,65 +99,32 @@ def test(installed=False):
99 os.system('cp -r %s/syspfiles/*.par pfiles/' % (os.environ['CTOOLS'])) 99 os.system('cp -r %s/syspfiles/*.par pfiles/' % (os.environ['CTOOLS']))
100 os.system('chmod u+w pfiles/*') 100 os.system('chmod u+w pfiles/*')
101 101
  102 + # Define list of test suites
  103 + tests = [test_ctobssim.Test(),
  104 + test_ctselect.Test(),
  105 + test_ctbin.Test(),
  106 + test_ctlike.Test(),
  107 + test_cttsmap.Test(),
  108 + test_ctmodel.Test(),
  109 + test_ctskymap.Test(),
  110 + test_ctexpcube.Test(),
  111 + test_ctpsfcube.Test(),
  112 + test_ctedispcube.Test(),
  113 + test_ctbkgcube.Test(),
  114 + test_ctmapcube.Test(),
  115 + test_ctcubemask.Test(),
  116 + test_ctbutterfly.Test(),
  117 + test_ctulimit.Test(),
  118 + test_cterror.Test(),
  119 + test_pipelines.Test()]
  120 +
102 # Allocate test suite container 121 # Allocate test suite container
103 suites = gammalib.GTestSuites('ctools unit testing') 122 suites = gammalib.GTestSuites('ctools unit testing')
104 123
105 - # Allocate test suites and append them to the container  
106 - suite_ctobssim = test_ctobssim.Test()  
107 - suite_ctselect = test_ctselect.Test()  
108 - suite_ctbin = test_ctbin.Test()  
109 - suite_ctlike = test_ctlike.Test()  
110 - suite_cttsmap = test_cttsmap.Test()  
111 - suite_ctmodel = test_ctmodel.Test()  
112 - suite_ctskymap = test_ctskymap.Test()  
113 - suite_ctexpcube = test_ctexpcube.Test()  
114 - suite_ctpsfcube = test_ctpsfcube.Test()  
115 - suite_ctedispcube = test_ctedispcube.Test()  
116 - suite_ctbkgcube = test_ctbkgcube.Test()  
117 - suite_ctmapcube = test_ctmapcube.Test()  
118 - suite_ctcubemask = test_ctcubemask.Test()  
119 - suite_ctbutterfly = test_ctbutterfly.Test()  
120 - suite_ctulimit = test_ctulimit.Test()  
121 - suite_cterror = test_cterror.Test()  
122 - suite_pipelines = test_pipelines.Test()  
123 -  
124 - # Setup unit tests  
125 - suite_ctobssim.set()  
126 - suite_ctselect.set()  
127 - suite_ctbin.set()  
128 - suite_ctlike.set()  
129 - suite_cttsmap.set()  
130 - suite_ctmodel.set()  
131 - suite_ctskymap.set()  
132 - suite_ctexpcube.set()  
133 - suite_ctpsfcube.set()  
134 - suite_ctedispcube.set()  
135 - suite_ctbkgcube.set()  
136 - suite_ctmapcube.set()  
137 - suite_ctcubemask.set()  
138 - suite_ctbutterfly.set()  
139 - suite_ctulimit.set()  
140 - suite_cterror.set()  
141 - suite_pipelines.set()  
142 -  
143 - # Append tests to container  
144 - suites.append(suite_ctobssim)  
145 - suites.append(suite_ctselect)  
146 - suites.append(suite_ctbin)  
147 - suites.append(suite_ctlike)  
148 - suites.append(suite_cttsmap)  
149 - suites.append(suite_ctmodel)  
150 - suites.append(suite_ctskymap)  
151 - suites.append(suite_ctexpcube)  
152 - suites.append(suite_ctpsfcube)  
153 - suites.append(suite_ctedispcube)  
154 - suites.append(suite_ctbkgcube)  
155 - suites.append(suite_ctmapcube)  
156 - suites.append(suite_ctcubemask)  
157 - suites.append(suite_ctbutterfly)  
158 - suites.append(suite_ctulimit)  
159 - suites.append(suite_cterror)  
160 - suites.append(suite_pipelines) 124 + # Set test suites and append them to suite container
  125 + for suite in tests:
  126 + suite.set()
  127 + suites.append(suite)
161 128
162 # Run test suite 129 # Run test suite
163 success = suites.run() 130 success = suites.run()