@@ -499,7 +499,8 @@ def test_path_normalization(mocker, orig_src, orig_img, new_src, new_img):
499499 ),
500500 ],
501501)
502- def test_picture_generation (mocker , orig_tag , new_tag , call_args ):
502+ def test_html_and_pictures_generation (mocker , orig_tag , new_tag , call_args ):
503+ """Tests that the generated html is as expected and the images are processed."""
503504 process = mocker .patch ("pelican.plugins.image_process.image_process.process_image" )
504505
505506 settings = get_settings (
@@ -508,6 +509,8 @@ def test_picture_generation(mocker, orig_tag, new_tag, call_args):
508509
509510 assert harvest_images_in_fragment (orig_tag , settings ) == new_tag
510511
512+ # Check that process_image was called with the expected arguments
513+ # and in the expecter order.
511514 for i , (orig_img , new_img , transform_params ) in enumerate (call_args ):
512515 assert process .mock_calls [i ] == mocker .call (
513516 (
@@ -519,6 +522,140 @@ def test_picture_generation(mocker, orig_tag, new_tag, call_args):
519522 )
520523
521524
525+ @pytest .mark .parametrize (
526+ "orig_tag, new_tag" ,
527+ [
528+ # <img/> src attribute with no quotes, spaces or commas.
529+ (
530+ '<img class="image-process-thumb" src="/tmp/my&_dir/my!_test.jpg" />' ,
531+ '<img class="image-process-thumb" '
532+ 'src="/tmp/my&_dir/derivs/thumb/my!_test.jpg"/>' ,
533+ ),
534+ # <img/> src attribute with double quotes, spaces and commas.
535+ (
536+ '<img class="image-process-thumb" '
537+ 'src="/tmp/my," dir/my "test,.jpg" />' ,
538+ '<img class="image-process-thumb" '
539+ "src='/tmp/my,\" dir/derivs/thumb/my \" test,.jpg'/>" ,
540+ ),
541+ # <img/> src attribute with single and double quotes, spaces and commas.
542+ (
543+ '<img class="image-process-thumb" '
544+ 'src="/tmp/m\' y," dir/my "test,.jpg" />' ,
545+ '<img class="image-process-thumb" '
546+ 'src="/tmp/m\' y," dir/derivs/thumb/my "test,.jpg"/>' ,
547+ ),
548+ # <img/> srcset attribute with no quotes, spaces or commas.
549+ (
550+ '<img class="image-process-crisp" src="/tmp/my&_dir/my!_test.jpg" />' ,
551+ '<img class="image-process-crisp" '
552+ 'src="/tmp/my&_dir/derivs/crisp/1x/my!_test.jpg" '
553+ 'srcset="/tmp/my&_dir/derivs/crisp/1x/my!_test.jpg 1x, '
554+ "/tmp/my&_dir/derivs/crisp/2x/my!_test.jpg 2x, "
555+ '/tmp/my&_dir/derivs/crisp/4x/my!_test.jpg 4x"/>' ,
556+ ),
557+ # <img/> srcset attribute with double quotes, spaces and commas.
558+ (
559+ '<img class="image-process-crisp" '
560+ 'src="/tmp/my," dir/my "test,.jpg" />' ,
561+ '<img class="image-process-crisp" '
562+ "src='/tmp/my,\" dir/derivs/crisp/1x/my \" test,.jpg' "
563+ 'srcset="/tmp/my%2C%22%20dir/derivs/crisp/1x/my%20%22test%2C.jpg 1x, '
564+ "/tmp/my%2C%22%20dir/derivs/crisp/2x/my%20%22test%2C.jpg 2x, "
565+ '/tmp/my%2C%22%20dir/derivs/crisp/4x/my%20%22test%2C.jpg 4x"/>' ,
566+ ),
567+ # <img/> srcset attribute with single and double quotes, spaces and commas.
568+ (
569+ '<img class="image-process-crisp" '
570+ 'src="/tmp/m\' y," dir/my "test,.jpg" />' ,
571+ '<img class="image-process-crisp" '
572+ 'src="/tmp/m\' y," dir/derivs/crisp/1x/my "test,.jpg" '
573+ 'srcset="/tmp/m%27y%2C%22%20dir/derivs/crisp/1x/my%20%22test%2C.jpg 1x, '
574+ "/tmp/m%27y%2C%22%20dir/derivs/crisp/2x/my%20%22test%2C.jpg 2x, "
575+ '/tmp/m%27y%2C%22%20dir/derivs/crisp/4x/my%20%22test%2C.jpg 4x"/>' ,
576+ ),
577+ # <picture/> src and srcset attributes with no quotes, spaces or commas.
578+ (
579+ '<picture><source class="source-1" '
580+ 'src="/my&_dir/my!_pelican-closeup.jpg"/><img '
581+ 'class="image-process-pict" src="/my&_dir/my!_pelican.jpg"/>'
582+ "</picture>" ,
583+ '<picture><source media="(min-width: 640px)" sizes="100vw" '
584+ 'srcset="/my&_dir/derivs/pict/default/640w/'
585+ "my!_pelican.jpg 640w, "
586+ "/my&_dir/derivs/pict/default/1024w/my!_pelican.jpg 1024w, "
587+ '/my&_dir/derivs/pict/default/1600w/my!_pelican.jpg 1600w"/>'
588+ '<source srcset="/my&_dir/derivs/pict/source-1/1x/'
589+ "my!_pelican-closeup.jpg 1x, "
590+ "/my&_dir/derivs/pict/source-1/2x/"
591+ 'my!_pelican-closeup.jpg 2x"/><img '
592+ 'class="image-process-pict" '
593+ 'src="/my&_dir/derivs/pict/default/640w/my!_pelican.jpg"/>'
594+ "</picture>" ,
595+ ),
596+ # <picture/> src and srcset attributes with double quotes, spaces and commas.
597+ (
598+ '<picture><source class="source-1" '
599+ 'src="/my," dir/my "pelican-closeup,.jpg"/><img '
600+ 'class="image-process-pict" src="/my," dir/my "pelican,.jpg"/>'
601+ "</picture>" ,
602+ '<picture><source media="(min-width: 640px)" sizes="100vw" '
603+ 'srcset="/my%2C%22%20dir/derivs/pict/default/640w/'
604+ "my%20%22pelican%2C.jpg 640w, "
605+ "/my%2C%22%20dir/derivs/pict/default/1024w/my%20%22pelican%2C.jpg 1024w, "
606+ '/my%2C%22%20dir/derivs/pict/default/1600w/my%20%22pelican%2C.jpg 1600w"/>'
607+ '<source srcset="/my%2C%22%20dir/derivs/pict/source-1/1x/'
608+ "my%20%22pelican-closeup%2C.jpg 1x, "
609+ "/my%2C%22%20dir/derivs/pict/source-1/2x/"
610+ 'my%20%22pelican-closeup%2C.jpg 2x"/><img '
611+ 'class="image-process-pict" '
612+ "src='/my,\" dir/derivs/pict/default/640w/my \" pelican,.jpg'/>"
613+ "</picture>" ,
614+ ),
615+ # <picture/> src and srcset attributes
616+ # with single and double quotes, spaces and commas.
617+ (
618+ '<picture><source class="source-1" '
619+ 'src="/m\' y," dir/my "pelican-closeup,.jpg"/><img '
620+ 'class="image-process-pict" src="/m\' y," dir/my "pelican,.jpg"/>'
621+ "</picture>" ,
622+ '<picture><source media="(min-width: 640px)" sizes="100vw" '
623+ 'srcset="/m%27y%2C%22%20dir/derivs/pict/default/640w/'
624+ "my%20%22pelican%2C.jpg 640w, "
625+ "/m%27y%2C%22%20dir/derivs/pict/default/1024w/"
626+ "my%20%22pelican%2C.jpg 1024w, "
627+ "/m%27y%2C%22%20dir/derivs/pict/default/1600w/"
628+ 'my%20%22pelican%2C.jpg 1600w"/>'
629+ '<source srcset="/m%27y%2C%22%20dir/derivs/pict/source-1/1x/'
630+ "my%20%22pelican-closeup%2C.jpg 1x, "
631+ "/m%27y%2C%22%20dir/derivs/pict/source-1/2x/"
632+ 'my%20%22pelican-closeup%2C.jpg 2x"/><img '
633+ 'class="image-process-pict" '
634+ 'src="/m\' y," dir/derivs/pict/default/640w/my "pelican,.jpg"/>'
635+ "</picture>" ,
636+ ),
637+ ],
638+ )
639+ def test_special_chars_in_image_path_are_handled_properly (mocker , orig_tag , new_tag ):
640+ """Tests that special characters in image paths are handled properly.
641+
642+ For the src attribute, single or double quotes may need to be escaped,
643+ according to the quotation mark used to enclose the attribute value.
644+
645+ For the srcset attribute, in addition to quotes, spaces and commas
646+ need to be url-encoded.
647+
648+ Related to issue #78 https://github.com/pelican-plugins/image-process/issues/78
649+ """
650+ mocker .patch ("pelican.plugins.image_process.image_process.process_image" )
651+
652+ settings = get_settings (
653+ IMAGE_PROCESS = COMPLEX_TRANSFORMS , IMAGE_PROCESS_DIR = "derivs"
654+ )
655+
656+ assert harvest_images_in_fragment (orig_tag , settings ) == new_tag
657+
658+
522659def process_image_mock_exif_tool_started (image , settings ):
523660 assert ExifTool ._instance is not None
524661
0 commit comments