Coverage for test / idm_orcid_test.py: 99%

164 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-25 18:06 +0000

1# SPDX-FileCopyrightText: 2023 Marta Soricetti <marta.soricetti@unibo.it> 

2# SPDX-FileCopyrightText: 2023-2024 Arianna Moretti <arianna.moretti4@unibo.it> 

3# SPDX-FileCopyrightText: 2024-2026 Arcangelo Massari <arcangelo.massari@unibo.it> 

4# 

5# SPDX-License-Identifier: ISC 

6 

7import json 

8import re 

9import unittest 

10from os import makedirs 

11from os.path import exists, join 

12 

13from oc_ds_converter.oc_idmanager.orcid import ORCIDManager 

14 

15 

16class orcidIdentifierManagerTest(unittest.TestCase): 

17 """This class aim at testing identifiers manager.""" 

18 

19 def setUp(self): 

20 if not exists("tmp"): 

21 makedirs("tmp") 

22 

23 self.test_dir = join("test", "data") 

24 self.test_json_path = join(self.test_dir, "glob.json") 

25 with open(self.test_json_path, encoding="utf-8") as fp: 

26 self.data = json.load(fp) 

27 

28 self.valid_orcid_1 = "0000-0003-0530-4305" 

29 self.valid_orcid_2 = "0000-0001-5506-523X" 

30 self.invalid_orcid_1 = "0000-0003-0530-430C" 

31 self.invalid_orcid_2 = "0000-0001-5506-5232" 

32 self.invalid_orcid_3 = "0000-0001-5506-523" 

33 self.invalid_orcid_4 = "1-5506-5232" 

34 self.invalid_orcid_5 = "0000-0001-2345-6789" 

35 

36 

37 def test_orcid_normalise(self): 

38 om = ORCIDManager() 

39 self.assertEqual( 

40 self.valid_orcid_1, om.normalise(self.valid_orcid_1.replace("-", " ")) 

41 ) 

42 self.assertEqual( 

43 self.valid_orcid_1, om.normalise("https://orcid.org/" + self.valid_orcid_1) 

44 ) 

45 self.assertEqual( 

46 self.valid_orcid_2, om.normalise(self.valid_orcid_2.replace("-", " ")) 

47 ) 

48 self.assertEqual( 

49 self.invalid_orcid_3, om.normalise(self.invalid_orcid_3.replace("-", " ")) 

50 ) 

51 

52 def test_orcid_is_valid(self): 

53 om = ORCIDManager() 

54 self.assertTrue(om.is_valid(self.valid_orcid_1)) 

55 self.assertTrue(om.is_valid(self.valid_orcid_2)) 

56 self.assertFalse(om.is_valid(self.invalid_orcid_1)) 

57 self.assertFalse(om.is_valid(self.invalid_orcid_2)) 

58 self.assertFalse(om.is_valid(self.invalid_orcid_3)) 

59 self.assertFalse(om.is_valid(self.invalid_orcid_4)) 

60 

61 om_file = ORCIDManager(testing=True, use_api_service=False) 

62 self.assertTrue(om_file.normalise(self.valid_orcid_1, include_prefix=True) in self.data) 

63 self.assertTrue(om_file.normalise(self.valid_orcid_2, include_prefix=True) in self.data) 

64 self.assertTrue(om_file.is_valid(om_file.normalise(self.valid_orcid_1, include_prefix=True))) 

65 self.assertTrue(om_file.is_valid(om_file.normalise(self.valid_orcid_2, include_prefix=True))) 

66 

67 om_nofile_noapi = ORCIDManager(use_api_service=False) 

68 self.assertTrue(om_nofile_noapi.is_valid(self.valid_orcid_1)) 

69 self.assertTrue(om_nofile_noapi.is_valid(self.valid_orcid_2)) 

70 

71 def test_exists(self): 

72 with self.subTest(msg="get_extra_info=True, allow_extra_api=None"): 

73 orcid_manager = ORCIDManager() 

