4141#
4242# total number of plot_*.py files in
4343# (examples + examples_rst_index + examples_with_rst + examples_README_header)
44- N_EXAMPLES = 15 + 3 + 2 + 1
45- N_FAILING = 2
44+ N_EXAMPLES = 17 + 3 + 2 + 1
45+ N_FAILING = 4
4646N_GOOD = N_EXAMPLES - N_FAILING # galleries that run w/o error
4747# passthroughs and non-executed examples in
4848# (examples + examples_rst_index + examples_with_rst + examples_README_header)
@@ -193,7 +193,7 @@ def test_junit(sphinx_app, tmp_path):
193193 want = dict (
194194 errors = "0" ,
195195 failures = "0" ,
196- skipped = "2 " ,
196+ skipped = "4 " ,
197197 tests = f"{ N_EXAMPLES } " ,
198198 name = "sphinx-gallery" ,
199199 )
@@ -241,18 +241,42 @@ def test_junit(sphinx_app, tmp_path):
241241 with open (junit_file , "rb" ) as fid :
242242 suite = lxml .etree .fromstring (fid .read ())
243243 # this time we only ran the stale files
244- want .update (failures = "2" , skipped = "1 " , tests = "3 " )
244+ want .update (failures = "2" , skipped = "3 " , tests = "5 " )
245245 got = dict (suite .attrib )
246246 del got ["time" ]
247- assert len (suite ) == 3
248- assert suite [0 ].attrib ["classname" ] == "plot_numpy_matplotlib"
249- assert suite [0 ][0 ].tag == "failure" , suite [0 ].attrib ["classname" ]
250- assert suite [0 ][0 ].attrib ["message" ].startswith ("RuntimeError: Forcing" )
251- assert suite [1 ].attrib ["classname" ] == "plot_scraper_broken"
252- assert suite [1 ][0 ].tag == "skipped" , suite [1 ].attrib ["classname" ]
253- assert suite [2 ].attrib ["classname" ] == "plot_future_imports_broken"
254- assert suite [2 ][0 ].tag == "failure" , suite [2 ].attrib ["classname" ]
255- assert suite [2 ][0 ].attrib ["message" ] == "Passed even though it was marked to fail"
247+ skips_and_fails = [
248+ {
249+ "classname" : "plot_failing_example" ,
250+ "tag" : "skipped" ,
251+ "message" : None ,
252+ },
253+ {
254+ "classname" : "plot_failing_example_thumbnail" ,
255+ "tag" : "skipped" ,
256+ "message" : None ,
257+ },
258+ {
259+ "classname" : "plot_numpy_matplotlib" ,
260+ "tag" : "failure" ,
261+ "message" : "RuntimeError: Forcing" ,
262+ },
263+ {
264+ "classname" : "plot_scraper_broken" ,
265+ "tag" : "skipped" ,
266+ "message" : None ,
267+ },
268+ {
269+ "classname" : "plot_future_imports_broken" ,
270+ "tag" : "failure" ,
271+ "message" : "Passed even though it was marked to fail" ,
272+ },
273+ ]
274+ assert len (suite ) == len (skips_and_fails )
275+ for this_suite , this_example in zip (suite , skips_and_fails ):
276+ assert this_suite .attrib ["classname" ] == this_example ["classname" ]
277+ assert this_suite [0 ].tag == this_example ["tag" ], this_suite .attrib ["classname" ]
278+ if this_example ["message" ] is not None :
279+ assert this_suite [0 ].attrib ["message" ].startswith (this_example ["message" ])
256280 assert got == want
257281
258282
@@ -330,6 +354,47 @@ def test_negative_thumbnail_config(sphinx_app, tmpdir):
330354 assert corr > 0.99
331355
332356
357+ def test_thumbnail_expected_failing_examples (sphinx_app , tmpdir ):
358+ """Test thumbnail behaviour for expected failing examples."""
359+ import numpy as np
360+
361+ # Get the "BROKEN" stamp for the default failing example thumbnail
362+ stamp_fname = op .join (
363+ sphinx_app .srcdir , "_static_nonstandard" , "broken_example.png"
364+ )
365+ stamp_fname_scaled = str (tmpdir .join ("new.png" ))
366+ scale_image (
367+ stamp_fname ,
368+ stamp_fname_scaled ,
369+ * sphinx_app .config .sphinx_gallery_conf ["thumbnail_size" ],
370+ )
371+ Image = _get_image ()
372+ broken_stamp = np .asarray (Image .open (stamp_fname_scaled ))
373+ assert broken_stamp .shape [2 ] in (3 , 4 ) # optipng can strip the alpha channel
374+
375+ # Get thumbnail from example with failing example thumbnail behaviour
376+ # (i.e. thumbnail should be "BROKEN" stamp)
377+ thumb_fname = op .join (
378+ sphinx_app .outdir , "_images" , "sphx_glr_plot_failing_example_thumb.png"
379+ )
380+ thumbnail = np .asarray (Image .open (thumb_fname ))
381+ assert broken_stamp .shape [:2 ] == thumbnail .shape [:2 ]
382+ corr = np .corrcoef (broken_stamp [..., :3 ].ravel (), thumbnail [..., :3 ].ravel ())[0 , 1 ]
383+ assert corr > 0.99 # i.e. thumbnail and "BROKEN" stamp are identical
384+
385+ # Get thumbnail from example with default thumbnail behaviour
386+ # (i.e. thumbnail should be the plot from the example, not the "BROKEN" stamp)
387+ thumb_fname = op .join (
388+ sphinx_app .outdir ,
389+ "_images" ,
390+ "sphx_glr_plot_failing_example_thumbnail_thumb.png" ,
391+ )
392+ thumbnail = np .asarray (Image .open (thumb_fname ))
393+ assert broken_stamp .shape [:2 ] == thumbnail .shape [:2 ]
394+ corr = np .corrcoef (broken_stamp [..., :3 ].ravel (), thumbnail [..., :3 ].ravel ())[0 , 1 ]
395+ assert corr < 0.7 # i.e. thumbnail and "BROKEN" stamp are not identical
396+
397+
333398def test_command_line_args_img (sphinx_app ):
334399 generated_examples_dir = op .join (sphinx_app .outdir , "auto_examples" )
335400 thumb_fname = "../_images/sphx_glr_plot_command_line_args_thumb.png"
@@ -797,6 +862,8 @@ def test_rebuild(tmpdir_factory, sphinx_app):
797862 "sg_api_usage" ,
798863 "plot_future_imports_broken" ,
799864 "plot_scraper_broken" ,
865+ "plot_failing_example" ,
866+ "plot_failing_example_thumbnail" ,
800867 )
801868 _assert_mtimes (generated_rst_0 , generated_rst_1 , ignore = ignore )
802869
@@ -890,6 +957,8 @@ def _rerun(
890957 #
891958 # - auto_examples/future/plot_future_imports_broken
892959 # - auto_examples/future/sg_execution_times
960+ # - auto_examples/plot_failing_example
961+ # - auto_examples/plot_failing_example_thumbnail
893962 # - auto_examples/plot_scraper_broken
894963 # - auto_examples/sg_execution_times
895964 # - auto_examples_rst_index/sg_execution_times
@@ -904,9 +973,9 @@ def _rerun(
904973 # - auto_examples/index
905974 # - auto_examples/plot_numpy_matplotlib
906975 if how == "modify" :
907- n_ch = "([3-9]|10|11)"
976+ n_ch = "([3-9]|1[0-3])" # 3-13
908977 else :
909- n_ch = "[1-9]"
978+ n_ch = "( [1-9]|1[01])" # 1-11
910979 lines = "\n " .join ([f"\n { how } != { n_ch } :" ] + lines )
911980 want = f".*updating environment:.*[0|1] added, { n_ch } changed, 0 removed.*"
912981 assert re .match (want , status , flags ) is not None , lines
@@ -968,6 +1037,8 @@ def _rerun(
9681037 # this one will not change even though it was retried
9691038 "plot_future_imports_broken" ,
9701039 "plot_scraper_broken" ,
1040+ "plot_failing_example" ,
1041+ "plot_failing_example_thumbnail" ,
9711042 )
9721043 # not reliable on Windows and one Ubuntu run
9731044 bad = sys .platform .startswith ("win" ) or os .getenv ("BAD_MTIME" , "0" ) == "1"
@@ -1381,10 +1452,10 @@ def test_recommend_n_examples(sphinx_app):
13811452
13821453 assert '<p class="rubric">Related examples</p>' in html
13831454 assert count == n_examples
1384- # Check the same 3 related examples are shown
1455+ # Check the same 3 related examples are shown (can change when new examples added)
13851456 assert "sphx-glr-auto-examples-plot-repr-py" in html
1386- assert "sphx-glr-auto-examples-plot-webp -py" in html
1387- assert "sphx-glr-auto-examples-plot-numpy-matplotlib -py" in html
1457+ assert "sphx-glr-auto-examples-plot-matplotlib-backend -py" in html
1458+ assert "sphx-glr-auto-examples-plot-second-future-imports -py" in html
13881459
13891460
13901461def test_sidebar_components_download_links (sphinx_app ):
0 commit comments