1""" 2Name: r_watershed_test 3Purpose: This script is to demonstrate a unit test for r.watershed 4 module (originally developed for GIS582 course at NCSU). 5 6Author: Stephanie Wendel 7Copyright: (C) 205 by Stephanie Wendel and the GRASS Development Team 8Licence: This program is free software under the GNU General Public 9 License (>=v2). Read the file COPYING that comes with GRASS 10 for details. 11""" 12 13from grass.gunittest.case import TestCase 14from grass.gunittest.main import test 15 16 17class TestWatershed(TestCase): 18 """Test case for watershed module""" 19 20 # Setup variables to be used for outputs 21 accumulation = 'test_accumulation' 22 drainage = 'test_drainage' 23 basin = 'test_basin' 24 stream = 'test_stream' 25 halfbasin = 'test_halfbasin' 26 slopelength = 'test_slopelength' 27 slopesteepness = 'test_slopesteepness' 28 elevation = 'elevation' 29 lengthslope_2 = 'test_lengthslope_2' 30 stream_2 = 'test_stream_2' 31 32 @classmethod 33 def setUpClass(cls): 34 """Ensures expected computational region and setup""" 35 # Always use the computational region of the raster elevation 36 cls.use_temp_region() 37 cls.runModule('g.region', raster=cls.elevation) 38 39 @classmethod 40 def tearDownClass(cls): 41 """Remove the temporary region""" 42 cls.del_temp_region() 43 44 def tearDown(self): 45 """Remove the outputs created from the watershed module 46 47 This is executed after each test run. 48 """ 49 self.runModule('g.remove', flags='f', type='raster', 50 name=[self.accumulation, self.drainage, 51 self.basin, self.stream, 52 self.halfbasin, self.slopelength, 53 self.slopesteepness, self.lengthslope_2, 54 self.stream_2]) 55 56 def test_OutputCreated(self): 57 """Test to see if the outputs are created""" 58 # run the watershed module 59 self.assertModule('r.watershed', elevation=self.elevation, 60 threshold='10000', accumulation=self.accumulation, 61 drainage=self.drainage, basin=self.basin, stream=self.stream, 62 half_basin=self.halfbasin, length_slope=self.slopelength, 63 slope_steepness=self.slopesteepness) 64 # check to see if accumulation output is in mapset 65 self.assertRasterExists(self.accumulation, 66 msg='accumulation output was not created') 67 # check to see if drainage output is in mapset 68 self.assertRasterExists(self.drainage, 69 msg='drainage output was not created') 70 # check to see if basin output is in mapset 71 self.assertRasterExists(self.basin, 72 msg='basin output was not created') 73 # check to see if stream output is in mapset 74 self.assertRasterExists(self.stream, 75 msg='stream output was not created') 76 # check to see if half.basin output is in mapset 77 self.assertRasterExists(self.halfbasin, 78 msg='half.basin output was not created') 79 # check to see if length.slope output is in mapset 80 self.assertRasterExists(self.slopelength, 81 msg='length.slope output was not created') 82 # check to see if slope.steepness output is in mapset 83 self.assertRasterExists(self.slopesteepness, 84 msg='slope.steepness output was not created') 85 86 def test_fourFlag(self): 87 """Test the -4 flag and the stream and slope lengths 88 89 Tests the -4 flag to see if the stream and slope lengths are 90 approximately the same as the outputs from the default 91 module run. 92 """ 93 # Run module with default settings 94 self.assertModule('r.watershed', elevation=self.elevation, 95 threshold='10000', stream=self.stream, 96 length_slope=self.slopelength, overwrite=True) 97 # Run module with flag 4 98 self.assertModule('r.watershed', flags='4', elevation='elevation', 99 threshold='10000', stream=self.stream_2, 100 length_slope=self.lengthslope_2) 101 # Use the assertRastersNoDifference with precsion 100 to see if close 102 # Compare stream output 103 self.assertRastersNoDifference(self.stream_2, self.stream, 100) 104 # Compare length_slope output 105 self.assertRastersNoDifference(self.lengthslope_2, 106 self.slopelength, 10) 107 108 def test_watershedThreadholdfail(self): 109 """Test if threshold of 0 or a negative is accepted 110 111 The module should fail in this test, if it fails, test succeeds. 112 """ 113 self.assertModuleFail('r.watershed', elevation=self.elevation, 114 threshold='0', stream=self.stream, overwrite=True, 115 msg='Threshold value of 0 considered valid.') 116 self.assertModuleFail('r.watershed', elevation=self.elevation, 117 threshold='-1', stream=self.stream, overwrite=True, 118 msg='Threshold value of 0 considered valid.') 119 120 def test_thresholdsize(self): 121 """Test the expected range of basin output values""" 122 self.assertModule('r.watershed', elevation=self.elevation, 123 threshold='100000', basin=self.basin, overwrite=True) 124 # it is expected that 100k Threshold has a min=2 and max=12 for this 125 # data 126 self.assertRasterMinMax(self.basin, 2, 12) 127 # it is expected that 100k Threshold has a min=2 and max=256 for this 128 # data 129 self.assertModule('r.watershed', elevation=self.elevation, 130 threshold='10000', basin=self.basin, overwrite=True) 131 self.assertRasterMinMax(self.basin, 2, 256) 132 133 def test_drainageDirection(self): 134 """Test if the drainage direction is between -8 and 8.""" 135 self.assertModule('r.watershed', elevation=self.elevation, 136 threshold='100000', drainage=self.drainage) 137 # Make sure the min/max is between -8 and 8 138 self.assertRasterMinMax(self.drainage, -8, 8, 139 msg='Direction must be between -8 and 8') 140 141 def test_basinValue(self): 142 """Check to see if the basin value is 0 or greater""" 143 self.assertModule('r.watershed', elevation=self.elevation, 144 threshold='10000', basin=self.basin) 145 # Make sure the minimum value is 0 for basin value representing unique 146 # positive integer. 147 # TODO: test just min, max is theoretically unlimited 148 # or set a lower value according to what is expected with this data 149 # TODO: add test which tests that 'max basin id' == 'num of basins' 150 self.assertRasterMinMax(self.basin, 0, 1000000, 151 msg='A basin value is less than 0 or greater than 1000000') 152 153if __name__ == '__main__': 154 test() 155