74 output = orcid_manager.exists(self.valid_orcid_2, get_extra_info=True, allow_extra_api=None) 

75 self.assertTrue(output[0]) # Check if exists 

76 info = output[1] 

77 self.assertEqual(info['id'], '0000-0001-5506-523X') 

78 self.assertTrue(info['valid']) 

79 self.assertEqual(info['family_name'], 'Shotton') 

80 self.assertEqual(info['given_name'], 'David') 

81 self.assertEqual(info['email'], "") 

82 self.assertEqual(info['external_identifiers'], {}) 

83 self.assertEqual(info['submission_date'], '2012-10-31') 

84 # Check if update_date is a valid date string and not earlier than submission_date 

85 self.assertTrue(re.match(r'\d{4}-\d{2}-\d{2}', info['update_date'])) 

86 self.assertGreaterEqual(info['update_date'], info['submission_date']) 

87 with self.subTest(msg="get_extra_info=False, allow_extra_api=None"): 

88 orcid_manager = ORCIDManager() 

89 output = orcid_manager.exists(orcid_manager.normalise(self.valid_orcid_1), get_extra_info=False, allow_extra_api=None) 

90 expected_output = True 

91 self.assertEqual(output, expected_output) 

92 with self.subTest(msg="get_extra_info=False, allow_extra_api='None'"): 

93 orcid_manager = ORCIDManager() 

94 output = orcid_manager.exists(self.invalid_orcid_5, get_extra_info=False, allow_extra_api='None') 

95 expected_output = False 

96 self.assertEqual(output, expected_output) 

97 

98 def test_orcid_default(self): 

99 am_nofile = ORCIDManager(testing=True) 

100 # Uses RedisStorageManager with testing=True (fakeredis) 

101 # uses API 

102 self.assertTrue(am_nofile.is_valid(self.valid_orcid_1)) 

103 self.assertTrue(am_nofile.is_valid(self.valid_orcid_2)) 

104 self.assertFalse(am_nofile.is_valid(self.invalid_orcid_2)) 

105 self.assertFalse(am_nofile.is_valid(self.invalid_orcid_1)) 

106 validated_ids = [self.valid_orcid_1, self.valid_orcid_2, self.invalid_orcid_1, self.invalid_orcid_2] 

107 # check that all the validated ids are stored in redis 

108 all_ids_stored = am_nofile.storage_manager.get_all_keys() 

109 self.assertTrue(all(am_nofile.normalise(x, include_prefix=True) in all_ids_stored for x in validated_ids)) 

110 am_nofile.storage_manager.delete_storage() 

111 # check that the storage was correctly deleted 

112 self.assertEqual(am_nofile.storage_manager.get_all_keys(), set()) 

113 

114 def test_orcid_memory_file_noapi(self): 

115 # Uses support file (without updating it) 

116 # Uses RedisStorageManager storage manager 

117 # does not use API (so a syntactically correct id is considered to be valid) 

118 am_file = ORCIDManager(testing=True, use_api_service=False) 

119 self.assertTrue(am_file.normalise(self.valid_orcid_1, include_prefix=True) in self.data) 

120 self.assertTrue(am_file.normalise(self.invalid_orcid_2, include_prefix=True) in self.data) 

121 self.assertFalse(am_file.is_valid(self.invalid_orcid_2)) # is stored in support file as invalid 

122 self.assertTrue(am_file.is_valid(am_file.normalise(self.invalid_orcid_5, include_prefix=True))) # is not stored in support file as invalid, does not exist but has correct syntax 

123 

124 def test_orcid_memory_file_api(self): 

125 # Uses support file (without updating it) 

126 # Uses RedisStorageManager storage manager 

127 # uses API (so a syntactically correct id which is not valid is considered to be invalid) 

128 am_file = ORCIDManager(testing=True, use_api_service=True) 

129 self.assertFalse(am_file.is_valid(self.invalid_orcid_1)) 

130 

131 def test_orcid_memory_nofile_noapi(self): 

