\ No newline at end of file
diff --git a/tests/test_exercise_references/_enum_numref_notitle.sphinx8.1.html b/tests/test_exercise_references/_enum_numref_notitle.sphinx8.1.html
new file mode 100644
index 0000000..eb699a4
--- /dev/null
+++ b/tests/test_exercise_references/_enum_numref_notitle.sphinx8.1.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/tests/test_exercise_references/_enum_numref_placeholders.sphinx8.1.html b/tests/test_exercise_references/_enum_numref_placeholders.sphinx8.1.html
new file mode 100644
index 0000000..9bc2e26
--- /dev/null
+++ b/tests/test_exercise_references/_enum_numref_placeholders.sphinx8.1.html
@@ -0,0 +1,12 @@
+
\ No newline at end of file
diff --git a/tests/test_exercise_references/_enum_numref_title.sphinx8.1.html b/tests/test_exercise_references/_enum_numref_title.sphinx8.1.html
new file mode 100644
index 0000000..e3e637c
--- /dev/null
+++ b/tests/test_exercise_references/_enum_numref_title.sphinx8.1.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/tests/test_exercise_references/_enum_ref_mathtitle.sphinx8.1.html b/tests/test_exercise_references/_enum_ref_mathtitle.sphinx8.1.html
new file mode 100644
index 0000000..e12e85d
--- /dev/null
+++ b/tests/test_exercise_references/_enum_ref_mathtitle.sphinx8.1.html
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/tests/test_exercise_references/_enum_ref_notitle.sphinx8.1.html b/tests/test_exercise_references/_enum_ref_notitle.sphinx8.1.html
new file mode 100644
index 0000000..2f1474c
--- /dev/null
+++ b/tests/test_exercise_references/_enum_ref_notitle.sphinx8.1.html
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/tests/test_exercise_references/_enum_ref_title.sphinx8.1.html b/tests/test_exercise_references/_enum_ref_title.sphinx8.1.html
new file mode 100644
index 0000000..53e83f8
--- /dev/null
+++ b/tests/test_exercise_references/_enum_ref_title.sphinx8.1.html
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/tests/test_exercise_references/_unenum_numref_mathtitle.sphinx8.1.html b/tests/test_exercise_references/_unenum_numref_mathtitle.sphinx8.1.html
new file mode 100644
index 0000000..0773678
--- /dev/null
+++ b/tests/test_exercise_references/_unenum_numref_mathtitle.sphinx8.1.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/tests/test_exercise_references/_unenum_numref_notitle.sphinx8.1.html b/tests/test_exercise_references/_unenum_numref_notitle.sphinx8.1.html
new file mode 100644
index 0000000..a7329f2
--- /dev/null
+++ b/tests/test_exercise_references/_unenum_numref_notitle.sphinx8.1.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/tests/test_exercise_references/_unenum_numref_title.sphinx8.1.html b/tests/test_exercise_references/_unenum_numref_title.sphinx8.1.html
new file mode 100644
index 0000000..25c62f2
--- /dev/null
+++ b/tests/test_exercise_references/_unenum_numref_title.sphinx8.1.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/tests/test_exercise_references/_unenum_ref_mathtitle.sphinx8.1.html b/tests/test_exercise_references/_unenum_ref_mathtitle.sphinx8.1.html
new file mode 100644
index 0000000..3a9cdc0
--- /dev/null
+++ b/tests/test_exercise_references/_unenum_ref_mathtitle.sphinx8.1.html
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/tests/test_exercise_references/_unenum_ref_notitle.sphinx8.1.html b/tests/test_exercise_references/_unenum_ref_notitle.sphinx8.1.html
new file mode 100644
index 0000000..9678f3d
--- /dev/null
+++ b/tests/test_exercise_references/_unenum_ref_notitle.sphinx8.1.html
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/tests/test_exercise_references/_unenum_ref_title.sphinx8.1.html b/tests/test_exercise_references/_unenum_ref_title.sphinx8.1.html
new file mode 100644
index 0000000..f9e2427
--- /dev/null
+++ b/tests/test_exercise_references/_unenum_ref_title.sphinx8.1.html
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/tests/test_gateddirective.py b/tests/test_gateddirective.py
index 8edbe70..7e3e180 100644
--- a/tests/test_gateddirective.py
+++ b/tests/test_gateddirective.py
@@ -17,7 +17,12 @@ def strip_escseq(text: str) -> str:
return re.sub(r"\x1b\[[0-9;]*m", "", text)
-SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}"
+# Sphinx 8.1.x (Python 3.10 only) has different XML output than 8.2+
+# Use .sphinx8.1 for 8.1.x, .sphinx8 for 8.2+ (the standard)
+if sphinx.version_info[0] == 8 and sphinx.version_info[1] == 1:
+ SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}.{sphinx.version_info[1]}"
+else:
+ SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}"
@pytest.mark.sphinx("html", testroot="gateddirective")
diff --git a/tests/test_gateddirective/exercise-gated-0.sphinx8.1.html b/tests/test_gateddirective/exercise-gated-0.sphinx8.1.html
new file mode 100644
index 0000000..efd2440
--- /dev/null
+++ b/tests/test_gateddirective/exercise-gated-0.sphinx8.1.html
@@ -0,0 +1,9 @@
+
+
Exercise 3
+
+
Replicate this figure using matplotlib
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/test_gateddirective/exercise-gated-1.sphinx8.1.html b/tests/test_gateddirective/exercise-gated-1.sphinx8.1.html
new file mode 100644
index 0000000..bded47e
--- /dev/null
+++ b/tests/test_gateddirective/exercise-gated-1.sphinx8.1.html
@@ -0,0 +1,8 @@
+
+
Exercise 4 (Replicate Matplotlib Plot)
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/test_gateddirective/exercise-gated.sphinx8.1.xml b/tests/test_gateddirective/exercise-gated.sphinx8.1.xml
new file mode 100644
index 0000000..40285bf
--- /dev/null
+++ b/tests/test_gateddirective/exercise-gated.sphinx8.1.xml
@@ -0,0 +1,24 @@
+
+
+
+ Gated Exercises
+
+ Some Gated reference exercises
+
+
+ Exercise
+
+
+ Replicate this figure using matplotlib
+
+
+
+ and another version with a title embedded
+
+
+ Exercise
+
+ Replicate Matplotlib Plot
+
+
+
diff --git a/tests/test_gateddirective/solution-exercise-0.sphinx8.1.html b/tests/test_gateddirective/solution-exercise-0.sphinx8.1.html
new file mode 100644
index 0000000..609f4a5
--- /dev/null
+++ b/tests/test_gateddirective/solution-exercise-0.sphinx8.1.html
@@ -0,0 +1,43 @@
+
importnumpyasnp
+importmatplotlib.pyplotasplt
+
+# Fixing random state for reproducibility
+np.random.seed(19680801)
+
+dt=0.01
+t=np.arange(0,30,dt)
+nse1=np.random.randn(len(t))# white noise 1
+nse2=np.random.randn(len(t))# white noise 2
+
+# Two signals with a coherent part at 10Hz and a random part
+s1=np.sin(2*np.pi*10*t)+nse1
+s2=np.sin(2*np.pi*10*t)+nse2
+
+fig,axs=plt.subplots(2,1)
+axs[0].plot(t,s1,t,s2)
+axs[0].set_xlim(0,2)
+axs[0].set_xlabel('time')
+axs[0].set_ylabel('s1 and s2')
+axs[0].grid(True)
+
+cxy,f=axs[1].cohere(s1,s2,NFFT=256,Fs=1./dt)
+axs[1].set_ylabel('coherence')
+
+fig.tight_layout()
+plt.show()
+
+
+
+
+
+
+
+
With some follow up text to the solution
+
+
\ No newline at end of file
diff --git a/tests/test_gateddirective/solution-exercise-1.sphinx8.1.html b/tests/test_gateddirective/solution-exercise-1.sphinx8.1.html
new file mode 100644
index 0000000..912e9fe
--- /dev/null
+++ b/tests/test_gateddirective/solution-exercise-1.sphinx8.1.html
@@ -0,0 +1,43 @@
+
importnumpyasnp
+importmatplotlib.pyplotasplt
+
+# Fixing random state for reproducibility
+np.random.seed(19680801)
+
+dt=0.01
+t=np.arange(0,30,dt)
+nse1=np.random.randn(len(t))# white noise 1
+nse2=np.random.randn(len(t))# white noise 2
+
+# Two signals with a coherent part at 10Hz and a random part
+s1=np.sin(2*np.pi*10*t)+nse1
+s2=np.sin(2*np.pi*10*t)+nse2
+
+fig,axs=plt.subplots(2,1)
+axs[0].plot(t,s1,t,s2)
+axs[0].set_xlim(0,2)
+axs[0].set_xlabel('time')
+axs[0].set_ylabel('s1 and s2')
+axs[0].grid(True)
+
+cxy,f=axs[1].cohere(s1,s2,NFFT=256,Fs=1./dt)
+axs[1].set_ylabel('coherence')
+
+fig.tight_layout()
+plt.show()
+
+
+
+
+
+
+
+
With some follow up text to the solution
+
+
\ No newline at end of file
diff --git a/tests/test_gateddirective/solution-exercise-gated-0.sphinx8.1.html b/tests/test_gateddirective/solution-exercise-gated-0.sphinx8.1.html
new file mode 100644
index 0000000..cb426ea
--- /dev/null
+++ b/tests/test_gateddirective/solution-exercise-gated-0.sphinx8.1.html
@@ -0,0 +1,43 @@
+
importnumpyasnp
+importmatplotlib.pyplotasplt
+
+# Fixing random state for reproducibility
+np.random.seed(19680801)
+
+dt=0.01
+t=np.arange(0,30,dt)
+nse1=np.random.randn(len(t))# white noise 1
+nse2=np.random.randn(len(t))# white noise 2
+
+# Two signals with a coherent part at 10Hz and a random part
+s1=np.sin(2*np.pi*10*t)+nse1
+s2=np.sin(2*np.pi*10*t)+nse2
+
+fig,axs=plt.subplots(2,1)
+axs[0].plot(t,s1,t,s2)
+axs[0].set_xlim(0,2)
+axs[0].set_xlabel('time')
+axs[0].set_ylabel('s1 and s2')
+axs[0].grid(True)
+
+cxy,f=axs[1].cohere(s1,s2,NFFT=256,Fs=1./dt)
+axs[1].set_ylabel('coherence')
+
+fig.tight_layout()
+plt.show()
+
+
+
+
+
+
+
+
With some follow up text to the solution
+
+
\ No newline at end of file
diff --git a/tests/test_gateddirective/solution-exercise-gated-1.sphinx8.1.html b/tests/test_gateddirective/solution-exercise-gated-1.sphinx8.1.html
new file mode 100644
index 0000000..76bf8b2
--- /dev/null
+++ b/tests/test_gateddirective/solution-exercise-gated-1.sphinx8.1.html
@@ -0,0 +1,43 @@
+
importnumpyasnp
+importmatplotlib.pyplotasplt
+
+# Fixing random state for reproducibility
+np.random.seed(19680801)
+
+dt=0.01
+t=np.arange(0,30,dt)
+nse1=np.random.randn(len(t))# white noise 1
+nse2=np.random.randn(len(t))# white noise 2
+
+# Two signals with a coherent part at 10Hz and a random part
+s1=np.sin(2*np.pi*10*t)+nse1
+s2=np.sin(2*np.pi*10*t)+nse2
+
+fig,axs=plt.subplots(2,1)
+axs[0].plot(t,s1,t,s2)
+axs[0].set_xlim(0,2)
+axs[0].set_xlabel('time')
+axs[0].set_ylabel('s1 and s2')
+axs[0].grid(True)
+
+cxy,f=axs[1].cohere(s1,s2,NFFT=256,Fs=1./dt)
+axs[1].set_ylabel('coherence')
+
+fig.tight_layout()
+plt.show()
+
+
+
+
+
+
+
+
With some follow up text to the solution
+
+
\ No newline at end of file
diff --git a/tests/test_gateddirective/solution-exercise-gated.sphinx8.1.xml b/tests/test_gateddirective/solution-exercise-gated.sphinx8.1.xml
new file mode 100644
index 0000000..87e88a5
--- /dev/null
+++ b/tests/test_gateddirective/solution-exercise-gated.sphinx8.1.xml
@@ -0,0 +1,111 @@
+
+
+
+ Gated Solutions to exercise-gated.md
+
+ A solution using the gated directive
+
+
+ Solution to
+
+
+ This is a solution to Gated Exercise 1
+
+
+
+ import numpy as np
+ import matplotlib.pyplot as plt
+
+ # Fixing random state for reproducibility
+ np.random.seed(19680801)
+
+ dt = 0.01
+ t = np.arange(0, 30, dt)
+ nse1 = np.random.randn(len(t)) # white noise 1
+ nse2 = np.random.randn(len(t)) # white noise 2
+
+ # Two signals with a coherent part at 10Hz and a random part
+ s1 = np.sin(2 * np.pi * 10 * t) + nse1
+ s2 = np.sin(2 * np.pi * 10 * t) + nse2
+
+ fig, axs = plt.subplots(2, 1)
+ axs[0].plot(t, s1, t, s2)
+ axs[0].set_xlim(0, 2)
+ axs[0].set_xlabel('time')
+ axs[0].set_ylabel('s1 and s2')
+ axs[0].grid(True)
+
+ cxy, f = axs[1].cohere(s1, s2, NFFT=256, Fs=1. / dt)
+ axs[1].set_ylabel('coherence')
+
+ fig.tight_layout()
+ plt.show()
+
+
+
+
+
+
+
+
+ With some follow up text to the solution
+
+ and then a solution to
+
+
+ gated-exercise-2
+
+ A solution using the gated directive
+
+
+ Solution to
+
+
+ This is a solution to Gated Exercise 2
+
+
+
+ import numpy as np
+ import matplotlib.pyplot as plt
+
+ # Fixing random state for reproducibility
+ np.random.seed(19680801)
+
+ dt = 0.01
+ t = np.arange(0, 30, dt)
+ nse1 = np.random.randn(len(t)) # white noise 1
+ nse2 = np.random.randn(len(t)) # white noise 2
+
+ # Two signals with a coherent part at 10Hz and a random part
+ s1 = np.sin(2 * np.pi * 10 * t) + nse1
+ s2 = np.sin(2 * np.pi * 10 * t) + nse2
+
+ fig, axs = plt.subplots(2, 1)
+ axs[0].plot(t, s1, t, s2)
+ axs[0].set_xlim(0, 2)
+ axs[0].set_xlabel('time')
+ axs[0].set_ylabel('s1 and s2')
+ axs[0].grid(True)
+
+ cxy, f = axs[1].cohere(s1, s2, NFFT=256, Fs=1. / dt)
+ axs[1].set_ylabel('coherence')
+
+ fig.tight_layout()
+ plt.show()
+
+
+
+
+
+
+
+
+ With some follow up text to the solution
+
+
+ References to Solutions
+
+ This is a reference to
+
+
+ gated-exercise-solution-1
diff --git a/tests/test_gateddirective/solution-exercise.sphinx8.1.xml b/tests/test_gateddirective/solution-exercise.sphinx8.1.xml
new file mode 100644
index 0000000..29cd9d9
--- /dev/null
+++ b/tests/test_gateddirective/solution-exercise.sphinx8.1.xml
@@ -0,0 +1,114 @@
+
+
+
+ Gated Solutions to exercise.md
+
+ A solution using the gated directive
+
+
+ Solution to
+
+
+ This is a solution to Non-Gated Exercise 1
+
+
+
+ import numpy as np
+ import matplotlib.pyplot as plt
+
+ # Fixing random state for reproducibility
+ np.random.seed(19680801)
+
+ dt = 0.01
+ t = np.arange(0, 30, dt)
+ nse1 = np.random.randn(len(t)) # white noise 1
+ nse2 = np.random.randn(len(t)) # white noise 2
+
+ # Two signals with a coherent part at 10Hz and a random part
+ s1 = np.sin(2 * np.pi * 10 * t) + nse1
+ s2 = np.sin(2 * np.pi * 10 * t) + nse2
+
+ fig, axs = plt.subplots(2, 1)
+ axs[0].plot(t, s1, t, s2)
+ axs[0].set_xlim(0, 2)
+ axs[0].set_xlabel('time')
+ axs[0].set_ylabel('s1 and s2')
+ axs[0].grid(True)
+
+ cxy, f = axs[1].cohere(s1, s2, NFFT=256, Fs=1. / dt)
+ axs[1].set_ylabel('coherence')
+
+ fig.tight_layout()
+ plt.show()
+
+
+
+
+
+
+
+
+ With some follow up text to the solution
+
+ and a solution to
+
+
+ exercise-2
+
+
+ Solution to
+
+
+ This is a solution to Non-Gated Exercise 1
+
+
+
+ import numpy as np
+ import matplotlib.pyplot as plt
+
+ # Fixing random state for reproducibility
+ np.random.seed(19680801)
+
+ dt = 0.01
+ t = np.arange(0, 30, dt)
+ nse1 = np.random.randn(len(t)) # white noise 1
+ nse2 = np.random.randn(len(t)) # white noise 2
+
+ # Two signals with a coherent part at 10Hz and a random part
+ s1 = np.sin(2 * np.pi * 10 * t) + nse1
+ s2 = np.sin(2 * np.pi * 10 * t) + nse2
+
+ fig, axs = plt.subplots(2, 1)
+ axs[0].plot(t, s1, t, s2)
+ axs[0].set_xlim(0, 2)
+ axs[0].set_xlabel('time')
+ axs[0].set_ylabel('s1 and s2')
+ axs[0].grid(True)
+
+ cxy, f = axs[1].cohere(s1, s2, NFFT=256, Fs=1. / dt)
+ axs[1].set_ylabel('coherence')
+
+ fig.tight_layout()
+ plt.show()
+
+
+
+
+
+
+
+
+ With some follow up text to the solution
+
+
+ References
+
+ This is a reference to
+
+
+ solution-gated-1
+
+ This is a reference to
+
+
+ solution-gated-2
diff --git a/tests/test_latex.py b/tests/test_latex.py
index 368d964..e29b5bc 100644
--- a/tests/test_latex.py
+++ b/tests/test_latex.py
@@ -2,7 +2,12 @@
import pytest
import sphinx
-SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}"
+# Sphinx 8.1.x (Python 3.10 only) has different XML output than 8.2+
+# Use .sphinx8.1 for 8.1.x, .sphinx8 for 8.2+ (the standard)
+if sphinx.version_info[0] == 8 and sphinx.version_info[1] == 1:
+ SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}.{sphinx.version_info[1]}"
+else:
+ SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}"
@pytest.mark.sphinx("latex", testroot="simplebook")
diff --git a/tests/test_latex/test_latex_build.sphinx8.1.tex b/tests/test_latex/test_latex_build.sphinx8.1.tex
new file mode 100644
index 0000000..f6293f6
--- /dev/null
+++ b/tests/test_latex/test_latex_build.sphinx8.1.tex
@@ -0,0 +1,181 @@
+\begin{document}
+
+\ifdefined\shorthandoff
+ \ifnum\catcode`\=\string=\active\shorthandoff{=}\fi
+ \ifnum\catcode`\"=\active\shorthandoff{"}\fi
+\fi
+
+\pagestyle{empty}
+\sphinxmaketitle
+\pagestyle{plain}
+\sphinxtableofcontents
+\pagestyle{normal}
+\phantomsection\label{\detokenize{index::doc}}
+
+
+\sphinxstepscope
+
+
+\chapter{Exercise}
+\label{\detokenize{exercise:exercise}}\label{\detokenize{exercise::doc}}
+\sphinxAtStartPar
+A collection of exercise directives
+\phantomsection \label{exercise:exercise-1}
+
+\begin{sphinxadmonition}{note}{Exercise 1 (\protect\(n!\protect\) factorial)}
+
+
+
+\sphinxAtStartPar
+Exercise 1 about \(n!\) factorial
+\end{sphinxadmonition}
+\phantomsection \label{exercise:exercise-2}
+\begin{sphinxadmonition}{note}{Exercise (\protect\(n!\protect\) factorial)}
+
+
+
+\sphinxAtStartPar
+Exercise 2 about \(n!\) factorial
+\end{sphinxadmonition}
+\phantomsection \label{exercise:exercise-3}
+
+\begin{sphinxadmonition}{note}{Exercise 2}
+
+
+
+\sphinxAtStartPar
+Exercise 3 Content with Number
+\end{sphinxadmonition}
+\phantomsection \label{exercise:exercise-4}
+\begin{sphinxadmonition}{note}{Exercise}
+
+
+
+\sphinxAtStartPar
+Exercise 4 Content with no Number
+\end{sphinxadmonition}
+
+
+\section{References}
+\label{\detokenize{exercise:references}}
+
+\subsection{Standard References}
+\label{\detokenize{exercise:standard-references}}
+\sphinxAtStartPar
+This is a link to \DUrole{xref}{\DUrole{std}{\DUrole{std-ref}{exercise\sphinxhyphen{}no\sphinxhyphen{}title}}}
+
+\sphinxAtStartPar
+This is a link to \hyperref[exercise:exercise-1]{Exercise 1}
+
+\sphinxAtStartPar
+This is a link to {\hyperref[\detokenize{exercise:exercise-2}]{\sphinxcrossref{\DUrole{std}{\DUrole{std-ref}{Exercise}}}}}
+
+\sphinxAtStartPar
+This ia another link with custom text \hyperref[exercise:exercise-3]{Exercise 3 Custom Text}
+
+\sphinxAtStartPar
+This ia another link with custom text {\hyperref[\detokenize{exercise:exercise-4}]{\sphinxcrossref{\DUrole{std}{\DUrole{std-ref}{Exercise 4 Custom Text}}}}}
+
+
+\subsection{Numbered References}
+\label{\detokenize{exercise:numbered-references}}
+\sphinxAtStartPar
+This is a numbered reference to \hyperref[exercise:exercise-1]{Exercise 1}
+
+\sphinxAtStartPar
+This is a numbered reference to \sphinxcode{\sphinxupquote{exercise\sphinxhyphen{}2}} and should be broken as exercise 2 is not an
+enumerated exercise node.
+
+\sphinxAtStartPar
+This is a numbered reference to \hyperref[exercise:exercise-3]{Exercise 2}
+
+\sphinxAtStartPar
+This is a numbered reference with custom text to \hyperref[exercise:exercise-3]{Custom Text with a Number 2}
+
+\sphinxAtStartPar
+This is a numbered reference to \sphinxcode{\sphinxupquote{exercise\sphinxhyphen{}4}} and should be broken as exercise 2 is not an
+enumerated exercise node.
+
+\sphinxAtStartPar
+This is a numbered reference with custom text to \sphinxcode{\sphinxupquote{Custom Text with a Number \{number\}}} and should be broken as exercise 2 is not an
+enumerated exercise node.
+
+\sphinxstepscope
+
+
+\chapter{Solution}
+\label{\detokenize{solution:solution}}\label{\detokenize{solution::doc}}
+\sphinxAtStartPar
+A collection of solution directives
+\phantomsection \label{solution:solution-1}
+
+\begin{sphinxadmonition}{note}{Solution to Exercise 1 (\protect\(n!\protect\) factorial)}
+
+
+
+\sphinxAtStartPar
+This is a solution to exercise 1
+\end{sphinxadmonition}
+\phantomsection \label{solution:solution-2}
+
+\begin{sphinxadmonition}{note}{Solution to Exercise (\protect\(n!\protect\) factorial)}
+
+
+
+\sphinxAtStartPar
+This is a solution to exercise 2
+\end{sphinxadmonition}
+\phantomsection \label{solution:solution-3}
+
+\begin{sphinxadmonition}{note}{Solution to Exercise 2}
+
+
+
+\sphinxAtStartPar
+This is a solution to exercise 3
+\end{sphinxadmonition}
+\phantomsection \label{solution:solution-4}
+
+\begin{sphinxadmonition}{note}{Solution to Exercise}
+
+
+
+\sphinxAtStartPar
+This is a solution to exercise 4
+\end{sphinxadmonition}
+
+
+\section{References}
+\label{\detokenize{solution:references}}
+
+\subsection{Standard References}
+\label{\detokenize{solution:standard-references}}
+\sphinxAtStartPar
+This is a link to {\hyperref[\detokenize{solution:solution-1}]{\sphinxcrossref{\DUrole{std}{\DUrole{std-ref}{Solution to Exercise 1 (n! factorial)}}}}}
+
+\sphinxAtStartPar
+This is a link to {\hyperref[\detokenize{solution:solution-2}]{\sphinxcrossref{\DUrole{std}{\DUrole{std-ref}{Solution to Exercise (n! factorial)}}}}}
+
+\sphinxAtStartPar
+This is a link to {\hyperref[\detokenize{solution:solution-3}]{\sphinxcrossref{\DUrole{std}{\DUrole{std-ref}{Solution to Exercise 2}}}}}
+
+\sphinxAtStartPar
+This is a link to {\hyperref[\detokenize{solution:solution-4}]{\sphinxcrossref{\DUrole{std}{\DUrole{std-ref}{Solution to Exercise}}}}}
+
+\sphinxAtStartPar
+This ia another link to a different {\hyperref[\detokenize{solution:solution-1}]{\sphinxcrossref{\DUrole{std}{\DUrole{std-ref}{Solution to Exercise 1 (n! factorial)}}}}}
+
+
+\subsection{Numbered References}
+\label{\detokenize{solution:numbered-references}}
+\sphinxAtStartPar
+Solution nodes are not enumerated nodes so these wonβt work
+
+\sphinxAtStartPar
+This is a link to \sphinxcode{\sphinxupquote{solution\sphinxhyphen{}1}}
+
+
+
+\renewcommand{\indexname}{Index}
+\printindex
+\end{document}
diff --git a/tests/test_solution.py b/tests/test_solution.py
index 07c50bc..07f8265 100644
--- a/tests/test_solution.py
+++ b/tests/test_solution.py
@@ -2,7 +2,12 @@
import pytest
import sphinx
-SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}"
+# Sphinx 8.1.x (Python 3.10 only) has different XML output than 8.2+
+# Use .sphinx8.1 for 8.1.x, .sphinx8 for 8.2+ (the standard)
+if sphinx.version_info[0] == 8 and sphinx.version_info[1] == 1:
+ SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}.{sphinx.version_info[1]}"
+else:
+ SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}"
@pytest.mark.sphinx("html", testroot="mybook")
diff --git a/tests/test_solution/_linked_duplicate_label.sphinx8.1.xml b/tests/test_solution/_linked_duplicate_label.sphinx8.1.xml
new file mode 100644
index 0000000..911fa54
--- /dev/null
+++ b/tests/test_solution/_linked_duplicate_label.sphinx8.1.xml
@@ -0,0 +1,10 @@
+
+
+
+ _linked_duplicate_label
+
+
+ Solution to
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
diff --git a/tests/test_solution/_linked_enum.sphinx8.1.xml b/tests/test_solution/_linked_enum.sphinx8.1.xml
new file mode 100644
index 0000000..272bd7f
--- /dev/null
+++ b/tests/test_solution/_linked_enum.sphinx8.1.xml
@@ -0,0 +1,29 @@
+
+
+
+ _linked_enum
+
+
+ Exercise
+
+ This is a title
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+
+ Solution to
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+ P_t(x, y) = \mathbb 1\{x = y\} + t Q(x, y) + o(t)
+
+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+
+ P_t(x, y) = \mathbb 1\{x = y\} + t Q(x, y) + o(t)
diff --git a/tests/test_solution/_linked_enum_class.sphinx8.1.xml b/tests/test_solution/_linked_enum_class.sphinx8.1.xml
new file mode 100644
index 0000000..daa32c8
--- /dev/null
+++ b/tests/test_solution/_linked_enum_class.sphinx8.1.xml
@@ -0,0 +1,10 @@
+
+
+
+ _linked_enum_class
+
+
+ Solution to
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
diff --git a/tests/test_solution/_linked_missing_arg.sphinx8.1.xml b/tests/test_solution/_linked_missing_arg.sphinx8.1.xml
new file mode 100644
index 0000000..6ecb8d7
--- /dev/null
+++ b/tests/test_solution/_linked_missing_arg.sphinx8.1.xml
@@ -0,0 +1,4 @@
+
+
+
+ _linked_missing_arg
diff --git a/tests/test_solution/_linked_unenum_mathtitle.sphinx8.1.xml b/tests/test_solution/_linked_unenum_mathtitle.sphinx8.1.xml
new file mode 100644
index 0000000..d5c931a
--- /dev/null
+++ b/tests/test_solution/_linked_unenum_mathtitle.sphinx8.1.xml
@@ -0,0 +1,24 @@
+
+
+
+ _linked_unenum_mathtitle
+
+
+ Exercise
+
+ This is a title
+