1111import jakarta .mail .internet .MimeMultipart ;
1212import jakarta .validation .ConstraintViolationException ;
1313import org .jspecify .annotations .NullMarked ;
14+ import org .jspecify .annotations .Nullable ;
1415import org .junit .jupiter .api .BeforeEach ;
1516import org .junit .jupiter .api .Test ;
17+ import org .junit .jupiter .params .ParameterizedTest ;
18+ import org .junit .jupiter .params .provider .CsvSource ;
1619import org .mockito .ArgumentCaptor ;
1720import org .springframework .beans .factory .annotation .Autowired ;
1821import org .springframework .boot .test .context .SpringBootTest ;
@@ -164,25 +167,10 @@ void givenRequiredParameterWithAttachedFiles_sendOrFail_shouldSendImmediately()
164167 void givenInlineAttachment_schedule_shouldPersistContentId () throws EmailException , AttachmentException {
165168 when (attachmentDataSource .storeAttachmentPayload (any ())).thenReturn (33L );
166169
167- var parameter = EmailParameter .builder ()
168- .scheduledAt (OffsetDateTime .now ())
169- .email (EmailParameter .Email .builder ()
170- .subject ("Example email subject" )
171- .textBody ("Email body" )
172- .htmlBody ("<h1>Html email body</h1><img src=\" cid:header-logo\" >" )
173- .recipient ("person1@example.com" )
174- .attachment (
175- EmailParameter .Email .Attachment .builder ()
176- .contentType ("image/png" )
177- .fileName ("logo.png" )
178- .contentId ("header-logo" )
179- .payload (new ByteArrayInputStream (new byte []{1 , 2 , 3 }))
180- .build ()
181- )
182- .fromAddress ("somebody@aboutbits.it" )
183- .fromName ("somebody" )
184- .build ()
185- ).build ();
170+ var parameter = getValidParameterWithInlineAttachment (
171+ "<h1>Html email body</h1><img src=\" cid:header-logo\" >" ,
172+ inlineAttachment ("header-logo" )
173+ );
186174
187175 var result = manageEmail .schedule (parameter );
188176
@@ -198,32 +186,11 @@ void givenInlineAndRegularAttachment_sendOrFail_shouldAddInlineAndRegularMimePar
198186 when (attachmentDataSource .getAttachmentPayload (anyLong ()))
199187 .thenAnswer (_ -> new ByteArrayInputStream (new byte []{1 , 2 , 3 }));
200188
201- var parameter = EmailParameter .builder ()
202- .scheduledAt (OffsetDateTime .now ())
203- .email (EmailParameter .Email .builder ()
204- .subject ("Example email subject" )
205- .textBody ("Email body" )
206- .htmlBody ("<h1>Html email body</h1><img src=\" cid:header-logo\" >" )
207- .recipient ("person1@example.com" )
208- .attachment (
209- EmailParameter .Email .Attachment .builder ()
210- .contentType ("image/png" )
211- .fileName ("logo.png" )
212- .contentId ("header-logo" )
213- .payload (new ByteArrayInputStream (new byte []{1 , 2 , 3 }))
214- .build ()
215- )
216- .attachment (
217- EmailParameter .Email .Attachment .builder ()
218- .contentType ("image/png" )
219- .fileName ("x.png" )
220- .payload (new ByteArrayInputStream (new byte []{1 , 2 , 3 }))
221- .build ()
222- )
223- .fromAddress ("somebody@aboutbits.it" )
224- .fromName ("somebody" )
225- .build ()
226- ).build ();
189+ var parameter = getValidParameterWithInlineAttachment (
190+ "<h1>Html email body</h1><img src=\" cid:header-logo\" >" ,
191+ inlineAttachment ("header-logo" ),
192+ regularAttachment ("x.png" )
193+ );
227194
228195 var result = manageEmail .sendOrFail (parameter );
229196
@@ -244,6 +211,7 @@ void givenInlineAndRegularAttachment_sendOrFail_shouldAddInlineAndRegularMimePar
244211 .orElseThrow ();
245212 assertThat (inlinePart .getContentID ()).isEqualTo ("<header-logo>" );
246213 assertThat (inlinePart .getContentType ()).startsWith ("image/png" );
214+ assertThat (inlinePart .getFileName ()).isEqualTo ("logo.png" );
247215
248216 var attachmentPart = parts .stream ()
249217 .filter (part -> hasDisposition (part , Part .ATTACHMENT ))
@@ -253,80 +221,42 @@ void givenInlineAndRegularAttachment_sendOrFail_shouldAddInlineAndRegularMimePar
253221 }
254222
255223 @ Test
256- void givenInlineAttachmentWithoutHtmlBody_schedule_shouldFail () {
257- var parameter = EmailParameter .builder ()
258- .scheduledAt (OffsetDateTime .now ())
259- .email (EmailParameter .Email .builder ()
260- .subject ("Example email subject" )
261- .textBody ("Email body" )
262- .htmlBody ("" )
263- .recipient ("person1@example.com" )
264- .attachment (
265- EmailParameter .Email .Attachment .builder ()
266- .contentType ("image/png" )
267- .fileName ("logo.png" )
268- .contentId ("header-logo" )
269- .payload (new ByteArrayInputStream (new byte [0 ]))
270- .build ()
271- )
272- .fromAddress ("somebody@aboutbits.it" )
273- .fromName ("somebody" )
274- .build ()
275- ).build ();
224+ void givenUppercaseCidReference_schedule_shouldSucceed () throws EmailException , AttachmentException {
225+ when (attachmentDataSource .storeAttachmentPayload (any ())).thenReturn (33L );
276226
277- assertThatExceptionOfType (ConstraintViolationException .class ).isThrownBy (
278- () -> manageEmail .schedule (parameter )
227+ var parameter = getValidParameterWithInlineAttachment (
228+ "<h1>Html email body</h1><img src=\" CID:header-logo\" >" ,
229+ inlineAttachment ("header-logo" )
279230 );
231+
232+ var result = manageEmail .schedule (parameter );
233+
234+ assertThat (result .state ()).isEqualTo (EmailState .PENDING );
280235 }
281236
282- @ Test
283- void givenContentIdNotReferencedInHtmlBody_schedule_shouldFail () {
284- var parameter = EmailParameter .builder ()
285- .scheduledAt (OffsetDateTime .now ())
286- .email (EmailParameter .Email .builder ()
287- .subject ("Example email subject" )
288- .textBody ("Email body" )
289- .htmlBody ("<h1>Html email body</h1>" )
290- .recipient ("person1@example.com" )
291- .attachment (
292- EmailParameter .Email .Attachment .builder ()
293- .contentType ("image/png" )
294- .fileName ("logo.png" )
295- .contentId ("header-logo" )
296- .payload (new ByteArrayInputStream (new byte [0 ]))
297- .build ()
298- )
299- .fromAddress ("somebody@aboutbits.it" )
300- .fromName ("somebody" )
301- .build ()
302- ).build ();
237+ @ ParameterizedTest
238+ @ CsvSource ({
239+ "'', header-logo" ,
240+ ", header-logo" ,
241+ "<h1>Html email body</h1>, header-logo" ,
242+ "<img src=cid:header-logo-big>, header-logo" ,
243+ "<h1>Html email body</h1>, ' '"
244+ })
245+ void givenInvalidInlineAttachment_schedule_shouldFail (@ Nullable String htmlBody , String contentId ) {
246+ var parameter = getValidParameterWithInlineAttachment (htmlBody , inlineAttachment (contentId ));
303247
304248 assertThatExceptionOfType (ConstraintViolationException .class ).isThrownBy (
305249 () -> manageEmail .schedule (parameter )
306250 );
307251 }
308252
309253 @ Test
310- void givenBlankContentId_schedule_shouldFail () {
311- var parameter = EmailParameter .builder ()
312- .scheduledAt (OffsetDateTime .now ())
313- .email (EmailParameter .Email .builder ()
314- .subject ("Example email subject" )
315- .textBody ("Email body" )
316- .htmlBody ("<h1>Html email body</h1>" )
317- .recipient ("person1@example.com" )
318- .attachment (
319- EmailParameter .Email .Attachment .builder ()
320- .contentType ("image/png" )
321- .fileName ("logo.png" )
322- .contentId (" " )
323- .payload (new ByteArrayInputStream (new byte [0 ]))
324- .build ()
325- )
326- .fromAddress ("somebody@aboutbits.it" )
327- .fromName ("somebody" )
328- .build ()
329- ).build ();
254+ void givenDuplicateContentIds_schedule_shouldFail () {
255+ var parameter = getValidParameterWithInlineAttachment (
256+ "<h1>Html email body</h1><img src=\" cid:header-logo\" >" ,
257+ inlineAttachment ("header-logo" ),
258+ inlineAttachment ("header-logo" , "other.png" )
259+ );
330260
331261 assertThatExceptionOfType (ConstraintViolationException .class ).isThrownBy (
332262 () -> manageEmail .schedule (parameter )
@@ -399,6 +329,51 @@ private static EmailParameter getValidParameterWithAttachment() {
399329 ).build ();
400330 }
401331
332+ private static EmailParameter getValidParameterWithInlineAttachment (
333+ @ Nullable String htmlBody ,
334+ EmailParameter .Email .Attachment ... attachments
335+ ) {
336+ var emailBuilder = EmailParameter .Email .builder ()
337+ .subject ("Example email subject" )
338+ .textBody ("Email body" )
339+ .recipient ("person1@example.com" )
340+ .fromAddress ("somebody@aboutbits.it" )
341+ .fromName ("somebody" );
342+
343+ if (htmlBody != null ) {
344+ emailBuilder .htmlBody (htmlBody );
345+ }
346+ for (var attachment : attachments ) {
347+ emailBuilder .attachment (attachment );
348+ }
349+
350+ return EmailParameter .builder ()
351+ .scheduledAt (OffsetDateTime .now ())
352+ .email (emailBuilder .build ())
353+ .build ();
354+ }
355+
356+ private static EmailParameter .Email .Attachment inlineAttachment (String contentId ) {
357+ return inlineAttachment (contentId , "logo.png" );
358+ }
359+
360+ private static EmailParameter .Email .Attachment inlineAttachment (String contentId , String fileName ) {
361+ return EmailParameter .Email .Attachment .builder ()
362+ .contentType ("image/png" )
363+ .fileName (fileName )
364+ .contentId (contentId )
365+ .payload (new ByteArrayInputStream (new byte []{1 , 2 , 3 }))
366+ .build ();
367+ }
368+
369+ private static EmailParameter .Email .Attachment regularAttachment (String fileName ) {
370+ return EmailParameter .Email .Attachment .builder ()
371+ .contentType ("image/png" )
372+ .fileName (fileName )
373+ .payload (new ByteArrayInputStream (new byte []{1 , 2 , 3 }))
374+ .build ();
375+ }
376+
402377 private static List <MimeBodyPart > flattenParts (Object content ) throws Exception {
403378 var parts = new ArrayList <MimeBodyPart >();
404379 if (content instanceof MimeMultipart multipart ) {
0 commit comments