132 # Does not use support file 

133 # Uses RedisStorageManager storage manager 

134 # Does not API (so a syntactically correct id which is not valid is considered to be valid) 

135 am_nofile_noapi = ORCIDManager(testing=True, use_api_service=False) 

136 self.assertTrue(am_nofile_noapi.is_valid(self.valid_orcid_1)) 

137 self.assertTrue(am_nofile_noapi.is_valid(self.invalid_orcid_5)) 

138 am_nofile_noapi.storage_manager.delete_storage() 

139 

140 

141 

142 def test_orcid_sqlite_nofile_api(self): 

143 # No pre-existing data 

144 # storage manager : RedisStorageManager 

145 # uses API 

146 sql_am_nofile = ORCIDManager(testing=True) 

147 self.assertTrue(sql_am_nofile.is_valid(self.valid_orcid_1)) 

148 self.assertTrue(sql_am_nofile.is_valid(self.valid_orcid_2)) 

149 self.assertFalse(sql_am_nofile.is_valid(self.invalid_orcid_1)) 

150 self.assertFalse(sql_am_nofile.is_valid(self.invalid_orcid_2)) 

151 # check that the redis storage contains all the validated ids 

152 validated_ids = [self.valid_orcid_1, self.valid_orcid_2, self.invalid_orcid_1, self.invalid_orcid_2] 

153 all_ids_stored = sql_am_nofile.storage_manager.get_all_keys() 

154 # check that all the validated ids are stored 

155 self.assertTrue(all(sql_am_nofile.normalise(x, include_prefix=True) in all_ids_stored for x in validated_ids)) 

156 sql_am_nofile.storage_manager.delete_storage() 

157 # check that the storage was correctly deleted 

158 self.assertEqual(sql_am_nofile.storage_manager.get_all_keys(), set()) 

159 

160 def test_orcid_sqlite_file_api(self): 

161 # Uses pre-existing data in Redis 

162 # Uses RedisStorageManager storage manager 

163 # tests validation behavior with pre-seeded data 

164 to_insert = [self.invalid_orcid_1, self.valid_orcid_1] 

165 sql_file = ORCIDManager(testing=True, use_api_service=True) 

166 for id in to_insert: 

167 norm_id = sql_file.normalise(id, include_prefix=True) 

168 is_valid = sql_file.is_valid(norm_id) 

169 sql_file.storage_manager.set_value(norm_id, is_valid) 

170 

171 sql_no_api = ORCIDManager(testing=True, use_api_service=False) 

172 # Copy values from the first manager to the second for testing 

173 for id in to_insert: 

174 norm_id = sql_no_api.normalise(id, include_prefix=True) 

175 value = sql_file.storage_manager.get_value(norm_id) 

176 if value is not None: 

177 sql_no_api.storage_manager.set_value(norm_id, value) 

178 all_db_keys = sql_no_api.storage_manager.get_all_keys() 

179 # check that all the normalised ids in the list were correctly inserted 

180 self.assertTrue(all(sql_no_api.normalise(x, include_prefix=True) in all_db_keys for x in to_insert)) 

181 self.assertTrue(sql_no_api.is_valid(self.valid_orcid_1)) # is stored as valid 

182 self.assertFalse(sql_no_api.is_valid(self.invalid_orcid_1)) # is stored as invalid 

183 self.assertTrue(sql_no_api.is_valid(sql_no_api.normalise(self.invalid_orcid_5, include_prefix=True))) # not stored as invalid, has correct syntax 

184 sql_no_api.storage_manager.delete_storage() 

185 

186 def test_orcid_sqlite_nofile_noapi(self): 

187 # Does not use support file 

188 # Uses RedisStorageManager storage manager 

189 # Does not use API (so a syntactically correct id which is not valid is considered to be valid) 

190 am_nofile_noapi = ORCIDManager(testing=True, use_api_service=False) 

191 self.assertTrue(am_nofile_noapi.is_valid(self.valid_orcid_1)) 

