Skip to content

Commit 33d8dfa

Browse files
committed
Improve test coverage to 99%
1 parent d5b7dfb commit 33d8dfa

3 files changed

Lines changed: 121 additions & 0 deletions

File tree

tests/test_api.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,41 @@ def test_convenience_functions():
282282
assert ci.get_cas("caffeine") is None
283283

284284

285+
def test_convenience_functions_return_none_on_not_found():
286+
"""Tests that convenience functions return None when compound is not found."""
287+
assert ci.get_weight("nonexistent") is None
288+
assert ci.get_formula("nonexistent") is None
289+
assert ci.get_canonical_smiles("nonexistent") is None
290+
assert ci.get_isomeric_smiles("nonexistent") is None
291+
assert ci.get_iupac_name("nonexistent") is None
292+
assert ci.get_xlogp("nonexistent") is None
293+
assert ci.get_cas("nonexistent") is None
294+
assert ci.get_exact_mass("nonexistent") is None
295+
assert ci.get_monoisotopic_mass("nonexistent") is None
296+
assert ci.get_tpsa("nonexistent") is None
297+
assert ci.get_complexity("nonexistent") is None
298+
assert ci.get_h_bond_donor_count("nonexistent") is None
299+
assert ci.get_h_bond_acceptor_count("nonexistent") is None
300+
assert ci.get_rotatable_bond_count("nonexistent") is None
301+
assert ci.get_heavy_atom_count("nonexistent") is None
302+
assert ci.get_charge("nonexistent") is None
303+
assert ci.get_atom_stereo_count("nonexistent") is None
304+
assert ci.get_bond_stereo_count("nonexistent") is None
305+
assert ci.get_covalent_unit_count("nonexistent") is None
306+
assert ci.get_inchi("nonexistent") is None
307+
assert ci.get_inchi_key("nonexistent") is None
308+
309+
310+
def test_convenience_functions_return_none_on_ambiguous():
311+
"""Tests that convenience functions return None when identifier is ambiguous."""
312+
assert ci.get_weight("ambiguous") is None
313+
assert ci.get_formula("ambiguous") is None
314+
assert ci.get_canonical_smiles("ambiguous") is None
315+
assert ci.get_isomeric_smiles("ambiguous") is None
316+
assert ci.get_iupac_name("ambiguous") is None
317+
assert ci.get_xlogp("ambiguous") is None
318+
319+
285320
def test_get_compound_and_compounds():
286321
"""Tests the Compound object retrieval functions."""
287322
cmpd = ci.get_compound("aspirin")

tests/test_api_helpers_unit.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,26 @@ def test_get_batch_properties_invalid_response(self):
205205
result = api_helpers.get_batch_properties([1, 2], ["MolecularWeight"])
206206
assert result == {1: {}, 2: {}}
207207

208+
def test_get_batch_properties_pagination_fails_on_second_request(self):
209+
"""Test that pagination stops when a subsequent request fails."""
210+
first_response = {
211+
"PropertyTable": {"Properties": [{"CID": 1, "MolecularWeight": "100.0"}]},
212+
"ListKey": "test_key_123",
213+
}
214+
215+
# Second request returns invalid data (simulating a failure)
216+
second_response = "invalid"
217+
218+
with mock.patch.object(
219+
api_helpers,
220+
"_fetch_with_ratelimit_and_retry",
221+
side_effect=[first_response, second_response],
222+
):
223+
result = api_helpers.get_batch_properties([1, 2], ["MolecularWeight"])
224+
# Should only have data from first page since second page failed
225+
assert 1 in result
226+
assert result[1]["MolecularWeight"] == "100.0"
227+
208228
def test_get_cas_for_cid_success(self):
209229
mock_response = {
210230
"Record": {

tests/test_cheminfo_api_unit.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,3 +392,69 @@ def test_draw_compound_image_request_fails(self):
392392
result = cheminfo_api.draw_compound("caffeine")
393393
assert result is None
394394
mock_print.assert_called()
395+
396+
397+
class TestFetchScalar:
398+
def test_property_with_invalid_type_returns_none(self):
399+
"""Test that properties with invalid types return None."""
400+
with mock.patch.object(
401+
cheminfo_api, "_resolve_to_single_cid", return_value=2519
402+
):
403+
with mock.patch(
404+
"ChemInformant.api_helpers.get_batch_properties",
405+
return_value={2519: {"MolecularWeight": ["invalid", "list"]}},
406+
):
407+
result = cheminfo_api._fetch_scalar(2519, "molecular_weight")
408+
assert result is None
409+
410+
411+
class TestGetSynonyms:
412+
def test_get_synonyms_returns_empty_list_on_not_found(self):
413+
"""Test that get_synonyms returns empty list when compound not found."""
414+
result = cheminfo_api.get_synonyms("nonexistent")
415+
assert result == []
416+
417+
def test_get_synonyms_returns_empty_list_on_ambiguous(self):
418+
"""Test that get_synonyms returns empty list when identifier is ambiguous."""
419+
result = cheminfo_api.get_synonyms("ambiguous")
420+
assert result == []
421+
422+
423+
class TestCompoundModel:
424+
def test_safe_float_handles_invalid_types(self):
425+
"""Test that _safe_float returns None for invalid values."""
426+
# Test with valid values
427+
compound = Compound(
428+
input_identifier="test",
429+
cid="123",
430+
status="OK",
431+
molecular_weight=100.5,
432+
)
433+
assert compound.molecular_weight == 100.5
434+
435+
# Test with None
436+
compound = Compound(
437+
input_identifier="test", cid="123", status="OK", molecular_weight=None
438+
)
439+
assert compound.molecular_weight is None
440+
441+
# Test with empty string
442+
compound = Compound(
443+
input_identifier="test", cid="123", status="OK", molecular_weight=""
444+
)
445+
assert compound.molecular_weight is None
446+
447+
# Test with invalid string (ValueError)
448+
compound = Compound(
449+
input_identifier="test",
450+
cid="123",
451+
status="OK",
452+
molecular_weight="not_a_number",
453+
)
454+
assert compound.molecular_weight is None
455+
456+
# Test with invalid type (TypeError) - using a complex object
457+
compound = Compound(
458+
input_identifier="test", cid="123", status="OK", molecular_weight={"key": "value"}
459+
)
460+
assert compound.molecular_weight is None

0 commit comments

Comments
 (0)