1414import java .lang .reflect .Field ;
1515import java .lang .reflect .Method ;
1616import java .util .HashMap ;
17+ import java .util .Iterator ;
1718import java .util .Map ;
18- import static org .mockito .Mockito .*;
19+ import java .util .concurrent .atomic .AtomicReference ;
20+
1921@ RunWith (RobolectricTestRunner .class )
2022@ Config (sdk = 28 , manifest = Config .NONE )
2123public class TestContentType {
@@ -336,27 +338,8 @@ private ContentType createBareContentType(String contentTypeUid) {
336338 return new ContentType (contentTypeUid );
337339 }
338340
339- private ContentType createContentTypeWithStackAndHeaders (String contentTypeUid ) throws Exception {
340- ContentType contentType = new ContentType (contentTypeUid );
341-
342- // mock Stack and inject a stackHeader / localHeader field if present
343- Stack mockStack = mock (Stack .class );
344-
345- // We will inject "localHeader" field into Stack if it exists
346- try {
347- Field localHeaderField = Stack .class .getDeclaredField ("localHeader" );
348- localHeaderField .setAccessible (true );
349- ArrayMap <String , Object > stackHeaders = new ArrayMap <>();
350- stackHeaders .put ("environment" , "prod-env" );
351- stackHeaders .put ("stackKey" , "stackVal" );
352- localHeaderField .set (mockStack , stackHeaders );
353- } catch (NoSuchFieldException ignored ) {
354- // If Stack doesn't have localHeader, getHeader will just use localHeader or
355- // null.
356- }
357-
358- contentType .setStackInstance (mockStack );
359- return contentType ;
341+ private ContentType createContentTypeWithStackAndHeaders (String contentTypeUid ) {
342+ return stack .contentType (contentTypeUid );
360343 }
361344
362345 private ArrayMap <String , Object > getLocalHeader (ContentType contentType ) throws Exception {
@@ -484,82 +467,68 @@ public void testQueryHasFormHeaderNonNull() throws Exception {
484467 @ Test
485468 public void testFetchWithEmptyContentTypeNameCallsOnRequestFail () throws Exception {
486469 ContentType contentType = createBareContentType ("" );
487-
488- // make sure stackInstance is not null
489- contentType .setStackInstance (mock (Stack .class ));
490-
491- ContentTypesCallback callback = mock (ContentTypesCallback .class );
470+ contentType .setStackInstance (stack );
471+
472+ final AtomicReference <Error > errorRef = new AtomicReference <>();
473+ ContentTypesCallback callback = new ContentTypesCallback () {
474+ @ Override
475+ public void onCompletion (ContentTypesModel contentTypesModel , Error error ) {
476+ if (error != null ) {
477+ errorRef .set (error );
478+ }
479+ }
480+ };
492481
493482 contentType .fetch (new JSONObject (), callback );
494483
495- verify ( callback ). onRequestFail ( eq ( ResponseType . UNKNOWN ), any ( Error . class ));
484+ assertNotNull ( errorRef . get ( ));
496485 }
497486
498487 @ Test
499488 public void testFetchExceptionCallsOnRequestFail () throws Exception {
500489 ContentType contentType = createBareContentType ("blog" );
501- contentType .setStackInstance (mock ( Stack . class ) );
490+ contentType .setStackInstance (stack );
502491
503- // Force an exception by using bad JSONObject for params
504- JSONObject badParams = mock (JSONObject .class );
505- when (badParams .keys ()).thenThrow (new RuntimeException ("boom" ));
492+ final AtomicReference <Error > errorRef = new AtomicReference <>();
493+ ContentTypesCallback callback = new ContentTypesCallback () {
494+ @ Override
495+ public void onCompletion (ContentTypesModel contentTypesModel , Error error ) {
496+ if (error != null ) {
497+ errorRef .set (error );
498+ }
499+ }
500+ };
506501
507- ContentTypesCallback callback = mock ( ContentTypesCallback . class );
502+ contentType . fetch ( new ThrowingJSONObject (), callback );
508503
509- contentType .fetch (badParams , callback );
510-
511- verify (callback ).onRequestFail (eq (ResponseType .UNKNOWN ), any (Error .class ));
504+ assertNotNull (errorRef .get ());
512505 }
513506
514507 @ Test
515508 public void testFetchNullParamsAndEnvironmentHeader () throws Exception {
516509 ContentType contentType = createBareContentType ("blog" );
510+ contentType .setStackInstance (stack );
517511
518- // Create a fake Stack with environment in its localHeader (so getHeader picks
519- // it)
520- Stack mockStack = mock (Stack .class );
521-
522- // Inject stack.localHeader if it exists
523- try {
524- Field localHeaderField = Stack .class .getDeclaredField ("localHeader" );
525- localHeaderField .setAccessible (true );
526- ArrayMap <String , Object > stackHeaders = new ArrayMap <>();
527- stackHeaders .put ("environment" , "prod-env" );
528- localHeaderField .set (mockStack , stackHeaders );
529- } catch (NoSuchFieldException ignored ) {
530- }
512+ ContentTypesCallback callback = new ContentTypesCallback () {
513+ @ Override
514+ public void onCompletion (ContentTypesModel contentTypesModel , Error error ) {}
515+ };
531516
532- // Inject VERSION field if exists so URL is built properly (not strictly
533- // necessary for coverage)
534- try {
535- Field versionField = Stack .class .getDeclaredField ("VERSION" );
536- versionField .setAccessible (true );
537- versionField .set (mockStack , "v3" );
538- } catch (NoSuchFieldException ignored ) {
539- }
540-
541- contentType .setStackInstance (mockStack );
542-
543- ContentTypesCallback callback = mock (ContentTypesCallback .class );
544-
545- // this will hit:
546- // if (params == null) params = new JSONObject();
547- // then iterate keys (none)
548- // then add environment if headers contains it
549517 contentType .fetch (null , callback );
550-
551- // We don't verify callback interactions here; this is just to cover branches.
552518 }
553519
554520 @ Test
555521 public void testFetchNormalCallDoesNotCrash () throws Exception {
556522 ContentType contentType = createBareContentType ("blog" );
557- contentType .setStackInstance (mock ( Stack . class ) );
523+ contentType .setStackInstance (stack );
558524
559525 JSONObject params = new JSONObject ();
560526 params .put ("limit" , 3 );
561527
562- ContentTypesCallback callback = mock (ContentTypesCallback .class );
528+ ContentTypesCallback callback = new ContentTypesCallback () {
529+ @ Override
530+ public void onCompletion (ContentTypesModel contentTypesModel , Error error ) {}
531+ };
563532
564533 contentType .fetch (params , callback );
565534 }
@@ -593,4 +562,12 @@ public void testGetUrlParamsNullOrEmptyReturnsNull() throws Exception {
593562 HashMap <String , Object > resultEmpty = invokeGetUrlParams (contentType , empty );
594563 assertNull (resultEmpty );
595564 }
565+
566+ /** JSONObject that throws when keys() is called – used to trigger exception path in fetch() without Mockito. */
567+ private static class ThrowingJSONObject extends JSONObject {
568+ @ Override
569+ public Iterator <String > keys () {
570+ throw new RuntimeException ("boom" );
571+ }
572+ }
596573}
0 commit comments