192 self.assertTrue(am_nofile_noapi.is_valid(self.invalid_orcid_5)) 

193 am_nofile_noapi.storage_manager.delete_storage() 

194 

195 

196 

197 #### REDIS STORAGE MANAGER 

198 def test_orcid_redis_nofile_api(self): 

199 # No available data in redis db 

200 # Storage manager : RedisStorageManager 

201 # uses API 

202 sql_am_nofile = ORCIDManager(testing=True) 

203 self.assertTrue(sql_am_nofile.is_valid(self.valid_orcid_1)) 

204 self.assertTrue(sql_am_nofile.is_valid(self.valid_orcid_2)) 

205 self.assertFalse(sql_am_nofile.is_valid(self.invalid_orcid_1)) 

206 self.assertFalse(sql_am_nofile.is_valid(self.invalid_orcid_2)) 

207 # check that the redis db was correctly filled and that it contains all the validated ids 

208 

209 validated_ids = {self.valid_orcid_1, self.valid_orcid_2, self.invalid_orcid_1, self.invalid_orcid_2} 

210 validated_ids = {sql_am_nofile.normalise(x, include_prefix=True) for x in validated_ids} 

211 all_ids_stored = sql_am_nofile.storage_manager.get_all_keys() 

212 # check that all the validated ids are stored in the json file 

213 self.assertEqual(validated_ids, all_ids_stored) 

214 sql_am_nofile.storage_manager.delete_storage() 

215 # check that the support file was correctly deleted 

216 self.assertEqual(sql_am_nofile.storage_manager.get_all_keys(), set()) 

217 

218 def test_orcid_redis_file_api(self): 

219 # Uses data in redis db 

220 # Uses RedisStorageManager 

221 # does not use API (so a syntactically correct id is considered to be valid) 

222 # fills db 

223 

224 to_insert = [self.invalid_orcid_1, self.valid_orcid_1] 

225 sql_file = ORCIDManager(testing=True, use_api_service=True) 

226 for id in to_insert: 

227 norm_id = sql_file.normalise(id, include_prefix=True) 

228 is_valid = sql_file.is_valid(norm_id) 

229 sql_file.storage_manager.set_value(norm_id,is_valid) 

230 

231 sql_no_api = ORCIDManager(testing=True, use_api_service=False) 

232 # Copy values from the first manager to the second for testing 

233 for id in to_insert: 

234 norm_id = sql_no_api.normalise(id, include_prefix=True) 

235 value = sql_file.storage_manager.get_value(norm_id) 

236 if value is not None: 

237 sql_no_api.storage_manager.set_value(norm_id, value) 

238 all_db_keys = sql_no_api.storage_manager.get_all_keys() 

239 #check that all the normalised ids in the list were correctly inserted in the db 

240 self.assertTrue(all(sql_no_api.normalise(x,include_prefix=True) in all_db_keys for x in to_insert)) 

241 

242 self.assertTrue(sql_no_api.is_valid(self.valid_orcid_1)) # is stored in support file as valid 

243 self.assertFalse(sql_no_api.is_valid(self.invalid_orcid_1)) # is stored in support file as invalid 

244 self.assertTrue(sql_no_api.is_valid(sql_no_api.normalise(self.invalid_orcid_5, include_prefix=True))) # is not stored in support file as invalid, does not exist but has correct syntax 

245 sql_no_api.storage_manager.delete_storage() 

246 

247 def test_orcid_redis_nofile_noapi(self): 

248 # No data in redis db 

249 # Uses RedisStorageManager 

250 # Does not API (so a syntactically correct id which is not valid is considered to be valid) 

251 am_nofile_noapi = ORCIDManager(testing=True, use_api_service=False) 

252 self.assertTrue(am_nofile_noapi.is_valid(self.valid_orcid_1)) 

253 self.assertTrue(am_nofile_noapi.is_valid(self.invalid_orcid_5)) 

254 am_nofile_noapi.storage_manager.delete_storage() 

255 

256 

257