1+ import json
2+
13import pytest
24import requests_mock
35import requests
@@ -93,6 +95,14 @@ def test_get_projects_success_no_elements_key(client, requests_mock):
9395
9496 assert projects == mock_response_data
9597
98+ def test_get_projects_success_unexpected_scalar_response (client , monkeypatch ):
99+ """Tests retrieving projects when the API returns a scalar value."""
100+ monkeypatch .setattr (client , "_request" , lambda ** kwargs : "unexpected" )
101+
102+ projects = client .get_projects ()
103+
104+ assert projects == []
105+
96106def test_get_projects_auth_error (client , requests_mock ):
97107 """Tests authentication error during get_projects."""
98108 mock_url = f"{ TEST_BASE_URL } /projects"
@@ -165,6 +175,17 @@ def test_create_project_api_error(client, requests_mock):
165175 with pytest .raises (SysMLV2APIError , match = "Unexpected status code for POST /projects" ):
166176 client .create_project (request_data )
167177
178+ def test_delete_project_success (client , requests_mock ):
179+ """Tests successfully deleting a project."""
180+ mock_url = f"{ TEST_BASE_URL } /projects/{ TEST_PROJECT_ID } "
181+ requests_mock .delete (mock_url , json = {}, status_code = 200 )
182+
183+ result = client .delete_project (TEST_PROJECT_ID )
184+
185+ assert result == {}
186+ assert requests_mock .last_request .url == mock_url
187+ assert requests_mock .last_request .method == "DELETE"
188+
168189
169190# --- Test Get Element ---
170191
@@ -229,6 +250,24 @@ def test_get_owned_elements_empty(client, requests_mock):
229250
230251 assert owned_elements == []
231252
253+ def test_get_owned_elements_success_list_response (client , requests_mock ):
254+ """Tests retrieving owned elements when the API returns a bare list."""
255+ mock_url = f"{ TEST_BASE_URL } /projects/{ TEST_PROJECT_ID } /commits/{ TEST_COMMIT_ID } /elements/{ TEST_ELEMENT_ID } /owned"
256+ mock_response_data = [{"id" : "owned_elem_1" }]
257+ requests_mock .get (mock_url , json = mock_response_data , status_code = 200 )
258+
259+ owned_elements = client .get_owned_elements (TEST_PROJECT_ID , TEST_ELEMENT_ID , TEST_COMMIT_ID )
260+
261+ assert owned_elements == mock_response_data
262+
263+ def test_get_owned_elements_success_unexpected_scalar_response (client , monkeypatch ):
264+ """Tests retrieving owned elements when the API returns a scalar value."""
265+ monkeypatch .setattr (client , "_request" , lambda ** kwargs : "unexpected" )
266+
267+ owned_elements = client .get_owned_elements (TEST_PROJECT_ID , TEST_ELEMENT_ID , TEST_COMMIT_ID )
268+
269+ assert owned_elements == []
270+
232271# --- Test Create Commit ---
233272
234273def test_create_commit_success (client , requests_mock ):
@@ -378,6 +417,14 @@ def test_list_commits_success_dict_response(client, requests_mock):
378417
379418 assert commits == mock_response_data ["elements" ]
380419
420+ def test_list_commits_success_unexpected_scalar_response (client , monkeypatch ):
421+ """Tests listing commits when the API returns a scalar value."""
422+ monkeypatch .setattr (client , "_request" , lambda ** kwargs : "unexpected" )
423+
424+ commits = client .list_commits (TEST_PROJECT_ID )
425+
426+ assert commits == []
427+
381428def test_list_commits_project_not_found (client , requests_mock ):
382429 """Tests 404 when listing commits for a non-existent project."""
383430 mock_url = f"{ TEST_BASE_URL } /projects/invalid_project/commits"
@@ -398,6 +445,18 @@ def test_list_branches_success(client, requests_mock):
398445 branches = client .list_branches (TEST_PROJECT_ID )
399446 assert branches == mock_response
400447
448+ def test_list_branches_success_dict_response (client , requests_mock ):
449+ mock_url = f"{ TEST_BASE_URL } /projects/{ TEST_PROJECT_ID } /branches"
450+ mock_response = {"elements" : [{"id" : TEST_BRANCH_ID , "name" : "develop" }]}
451+ requests_mock .get (mock_url , json = mock_response , status_code = 200 )
452+ branches = client .list_branches (TEST_PROJECT_ID )
453+ assert branches == mock_response ["elements" ]
454+
455+ def test_list_branches_success_unexpected_scalar_response (client , monkeypatch ):
456+ monkeypatch .setattr (client , "_request" , lambda ** kwargs : "unexpected" )
457+ branches = client .list_branches (TEST_PROJECT_ID )
458+ assert branches == []
459+
401460def test_create_branch_success (client , requests_mock ):
402461 mock_url = f"{ TEST_BASE_URL } /projects/{ TEST_PROJECT_ID } /branches"
403462 request_data = {"name" : "feature-branch" , "head" : {"@id" : TEST_COMMIT_ID }}
@@ -438,6 +497,18 @@ def test_list_tags_success(client, requests_mock):
438497 tags = client .list_tags (TEST_PROJECT_ID )
439498 assert tags == mock_response
440499
500+ def test_list_tags_success_dict_response (client , requests_mock ):
501+ mock_url = f"{ TEST_BASE_URL } /projects/{ TEST_PROJECT_ID } /tags"
502+ mock_response = {"elements" : [{"id" : TEST_TAG_ID , "name" : "v1.0" }]}
503+ requests_mock .get (mock_url , json = mock_response , status_code = 200 )
504+ tags = client .list_tags (TEST_PROJECT_ID )
505+ assert tags == mock_response ["elements" ]
506+
507+ def test_list_tags_success_unexpected_scalar_response (client , monkeypatch ):
508+ monkeypatch .setattr (client , "_request" , lambda ** kwargs : "unexpected" )
509+ tags = client .list_tags (TEST_PROJECT_ID )
510+ assert tags == []
511+
441512def test_create_tag_success (client , requests_mock ):
442513 mock_url = f"{ TEST_BASE_URL } /projects/{ TEST_PROJECT_ID } /tags"
443514 request_data = {"name" : "v1.0-release" , "taggedCommit" : {"@id" : TEST_COMMIT_ID }}
@@ -484,6 +555,20 @@ def test_list_elements_commit_not_found(client, requests_mock):
484555 with pytest .raises (SysMLV2NotFoundError ):
485556 client .list_elements (TEST_PROJECT_ID , "invalid_commit" )
486557
558+ def test_list_elements_success_dict_response (client , requests_mock ):
559+ """Tests listing elements when the API returns a dict with 'elements'."""
560+ mock_url = f"{ TEST_BASE_URL } /projects/{ TEST_PROJECT_ID } /commits/{ TEST_COMMIT_ID } /elements"
561+ mock_response_data = {"elements" : [{"id" : "elem1" }, {"id" : "elem2" }]}
562+ requests_mock .get (mock_url , json = mock_response_data , status_code = 200 )
563+ elements = client .list_elements (TEST_PROJECT_ID , TEST_COMMIT_ID )
564+ assert elements == mock_response_data ["elements" ]
565+
566+ def test_list_elements_success_unexpected_scalar_response (client , monkeypatch ):
567+ """Tests listing elements when the API returns a scalar value."""
568+ monkeypatch .setattr (client , "_request" , lambda ** kwargs : "unexpected" )
569+ elements = client .list_elements (TEST_PROJECT_ID , TEST_COMMIT_ID )
570+ assert elements == []
571+
487572
488573# --- Test List Relationships ---
489574
@@ -510,3 +595,62 @@ def test_list_relationships_element_not_found(client, requests_mock):
510595 requests_mock .get (mock_url , status_code = 404 )
511596 with pytest .raises (SysMLV2NotFoundError ):
512597 client .list_relationships (TEST_PROJECT_ID , "invalid_element" , TEST_COMMIT_ID )
598+
599+ def test_list_relationships_success_dict_response (client , requests_mock ):
600+ """Tests listing relationships when the API returns a dict with 'elements'."""
601+ mock_url = f"{ TEST_BASE_URL } /projects/{ TEST_PROJECT_ID } /commits/{ TEST_COMMIT_ID } /elements/{ TEST_ELEMENT_ID } /relationships?direction=both"
602+ mock_response_data = {"elements" : [{"id" : "rel1" }]}
603+ requests_mock .get (mock_url , json = mock_response_data , status_code = 200 )
604+ relationships = client .list_relationships (TEST_PROJECT_ID , TEST_ELEMENT_ID , TEST_COMMIT_ID )
605+ assert relationships == mock_response_data ["elements" ]
606+
607+ def test_list_relationships_success_unexpected_scalar_response (client , monkeypatch ):
608+ """Tests listing relationships when the API returns a scalar value."""
609+ monkeypatch .setattr (client , "_request" , lambda ** kwargs : "unexpected" )
610+ relationships = client .list_relationships (TEST_PROJECT_ID , TEST_ELEMENT_ID , TEST_COMMIT_ID )
611+ assert relationships == []
612+
613+
614+ # --- Test _request Edge Cases ---
615+
616+ def test_request_bad_request_uses_text_when_json_decode_fails (client , monkeypatch ):
617+ """Tests 400 handling falls back to response text when JSON decoding fails."""
618+
619+ class FakeResponse :
620+ status_code = 400
621+ text = "plain error text"
622+ content = b"plain error text"
623+
624+ def json (self ):
625+ raise json .JSONDecodeError ("Expecting value" , "plain error text" , 0 )
626+
627+ monkeypatch .setattr (client ._session , "request" , lambda ** kwargs : FakeResponse ())
628+
629+ with pytest .raises (SysMLV2BadRequestError , match = "plain error text" ):
630+ client ._request (method = "GET" , endpoint = "/projects" )
631+
632+ def test_request_network_error_wrapped (client , monkeypatch ):
633+ """Tests request-layer network exceptions are wrapped in SysMLV2Error."""
634+ def raise_request_exception (** kwargs ):
635+ raise requests .exceptions .ConnectionError ("connection dropped" )
636+
637+ monkeypatch .setattr (client ._session , "request" , raise_request_exception )
638+
639+ with pytest .raises (SysMLV2Error , match = "Network error during request" ):
640+ client ._request (method = "GET" , endpoint = "/projects" )
641+
642+ def test_request_success_json_decode_error_wrapped (client , monkeypatch ):
643+ """Tests invalid JSON on a successful response is wrapped in SysMLV2Error."""
644+
645+ class FakeResponse :
646+ status_code = 200
647+ text = "not json"
648+ content = b"not json"
649+
650+ def json (self ):
651+ raise json .JSONDecodeError ("Expecting value" , "not json" , 0 )
652+
653+ monkeypatch .setattr (client ._session , "request" , lambda ** kwargs : FakeResponse ())
654+
655+ with pytest .raises (SysMLV2Error , match = "Failed to decode JSON response" ):
656+ client ._request (method = "GET" , endpoint = "/projects" )
0 commit comments