Coverage for tests/test_CompoundRegion.py: 34%

86 statements  

« prev     ^ index     » next       coverage.py v6.4, created at 2022-06-02 03:22 -0700

1# 

2# LSST Data Management System 

3# See COPYRIGHT file at the top of the source tree. 

4# 

5# This product includes software developed by the 

6# LSST Project (http://www.lsst.org/). 

7# 

8# This program is free software: you can redistribute it and/or modify 

9# it under the terms of the GNU General Public License as published by 

10# the Free Software Foundation, either version 3 of the License, or 

11# (at your option) any later version. 

12# 

13# This program is distributed in the hope that it will be useful, 

14# but WITHOUT ANY WARRANTY; without even the implied warranty of 

15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

16# GNU General Public License for more details. 

17# 

18# You should have received a copy of the LSST License Statement and 

19# the GNU General Public License along with this program. If not, 

20# see <https://www.lsstcorp.org/LegalNotices/>. 

21# 

22 

23import pickle 

24import unittest 

25 

26try: 

27 import yaml 

28except ImportError: 

29 yaml = None 

30 

31from lsst.sphgeom import ( 

32 CONTAINS, 

33 DISJOINT, 

34 INTERSECTS, 

35 WITHIN, 

36 Angle, 

37 AngleInterval, 

38 Box, 

39 Circle, 

40 CompoundRegion, 

41 IntersectionRegion, 

42 LonLat, 

43 NormalizedAngleInterval, 

44 Region, 

45 UnionRegion, 

46 UnitVector3d, 

47) 

48 

49 

50class CompoundRegionTestMixin: 

51 """Tests for both UnionRegion and IntersectionRegion. 

52 

53 Concrete TestCase subclasses are responsible for adding an `instance` 

54 attribute with a non-trivial instance of the `CompoundRegion` subclass 

55 being tested. 

56 """ 

57 

58 def setUp(self): 

59 self.point_in_circle = LonLat.fromDegrees(44.0, 45.0) 

60 self.point_in_box = LonLat.fromDegrees(46.0, 45.0) 

61 self.point_in_both = LonLat.fromDegrees(45.0, 45.0) 

62 self.point_in_neither = LonLat.fromDegrees(45.0, 48.0) 

63 self.circle = Circle(UnitVector3d(self.point_in_circle), Angle.fromDegrees(1.0)) 

64 self.box = Box.fromDegrees( 

65 self.point_in_box.getLon().asDegrees() - 1.5, 

66 self.point_in_box.getLat().asDegrees() - 1.5, 

67 self.point_in_box.getLon().asDegrees() + 1.5, 

68 self.point_in_box.getLat().asDegrees() + 1.5, 

69 ) 

70 self.faraway = Circle( 

71 UnitVector3d(self.point_in_neither), Angle.fromDegrees(0.1) 

72 ) 

73 self.operands = (self.circle, self.box) 

74 

75 def assertOperandsEqual(self, region, operands): 

76 """Assert that a compound regions operands are equal to the given 

77 tuple of operands. 

78 """ 

79 self.assertCountEqual((region.cloneOperand(0), region.cloneOperand(1)), operands) 

80 

81 def assertCompoundRegionsEqual(self, a, b): 

82 """Assert that two compound regions are equal. 

83 

84 CompoundRegion does not implement equality comparison because 

85 regions in general do not, and hence it cannot delegate that operation 

86 to its operands. But the concrete operands (circle and box) we use in 

87 these tests do implement equality comparison. 

88 """ 

89 self.assertEqual(type(a), type(b)) 

90 self.assertOperandsEqual(a, (b.cloneOperand(0), b.cloneOperand(1))) 

91 

92 def testSetUp(self): 

93 """Test that the points and operand regions being tested have the 

94 relationships expected. 

95 """ 

96 self.assertTrue(self.circle.contains(UnitVector3d(self.point_in_circle))) 

97 self.assertTrue(self.circle.contains(UnitVector3d(self.point_in_both))) 

98 self.assertFalse(self.circle.contains(UnitVector3d(self.point_in_box))) 

99 self.assertFalse(self.circle.contains(UnitVector3d(self.point_in_neither))) 

100 self.assertTrue(self.box.contains(UnitVector3d(self.point_in_box))) 

101 self.assertTrue(self.box.contains(UnitVector3d(self.point_in_both))) 

102 self.assertFalse(self.box.contains(UnitVector3d(self.point_in_circle))) 

103 self.assertFalse(self.box.contains(UnitVector3d(self.point_in_neither))) 

104 self.assertEqual(self.circle.relate(self.circle), CONTAINS | WITHIN) 

105 self.assertEqual(self.circle.relate(self.box), INTERSECTS) 

106 self.assertEqual(self.circle.relate(self.faraway), DISJOINT) 

