1+ import pytest
2+
13import suitesparse_graphblas
2- from suitesparse_graphblas import ffi , lib # noqa: F401
4+ from suitesparse_graphblas import ffi , lib
35
46
57def test_matrix_existence ():
@@ -12,3 +14,55 @@ def test_version():
1214 version = suitesparse_graphblas .__version__
1315 version = [int (x ) for x in version .split ("+" )[0 ].split ("." )]
1416 assert version > [9 , 4 , 4 , 0 ]
17+
18+
19+ def test_openmp ():
20+ # GraphBLAS only warns at configure time when OpenMP is missing and still
21+ # builds a working, but serial, library, so a serial build is invisible
22+ # from the outside: conda-forge's graphblas 10.5.0 shipped that way on
23+ # osx-arm64. Wheels build GraphBLAS from source in suitesparse.sh, where
24+ # macOS has to point CMake at Homebrew's libomp by hand, so the same slip
25+ # is possible here.
26+ val_ptr = ffi .new ("int32_t*" )
27+ info = lib .GrB_Global_get_INT32 (lib .GrB_GLOBAL , val_ptr , lib .GxB_LIBRARY_OPENMP )
28+ assert info == lib .GrB_SUCCESS
29+ assert val_ptr [0 ], "libgraphblas was built without OpenMP"
30+
31+
32+ def test_libgraphblas_version_matches_the_loaded_library ():
33+ """The GraphBLAS this extension was compiled against must be the one it loads.
34+
35+ ``libgraphblas_version`` reads cffi ``#define`` constants, which are
36+ resolved when the C extension is compiled against a particular
37+ GraphBLAS.h. The values below come from the shared library actually loaded
38+ at runtime. When those disagree, every cffi call is reading a struct laid
39+ out by a different build -- a mismatch that surfaces later as an
40+ unexplained ``GrB_OUT_OF_MEMORY`` or a crash, never as an import error.
41+ """
42+ val_ptr = ffi .new ("int32_t*" )
43+ runtime = []
44+ for field in (
45+ lib .GrB_LIBRARY_VER_MAJOR ,
46+ lib .GrB_LIBRARY_VER_MINOR ,
47+ lib .GrB_LIBRARY_VER_PATCH ,
48+ ):
49+ assert lib .GrB_Global_get_INT32 (lib .GrB_GLOBAL , val_ptr , field ) == lib .GrB_SUCCESS
50+ runtime .append (val_ptr [0 ])
51+ assert tuple (runtime ) == suitesparse_graphblas .libgraphblas_version
52+
53+
54+ def test_version_tracks_libgraphblas ():
55+ """A released version's first three parts are the SuiteSparse:GraphBLAS version.
56+
57+ That convention is what lets a caller infer the library version from the
58+ package version, and it only holds for a release: between releases the
59+ version reports the previous tag, which is why ``libgraphblas_version``
60+ exists and why anything gating on a library feature should read that
61+ instead. Skipped on a development build rather than asserted, since
62+ disagreeing there is the expected state, not a defect.
63+ """
64+ version = suitesparse_graphblas .__version__
65+ if "+" in version :
66+ pytest .skip (f"development build between releases: { version } " )
67+ parts = tuple (int (x ) for x in version .split ("." )[:3 ])
68+ assert parts == suitesparse_graphblas .libgraphblas_version
0 commit comments