feat(serialize-xml): port tests
ci/woodpecker/push/woodpecker Pipeline failed
Details
ci/woodpecker/push/woodpecker Pipeline failed
Details
This commit is contained in:
parent
846bb1a982
commit
5e89193244
|
@ -29,8 +29,8 @@ public class NativeXmlWriter implements Closeable, Flushable {
|
||||||
private String deferredText = null;
|
private String deferredText = null;
|
||||||
private boolean wasText = false;
|
private boolean wasText = false;
|
||||||
|
|
||||||
private boolean lenient;
|
private boolean lenient = false;
|
||||||
private boolean escapeNonAscii;
|
private boolean escapeNonAscii = true;
|
||||||
public NativeXmlWriter(Writer out) {
|
public NativeXmlWriter(Writer out) {
|
||||||
this.out = Objects.requireNonNull(out, "out == null");
|
this.out = Objects.requireNonNull(out, "out == null");
|
||||||
newline = indent = "";
|
newline = indent = "";
|
||||||
|
@ -100,6 +100,9 @@ public class NativeXmlWriter implements Closeable, Flushable {
|
||||||
|
|
||||||
public NativeXmlWriter endTag() throws IOException {
|
public NativeXmlWriter endTag() throws IOException {
|
||||||
int context = peek();
|
int context = peek();
|
||||||
|
if (context == DANGLING_NAME) {
|
||||||
|
throw new IllegalStateException("Dangling name.");
|
||||||
|
}
|
||||||
if (context != TAG_HEAD && context != TAG_BODY) {
|
if (context != TAG_HEAD && context != TAG_BODY) {
|
||||||
throw new IllegalStateException("Nesting problem.");
|
throw new IllegalStateException("Nesting problem.");
|
||||||
}
|
}
|
||||||
|
@ -204,10 +207,10 @@ public class NativeXmlWriter implements Closeable, Flushable {
|
||||||
|
|
||||||
public NativeXmlWriter attributeName(String name) throws IOException {
|
public NativeXmlWriter attributeName(String name) throws IOException {
|
||||||
Objects.requireNonNull(name, "name == null");
|
Objects.requireNonNull(name, "name == null");
|
||||||
wasText = false;
|
|
||||||
if (peek() != TAG_HEAD) {
|
if (peek() != TAG_HEAD) {
|
||||||
throw new IllegalStateException("Nesting problem.");
|
throw new IllegalStateException("Nesting problem.");
|
||||||
}
|
}
|
||||||
|
wasText = false;
|
||||||
replaceTop(DANGLING_NAME);
|
replaceTop(DANGLING_NAME);
|
||||||
out.write(' ');
|
out.write(' ');
|
||||||
name(name);
|
name(name);
|
||||||
|
@ -216,10 +219,10 @@ public class NativeXmlWriter implements Closeable, Flushable {
|
||||||
|
|
||||||
public NativeXmlWriter attributeValue(String value) throws IOException {
|
public NativeXmlWriter attributeValue(String value) throws IOException {
|
||||||
value = value == null ? "null" : value;
|
value = value == null ? "null" : value;
|
||||||
wasText = false;
|
|
||||||
if (peek() != DANGLING_NAME) {
|
if (peek() != DANGLING_NAME) {
|
||||||
throw new IllegalStateException("Nesting problem.");
|
throw new IllegalStateException("Nesting problem.");
|
||||||
}
|
}
|
||||||
|
wasText = false;
|
||||||
replaceTop(TAG_HEAD);
|
replaceTop(TAG_HEAD);
|
||||||
out.write('=');
|
out.write('=');
|
||||||
out.write('"');
|
out.write('"');
|
||||||
|
@ -229,12 +232,13 @@ public class NativeXmlWriter implements Closeable, Flushable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public NativeXmlWriter text(String text) throws IOException {
|
public NativeXmlWriter text(String text) throws IOException {
|
||||||
if (peek() == TAG_HEAD && !text.contains("\n") && deferredComments.isEmpty()) {
|
text = text == null ? "null" : text;
|
||||||
|
if (peek() == TAG_HEAD && !text.contains("\n") && deferredText == null && deferredComments.isEmpty()) {
|
||||||
deferredText = text;
|
deferredText = text;
|
||||||
|
wasText = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
text = text == null ? "" : text;
|
if (wasText && deferredComments.isEmpty()) deferredComments.add("");
|
||||||
if (wasText) comment("");
|
|
||||||
beforeValue();
|
beforeValue();
|
||||||
escapeText(text, true);
|
escapeText(text, true);
|
||||||
wasText = true;
|
wasText = true;
|
||||||
|
|
|
@ -0,0 +1,368 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.gitlab.jfronny.commons.serialize.xml.test;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.commons.serialize.xml.NativeXmlWriter;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static org.junit.Assert.assertThrows;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
@SuppressWarnings("resource")
|
||||||
|
public final class NativeXmlWriterTest {
|
||||||
|
@Test
|
||||||
|
public void testWriteComments() throws IOException {
|
||||||
|
String expectedJson = """
|
||||||
|
<!-- comment at file head -->
|
||||||
|
<root>
|
||||||
|
<!-- comment directly after context -->
|
||||||
|
<a>true</a>
|
||||||
|
<!-- comment before context -->
|
||||||
|
<inner att="value">
|
||||||
|
<!-- comment directly after attribute name -->
|
||||||
|
<b att="value">
|
||||||
|
<!-- comment after attribute value -->
|
||||||
|
false
|
||||||
|
</b>
|
||||||
|
<cnt><!-- only comment inside tag --></cnt>
|
||||||
|
</inner>
|
||||||
|
<!-- comment before context end -->
|
||||||
|
</root>
|
||||||
|
<!-- comment behind the object -->""";
|
||||||
|
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
NativeXmlWriter jw = new NativeXmlWriter(sw);
|
||||||
|
jw.setLenient(true);
|
||||||
|
jw.setIndent(" ");
|
||||||
|
|
||||||
|
jw.comment("comment at file head")
|
||||||
|
.beginTag("root")
|
||||||
|
.comment("comment directly after context")
|
||||||
|
.beginTag("a")
|
||||||
|
.text("true")
|
||||||
|
.endTag()
|
||||||
|
.comment("comment before context")
|
||||||
|
.beginTag("inner")
|
||||||
|
.attributeName("att")
|
||||||
|
.comment("comment directly after attribute name")
|
||||||
|
.attributeValue("value")
|
||||||
|
.beginTag("b")
|
||||||
|
.attributeName("att")
|
||||||
|
.attributeValue("value")
|
||||||
|
.comment("comment after attribute value")
|
||||||
|
.text("false")
|
||||||
|
.endTag()
|
||||||
|
.beginTag("cnt")
|
||||||
|
.comment("only comment inside tag")
|
||||||
|
.endTag()
|
||||||
|
.endTag()
|
||||||
|
.comment("comment before context end")
|
||||||
|
.endTag()
|
||||||
|
.comment("comment behind the object");
|
||||||
|
|
||||||
|
jw.close();
|
||||||
|
assertThat(sw.toString()).isEqualTo(expectedJson);
|
||||||
|
sw.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaultStrictness() throws IOException {
|
||||||
|
NativeXmlWriter jsonWriter = new NativeXmlWriter(new StringWriter());
|
||||||
|
assertThat(jsonWriter.isLenient()).isEqualTo(false);
|
||||||
|
jsonWriter.text("false");
|
||||||
|
jsonWriter.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// for NativeXmlWriter.setLenient
|
||||||
|
@Test
|
||||||
|
public void testSetLenientTrue() throws IOException {
|
||||||
|
NativeXmlWriter jsonWriter = new NativeXmlWriter(new StringWriter());
|
||||||
|
jsonWriter.setLenient(true);
|
||||||
|
assertThat(jsonWriter.isLenient()).isEqualTo(true);
|
||||||
|
jsonWriter.text("false");
|
||||||
|
jsonWriter.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// for NativeXmlWriter.setLenient
|
||||||
|
@Test
|
||||||
|
public void testSetLenientFalse() throws IOException {
|
||||||
|
NativeXmlWriter jsonWriter = new NativeXmlWriter(new StringWriter());
|
||||||
|
jsonWriter.setLenient(false);
|
||||||
|
assertThat(jsonWriter.isLenient()).isEqualTo(false);
|
||||||
|
jsonWriter.text("false");
|
||||||
|
jsonWriter.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmptyTag() throws IOException {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
NativeXmlWriter jw = new NativeXmlWriter(sw);
|
||||||
|
jw.beginTag("empty").endTag();
|
||||||
|
jw.close();
|
||||||
|
assertThat(sw.toString()).isEqualTo("<empty/>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTopLevelValueTypes() throws IOException {
|
||||||
|
StringWriter string5 = new StringWriter();
|
||||||
|
NativeXmlWriter writert = new NativeXmlWriter(string5);
|
||||||
|
writert.text("a");
|
||||||
|
writert.close();
|
||||||
|
assertThat(string5.toString()).isEqualTo("a");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameWithoutValue() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter jsonWriter = new NativeXmlWriter(stringWriter);
|
||||||
|
jsonWriter.beginTag("tag");
|
||||||
|
jsonWriter.attributeName("a");
|
||||||
|
try {
|
||||||
|
jsonWriter.endTag();
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
assertThat(expected).hasMessageThat().isEqualTo("Dangling name.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValueWithoutName() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter jsonWriter = new NativeXmlWriter(stringWriter);
|
||||||
|
jsonWriter.beginTag("tag");
|
||||||
|
try {
|
||||||
|
jsonWriter.attributeValue("a");
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
assertThat(expected).hasMessageThat().isEqualTo("Nesting problem.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleTopLevelValuesStrict() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter jsonWriter = new NativeXmlWriter(stringWriter);
|
||||||
|
jsonWriter.setLenient(false);
|
||||||
|
jsonWriter.beginTag("tag").endTag();
|
||||||
|
|
||||||
|
IllegalStateException expected =
|
||||||
|
assertThrows(IllegalStateException.class, () -> jsonWriter.beginTag("tag"));
|
||||||
|
assertThat(expected).hasMessageThat().isEqualTo("XML must have only one top-level value.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleTopLevelValuesLenient() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter writer = new NativeXmlWriter(stringWriter);
|
||||||
|
writer.setLenient(true);
|
||||||
|
writer.beginTag("tag");
|
||||||
|
writer.endTag();
|
||||||
|
writer.beginTag("tag2");
|
||||||
|
writer.endTag();
|
||||||
|
writer.close();
|
||||||
|
assertThat(stringWriter.toString()).isEqualTo("<tag/><tag2/>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNullName() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter jsonWriter = new NativeXmlWriter(stringWriter);
|
||||||
|
jsonWriter.beginTag("tag");
|
||||||
|
try {
|
||||||
|
jsonWriter.attributeName(null);
|
||||||
|
fail();
|
||||||
|
} catch (NullPointerException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNullStringValue() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter jsonWriter = new NativeXmlWriter(stringWriter);
|
||||||
|
jsonWriter.beginTag("tag");
|
||||||
|
jsonWriter.attributeName("a");
|
||||||
|
jsonWriter.attributeValue(null);
|
||||||
|
jsonWriter.endTag();
|
||||||
|
assertThat(stringWriter.toString()).isEqualTo("<tag a=\"null\"/>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnicodeLineBreaksEscaped() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter jsonWriter = new NativeXmlWriter(stringWriter);
|
||||||
|
jsonWriter.beginTag("body");
|
||||||
|
jsonWriter.text("\u2028 \u2029");
|
||||||
|
jsonWriter.endTag();
|
||||||
|
// JSON specification does not require that they are escaped, but Gson escapes them for
|
||||||
|
// compatibility with JavaScript where they are considered line breaks
|
||||||
|
assertThat(stringWriter.toString()).isEqualTo("<body>
 
</body>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeepNesting() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter jsonWriter = new NativeXmlWriter(stringWriter);
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
jsonWriter.beginTag("a");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
jsonWriter.endTag();
|
||||||
|
}
|
||||||
|
assertThat(stringWriter.toString())
|
||||||
|
.isEqualTo(
|
||||||
|
"<a><a><a><a><a><a><a><a><a><a>"
|
||||||
|
+ "<a><a><a><a><a><a><a><a><a>"
|
||||||
|
+ "<a/>"
|
||||||
|
+ "</a></a></a></a></a></a></a></a></a>"
|
||||||
|
+ "</a></a></a></a></a></a></a></a></a></a>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRepeatedName() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter jsonWriter = new NativeXmlWriter(stringWriter);
|
||||||
|
jsonWriter.beginTag("tag");
|
||||||
|
jsonWriter.attributeName("a");
|
||||||
|
jsonWriter.attributeValue("true");
|
||||||
|
jsonWriter.attributeName("a");
|
||||||
|
jsonWriter.attributeValue("false");
|
||||||
|
jsonWriter.beginTag("a").text("true").endTag();
|
||||||
|
jsonWriter.beginTag("a").text("false").endTag();
|
||||||
|
jsonWriter.endTag();
|
||||||
|
// NativeXmlWriter doesn't attempt to detect duplicate names
|
||||||
|
assertThat(stringWriter.toString()).isEqualTo("<tag a=\"true\" a=\"false\"><a>true</a><a>false</a></tag>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrettyPrintArray() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter jsonWriter = new NativeXmlWriter(stringWriter);
|
||||||
|
jsonWriter.setIndent(" ");
|
||||||
|
|
||||||
|
jsonWriter.beginTag("tag");
|
||||||
|
jsonWriter.attribute("a", "b");
|
||||||
|
jsonWriter.text("true");
|
||||||
|
jsonWriter.text("false");
|
||||||
|
jsonWriter.text("5.0");
|
||||||
|
jsonWriter.text(null);
|
||||||
|
jsonWriter.beginTag("object");
|
||||||
|
jsonWriter.attributeName("a").attributeValue("6.0");
|
||||||
|
jsonWriter.beginTag("b").text("7.0").endTag();
|
||||||
|
jsonWriter.endTag();
|
||||||
|
jsonWriter.beginTag("tag");
|
||||||
|
jsonWriter.text("8.0");
|
||||||
|
jsonWriter.text("9.0");
|
||||||
|
jsonWriter.endTag();
|
||||||
|
jsonWriter.endTag();
|
||||||
|
|
||||||
|
String expected =
|
||||||
|
"""
|
||||||
|
<tag a="b">
|
||||||
|
true
|
||||||
|
<!---->
|
||||||
|
false
|
||||||
|
<!---->
|
||||||
|
5.0
|
||||||
|
<!---->
|
||||||
|
null
|
||||||
|
<object a="6.0">
|
||||||
|
<b>7.0</b>
|
||||||
|
</object>
|
||||||
|
<tag>
|
||||||
|
8.0
|
||||||
|
<!---->
|
||||||
|
9.0
|
||||||
|
</tag>
|
||||||
|
</tag>""";
|
||||||
|
assertThat(stringWriter.toString()).isEqualTo(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClosedWriterThrowsOnStructure() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter writer = new NativeXmlWriter(stringWriter);
|
||||||
|
writer.beginTag("tag");
|
||||||
|
writer.endTag();
|
||||||
|
writer.close();
|
||||||
|
try {
|
||||||
|
writer.beginTag("tag");
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
writer.endTag();
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClosedWriterThrowsOnName() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter writer = new NativeXmlWriter(stringWriter);
|
||||||
|
writer.beginTag("tag");
|
||||||
|
writer.endTag();
|
||||||
|
writer.close();
|
||||||
|
try {
|
||||||
|
writer.attributeName("a");
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClosedWriterThrowsOnValue() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter writer = new NativeXmlWriter(stringWriter);
|
||||||
|
writer.beginTag("tag");
|
||||||
|
writer.endTag();
|
||||||
|
writer.close();
|
||||||
|
try {
|
||||||
|
writer.attributeValue("a");
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClosedWriterThrowsOnFlush() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter writer = new NativeXmlWriter(stringWriter);
|
||||||
|
writer.beginTag("tag");
|
||||||
|
writer.endTag();
|
||||||
|
writer.close();
|
||||||
|
try {
|
||||||
|
writer.flush();
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWriterCloseIsIdempotent() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
NativeXmlWriter writer = new NativeXmlWriter(stringWriter);
|
||||||
|
writer.beginTag("tag");
|
||||||
|
writer.endTag();
|
||||||
|
writer.close();
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue