1
1
"""
2
2
Test the functions that load libgmt.
3
3
"""
4
+ import ctypes
4
5
import shutil
5
6
import subprocess
6
7
import sys
12
13
from pygmt .exceptions import GMTCLibError , GMTCLibNotFoundError , GMTOSError
13
14
14
15
16
+ class FakedLibGMT : # pylint: disable=too-few-public-methods
17
+ """
18
+ Class for faking a GMT library.
19
+ """
20
+
21
+ def __init__ (self , name ):
22
+ self ._name = name
23
+
24
+ def __str__ (self ):
25
+ return self ._name
26
+
27
+
15
28
def test_check_libgmt ():
16
29
"""
17
30
Make sure check_libgmt fails when given a bogus library.
18
31
"""
19
- # create a fake library with a "_name" property
20
- def libgmt ():
21
- pass
22
-
23
- libgmt ._name = "/path/to/libgmt.so" # pylint: disable=protected-access
32
+ libgmt = FakedLibGMT ("/path/to/libgmt.so" )
24
33
msg = (
25
34
# pylint: disable=protected-access
26
35
f"Error loading '{ libgmt ._name } '. "
@@ -33,6 +42,22 @@ def libgmt():
33
42
check_libgmt (libgmt )
34
43
35
44
45
+ def test_clib_names ():
46
+ """
47
+ Make sure we get the correct library name for different OS names.
48
+ """
49
+ for linux in ["linux" , "linux2" , "linux3" ]:
50
+ assert clib_names (linux ) == ["libgmt.so" ]
51
+ assert clib_names ("darwin" ) == ["libgmt.dylib" ]
52
+ assert clib_names ("win32" ) == ["gmt.dll" , "gmt_w64.dll" , "gmt_w32.dll" ]
53
+ for freebsd in ["freebsd10" , "freebsd11" , "freebsd12" ]:
54
+ assert clib_names (freebsd ) == ["libgmt.so" ]
55
+ with pytest .raises (GMTOSError ):
56
+ clib_names ("meh" )
57
+
58
+
59
+ ###############################################################################
60
+ # Tests for load_libgmt
36
61
def test_load_libgmt ():
37
62
"""
38
63
Test that loading libgmt works and doesn't crash.
@@ -64,19 +89,85 @@ def test_load_libgmt_with_a_bad_library_path(monkeypatch):
64
89
assert check_libgmt (load_libgmt ()) is None
65
90
66
91
67
- def test_clib_names ( ):
92
+ def test_load_libgmt_with_broken_libraries ( monkeypatch ):
68
93
"""
69
- Make sure we get the correct library name for different OS names .
94
+ Test load_libgmt still works when a broken library is found .
70
95
"""
71
- for linux in ["linux" , "linux2" , "linux3" ]:
72
- assert clib_names (linux ) == ["libgmt.so" ]
73
- assert clib_names ("darwin" ) == ["libgmt.dylib" ]
74
- assert clib_names ("win32" ) == ["gmt.dll" , "gmt_w64.dll" , "gmt_w32.dll" ]
75
- for freebsd in ["freebsd10" , "freebsd11" , "freebsd12" ]:
76
- assert clib_names (freebsd ) == ["libgmt.so" ]
77
- with pytest .raises (GMTOSError ):
78
- clib_names ("meh" )
96
+ # load the GMT library before mocking the ctypes.CDLL function
97
+ loaded_libgmt = load_libgmt ()
98
+
99
+ def mock_ctypes_cdll_return (libname ):
100
+ """
101
+ Mock the return value of ctypes.CDLL.
102
+
103
+ Parameters
104
+ ----------
105
+ libname : str or FakedLibGMT or ctypes.CDLL
106
+ Path to the GMT library, a faked GMT library or a working library
107
+ loaded as ctypes.CDLL.
108
+
109
+ Return
110
+ ------
111
+ object
112
+ Either the loaded GMT library or the faked GMT library.
113
+ """
114
+ if isinstance (libname , FakedLibGMT ):
115
+ # libname is a faked GMT library, return the faked library
116
+ return libname
117
+ if isinstance (libname , str ):
118
+ # libname is an invalid library path in str type,
119
+ # raise OSError like the original ctypes.CDLL
120
+ raise OSError (f"Unable to find '{ libname } '" )
121
+ # libname is a loaded GMT library
122
+ return loaded_libgmt
123
+
124
+ with monkeypatch .context () as mpatch :
125
+ # pylint: disable=protected-access
126
+ # mock the ctypes.CDLL using mock_ctypes_cdll_return()
127
+ mpatch .setattr (ctypes , "CDLL" , mock_ctypes_cdll_return )
128
+
129
+ faked_libgmt1 = FakedLibGMT ("/path/to/faked/libgmt1.so" )
130
+ faked_libgmt2 = FakedLibGMT ("/path/to/faked/libgmt2.so" )
131
+
132
+ # case 1: two broken libraries
133
+ # Raise the GMTCLibNotFoundError exception
134
+ # The error message should contains information of both libraries
135
+ lib_fullnames = [faked_libgmt1 , faked_libgmt2 ]
136
+ msg_regex = (
137
+ fr"Error loading the GMT shared library '{ faked_libgmt1 ._name } '.\n"
138
+ fr"Error loading '{ faked_libgmt1 ._name } '. Couldn't access.*\n"
139
+ fr"Error loading the GMT shared library '{ faked_libgmt2 ._name } '.\n"
140
+ fr"Error loading '{ faked_libgmt2 ._name } '. Couldn't access.*"
141
+ )
142
+ with pytest .raises (GMTCLibNotFoundError , match = msg_regex ):
143
+ load_libgmt (lib_fullnames = lib_fullnames )
144
+
145
+ # case 2: broken library + invalid path
146
+ lib_fullnames = [faked_libgmt1 , "/invalid/path/to/libgmt.so" ]
147
+ msg_regex = (
148
+ fr"Error loading the GMT shared library '{ faked_libgmt1 ._name } '.\n"
149
+ fr"Error loading '{ faked_libgmt1 ._name } '. Couldn't access.*\n"
150
+ "Error loading the GMT shared library '/invalid/path/to/libgmt.so'.\n "
151
+ "Unable to find '/invalid/path/to/libgmt.so'"
152
+ )
153
+ with pytest .raises (GMTCLibNotFoundError , match = msg_regex ):
154
+ load_libgmt (lib_fullnames = lib_fullnames )
155
+
156
+ # case 3: broken library + invalid path + working library
157
+ lib_fullnames = [faked_libgmt1 , "/invalid/path/to/libgmt.so" , loaded_libgmt ]
158
+ assert check_libgmt (load_libgmt (lib_fullnames = lib_fullnames )) is None
159
+
160
+ # case 4: invalid path + broken library + working library
161
+ lib_fullnames = ["/invalid/path/to/libgmt.so" , faked_libgmt1 , loaded_libgmt ]
162
+ assert check_libgmt (load_libgmt (lib_fullnames = lib_fullnames )) is None
163
+
164
+ # case 5: working library + broken library + invalid path
165
+ lib_fullnames = [loaded_libgmt , faked_libgmt1 , "/invalid/path/to/libgmt.so" ]
166
+ assert check_libgmt (load_libgmt (lib_fullnames = lib_fullnames )) is None
79
167
168
+ # case 6: repeated broken library + working library
169
+ lib_fullnames = [faked_libgmt1 , faked_libgmt1 , loaded_libgmt ]
170
+ assert check_libgmt (load_libgmt (lib_fullnames = lib_fullnames )) is None
80
171
81
172
###############################################################################
82
173
# Tests for clib_full_names
0 commit comments