/* * 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> createInput() { Map> map = new LinkedHashMap<>(); map.put("a", Arrays.asList(1, 2)); return map; } private static String buildExpected(String newline, String indent, boolean spaceAfterSeparators) { String expected = "{\"a\":[1,2]}"; String commaSpace = spaceAfterSeparators && newline.isEmpty() ? " " : ""; return expected .replace("", newline) .replace("", indent) .replace("", spaceAfterSeparators ? " " : "") .replace("", 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>> inputType = new TypeToken>>() {}; Map> 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."); } } }