2626import java .io .Reader ;
2727import java .nio .charset .Charset ;
2828import java .nio .charset .StandardCharsets ;
29+ import java .util .Arrays ;
2930import java .util .HashMap ;
3031import java .util .List ;
3132import java .util .Map ;
3233
3334import static org .hamcrest .CoreMatchers .equalTo ;
3435import static org .hamcrest .CoreMatchers .notNullValue ;
3536import static org .hamcrest .MatcherAssert .assertThat ;
37+ import static org .hamcrest .Matchers .containsString ;
3638import static org .hamcrest .Matchers .hasKey ;
39+ import static org .junit .jupiter .api .Assertions .assertThrows ;
3740
3841class PluginModelTests {
3942
@@ -75,14 +78,14 @@ final void testSerialization_empty_plugin_to_YAML() throws JsonGenerationExcepti
7578
7679 final String serialized = mapper .writeValueAsString (pluginModel );
7780
78- InputStream inputStream = PluginModelTests .class .getResourceAsStream ("plugin_model_null .yaml" );
81+ InputStream inputStream = PluginModelTests .class .getResourceAsStream ("plugin_model_with_empty_object .yaml" );
7982
8083 assertThat (serialized , notNullValue ());
81- assertThat (serialized , equalTo (convertInputStreamToString (inputStream )));
84+ assertThat (serialized , equalTo (stripComments ( convertInputStreamToString (inputStream ) )));
8285 }
8386
8487 @ ParameterizedTest
85- @ ValueSource (strings = {"plugin_model_empty.yaml" , "plugin_model_not_present.yaml" , "plugin_model_null .yaml" })
88+ @ ValueSource (strings = {"plugin_model_with_empty_object .yaml" })
8689 final void deserialize_with_empty_inner (final String resourceName ) throws IOException {
8790 final InputStream inputStream = PluginModelTests .class .getResourceAsStream (resourceName );
8891
@@ -94,6 +97,17 @@ final void deserialize_with_empty_inner(final String resourceName) throws IOExce
9497 assertThat (pluginModel .getPluginSettings ().size (), equalTo (0 ));
9598 }
9699
100+ @ Test
101+ final void deserialize_with_no_value_returns_null_settings () throws IOException {
102+ final InputStream inputStream = PluginModelTests .class .getResourceAsStream ("plugin_model_not_present.yaml" );
103+
104+ final ObjectMapper mapper = new ObjectMapper (new YAMLFactory ());
105+
106+ final PluginModel pluginModel = mapper .readValue (inputStream , PluginModel .class );
107+ assertThat (pluginModel .getPluginName (), equalTo ("customPlugin" ));
108+ assertThat (pluginModel .getPluginSettings (), equalTo (null ));
109+ }
110+
97111 @ Test
98112 final void testUsingCustomSerializerWithPluginSettings_noExceptions () throws JsonGenerationException , JsonMappingException , IOException {
99113 final PluginModel pluginModel = new PluginModel ("customPlugin" , validPluginSettings ());
@@ -141,6 +155,116 @@ final void testUsingCustomDeserializer_with_array() throws JsonParseException, J
141155 assertThat (readValue .listOfPlugins .get (1 ).getPluginSettings ().get ("key2" ), equalTo ("value2" ));
142156 }
143157
158+ @ Test
159+ final void testUsingCustomDeserializer_with_array_of_three_preserves_all_entries () throws JsonParseException , JsonMappingException , IOException {
160+ InputStream inputStream = PluginModelTests .class .getResourceAsStream ("/list_of_plugins_multiple_fields.yaml" );
161+
162+ final ObjectMapper mapper = new ObjectMapper (new YAMLFactory ());
163+
164+ final PluginHolder readValue = mapper .readValue (inputStream , PluginHolder .class );
165+ assertThat (readValue , notNullValue ());
166+ assertThat (readValue .listOfPlugins , notNullValue ());
167+ assertThat (readValue .listOfPlugins .size (), equalTo (3 ));
168+ assertThat (readValue .listOfPlugins .get (0 ).getPluginName (), equalTo ("customPluginA" ));
169+ assertThat (readValue .listOfPlugins .get (0 ).getPluginSettings ().get ("key1" ), equalTo ("value1" ));
170+ assertThat (readValue .listOfPlugins .get (1 ).getPluginName (), equalTo ("customPluginB" ));
171+ assertThat (readValue .listOfPlugins .get (1 ).getPluginSettings ().get ("key2" ), equalTo ("value2" ));
172+ assertThat (readValue .listOfPlugins .get (2 ).getPluginName (), equalTo ("customPluginC" ));
173+ assertThat (readValue .listOfPlugins .get (2 ).getPluginSettings ().get ("key3" ), equalTo ("value3" ));
174+ }
175+
176+ @ Test
177+ final void testRoundTrip_withEmptyObject () throws IOException {
178+ final InputStream inputStream = PluginModelTests .class .getResourceAsStream ("plugin_model_with_empty_object.yaml" );
179+ final ObjectMapper mapper = new ObjectMapper (new YAMLFactory ());
180+
181+ final PluginModel pluginModel1 = mapper .readValue (inputStream , PluginModel .class );
182+ assertThat (pluginModel1 .getPluginName (), equalTo ("customPlugin" ));
183+ assertThat (pluginModel1 .getPluginSettings ().size (), equalTo (0 ));
184+
185+ final String serialized = mapper .writeValueAsString (pluginModel1 );
186+ assertThat (serialized .contains ("{}" ), equalTo (true ));
187+
188+ final PluginModel pluginModel2 = mapper .readValue (serialized , PluginModel .class );
189+ assertThat (pluginModel2 .getPluginName (), equalTo ("customPlugin" ));
190+ assertThat (pluginModel2 .getPluginSettings ().size (), equalTo (0 ));
191+ }
192+
193+ @ Test
194+ final void testRoundTrip_withNullValue () throws IOException {
195+ final InputStream inputStream = PluginModelTests .class .getResourceAsStream ("plugin_model_with_null.yaml" );
196+ final ObjectMapper mapper = new ObjectMapper (new YAMLFactory ());
197+
198+ // explicit null input -> deserializes with null settings (preserves null)
199+ final PluginModel pluginModel1 = mapper .readValue (inputStream , PluginModel .class );
200+ assertThat (pluginModel1 .getPluginName (), equalTo ("customPlugin" ));
201+ assertThat (pluginModel1 .getPluginSettings (), equalTo (null ));
202+
203+ // null settings -> serializes back as null (round-trip preserved)
204+ final String serialized = mapper .writeValueAsString (pluginModel1 );
205+ assertThat (serialized .contains ("null" ), equalTo (true ));
206+
207+ final PluginModel pluginModel2 = mapper .readValue (serialized , PluginModel .class );
208+ assertThat (pluginModel2 .getPluginName (), equalTo ("customPlugin" ));
209+ assertThat (pluginModel2 .getPluginSettings (), equalTo (null ));
210+ }
211+
212+ @ Test
213+ final void testRoundTrip_withEmptyValue () throws IOException {
214+ final InputStream inputStream = PluginModelTests .class .getResourceAsStream ("plugin_model_with_empty_value.yaml" );
215+ final ObjectMapper mapper = new ObjectMapper (new YAMLFactory ());
216+
217+ // no-value (customPlugin:) -> same as null -> deserializes with null settings
218+ final PluginModel pluginModel1 = mapper .readValue (inputStream , PluginModel .class );
219+ assertThat (pluginModel1 .getPluginName (), equalTo ("customPlugin" ));
220+ assertThat (pluginModel1 .getPluginSettings (), equalTo (null ));
221+
222+ // null settings -> serializes back as null (round-trip preserved)
223+ final String serialized = mapper .writeValueAsString (pluginModel1 );
224+ assertThat (serialized .contains ("null" ), equalTo (true ));
225+
226+ final PluginModel pluginModel2 = mapper .readValue (serialized , PluginModel .class );
227+ assertThat (pluginModel2 .getPluginName (), equalTo ("customPlugin" ));
228+ assertThat (pluginModel2 .getPluginSettings (), equalTo (null ));
229+ }
230+
231+ @ Test
232+ final void testDeserialize_emptyString_throwsException () throws IOException {
233+ final InputStream inputStream = PluginModelTests .class .getResourceAsStream ("plugin_model_empty_string.yaml" );
234+ final ObjectMapper mapper = new ObjectMapper (new YAMLFactory ());
235+
236+ final JsonMappingException exception = assertThrows (
237+ JsonMappingException .class ,
238+ () -> mapper .readValue (inputStream , PluginModel .class )
239+ );
240+ assertThat (exception .getMessage (), containsString ("Empty string is not allowed" ));
241+ }
242+
243+ @ Test
244+ final void testDeserialize_nonEmptyString_throwsException () throws IOException {
245+ final String yaml = "customPlugin: someStringValue" ;
246+ final ObjectMapper mapper = new ObjectMapper (new YAMLFactory ());
247+
248+ final JsonMappingException exception = assertThrows (
249+ JsonMappingException .class ,
250+ () -> mapper .readValue (yaml , PluginModel .class )
251+ );
252+ assertThat (exception .getMessage (), containsString ("String values not allowed" ));
253+ }
254+
255+ @ ParameterizedTest
256+ @ ValueSource (strings = {"plugin_model_number_value.yaml" , "plugin_model_boolean_value.yaml" , "plugin_model_array_value.yaml" })
257+ final void testDeserialize_invalidTokenType_throwsException (final String resourceName ) throws IOException {
258+ final InputStream inputStream = PluginModelTests .class .getResourceAsStream (resourceName );
259+ final ObjectMapper mapper = new ObjectMapper (new YAMLFactory ());
260+
261+ final JsonMappingException exception = assertThrows (
262+ JsonMappingException .class ,
263+ () -> mapper .readValue (inputStream , PluginModel .class )
264+ );
265+ assertThat (exception .getMessage (), containsString ("Unexpected value for plugin" ));
266+ }
267+
144268 static Map <String , Object > validPluginSettings () {
145269 final Map <String , Object > settings = new HashMap <>();
146270 settings .put ("key1" , "value1" );
@@ -160,4 +284,12 @@ static String convertInputStreamToString(InputStream inputStream) throws IOExcep
160284 return stringBuilder .toString ();
161285 }
162286
287+ static String stripComments (final String content ) {
288+ final String stripped = Arrays .stream (content .split ("\n " ))
289+ .filter (line -> !line .startsWith ("#" ))
290+ .collect (java .util .stream .Collectors .joining ("\n " ))
291+ .replaceAll ("^\n +" , "" );
292+ return content .endsWith ("\n " ) ? stripped + "\n " : stripped ;
293+ }
294+
163295}
0 commit comments