Repository: jhy/jsoup
Pull request #1994 (2023-09-11 23:43:59)

Bump org.junit.jupiter:junit-jupiter from 5.9.3 to 5.10.0
Bumps [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit5) from 5.9.3 to 5.10.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/junit-team/junit5/releases">org.junit.jupiter:junit-jupiter's releases</a>.</em></p>
<blockquote>
<p>JUnit 5.10.0 = Platform 1.10.0 + Jupiter 5.10.0 + Vintage 5.10.0</p>
<p>See <a href="http://junit.org/junit5/docs/5.10.0/release-notes/">Release Notes</a>.</p>
<p><strong>Full Changelog</strong>: <a href="https://github.com/junit-team/junit5/compare/r5.10.0-RC2...r5.10.0">https://github.com/junit-team/junit5/compare/r5.10.0-RC2...r5.10.0</a></p>
<p>JUnit 5.10.0-RC2 = Platform 1.10.0-RC2+ Jupiter 5.10.0-RC2 + Vintage 5.10.0-RC2</p>
<p>See <a href="http://junit.org/junit5/docs/5.10.0-RC2/release-notes/">Release Notes</a>.</p>
<p>JUnit 5.10.0-RC1 = Platform 1.10.0-RC1 + Jupiter 5.10.0-RC1 + Vintage 5.10.0-RC1</p>
<p>See <a href="http://junit.org/junit5/docs/5.10.0-RC1/release-notes/">Release Notes</a>.</p>
<p>JUnit 5.10.0-M1 = Platform 1.10.0-M1 + Jupiter 5.10.0-M1 + Vintage 5.10.0-M1</p>
<p>See <a href="http://junit.org/junit5/docs/5.10.0-M1/release-notes/">Release Notes</a>.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/junit-team/junit5/commit/7f619ca7ac9ecd1b20cc01c44a4df98f5fb67804"><code>7f619ca</code></a> Release 5.10</li>
<li><a href="https://github.com/junit-team/junit5/commit/9899de4a92520fb1b76cd1d4f2c9cd9150ebcfd1"><code>9899de4</code></a> Update Gradle Enterprise plugin to 3.14</li>
<li><a href="https://github.com/junit-team/junit5/commit/45b970fad4ea35ae46f40c8794611d47f8f28087"><code>45b970f</code></a> Replace soon-to-be-deprecated usages of project.buildDir</li>
<li><a href="https://github.com/junit-team/junit5/commit/463ae360d86837b955731df7d7fe56e9f7c155dd"><code>463ae36</code></a> Prune Release Notes for 5.10 GA</li>
<li><a href="https://github.com/junit-team/junit5/commit/893c64b47575df1d6499fb2064c81160c02e5c14"><code>893c64b</code></a> Back to snapshots for further development</li>
<li><a href="https://github.com/junit-team/junit5/commit/e6ff0c53ba851e48eaf26acc39988c5c4b469580"><code>e6ff0c5</code></a> Release 5.10.0-RC2</li>
<li><a href="https://github.com/junit-team/junit5/commit/b08a76b59f468df1dffeaae84a9bac4aa9163043"><code>b08a76b</code></a> Add 5.10.0-RC2 release notes</li>
<li><a href="https://github.com/junit-team/junit5/commit/2c278c7536c0c66eb2fc04e3c8665561bae0f0a7"><code>2c278c7</code></a> Revert &quot;Prune Release Notes for 5.10 GA&quot;</li>
<li><a href="https://github.com/junit-team/junit5/commit/acb6e65442b39c4372d8187f240f8f4f32da56d3"><code>acb6e65</code></a> Provide access to source element annotations for <code>TempDirFactory</code></li>
<li><a href="https://github.com/junit-team/junit5/commit/73818a193b7020a5c7bb3b11b1f178d8fe206462"><code>73818a1</code></a> Bump org.gradle.toolchains:foojay-resolver from 0.5.0 to 0.6.0</li>
<li>Additional commits viewable in <a href="https://github.com/junit-team/junit5/compare/r5.9.3...r5.10.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.junit.jupiter:junit-jupiter&package-manager=maven&previous-version=5.9.3&new-version=5.10.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/CHANGES b/CHANGES
index f8c1966d..989650e8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -31,6 +31,9 @@ Release 1.16.2 [PENDING]
   * Bugfix: `form` elements and empty elements (such as `img`) did not have their attributes de-duplicated.
     <https://github.com/jhy/jsoup/pull/1950>
 
+  * Bugfix: if Document.OutputSettings was cloned from a clone, an NPE would be thrown when used.
+    <https://github.com/jhy/jsoup/pull/1964>
+
   * Bugfix: in Jsoup.connect(url), URL paths containing a %2B were incorrectly recoded to a '+', or a '+' was recoded
     to a ' '. Fixed by reverting to the previous behavior of not encoding supplied paths, other than normalizing to
     ASCII.
