1. import binascii
    
  2. 
    
  3. from django.contrib.gis.geos import (
    
  4.     GEOSGeometry,
    
  5.     Point,
    
  6.     Polygon,
    
  7.     WKBReader,
    
  8.     WKBWriter,
    
  9.     WKTReader,
    
  10.     WKTWriter,
    
  11. )
    
  12. from django.contrib.gis.geos.libgeos import geos_version_tuple
    
  13. from django.test import SimpleTestCase
    
  14. 
    
  15. 
    
  16. class GEOSIOTest(SimpleTestCase):
    
  17.     def test01_wktreader(self):
    
  18.         # Creating a WKTReader instance
    
  19.         wkt_r = WKTReader()
    
  20.         wkt = "POINT (5 23)"
    
  21. 
    
  22.         # read() should return a GEOSGeometry
    
  23.         ref = GEOSGeometry(wkt)
    
  24.         g1 = wkt_r.read(wkt.encode())
    
  25.         g2 = wkt_r.read(wkt)
    
  26. 
    
  27.         for geom in (g1, g2):
    
  28.             self.assertEqual(ref, geom)
    
  29. 
    
  30.         # Should only accept string objects.
    
  31.         with self.assertRaises(TypeError):
    
  32.             wkt_r.read(1)
    
  33.         with self.assertRaises(TypeError):
    
  34.             wkt_r.read(memoryview(b"foo"))
    
  35. 
    
  36.     def test02_wktwriter(self):
    
  37.         # Creating a WKTWriter instance, testing its ptr property.
    
  38.         wkt_w = WKTWriter()
    
  39.         with self.assertRaises(TypeError):
    
  40.             wkt_w.ptr = WKTReader.ptr_type()
    
  41. 
    
  42.         ref = GEOSGeometry("POINT (5 23)")
    
  43.         ref_wkt = "POINT (5.0000000000000000 23.0000000000000000)"
    
  44.         self.assertEqual(ref_wkt, wkt_w.write(ref).decode())
    
  45. 
    
  46.     def test_wktwriter_constructor_arguments(self):
    
  47.         wkt_w = WKTWriter(dim=3, trim=True, precision=3)
    
  48.         ref = GEOSGeometry("POINT (5.34562 23 1.5)")
    
  49.         if geos_version_tuple() > (3, 10):
    
  50.             ref_wkt = "POINT Z (5.346 23 1.5)"
    
  51.         else:
    
  52.             ref_wkt = "POINT Z (5.35 23 1.5)"
    
  53.         self.assertEqual(ref_wkt, wkt_w.write(ref).decode())
    
  54. 
    
  55.     def test03_wkbreader(self):
    
  56.         # Creating a WKBReader instance
    
  57.         wkb_r = WKBReader()
    
  58. 
    
  59.         hex = b"000000000140140000000000004037000000000000"
    
  60.         wkb = memoryview(binascii.a2b_hex(hex))
    
  61.         ref = GEOSGeometry(hex)
    
  62. 
    
  63.         # read() should return a GEOSGeometry on either a hex string or
    
  64.         # a WKB buffer.
    
  65.         g1 = wkb_r.read(wkb)
    
  66.         g2 = wkb_r.read(hex)
    
  67.         for geom in (g1, g2):
    
  68.             self.assertEqual(ref, geom)
    
  69. 
    
  70.         bad_input = (1, 5.23, None, False)
    
  71.         for bad_wkb in bad_input:
    
  72.             with self.assertRaises(TypeError):
    
  73.                 wkb_r.read(bad_wkb)
    
  74. 
    
  75.     def test04_wkbwriter(self):
    
  76.         wkb_w = WKBWriter()
    
  77. 
    
  78.         # Representations of 'POINT (5 23)' in hex -- one normal and
    
  79.         # the other with the byte order changed.
    
  80.         g = GEOSGeometry("POINT (5 23)")
    
  81.         hex1 = b"010100000000000000000014400000000000003740"
    
  82.         wkb1 = memoryview(binascii.a2b_hex(hex1))
    
  83.         hex2 = b"000000000140140000000000004037000000000000"
    
  84.         wkb2 = memoryview(binascii.a2b_hex(hex2))
    
  85. 
    
  86.         self.assertEqual(hex1, wkb_w.write_hex(g))
    
  87.         self.assertEqual(wkb1, wkb_w.write(g))
    
  88. 
    
  89.         # Ensuring bad byteorders are not accepted.
    
  90.         for bad_byteorder in (-1, 2, 523, "foo", None):
    
  91.             # Equivalent of `wkb_w.byteorder = bad_byteorder`
    
  92.             with self.assertRaises(ValueError):
    
  93.                 wkb_w._set_byteorder(bad_byteorder)
    
  94. 
    
  95.         # Setting the byteorder to 0 (for Big Endian)
    
  96.         wkb_w.byteorder = 0
    
  97.         self.assertEqual(hex2, wkb_w.write_hex(g))
    
  98.         self.assertEqual(wkb2, wkb_w.write(g))
    
  99. 
    
  100.         # Back to Little Endian
    
  101.         wkb_w.byteorder = 1
    
  102. 
    
  103.         # Now, trying out the 3D and SRID flags.
    
  104.         g = GEOSGeometry("POINT (5 23 17)")
    
  105.         g.srid = 4326
    
  106. 
    
  107.         hex3d = b"0101000080000000000000144000000000000037400000000000003140"
    
  108.         wkb3d = memoryview(binascii.a2b_hex(hex3d))
    
  109.         hex3d_srid = (
    
  110.             b"01010000A0E6100000000000000000144000000000000037400000000000003140"
    
  111.         )
    
  112.         wkb3d_srid = memoryview(binascii.a2b_hex(hex3d_srid))
    
  113. 
    
  114.         # Ensuring bad output dimensions are not accepted
    
  115.         for bad_outdim in (-1, 0, 1, 4, 423, "foo", None):
    
  116.             with self.assertRaisesMessage(
    
  117.                 ValueError, "WKB output dimension must be 2 or 3"
    
  118.             ):
    
  119.                 wkb_w.outdim = bad_outdim
    
  120. 
    
  121.         # Now setting the output dimensions to be 3
    
  122.         wkb_w.outdim = 3
    
  123. 
    
  124.         self.assertEqual(hex3d, wkb_w.write_hex(g))
    
  125.         self.assertEqual(wkb3d, wkb_w.write(g))
    
  126. 
    
  127.         # Telling the WKBWriter to include the srid in the representation.
    
  128.         wkb_w.srid = True
    
  129.         self.assertEqual(hex3d_srid, wkb_w.write_hex(g))
    
  130.         self.assertEqual(wkb3d_srid, wkb_w.write(g))
    
  131. 
    
  132.     def test_wkt_writer_trim(self):
    
  133.         wkt_w = WKTWriter()
    
  134.         self.assertFalse(wkt_w.trim)
    
  135.         self.assertEqual(
    
  136.             wkt_w.write(Point(1, 1)), b"POINT (1.0000000000000000 1.0000000000000000)"
    
  137.         )
    
  138. 
    
  139.         wkt_w.trim = True
    
  140.         self.assertTrue(wkt_w.trim)
    
  141.         self.assertEqual(wkt_w.write(Point(1, 1)), b"POINT (1 1)")
    
  142.         self.assertEqual(wkt_w.write(Point(1.1, 1)), b"POINT (1.1 1)")
    
  143.         self.assertEqual(
    
  144.             wkt_w.write(Point(1.0 / 3, 1)), b"POINT (0.3333333333333333 1)"
    
  145.         )
    
  146. 
    
  147.         wkt_w.trim = False
    
  148.         self.assertFalse(wkt_w.trim)
    
  149.         self.assertEqual(
    
  150.             wkt_w.write(Point(1, 1)), b"POINT (1.0000000000000000 1.0000000000000000)"
    
  151.         )
    
  152. 
    
  153.     def test_wkt_writer_precision(self):
    
  154.         wkt_w = WKTWriter()
    
  155.         self.assertIsNone(wkt_w.precision)
    
  156.         self.assertEqual(
    
  157.             wkt_w.write(Point(1.0 / 3, 2.0 / 3)),
    
  158.             b"POINT (0.3333333333333333 0.6666666666666666)",
    
  159.         )
    
  160. 
    
  161.         wkt_w.precision = 1
    
  162.         self.assertEqual(wkt_w.precision, 1)
    
  163.         self.assertEqual(wkt_w.write(Point(1.0 / 3, 2.0 / 3)), b"POINT (0.3 0.7)")
    
  164. 
    
  165.         wkt_w.precision = 0
    
  166.         self.assertEqual(wkt_w.precision, 0)
    
  167.         self.assertEqual(wkt_w.write(Point(1.0 / 3, 2.0 / 3)), b"POINT (0 1)")
    
  168. 
    
  169.         wkt_w.precision = None
    
  170.         self.assertIsNone(wkt_w.precision)
    
  171.         self.assertEqual(
    
  172.             wkt_w.write(Point(1.0 / 3, 2.0 / 3)),
    
  173.             b"POINT (0.3333333333333333 0.6666666666666666)",
    
  174.         )
    
  175. 
    
  176.         with self.assertRaisesMessage(
    
  177.             AttributeError, "WKT output rounding precision must be "
    
  178.         ):
    
  179.             wkt_w.precision = "potato"
    
  180. 
    
  181.     def test_empty_point_wkb(self):
    
  182.         p = Point(srid=4326)
    
  183.         wkb_w = WKBWriter()
    
  184. 
    
  185.         wkb_w.srid = False
    
  186.         with self.assertRaisesMessage(
    
  187.             ValueError, "Empty point is not representable in WKB."
    
  188.         ):
    
  189.             wkb_w.write(p)
    
  190.         with self.assertRaisesMessage(
    
  191.             ValueError, "Empty point is not representable in WKB."
    
  192.         ):
    
  193.             wkb_w.write_hex(p)
    
  194. 
    
  195.         wkb_w.srid = True
    
  196.         for byteorder, hex in enumerate(
    
  197.             [
    
  198.                 b"0020000001000010E67FF80000000000007FF8000000000000",
    
  199.                 b"0101000020E6100000000000000000F87F000000000000F87F",
    
  200.             ]
    
  201.         ):
    
  202.             wkb_w.byteorder = byteorder
    
  203.             self.assertEqual(wkb_w.write_hex(p), hex)
    
  204.             self.assertEqual(GEOSGeometry(wkb_w.write_hex(p)), p)
    
  205.             self.assertEqual(wkb_w.write(p), memoryview(binascii.a2b_hex(hex)))
    
  206.             self.assertEqual(GEOSGeometry(wkb_w.write(p)), p)
    
  207. 
    
  208.     def test_empty_polygon_wkb(self):
    
  209.         p = Polygon(srid=4326)
    
  210.         p_no_srid = Polygon()
    
  211.         wkb_w = WKBWriter()
    
  212.         wkb_w.srid = True
    
  213.         for byteorder, hexes in enumerate(
    
  214.             [
    
  215.                 (b"000000000300000000", b"0020000003000010E600000000"),
    
  216.                 (b"010300000000000000", b"0103000020E610000000000000"),
    
  217.             ]
    
  218.         ):
    
  219.             wkb_w.byteorder = byteorder
    
  220.             for srid, hex in enumerate(hexes):
    
  221.                 wkb_w.srid = srid
    
  222.                 self.assertEqual(wkb_w.write_hex(p), hex)
    
  223.                 self.assertEqual(
    
  224.                     GEOSGeometry(wkb_w.write_hex(p)), p if srid else p_no_srid
    
  225.                 )
    
  226.                 self.assertEqual(wkb_w.write(p), memoryview(binascii.a2b_hex(hex)))
    
  227.                 self.assertEqual(GEOSGeometry(wkb_w.write(p)), p if srid else p_no_srid)