107 self.assertEqual(self.box.relate(self.circle), INTERSECTS) 

108 self.assertEqual(self.box.relate(self.box), CONTAINS | WITHIN) 

109 self.assertEqual(self.box.relate(self.faraway), DISJOINT) 

110 

111 def testOperands(self): 

112 """Test the cloneOperands accessor.""" 

113 self.assertOperandsEqual(self.instance, self.operands) 

114 

115 def testCodec(self): 

116 """Test that encode and decode round-trip.""" 

117 s = self.instance.encode() 

118 self.assertCompoundRegionsEqual(type(self.instance).decode(s), self.instance) 

119 self.assertCompoundRegionsEqual(CompoundRegion.decode(s), self.instance) 

120 self.assertCompoundRegionsEqual(Region.decode(s), self.instance) 

121 

122 def testPickle(self): 

123 """Test pickling round-trips.""" 

124 s = pickle.dumps(self.instance, pickle.HIGHEST_PROTOCOL) 

125 self.assertCompoundRegionsEqual(pickle.loads(s), self.instance) 

126 

127 def testString(self): 

128 """Test that repr returns a string that can be eval'd to yield an 

129 equivalent instance. 

130 """ 

131 self.assertCompoundRegionsEqual( 

132 self.instance, 

133 eval( 

134 repr(self.instance), 

135 dict( 

136 UnionRegion=UnionRegion, 

137 IntersectionRegion=IntersectionRegion, 

138 Box=Box, 

139 Circle=Circle, 

140 UnitVector3d=UnitVector3d, 

141 Angle=Angle, 

142 AngleInterval=AngleInterval, 

143 NormalizedAngleInterval=NormalizedAngleInterval, 

144 ), 

145 ), 

146 ) 

147 

148 @unittest.skipIf(not yaml, "YAML module can not be imported") 

149 def testYaml(self): 

150 """Test that YAML dump and load round-trip.""" 

151 self.assertCompoundRegionsEqual(yaml.safe_load(yaml.dump(self.instance)), self.instance) 

152 

153 

154class UnionRegionTestCase(CompoundRegionTestMixin, unittest.TestCase): 

155 def setUp(self): 

156 CompoundRegionTestMixin.setUp(self) 

157 self.instance = UnionRegion(*self.operands) 

158 

159 def testContains(self): 

160 """Test point-in-region checks.""" 

161 self.assertTrue(self.instance.contains(UnitVector3d(self.point_in_both))) 

162 self.assertTrue(self.instance.contains(UnitVector3d(self.point_in_circle))) 

163 self.assertTrue(self.instance.contains(UnitVector3d(self.point_in_box))) 

164 self.assertFalse(self.instance.contains(UnitVector3d(self.point_in_neither))) 

165 

166 def testRelate(self): 

167 """Test region-region relationship checks.""" 

168 self.assertEqual(self.instance.relate(self.circle), CONTAINS) 

169 self.assertEqual(self.instance.relate(self.box), CONTAINS) 

170 self.assertEqual(self.instance.relate(self.faraway), DISJOINT) 

171 self.assertEqual(self.circle.relate(self.instance), WITHIN) 

172 self.assertEqual(self.box.relate(self.instance), WITHIN) 

173 self.assertEqual(self.faraway.relate(self.instance), DISJOINT) 

174 

175 

176class IntersectionRegionTestCase(CompoundRegionTestMixin, unittest.TestCase): 

177 def setUp(self): 

178 CompoundRegionTestMixin.setUp(self) 

179 self.instance = IntersectionRegion(*self.operands) 

180 

181 def testContains(self): 

182 """Test point-in-region checks.""" 

183 self.assertTrue(self.instance.contains(UnitVector3d(self.point_in_both))) 

184 self.assertFalse(self.instance.contains(UnitVector3d(self.point_in_circle))) 

185 self.assertFalse(self.instance.contains(UnitVector3d(self.point_in_box))) 

186 self.assertFalse(self.instance.contains(UnitVector3d(self.point_in_neither))) 

187 

188 def testRelate(self): 

189 """Test region-region relationship checks.""" 

190 self.assertEqual(self.instance.relate(self.box), WITHIN) 

191 self.assertEqual(self.instance.relate(self.circle), WITHIN) 

192 self.assertEqual(self.instance.relate(self.faraway), DISJOINT) 

193 self.assertEqual(self.circle.relate(self.instance), CONTAINS) 

194 self.assertEqual(self.box.relate(self.instance), CONTAINS) 

195 self.assertEqual(self.faraway.relate(self.instance), DISJOINT) 

196 

197 

198if __name__ == "__main__": 198 ↛ 199line 198 didn't jump to line 199, because the condition on line 198 was never true

199 unittest.main()