feat(serialize-xml): port tests
ci/woodpecker/push/woodpecker Pipeline failed Details

This commit is contained in:
Johannes Frohnmeyer 2024-04-20 15:49:30 +02:00
parent 846bb1a982
commit 5e89193244
Signed by: Johannes
GPG Key ID: E76429612C2929F4
2 changed files with 379 additions and 7 deletions

View File

@ -29,8 +29,8 @@ public class NativeXmlWriter implements Closeable, Flushable {
private String deferredText = null;
private boolean wasText = false;
private boolean lenient;
private boolean escapeNonAscii;
private boolean lenient = false;
private boolean escapeNonAscii = true;
public NativeXmlWriter(Writer out) {
this.out = Objects.requireNonNull(out, "out == null");
newline = indent = "";
@ -100,6 +100,9 @@ public class NativeXmlWriter implements Closeable, Flushable {
public NativeXmlWriter endTag() throws IOException {
int context = peek();
if (context == DANGLING_NAME) {
throw new IllegalStateException("Dangling name.");
}
if (context != TAG_HEAD && context != TAG_BODY) {
throw new IllegalStateException("Nesting problem.");
}
@ -204,10 +207,10 @@ public class NativeXmlWriter implements Closeable, Flushable {
public NativeXmlWriter attributeName(String name) throws IOException {
Objects.requireNonNull(name, "name == null");
wasText = false;
if (peek() != TAG_HEAD) {
throw new IllegalStateException("Nesting problem.");
}
wasText = false;
replaceTop(DANGLING_NAME);
out.write(' ');
name(name);
@ -216,10 +219,10 @@ public class NativeXmlWriter implements Closeable, Flushable {
public NativeXmlWriter attributeValue(String value) throws IOException {
value = value == null ? "null" : value;
wasText = false;
if (peek() != DANGLING_NAME) {
throw new IllegalStateException("Nesting problem.");
}
wasText = false;
replaceTop(TAG_HEAD);
out.write('=');
out.write('"');
@ -229,12 +232,13 @@ public class NativeXmlWriter implements Closeable, Flushable {
}
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;
wasText = true;
return this;
}
text = text == null ? "" : text;
if (wasText) comment("");
if (wasText && deferredComments.isEmpty()) deferredComments.add("");
beforeValue();
escapeText(text, true);
wasText = true;

View File

@ -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>&#8232; &#8233;</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();
}
}