@@ -163,7 +163,6 @@ def multipointM_from_xyms(point_ms: tuple[float, float, float | None], oid_: int
163163multipointm = builds (multipointM_from_xyms , lists (tuples (xs , ys , ms ), min_size = 1 ), oid )
164164
165165@pytest .mark .hypothesis
166- # @settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large])
167166@given (expected = multipointm , i = integers (min_value = 1 ))
168167def test_MultiPointM_roundtrips (
169168 expected : shp .MultiPointM ,
@@ -196,7 +195,6 @@ def multipointZ_from_xyzms(pointz_ms: tuple[float, float, float, float | None],
196195
197196
198197@pytest .mark .hypothesis
199- # @settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large])
200198@given (expected = multipointz , i = integers (min_value = 1 ))
201199def test_MultiPointZ_roundtrips (
202200 expected : shp .MultiPointZ ,
@@ -248,7 +246,6 @@ def test_Polyline_roundtrips(
248246 assert actual .oid == expected .oid
249247
250248@pytest .mark .hypothesis
251- # @settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large])
252249@given (expected = polylinem , i = integers (min_value = 1 ))
253250def test_PolylineM_roundtrips (
254251 expected : shp .PolylineM ,
@@ -273,7 +270,6 @@ def test_PolylineM_roundtrips(
273270 assert actual .oid == expected .oid
274271
275272@pytest .mark .hypothesis
276- # @settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large])
277273@given (expected = polylinez , i = integers (min_value = 1 ))
278274def test_PolylineZ_roundtrips (
279275 expected : shp .PolylineZ ,
@@ -327,7 +323,6 @@ def test_Polygon_roundtrips(
327323 assert actual .oid == expected .oid
328324
329325@pytest .mark .hypothesis
330- # @settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large])
331326@given (expected = polygonm , i = integers (min_value = 1 ))
332327def test_PolygonM_roundtrips (
333328 expected : shp .PolygonM ,
@@ -352,7 +347,6 @@ def test_PolygonM_roundtrips(
352347 assert actual .oid == expected .oid
353348
354349@pytest .mark .hypothesis
355- # @settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large])
356350@given (expected = polygonz , i = integers (min_value = 1 ))
357351def test_PolygonZ_roundtrips (
358352 expected : shp .PolygonZ ,
@@ -392,7 +386,6 @@ def multipatch_from_xyzms_and_types(
392386
393387
394388@pytest .mark .hypothesis
395- # @settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large])
396389@given (expected = multipatch , i = integers (min_value = 1 ))
397390def test_MultiPatch_roundtrips (
398391 expected : shp .MultiPatch ,
@@ -418,6 +411,12 @@ def test_MultiPatch_roundtrips(
418411 assert actual .oid == expected .oid
419412 assert actual .partTypes == expected .partTypes , f"{ type (actual .partTypes )= } , { type (expected .partTypes )= } "
420413
414+ MAX_FILE_SIZE_16bw = (1 << 31 ) - 1 # This bound comes from encoding the
415+ # actual file size (in 16 bit words)
416+ # as a 4 byte signed integer.
417+ MAX_NUM_SHAPES = (MAX_FILE_SIZE_16bw - 50 ) // 6 # Minus 100B header, 12 bytes
418+ # per record (the minimum for
419+ # a Null shape).
421420
422421shape_codes_names_and_strategies = [
423422# (0, "Null Shape"),
@@ -438,7 +437,7 @@ def test_MultiPatch_roundtrips(
438437
439438def code_and_shape_strat_from_triple (t ):
440439 x , _name , shapes = t
441- return tuples (just (x ), lists (shapes , min_size = 0 )) # Empty shp files are in the esri spec.
440+ return tuples (just (x ), lists (shapes , min_size = 0 , max_size = MAX_NUM_SHAPES )) # Empty shp files are in the esri spec.
442441
443442codes_and_shapes_strats = [
444443 code_and_shape_strat_from_triple (t )
@@ -448,7 +447,6 @@ def code_and_shape_strat_from_triple(t):
448447codes_and_shapes = one_of (codes_and_shapes_strats )
449448
450449@pytest .mark .hypothesis
451- # @settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large])
452450@given (codes_and_shapes = codes_and_shapes )
453451def test_shp_reader_writer_roundtrip (codes_and_shapes )-> None :
454452 code_ex , expected_shapes = codes_and_shapes
@@ -483,3 +481,62 @@ def test_shp_reader_writer_roundtrip(codes_and_shapes)-> None:
483481 assert actual .partTypes == expected .partTypes , f"{ type (actual .partTypes )= } , { type (expected .partTypes )= } "
484482 else :
485483 assert not hasattr (expected , "partTypes" )
484+
485+
486+
487+ # SHX_UB = MAX_FILE_SIZE_16bw - 50
488+
489+
490+ # ## Surprisingly slow. Doesn't add enough value to merit waiting for
491+ # @composite
492+ # def positive_ints_with_bounded_sum(
493+ # draw,
494+ # min_x: int = 6,
495+ # upper_bound: int = SHX_UB,
496+ # max_len: int = MAX_NUM_SHAPES,
497+ # ):
498+ # assert min_x >= 1
499+ # assert upper_bound >= max_len
500+ # length = draw(integers(min_value=0, max_value=max_len))
501+ # if length == 0:
502+ # return []
503+
504+ # max_x = upper_bound - (length - 1)
505+ # result = []
506+
507+ # for i in range(length):
508+ # if max_x < min_x :
509+ # break
510+ # x = draw(integers(min_value=min_x, max_value=max_x))
511+ # result.append(x)
512+ # max_x -= x
513+
514+ # return result
515+
516+
517+ @pytest .mark .hypothesis
518+ @given (codes_and_shapes = codes_and_shapes )
519+ def test_shx_reader_writer_roundtrip (codes_and_shapes )-> None :
520+ code_ex , expected_shapes = codes_and_shapes
521+
522+ sizes_B = []
523+ offsets_B = []
524+ offset_B = 100 # "Thus, the offset for the first record in the
525+ # main file is 50 (16bw), given the 100-byte header. "
526+ shp_stream = io .BytesIO ()
527+ shx_stream = io .BytesIO ()
528+ with shp .ShpWriter (shp = shp_stream , shapeType = code_ex ) as shp_w :
529+ with shp .ShxWriter (shx = shx_stream , shp_writer = shp_w ) as shx_w :
530+ for shape in expected_shapes :
531+ offset_B , size_B = shp_w .shape (shape )
532+ sizes_B .append (size_B )
533+ offsets_B .append (offset_B )
534+ shx_w ._shx_record (offset_B , size_B )
535+
536+ shx_stream .seek (0 )
537+
538+ with shp .ShxReader (shx = shx_stream ) as r :
539+ assert r .numShapes == len (expected_shapes )
540+ assert r .offsets == offsets_B
541+ assert r .shape_lengths_B == sizes_B
542+
0 commit comments