diff --git a/pom.xml b/pom.xml
index 110c3375..8adc4e2d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -172,12 +172,12 @@
       </plugin>
       <plugin>
         <artifactId>maven-release-plugin</artifactId>
-        <version>3.0.0</version>
+        <version>3.0.1</version>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
-        <version>3.1.0</version>
+        <version>3.1.2</version>
         <configuration>
           <!-- smaller stack to find stack overflows -->
           <argLine>-Xss256k</argLine>
@@ -328,7 +328,7 @@
     <dependency>
       <groupId>org.junit.jupiter</groupId>
       <artifactId>junit-jupiter</artifactId>
-      <version>5.9.3</version>
+      <version>5.10.0</version>
       <scope>test</scope>
     </dependency>
 
diff --git a/src/main/java/org/jsoup/nodes/Document.java b/src/main/java/org/jsoup/nodes/Document.java
index 70c571f8..9930dc5e 100644
--- a/src/main/java/org/jsoup/nodes/Document.java
+++ b/src/main/java/org/jsoup/nodes/Document.java
@@ -385,9 +385,9 @@ public class Document extends Element {
         public enum Syntax {html, xml}
 
         private Entities.EscapeMode escapeMode = Entities.EscapeMode.base;
-        private Charset charset = DataUtil.UTF_8;
+        private Charset charset;
+        Entities.CoreCharset coreCharset; // fast encoders for ascii and utf8
         private final ThreadLocal<CharsetEncoder> encoderThreadLocal = new ThreadLocal<>(); // initialized by start of OuterHtmlVisitor
-        @Nullable Entities.CoreCharset coreCharset; // fast encoders for ascii and utf8
 
         private boolean prettyPrint = true;
         private boolean outline = false;
@@ -395,7 +395,9 @@ public class Document extends Element {
         private int maxPaddingWidth = 30;
         private Syntax syntax = Syntax.html;
 
-        public OutputSettings() {}
+        public OutputSettings() {
+            charset(DataUtil.UTF_8);
+        }
         
         /**
          * Get the document's current HTML escape mode: <code>base</code>, which provides a limited set of named HTML
@@ -439,6 +441,7 @@ public class Document extends Element {
          */
         public OutputSettings charset(Charset charset) {
             this.charset = charset;
+            coreCharset = Entities.CoreCharset.byName(charset.name());
             return this;
         }
 
@@ -456,7 +459,6 @@ public class Document extends Element {
             // created at start of OuterHtmlVisitor so each pass has own encoder, so OutputSettings can be shared among threads
             CharsetEncoder encoder = charset.newEncoder();
             encoderThreadLocal.set(encoder);
-            coreCharset = Entities.CoreCharset.byName(encoder.charset().name());
             return encoder;
         }
 
@@ -570,7 +572,7 @@ public class Document extends Element {
             } catch (CloneNotSupportedException e) {
                 throw new RuntimeException(e);
             }
-            clone.charset(charset.name()); // new charset and charset encoder
+            clone.charset(charset.name()); // new charset, coreCharset, and charset encoder
             clone.escapeMode = Entities.EscapeMode.valueOf(escapeMode.name());
             // indentAmount, maxPaddingWidth, and prettyPrint are primitives so object.clone() will handle
             return clone;


Test patch:
diff --git a/src/test/java/org/jsoup/nodes/EntitiesTest.java b/src/test/java/org/jsoup/nodes/EntitiesTest.java
index 886dfca5..7243c2f5 100644
--- a/src/test/java/org/jsoup/nodes/EntitiesTest.java
+++ b/src/test/java/org/jsoup/nodes/EntitiesTest.java
@@ -6,6 +6,7 @@ import org.junit.jupiter.api.Test;
 
 import static org.jsoup.nodes.Document.OutputSettings;
 import static org.jsoup.nodes.Entities.EscapeMode.*;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 public class EntitiesTest {
@@ -163,4 +164,15 @@ public class EntitiesTest {
         Document xml = Jsoup.parse(input, "", Parser.xmlParser());
         assertEquals(input, xml.html());
     }
+    
+    @Test public void escapeByClonedOutputSettings() {
+        OutputSettings outputSettings = new OutputSettings();
+        String text = "Hello &<> Å å π 新 there ¾ © »";
+        OutputSettings clone1 = outputSettings.clone();
+        OutputSettings clone2 = outputSettings.clone();
+
+        String escaped1 = assertDoesNotThrow(() -> Entities.escape(text, clone1));
+        String escaped2 = assertDoesNotThrow(() -> Entities.escape(text, clone2));
+        assertEquals(escaped1, escaped2);
+    }
 }