gson-comments/gson/src/test/java/com/google/gson/functional/FormattingStyleTest.java

215 lines
7.6 KiB
Java

/*
* Copyright (C) 2022 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 com.google.gson.functional;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import com.google.gson.FormattingStyle;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Functional tests for formatting styles.
*
* @author Mihai Nita
*/
@RunWith(JUnit4.class)
public class FormattingStyleTest {
// Create new input object every time to protect against tests accidentally modifying input
private static Map<String, List<Integer>> createInput() {
Map<String, List<Integer>> map = new LinkedHashMap<>();
map.put("a", Arrays.asList(1, 2));
return map;
}
private static String buildExpected(String newline, String indent, boolean spaceAfterSeparators) {
String expected =
"{<EOL><INDENT>\"a\":<COLON_SPACE>[<EOL><INDENT><INDENT>1,<COMMA_SPACE><EOL><INDENT><INDENT>2<EOL><INDENT>]<EOL>}";
String commaSpace = spaceAfterSeparators && newline.isEmpty() ? " " : "";
return expected
.replace("<EOL>", newline)
.replace("<INDENT>", indent)
.replace("<COLON_SPACE>", spaceAfterSeparators ? " " : "")
.replace("<COMMA_SPACE>", commaSpace);
}
// Various valid strings that can be used for newline and indent
private static final String[] TEST_NEWLINES = {
"", "\r", "\n", "\r\n", "\n\r\r\n", System.lineSeparator()
};
private static final String[] TEST_INDENTS = {"", " ", " ", "\t", " \t \t"};
@Test
public void testDefault() {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(createInput());
assertThat(json).isEqualTo(buildExpected("\n", " ", true));
}
@Test
public void testVariousCombinationsParse() {
// Mixing various indent and newline styles in the same string, to be parsed.
String jsonStringMix = "{\r\t'a':\r\n[ 1,2\t]\n}";
TypeToken<Map<String, List<Integer>>> inputType =
new TypeToken<Map<String, List<Integer>>>() {};
Map<String, List<Integer>> actualParsed;
// Test all that all combinations of newline can be parsed and generate the same INPUT.
for (String indent : TEST_INDENTS) {
for (String newline : TEST_NEWLINES) {
FormattingStyle style = FormattingStyle.PRETTY.withNewline(newline).withIndent(indent);
Gson gson = new GsonBuilder().setFormattingStyle(style).create();
String toParse = buildExpected(newline, indent, true);
actualParsed = gson.fromJson(toParse, inputType);
assertThat(actualParsed).isEqualTo(createInput());
// Parse the mixed string with the gson parsers configured with various newline / indents.
actualParsed = gson.fromJson(jsonStringMix, inputType);
assertThat(actualParsed).isEqualTo(createInput());
}
}
}
private static String toJson(Object obj, FormattingStyle style) {
return new GsonBuilder().setFormattingStyle(style).create().toJson(obj);
}
@Test
public void testFormatCompact() {
String json = toJson(createInput(), FormattingStyle.COMPACT);
String expectedJson = buildExpected("", "", false);
assertThat(json).isEqualTo(expectedJson);
// Sanity check to verify that `buildExpected` works correctly
assertThat(json).isEqualTo("{\"a\":[1,2]}");
}
@Test
public void testFormatPretty() {
String json = toJson(createInput(), FormattingStyle.PRETTY);
String expectedJson = buildExpected("\n", " ", true);
assertThat(json).isEqualTo(expectedJson);
// Sanity check to verify that `buildExpected` works correctly
assertThat(json)
.isEqualTo(
"{\n" //
+ " \"a\": [\n" //
+ " 1,\n" //
+ " 2\n" //
+ " ]\n" //
+ "}");
}
@Test
public void testFormatPrettySingleLine() {
FormattingStyle style = FormattingStyle.COMPACT.withSpaceAfterSeparators(true);
String json = toJson(createInput(), style);
String expectedJson = buildExpected("", "", true);
assertThat(json).isEqualTo(expectedJson);
// Sanity check to verify that `buildExpected` works correctly
assertThat(json).isEqualTo("{\"a\": [1, 2]}");
}
@Test
public void testFormat() {
for (String newline : TEST_NEWLINES) {
for (String indent : TEST_INDENTS) {
for (boolean spaceAfterSeparators : new boolean[] {true, false}) {
FormattingStyle style =
FormattingStyle.COMPACT
.withNewline(newline)
.withIndent(indent)
.withSpaceAfterSeparators(spaceAfterSeparators);
String json = toJson(createInput(), style);
String expectedJson = buildExpected(newline, indent, spaceAfterSeparators);
assertThat(json).isEqualTo(expectedJson);
}
}
}
}
/**
* Should be able to convert {@link FormattingStyle#COMPACT} to {@link FormattingStyle#PRETTY}
* using the {@code withX} methods.
*/
@Test
public void testCompactToPretty() {
FormattingStyle style =
FormattingStyle.COMPACT.withNewline("\n").withIndent(" ").withSpaceAfterSeparators(true);
String json = toJson(createInput(), style);
String expectedJson = toJson(createInput(), FormattingStyle.PRETTY);
assertThat(json).isEqualTo(expectedJson);
}
/**
* Should be able to convert {@link FormattingStyle#PRETTY} to {@link FormattingStyle#COMPACT}
* using the {@code withX} methods.
*/
@Test
public void testPrettyToCompact() {
FormattingStyle style =
FormattingStyle.PRETTY.withNewline("").withIndent("").withSpaceAfterSeparators(false);
String json = toJson(createInput(), style);
String expectedJson = toJson(createInput(), FormattingStyle.COMPACT);
assertThat(json).isEqualTo(expectedJson);
}
@Test
public void testStyleValidations() {
try {
// TBD if we want to accept \u2028 and \u2029. For now we don't because JSON specification
// does not consider them to be newlines
FormattingStyle.PRETTY.withNewline("\u2028");
fail("Gson should not accept anything but \\r and \\n for newline");
} catch (IllegalArgumentException expected) {
assertThat(expected)
.hasMessageThat()
.isEqualTo("Only combinations of \\n and \\r are allowed in newline.");
}
try {
FormattingStyle.PRETTY.withNewline("NL");
fail("Gson should not accept anything but \\r and \\n for newline");
} catch (IllegalArgumentException expected) {
assertThat(expected)
.hasMessageThat()
.isEqualTo("Only combinations of \\n and \\r are allowed in newline.");
}
try {
FormattingStyle.PRETTY.withIndent("\f");
fail("Gson should not accept anything but space and tab for indent");
} catch (IllegalArgumentException expected) {
assertThat(expected)
.hasMessageThat()
.isEqualTo("Only combinations of spaces and tabs are allowed in indent.");
}
}
}