@@ -693,4 +693,243 @@ public void onCompletion(ContentTypesModel model, Error error) {}
693693 assertEquals ("value1" , retrievedNested .get ("key1" ));
694694 assertEquals ("value2" , retrievedNested .get ("key2" ));
695695 }
696+
697+ // ========== EXCEPTION TESTS WITH ERROR MESSAGE ASSERTIONS ==========
698+
699+ @ Test
700+ void testDirectInstantiationThrowsExceptionWithCorrectMessage () {
701+ IllegalAccessException exception = assertThrows (IllegalAccessException .class , () -> {
702+ new ContentType ();
703+ });
704+
705+ assertEquals (ErrorMessages .DIRECT_INSTANTIATION_CONTENT_TYPE , exception .getMessage ());
706+ assertTrue (exception .getMessage ().contains ("Direct instantiation of ContentType is not allowed" ));
707+ assertTrue (exception .getMessage ().contains ("Stack.contentType(uid)" ));
708+ }
709+
710+ @ Test
711+ void testFetchWithNullContentTypeUidThrowsExceptionWithMessage () throws Exception {
712+ Stack stack = Contentstack .stack ("test_api_key" , "test_delivery_token" , "test_env" );
713+
714+ ContentType ctWithNullUid = new ContentType (null );
715+ ctWithNullUid .stackInstance = stack ;
716+ ctWithNullUid .headers = new LinkedHashMap <>();
717+ ctWithNullUid .headers .put ("environment" , "production" );
718+
719+ JSONObject params = new JSONObject ();
720+ ContentTypesCallback callback = new ContentTypesCallback () {
721+ @ Override
722+ public void onCompletion (ContentTypesModel model , Error error ) {}
723+ };
724+
725+ IllegalAccessException exception = assertThrows (IllegalAccessException .class , () -> {
726+ ctWithNullUid .fetch (params , callback );
727+ });
728+
729+ assertEquals (ErrorMessages .CONTENT_TYPE_UID_REQUIRED , exception .getMessage ());
730+ assertTrue (exception .getMessage ().contains ("Content type UID is required" ));
731+ }
732+
733+ @ Test
734+ void testFetchWithEmptyContentTypeUidThrowsExceptionWithMessage () throws Exception {
735+ Stack stack = Contentstack .stack ("test_api_key" , "test_delivery_token" , "test_env" );
736+
737+ ContentType ctWithEmptyUid = new ContentType ("" );
738+ ctWithEmptyUid .stackInstance = stack ;
739+ ctWithEmptyUid .headers = new LinkedHashMap <>();
740+ ctWithEmptyUid .headers .put ("environment" , "production" );
741+
742+ JSONObject params = new JSONObject ();
743+ ContentTypesCallback callback = new ContentTypesCallback () {
744+ @ Override
745+ public void onCompletion (ContentTypesModel model , Error error ) {}
746+ };
747+
748+ IllegalAccessException exception = assertThrows (IllegalAccessException .class , () -> {
749+ ctWithEmptyUid .fetch (params , callback );
750+ });
751+
752+ assertEquals (ErrorMessages .CONTENT_TYPE_UID_REQUIRED , exception .getMessage ());
753+ }
754+
755+ @ Test
756+ void testSetHeaderWithEmptyKeyDoesNotAddHeader () {
757+ int initialSize = contentType .headers .size ();
758+
759+ contentType .setHeader ("" , "some_value" );
760+
761+ // No exception thrown, but header should not be added
762+ assertEquals (initialSize , contentType .headers .size ());
763+ assertFalse (contentType .headers .containsKey ("" ));
764+ }
765+
766+ @ Test
767+ void testSetHeaderWithEmptyValueDoesNotAddHeader () {
768+ int initialSize = contentType .headers .size ();
769+
770+ contentType .setHeader ("some_key" , "" );
771+
772+ // No exception thrown, but header should not be added
773+ assertEquals (initialSize , contentType .headers .size ());
774+ assertFalse (contentType .headers .containsKey ("some_key" ));
775+ }
776+
777+ @ Test
778+ void testSetHeaderWithBothEmptyDoesNotAddHeader () {
779+ int initialSize = contentType .headers .size ();
780+
781+ contentType .setHeader ("" , "" );
782+
783+ // No exception thrown, but header should not be added
784+ assertEquals (initialSize , contentType .headers .size ());
785+ }
786+
787+ @ Test
788+ void testRemoveHeaderWithEmptyKeyDoesNotThrow () {
789+ // Should not throw exception
790+ assertDoesNotThrow (() -> contentType .removeHeader ("" ));
791+ }
792+
793+ @ Test
794+ void testRemoveNonExistentHeaderDoesNotThrow () {
795+ // Should not throw exception
796+ assertDoesNotThrow (() -> contentType .removeHeader ("non_existent_header" ));
797+ }
798+
799+ @ Test
800+ void testFetchWithNullParamsDoesNotThrow () throws Exception {
801+ Stack stack = Contentstack .stack ("test_api_key" , "test_delivery_token" , "test_env" );
802+ contentType .stackInstance = stack ;
803+ contentType .headers = new LinkedHashMap <>();
804+ contentType .headers .put ("environment" , "production" );
805+
806+ ContentTypesCallback callback = new ContentTypesCallback () {
807+ @ Override
808+ public void onCompletion (ContentTypesModel model , Error error ) {}
809+ };
810+
811+ // Even with null params, should handle gracefully (though might fail at network level)
812+ // The method signature requires @NotNull but testing runtime behavior
813+ assertThrows (NullPointerException .class , () -> {
814+ contentType .fetch (null , callback );
815+ });
816+ }
817+
818+ @ Test
819+ void testEntryWithNullUidCreatesEntry () {
820+ // Should create entry even with null UID (validation happens later)
821+ Entry entry = contentType .entry (null );
822+
823+ assertNotNull (entry );
824+ assertNull (entry .uid );
825+ }
826+
827+ @ Test
828+ void testEntryWithEmptyUidCreatesEntry () {
829+ // Should create entry even with empty UID (validation happens later)
830+ Entry entry = contentType .entry ("" );
831+
832+ assertNotNull (entry );
833+ assertEquals ("" , entry .uid );
834+ }
835+
836+ @ Test
837+ void testQueryCreation () {
838+ // Query creation should always succeed
839+ Query query = contentType .query ();
840+
841+ assertNotNull (query );
842+ assertNotNull (query .headers );
843+ assertEquals (contentType .headers , query .headers );
844+ }
845+
846+ @ Test
847+ void testSetContentTypeDataWithNullDoesNotThrow () {
848+ // Should handle null gracefully without throwing
849+ assertDoesNotThrow (() -> contentType .setContentTypeData (null ));
850+
851+ // contentTypeData should remain null
852+ assertNull (contentType .contentTypeData );
853+ }
854+
855+ @ Test
856+ void testSetContentTypeDataWithEmptyJSONObject () {
857+ JSONObject emptyData = new JSONObject ();
858+
859+ assertDoesNotThrow (() -> contentType .setContentTypeData (emptyData ));
860+
861+ // Fields should have default values
862+ assertEquals ("" , contentType .title );
863+ assertEquals ("" , contentType .description );
864+ assertEquals ("" , contentType .uid );
865+ assertNull (contentType .schema );
866+ assertNotNull (contentType .contentTypeData );
867+ }
868+
869+ @ Test
870+ void testSetContentTypeDataPopulatesAllFields () {
871+ JSONObject ctData = new JSONObject ();
872+ ctData .put ("uid" , "test_uid" );
873+ ctData .put ("title" , "Test Title" );
874+ ctData .put ("description" , "Test Description" );
875+
876+ JSONArray schema = new JSONArray ();
877+ JSONObject field = new JSONObject ();
878+ field .put ("uid" , "field_uid" );
879+ field .put ("data_type" , "text" );
880+ schema .put (field );
881+ ctData .put ("schema" , schema );
882+
883+ contentType .setContentTypeData (ctData );
884+
885+ assertEquals ("test_uid" , contentType .uid );
886+ assertEquals ("Test Title" , contentType .title );
887+ assertEquals ("Test Description" , contentType .description );
888+ assertNotNull (contentType .schema );
889+ assertEquals (1 , contentType .schema .length ());
890+ assertEquals ("field_uid" , contentType .schema .getJSONObject (0 ).getString ("uid" ));
891+ assertNotNull (contentType .contentTypeData );
892+ }
893+
894+ @ Test
895+ void testSetContentTypeDataWithMissingOptionalFields () {
896+ JSONObject ctData = new JSONObject ();
897+ ctData .put ("uid" , "minimal_uid" );
898+ // title, description, schema are optional
899+
900+ contentType .setContentTypeData (ctData );
901+
902+ assertEquals ("minimal_uid" , contentType .uid );
903+ assertEquals ("" , contentType .title ); // optString returns ""
904+ assertEquals ("" , contentType .description );
905+ assertNull (contentType .schema ); // optJSONArray returns null
906+ assertNotNull (contentType .contentTypeData );
907+ }
908+
909+ @ Test
910+ void testSetHeaderOverwritesExistingHeader () {
911+ contentType .setHeader ("test_header" , "value1" );
912+ assertEquals ("value1" , contentType .headers .get ("test_header" ));
913+
914+ // Overwrite with new value
915+ contentType .setHeader ("test_header" , "value2" );
916+ assertEquals ("value2" , contentType .headers .get ("test_header" ));
917+
918+ // Headers size should still be 1 (not 2)
919+ long count = contentType .headers .keySet ().stream ()
920+ .filter (key -> key .equals ("test_header" ))
921+ .count ();
922+ assertEquals (1 , count );
923+ }
924+
925+ @ Test
926+ void testStackInstanceSetterAssignsHeaders () throws IllegalAccessException {
927+ Stack newStack = Contentstack .stack ("new_key" , "new_token" , "new_env" );
928+
929+ contentType .setStackInstance (newStack );
930+
931+ assertNotNull (contentType .stackInstance );
932+ assertNotNull (contentType .headers );
933+ assertEquals (newStack .headers , contentType .headers );
934+ }
696935}
0 commit comments