entry : this.entrySet()) {
+ String name = entry.getKey();
+ Object valueThis = entry.getValue();
+ Object valueOther = ((JSONObject) other).get(name);
+ if (valueThis == valueOther) {
+ continue;
+ }
+ if (valueThis == null) {
+ return false;
+ }
+ if (valueThis instanceof JSONObject) {
+ if (!((JSONObject) valueThis).similar(valueOther)) {
+ return false;
+ }
+ } else if (valueThis instanceof JSONArray) {
+ if (!((JSONArray) valueThis).similar(valueOther)) {
+ return false;
+ }
+ } else if (!valueThis.equals(valueOther)) {
+ return false;
+ }
+ }
+ return true;
+ } catch (Throwable exception) {
+ return false;
+ }
+ }
+
+ /**
+ * Tests if the value should be tried as a decimal. It makes no test if there are actual digits.
+ *
+ * @param val value to test
+ * @return true if the string is "-0" or if it contains '.', 'e', or 'E', false otherwise.
+ */
+ protected static boolean isDecimalNotation(final String val) {
+ return val.indexOf('.') > -1 || val.indexOf('e') > -1
+ || val.indexOf('E') > -1 || "-0".equals(val);
+ }
+
+ /**
+ * Converts a string to a number using the narrowest possible type. Possible returns for this function are BigDecimal, Double, BigInteger, Long,
+ * and Integer. When a Double is returned, it should always be a valid Double and not NaN or +-infinity.
+ *
+ * @param val value to convert
+ * @return Number representation of the value.
+ * @throws NumberFormatException thrown if the value is not a valid number. A public caller should catch this and wrap it in a
+ * {@link JSONException} if applicable.
+ */
+ protected static Number stringToNumber(final String val) throws NumberFormatException {
+ char initial = val.charAt(0);
+ if ((initial >= '0' && initial <= '9') || initial == '-') {
+ // decimal representation
+ if (isDecimalNotation(val)) {
+ // quick dirty way to see if we need a BigDecimal instead of a Double
+ // this only handles some cases of overflow or underflow
+ if (val.length() > 14) {
+ return new BigDecimal(val);
+ }
+ final Double d = Double.valueOf(val);
+ if (d.isInfinite() || d.isNaN()) {
+ // if we can't parse it as a double, go up to BigDecimal
+ // this is probably due to underflow like 4.32e-678
+ // or overflow like 4.65e5324. The size of the string is small
+ // but can't be held in a Double.
+ return new BigDecimal(val);
+ }
+ return d;
+ }
+ // integer representation.
+ // This will narrow any values to the smallest reasonable Object representation
+ // (Integer, Long, or BigInteger)
+
+ // string version
+ // The compare string length method reduces GC,
+ // but leads to smaller integers being placed in larger wrappers even though not
+ // needed. i.e. 1,000,000,000 -> Long even though it's an Integer
+ // 1,000,000,000,000,000,000 -> BigInteger even though it's a Long
+ //if(val.length()<=9){
+ // return Integer.valueOf(val);
+ //}
+ //if(val.length()<=18){
+ // return Long.valueOf(val);
+ //}
+ //return new BigInteger(val);
+ // BigInteger version: We use a similar bitLenth compare as
+ // BigInteger#intValueExact uses. Increases GC, but objects hold
+ // only what they need. i.e. Less runtime overhead if the value is
+ // long lived. Which is the better tradeoff? This is closer to what's
+ // in stringToValue.
+ BigInteger bi = new BigInteger(val);
+ if (bi.bitLength() <= 31) {
+ return bi.intValue();
+ }
+ if (bi.bitLength() <= 63) {
+ return bi.longValue();
+ }
+ return bi;
+ }
+ throw new NumberFormatException("val [" + val + "] is not a valid number.");
+ }
+
+ /**
+ * Try to convert a string into a number, boolean, or null. If the string can't be converted, return the string.
+ *
+ * @param string A String.
+ * @return A simple JSON value.
+ */
+ // Changes to this method must be copied to the corresponding method in
+ // the XML class to keep full support for Android
+ public static Object stringToValue(String string) {
+ if (string.equals("")) {
+ return string;
+ }
+ if (string.equalsIgnoreCase("true")) {
+ return Boolean.TRUE;
+ }
+ if (string.equalsIgnoreCase("false")) {
+ return Boolean.FALSE;
+ }
+ if (string.equalsIgnoreCase("null")) {
+ return JSONObject.NULL;
+ }
+
+ /*
+ * If it might be a number, try converting it. If a number cannot be
+ * produced, then the value will just be a string.
+ */
+ char initial = string.charAt(0);
+ if ((initial >= '0' && initial <= '9') || initial == '-') {
+ try {
+ // if we want full Big Number support this block can be replaced with:
+ // return stringToNumber(string);
+ if (isDecimalNotation(string)) {
+ Double d = Double.valueOf(string);
+ if (!d.isInfinite() && !d.isNaN()) {
+ return d;
+ }
+ } else {
+ Long myLong = Long.valueOf(string);
+ if (string.equals(myLong.toString())) {
+ if (myLong.longValue() == myLong.intValue()) {
+ return myLong.intValue();
+ }
+ return myLong;
+ }
+ }
+ } catch (NumberFormatException ignore) {
+ }
+ }
+ return string;
+ }
+
+ /**
+ * Throw an exception if the object is a NaN or infinite number.
+ *
+ * @param o The object to test.
+ * @throws JSONException If o is a non-finite number.
+ */
+ public static void testValidity(Object o) throws JSONException {
+ if (o != null) {
+ if (o instanceof Double) {
+ if (((Double) o).isInfinite() || ((Double) o).isNaN()) {
+ throw new JSONException("JSON does not allow non-finite numbers.");
+ }
+ } else if (o instanceof Float) {
+ if (((Float) o).isInfinite() || ((Float) o).isNaN()) {
+ throw new JSONException("JSON does not allow non-finite numbers.");
+ }
+ }
+ }
+ }
+
+ /**
+ * Produce a JSONArray containing the values of the members of this JSONObject.
+ *
+ * @param names A JSONArray containing a list of key strings. This determines the sequence of the values in the result.
+ * @return A JSONArray of values.
+ * @throws JSONException If any of the values are non-finite numbers.
+ */
+ public JSONArray toJSONArray(JSONArray names) throws JSONException {
+ if (names == null || names.isEmpty()) {
+ return null;
+ }
+ JSONArray ja = new JSONArray();
+ for (int i = 0; i < names.length(); i += 1) {
+ ja.put(this.opt(names.getString(i)));
+ }
+ return ja;
+ }
+
+ /**
+ * Make a JSON text of this JSONObject. For compactness, no whitespace is added. If this would not result in a syntactically correct JSON text,
+ * then null will be returned instead.
+ *
+ *
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ *
+ * @return a printable, displayable, portable, transmittable representation of the object, beginning with { (left
+ * brace) and ending with } (right brace).
+ */
+ @Override
+ public String toString() {
+ try {
+ return this.toString(-1);
+ } catch (JSONException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Make a pretty-printed JSON text of this JSONObject.
+ *
+ *
+ * If indentFactor > 0 and the {@link JSONObject} has only one key, then the object will be output on a single line:
+ *
{@code {"key": 1}}
+ *
+ *
+ * If an object has 2 or more keys, then it will be output across multiple lines: {
+ * "key1": 1,
+ * "key2": "value 2",
+ * "key3": 3
+ * }
+ *
+ *
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ *
+ * @param indentFactor The number of spaces to add to each level of indentation.
+ * @return a printable, displayable, portable, transmittable representation of the object, beginning with { (left
+ * brace) and ending with } (right brace).
+ * @throws JSONException If the object contains an invalid number.
+ */
+ @Override
+ public String toString(int indentFactor) throws JSONException {
+ StringWriter w = new StringWriter();
+ JSONOptions options;
+ if (indentFactor == -1) {
+ options = JSONOptions.getDefault();
+ } else {
+ options = JSONOptions.createOptions().setIndentFactor(indentFactor);
+ }
+ synchronized (w.getBuffer()) {
+ return this.write(w, 0, options).toString();
+ }
+ }
+
+ /**
+ * Make a JSON text of an Object value. If the object has an value.toJSONString() method, then that method will be used to produce the JSON text.
+ * The method is required to produce a strictly conforming text. If the object does not contain a toJSONString method (which is the most common
+ * case), then a text will be produced by other means. If the value is an array or Collection, then a JSONArray will be made from it and its
+ * toJSONString method will be called. If the value is a MAP, then a JSONObject will be made from it and its toJSONString method will be called.
+ * Otherwise, the value's toString method will be called, and the result will be quoted.
+ *
+ *
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @param value The value to be serialized.
+ * @return a printable, displayable, transmittable representation of the object, beginning with { (left brace) and
+ * ending with } (right brace).
+ * @throws JSONException If the value is or contains an invalid number.
+ */
+ public static String valueToString(Object value) throws JSONException {
+ // moves the implementation to JSONWriter as:
+ // 1. It makes more sense to be part of the writer class
+ // 2. For Android support this method is not available. By implementing it in the Writer
+ // Android users can use the writer with the built in Android JSONObject implementation.
+ return JSONWriter.valueToString(value);
+ }
+
+ /**
+ * Wrap an object, if necessary. If the object is null, return the NULL object. If it is an array or collection, wrap it in a
+ * JSONArray. If it is a map, wrap it in a JSONObject. If it is a standard property (Double, String, et al) then it is already wrapped. Otherwise,
+ * if it comes from one of the java packages, turn it into a string. And if it doesn't, try to wrap it in a JSONObject. If the wrapping fails, then
+ * null is returned.
+ *
+ * @param object The object to wrap
+ * @return The wrapped value
+ */
+ public static Object wrap(Object object) {
+ try {
+ if (object == null) {
+ return NULL;
+ }
+ if (object instanceof JSONObject || object instanceof JSONArray
+ || NULL.equals(object) || object instanceof JSONString
+ || object instanceof Byte || object instanceof Character
+ || object instanceof Short || object instanceof Integer
+ || object instanceof Long || object instanceof Boolean
+ || object instanceof Float || object instanceof Double
+ || object instanceof String || object instanceof BigInteger
+ || object instanceof BigDecimal || object instanceof Enum) {
+ return object;
+ }
+
+ if (object instanceof Collection) {
+ Collection> coll = (Collection>) object;
+ return new JSONArray(coll);
+ }
+ if (object.getClass().isArray()) {
+ return new JSONArray(object);
+ }
+ if (object instanceof Map) {
+ Map, ?> map = (Map, ?>) object;
+ return new JSONObject(map);
+ }
+ Package objectPackage = object.getClass().getPackage();
+ String objectPackageName = objectPackage != null ? objectPackage
+ .getName() : "";
+ if (objectPackageName.startsWith("java.")
+ || objectPackageName.startsWith("javax.")
+ || object.getClass().getClassLoader() == null) {
+ return object.toString();
+ }
+ return new JSONObject(object);
+ } catch (JSONException exception) {
+ return null;
+ }
+ }
+
+ /**
+ * Write the contents of the JSONObject as JSON text to a writer. For compactness, no whitespace is added.
+ *
+ *
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ *
+ * @param writer the writer
+ * @return The writer.
+ * @throws JSONException
+ */
+ @Override
+ public Writer write(Writer writer) throws JSONException {
+ return this.write(writer, 0);
+ }
+
+ static final Writer writeValue(Writer writer, Object value, int indent, JSONOptions options) throws JSONException, IOException {
+ return writeValue(writer, value, indent, false, options);
+ }
+
+ static final Writer writeValue(Writer writer, Object value, int indent, boolean isValue, JSONOptions options) throws JSONException, IOException {
+ options = JSONOptions.getOptions(options);
+ if (value == null) {
+ writer.write("null");
+ } else if (value instanceof JSONObject.Null) {
+ writer.write("null");
+ } else if (value instanceof JSONString) {
+ Object o;
+ try {
+ o = ((JSONString) value).toJSONString();
+ } catch (Exception e) {
+ throw new JSONException(e);
+ }
+ writer.write(o != null ? o.toString() : quote(value.toString()));
+ } else if (value instanceof Number) {
+ // not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary
+ final String numberAsString = numberToString((Number) value, options.isKeepingDecimalPoints());
+ try {
+ // Use the BigDecimal constructor for its parser to validate the format.
+ @SuppressWarnings("unused")
+ BigDecimal testNum = new BigDecimal(numberAsString);
+ // Close enough to a JSON number that we will use it unquoted
+ writer.write(numberAsString);
+ } catch (NumberFormatException ex) {
+ // The Number value is not a valid JSON number.
+ // Instead we will quote it as a string
+ quote(numberAsString, writer);
+ }
+ } else if (value instanceof Boolean) {
+ writer.write(value.toString());
+ } else if (value instanceof Enum>) {
+ writer.write(quote(((Enum>) value).name()));
+ } else if (value instanceof JSONObject) {
+ ((JSONObject) value).write(writer, indent, isValue, options);
+ } else if (value instanceof JSONArray) {
+ ((JSONArray) value).write(writer, indent, options);
+ } else if (value instanceof Map) {
+ Map, ?> map = (Map, ?>) value;
+ new JSONObject(map).write(writer, indent, isValue, options);
+ } else if (value instanceof Collection) {
+ Collection> coll = (Collection>) value;
+ new JSONArray(coll).write(writer, indent, options);
+ } else if (value.getClass().isArray()) {
+ new JSONArray(value).write(writer, indent, options);
+ } else {
+ quote(value.toString(), writer);
+ }
+ return writer;
+ }
+
+ static final void indent(Writer writer, int indent) throws IOException {
+ for (int i = 0; i < indent; i += 1) {
+ writer.write(' ');
+ }
+ }
+
+ /**
+ * Write the contents of the JSONObject as JSON text to a writer, without keeping the keys natural order.
+ *
+ *
+ * @param writer Writes the serialized JSON
+ * @param indent The indentation of the top level
+ * @return The writer
+ * @throws JSONException if the JSONObject was unable to write
+ */
+ @Override
+ public Writer write(Writer writer, int indent) throws JSONException {
+ return write(writer, indent, null);
+ }
+
+ private boolean shouldIndent(int length, JSONOptions options) {
+ if (length == 1) {
+ switch (options.getIndentationType()) {
+ case JSONOptions.INDENT_ALL:
+ return true;
+ case JSONOptions.INDENT_DEFAULT:
+ return false;
+ case JSONOptions.INDENT_OBJECTS:
+ Object value = map.values().iterator().next();
+ return value instanceof JSONElement;
+ default:
+ return false;
+ }
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Write the contents of the JSONObject as JSON text to a writer.
+ *
+ *
+ * If indentFactor > 0 and the {@link JSONObject} has only one key, then the object will be output on a single line:
+ *
{@code {"key": 1}}
+ *
+ *
+ * If an object has 2 or more keys, then it will be output across multiple lines: {
+ * "key1": 1,
+ * "key2": "value 2",
+ * "key3": 3
+ * }
+ *
+ *
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ *
+ * @param writer Writes the serialized JSON
+ * @param indent The indentation of the top level
+ * @param isValue true to write a value
+ * @param options the JSON configuration options
+ * @return The writer
+ * @throws JSONException if the JSONObject was unable to write
+ */
+ public Writer write(Writer writer, int indent, boolean isValue, JSONOptions options) throws JSONException {
+ try {
+ options = JSONOptions.getOptions(options);
+ int indentFactor = options.getIndentFactor();
+ boolean commanate = false;
+ Map theMap;
+ if (options.isKeepingKeysNaturalOrder()) {
+ theMap = new TreeMap<>(map);
+ } else {
+ theMap = map;
+ }
+ final int length = this.length();
+ if (isValue && indent > 0) {
+ indent(writer, 1);
+ } else {
+ indent(writer, indent);
+ }
+ writer.write('{');
+
+ if (length != 0) {
+ boolean shouldIndent = shouldIndent(length, options);
+ if (!shouldIndent) {
+ final Entry entry = theMap.entrySet().iterator().next();
+ final String key = entry.getKey();
+ writer.write(quote(key));
+ writer.write(':');
+ if (indentFactor > 0) {
+ writer.write(' ');
+ }
+ try {
+ writeValue(writer, entry.getValue(), indent, options);
+ } catch (IOException | JSONException e) {
+ throw new JSONException("Unable to write JSONObject value for key: " + key, e);
+ }
+ } else {
+ int newindent = indent + indentFactor;
+ for (final Entry entry : theMap.entrySet()) {
+ if (commanate) {
+ writer.write(',');
+ }
+ if (indentFactor > 0) {
+ writer.write('\n');
+ }
+ indent(writer, newindent);
+ final String key = entry.getKey();
+ writer.write(quote(key));
+ writer.write(':');
+ if (indentFactor > 0) {
+ writer.write(' ');
+ }
+ try {
+ newindent = indent + indentFactor;
+ writeValue(writer, entry.getValue(), newindent, true, options);
+ } catch (IOException | JSONException e) {
+ throw new JSONException("Unable to write JSONObject value for key: " + key, e);
+ }
+ commanate = true;
+ }
+ if (indentFactor > 0) {
+ writer.write('\n');
+ }
+ indent(writer, indent);
+ }
+ }
+ writer.write('}');
+ return writer;
+ } catch (IOException exception) {
+ throw new JSONException(exception);
+ }
+ }
+
+ /**
+ * Returns a java.util.Map containing all of the entries in this object. If an entry in the object is a JSONArray or JSONObject it will also be
+ * converted.
+ *
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @return a java.util.Map containing the entries of this object
+ */
+ public Map toMap() {
+ Map results = new HashMap<>();
+ for (Entry entry : this.entrySet()) {
+ Object value;
+ if (entry.getValue() == null || NULL.equals(entry.getValue())) {
+ value = null;
+ } else if (entry.getValue() instanceof JSONObject) {
+ value = ((JSONObject) entry.getValue()).toMap();
+ } else if (entry.getValue() instanceof JSONArray) {
+ value = ((JSONArray) entry.getValue()).toList();
+ } else {
+ value = entry.getValue();
+ }
+ results.put(entry.getKey(), value);
+ }
+ return results;
+ }
+}
diff --git a/src/org/json/JSONOptions.java b/src/org/json/JSONOptions.java
new file mode 100644
index 000000000..58fd350f4
--- /dev/null
+++ b/src/org/json/JSONOptions.java
@@ -0,0 +1,399 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+/**
+ * Stores options for reading or serializing JSON content.
+ *
+ * It is possible to specifically set the options to use when saving JSON content (or
+ * reading through the {@link FileUtils} class). For example:
+ *
+ * - {@link FileUtils#toFile(org.json.JSONElement, java.io.File, org.json.JSONOptions)}
+ *
+ *
+ * By default saving or reading will use a default options which content can be modified. For example:
+ *
+ * - {@link FileUtils#toFile(org.json.JSONElement, java.io.File)}
+ *
+ *
+ * Options
+ * Charset Option
+ * It is possible to specify the charset to read or write JSON files. By default the charset is UTF-8.
+ *
+ * key ordering Option
+ * It is possible to ensure that the keys are written according to their natural order (String order). By
+ * default this option is set to false.
+ *
+ * You must be aware that the ordering of the keys has no meaning for JSON files. It can only be useful to set this option to true if you want the
+ * result to be easily human-readable.
+ *
+ * Allowing comments Option
+ * It is possible to allow javascript comments whe reading JSON content. By default
+ * comments are not allowed.
+ *
+ * Decimal points Option
+ * It is possible to keep decimal points when serializing float or double numbers. By default
+ * float or double numbers which are equal to int values will not have their decimal points
+ * when serializing.
+ *
+ * Indentation type Option
+ * By default the result is not indented. The possible types are:
+ *
+ * - {@link #INDENT_DEFAULT}: the default indentation type
+ * - {@link #INDENT_ALL}: all fields are indented
+ * - {@link #INDENT_OBJECTS}: only objects and arrays fields are indented
+ *
+ *
+ * Indent factor Option
+ * The ident factor is the number of spaces to add to each level of indentation. By default
+ * it is equal to 0.
+ *
+ * Keep XML Strings Option
+ * Set if values will not be coerced into boolean or numeric values and will instead be left as strings. This is only valid for XML parsing. By default
+ * it is false.
+ *
+ * @since 1.7.2
+ */
+public class JSONOptions {
+ private static JSONOptions STATIC_OPTIONS = null;
+ /**
+ * The default indentation type.
+ */
+ public static final short INDENT_DEFAULT = 0;
+ /**
+ * The object indentation type. Only objects fields are indented.
+ */
+ public static final short INDENT_OBJECTS = 1;
+ /**
+ * The "All" indentation type. All fields are indented.
+ */
+ public static final short INDENT_ALL = 2;
+ private boolean keepDecimalPoints = false;
+ private boolean keysNaturalOrder = false;
+ private short resultIndentationType = INDENT_DEFAULT;
+ private boolean acceptComments = false;
+ private boolean keepXMLStrings = false;
+ private int indentFactor = 0;
+ private String charset = "UTF-8";
+
+ public JSONOptions() {
+ }
+
+ /**
+ * Return the default options. The default options will be used when reading or
+ * writing JSON content without specifying the options explicitly. For example:
+ * {@link FileUtils#toFile(org.json.JSONElement, java.io.File)}.
+ *
+ * @return the default options
+ */
+ public static JSONOptions getDefault() {
+ if (STATIC_OPTIONS == null) {
+ STATIC_OPTIONS = new JSONOptions();
+ }
+ return STATIC_OPTIONS;
+ }
+
+ /**
+ * Reset the default options.
+ *
+ * @return the default options
+ */
+ public static JSONOptions resetDefault() {
+ STATIC_OPTIONS = getDefault();
+ STATIC_OPTIONS.reset();
+ return STATIC_OPTIONS;
+ }
+
+ /**
+ * Reset this options values.
+ */
+ public void reset() {
+ keepDecimalPoints = false;
+ keysNaturalOrder = false;
+ resultIndentationType = INDENT_DEFAULT;
+ acceptComments = false;
+ keepXMLStrings = false;
+ indentFactor = 0;
+ charset = "UTF-8";
+ }
+
+ /**
+ * Return a new JSONOptions with default parameters values.
+ *
+ * @return the JSONOptions
+ */
+ public static JSONOptions createOptions() {
+ return new JSONOptions();
+ }
+
+ /**
+ * Return a not null JSONOptions. If the provided options is not null, return this JSONOptions. Else return the default JSONOptions, creating
+ * it if necessary.
+ *
+ * @param options the provided JSONOptions (may be null)
+ * @return the returned JSONOptions (will never be null)
+ */
+ public static JSONOptions getOptions(JSONOptions options) {
+ if (options == null) {
+ options = getDefault();
+ }
+ return options;
+ }
+
+ /**
+ * Set if decimal points must be kept in the serialized results for decimal values, for the default options.
+ *
+ * @param keepDecimalPoints true if decimal points must be kept in the results for decimal values
+ * @return the default options
+ */
+ public static JSONOptions setDefaultKeepDecimalPoints(boolean keepDecimalPoints) {
+ JSONOptions options = JSONOptions.getDefault();
+ options.keepDecimalPoints = keepDecimalPoints;
+ return options;
+ }
+
+ /**
+ * Set if decimal points must be kept in the serialized results for decimal values. It is false by default, so trailing decimal points will be
+ * removed.
+ *
+ * @param keepDecimalPoints true if decimal points must be kept in the results for decimal values
+ * @return this
+ */
+ public JSONOptions keepDecimalPoints(boolean keepDecimalPoints) {
+ this.keepDecimalPoints = keepDecimalPoints;
+ return this;
+ }
+
+ /**
+ * Return true if decimal points must be kept in the serialized results for decimal values. It is false by default, so trailing decimal points will be
+ * removed.
+ *
+ * @return true if decimal points must be kept in the serialized results for decimal values. It is false by default, so trailing decimal points will be
+ * removed
+ */
+ public boolean isKeepingDecimalPoints() {
+ return keepDecimalPoints;
+ }
+
+ /**
+ * Set the charset to use when reading or writing JSON content, for the default options.
+ *
+ * @param charset true the charset
+ * @return the default options
+ */
+ public static JSONOptions setDefaultCharSetName(String charset) {
+ JSONOptions options = JSONOptions.getDefault();
+ options.charset = charset;
+ return options;
+ }
+
+ /**
+ * Set the charset to use when reading or writing JSON content.
+ *
+ * @param charset true the charset
+ * @return this
+ */
+ public JSONOptions setCharSetName(String charset) {
+ this.charset = charset;
+ return this;
+ }
+
+ /**
+ * Return the charset to use when reading or writing JSON content.
+ *
+ * @return the charset
+ */
+ public String getCharset() {
+ return charset;
+ }
+
+ /**
+ * Set if javascript comments should be accepted, for the default options..
+ *
+ * @param accept true if javascript comments should be accepted
+ * @return the default options
+ */
+ public static JSONOptions setDefaultAcceptJavascriptComments(boolean accept) {
+ JSONOptions options = JSONOptions.getDefault();
+ options.acceptComments = accept;
+ return options;
+ }
+
+ /**
+ * Set if javascript comments should be accepted.
+ *
+ * @param accept true if javascript comments should be accepted
+ * @return this
+ */
+ public JSONOptions acceptJavascriptComments(boolean accept) {
+ this.acceptComments = accept;
+ return this;
+ }
+
+ /**
+ * Return true if javascript comments should be accepted.
+ *
+ * @return true if javascript comments should be accepted
+ */
+ public boolean isAcceptingJavascriptComments() {
+ return acceptComments;
+ }
+
+ /**
+ * Set if the keys natural order should be kept, for the default options.
+ *
+ * @param keysNaturalOrder true if the keys natural order must be kept
+ * @return the default options
+ */
+ public static JSONOptions setDefaultKeepKeysNaturalOrder(boolean keysNaturalOrder) {
+ JSONOptions options = JSONOptions.getDefault();
+ options.keysNaturalOrder = keysNaturalOrder;
+ return options;
+ }
+
+ /**
+ * Set if the keys natural order should be kept.
+ *
+ * @param keysNaturalOrder true if the keys natural order must be kept
+ * @return this
+ */
+ public JSONOptions keepKeysNaturalOrder(boolean keysNaturalOrder) {
+ this.keysNaturalOrder = keysNaturalOrder;
+ return this;
+ }
+
+ /**
+ * Return true if the keys natural order should be kept.
+ *
+ * @return true if the keys natural order should be kept
+ */
+ public boolean isKeepingKeysNaturalOrder() {
+ return keysNaturalOrder;
+ }
+
+ /**
+ * Set if values will not be coerced into boolean or numeric values and will instead be left as strings, for the default options. This is only
+ * valid for XML parsing.
+ *
+ * @param keepXMLStrings true if values will not be coerced into boolean or numeric values and will instead be left as strings
+ * @return the default options
+ */
+ public static JSONOptions setDefaultKeepXMLStrings(boolean keepXMLStrings) {
+ JSONOptions options = JSONOptions.getDefault();
+ options.keepXMLStrings = keepXMLStrings;
+ return options;
+ }
+
+ /**
+ * Set if values will not be coerced into boolean or numeric values and will instead be left as strings. This is only valid for XML parsing.
+ *
+ * @param keepXMLStrings true if values will not be coerced into boolean or numeric values and will instead be left as strings
+ * @return this
+ */
+ public JSONOptions keepXMLStrings(boolean keepXMLStrings) {
+ this.keepXMLStrings = keepXMLStrings;
+ return this;
+ }
+
+ /**
+ * Return true if values will not be coerced into boolean or numeric values and will instead be left as strings. This is only valid for XML parsing.
+ *
+ * @return true if values will not be coerced into boolean or numeric values and will instead be left as strings
+ */
+ public boolean isKeepingXMLStrings() {
+ return keepXMLStrings;
+ }
+
+ /**
+ * Set the number of spaces to add to each level of indentation, for the default options.
+ *
+ * @param indentFactor the indent factor
+ * @return the default options
+ */
+ public static JSONOptions setDefaultIndentFactor(int indentFactor) {
+ JSONOptions options = JSONOptions.getDefault();
+ options.indentFactor = indentFactor;
+ return options;
+ }
+
+ /**
+ * Set the number of spaces to add to each level of indentation.
+ *
+ * @param indentFactor the indent factor
+ * @return this
+ */
+ public JSONOptions setIndentFactor(int indentFactor) {
+ this.indentFactor = indentFactor;
+ return this;
+ }
+
+ /**
+ * Return the number of spaces to add to each level of indentation.
+ *
+ * @return the indent factor
+ */
+ public int getIndentFactor() {
+ return indentFactor;
+ }
+
+ /**
+ * Set the result indentation type, for the default options. The possible types are:
+ *
+ * - {@link #INDENT_DEFAULT}: the default indentation type
+ * - {@link #INDENT_ALL}: all fields are indented
+ * - {@link #INDENT_OBJECTS}: only objects and arrays fields are indented
+ *
+ *
+ * @param indentType the result indentation type
+ * @return the default options
+ */
+ public static JSONOptions setDefaultIndentationType(short indentType) {
+ JSONOptions options = JSONOptions.getDefault();
+ options.resultIndentationType = indentType;
+ return options;
+ }
+
+ /**
+ * Set the result indentation type. The possible types are:
+ *
+ * - {@link #INDENT_DEFAULT}: the default indentation type
+ * - {@link #INDENT_ALL}: all fields are indented
+ * - {@link #INDENT_OBJECTS}: only objects and arrays fields are indented
+ *
+ *
+ * @param indentType the result indentation type
+ * @return this
+ */
+ public JSONOptions setIndentationType(short indentType) {
+ this.resultIndentationType = indentType;
+ return this;
+ }
+
+ /**
+ * Return the result indentation type.
+ *
+ * @return the result indentation type
+ */
+ public short getIndentationType() {
+ return resultIndentationType;
+ }
+}
diff --git a/src/org/json/JSONPointer.java b/src/org/json/JSONPointer.java
new file mode 100644
index 000000000..a7b3dbc2a
--- /dev/null
+++ b/src/org/json/JSONPointer.java
@@ -0,0 +1,290 @@
+package org.json;
+
+import static java.lang.String.format;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/*
+Copyright (c) 2002 JSON.org
+Copyright (c) 2019 Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+/**
+ * A JSON Pointer is a simple query language defined for JSON documents by
+ * RFC 6901.
+ *
+ * In a nutshell, JSONPointer allows the user to navigate into a JSON document
+ * using strings, and retrieve targeted objects, like a simple form of XPATH.
+ * Path segments are separated by the '/' char, which signifies the root of
+ * the document when it appears as the first char of the string. Array
+ * elements are navigated using ordinals, counting from 0. JSONPointer strings
+ * may be extended to any arbitrary number of segments. If the navigation
+ * is successful, the matched item is returned. A matched item may be a
+ * JSONObject, a JSONArray, or a JSON value. If the JSONPointer string building
+ * fails, an appropriate exception is thrown. If the navigation fails to find
+ * a match, a JSONPointerException is thrown.
+ *
+ * @author JSON.org
+ * @version 1.4
+ */
+public class JSONPointer {
+
+ // used for URL encoding and decoding
+ private static final String ENCODING = "utf-8";
+
+ /**
+ * This class allows the user to build a JSONPointer in steps, using
+ * exactly one segment in each step.
+ */
+ public static class Builder {
+
+ // Segments for the eventual JSONPointer string
+ private final List refTokens = new ArrayList<>();
+
+ /**
+ * Creates a {@code JSONPointer} instance using the tokens previously set using the
+ * {@link #append(String)} method calls.
+ */
+ public JSONPointer build() {
+ return new JSONPointer(this.refTokens);
+ }
+
+ /**
+ * Adds an arbitrary token to the list of reference tokens. It can be any non-null value.
+ *
+ * Unlike in the case of JSON string or URI fragment representation of JSON pointers, the
+ * argument of this method MUST NOT be escaped. If you want to query the property called
+ * {@code "a~b"} then you should simply pass the {@code "a~b"} string as-is, there is no
+ * need to escape it as {@code "a~0b"}.
+ *
+ * @param token the new token to be appended to the list
+ * @return {@code this}
+ * @throws NullPointerException if {@code token} is null
+ */
+ public Builder append(String token) {
+ if (token == null) {
+ throw new NullPointerException("token cannot be null");
+ }
+ this.refTokens.add(token);
+ return this;
+ }
+
+ /**
+ * Adds an integer to the reference token list. Although not necessarily, mostly this token will
+ * denote an array index.
+ *
+ * @param arrayIndex the array index to be added to the token list
+ * @return {@code this}
+ */
+ public Builder append(int arrayIndex) {
+ this.refTokens.add(String.valueOf(arrayIndex));
+ return this;
+ }
+ }
+
+ /**
+ * Static factory method for {@link Builder}. Example usage:
+ *
+ *
+ * JSONPointer pointer = JSONPointer.builder()
+ * .append("obj")
+ * .append("other~key").append("another/key")
+ * .append("\"")
+ * .append(0)
+ * .build();
+ *
+ *
+ * @return a builder instance which can be used to construct a {@code JSONPointer} instance by chained
+ * {@link Builder#append(String)} calls.
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ // Segments for the JSONPointer string
+ private final List refTokens;
+
+ /**
+ * Pre-parses and initializes a new {@code JSONPointer} instance. If you want to
+ * evaluate the same JSON Pointer on different JSON documents then it is recommended
+ * to keep the {@code JSONPointer} instances due to performance considerations.
+ *
+ * @param pointer the JSON String or URI Fragment representation of the JSON pointer.
+ * @throws IllegalArgumentException if {@code pointer} is not a valid JSON pointer
+ */
+ public JSONPointer(final String pointer) {
+ if (pointer == null) {
+ throw new NullPointerException("pointer cannot be null");
+ }
+ if (pointer.isEmpty() || pointer.equals("#")) {
+ this.refTokens = Collections.emptyList();
+ return;
+ }
+ String refs;
+ if (pointer.startsWith("#/")) {
+ refs = pointer.substring(2);
+ try {
+ refs = URLDecoder.decode(refs, ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ } else if (pointer.startsWith("/")) {
+ refs = pointer.substring(1);
+ } else {
+ throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'");
+ }
+ this.refTokens = new ArrayList<>();
+ int slashIdx = -1;
+ int prevSlashIdx = 0;
+ do {
+ prevSlashIdx = slashIdx + 1;
+ slashIdx = refs.indexOf('/', prevSlashIdx);
+ if (prevSlashIdx == slashIdx || prevSlashIdx == refs.length()) {
+ // found 2 slashes in a row ( obj//next )
+ // or single slash at the end of a string ( obj/test/ )
+ this.refTokens.add("");
+ } else if (slashIdx >= 0) {
+ final String token = refs.substring(prevSlashIdx, slashIdx);
+ this.refTokens.add(unescape(token));
+ } else {
+ // last item after separator, or no separator at all.
+ final String token = refs.substring(prevSlashIdx);
+ this.refTokens.add(unescape(token));
+ }
+ } while (slashIdx >= 0);
+ // using split does not take into account consecutive separators or "ending nulls"
+ //for (String token : refs.split("/")) {
+ // this.refTokens.add(unescape(token));
+ //}
+ }
+
+ public JSONPointer(List refTokens) {
+ this.refTokens = new ArrayList<>(refTokens);
+ }
+
+ private String unescape(String token) {
+ return token.replace("~1", "/").replace("~0", "~").replace("\\\"", "\"").replace("\\\\", "\\");
+ }
+
+ /**
+ * Evaluates this JSON Pointer on the given {@code document}. The {@code document}
+ * is usually a {@link JSONObject} or a {@link JSONArray} instance, but the empty
+ * JSON Pointer ({@code ""}) can be evaluated on any JSON values and in such case the
+ * returned value will be {@code document} itself.
+ *
+ * @param document the JSON document which should be the subject of querying.
+ * @return the result of the evaluation
+ * @throws JSONPointerException if an error occurs during evaluation
+ */
+ public Object queryFrom(Object document) throws JSONPointerException {
+ if (this.refTokens.isEmpty()) {
+ return document;
+ }
+ Object current = document;
+ for (String token : this.refTokens) {
+ if (current instanceof JSONObject) {
+ current = ((JSONObject) current).opt(unescape(token));
+ } else if (current instanceof JSONArray) {
+ current = readByIndexToken(current, token);
+ } else {
+ throw new JSONPointerException(format(
+ "value [%s] is not an array or object therefore its key %s cannot be resolved", current,
+ token));
+ }
+ }
+ return current;
+ }
+
+ /**
+ * Matches a JSONArray element by ordinal position
+ *
+ * @param current the JSONArray to be evaluated
+ * @param indexToken the array index in string form
+ * @return the matched object. If no matching item is found a
+ * @throws JSONPointerException is thrown if the index is out of bounds
+ */
+ private Object readByIndexToken(Object current, String indexToken) throws JSONPointerException {
+ try {
+ int index = Integer.parseInt(indexToken);
+ JSONArray currentArr = (JSONArray) current;
+ if (index >= currentArr.length()) {
+ throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index,
+ currentArr.length()));
+ }
+ try {
+ return currentArr.get(index);
+ } catch (JSONException e) {
+ throw new JSONPointerException("Error reading value at index position " + index, e);
+ }
+ } catch (NumberFormatException e) {
+ throw new JSONPointerException(format("%s is not an array index", indexToken), e);
+ }
+ }
+
+ /**
+ * Returns a string representing the JSONPointer path value using string
+ * representation
+ */
+ @Override
+ public String toString() {
+ StringBuilder rval = new StringBuilder("");
+ for (String token : this.refTokens) {
+ rval.append('/').append(escape(token));
+ }
+ return rval.toString();
+ }
+
+ /**
+ * Escapes path segment values to an unambiguous form.
+ * The escape char to be inserted is '~'. The chars to be escaped
+ * are ~, which maps to ~0, and /, which maps to ~1. Backslashes
+ * and double quote chars are also escaped.
+ *
+ * @param token the JSONPointer segment value to be escaped
+ * @return the escaped value for the token
+ */
+ private String escape(String token) {
+ return token.replace("~", "~0").replace("/", "~1").replace("\\", "\\\\").replace("\"", "\\\"");
+ }
+
+ /**
+ * Returns a string representing the JSONPointer path value using URI
+ * fragment identifier representation
+ */
+ public String toURIFragment() {
+ try {
+ StringBuilder rval = new StringBuilder("#");
+ for (String token : this.refTokens) {
+ rval.append('/').append(URLEncoder.encode(token, ENCODING));
+ }
+ return rval.toString();
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/JSONPointerException.java b/src/org/json/JSONPointerException.java
similarity index 100%
rename from JSONPointerException.java
rename to src/org/json/JSONPointerException.java
diff --git a/JSONPropertyIgnore.java b/src/org/json/JSONPropertyIgnore.java
similarity index 100%
rename from JSONPropertyIgnore.java
rename to src/org/json/JSONPropertyIgnore.java
diff --git a/JSONPropertyName.java b/src/org/json/JSONPropertyName.java
similarity index 100%
rename from JSONPropertyName.java
rename to src/org/json/JSONPropertyName.java
diff --git a/JSONString.java b/src/org/json/JSONString.java
similarity index 100%
rename from JSONString.java
rename to src/org/json/JSONString.java
diff --git a/JSONStringer.java b/src/org/json/JSONStringer.java
similarity index 100%
rename from JSONStringer.java
rename to src/org/json/JSONStringer.java
diff --git a/src/org/json/JSONTokener.java b/src/org/json/JSONTokener.java
new file mode 100644
index 000000000..fe664a0eb
--- /dev/null
+++ b/src/org/json/JSONTokener.java
@@ -0,0 +1,522 @@
+package org.json;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+
+/*
+Copyright (c) 2002 JSON.org
+Copyright (c) 2019 Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+/**
+ * A JSONTokener takes a source string and extracts characters and tokens from
+ * it. It is used by the JSONObject and JSONArray constructors to parse
+ * JSON source strings.
+ *
+ * @author JSON.org
+ * @version 1.4
+ */
+public class JSONTokener {
+ /** current read character position on the current line. */
+ private long character;
+ /** flag to indicate if the end of the input has been found. */
+ private boolean eof;
+ /** current read index of the input. */
+ private long index;
+ /** current line of the input. */
+ private long line;
+ /** previous character read from the input. */
+ private char previous;
+ /** Reader for the input. */
+ private final Reader reader;
+ /** flag to indicate that a previous character was requested. */
+ private boolean usePrevious;
+ /** the number of characters read in the previous line. */
+ private long characterPreviousLine;
+
+ /**
+ * Construct a JSONTokener from a Reader. The caller must close the Reader.
+ *
+ * @param reader A reader.
+ */
+ public JSONTokener(Reader reader) {
+ this.reader = reader.markSupported() ? reader : new BufferedReader(reader);
+ this.eof = false;
+ this.usePrevious = false;
+ this.previous = 0;
+ this.index = 0;
+ this.character = 1;
+ this.characterPreviousLine = 0;
+ this.line = 1;
+ }
+
+ /**
+ * Construct a JSONTokener from an InputStream. The caller must close the input stream.
+ *
+ * @param inputStream The source.
+ */
+ public JSONTokener(InputStream inputStream) {
+ this(new InputStreamReader(inputStream));
+ }
+
+ /**
+ * Construct a JSONTokener from a string.
+ *
+ * @param s A source string.
+ */
+ public JSONTokener(String s) {
+ this(new StringReader(s));
+ }
+
+ /**
+ * Back up one character. This provides a sort of lookahead capability,
+ * so that you can test for a digit or letter before attempting to parse
+ * the next number or identifier.
+ *
+ * @throws JSONException Thrown if trying to step back more than 1 step
+ * or if already at the start of the string
+ */
+ public void back() throws JSONException {
+ if (this.usePrevious || this.index <= 0) {
+ throw new JSONException("Stepping back two steps is not supported");
+ }
+ this.decrementIndexes();
+ this.usePrevious = true;
+ this.eof = false;
+ }
+
+ /**
+ * Decrements the indexes for the {@link #back()} method based on the previous character read.
+ */
+ private void decrementIndexes() {
+ this.index--;
+ if (this.previous == '\r' || this.previous == '\n') {
+ this.line--;
+ this.character = this.characterPreviousLine;
+ } else if (this.character > 0) {
+ this.character--;
+ }
+ }
+
+ /**
+ * Get the hex value of a character (base16).
+ *
+ * @param c A character between '0' and '9' or between 'A' and 'F' or
+ * between 'a' and 'f'.
+ * @return An int between 0 and 15, or -1 if c was not a hex digit.
+ */
+ public static int dehexchar(char c) {
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ }
+ if (c >= 'A' && c <= 'F') {
+ return c - ('A' - 10);
+ }
+ if (c >= 'a' && c <= 'f') {
+ return c - ('a' - 10);
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if the end of the input has been reached.
+ *
+ * @return true if at the end of the file and we didn't step back
+ */
+ public boolean end() {
+ return this.eof && !this.usePrevious;
+ }
+
+ /**
+ * Determine if the source string still contains characters that next()
+ * can consume.
+ *
+ * @return true if not yet at the end of the source.
+ * @throws JSONException thrown if there is an error stepping forward
+ * or backward while checking for more data.
+ */
+ public boolean more() throws JSONException {
+ if (this.usePrevious) {
+ return true;
+ }
+ try {
+ this.reader.mark(1);
+ } catch (IOException e) {
+ throw new JSONException("Unable to preserve stream position", e);
+ }
+ try {
+ // -1 is EOF, but next() can not consume the null character '\0'
+ if (this.reader.read() <= 0) {
+ this.eof = true;
+ return false;
+ }
+ this.reader.reset();
+ } catch (IOException e) {
+ throw new JSONException("Unable to read the next character from the stream", e);
+ }
+ return true;
+ }
+
+ /**
+ * Get the next character in the source string.
+ *
+ * @return The next character, or 0 if past the end of the source string.
+ * @throws JSONException Thrown if there is an error reading the source string.
+ */
+ public char next() throws JSONException {
+ int c;
+ if (this.usePrevious) {
+ this.usePrevious = false;
+ c = this.previous;
+ } else {
+ try {
+ c = this.reader.read();
+ } catch (IOException exception) {
+ throw new JSONException(exception);
+ }
+ }
+ if (c <= 0) { // End of stream
+ this.eof = true;
+ return 0;
+ }
+ this.incrementIndexes(c);
+ this.previous = (char) c;
+ return this.previous;
+ }
+
+ /**
+ * Increments the internal indexes according to the previous character
+ * read and the character passed as the current character.
+ *
+ * @param c the current character read.
+ */
+ private void incrementIndexes(int c) {
+ if (c > 0) {
+ this.index++;
+ if (c == '\r') {
+ this.line++;
+ this.characterPreviousLine = this.character;
+ this.character = 0;
+ } else if (c == '\n') {
+ if (this.previous != '\r') {
+ this.line++;
+ this.characterPreviousLine = this.character;
+ }
+ this.character = 0;
+ } else {
+ this.character++;
+ }
+ }
+ }
+
+ /**
+ * Consume the next character, and check that it matches a specified
+ * character.
+ *
+ * @param c The character to match.
+ * @return The character.
+ * @throws JSONException if the character does not match.
+ */
+ public char next(char c) throws JSONException {
+ char n = this.next();
+ if (n != c) {
+ if (n > 0) {
+ throw this.syntaxError("Expected '" + c + "' and instead saw '" + n + "'");
+ }
+ throw this.syntaxError("Expected '" + c + "' and instead saw ''");
+ }
+ return n;
+ }
+
+ /**
+ * Get the next n characters.
+ *
+ * @param n The number of characters to take.
+ * @return A string of n characters.
+ * @throws JSONException Substring bounds error if there are not n characters remaining in the source string.
+ */
+ public String next(int n) throws JSONException {
+ if (n == 0) {
+ return "";
+ }
+
+ char[] chars = new char[n];
+ int pos = 0;
+
+ while (pos < n) {
+ chars[pos] = this.next();
+ if (this.end()) {
+ throw this.syntaxError("Substring bounds error");
+ }
+ pos += 1;
+ }
+ return new String(chars);
+ }
+
+ /**
+ * Get the next char in the string, skipping whitespace.
+ *
+ * @throws JSONException Thrown if there is an error reading the source string.
+ * @return A character, or 0 if there are no more characters.
+ */
+ public char nextClean() throws JSONException {
+ for (;;) {
+ char c = this.next();
+ if (c == 0 || c > ' ') {
+ return c;
+ }
+ }
+ }
+
+ /**
+ * Return the characters up to the next close quote character.
+ * Backslash processing is done. The formal JSON format does not
+ * allow strings in single quotes, but an implementation is allowed to
+ * accept them.
+ *
+ * @param quote The quoting character, either " (double quote) or
+ * ' (single quote).
+ * @return A String.
+ * @throws JSONException Unterminated string.
+ */
+ public String nextString(char quote) throws JSONException {
+ char c;
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ c = this.next();
+ switch (c) {
+ case 0:
+ case '\n':
+ case '\r':
+ throw this.syntaxError("Unterminated string");
+ case '\\':
+ c = this.next();
+ switch (c) {
+ case 'b':
+ sb.append('\b');
+ break;
+ case 't':
+ sb.append('\t');
+ break;
+ case 'n':
+ sb.append('\n');
+ break;
+ case 'f':
+ sb.append('\f');
+ break;
+ case 'r':
+ sb.append('\r');
+ break;
+ case 'u':
+ try {
+ sb.append((char) Integer.parseInt(this.next(4), 16));
+ } catch (NumberFormatException e) {
+ throw this.syntaxError("Illegal escape.", e);
+ }
+ break;
+ case '"':
+ case '\'':
+ case '\\':
+ case '/':
+ sb.append(c);
+ break;
+ default:
+ throw this.syntaxError("Illegal escape.");
+ }
+ break;
+ default:
+ if (c == quote) {
+ return sb.toString();
+ }
+ sb.append(c);
+ }
+ }
+ }
+
+ /**
+ * Get the text up but not including the specified character or the
+ * end of line, whichever comes first.
+ *
+ * @param delimiter A delimiter character.
+ * @return A string.
+ * @throws JSONException Thrown if there is an error while searching
+ * for the delimiter
+ */
+ public String nextTo(char delimiter) throws JSONException {
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ char c = this.next();
+ if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
+ if (c != 0) {
+ this.back();
+ }
+ return sb.toString().trim();
+ }
+ sb.append(c);
+ }
+ }
+
+ /**
+ * Get the text up but not including one of the specified delimiter
+ * characters or the end of line, whichever comes first.
+ *
+ * @param delimiters A set of delimiter characters.
+ * @return A string, trimmed.
+ * @throws JSONException Thrown if there is an error while searching
+ * for the delimiter
+ */
+ public String nextTo(String delimiters) throws JSONException {
+ char c;
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ c = this.next();
+ if (delimiters.indexOf(c) >= 0 || c == 0
+ || c == '\n' || c == '\r') {
+ if (c != 0) {
+ this.back();
+ }
+ return sb.toString().trim();
+ }
+ sb.append(c);
+ }
+ }
+
+ /**
+ * Get the next value. The value can be a Boolean, Double, Integer,
+ * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
+ *
+ * @throws JSONException If syntax error.
+ *
+ * @return An object.
+ */
+ public Object nextValue() throws JSONException {
+ char c = this.nextClean();
+ String string;
+
+ switch (c) {
+ case '"':
+ case '\'':
+ return this.nextString(c);
+ case '{':
+ this.back();
+ return new JSONObject(this);
+ case '[':
+ this.back();
+ return new JSONArray(this);
+ }
+
+ /*
+ * Handle unquoted text. This could be the values true, false, or
+ * null, or it can be a number. An implementation (such as this one)
+ * is allowed to also accept non-standard forms.
+ *
+ * Accumulate characters until we reach the end of the text or a
+ * formatting character.
+ */
+ StringBuilder sb = new StringBuilder();
+ while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
+ sb.append(c);
+ c = this.next();
+ }
+ this.back();
+
+ string = sb.toString().trim();
+ if ("".equals(string)) {
+ throw this.syntaxError("Missing value");
+ }
+ return JSONObject.stringToValue(string);
+ }
+
+ /**
+ * Skip characters until the next character is the requested character.
+ * If the requested character is not found, no characters are skipped.
+ *
+ * @param to A character to skip to.
+ * @return The requested character, or zero if the requested character
+ * is not found.
+ * @throws JSONException Thrown if there is an error while searching
+ * for the to character
+ */
+ public char skipTo(char to) throws JSONException {
+ char c;
+ try {
+ long startIndex = this.index;
+ long startCharacter = this.character;
+ long startLine = this.line;
+ this.reader.mark(1000000);
+ do {
+ c = this.next();
+ if (c == 0) {
+ // in some readers, reset() may throw an exception if
+ // the remaining portion of the input is greater than
+ // the mark size (1,000,000 above).
+ this.reader.reset();
+ this.index = startIndex;
+ this.character = startCharacter;
+ this.line = startLine;
+ return 0;
+ }
+ } while (c != to);
+ this.reader.mark(1);
+ } catch (IOException exception) {
+ throw new JSONException(exception);
+ }
+ this.back();
+ return c;
+ }
+
+ /**
+ * Make a JSONException to signal a syntax error.
+ *
+ * @param message The error message.
+ * @return A JSONException object, suitable for throwing
+ */
+ public JSONException syntaxError(String message) {
+ return new JSONException(message + this.toString());
+ }
+
+ /**
+ * Make a JSONException to signal a syntax error.
+ *
+ * @param message The error message.
+ * @param causedBy The throwable that caused the error.
+ * @return A JSONException object, suitable for throwing
+ */
+ public JSONException syntaxError(String message, Throwable causedBy) {
+ return new JSONException(message + this.toString(), causedBy);
+ }
+
+ /**
+ * Make a printable string of this JSONTokener.
+ *
+ * @return " at {index} [character {character} line {line}]"
+ */
+ @Override
+ public String toString() {
+ return " at " + this.index + " [character " + this.character + " line "
+ + this.line + "]";
+ }
+}
diff --git a/JSONWriter.java b/src/org/json/JSONWriter.java
similarity index 100%
rename from JSONWriter.java
rename to src/org/json/JSONWriter.java
diff --git a/src/org/json/Main.java b/src/org/json/Main.java
new file mode 100644
index 000000000..1b868c512
--- /dev/null
+++ b/src/org/json/Main.java
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 2018 Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+package org.json;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.PropertyResourceBundle;
+
+/**
+ * Main class, only used to give some informations about the version of the library on the command line.
+ *
+ * @since 1.0
+ */
+public class Main {
+ public static void main(String[] args) {
+ URL url = Main.class.getResource("json.properties");
+ try {
+ PropertyResourceBundle prb = new PropertyResourceBundle(url.openStream());
+ String version = prb.getString("version");
+ String date = prb.getString("date");
+ System.out.println("JSON version " + version + " build on " + date);
+ System.out.println("Distributed under the JSON License");
+ System.out.println("(This is a fork of https://github.com/stleary/JSON-java)");
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/Property.java b/src/org/json/Property.java
similarity index 100%
rename from Property.java
rename to src/org/json/Property.java
diff --git a/src/org/json/XML.java b/src/org/json/XML.java
new file mode 100644
index 000000000..0b371cad0
--- /dev/null
+++ b/src/org/json/XML.java
@@ -0,0 +1,663 @@
+package org.json;
+
+/*
+Copyright (c) 2015 JSON.org
+Copyright (c) 2018, 2019 Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Iterator;
+
+/**
+ * This provides static methods to convert an XML text into a JSONObject, and to
+ * covert a JSONObject into an XML text.
+ *
+ * @author JSON.org
+ * @version 1.4
+ */
+public class XML {
+ /** The Character '&'. */
+ public static final Character AMP = '&';
+
+ /** The Character '''. */
+ public static final Character APOS = '\'';
+
+ /** The Character '!'. */
+ public static final Character BANG = '!';
+
+ /** The Character '='. */
+ public static final Character EQ = '=';
+
+ /** The Character '>'. */
+ public static final Character GT = '>';
+
+ /** The Character '<'. */
+ public static final Character LT = '<';
+
+ /** The Character '?'. */
+ public static final Character QUEST = '?';
+
+ /** The Character '"'. */
+ public static final Character QUOT = '"';
+
+ /** The Character '/'. */
+ public static final Character SLASH = '/';
+
+ /**
+ * Creates an iterator for navigating Code Points in a string instead of
+ * characters. Once Java7 support is dropped, this can be replaced with
+ *
+ * string.codePoints()
+ *
+ * which is available in Java8 and above.
+ *
+ * @see http://stackoverflow.com/a/21791059/6030888
+ */
+ private static Iterable codePointIterator(final String string) {
+ return new Iterable() {
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+ private int nextIndex = 0;
+ private int length = string.length();
+
+ @Override
+ public boolean hasNext() {
+ return this.nextIndex < this.length;
+ }
+
+ @Override
+ public Integer next() {
+ int result = string.codePointAt(this.nextIndex);
+ this.nextIndex += Character.charCount(result);
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Replace special characters with XML escapes:
+ *
+ *
+ * & (ampersand) is replaced by &
+ * < (less than) is replaced by <
+ * > (greater than) is replaced by >
+ * " (double quote) is replaced by "
+ * ' (single quote / apostrophe) is replaced by '
+ *
+ *
+ * @param string
+ * The string to be escaped.
+ * @return The escaped string.
+ */
+ public static String escape(String string) {
+ StringBuilder sb = new StringBuilder(string.length());
+ for (final int cp : codePointIterator(string)) {
+ switch (cp) {
+ case '&':
+ sb.append("&");
+ break;
+ case '<':
+ sb.append("<");
+ break;
+ case '>':
+ sb.append(">");
+ break;
+ case '"':
+ sb.append(""");
+ break;
+ case '\'':
+ sb.append("'");
+ break;
+ default:
+ if (mustEscape(cp)) {
+ sb.append("");
+ sb.append(Integer.toHexString(cp));
+ sb.append(';');
+ } else {
+ sb.appendCodePoint(cp);
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * @param cp code point to test
+ * @return true if the code point is not valid for an XML
+ */
+ private static boolean mustEscape(int cp) {
+ /* Valid range from https://www.w3.org/TR/REC-xml/#charsets
+ *
+ * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
+ *
+ * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
+ */
+ // isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F)
+ // all ISO control characters are out of range except tabs and new lines
+ return (Character.isISOControl(cp)
+ && cp != 0x9
+ && cp != 0xA
+ && cp != 0xD) || !( // valid the range of acceptable characters that aren't control
+ (cp >= 0x20 && cp <= 0xD7FF)
+ || (cp >= 0xE000 && cp <= 0xFFFD)
+ || (cp >= 0x10000 && cp <= 0x10FFFF));
+ }
+
+ /**
+ * Removes XML escapes from the string.
+ *
+ * @param string
+ * string to remove escapes from
+ * @return string with converted entities
+ */
+ public static String unescape(String string) {
+ StringBuilder sb = new StringBuilder(string.length());
+ for (int i = 0, length = string.length(); i < length; i++) {
+ char c = string.charAt(i);
+ if (c == '&') {
+ final int semic = string.indexOf(';', i);
+ if (semic > i) {
+ final String entity = string.substring(i + 1, semic);
+ sb.append(XMLTokener.unescapeEntity(entity));
+ // skip past the entity we just parsed.
+ i += entity.length() + 1;
+ } else {
+ // this shouldn't happen in most cases since the parser
+ // errors on unclosed entries.
+ sb.append(c);
+ }
+ } else {
+ // not part of an entity
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Throw an exception if the string contains whitespace. Whitespace is not
+ * allowed in tagNames and attributes.
+ *
+ * @param string
+ * A string.
+ * @throws JSONException Thrown if the string contains whitespace or is empty.
+ */
+ public static void noSpace(String string) throws JSONException {
+ int i, length = string.length();
+ if (length == 0) {
+ throw new JSONException("Empty string.");
+ }
+ for (i = 0; i < length; i += 1) {
+ if (Character.isWhitespace(string.charAt(i))) {
+ throw new JSONException("'" + string + "' contains a space character.");
+ }
+ }
+ }
+
+ /**
+ * Scan the content following the named tag, attaching it to the context.
+ *
+ * @param x
+ * The XMLTokener containing the source string.
+ * @param context
+ * The JSONObject that will include the new material.
+ * @param name
+ * The tag name.
+ * @return true if the close tag is processed.
+ * @throws JSONException
+ */
+ private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings) throws JSONException {
+ char c;
+ int i;
+ JSONObject jsonobject;
+ String string;
+ String tagName;
+ Object token;
+
+ // Test for and skip past these forms:
+ //
+ //
+ //
+ // ... ?>
+ // Report errors for these forms:
+ // <>
+ // <=
+ // <<
+ token = x.nextToken();
+
+ // ");
+ return false;
+ }
+ x.back();
+ } else if (c == '[') {
+ token = x.nextToken();
+ if ("CDATA".equals(token)) {
+ if (x.next() == '[') {
+ string = x.nextCDATA();
+ if (string.length() > 0) {
+ context.accumulate("content", string);
+ }
+ return false;
+ }
+ }
+ throw x.syntaxError("Expected 'CDATA['");
+ }
+ i = 1;
+ do {
+ token = x.nextMeta();
+ if (token == null) {
+ throw x.syntaxError("Missing '>' after ' 0);
+ return false;
+ } else if (token == QUEST) {
+
+ //
+ x.skipPast("?>");
+ return false;
+ } else if (token == SLASH) {
+
+ // Close tag
+ token = x.nextToken();
+ if (name == null) {
+ throw x.syntaxError("Mismatched close tag " + token);
+ }
+ if (!token.equals(name)) {
+ throw x.syntaxError("Mismatched " + name + " and " + token);
+ }
+ if (x.nextToken() != GT) {
+ throw x.syntaxError("Misshaped close tag");
+ }
+ return true;
+
+ } else if (token instanceof Character) {
+ throw x.syntaxError("Misshaped tag");
+
+ // Open tag <
+ } else {
+ tagName = (String) token;
+ token = null;
+ jsonobject = new JSONObject();
+ for (;;) {
+ if (token == null) {
+ token = x.nextToken();
+ }
+ // attribute = value
+ if (token instanceof String) {
+ string = (String) token;
+ token = x.nextToken();
+ if (token == EQ) {
+ token = x.nextToken();
+ if (!(token instanceof String)) {
+ throw x.syntaxError("Missing value");
+ }
+ jsonobject.accumulate(string, keepStrings ? ((String) token) : stringToValue((String) token));
+ token = null;
+ } else {
+ jsonobject.accumulate(string, "");
+ }
+
+ } else if (token == SLASH) {
+ // Empty tag <.../>
+ if (x.nextToken() != GT) {
+ throw x.syntaxError("Misshaped tag");
+ }
+ if (jsonobject.length() > 0) {
+ context.accumulate(tagName, jsonobject);
+ } else {
+ context.accumulate(tagName, "");
+ }
+ return false;
+
+ } else if (token == GT) {
+ // Content, between <...> and
+ for (;;) {
+ token = x.nextContent();
+ if (token == null) {
+ if (tagName != null) {
+ throw x.syntaxError("Unclosed tag " + tagName);
+ }
+ return false;
+ } else if (token instanceof String) {
+ string = (String) token;
+ if (string.length() > 0) {
+ jsonobject.accumulate("content",
+ keepStrings ? string : stringToValue(string));
+ }
+
+ } else if (token == LT) {
+ // Nested element
+ if (parse(x, jsonobject, tagName, keepStrings)) {
+ if (jsonobject.length() == 0) {
+ context.accumulate(tagName, "");
+ } else if (jsonobject.length() == 1
+ && jsonobject.opt("content") != null) {
+ context.accumulate(tagName,
+ jsonobject.opt("content"));
+ } else {
+ context.accumulate(tagName, jsonobject);
+ }
+ return false;
+ }
+ }
+ }
+ } else {
+ throw x.syntaxError("Misshaped tag");
+ }
+ }
+ }
+ }
+
+ /**
+ * This method is the same as {@link JSONObject#stringToValue(String)}.
+ *
+ * @param string String to convert
+ * @return JSON value of this string or the string
+ */
+ // To maintain compatibility with the Android API, this method is a direct copy of
+ // the one in JSONObject. Changes made here should be reflected there.
+ public static Object stringToValue(String string) {
+ if (string.equals("")) {
+ return string;
+ }
+ if (string.equalsIgnoreCase("true")) {
+ return Boolean.TRUE;
+ }
+ if (string.equalsIgnoreCase("false")) {
+ return Boolean.FALSE;
+ }
+ if (string.equalsIgnoreCase("null")) {
+ return JSONObject.NULL;
+ }
+
+ /*
+ * If it might be a number, try converting it. If a number cannot be
+ * produced, then the value will just be a string.
+ */
+ char initial = string.charAt(0);
+ if ((initial >= '0' && initial <= '9') || initial == '-') {
+ try {
+ // if we want full Big Number support this block can be replaced with:
+ // return stringToNumber(string);
+ if (string.indexOf('.') > -1 || string.indexOf('e') > -1 || string.indexOf('E') > -1 || "-0".equals(string)) {
+ Double d = Double.valueOf(string);
+ if (!d.isInfinite() && !d.isNaN()) {
+ return d;
+ }
+ } else {
+ Long myLong = Long.valueOf(string);
+ if (string.equals(myLong.toString())) {
+ if (myLong.longValue() == myLong.intValue()) {
+ return myLong.intValue();
+ }
+ return myLong;
+ }
+ }
+ } catch (NumberFormatException ignore) {
+ }
+ }
+ return string;
+ }
+
+ /**
+ * Convert a well-formed (but not necessarily valid) XML string into a
+ * JSONObject. Some information may be lost in this transformation because
+ * JSON is a data format and XML is a document format. XML uses elements,
+ * attributes, and content text, while JSON uses unordered collections of
+ * name/value pairs and arrays of values. JSON does not does not like to
+ * distinguish between elements and attributes. Sequences of similar
+ * elements are represented as JSONArrays. Content text may be placed in a
+ * "content" member. Comments, prologs, DTDs, and <[ [ ]]>
+ * are ignored.
+ *
+ * @param string
+ * The source string.
+ * @return A JSONObject containing the structured data from the XML string.
+ * @throws JSONException Thrown if there is an errors while parsing the string
+ */
+ public static JSONObject toJSONObject(String string) throws JSONException {
+ return toJSONObject(string, false);
+ }
+
+ /**
+ * Convert a well-formed (but not necessarily valid) XML into a
+ * JSONObject. Some information may be lost in this transformation because
+ * JSON is a data format and XML is a document format. XML uses elements,
+ * attributes, and content text, while JSON uses unordered collections of
+ * name/value pairs and arrays of values. JSON does not does not like to
+ * distinguish between elements and attributes. Sequences of similar
+ * elements are represented as JSONArrays. Content text may be placed in a
+ * "content" member. Comments, prologs, DTDs, and <[ [ ]]>
+ * are ignored.
+ *
+ * @param reader The XML source reader.
+ * @return A JSONObject containing the structured data from the XML string.
+ * @throws JSONException Thrown if there is an errors while parsing the string
+ */
+ public static JSONObject toJSONObject(Reader reader) throws JSONException {
+ return toJSONObject(reader, false);
+ }
+
+ /**
+ * Convert a well-formed (but not necessarily valid) XML into a
+ * JSONObject. Some information may be lost in this transformation because
+ * JSON is a data format and XML is a document format. XML uses elements,
+ * attributes, and content text, while JSON uses unordered collections of
+ * name/value pairs and arrays of values. JSON does not does not like to
+ * distinguish between elements and attributes. Sequences of similar
+ * elements are represented as JSONArrays. Content text may be placed in a
+ * "content" member. Comments, prologs, DTDs, and <[ [ ]]>
+ * are ignored.
+ *
+ * All values are converted as strings, for 1, 01, 29.0 will not be coerced to
+ * numbers but will instead be the exact value as seen in the XML document.
+ *
+ * @param reader The XML source reader.
+ * @param keepStrings If true, then values will not be coerced into boolean
+ * or numeric values and will instead be left as strings
+ * @return A JSONObject containing the structured data from the XML string.
+ * @throws JSONException Thrown if there is an errors while parsing the string
+ */
+ public static JSONObject toJSONObject(Reader reader, boolean keepStrings) throws JSONException {
+ JSONObject jo = new JSONObject();
+ XMLTokener x = new XMLTokener(reader);
+ while (x.more()) {
+ x.skipPast("<");
+ if (x.more()) {
+ parse(x, jo, null, keepStrings);
+ }
+ }
+ return jo;
+ }
+
+ /**
+ * Convert a well-formed (but not necessarily valid) XML string into a
+ * JSONObject. Some information may be lost in this transformation because
+ * JSON is a data format and XML is a document format. XML uses elements,
+ * attributes, and content text, while JSON uses unordered collections of
+ * name/value pairs and arrays of values. JSON does not does not like to
+ * distinguish between elements and attributes. Sequences of similar
+ * elements are represented as JSONArrays. Content text may be placed in a
+ * "content" member. Comments, prologs, DTDs, and <[ [ ]]>
+ * are ignored.
+ *
+ * All values are converted as strings, for 1, 01, 29.0 will not be coerced to
+ * numbers but will instead be the exact value as seen in the XML document.
+ *
+ * @param string The source string.
+ * @param keepStrings If true, then values will not be coerced into boolean or numeric values and will instead be left as strings
+ * @return A JSONObject containing the structured data from the XML string.
+ * @throws JSONException Thrown if there is an errors while parsing the string
+ */
+ public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
+ return toJSONObject(new StringReader(string), keepStrings);
+ }
+
+ /**
+ * Convert a JSONObject into a well-formed, element-normal XML string.
+ *
+ * @param object
+ * A JSONObject.
+ * @return A string.
+ * @throws JSONException Thrown if there is an error parsing the string
+ */
+ public static String toString(Object object) throws JSONException {
+ return toString(object, null);
+ }
+
+ /**
+ * Convert a JSONObject into a well-formed, element-normal XML string.
+ *
+ * @param object
+ * A JSONObject.
+ * @param tagName
+ * The optional name of the enclosing tag.
+ * @return A string.
+ * @throws JSONException Thrown if there is an error parsing the string
+ */
+ public static String toString(final Object object, final String tagName)
+ throws JSONException {
+ StringBuilder sb = new StringBuilder();
+ JSONArray ja;
+ JSONObject jo;
+ String string;
+
+ if (object instanceof JSONObject) {
+
+ // Emit
+ if (tagName != null) {
+ sb.append('<');
+ sb.append(tagName);
+ sb.append('>');
+ }
+
+ // Loop thru the keys.
+ // don't use the new entrySet accessor to maintain Android Support
+ jo = (JSONObject) object;
+ for (final String key : jo.keySet()) {
+ Object value = jo.opt(key);
+ if (value == null) {
+ value = "";
+ } else if (value.getClass().isArray()) {
+ value = new JSONArray(value);
+ }
+
+ // Emit content in body
+ if ("content".equals(key)) {
+ if (value instanceof JSONArray) {
+ ja = (JSONArray) value;
+ int jaLength = ja.length();
+ // don't use the new iterator API to maintain support for Android
+ for (int i = 0; i < jaLength; i++) {
+ if (i > 0) {
+ sb.append('\n');
+ }
+ Object val = ja.opt(i);
+ sb.append(escape(val.toString()));
+ }
+ } else {
+ sb.append(escape(value.toString()));
+ }
+
+ // Emit an array of similar keys
+ } else if (value instanceof JSONArray) {
+ ja = (JSONArray) value;
+ int jaLength = ja.length();
+ // don't use the new iterator API to maintain support for Android
+ for (int i = 0; i < jaLength; i++) {
+ Object val = ja.opt(i);
+ if (val instanceof JSONArray) {
+ sb.append('<');
+ sb.append(key);
+ sb.append('>');
+ sb.append(toString(val));
+ sb.append("");
+ sb.append(key);
+ sb.append('>');
+ } else {
+ sb.append(toString(val, key));
+ }
+ }
+ } else if ("".equals(value)) {
+ sb.append('<');
+ sb.append(key);
+ sb.append("/>");
+
+ // Emit a new tag
+ } else {
+ sb.append(toString(value, key));
+ }
+ }
+ if (tagName != null) {
+
+ // Emit the close tag
+ sb.append("");
+ sb.append(tagName);
+ sb.append('>');
+ }
+ return sb.toString();
+
+ }
+
+ if (object != null && (object instanceof JSONArray || object.getClass().isArray())) {
+ if (object.getClass().isArray()) {
+ ja = new JSONArray(object);
+ } else {
+ ja = (JSONArray) object;
+ }
+ int jaLength = ja.length();
+ // don't use the new iterator API to maintain support for Android
+ for (int i = 0; i < jaLength; i++) {
+ Object val = ja.opt(i);
+ // XML does not have good support for arrays. If an array
+ // appears in a place where XML is lacking, synthesize an
+ // element.
+ sb.append(toString(val, tagName == null ? "array" : tagName));
+ }
+ return sb.toString();
+ }
+
+ string = (object == null) ? "null" : escape(object.toString());
+ return (tagName == null) ? "\"" + string + "\""
+ : (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName + ">" + string + "" + tagName + ">";
+
+ }
+}
diff --git a/src/org/json/XMLTokener.java b/src/org/json/XMLTokener.java
new file mode 100644
index 000000000..0a7b14804
--- /dev/null
+++ b/src/org/json/XMLTokener.java
@@ -0,0 +1,403 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+Copyright (c) 2019 Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+import java.io.Reader;
+import java.util.HashMap;
+
+/**
+ * The XMLTokener extends the JSONTokener to provide additional methods
+ * for the parsing of XML texts.
+ *
+ * @author JSON.org
+ * @version 1.4
+ */
+public class XMLTokener extends JSONTokener {
+ /** The table of entity values. It initially contains Character values for
+ * amp, apos, gt, lt, quot.
+ */
+ public static final HashMap entity;
+
+ static {
+ entity = new HashMap<>(8);
+ entity.put("amp", XML.AMP);
+ entity.put("apos", XML.APOS);
+ entity.put("gt", XML.GT);
+ entity.put("lt", XML.LT);
+ entity.put("quot", XML.QUOT);
+ }
+
+ /**
+ * Construct an XMLTokener from a Reader.
+ *
+ * @param r A source reader.
+ */
+ public XMLTokener(Reader r) {
+ super(r);
+ }
+
+ /**
+ * Construct an XMLTokener from a string.
+ *
+ * @param s A source string.
+ */
+ public XMLTokener(String s) {
+ super(s);
+ }
+
+ /**
+ * Get the text in the CDATA block.
+ *
+ * @return The string up to the ]]>.
+ * @throws JSONException If the ]]> is not found.
+ */
+ public String nextCDATA() throws JSONException {
+ char c;
+ int i;
+ StringBuilder sb = new StringBuilder();
+ while (more()) {
+ c = next();
+ sb.append(c);
+ i = sb.length() - 3;
+ if (i >= 0 && sb.charAt(i) == ']'
+ && sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') {
+ sb.setLength(i);
+ return sb.toString();
+ }
+ }
+ throw syntaxError("Unclosed CDATA");
+ }
+
+ /**
+ * Get the next XML outer token, trimming whitespace. There are two kinds
+ * of tokens: the '<' character which begins a markup tag, and the content
+ * text between markup tags.
+ *
+ * @return A string, or a '<' Character, or null if there is no more
+ * source text.
+ * @throws JSONException
+ */
+ public Object nextContent() throws JSONException {
+ char c;
+ StringBuilder sb;
+ do {
+ c = next();
+ } while (Character.isWhitespace(c));
+ if (c == 0) {
+ return null;
+ }
+ if (c == '<') {
+ return XML.LT;
+ }
+ sb = new StringBuilder();
+ for (;;) {
+ if (c == 0) {
+ return sb.toString().trim();
+ }
+ if (c == '<') {
+ back();
+ return sb.toString().trim();
+ }
+ if (c == '&') {
+ sb.append(nextEntity(c));
+ } else {
+ sb.append(c);
+ }
+ c = next();
+ }
+ }
+
+ /**
+ * Return the next entity. These entities are translated to Characters:
+ * & ' > < ".
+ *
+ * @param ampersand An ampersand character.
+ * @return A Character or an entity String if the entity is not recognized.
+ * @throws JSONException If missing ';' in XML entity.
+ */
+ public Object nextEntity(char ampersand) throws JSONException {
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ char c = next();
+ if (Character.isLetterOrDigit(c) || c == '#') {
+ sb.append(Character.toLowerCase(c));
+ } else if (c == ';') {
+ break;
+ } else {
+ throw syntaxError("Missing ';' in XML entity: &" + sb);
+ }
+ }
+ String string = sb.toString();
+ return unescapeEntity(string);
+ }
+
+ /**
+ * Unescapes an XML entity encoding;
+ *
+ * @param e entity (only the actual entity value, not the preceding & or ending ;
+ * @return
+ */
+ static String unescapeEntity(String e) {
+ // validate
+ if (e == null || e.isEmpty()) {
+ return "";
+ }
+ // if our entity is an encoded unicode point, parse it.
+ if (e.charAt(0) == '#') {
+ int cp;
+ if (e.charAt(1) == 'x') {
+ // hex encoded unicode
+ cp = Integer.parseInt(e.substring(2), 16);
+ } else {
+ // decimal encoded unicode
+ cp = Integer.parseInt(e.substring(1));
+ }
+ return new String(new int[] { cp }, 0, 1);
+ }
+ Character knownEntity = entity.get(e);
+ if (knownEntity == null) {
+ // we don't know the entity so keep it encoded
+ return '&' + e + ';';
+ }
+ return knownEntity.toString();
+ }
+
+ /**
+ * Returns the next XML meta token. This is used for skipping over
+ * and ...?> structures.
+ *
+ * @return Syntax characters (< > / = ! ?) are returned as
+ * Character, and strings and names are returned as Boolean. We don't care
+ * what the values actually are.
+ * @throws JSONException If a string is not properly closed or if the XML
+ * is badly structured.
+ */
+ public Object nextMeta() throws JSONException {
+ char c;
+ char q;
+ do {
+ c = next();
+ } while (Character.isWhitespace(c));
+ switch (c) {
+ case 0:
+ throw syntaxError("Misshaped meta tag");
+ case '<':
+ return XML.LT;
+ case '>':
+ return XML.GT;
+ case '/':
+ return XML.SLASH;
+ case '=':
+ return XML.EQ;
+ case '!':
+ return XML.BANG;
+ case '?':
+ return XML.QUEST;
+ case '"':
+ case '\'':
+ q = c;
+ for (;;) {
+ c = next();
+ if (c == 0) {
+ throw syntaxError("Unterminated string");
+ }
+ if (c == q) {
+ return Boolean.TRUE;
+ }
+ }
+ default:
+ for (;;) {
+ c = next();
+ if (Character.isWhitespace(c)) {
+ return Boolean.TRUE;
+ }
+ switch (c) {
+ case 0:
+ case '<':
+ case '>':
+ case '/':
+ case '=':
+ case '!':
+ case '?':
+ case '"':
+ case '\'':
+ back();
+ return Boolean.TRUE;
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the next XML Token. These tokens are found inside of angle
+ * brackets. It may be one of these characters: / &t; = ! ? or it
+ * may be a string wrapped in single quotes or double quotes, or it may be a
+ * name.
+ *
+ * @return a String or a Character.
+ * @throws JSONException If the XML is not well formed.
+ */
+ public Object nextToken() throws JSONException {
+ char c;
+ char q;
+ StringBuilder sb;
+ do {
+ c = next();
+ } while (Character.isWhitespace(c));
+ switch (c) {
+ case 0:
+ throw syntaxError("Misshaped element");
+ case '<':
+ throw syntaxError("Misplaced '<'");
+ case '>':
+ return XML.GT;
+ case '/':
+ return XML.SLASH;
+ case '=':
+ return XML.EQ;
+ case '!':
+ return XML.BANG;
+ case '?':
+ return XML.QUEST;
+
+// Quoted string
+ case '"':
+ case '\'':
+ q = c;
+ sb = new StringBuilder();
+ for (;;) {
+ c = next();
+ if (c == 0) {
+ throw syntaxError("Unterminated string");
+ }
+ if (c == q) {
+ return sb.toString();
+ }
+ if (c == '&') {
+ sb.append(nextEntity(c));
+ } else {
+ sb.append(c);
+ }
+ }
+ default:
+
+// Name
+ sb = new StringBuilder();
+ for (;;) {
+ sb.append(c);
+ c = next();
+ if (Character.isWhitespace(c)) {
+ return sb.toString();
+ }
+ switch (c) {
+ case 0:
+ return sb.toString();
+ case '>':
+ case '/':
+ case '=':
+ case '!':
+ case '?':
+ case '[':
+ case ']':
+ back();
+ return sb.toString();
+ case '<':
+ case '"':
+ case '\'':
+ throw syntaxError("Bad character in a name");
+ }
+ }
+ }
+ }
+
+ /**
+ * Skip characters until past the requested string.
+ * If it is not found, we are left at the end of the source with a result of false.
+ *
+ * @param to A string to skip past.
+ */
+ // The Android implementation of JSONTokener has a public method of public void skipPast(String to)
+ // even though ours does not have that method, to have API compatibility, our method in the subclass
+ // should match.
+ public void skipPast(String to) {
+ boolean b;
+ char c;
+ int i;
+ int j;
+ int offset = 0;
+ int length = to.length();
+ char[] circle = new char[length];
+
+ /*
+ * First fill the circle buffer with as many characters as are in the
+ * to string. If we reach an early end, bail.
+ */
+ for (i = 0; i < length; i += 1) {
+ c = next();
+ if (c == 0) {
+ return;
+ }
+ circle[i] = c;
+ }
+
+ /* We will loop, possibly for all of the remaining characters. */
+ for (;;) {
+ j = offset;
+ b = true;
+
+ /* Compare the circle buffer with the to string. */
+ for (i = 0; i < length; i += 1) {
+ if (circle[j] != to.charAt(i)) {
+ b = false;
+ break;
+ }
+ j += 1;
+ if (j >= length) {
+ j -= length;
+ }
+ }
+
+ /* If we exit the loop with b intact, then victory is ours. */
+ if (b) {
+ return;
+ }
+
+ /* Get the next character. If there isn't one, then defeat is ours. */
+ c = next();
+ if (c == 0) {
+ return;
+ }
+ /*
+ * Shove the character in the circle buffer and advance the
+ * circle offset. The offset is mod n.
+ */
+ circle[offset] = c;
+ offset += 1;
+ if (offset >= length) {
+ offset -= length;
+ }
+ }
+ }
+}
diff --git a/src/org/json/json.properties b/src/org/json/json.properties
new file mode 100644
index 000000000..d18ce04db
--- /dev/null
+++ b/src/org/json/json.properties
@@ -0,0 +1,2 @@
+version=1.7.7
+date=23/01/2024
diff --git a/src/org/json/package.html b/src/org/json/package.html
new file mode 100644
index 000000000..ba76a6745
--- /dev/null
+++ b/src/org/json/package.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+ The json package. The code is copied from the https://github.com/stleary/JSON-java project.
+
+
diff --git a/src/overview.html b/src/overview.html
new file mode 100644
index 000000000..d3768dcac
--- /dev/null
+++ b/src/overview.html
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+ This is a fork of the JSON project in github (https://github.com/stleary/JSON-java) for the 20180813 version.
+
+
+ Compared to this implementation:
+
+ - this is a Netbeans project
+ - JSONObject and JSONArray both have an equals and hashCode method
+ - a FileUtils class with static method has been added to simply the generation to/from a File / a JSON object
+ - The supported Java version is Java 8
+
+
+ Overview
+ JSON is a light-weight, language independent, data interchange format. See http://www.JSON.org/
+
+
+ The files in this package implement JSON encoders/decoders in Java.
+ It also includes the capability to convert between JSON and XML, HTTP
+ headers, Cookies, and CDL.
+
+
+ This is a reference implementation. There is a large number of JSON packages
+ in Java. Perhaps someday the Java community will standardize on one. Until
+ then, choose carefully.
+
+
+ The license includes this restriction: "The software shall be used for good,
+ not evil." If your conscience cannot live with that, then choose a different
+ package.
+
+
+ The package compiles on Java 1.8.
+
+
Code structure
+
+ - JSONObject.java: The JSONObject can parse text from a String or a JSONTokener
+ to produce a map-like object. The object provides methods for manipulating its
+ contents, and for producing a JSON compliant object serialization.
+ - JSONArray.java: The JSONArray can parse text from a String or a JSONTokener
+ to produce a vector-like object. The object provides methods for manipulating
+ its contents, and for producing a JSON compliant array serialization.
+ - JSONTokener.java: The JSONTokener breaks a text into a sequence of individual
+ tokens. It can be constructed from a String, Reader, or InputStream
+ - JSONException.java: The JSONException is the standard exception type thrown by this package.
+ - JSONPointer.java: Implementation of [JSON Pointer (RFC 6901)](https://tools.ietf.org/html/rfc6901). Supports
+ JSON Pointers both in the form of string representation and URI fragment representation.
+ - JSONPropertyIgnore.java: Annotation class that can be used on Java Bean getter methods.
+ When used on a bean method that would normally be serialized into a JSONObject, it
+ overrides the getter-to-key-name logic and forces the property to be excluded from the
+ resulting JSONObject.
+ - JSONPropertyName.java: Annotation class that can be used on Java Bean getter methods.
+ When used on a bean method that would normally be serialized into a JSONObject, it
+ overrides the getter-to-key-name logic and uses the value of the annotation. The Bean
+ processor will look through the class hierarchy. This means you can use the annotation on
+ a base class or interface and the value of the annotation will be used even if the getter
+ is overridden in a child class.
+ - JSONString.java: The JSONString interface requires a toJSONString method,
+ allowing an object to provide its own serialization.
+ - JSONStringer.java: The JSONStringer provides a convenient facility for
+ building JSON strings.
+ - JSONWriter.java: The JSONWriter provides a convenient facility for building
+ JSON text through a writer.
+ - CDL.java: CDL provides support for converting between JSON and comma delimited lists.
+ - Cookie.java: Cookie provides support for converting between JSON and cookies.
+ - CookieList.java: CookieList provides support for converting between JSON and cookie lists.
+ - HTTP.java: HTTP provides support for converting between JSON and HTTP headers.
+ - XML.java: XML provides support for converting between JSON and XML.
+
+
+ About numeric types
+ Numeric types in this package comply with
+ [ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf) and
+ [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159#section-6).
+ This package fully supports `Integer`, `Long`, and `Double` Java types. Partial support
+ for `BigInteger` and `BigDecimal` values in `JSONObject` and `JSONArray` objects is provided
+ in the form of `get()`, `opt()`, and `put()` API methods.
+
+
+ In compliance with RFC7159 page 10 section 9, the parser is more lax with what is valid
+ JSON than the Generator. For Example, the tab character (U+0009) is allowed when reading
+ JSON Text strings, but when output by the Generator, tab is properly converted to \t in
+ the string. Other instances may occur where reading invalid JSON text does not cause an
+ error to be generated. Malformed JSON Texts such as missing end " (quote) on strings or
+ invalid number formats (1.2e6.3) will cause errors as such documents can not be read
+ reliably.
+
+
diff --git a/test/org/json/FileUtils2Test.java b/test/org/json/FileUtils2Test.java
new file mode 100644
index 000000000..708fed571
--- /dev/null
+++ b/test/org/json/FileUtils2Test.java
@@ -0,0 +1,115 @@
+/*
+Copyright (C) 2020, 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @version 1.7.2
+ */
+public class FileUtils2Test {
+
+ public FileUtils2Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of toFile method, of class FileUtils.
+ */
+ @Test
+ public void testFromFile() throws Exception {
+ System.out.println("FileUtils2Test : testFromFile");
+
+ URL url = this.getClass().getResource("testJSONArray.json");
+ JSONArray array = FileUtils.toJSONArray(url);
+ assertEquals("Array length", 3, array.length());
+ Object o = array.get(0);
+ assertEquals("First index", "cookie", o);
+ }
+
+ /**
+ * Test of toFile method.
+ */
+ @Test
+ public void testToFile() throws IOException {
+ System.out.println("FileUtils2Test : testToFile");
+ JSONArray array = new JSONArray();
+ array.put("cookie");
+ array.put("fish");
+ array.put("chips");
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(array, file);
+ array = FileUtils.toJSONArray(file);
+ file.delete();
+
+ assertEquals("Array length", 3, array.length());
+ Object o = array.get(0);
+ assertEquals("First index", "cookie", o);
+ }
+
+ /**
+ * Test of toURL method.
+ */
+ @Test
+ public void testToURL() throws IOException {
+ System.out.println("FileUtils2Test : testToURL");
+ JSONArray array = new JSONArray();
+ array.put("cookie");
+ array.put("fish");
+ array.put("chips");
+
+ File file = File.createTempFile("json", ".json");
+ URL url = file.toURI().toURL();
+ FileUtils.toURL(array, url);
+ array = FileUtils.toJSONArray(file);
+ file.delete();
+
+ assertEquals("Array length", 3, array.length());
+ Object o = array.get(0);
+ assertEquals("First index", "cookie", o);
+ }
+}
diff --git a/test/org/json/FileUtils3Test.java b/test/org/json/FileUtils3Test.java
new file mode 100644
index 000000000..96f3e4ef1
--- /dev/null
+++ b/test/org/json/FileUtils3Test.java
@@ -0,0 +1,175 @@
+/*
+Copyright (C) 2020, 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @version 1.7.2
+ */
+public class FileUtils3Test {
+
+ public FileUtils3Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of toJSONObject method, of class FileUtils.
+ */
+ @Test
+ public void testFromFile() throws Exception {
+ System.out.println("FileUtils3Test : testFromFile");
+
+ URL url = this.getClass().getResource("testJSON7.json");
+ JSONObject jsonObj = FileUtils.toJSONObject(url);
+
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertNull("name", name);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ }
+
+ /**
+ * Test of toFile method.
+ */
+ @Test
+ public void testToFile() throws IOException {
+ System.out.println("FileUtilsTest : testToFile");
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.putNULL("name");
+ jsonObj.put("birthday", "1940-02-10");
+ jsonObj.put("age", 76);
+ jsonObj.put("married", false);
+
+ // Cannot set null directly
+ jsonObj.putNULL("car");
+
+ jsonObj.put("favorite_foods", new String[] { "cookie", "fish", "chips" });
+
+ JSONObject passportJsonObj = new JSONObject();
+ passportJsonObj.put("id", 100001);
+ passportJsonObj.put("nationality", "American");
+ jsonObj.put("passport", passportJsonObj);
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(jsonObj, file);
+ jsonObj = FileUtils.toJSONObject(file);
+ file.delete();
+
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertNull("name", name);
+ String car = jsonObj.getString("car");
+ assertNull("car", car);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ }
+
+ /**
+ * Test of toURL method.
+ */
+ @Test
+ public void testToURL() throws IOException {
+ System.out.println("FileUtilsTest : testToURL");
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.putNULL("name");
+ jsonObj.put("birthday", "1940-02-10");
+ jsonObj.put("age", 76);
+ jsonObj.put("married", false);
+
+ // Cannot set null directly
+ jsonObj.putNULL("car");
+
+ jsonObj.put("favorite_foods", new String[] { "cookie", "fish", "chips" });
+
+ JSONObject passportJsonObj = new JSONObject();
+ passportJsonObj.put("id", 100001);
+ passportJsonObj.put("nationality", "American");
+ jsonObj.put("passport", passportJsonObj);
+
+ File file = File.createTempFile("json", ".json");
+ URL url = file.toURI().toURL();
+ FileUtils.toURL(jsonObj, url);
+ file.delete();
+ jsonObj = FileUtils.toJSONObject(url);
+
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertNull("name", name);
+ String car = jsonObj.getString("car");
+ assertNull("car", car);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ }
+}
diff --git a/test/org/json/FileUtils4Test.java b/test/org/json/FileUtils4Test.java
new file mode 100644
index 000000000..b84dd6c90
--- /dev/null
+++ b/test/org/json/FileUtils4Test.java
@@ -0,0 +1,122 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @version 1.7.3
+ */
+public class FileUtils4Test {
+
+ public FileUtils4Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of toFile method.
+ */
+ @Test
+ public void testToFile() throws IOException {
+ System.out.println("FileUtils4Test : testToFile");
+ JSONOptions.getDefault().keepKeysNaturalOrder(true);
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("name", "Bob");
+ jsonObj.put("age", 23);
+ JSONObject socialSecJSon = new JSONObject();
+ socialSecJSon.put("gender", "Male");
+ socialSecJSon.put("number", 100000);
+ JSONArray children = new JSONArray();
+ jsonObj.put("children", children);
+ JSONObject child = new JSONObject();
+ child.put("name", "Paul");
+ children.put(child);
+ child = new JSONObject();
+ child.put("name", "Suzanne");
+ children.put(child);
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(jsonObj, file);
+
+ URL expected = this.getClass().getResource("expected/expected1.json");
+ URL result = file.toURI().toURL();
+ boolean isEqual = TestUtilities.checkContent(expected, result);
+ assertTrue("The file must be equal", isEqual);
+ file.delete();
+ }
+
+ /**
+ * Test of toFile method, using a variable.
+ */
+ @Test
+ public void testToFile2() throws IOException {
+ System.out.println("FileUtils4Test : testToFile2");
+ JSONOptions.getDefault().keepKeysNaturalOrder(true);
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("name", "Bob");
+ jsonObj.put("age", 23);
+ JSONObject socialSecJSon = new JSONObject();
+ socialSecJSon.put("gender", "Male");
+ socialSecJSon.put("number", 100000);
+ JSONArray children = new JSONArray();
+ jsonObj.put("children", children);
+ JSONObject child = new JSONObject();
+ child.put("name", "Paul");
+ children.put(child);
+ child = new JSONObject();
+ child.put("name", "Suzanne");
+ children.put(child);
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(jsonObj, file, "a");
+
+ URL expected = this.getClass().getResource("expected/expected2.json");
+ URL result = file.toURI().toURL();
+ boolean isEqual = TestUtilities.checkContent(expected, result);
+ assertTrue("The file must be equal", isEqual);
+ file.delete();
+ }
+}
diff --git a/test/org/json/FileUtils5Test.java b/test/org/json/FileUtils5Test.java
new file mode 100644
index 000000000..a9c50d01c
--- /dev/null
+++ b/test/org/json/FileUtils5Test.java
@@ -0,0 +1,92 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @since 1.7.2
+ */
+public class FileUtils5Test {
+
+ public FileUtils5Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of toFile method.
+ */
+ @Test
+ public void testToFile() throws IOException {
+ System.out.println("FileUtils5Test : testToFile");
+ JSONOptions.getDefault()
+ .keepKeysNaturalOrder(true)
+ .setIndentFactor(2);
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("name", "Bob");
+ jsonObj.put("age", 23);
+ JSONObject socialSecJSon = new JSONObject();
+ socialSecJSon.put("gender", "Male");
+ socialSecJSon.put("number", 100000);
+ JSONArray children = new JSONArray();
+ jsonObj.put("children", children);
+ JSONObject child = new JSONObject();
+ child.put("name", "Paul");
+ children.put(child);
+ child = new JSONObject();
+ child.put("name", "Suzanne");
+ children.put(child);
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(jsonObj, file);
+
+ URL expected = this.getClass().getResource("expected/expected3.json");
+ URL result = file.toURI().toURL();
+ boolean isEqual = TestUtilities.checkContent(expected, result);
+ assertTrue("The file must be equal", isEqual);
+ file.delete();
+ }
+}
diff --git a/test/org/json/FileUtils6BTest.java b/test/org/json/FileUtils6BTest.java
new file mode 100644
index 000000000..9fbca5aa5
--- /dev/null
+++ b/test/org/json/FileUtils6BTest.java
@@ -0,0 +1,96 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @since 1.7.2
+ */
+public class FileUtils6BTest {
+
+ public FileUtils6BTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of toFile method.
+ */
+ @Test
+ public void testToFile2() throws IOException {
+ System.out.println("FileUtils6Test : testToFile2");
+ JSONOptions.getDefault()
+ .keepKeysNaturalOrder(true).setIndentFactor(2)
+ .setIndentationType(JSONOptions.INDENT_DEFAULT);
+ JSONObject rootObj = new JSONObject();
+
+ JSONObject personObj = new JSONObject();
+ personObj.put("name", "Bob");
+ personObj.put("age", 23);
+ rootObj.put("person", personObj);
+
+ JSONObject socialSecJSon = new JSONObject();
+ socialSecJSon.put("gender", "Male");
+ socialSecJSon.put("number", 100000);
+ JSONArray children = new JSONArray();
+ personObj.put("children", children);
+ JSONObject child = new JSONObject();
+ child.put("name", "Paul");
+ children.put(child);
+ child = new JSONObject();
+ child.put("name", "Suzanne");
+ children.put(child);
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(rootObj, file);
+
+ URL expected = this.getClass().getResource("expected/expected6.json");
+ URL result = file.toURI().toURL();
+ boolean isEqual = TestUtilities.checkContent(expected, result);
+ assertTrue("The file must be equal", isEqual);
+ file.delete();
+ }
+}
diff --git a/test/org/json/FileUtils6Test.java b/test/org/json/FileUtils6Test.java
new file mode 100644
index 000000000..f44f2d171
--- /dev/null
+++ b/test/org/json/FileUtils6Test.java
@@ -0,0 +1,135 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @since 1.7.2
+ */
+public class FileUtils6Test {
+
+ public FileUtils6Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of toFile method.
+ */
+ @Test
+ public void testToFile() throws IOException {
+ System.out.println("FileUtils6Test : testToFile");
+ JSONOptions.getDefault()
+ .keepKeysNaturalOrder(true).setIndentFactor(2)
+ .setIndentationType(JSONOptions.INDENT_OBJECTS);
+ JSONObject rootObj = new JSONObject();
+
+ JSONObject personObj = new JSONObject();
+ personObj.put("name", "Bob");
+ personObj.put("age", 23);
+ rootObj.put("person", personObj);
+
+ JSONObject socialSecJSon = new JSONObject();
+ socialSecJSon.put("gender", "Male");
+ socialSecJSon.put("number", 100000);
+ JSONArray children = new JSONArray();
+ personObj.put("children", children);
+ JSONObject child = new JSONObject();
+ child.put("name", "Paul");
+ children.put(child);
+ child = new JSONObject();
+ child.put("name", "Suzanne");
+ children.put(child);
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(rootObj, file);
+
+ URL expected = this.getClass().getResource("expected/expected4.json");
+ URL result = file.toURI().toURL();
+ boolean isEqual = TestUtilities.checkContent(expected, result);
+ assertTrue("The file must be equal", isEqual);
+ file.delete();
+ }
+
+ /**
+ * Test of toFile method.
+ */
+ @Test
+ public void testToFile2() throws IOException {
+ System.out.println("FileUtils6Test : testToFile2");
+ JSONOptions.getDefault()
+ .keepKeysNaturalOrder(true)
+ .setIndentationType(JSONOptions.INDENT_ALL)
+ .setIndentFactor(2);
+ JSONObject rootObj = new JSONObject();
+
+ JSONObject personObj = new JSONObject();
+ personObj.put("name", "Bob");
+ personObj.put("age", 23);
+ rootObj.put("person", personObj);
+
+ JSONObject socialSecJSon = new JSONObject();
+ socialSecJSon.put("gender", "Male");
+ socialSecJSon.put("number", 100000);
+ JSONArray children = new JSONArray();
+ personObj.put("children", children);
+ JSONObject child = new JSONObject();
+ child.put("name", "Paul");
+ children.put(child);
+ child = new JSONObject();
+ child.put("name", "Suzanne");
+ children.put(child);
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(rootObj, file);
+
+ URL expected = this.getClass().getResource("expected/expected5.json");
+ URL result = file.toURI().toURL();
+ boolean isEqual = TestUtilities.checkContent(expected, result);
+ assertTrue("The file must be equal", isEqual);
+ file.delete();
+ }
+}
diff --git a/test/org/json/FileUtils7Test.java b/test/org/json/FileUtils7Test.java
new file mode 100644
index 000000000..4eedd7015
--- /dev/null
+++ b/test/org/json/FileUtils7Test.java
@@ -0,0 +1,91 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @since 1.7.3
+ */
+public class FileUtils7Test {
+
+ public FileUtils7Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of toFile method.
+ */
+ @Test
+ public void testToFile() throws IOException {
+ System.out.println("FileUtils6Test : testToFile");
+ JSONOptions.getDefault()
+ .keepKeysNaturalOrder(true).setIndentFactor(2)
+ .setIndentationType(JSONOptions.INDENT_OBJECTS);
+ JSONObject rootObj = new JSONObject();
+
+ JSONObject personObj = new JSONObject();
+ personObj.put("name", "Bob");
+ personObj.put("age", 23);
+ rootObj.put("person", personObj);
+
+ JSONObject socialSecJSon = new JSONObject();
+ socialSecJSon.put("gender", "Male");
+ socialSecJSon.put("number", 100000);
+ JSONObject child = new JSONObject();
+ child.put("name", "Paul");
+ personObj.put("child", child);
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(rootObj, file);
+
+ URL expected = this.getClass().getResource("expected/expected7.json");
+ URL result = file.toURI().toURL();
+ boolean isEqual = TestUtilities.checkContent(expected, result);
+ assertTrue("The file must be equal", isEqual);
+ file.delete();
+ }
+}
diff --git a/test/org/json/FileUtils8Test.java b/test/org/json/FileUtils8Test.java
new file mode 100644
index 000000000..f0ca58331
--- /dev/null
+++ b/test/org/json/FileUtils8Test.java
@@ -0,0 +1,122 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @since 1.7.4
+ */
+public class FileUtils8Test {
+
+ public FileUtils8Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of toFile method.
+ */
+ @Test
+ public void testToFile() throws IOException {
+ System.out.println("FileUtils8Test : testToFile");
+ JSONOptions.getDefault()
+ .keepKeysNaturalOrder(true).setIndentFactor(2)
+ .setIndentationType(JSONOptions.INDENT_OBJECTS);
+ JSONObject rootObj = new JSONObject();
+
+ JSONObject personObj = new JSONObject();
+ personObj.put("name", "Bob");
+ personObj.put("age", 23);
+ rootObj.put("person", personObj);
+
+ JSONArray children = new JSONArray();
+ personObj.put("children", children);
+ children.put(1);
+ children.put(2);
+ children.put(3);
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(rootObj, file);
+
+ URL expected = this.getClass().getResource("expected/expected8.json");
+ URL result = file.toURI().toURL();
+ boolean isEqual = TestUtilities.checkContent(expected, result);
+ assertTrue("The file must be equal", isEqual);
+ file.delete();
+ }
+
+ /**
+ * Test of toFile method.
+ */
+ @Test
+ public void testToFile2() throws IOException {
+ System.out.println("FileUtils8Test : testToFile2");
+ JSONOptions.getDefault()
+ .keepKeysNaturalOrder(true).setIndentFactor(2)
+ .setIndentationType(JSONOptions.INDENT_OBJECTS);
+ JSONObject rootObj = new JSONObject();
+
+ JSONObject personObj = new JSONObject();
+ personObj.put("name", "Bob");
+ personObj.put("age", 23);
+ rootObj.put("person", personObj);
+
+ JSONArray children = new JSONArray();
+ personObj.put("children", children);
+ children.put("A");
+ children.put("B");
+ children.put("C");
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(rootObj, file);
+
+ URL expected = this.getClass().getResource("expected/expected9.json");
+ URL result = file.toURI().toURL();
+ boolean isEqual = TestUtilities.checkContent(expected, result);
+ assertTrue("The file must be equal", isEqual);
+ file.delete();
+ }
+}
diff --git a/test/org/json/FileUtils9Test.java b/test/org/json/FileUtils9Test.java
new file mode 100644
index 000000000..0e882b822
--- /dev/null
+++ b/test/org/json/FileUtils9Test.java
@@ -0,0 +1,177 @@
+/*
+Copyright (C) 2024 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Check using InputStream to get JSON content.
+ *
+ * @since 1.7.7
+ */
+public class FileUtils9Test {
+
+ public FileUtils9Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of toJSONObject method.
+ */
+ @Test
+ public void testFromFile() throws Exception {
+ System.out.println("FileUtils9Test : testFromFile");
+
+ URL url = this.getClass().getResource("testJSON.json");
+ InputStream stream = url.openStream();
+ JSONObject jsonObj = FileUtils.toJSONObject(stream);
+
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Tom", name);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ }
+
+ /**
+ * Test of toFile method, of class FileUtils.
+ */
+ @Test
+ public void testFromFile2() throws Exception {
+ System.out.println("FileUtils9Test : testFromFile2");
+
+ URL url = this.getClass().getResource("testJSONArray.json");
+ InputStream stream = url.openStream();
+ JSONArray array = FileUtils.toJSONArray(stream);
+ assertEquals("Array length", 3, array.length());
+ Object o = array.get(0);
+ assertEquals("First index", "cookie", o);
+ }
+
+ /**
+ * Test of toJSONObject method.
+ */
+ @Test
+ public void testFromFile3() throws Exception {
+ System.out.println("FileUtils9Test : testFromFile3");
+
+ URL url = this.getClass().getResource("testJSON.json");
+ InputStream stream = url.openStream();
+ JSONElement jsonElt = FileUtils.toJSONElement(stream);
+ assertTrue("JSONElement must be a JSONObject", jsonElt instanceof JSONObject);
+ JSONObject jsonObj = (JSONObject) jsonElt;
+
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Tom", name);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ }
+
+ /**
+ * Test of toJSONObject method.
+ */
+ @Test
+ public void testToJSONObjectWithComments() throws IOException {
+ System.out.println("FileUtils9Test : testToJSONObjectWithComments");
+ JSONOptions.getDefault().acceptJavascriptComments(true);
+ JSONOptions.getDefault().keepKeysNaturalOrder(true);
+ URL url = this.getClass().getResource("comments/comments2.json");
+ InputStream stream = url.openStream();
+ JSONObject jsonObj = FileUtils.toJSONObject(stream);
+
+ int age = jsonObj.getInt("age");
+ assertEquals("Age", 23, age);
+
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Bob", name);
+
+ JSONArray array = jsonObj.getJSONArray("children");
+ assertNotNull("children array must exist", array);
+ assertEquals("array length", 2, array.length());
+ }
+
+ /**
+ * Test of toJSONObject method.
+ */
+ @Test
+ public void testToJSONObjectWithComments2() throws IOException {
+ System.out.println("FileUtils9Test : testToJSONObjectWithComments2");
+ JSONOptions.getDefault().acceptJavascriptComments(true);
+ JSONOptions.getDefault().keepKeysNaturalOrder(true);
+ URL url = this.getClass().getResource("comments/comments2.json");
+ InputStream stream = url.openStream();
+ JSONObject jsonObj = FileUtils.toJSONObject(stream);
+
+ int age = jsonObj.getInt("age");
+ assertEquals("Age", 23, age);
+
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Bob", name);
+
+ JSONArray array = jsonObj.getJSONArray("children");
+ assertNotNull("children array must exist", array);
+ assertEquals("array length", 2, array.length());
+ }
+}
diff --git a/test/org/json/FileUtilsComments2Test.java b/test/org/json/FileUtilsComments2Test.java
new file mode 100644
index 000000000..384ba8e60
--- /dev/null
+++ b/test/org/json/FileUtilsComments2Test.java
@@ -0,0 +1,105 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Tests with comments.
+ *
+ * @since 1.7.2
+ */
+public class FileUtilsComments2Test {
+
+ public FileUtilsComments2Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of toJSONObject method.
+ */
+ @Test
+ public void testToJSONObjectWithComments() throws IOException {
+ System.out.println("FileUtilsComments2Test : testToJSONObjectWithComments");
+ JSONOptions.getDefault().acceptJavascriptComments(true);
+ JSONOptions.getDefault().keepKeysNaturalOrder(true);
+ URL url = this.getClass().getResource("comments/comments2.json");
+ File file = new File(url.getFile());
+ JSONObject jsonObj = FileUtils.toJSONObject(file);
+
+ int age = jsonObj.getInt("age");
+ assertEquals("Age", 23, age);
+
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Bob", name);
+
+ JSONArray array = jsonObj.getJSONArray("children");
+ assertNotNull("children array must exist", array);
+ assertEquals("array length", 2, array.length());
+ }
+
+ /**
+ * Test of toJSONObject method.
+ */
+ @Test
+ public void testToJSONObjectWithComments2() throws IOException {
+ System.out.println("FileUtilsComments2Test : testToJSONObjectWithComments2");
+ JSONOptions.getDefault().acceptJavascriptComments(true);
+ JSONOptions.getDefault().keepKeysNaturalOrder(true);
+ URL url = this.getClass().getResource("comments/comments2.json");
+ JSONObject jsonObj = FileUtils.toJSONObject(url);
+
+ int age = jsonObj.getInt("age");
+ assertEquals("Age", 23, age);
+
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Bob", name);
+
+ JSONArray array = jsonObj.getJSONArray("children");
+ assertNotNull("children array must exist", array);
+ assertEquals("array length", 2, array.length());
+ }
+}
diff --git a/test/org/json/FileUtilsCommentsTest.java b/test/org/json/FileUtilsCommentsTest.java
new file mode 100644
index 000000000..6b27a6776
--- /dev/null
+++ b/test/org/json/FileUtilsCommentsTest.java
@@ -0,0 +1,105 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Tests with comments.
+ *
+ * @since 1.7.2
+ */
+public class FileUtilsCommentsTest {
+
+ public FileUtilsCommentsTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of toJSONObject method.
+ */
+ @Test
+ public void testToJSONObjectWithComments() throws IOException {
+ System.out.println("FileUtilsCommentsTest : testToJSONObjectWithComments");
+ JSONOptions.getDefault().acceptJavascriptComments(true);
+ JSONOptions.getDefault().keepKeysNaturalOrder(true);
+ URL url = this.getClass().getResource("comments/comments1.json");
+ File file = new File(url.getFile());
+ JSONObject jsonObj = FileUtils.toJSONObject(file);
+
+ int age = jsonObj.getInt("age");
+ assertEquals("Age", 23, age);
+
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Bob", name);
+
+ JSONArray array = jsonObj.getJSONArray("children");
+ assertNotNull("children array must exist", array);
+ assertEquals("array length", 2, array.length());
+ }
+
+ /**
+ * Test of toJSONObject method.
+ */
+ @Test
+ public void testToJSONObjectWithComments2() throws IOException {
+ System.out.println("FileUtilsCommentsTest : testToJSONObjectWithComments2");
+ JSONOptions.getDefault().acceptJavascriptComments(true);
+ JSONOptions.getDefault().keepKeysNaturalOrder(true);
+ URL url = this.getClass().getResource("comments/comments1.json");
+ JSONObject jsonObj = FileUtils.toJSONObject(url);
+
+ int age = jsonObj.getInt("age");
+ assertEquals("Age", 23, age);
+
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Bob", name);
+
+ JSONArray array = jsonObj.getJSONArray("children");
+ assertNotNull("children array must exist", array);
+ assertEquals("array length", 2, array.length());
+ }
+}
diff --git a/test/org/json/FileUtilsTest.java b/test/org/json/FileUtilsTest.java
new file mode 100644
index 000000000..ccddf85b9
--- /dev/null
+++ b/test/org/json/FileUtilsTest.java
@@ -0,0 +1,170 @@
+/*
+Copyright (C) 2018, 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @version 1.7.2
+ */
+public class FileUtilsTest {
+
+ public FileUtilsTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of toJSONObject method.
+ */
+ @Test
+ public void testFromFile() throws Exception {
+ System.out.println("FileUtilsTest : testFromFile");
+
+ URL url = this.getClass().getResource("testJSON.json");
+ JSONObject jsonObj = FileUtils.toJSONObject(url);
+
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Tom", name);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ }
+
+ /**
+ * Test of toFile method.
+ */
+ @Test
+ public void testToFile() throws IOException {
+ System.out.println("FileUtilsTest : testToFile");
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("name", "Tom");
+ jsonObj.put("birthday", "1940-02-10");
+ jsonObj.put("age", 76);
+ jsonObj.put("married", false);
+
+ // Cannot set null directly
+ jsonObj.put("car", JSONObject.NULL);
+
+ jsonObj.put("favorite_foods", new String[] { "cookie", "fish", "chips" });
+
+ JSONObject passportJsonObj = new JSONObject();
+ passportJsonObj.put("id", 100001);
+ passportJsonObj.put("nationality", "American");
+ jsonObj.put("passport", passportJsonObj);
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(jsonObj, file);
+ jsonObj = FileUtils.toJSONObject(file);
+ file.delete();
+
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Tom", name);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ }
+
+ /**
+ * Test of toURL method.
+ */
+ @Test
+ public void testToURL() throws IOException {
+ System.out.println("FileUtilsTest : testToURL");
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("name", "Tom");
+ jsonObj.put("birthday", "1940-02-10");
+ jsonObj.put("age", 76);
+ jsonObj.put("married", false);
+
+ // Cannot set null directly
+ jsonObj.put("car", JSONObject.NULL);
+
+ jsonObj.put("favorite_foods", new String[] { "cookie", "fish", "chips" });
+
+ JSONObject passportJsonObj = new JSONObject();
+ passportJsonObj.put("id", 100001);
+ passportJsonObj.put("nationality", "American");
+ jsonObj.put("passport", passportJsonObj);
+
+ File file = File.createTempFile("json", ".json");
+ URL url = file.toURI().toURL();
+ FileUtils.toURL(jsonObj, url);
+ file.delete();
+ jsonObj = FileUtils.toJSONObject(file);
+
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Tom", name);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ }
+}
diff --git a/test/org/json/JSONElementTest.java b/test/org/json/JSONElementTest.java
new file mode 100644
index 000000000..16f6be2db
--- /dev/null
+++ b/test/org/json/JSONElementTest.java
@@ -0,0 +1,81 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import java.io.Writer;
+import java.net.URL;
+
+/**
+ *
+ * @since 1.7.5
+ */
+public class JSONElementTest {
+
+ public JSONElementTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+ /**
+ * Test of testFromString method, of class JSONElement.
+ */
+ @Test
+ public void testFromString() {
+ System.out.println("JSONElementTest : testFromString");
+ URL url = this.getClass().getResource("testJSON.json");
+ String content = TestUtilities.getContent(url);
+ JSONElement element = JSONElement.fromString(content);
+ assertTrue("JSONElement must be a JSONObject", element instanceof JSONObject);
+ }
+
+ /**
+ * Test of testFromString method, of class JSONElement.
+ */
+ @Test
+ public void testFromString2() {
+ System.out.println("JSONElementTest : testFromString2");
+ URL url = this.getClass().getResource("testJSONArray.json");
+ String content = TestUtilities.getContent(url);
+ JSONElement element = JSONElement.fromString(content);
+ assertTrue("JSONElement must be a JSONArray", element instanceof JSONArray);
+ }
+
+}
diff --git a/test/org/json/JSONObject2Test.java b/test/org/json/JSONObject2Test.java
new file mode 100644
index 000000000..8786ca04d
--- /dev/null
+++ b/test/org/json/JSONObject2Test.java
@@ -0,0 +1,92 @@
+/*
+Copyright (C) 2018 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @since 1.2
+ */
+public class JSONObject2Test {
+
+ public JSONObject2Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of creation method, of class JSONObject.
+ */
+ @Test
+ public void testGetString() {
+ System.out.println("JSONObject2Test : testGetString");
+
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("name", "Tom");
+ jsonObj.put("birthday", "1940-02-10");
+ jsonObj.put("age", 76);
+ jsonObj.put("married", false);
+
+ assertEquals("int field", 76, jsonObj.get("age"));
+ assertEquals("int field", "76", jsonObj.getString("age"));
+ assertEquals("int field", "Tom", jsonObj.getString("name"));
+ }
+
+ /**
+ * Test of creation method, of class JSONObject.
+ */
+ @Test
+ public void testCreate() {
+ System.out.println("JSONObject2Test : testCreate");
+
+ JSONObject jsonObj = JSONObject.create()
+ .put("name", "Tom")
+ .put("birthday", "1940-02-10")
+ .put("age", 76)
+ .put("married", false);
+
+ assertEquals("int field", 76, jsonObj.get("age"));
+ assertEquals("int field", "76", jsonObj.getString("age"));
+ assertEquals("int field", "Tom", jsonObj.getString("name"));
+ }
+
+}
diff --git a/test/org/json/JSONObject3Test.java b/test/org/json/JSONObject3Test.java
new file mode 100644
index 000000000..23d8a72e8
--- /dev/null
+++ b/test/org/json/JSONObject3Test.java
@@ -0,0 +1,71 @@
+/*
+Copyright (C) 2019 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertNull;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @version 1.7.2
+ */
+public class JSONObject3Test {
+
+ public JSONObject3Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of creation method, of class JSONObject.
+ */
+ @Test
+ public void testGetArray() throws IOException {
+ System.out.println("JSONObject3Test : testGetArray");
+
+ URL url = this.getClass().getResource("testJSON6.json");
+ JSONObject jsonObj = FileUtils.toJSONObject(url);
+
+ JSONArray array = jsonObj.optJSONArray("favorite_foods");
+ assertNull("favorite_foods is null", array);
+ }
+}
diff --git a/test/org/json/JSONObject4Test.java b/test/org/json/JSONObject4Test.java
new file mode 100644
index 000000000..2416bb34d
--- /dev/null
+++ b/test/org/json/JSONObject4Test.java
@@ -0,0 +1,99 @@
+/*
+Copyright (C) 2020 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @version 1.7.5
+ */
+public class JSONObject4Test {
+
+ public JSONObject4Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of creation method, of class JSONObject.
+ */
+ @Test
+ public void testCreate() {
+ System.out.println("JSONObject4Test : testCreate");
+
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("name", "Tom");
+ jsonObj.put("birthday", "1940-02-10");
+ jsonObj.put("age", 76);
+ jsonObj.put("married", false);
+
+ // Cannot set null directly
+ jsonObj.putNULL("car");
+
+ jsonObj.put("favorite_foods", new String[] { "cookie", "fish", "chips" });
+
+ JSONObject passportJsonObj = new JSONObject();
+ passportJsonObj.put("id", 100001);
+ passportJsonObj.put("nationality", "American");
+ jsonObj.put("passport", passportJsonObj);
+
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Tom", name);
+ String car = jsonObj.getString("car");
+ assertNull("car", car);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ }
+
+}
diff --git a/test/org/json/JSONObject5Test.java b/test/org/json/JSONObject5Test.java
new file mode 100644
index 000000000..d238a8554
--- /dev/null
+++ b/test/org/json/JSONObject5Test.java
@@ -0,0 +1,78 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import static org.junit.Assert.assertTrue;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Get JSON elements from Strings.
+ *
+ * @since 1.7.5
+ */
+public class JSONObject5Test {
+
+ public JSONObject5Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of creation method, of class JSONObject.
+ */
+ @Test
+ public void testGetFromString() {
+ System.out.println("JSONObject5Test : testGetFromString");
+ String str = "{\"age\":23,\"children\":[{\"name\":\"Paul\"},{\"name\":\"Suzanne\"}],\"name\":\"Bob\"}";
+ JSONElement element = JSONElement.fromString(str);
+ assertTrue("JSONElement must be a JSONObject", element instanceof JSONObject);
+ }
+
+ /**
+ * Test of creation method, of class JSONObject.
+ */
+ @Test
+ public void testGetFromString2() {
+ System.out.println("JSONObject5Test : testGetFromString2");
+ String str = "[{\"name\": \"Paul\"}, {\"name\": \"Suzanne\"}]";
+ JSONElement element = JSONElement.fromString(str);
+ assertTrue("JSONElement must be a JSONArray", element instanceof JSONArray);
+ }
+}
diff --git a/test/org/json/JSONObjectEmptyTest.java b/test/org/json/JSONObjectEmptyTest.java
new file mode 100644
index 000000000..8ca53357a
--- /dev/null
+++ b/test/org/json/JSONObjectEmptyTest.java
@@ -0,0 +1,87 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.After;
+import org.junit.AfterClass;
+import static org.junit.Assert.fail;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Get JSON elements from Strings.
+ *
+ * @since 1.7.5
+ */
+public class JSONObjectEmptyTest {
+
+ public JSONObjectEmptyTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of creation method, of class JSONObject. Must have a syntax error.
+ */
+ @Test
+ public void testGetFromEmptyString() {
+ System.out.println("JSONObjectEmptyTest : testGetFromEmptyString");
+ try {
+ JSONObject object = new JSONObject(" ");
+ fail("We should have a JSONException");
+ } catch (JSONException e) {
+ assertEquals("A JSONObject text must begin with '{' at 1 [character 2 line 1]", e.getMessage());
+ // we should go here
+ }
+ }
+
+ /**
+ * Test of creation method, of class JSONArray. Must have a syntax error.
+ */
+ @Test
+ public void testGetFromEmptyString2() {
+ System.out.println("JSONObjectEmptyTest : testGetFromEmptyString");
+ try {
+ JSONArray object = new JSONArray(" ");
+ fail("We should have a JSONException");
+ } catch (JSONException e) {
+ assertEquals("A JSONArray text must start with '[' at 1 [character 2 line 1]", e.getMessage());
+ // we should go here
+ }
+ }
+}
diff --git a/test/org/json/JSONObjectNumbers2Test.java b/test/org/json/JSONObjectNumbers2Test.java
new file mode 100644
index 000000000..ad9f47b62
--- /dev/null
+++ b/test/org/json/JSONObjectNumbers2Test.java
@@ -0,0 +1,97 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @since 1.7.2
+ */
+public class JSONObjectNumbers2Test {
+
+ public JSONObjectNumbers2Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ JSONOptions.getDefault().keepDecimalPoints(true);
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of numberToString method, of class JSONObject.
+ */
+ @Test
+ public void testNumberToStringFloat() {
+ System.out.println("JSONObjectNumbers2Test : testNumberToStringFloat");
+ float f = 1.5f;
+ String result = JSONObject.numberToString(f, true);
+ assertEquals("Result", "1.5", result);
+
+ f = 1f;
+ result = JSONObject.numberToString(f, true);
+ assertEquals("Result", "1.0", result);
+ }
+
+ /**
+ * Test of numberToString method, of class JSONObject.
+ */
+ @Test
+ public void testNumberToStringDouble() {
+ System.out.println("JSONObjectNumbers2Test : testNumberToStringDouble");
+ double d = 1.5d;
+ String result = JSONObject.numberToString(d, true);
+ assertEquals("Result", "1.5", result);
+
+ d = 1f;
+ result = JSONObject.numberToString(d, true);
+ assertEquals("Result", "1.0", result);
+ }
+
+ /**
+ * Test of numberToString method, of class JSONObject.
+ */
+ @Test
+ public void testNumberToStringInt() {
+ System.out.println("JSONObjectNumbers2Test : testNumberToStringInt");
+ int i = 1;
+ String result = JSONObject.numberToString(i);
+ assertEquals("Result", "1", result);
+ }
+}
diff --git a/test/org/json/JSONObjectNumbers3Test.java b/test/org/json/JSONObjectNumbers3Test.java
new file mode 100644
index 000000000..0dcbccd8f
--- /dev/null
+++ b/test/org/json/JSONObjectNumbers3Test.java
@@ -0,0 +1,97 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @since 1.7.2
+ */
+public class JSONObjectNumbers3Test {
+
+ public JSONObjectNumbers3Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ JSONOptions.getDefault().keepDecimalPoints(true);
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of numberToString method, of class JSONObject.
+ */
+ @Test
+ public void testNumberToStringFloat() {
+ System.out.println("JSONObjectNumbers3Test : testNumberToStringFloat");
+ float f = 1.5f;
+ String result = JSONObject.numberToString(f);
+ assertEquals("Result", "1.5", result);
+
+ f = 1f;
+ result = JSONObject.numberToString(f);
+ assertEquals("Result", "1", result);
+ }
+
+ /**
+ * Test of numberToString method, of class JSONObject.
+ */
+ @Test
+ public void testNumberToStringDouble() {
+ System.out.println("JSONObjectNumbers3Test : testNumberToStringDouble");
+ double d = 1.5d;
+ String result = JSONObject.numberToString(d);
+ assertEquals("Result", "1.5", result);
+
+ d = 1f;
+ result = JSONObject.numberToString(d);
+ assertEquals("Result", "1", result);
+ }
+
+ /**
+ * Test of numberToString method, of class JSONObject.
+ */
+ @Test
+ public void testNumberToStringInt() {
+ System.out.println("JSONObjectNumbers3Test : testNumberToStringInt");
+ int i = 1;
+ String result = JSONObject.numberToString(i);
+ assertEquals("Result", "1", result);
+ }
+}
diff --git a/test/org/json/JSONObjectNumbersTest.java b/test/org/json/JSONObjectNumbersTest.java
new file mode 100644
index 000000000..324f70c67
--- /dev/null
+++ b/test/org/json/JSONObjectNumbersTest.java
@@ -0,0 +1,96 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @since 1.7.2
+ */
+public class JSONObjectNumbersTest {
+
+ public JSONObjectNumbersTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of numberToString method, of class JSONObject.
+ */
+ @Test
+ public void testNumberToStringFloat() {
+ System.out.println("JSONObjectNumbersTest : testNumberToStringFloat");
+ float f = 1.5f;
+ String result = JSONObject.numberToString(f);
+ assertEquals("Result", "1.5", result);
+
+ f = 1f;
+ result = JSONObject.numberToString(f);
+ assertEquals("Result", "1", result);
+ }
+
+ /**
+ * Test of numberToString method, of class JSONObject.
+ */
+ @Test
+ public void testNumberToStringDouble() {
+ System.out.println("JSONObjectNumbersTest : testNumberToStringDouble");
+ double d = 1.5d;
+ String result = JSONObject.numberToString(d);
+ assertEquals("Result", "1.5", result);
+
+ d = 1f;
+ result = JSONObject.numberToString(d);
+ assertEquals("Result", "1", result);
+ }
+
+ /**
+ * Test of numberToString method, of class JSONObject.
+ */
+ @Test
+ public void testNumberToStringInt() {
+ System.out.println("JSONObjectNumbersTest : testNumberToStringInt");
+ int i = 1;
+ String result = JSONObject.numberToString(i);
+ assertEquals("Result", "1", result);
+ }
+}
diff --git a/test/org/json/JSONObjectTest.java b/test/org/json/JSONObjectTest.java
new file mode 100644
index 000000000..e6a9cdf76
--- /dev/null
+++ b/test/org/json/JSONObjectTest.java
@@ -0,0 +1,162 @@
+/*
+Copyright (C) 2018 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @since 1.1
+ */
+public class JSONObjectTest {
+
+ public JSONObjectTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of creation method, of class JSONObject.
+ */
+ @Test
+ public void testCreate() {
+ System.out.println("JSONObjectTest : testCreate");
+
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("name", "Tom");
+ jsonObj.put("birthday", "1940-02-10");
+ jsonObj.put("age", 76);
+ jsonObj.put("married", false);
+
+ // Cannot set null directly
+ jsonObj.put("car", JSONObject.NULL);
+
+ jsonObj.put("favorite_foods", new String[] { "cookie", "fish", "chips" });
+
+ JSONObject passportJsonObj = new JSONObject();
+ passportJsonObj.put("id", 100001);
+ passportJsonObj.put("nationality", "American");
+ jsonObj.put("passport", passportJsonObj);
+
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Tom", name);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ }
+
+ /**
+ * Test of Equals method, of class JSONObject.
+ */
+ @Test
+ public void testEquals() throws IOException {
+ System.out.println("JSONObjectTest : testEquals");
+
+ URL url = this.getClass().getResource("testJSON.json");
+ JSONObject jsonObj = FileUtils.toJSONObject(url);
+
+ URL url2 = this.getClass().getResource("testJSON2.json");
+ JSONObject jsonObj2 = FileUtils.toJSONObject(url2);
+
+ assertEquals("must be equal", jsonObj, jsonObj2);
+ }
+
+ /**
+ * Test of Equals method, of class JSONObject.
+ */
+ @Test
+ public void testEquals2() throws IOException {
+ System.out.println("JSONObjectTest : testEquals2");
+
+ URL url = this.getClass().getResource("testJSON.json");
+ JSONObject jsonObj = FileUtils.toJSONObject(url);
+
+ URL url2 = this.getClass().getResource("testJSON3.json");
+ JSONObject jsonObj2 = FileUtils.toJSONObject(url2);
+
+ assertFalse("must not be equal", jsonObj.equals(jsonObj2));
+ }
+
+ /**
+ * Test of Equals method, of class JSONObject.
+ */
+ @Test
+ public void testEquals3() throws IOException {
+ System.out.println("JSONObjectTest : testEquals3");
+
+ URL url = this.getClass().getResource("testJSON.json");
+ JSONObject jsonObj = FileUtils.toJSONObject(url);
+
+ URL url2 = this.getClass().getResource("testJSON4.json");
+ JSONObject jsonObj2 = FileUtils.toJSONObject(url2);
+
+ assertFalse("must not be equal", jsonObj.equals(jsonObj2));
+ }
+
+ /**
+ * Test of Equals method, of class JSONObject.
+ */
+ @Test
+ public void testEquals4() throws IOException {
+ System.out.println("JSONObjectTest : testEquals4");
+
+ URL url = this.getClass().getResource("testJSON.json");
+ JSONObject jsonObj = FileUtils.toJSONObject(url);
+
+ URL url2 = this.getClass().getResource("testJSON5.json");
+ JSONObject jsonObj2 = FileUtils.toJSONObject(url2);
+
+ assertEquals("must be equal", jsonObj, jsonObj2);
+ }
+
+}
diff --git a/test/org/json/JSONWriter2Test.java b/test/org/json/JSONWriter2Test.java
new file mode 100644
index 000000000..553bf753d
--- /dev/null
+++ b/test/org/json/JSONWriter2Test.java
@@ -0,0 +1,100 @@
+/*
+Copyright (C) 2019 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import java.io.File;
+import java.io.IOException;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @since 1.4
+ */
+public class JSONWriter2Test {
+
+ public JSONWriter2Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of FileUtils.toFile(JSONObject, File).
+ */
+ @Test
+ public void testWrite() throws IOException {
+ System.out.println("JSONWriter2Test : testWrite");
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("name", "Tom");
+ jsonObj.put("birthday", "1940-02-10");
+ jsonObj.put("age", 76);
+ jsonObj.put("married", false);
+
+ // Cannot set null directly
+ jsonObj.put("car", JSONObject.NULL);
+
+ jsonObj.put("favorite_foods", new String[] { "cookie", "fish", "chips" });
+
+ JSONObject passportJsonObj = new JSONObject();
+ passportJsonObj.put("id", 100001);
+ passportJsonObj.put("nationality", "American");
+ jsonObj.put("passport", passportJsonObj);
+
+ File file = File.createTempFile("json", ".json");
+ FileUtils.toFile(jsonObj, file);
+
+ jsonObj = FileUtils.toJSONObject(file);
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Tom", name);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ }
+}
diff --git a/test/org/json/JSONWriter3Test.java b/test/org/json/JSONWriter3Test.java
new file mode 100644
index 000000000..3a87fc96f
--- /dev/null
+++ b/test/org/json/JSONWriter3Test.java
@@ -0,0 +1,102 @@
+/*
+Copyright (C) 2019 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @since 1.4
+ */
+public class JSONWriter3Test {
+
+ public JSONWriter3Test() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of FileUtils.toURL(JSONObject, URL).
+ */
+ @Test
+ public void testWrite() throws IOException {
+ System.out.println("JSONWriter3Test : testWrite");
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("name", "Tom");
+ jsonObj.put("birthday", "1940-02-10");
+ jsonObj.put("age", 76);
+ jsonObj.put("married", false);
+
+ // Cannot set null directly
+ jsonObj.put("car", JSONObject.NULL);
+
+ jsonObj.put("favorite_foods", new String[] { "cookie", "fish", "chips" });
+
+ JSONObject passportJsonObj = new JSONObject();
+ passportJsonObj.put("id", 100001);
+ passportJsonObj.put("nationality", "American");
+ jsonObj.put("passport", passportJsonObj);
+
+ File file = File.createTempFile("json", ".json");
+ URL url = file.toURI().toURL();
+ FileUtils.toURL(jsonObj, url);
+
+ jsonObj = FileUtils.toJSONObject(url);
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Tom", name);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ }
+}
diff --git a/test/org/json/JSONWriterTest.java b/test/org/json/JSONWriterTest.java
new file mode 100644
index 000000000..f04bdb0ba
--- /dev/null
+++ b/test/org/json/JSONWriterTest.java
@@ -0,0 +1,108 @@
+/*
+Copyright (C) 2018, 2019 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @version 1.4
+ */
+public class JSONWriterTest {
+
+ public JSONWriterTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of FileUtils.toJSONObject(File).
+ */
+ @Test
+ public void testWrite() throws IOException {
+ System.out.println("JSONWriterTest : testWrite");
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("name", "Tom");
+ jsonObj.put("birthday", "1940-02-10");
+ jsonObj.put("age", 76);
+ jsonObj.put("married", false);
+
+ // Cannot set null directly
+ jsonObj.put("car", JSONObject.NULL);
+
+ jsonObj.put("favorite_foods", new String[] { "cookie", "fish", "chips" });
+
+ JSONObject passportJsonObj = new JSONObject();
+ passportJsonObj.put("id", 100001);
+ passportJsonObj.put("nationality", "American");
+ jsonObj.put("passport", passportJsonObj);
+
+ File file = File.createTempFile("json", ".json");
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
+ jsonObj.write(writer);
+ writer.flush();
+ jsonObj = FileUtils.toJSONObject(file);
+
+ boolean isMarried = jsonObj.getBoolean("married");
+ assertFalse("married", isMarried);
+ int age = jsonObj.getInt("age");
+ assertEquals("age", 76, age);
+ String name = jsonObj.getString("name");
+ assertEquals("name", "Tom", name);
+
+ JSONObject jsonObjField = jsonObj.getJSONObject("passport");
+ assertNotNull("passport", jsonObjField);
+ int id = jsonObjField.getInt("id");
+ assertEquals("id", 100001, id);
+ String nationality = jsonObjField.getString("nationality");
+ assertEquals("nationality", "American", nationality);
+ } catch (IOException e) {
+ fail("Could not write JSON content");
+ }
+ }
+}
diff --git a/test/org/json/TestUtilities.java b/test/org/json/TestUtilities.java
new file mode 100644
index 000000000..c49378e82
--- /dev/null
+++ b/test/org/json/TestUtilities.java
@@ -0,0 +1,64 @@
+/*
+Copyright (C) 2021 by Herve Girod
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+package org.json;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+
+/**
+ *
+ * @since 1.7.2
+ */
+public class TestUtilities {
+
+ public static boolean checkContent(URL url1, URL url2) {
+ String content1 = getContent(url1);
+ String content2 = getContent(url2);
+ return content1.equals(content2);
+
+ }
+
+ public static String getContent(URL url) {
+ StringBuilder buf = new StringBuilder();
+ try {
+ try (
+ BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
+ // write the output to stdout
+ boolean first = true;
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (first) {
+ first = false;
+ } else {
+ buf.append("\n");
+ }
+ buf.append(line);
+ }
+ reader.close();
+ }
+ } catch (IOException e) {
+ }
+ return buf.toString();
+ }
+}
diff --git a/test/org/json/comments/comments1.json b/test/org/json/comments/comments1.json
new file mode 100644
index 000000000..42d377e90
--- /dev/null
+++ b/test/org/json/comments/comments1.json
@@ -0,0 +1,10 @@
+{
+ /* this is a comment
+ */
+ "age": 23,
+ "children": [
+ {"name": "Paul"},
+ {"name": "Suzanne"}
+ ],
+ "name": "Bob"
+}
\ No newline at end of file
diff --git a/test/org/json/comments/comments2.json b/test/org/json/comments/comments2.json
new file mode 100644
index 000000000..9af4d4a31
--- /dev/null
+++ b/test/org/json/comments/comments2.json
@@ -0,0 +1,11 @@
+{
+ /* this is a comment
+ */
+ "age": 23,
+ "children": [
+ /* this is a second comment */
+ {"name": "Paul"},
+ {"name": "Suzanne"}
+ ],
+ "name": "Bob"
+}
\ No newline at end of file
diff --git a/test/org/json/expected/expected1.json b/test/org/json/expected/expected1.json
new file mode 100644
index 000000000..a0394d619
--- /dev/null
+++ b/test/org/json/expected/expected1.json
@@ -0,0 +1 @@
+{"age":23,"children":[{"name":"Paul"},{"name":"Suzanne"}],"name":"Bob"}
\ No newline at end of file
diff --git a/test/org/json/expected/expected2.json b/test/org/json/expected/expected2.json
new file mode 100644
index 000000000..74d22dc72
--- /dev/null
+++ b/test/org/json/expected/expected2.json
@@ -0,0 +1 @@
+var a = {"age":23,"children":[{"name":"Paul"},{"name":"Suzanne"}],"name":"Bob"}
\ No newline at end of file
diff --git a/test/org/json/expected/expected3.json b/test/org/json/expected/expected3.json
new file mode 100644
index 000000000..fc29cba95
--- /dev/null
+++ b/test/org/json/expected/expected3.json
@@ -0,0 +1,8 @@
+{
+ "age": 23,
+ "children": [
+ {"name": "Paul"},
+ {"name": "Suzanne"}
+ ],
+ "name": "Bob"
+}
\ No newline at end of file
diff --git a/test/org/json/expected/expected4.json b/test/org/json/expected/expected4.json
new file mode 100644
index 000000000..3070d66df
--- /dev/null
+++ b/test/org/json/expected/expected4.json
@@ -0,0 +1,10 @@
+{
+ "person": {
+ "age": 23,
+ "children": [
+ {"name": "Paul"},
+ {"name": "Suzanne"}
+ ],
+ "name": "Bob"
+ }
+}
\ No newline at end of file
diff --git a/test/org/json/expected/expected5.json b/test/org/json/expected/expected5.json
new file mode 100644
index 000000000..c411ff3de
--- /dev/null
+++ b/test/org/json/expected/expected5.json
@@ -0,0 +1,14 @@
+{
+ "person": {
+ "age": 23,
+ "children": [
+ {
+ "name": "Paul"
+ },
+ {
+ "name": "Suzanne"
+ }
+ ],
+ "name": "Bob"
+ }
+}
\ No newline at end of file
diff --git a/test/org/json/expected/expected6.json b/test/org/json/expected/expected6.json
new file mode 100644
index 000000000..2683a531c
--- /dev/null
+++ b/test/org/json/expected/expected6.json
@@ -0,0 +1,8 @@
+{"person": {
+ "age": 23,
+ "children": [
+ {"name": "Paul"},
+ {"name": "Suzanne"}
+ ],
+ "name": "Bob"
+}}
\ No newline at end of file
diff --git a/test/org/json/expected/expected7.json b/test/org/json/expected/expected7.json
new file mode 100644
index 000000000..e8a79f780
--- /dev/null
+++ b/test/org/json/expected/expected7.json
@@ -0,0 +1,7 @@
+{
+ "person": {
+ "age": 23,
+ "child": {"name": "Paul"},
+ "name": "Bob"
+ }
+}
\ No newline at end of file
diff --git a/test/org/json/expected/expected8.json b/test/org/json/expected/expected8.json
new file mode 100644
index 000000000..b20cbf1cf
--- /dev/null
+++ b/test/org/json/expected/expected8.json
@@ -0,0 +1,7 @@
+{
+ "person": {
+ "age": 23,
+ "children": [1, 2, 3],
+ "name": "Bob"
+ }
+}
\ No newline at end of file
diff --git a/test/org/json/expected/expected9.json b/test/org/json/expected/expected9.json
new file mode 100644
index 000000000..34d39a6f3
--- /dev/null
+++ b/test/org/json/expected/expected9.json
@@ -0,0 +1,7 @@
+{
+ "person": {
+ "age": 23,
+ "children": ["A", "B", "C"],
+ "name": "Bob"
+ }
+}
\ No newline at end of file
diff --git a/test/org/json/stleary/CDLTest.java b/test/org/json/stleary/CDLTest.java
new file mode 100644
index 000000000..9a441dac7
--- /dev/null
+++ b/test/org/json/stleary/CDLTest.java
@@ -0,0 +1,298 @@
+package org.json.stleary;
+
+import static org.junit.Assert.*;
+import org.json.CDL;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.junit.Test;
+
+/**
+ * Tests for CDL.java.
+ * CDL provides an application level API, but it is not used by the
+ * reference app. To test it, strings will be converted to JSON-Java classes
+ * and then converted back.
+ */
+public class CDLTest {
+
+ /**
+ * String of lines where the column names are in the first row,
+ * and all subsequent rows are values. All keys and values should be legal.
+ */
+ String lines = new String(
+ "Col 1, Col 2, \tCol 3, Col 4, Col 5, Col 6, Col 7\n"
+ + "val1, val2, val3, val4, val5, val6, val7\n"
+ + "1, 2, 3, 4\t, 5, 6, 7\n"
+ + "true, false, true, true, false, false, false\n"
+ + "0.23, 57.42, 5e27, -234.879, 2.34e5, 0.0, 9e-3\n"
+ + "\"va\tl1\", \"v\bal2\", \"val3\", \"val\f4\", \"val5\", va\'l6, val7\n"
+ );
+
+ /**
+ * CDL.toJSONArray() adds all values asstrings, with no filtering or
+ * conversions. For testing, this means that the expected JSONObject
+ * values all must be quoted in the cases where the JSONObject parsing
+ * might normally convert the value into a non-string.
+ */
+ String expectedLines = new String(
+ "[{Col 1:val1, Col 2:val2, Col 3:val3, Col 4:val4, Col 5:val5, Col 6:val6, Col 7:val7}, "
+ + "{Col 1:\"1\", Col 2:\"2\", Col 3:\"3\", Col 4:\"4\", Col 5:\"5\", Col 6:\"6\", Col 7:\"7\"}, "
+ + "{Col 1:\"true\", Col 2:\"false\", Col 3:\"true\", Col 4:\"true\", Col 5:\"false\", Col 6:\"false\", Col 7:\"false\"}, "
+ + "{Col 1:\"0.23\", Col 2:\"57.42\", Col 3:\"5e27\", Col 4:\"-234.879\", Col 5:\"2.34e5\", Col 6:\"0.0\", Col 7:\"9e-3\"}, "
+ + "{Col 1:\"va\tl1\", Col 2:\"v\bal2\", Col 3:val3, Col 4:\"val\f4\", Col 5:val5, Col 6:va\'l6, Col 7:val7}]");
+
+ /**
+ * Attempts to create a JSONArray from a null string.
+ * Expect a NullPointerException.
+ */
+ @Test(expected = NullPointerException.class)
+ public void exceptionOnNullString() {
+ String nullStr = null;
+ CDL.toJSONArray(nullStr);
+ }
+
+ /**
+ * Attempts to create a JSONArray from a string with unbalanced quotes
+ * in column title line. Expects a JSONException.
+ */
+ @Test
+ public void unbalancedQuoteInName() {
+ String badLine = "Col1, \"Col2\nVal1, Val2";
+ try {
+ CDL.toJSONArray(badLine);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Missing close quote '\"'. at 12 [character 0 line 2]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Attempts to create a JSONArray from a string with unbalanced quotes
+ * in value line. Expects a JSONException.
+ */
+ @Test
+ public void unbalancedQuoteInValue() {
+ String badLine = "Col1, Col2\n\"Val1, Val2";
+ try {
+ CDL.toJSONArray(badLine);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Missing close quote '\"'. at 22 [character 11 line 2]",
+ e.getMessage());
+
+ }
+ }
+
+ /**
+ * Attempts to create a JSONArray from a string with null char
+ * in column title line. Expects a JSONException.
+ */
+ @Test
+ public void nullInName() {
+ String badLine = "C\0ol1, Col2\nVal1, Val2";
+ try {
+ CDL.toJSONArray(badLine);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Bad character 'o' (111). at 2 [character 3 line 1]",
+ e.getMessage());
+
+ }
+ }
+
+ /**
+ * Attempt to create a JSONArray with unbalanced quotes and a properly escaped doubled quote.
+ * Expects a JSONException.
+ */
+ @Test
+ public void unbalancedEscapedQuote() {
+ String badLine = "Col1, Col2\n\"Val1, \"\"Val2\"\"";
+ try {
+ CDL.toJSONArray(badLine);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Missing close quote '\"'. at 26 [character 15 line 2]",
+ e.getMessage());
+
+ }
+ }
+
+ /**
+ * Assert that there is no error for a single escaped quote within a properly embedded quote.
+ */
+ @Test
+ public void singleEscapedQuote() {
+ String singleEscape = "Col1, Col2\nVal1, \"\"\"Val2\"";
+ JSONArray jsonArray = CDL.toJSONArray(singleEscape);
+
+ String cdlStr = CDL.toString(jsonArray);
+ assertTrue(cdlStr.contains("Col1"));
+ assertTrue(cdlStr.contains("Col2"));
+ assertTrue(cdlStr.contains("Val1"));
+ assertTrue(cdlStr.contains("\"Val2"));
+ }
+
+ /**
+ * Assert that there is no error for a single escaped quote within a properly
+ * embedded quote when not the last value.
+ */
+ @Test
+ public void singleEscapedQuoteMiddleString() {
+ String singleEscape = "Col1, Col2\nVal1, \"\"\"Val2\"\nVal 3,Val 4";
+ JSONArray jsonArray = CDL.toJSONArray(singleEscape);
+
+ String cdlStr = CDL.toString(jsonArray);
+ assertTrue(cdlStr.contains("Col1"));
+ assertTrue(cdlStr.contains("Col2"));
+ assertTrue(cdlStr.contains("Val1"));
+ assertTrue(cdlStr.contains("\"Val2"));
+ }
+
+ /**
+ * Attempt to create a JSONArray with an escape quote and no enclosing quotes.
+ * Expects a JSONException.
+ */
+ @Test
+ public void badEscapedQuote() {
+ String badLine = "Col1, Col2\nVal1, \"\"Val2";
+
+ try {
+ CDL.toJSONArray(badLine);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ System.out.println("Message" + e.getMessage());
+ assertEquals("Expecting an exception message",
+ "Bad character 'V' (86). at 20 [character 9 line 2]",
+ e.getMessage());
+
+ }
+
+ }
+
+ /**
+ * call toString with a null array
+ */
+ @Test(expected = NullPointerException.class)
+ public void nullJSONArrayToString() {
+ CDL.toString((JSONArray) null);
+ }
+
+ /**
+ * Create a JSONArray from an empty string
+ */
+ @Test
+ public void emptyString() {
+ String emptyStr = "";
+ JSONArray jsonArray = CDL.toJSONArray(emptyStr);
+ assertTrue("CDL should return null when the input string is empty",
+ jsonArray == null);
+ }
+
+ /**
+ * Create a JSONArray with only 1 row
+ */
+ @Test
+ public void onlyColumnNames() {
+ String columnNameStr = "col1, col2, col3";
+ JSONArray jsonArray = CDL.toJSONArray(columnNameStr);
+ assertNull("CDL should return null when only 1 row is given",
+ jsonArray);
+ }
+
+ /**
+ * Create a JSONArray from string containing only whitespace and commas
+ */
+ @Test
+ public void emptyLinesToJSONArray() {
+ String str = " , , , \n , , , ";
+ JSONArray jsonArray = CDL.toJSONArray(str);
+ assertNull("JSONArray should be null for no content",
+ jsonArray);
+ }
+
+ /**
+ * call toString with a null array
+ */
+ @Test
+ public void emptyJSONArrayToString() {
+ JSONArray jsonArray = new JSONArray();
+ String str = CDL.toString(jsonArray);
+ assertNull("CDL should return null for toString(null)",
+ str);
+ }
+
+ /**
+ * call toString with a null arrays for names and values
+ */
+ @Test
+ public void nullJSONArraysToString() {
+ String str = CDL.toString(null, null);
+ assertNull("CDL should return null for toString(null)",
+ str);
+ }
+
+ /**
+ * Given a JSONArray that was not built by CDL, some chars may be
+ * found that would otherwise be filtered out by CDL.
+ */
+ @Test
+ public void checkSpecialChars() {
+ JSONArray jsonArray = new JSONArray();
+ JSONObject jsonObject = new JSONObject();
+ jsonArray.put(jsonObject);
+ // \r will be filtered from name
+ jsonObject.put("Col \r1", "V1");
+ // \r will be filtered from value
+ jsonObject.put("Col 2", "V2\r");
+ assertTrue("expected length should be 1", jsonArray.length() == 1);
+ String cdlStr = CDL.toString(jsonArray);
+ jsonObject = jsonArray.getJSONObject(0);
+ assertTrue(cdlStr.contains("\"Col 1\""));
+ assertTrue(cdlStr.contains("Col 2"));
+ assertTrue(cdlStr.contains("V1"));
+ assertTrue(cdlStr.contains("\"V2\""));
+ }
+
+ /**
+ * Create a JSONArray from a string of lines
+ */
+ @Test
+ public void textToJSONArray() {
+ JSONArray jsonArray = CDL.toJSONArray(lines);
+ JSONArray expectedJsonArray = new JSONArray(expectedLines);
+ Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray);
+ }
+
+ /**
+ * Create a JSONArray from a JSONArray of titles and a
+ * string of value lines
+ */
+ @Test
+ public void jsonArrayToJSONArray() {
+ String nameArrayStr = "[Col1, Col2]";
+ String values = "V1, V2";
+ JSONArray nameJSONArray = new JSONArray(nameArrayStr);
+ JSONArray jsonArray = CDL.toJSONArray(nameJSONArray, values);
+ JSONArray expectedJsonArray = new JSONArray("[{Col1:V1,Col2:V2}]");
+ Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray);
+ }
+
+ /**
+ * Create a JSONArray from a string of lines,
+ * then convert to string and then back to JSONArray
+ */
+ @Test
+ public void textToJSONArrayAndBackToString() {
+ JSONArray jsonArray = CDL.toJSONArray(lines);
+ String jsonStr = CDL.toString(jsonArray);
+ JSONArray finalJsonArray = CDL.toJSONArray(jsonStr);
+ JSONArray expectedJsonArray = new JSONArray(expectedLines);
+ Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray);
+ }
+
+}
diff --git a/test/org/json/stleary/CookieTest.java b/test/org/json/stleary/CookieTest.java
new file mode 100644
index 000000000..013d5ef0d
--- /dev/null
+++ b/test/org/json/stleary/CookieTest.java
@@ -0,0 +1,222 @@
+package org.json.stleary;
+
+import static org.junit.Assert.*;
+import org.json.*;
+import org.junit.Test;
+
+/**
+ * HTTP cookie specification: RFC6265
+ *
+ * At its most basic, a cookie is a name=value pair. The value may be subdivided
+ * into other cookies, but that is not tested here. The cookie may also include
+ * certain named attributes, delimited by semicolons.
+ *
+ * The Cookie.toString() method emits certain attributes if present: expires,
+ * domain, path, secure. All but secure are name-value pairs. Other attributes
+ * are not included in the toString() output.
+ *
+ * A JSON-Java encoded cookie escapes '+', '%', '=', ';' with %hh values.
+ */
+public class CookieTest {
+
+ /**
+ * Attempts to create a JSONObject from a null string.
+ * Expects a NullPointerException.
+ */
+ @Test(expected = NullPointerException.class)
+ public void nullCookieException() {
+ String cookieStr = null;
+ Cookie.toJSONObject(cookieStr);
+ }
+
+ /**
+ * Attempts to create a JSONObject from a cookie string with
+ * no '=' char.
+ * Expects a JSONException.
+ */
+ @Test
+ public void malFormedNameValueException() {
+ String cookieStr = "thisCookieHasNoEqualsChar";
+ try {
+ Cookie.toJSONObject(cookieStr);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Expected '=' and instead saw '' at 25 [character 26 line 1]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Attempts to create a JSONObject from a cookie string
+ * with embedded ';' char.
+ * Expects a JSONException.
+ */
+ @Test
+ public void malFormedAttributeException() {
+ String cookieStr = "this=Cookie;myAttribute";
+ try {
+ Cookie.toJSONObject(cookieStr);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Missing '=' in cookie parameter. at 23 [character 24 line 1]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Attempts to create a JSONObject from an empty cookie string.
+ * Note: Cookie throws an exception, but CookieList does not.
+ * Expects a JSONException
+ */
+ @Test
+ public void emptyStringCookieException() {
+ String cookieStr = "";
+ try {
+ Cookie.toJSONObject(cookieStr);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Expected '=' and instead saw '' at 0 [character 1 line 1]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Cookie from a simple name/value pair with no delimiter
+ */
+ @Test
+ public void simpleCookie() {
+ String cookieStr = "SID=31d4d96e407aad42";
+ String expectedCookieStr = "{\"name\":\"SID\",\"value\":\"31d4d96e407aad42\"}";
+ JSONObject jsonObject = Cookie.toJSONObject(cookieStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedCookieStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
+ }
+
+ /**
+ * Store a cookie with all of the supported attributes in a
+ * JSONObject. The secure attribute, which has no value, is treated
+ * as a boolean.
+ */
+ @Test
+ public void multiPartCookie() {
+ String cookieStr
+ = "PH=deleted; "
+ + " expires=Wed, 19-Mar-2014 17:53:53 GMT;"
+ + "path=/; "
+ + " domain=.yahoo.com;"
+ + "secure";
+ String expectedCookieStr
+ = "{"
+ + "\"name\":\"PH\","
+ + "\"value\":\"deleted\","
+ + "\"path\":\"/\","
+ + "\"expires\":\"Wed, 19-Mar-2014 17:53:53 GMT\","
+ + "\"domain\":\".yahoo.com\","
+ + "\"secure\":true"
+ + "}";
+ JSONObject jsonObject = Cookie.toJSONObject(cookieStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedCookieStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
+ }
+
+ /**
+ * Cookie.toString() will omit the non-standard "thiswont=beIncluded"
+ * attribute, but the attribute is still stored in the JSONObject.
+ * This test confirms both behaviors.
+ */
+ @Test
+ public void convertCookieToString() {
+ String cookieStr
+ = "PH=deleted; "
+ + " expires=Wed, 19-Mar-2014 17:53:53 GMT;"
+ + "path=/; "
+ + " domain=.yahoo.com;"
+ + "thisWont=beIncluded;"
+ + "secure";
+ String expectedCookieStr
+ = "{\"path\":\"/\","
+ + "\"expires\":\"Wed, 19-Mar-2014 17:53:53 GMT\","
+ + "\"domain\":\".yahoo.com\","
+ + "\"name\":\"PH\","
+ + "\"secure\":true,"
+ + "\"value\":\"deleted\"}";
+ // Add the nonstandard attribute to the expected cookie string
+ String expectedDirectCompareCookieStr
+ = expectedCookieStr.replaceAll("\\{", "\\{\"thisWont\":\"beIncluded\",");
+ // convert all strings into JSONObjects
+ JSONObject jsonObject = Cookie.toJSONObject(cookieStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedCookieStr);
+ JSONObject expectedDirectCompareJsonObject
+ = new JSONObject(expectedDirectCompareCookieStr);
+ // emit the string
+ String cookieToStr = Cookie.toString(jsonObject);
+ // create a final JSONObject from the string
+ JSONObject finalJsonObject = Cookie.toJSONObject(cookieToStr);
+ // JSONObject should contain the nonstandard string
+ Util.compareActualVsExpectedJsonObjects(jsonObject, expectedDirectCompareJsonObject);
+ // JSONObject -> string -> JSONObject should not contain the nonstandard string
+ Util.compareActualVsExpectedJsonObjects(finalJsonObject, expectedJsonObject);
+ }
+
+ /**
+ * A string may be URL-encoded when converting to JSONObject.
+ * If found, '+' is converted to ' ', and %hh hex strings are converted
+ * to their ascii char equivalents. This test confirms the decoding
+ * behavior.
+ */
+ @Test
+ public void convertEncodedCookieToString() {
+ String cookieStr
+ = "PH=deleted; "
+ + " expires=Wed,+19-Mar-2014+17:53:53+GMT;"
+ + "path=/%2Bthis/is%26/a/spec%3Bsegment%3D; "
+ + " domain=.yahoo.com;"
+ + "secure";
+ String expectedCookieStr
+ = "{\"path\":\"/+this/is&/a/spec;segment=\","
+ + "\"expires\":\"Wed, 19-Mar-2014 17:53:53 GMT\","
+ + "\"domain\":\".yahoo.com\","
+ + "\"name\":\"PH\","
+ + "\"secure\":true,"
+ + "\"value\":\"deleted\"}";
+ JSONObject jsonObject = Cookie.toJSONObject(cookieStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedCookieStr);
+ String cookieToStr = Cookie.toString(jsonObject);
+ JSONObject finalJsonObject = Cookie.toJSONObject(cookieToStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
+ Util.compareActualVsExpectedJsonObjects(finalJsonObject, expectedJsonObject);
+ }
+
+ /**
+ * A public API method performs a URL encoding for selected chars
+ * in a string. Control chars, '+', '%', '=', ';' are all encoded
+ * as %hh hex strings. The string is also trimmed.
+ * This test confirms that behavior.
+ */
+ @Test
+ public void escapeString() {
+ String str = " +%\r\n\t\b%=;;; ";
+ String expectedStr = "%2b%25%0d%0a%09%08%25%3d%3b%3b%3b";
+ String actualStr = Cookie.escape(str);
+ assertTrue("expect escape() to encode correctly. Actual: " + actualStr
+ + " expected: " + expectedStr, expectedStr.equals(actualStr));
+ }
+
+ /**
+ * A public API method performs URL decoding for strings.
+ * '+' is converted to space and %hh hex strings are converted to
+ * their ascii equivalent values. The string is not trimmed.
+ * This test confirms that behavior.
+ */
+ @Test
+ public void unescapeString() {
+ String str = " +%2b%25%0d%0a%09%08%25%3d%3b%3b%3b+ ";
+ String expectedStr = " +%\r\n\t\b%=;;; ";
+ String actualStr = Cookie.unescape(str);
+ assertTrue("expect unescape() to decode correctly. Actual: " + actualStr
+ + " expected: " + expectedStr, expectedStr.equals(actualStr));
+ }
+}
diff --git a/test/org/json/stleary/HTTPTest.java b/test/org/json/stleary/HTTPTest.java
new file mode 100644
index 000000000..53f5cfcb1
--- /dev/null
+++ b/test/org/json/stleary/HTTPTest.java
@@ -0,0 +1,194 @@
+package org.json.stleary;
+
+import static org.junit.Assert.*;
+import org.json.*;
+import org.junit.Test;
+
+/**
+ * Unit tests for JSON-Java HTTP.java. See RFC7230.
+ */
+public class HTTPTest {
+
+ /**
+ * Attempt to call HTTP.toJSONObject() with a null string
+ * Expects a NUllPointerException.
+ */
+ @Test(expected = NullPointerException.class)
+ public void nullHTTPException() {
+ String httpStr = null;
+ HTTP.toJSONObject(httpStr);
+ }
+
+ /**
+ * Attempt to call HTTP.toJSONObject() with a string containing
+ * an empty object. Expects a JSONException.
+ */
+ @Test
+ public void notEnoughHTTPException() {
+ String httpStr = "{}";
+ JSONObject jsonObject = new JSONObject(httpStr);
+ try {
+ HTTP.toString(jsonObject);
+ assertTrue("Expected to throw exception", false);
+ } catch (JSONException e) {
+ assertTrue("Expecting an exception message",
+ "Not enough material for an HTTP header.".equals(e.getMessage()));
+ }
+ }
+
+ /**
+ * Calling HTTP.toJSONObject() with an empty string will result in a
+ * populated JSONObject with keys but no values for Request-URI, Method,
+ * and HTTP-Version.
+ */
+ @Test
+ public void emptyStringHTTPRequest() {
+ String httpStr = "";
+ String expectedHTTPStr = "{\"Request-URI\":\"\",\"Method\":\"\",\"HTTP-Version\":\"\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
+ }
+
+ /**
+ * Call HTTP.toJSONObject() with a Request-URI, Method,
+ * and HTTP-Version.
+ */
+ @Test
+ public void simpleHTTPRequest() {
+ String httpStr = "GET /hello.txt HTTP/1.1";
+ String expectedHTTPStr
+ = "{\"Request-URI\":\"/hello.txt\",\"Method\":\"GET\",\"HTTP-Version\":\"HTTP/1.1\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
+ }
+
+ /**
+ * Call HTTP.toJSONObject() with a response string containing a
+ * HTTP-Version, Status-Code, and Reason.
+ */
+ @Test
+ public void simpleHTTPResponse() {
+ String httpStr = "HTTP/1.1 200 OK";
+ String expectedHTTPStr
+ = "{\"HTTP-Version\":\"HTTP/1.1\",\"Status-Code\":\"200\",\"Reason-Phrase\":\"OK\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
+ }
+
+ /**
+ * Call HTTP.toJSONObject() with a full request string including
+ * request headers.
+ */
+ @Test
+ public void extendedHTTPRequest() {
+ String httpStr
+ = "POST /enlighten/calais.asmx HTTP/1.1\n"
+ + "Host: api.opencalais.com\n"
+ + "Content-Type: text/xml; charset=utf-8\n"
+ + "Content-Length: 100\n"
+ + "SOAPAction: \"http://clearforest.com/Enlighten\"";
+ String expectedHTTPStr
+ = "{"
+ + "\"Request-URI\":\"/enlighten/calais.asmx\","
+ + "\"Host\":\"api.opencalais.com\","
+ + "\"Method\":\"POST\","
+ + "\"HTTP-Version\":\"HTTP/1.1\","
+ + "\"Content-Length\":\"100\","
+ + "\"Content-Type\":\"text/xml; charset=utf-8\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ /**
+ * Not too easy for JSONObject to parse a string with embedded quotes.
+ * For the sake of the test, add it here.
+ */
+ expectedJsonObject.put("SOAPAction", "\"http://clearforest.com/Enlighten\"");
+ Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
+ }
+
+ /**
+ * Call HTTP.toJSONObject() with a full response string including
+ * response headers.
+ */
+ @Test
+ public void extendedHTTPResponse() {
+ String httpStr
+ = "HTTP/1.1 200 OK\n"
+ + "Content-Type: text/xml; charset=utf-8\n"
+ + "Content-Length: 100\n";
+ String expectedHTTPStr
+ = "{\"HTTP-Version\":\"HTTP/1.1\","
+ + "\"Status-Code\":\"200\","
+ + "\"Content-Length\":\"100\","
+ + "\"Reason-Phrase\":\"OK\","
+ + "\"Content-Type\":\"text/xml; charset=utf-8\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
+ }
+
+ /**
+ * Call HTTP.toJSONObject() with a full POST request string including
+ * response headers, then convert it back into an HTTP string.
+ */
+ @Test
+ public void convertHTTPRequestToString() {
+ String httpStr
+ = "POST /enlighten/calais.asmx HTTP/1.1\n"
+ + "Host: api.opencalais.com\n"
+ + "Content-Type: text/xml; charset=utf-8\n"
+ + "Content-Length: 100";
+ String expectedHTTPStr
+ = "{"
+ + "\"Request-URI\":\"/enlighten/calais.asmx\","
+ + "\"Host\":\"api.opencalais.com\","
+ + "\"Method\":\"POST\","
+ + "\"HTTP-Version\":\"HTTP/1.1\","
+ + "\"Content-Length\":\"100\","
+ + "\"Content-Type\":\"text/xml; charset=utf-8\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ String httpToStr = HTTP.toString(jsonObject);
+ /**
+ * JSONObject objects to crlfs and any trailing chars.
+ * For the sake of the test, simplify the resulting string
+ */
+ httpToStr = httpToStr.replaceAll("(" + HTTP.CRLF + HTTP.CRLF + ")", "");
+ httpToStr = httpToStr.replaceAll(HTTP.CRLF, "\n");
+ JSONObject finalJsonObject = HTTP.toJSONObject(httpToStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
+ Util.compareActualVsExpectedJsonObjects(finalJsonObject, expectedJsonObject);
+ }
+
+ /**
+ * Call HTTP.toJSONObject() with a full response string including
+ * response headers, then convert it back into an HTTP string.
+ */
+ @Test
+ public void convertHTTPResponseToString() {
+ String httpStr
+ = "HTTP/1.1 200 OK\n"
+ + "Content-Type: text/xml; charset=utf-8\n"
+ + "Content-Length: 100\n";
+ String expectedHTTPStr
+ = "{\"HTTP-Version\":\"HTTP/1.1\","
+ + "\"Status-Code\":\"200\","
+ + "\"Content-Length\":\"100\","
+ + "\"Reason-Phrase\":\"OK\","
+ + "\"Content-Type\":\"text/xml; charset=utf-8\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ String httpToStr = HTTP.toString(jsonObject);
+ /**
+ * JSONObject objects to crlfs and any trailing chars.
+ * For the sake of the test, simplify the resulting string
+ */
+ httpToStr = httpToStr.replaceAll("(" + HTTP.CRLF + HTTP.CRLF + ")", "");
+ httpToStr = httpToStr.replaceAll(HTTP.CRLF, "\n");
+ JSONObject finalJsonObject = HTTP.toJSONObject(httpToStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
+ Util.compareActualVsExpectedJsonObjects(finalJsonObject, expectedJsonObject);
+ }
+}
diff --git a/test/org/json/stleary/JSONObjectLocaleTest.java b/test/org/json/stleary/JSONObjectLocaleTest.java
new file mode 100644
index 000000000..97879dba8
--- /dev/null
+++ b/test/org/json/stleary/JSONObjectLocaleTest.java
@@ -0,0 +1,54 @@
+package org.json.stleary;
+
+import static org.junit.Assert.*;
+import java.util.*;
+import org.json.*;
+import org.json.stleary.data.MyLocaleBean;
+import org.junit.*;
+
+/**
+ * Note: This file is saved as UTF-8. Do not save as ASCII or the tests will
+ * fail.
+ *
+ */
+public class JSONObjectLocaleTest {
+ /**
+ * JSONObject built from a bean with locale-specific keys.
+ * In the Turkish alphabet, there are 2 versions of the letter "i".
+ * 'eh' I ı (dotless i)
+ * 'ee' İ i (dotted i)
+ * A problem can occur when parsing the public get methods for a bean.
+ * If the method starts with getI... then the key name will be lowercased
+ * to 'i' in English, and 'ı' in Turkish.
+ * We want the keys to be consistent regardless of locale, so JSON-Java
+ * lowercase operations are made to be locale-neutral by specifying
+ * Locale.ROOT. This causes 'I' to be universally lowercased to 'i'
+ * regardless of the locale currently in effect.
+ */
+ @Test
+ public void jsonObjectByLocaleBean() {
+
+ MyLocaleBean myLocaleBean = new MyLocaleBean();
+
+ /**
+ * This is just the control case which happens when the locale.ROOT
+ * lowercasing behavior is the same as the current locale.
+ */
+ Locale.setDefault(new Locale("en"));
+ JSONObject jsonen = new JSONObject(myLocaleBean);
+ assertEquals("expected size 2, found: " + jsonen.length(), 2, jsonen.length());
+ assertEquals("expected jsonen[i] == beanI", "beanI", jsonen.getString("i"));
+ assertEquals("expected jsonen[id] == beanId", "beanId", jsonen.getString("id"));
+
+ /**
+ * Without the JSON-Java change, these keys would be stored internally as
+ * starting with the letter, 'ı' (dotless i), since the lowercasing of
+ * the getI and getId keys would be specific to the Turkish locale.
+ */
+ Locale.setDefault(new Locale("tr"));
+ JSONObject jsontr = new JSONObject(myLocaleBean);
+ assertEquals("expected size 2, found: " + jsontr.length(), 2, jsontr.length());
+ assertEquals("expected jsontr[i] == beanI", "beanI", jsontr.getString("i"));
+ assertEquals("expected jsontr[id] == beanId", "beanId", jsontr.getString("id"));
+ }
+}
diff --git a/test/org/json/stleary/JSONPointerTest.java b/test/org/json/stleary/JSONPointerTest.java
new file mode 100644
index 000000000..b5f2892e0
--- /dev/null
+++ b/test/org/json/stleary/JSONPointerTest.java
@@ -0,0 +1,356 @@
+package org.json.stleary;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import java.io.InputStream;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.json.JSONPointer;
+import org.json.JSONPointerException;
+import org.json.JSONTokener;
+import org.junit.Test;
+
+public class JSONPointerTest {
+
+ private static final JSONObject document;
+
+ static {
+ @SuppressWarnings("resource")
+ InputStream resourceAsStream = JSONPointerTest.class.getResourceAsStream("jsonpointer-testdoc.json");
+ if (resourceAsStream == null) {
+ throw new ExceptionInInitializerError("Unable to locate test file. Please check your development environment configuration");
+ }
+ document = new JSONObject(new JSONTokener(resourceAsStream));
+ }
+
+ private Object query(String pointer) {
+ return new JSONPointer(pointer).queryFrom(document);
+ }
+
+ @Test
+ public void emptyPointer() {
+ assertSame(document, query(""));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void nullPointer() {
+ new JSONPointer((String) null);
+ }
+
+ @Test
+ public void objectPropertyQuery() {
+ assertSame(document.get("foo"), query("/foo"));
+ }
+
+ @Test
+ public void arrayIndexQuery() {
+ assertSame(document.getJSONArray("foo").get(0), query("/foo/0"));
+ }
+
+ @Test(expected = JSONPointerException.class)
+ public void stringPropOfArrayFailure() {
+ query("/foo/bar");
+ }
+
+ @Test
+ public void queryByEmptyKey() {
+ assertSame(document.get(""), query("/"));
+ }
+
+ @Test
+ public void queryByEmptyKeySubObject() {
+ assertSame(document.getJSONObject("obj").getJSONObject(""), query("/obj/"));
+ }
+
+ @Test
+ public void queryByEmptyKeySubObjectSubOject() {
+ assertSame(
+ document.getJSONObject("obj").getJSONObject("").get(""),
+ query("/obj//")
+ );
+ }
+
+ @Test
+ public void queryByEmptyKeySubObjectValue() {
+ assertSame(
+ document.getJSONObject("obj").getJSONObject("").get("subKey"),
+ query("/obj//subKey")
+ );
+ }
+
+ @Test
+ public void slashEscaping() {
+ assertSame(document.get("a/b"), query("/a~1b"));
+ }
+
+ @Test
+ public void tildeEscaping() {
+ assertSame(document.get("m~n"), query("/m~0n"));
+ }
+
+ @Test
+ public void backslashEscaping() {
+ assertSame(document.get("i\\j"), query("/i\\\\j"));
+ }
+
+ @Test
+ public void quotationEscaping() {
+ assertSame(document.get("k\"l"), query("/k\\\\\\\"l"));
+ }
+
+ @Test
+ public void whitespaceKey() {
+ assertSame(document.get(" "), query("/ "));
+ }
+
+ @Test
+ public void uriFragmentNotation() {
+ assertSame(document.get("foo"), query("#/foo"));
+ }
+
+ @Test
+ public void uriFragmentNotationRoot() {
+ assertSame(document, query("#"));
+ }
+
+ @Test
+ public void uriFragmentPercentHandling() {
+ assertSame(document.get("c%d"), query("#/c%25d"));
+ assertSame(document.get("e^f"), query("#/e%5Ef"));
+ assertSame(document.get("g|h"), query("#/g%7Ch"));
+ assertSame(document.get("m~n"), query("#/m~0n"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void syntaxError() {
+ new JSONPointer("key");
+ }
+
+ @Test(expected = JSONPointerException.class)
+ public void arrayIndexFailure() {
+ query("/foo/2");
+ }
+
+ @Test(expected = JSONPointerException.class)
+ public void primitiveFailure() {
+ query("/obj/key/failure");
+ }
+
+ @Test
+ public void builderTest() {
+ JSONPointer pointer = JSONPointer.builder()
+ .append("obj")
+ .append("other~key").append("another/key")
+ .append(0)
+ .build();
+ assertEquals("val", pointer.queryFrom(document));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void nullToken() {
+ JSONPointer.builder().append(null);
+ }
+
+ @Test
+ public void toStringEscaping() {
+ JSONPointer pointer = JSONPointer.builder()
+ .append("obj")
+ .append("other~key").append("another/key")
+ .append("\"")
+ .append(0)
+ .build();
+ assertEquals("/obj/other~0key/another~1key/\\\"/0", pointer.toString());
+ }
+
+ @Test
+ public void emptyPointerToString() {
+ assertEquals("", new JSONPointer("").toString());
+ }
+
+ @Test
+ public void toURIFragment() {
+ assertEquals("#/c%25d", new JSONPointer("/c%d").toURIFragment());
+ assertEquals("#/e%5Ef", new JSONPointer("/e^f").toURIFragment());
+ assertEquals("#/g%7Ch", new JSONPointer("/g|h").toURIFragment());
+ assertEquals("#/m%7En", new JSONPointer("/m~n").toURIFragment());
+ }
+
+ @Test
+ public void tokenListIsCopiedInConstructor() {
+ JSONPointer.Builder b = JSONPointer.builder().append("key1");
+ JSONPointer jp1 = b.build();
+ b.append("key2");
+ JSONPointer jp2 = b.build();
+ if (jp1.toString().equals(jp2.toString())) {
+ fail("Oops, my pointers are sharing a backing array");
+ }
+ }
+
+ /**
+ * Coverage for JSONObject query(String)
+ */
+ @Test
+ public void queryFromJSONObject() {
+ String str = "{"
+ + "\"stringKey\":\"hello world!\","
+ + "\"arrayKey\":[0,1,2],"
+ + "\"objectKey\": {"
+ + "\"a\":\"aVal\","
+ + "\"b\":\"bVal\""
+ + "}"
+ + "}";
+ JSONObject jsonObject = new JSONObject(str);
+ Object obj = jsonObject.query("/stringKey");
+ assertTrue("Expected 'hello world!'", "hello world!".equals(obj));
+ obj = jsonObject.query("/arrayKey/1");
+ assertTrue("Expected 1", Integer.valueOf(1).equals(obj));
+ obj = jsonObject.query("/objectKey/b");
+ assertTrue("Expected bVal", "bVal".equals(obj));
+ try {
+ obj = jsonObject.query("/a/b/c");
+ assertTrue("Expected JSONPointerException", false);
+ } catch (JSONPointerException e) {
+ assertTrue("Expected bad key/value exception",
+ "value [null] is not an array or object therefore its key b cannot be resolved".
+ equals(e.getMessage()));
+ }
+ }
+
+ /**
+ * Coverage for JSONObject query(JSONPointer)
+ */
+ @Test
+ public void queryFromJSONObjectUsingPointer() {
+ String str = "{"
+ + "\"stringKey\":\"hello world!\","
+ + "\"arrayKey\":[0,1,2],"
+ + "\"objectKey\": {"
+ + "\"a\":\"aVal\","
+ + "\"b\":\"bVal\""
+ + "}"
+ + "}";
+ JSONObject jsonObject = new JSONObject(str);
+ Object obj = jsonObject.query(new JSONPointer("/stringKey"));
+ assertTrue("Expected 'hello world!'", "hello world!".equals(obj));
+ obj = jsonObject.query(new JSONPointer("/arrayKey/1"));
+ assertTrue("Expected 1", Integer.valueOf(1).equals(obj));
+ obj = jsonObject.query(new JSONPointer("/objectKey/b"));
+ assertTrue("Expected bVal", "bVal".equals(obj));
+ try {
+ obj = jsonObject.query(new JSONPointer("/a/b/c"));
+ assertTrue("Expected JSONPointerException", false);
+ } catch (JSONPointerException e) {
+ assertTrue("Expected bad key/value exception",
+ "value [null] is not an array or object therefore its key b cannot be resolved".
+ equals(e.getMessage()));
+ }
+ }
+
+ /**
+ * Coverage for JSONObject optQuery(JSONPointer)
+ */
+ @Test
+ public void optQueryFromJSONObjectUsingPointer() {
+ String str = "{"
+ + "\"stringKey\":\"hello world!\","
+ + "\"arrayKey\":[0,1,2],"
+ + "\"objectKey\": {"
+ + "\"a\":\"aVal\","
+ + "\"b\":\"bVal\""
+ + "}"
+ + "}";
+ JSONObject jsonObject = new JSONObject(str);
+ Object obj = jsonObject.optQuery(new JSONPointer("/stringKey"));
+ assertTrue("Expected 'hello world!'", "hello world!".equals(obj));
+ obj = jsonObject.optQuery(new JSONPointer("/arrayKey/1"));
+ assertTrue("Expected 1", Integer.valueOf(1).equals(obj));
+ obj = jsonObject.optQuery(new JSONPointer("/objectKey/b"));
+ assertTrue("Expected bVal", "bVal".equals(obj));
+ obj = jsonObject.optQuery(new JSONPointer("/a/b/c"));
+ assertTrue("Expected null", obj == null);
+ }
+
+ /**
+ * Coverage for JSONArray query(String)
+ */
+ @Test
+ public void queryFromJSONArray() {
+ String str = "["
+ + "\"hello world!\","
+ + "[0,1,2],"
+ + "{"
+ + "\"a\":\"aVal\","
+ + "\"b\":\"bVal\""
+ + "}"
+ + "]";
+ JSONArray jsonArray = new JSONArray(str);
+ Object obj = jsonArray.query("/0");
+ assertTrue("Expected 'hello world!'", "hello world!".equals(obj));
+ obj = jsonArray.query("/1/1");
+ assertTrue("Expected 1", Integer.valueOf(1).equals(obj));
+ obj = jsonArray.query("/2/b");
+ assertTrue("Expected bVal", "bVal".equals(obj));
+ try {
+ obj = jsonArray.query("/a/b/c");
+ assertTrue("Expected JSONPointerException", false);
+ } catch (JSONPointerException e) {
+ assertTrue("Expected bad index exception",
+ "a is not an array index".equals(e.getMessage()));
+ }
+ }
+
+ /**
+ * Coverage for JSONArray query(JSONPointer)
+ */
+ @Test
+ public void queryFromJSONArrayUsingPointer() {
+ String str = "["
+ + "\"hello world!\","
+ + "[0,1,2],"
+ + "{"
+ + "\"a\":\"aVal\","
+ + "\"b\":\"bVal\""
+ + "}"
+ + "]";
+ JSONArray jsonArray = new JSONArray(str);
+ Object obj = jsonArray.query(new JSONPointer("/0"));
+ assertTrue("Expected 'hello world!'", "hello world!".equals(obj));
+ obj = jsonArray.query(new JSONPointer("/1/1"));
+ assertTrue("Expected 1", Integer.valueOf(1).equals(obj));
+ obj = jsonArray.query(new JSONPointer("/2/b"));
+ assertTrue("Expected bVal", "bVal".equals(obj));
+ try {
+ obj = jsonArray.query(new JSONPointer("/a/b/c"));
+ assertTrue("Expected JSONPointerException", false);
+ } catch (JSONPointerException e) {
+ assertTrue("Expected bad index exception",
+ "a is not an array index".equals(e.getMessage()));
+ }
+ }
+
+ /**
+ * Coverage for JSONArray optQuery(JSONPointer)
+ */
+ @Test
+ public void optQueryFromJSONArrayUsingPointer() {
+ String str = "["
+ + "\"hello world!\","
+ + "[0,1,2],"
+ + "{"
+ + "\"a\":\"aVal\","
+ + "\"b\":\"bVal\""
+ + "}"
+ + "]";
+ JSONArray jsonArray = new JSONArray(str);
+ Object obj = jsonArray.optQuery(new JSONPointer("/0"));
+ assertTrue("Expected 'hello world!'", "hello world!".equals(obj));
+ obj = jsonArray.optQuery(new JSONPointer("/1/1"));
+ assertTrue("Expected 1", Integer.valueOf(1).equals(obj));
+ obj = jsonArray.optQuery(new JSONPointer("/2/b"));
+ assertTrue("Expected bVal", "bVal".equals(obj));
+ obj = jsonArray.optQuery(new JSONPointer("/a/b/c"));
+ assertTrue("Expected null", obj == null);
+ }
+}
diff --git a/test/org/json/stleary/JSONStringTest.java b/test/org/json/stleary/JSONStringTest.java
new file mode 100644
index 000000000..6746ea3fd
--- /dev/null
+++ b/test/org/json/stleary/JSONStringTest.java
@@ -0,0 +1,369 @@
+package org.json.stleary;
+
+import static org.junit.Assert.*;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.*;
+import org.json.*;
+import org.junit.Test;
+
+/**
+ * Tests for JSONString implementations, and the difference between
+ * {@link JSONObject#valueToString} and {@link JSONObject#writeValue}.
+ */
+public class JSONStringTest {
+
+ /**
+ * This tests the JSONObject.writeValue() method. We can't test directly
+ * due to it being a package-protected method. Instead, we can call
+ * JSONArray.write(), which delegates the writing of each entry to
+ * writeValue().
+ */
+ @Test
+ public void writeValues() throws Exception {
+ JSONArray jsonArray = new JSONArray();
+ jsonArray.put((Object) null);
+
+ StringWriter writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[null]".equals(output));
+
+ jsonArray = new JSONArray();
+ jsonArray.put(JSONObject.NULL);
+ } finally {
+ writer.close();
+ }
+ writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[null]".equals(output));
+
+ jsonArray = new JSONArray();
+ jsonArray.put(new JSONObject());
+ } finally {
+ writer.close();
+ }
+ writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[{}]".equals(output));
+
+ jsonArray = new JSONArray();
+ jsonArray.put(new JSONArray());
+ } finally {
+ writer.close();
+ }
+ writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[[]]".equals(output));
+
+ jsonArray = new JSONArray();
+ Map, ?> singleMap = Collections.singletonMap("key1", "value1");
+ jsonArray.put((Object) singleMap);
+ } finally {
+ writer.close();
+ }
+ writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[{\"key1\":\"value1\"}]".equals(output));
+
+ jsonArray = new JSONArray();
+ List> singleList = Collections.singletonList("entry1");
+ jsonArray.put((Object) singleList);
+ } finally {
+ writer.close();
+ }
+ writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[[\"entry1\"]]".equals(output));
+
+ jsonArray = new JSONArray();
+ int[] intArray = new int[] { 1, 2, 3 };
+ jsonArray.put(intArray);
+ } finally {
+ writer.close();
+ }
+ writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[[1, 2, 3]]".equals(output));
+
+ jsonArray = new JSONArray();
+ jsonArray.put(24);
+ } finally {
+ writer.close();
+ }
+ writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[24]".equals(output));
+
+ jsonArray = new JSONArray();
+ jsonArray.put("string value");
+ } finally {
+ writer.close();
+ }
+ writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[\"string value\"]".equals(output));
+
+ jsonArray = new JSONArray();
+ jsonArray.put(true);
+ } finally {
+ writer.close();
+ }
+ writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[true]".equals(output));
+ } finally {
+ writer.close();
+ }
+
+ }
+
+ /**
+ * This tests the JSONObject.valueToString() method. These should be
+ * identical to the values above, except for the enclosing [ and ].
+ */
+ @SuppressWarnings("boxing")
+ @Test
+ public void valuesToString() throws Exception {
+
+ String output = JSONObject.valueToString(null);
+ assertTrue("String values should be equal", "null".equals(output));
+
+ output = JSONObject.valueToString(JSONObject.NULL);
+ assertTrue("String values should be equal", "null".equals(output));
+
+ output = JSONObject.valueToString(new JSONObject());
+ assertTrue("String values should be equal", "{}".equals(output));
+
+ output = JSONObject.valueToString(new JSONArray());
+ assertTrue("String values should be equal", "[]".equals(output));
+
+ Map, ?> singleMap = Collections.singletonMap("key1", "value1");
+ output = JSONObject.valueToString(singleMap);
+ assertTrue("String values should be equal", "{\"key1\":\"value1\"}".equals(output));
+
+ List> singleList = Collections.singletonList("entry1");
+ output = JSONObject.valueToString(singleList);
+ assertTrue("String values should be equal", "[\"entry1\"]".equals(output));
+
+ int[] intArray = new int[] { 1, 2, 3 };
+ output = JSONObject.valueToString(intArray);
+ assertTrue("String values should be equal", "[1, 2, 3]".equals(output));
+
+ output = JSONObject.valueToString(24);
+ assertTrue("String values should be equal", "24".equals(output));
+
+ output = JSONObject.valueToString("string value");
+ assertTrue("String values should be equal", "\"string value\"".equals(output));
+
+ output = JSONObject.valueToString(true);
+ assertTrue("String values should be equal", "true".equals(output));
+
+ }
+
+ /**
+ * Test what happens when toJSONString() returns a well-formed JSON value.
+ * This is the usual case.
+ */
+ @Test
+ public void testJSONStringValue() throws Exception {
+ JSONStringValue jsonString = new JSONStringValue();
+ JSONArray jsonArray = new JSONArray();
+
+ jsonArray.put(jsonString);
+
+ StringWriter writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[\"the JSON string value\"]".equals(output));
+
+ output = JSONObject.valueToString(jsonString);
+ assertTrue("String values should be equal", "\"the JSON string value\"".equals(output));
+ } finally {
+ writer.close();
+ }
+ }
+
+ /**
+ * Test what happens when toJSONString() returns null. In one case,
+ * use the object's toString() method. In the other, throw a JSONException.
+ */
+ @Test
+ public void testJSONNullStringValue() throws Exception {
+ JSONNullStringValue jsonString = new JSONNullStringValue();
+ JSONArray jsonArray = new JSONArray();
+
+ jsonArray.put(jsonString);
+
+ StringWriter writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[\"the toString value\"]".equals(output));
+
+ // The only different between writeValue() and valueToString():
+ // in this case, valueToString throws a JSONException
+ try {
+ output = JSONObject.valueToString(jsonString);
+ fail("Expected an exception, got a String value");
+ } catch (Exception e) {
+ assertTrue("Expected JSONException", e instanceof JSONException);
+ assertTrue("Exception message does not match", "Bad value from toJSONString: null".equals(e.getMessage()));
+ }
+ } finally {
+ writer.close();
+ }
+ }
+
+ /**
+ * Test what happens when toJSONString() returns an exception. In both
+ * cases, a JSONException is thrown, with the cause and message set from
+ * the original exception.
+ */
+ @Test
+ public void testJSONStringExceptionValue() throws IOException {
+ JSONStringExceptionValue jsonString = new JSONStringExceptionValue();
+ JSONArray jsonArray = new JSONArray();
+
+ jsonArray.put(jsonString);
+
+ StringWriter writer = new StringWriter();
+ try {
+ jsonArray.write(writer).toString();
+ fail("Expected an exception, got a String value");
+ } catch (JSONException e) {
+ assertEquals("Unable to write JSONArray value at index: 0", e.getMessage());
+ } catch (Exception e) {
+ fail("Expected JSONException");
+ } finally {
+ writer.close();
+ }
+
+ try {
+ JSONObject.valueToString(jsonString);
+ fail("Expected an exception, got a String value");
+ } catch (JSONException e) {
+ assertTrue("Exception message does not match", "the exception value".equals(e.getMessage()));
+ } catch (Exception e) {
+ fail("Expected JSONException");
+ }
+ }
+
+ /**
+ * Test what happens when a Java object's toString() returns a String value.
+ * This is the usual case.
+ */
+ @Test
+ public void testStringValue() throws Exception {
+ StringValue nonJsonString = new StringValue();
+ JSONArray jsonArray = new JSONArray();
+
+ jsonArray.put(nonJsonString);
+
+ StringWriter writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[\"the toString value for StringValue\"]".equals(output));
+
+ output = JSONObject.valueToString(nonJsonString);
+ assertTrue("String values should be equal", "\"the toString value for StringValue\"".equals(output));
+ } finally {
+ writer.close();
+ }
+ }
+
+ /**
+ * Test what happens when a Java object's toString() returns null.
+ * Defaults to empty string.
+ */
+ @Test
+ public void testNullStringValue() throws Exception {
+ NullStringValue nonJsonString = new NullStringValue();
+ JSONArray jsonArray = new JSONArray();
+
+ jsonArray.put(nonJsonString);
+
+ StringWriter writer = new StringWriter();
+ try {
+ String output = jsonArray.write(writer).toString();
+ assertTrue("String values should be equal", "[\"\"]".equals(output));
+
+ output = JSONObject.valueToString(nonJsonString);
+ assertTrue("String values should be equal", "\"\"".equals(output));
+ } finally {
+ writer.close();
+ }
+ }
+
+ /**
+ * A JSONString that returns a valid JSON string value.
+ */
+ private static final class JSONStringValue implements JSONString {
+
+ @Override
+ public String toJSONString() {
+ return "\"the JSON string value\"";
+ }
+
+ @Override
+ public String toString() {
+ return "the toString value for JSONStringValue";
+ }
+ }
+
+ /**
+ * A JSONString that returns null when calling toJSONString().
+ */
+ private static final class JSONNullStringValue implements JSONString {
+
+ @Override
+ public String toJSONString() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "the toString value";
+ }
+ }
+
+ /**
+ * A JSONString that throw an exception when calling toJSONString().
+ */
+ private static final class JSONStringExceptionValue implements JSONString {
+
+ @Override
+ public String toJSONString() {
+ throw new IllegalStateException("the exception value");
+ }
+
+ @Override
+ public String toString() {
+ return "the toString value for JSONStringExceptionValue";
+ }
+ }
+
+ public static final class StringValue {
+
+ @Override
+ public String toString() {
+ return "the toString value for StringValue";
+ }
+ }
+
+ public static final class NullStringValue {
+
+ @Override
+ public String toString() {
+ return null;
+ }
+ }
+}
diff --git a/test/org/json/stleary/JSONTokenerTest.java b/test/org/json/stleary/JSONTokenerTest.java
new file mode 100644
index 000000000..73a8e2bab
--- /dev/null
+++ b/test/org/json/stleary/JSONTokenerTest.java
@@ -0,0 +1,203 @@
+package org.json.stleary;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import org.json.JSONException;
+import org.json.JSONTokener;
+import org.junit.Test;
+
+/**
+ * Test specific to the {@link org.json.JSONTokener} class.
+ *
+ * @author John Aylward
+ *
+ */
+public class JSONTokenerTest {
+
+ /**
+ * verify that back() fails as expected.
+ *
+ * @throws IOException thrown if something unexpected happens.
+ */
+ @Test
+ public void verifyBackFailureZeroIndex() throws IOException {
+ try (Reader reader = new StringReader("some test string")) {
+ final JSONTokener tokener = new JSONTokener(reader);
+ try {
+ // this should fail since the index is 0;
+ tokener.back();
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Stepping back two steps is not supported", e.getMessage());
+ } catch (Exception e) {
+ fail("Unknown Exception type " + e.getClass().getCanonicalName() + " with message " + e.getMessage());
+ }
+
+ }
+ }
+
+ /**
+ * verify that back() fails as expected.
+ *
+ * @throws IOException thrown if something unexpected happens.
+ */
+ @Test
+ public void verifyBackFailureDoubleBack() throws IOException {
+ try (Reader reader = new StringReader("some test string")) {
+ final JSONTokener tokener = new JSONTokener(reader);
+ tokener.next();
+ tokener.back();
+ try {
+ // this should fail since the index is 0;
+ tokener.back();
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Stepping back two steps is not supported", e.getMessage());
+ } catch (Exception e) {
+ fail("Unknown Exception type " + e.getClass().getCanonicalName() + " with message " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Tests the failure of the skipTo method with a buffered reader. Preferably
+ * we'd like this not to fail but at this time we don't have a good recovery.
+ *
+ * @throws IOException thrown if something unexpected happens.
+ */
+ @Test
+ public void testSkipToFailureWithBufferedReader() throws IOException {
+ final byte[] superLongBuffer = new byte[1000001];
+ // fill our buffer
+ for (int i = 0; i < superLongBuffer.length; i++) {
+ superLongBuffer[i] = 'A';
+ }
+ try (Reader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(superLongBuffer)))) {
+ final JSONTokener tokener = new JSONTokener(reader);
+ try {
+ // this should fail since the internal markAhead buffer is only 1,000,000
+ // but 'B' doesn't exist in our buffer that is 1,000,001 in size
+ tokener.skipTo('B');
+ fail("Expected exception");
+ } catch (JSONException e) {
+ assertEquals("Mark invalid", e.getMessage());
+ } catch (Exception e) {
+ fail("Unknown Exception type " + e.getClass().getCanonicalName() + " with message " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Tests the success of the skipTo method with a String reader.
+ *
+ * @throws IOException thrown if something unexpected happens.
+ */
+ @Test
+ public void testSkipToSuccessWithStringReader() throws IOException {
+ final StringBuilder superLongBuffer = new StringBuilder(1000001);
+ // fill our buffer
+ for (int i = 0; i < superLongBuffer.length(); i++) {
+ superLongBuffer.append('A');
+ }
+ try (Reader reader = new StringReader(superLongBuffer.toString())) {
+ final JSONTokener tokener = new JSONTokener(reader);
+ try {
+ // this should not fail since the internal markAhead is ignored for StringReaders
+ tokener.skipTo('B');
+ } catch (Exception e) {
+ fail("Unknown Exception type " + e.getClass().getCanonicalName() + " with message " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Verify that next and back are working properly and tracking the correct positions
+ * with different new line combinations.
+ */
+ @Test
+ public void testNextBackComboWithNewLines() {
+ final String testString = "this is\nA test\r\nWith some different\rNew Lines";
+ // ^ ^ ^ ^
+ // index positions 0 8 16 36
+ final JSONTokener tokener = new JSONTokener(testString);
+ assertEquals(" at 0 [character 1 line 1]", tokener.toString());
+ assertEquals('t', tokener.next());
+ assertEquals(" at 1 [character 2 line 1]", tokener.toString());
+ tokener.skipTo('\n');
+ assertEquals("skipTo() improperly modifying indexes", " at 7 [character 8 line 1]", tokener.toString());
+ assertEquals('\n', tokener.next());
+ assertEquals(" at 8 [character 0 line 2]", tokener.toString());
+ assertEquals('A', tokener.next());
+ assertEquals(" at 9 [character 1 line 2]", tokener.toString());
+ tokener.back();
+ assertEquals(" at 8 [character 0 line 2]", tokener.toString());
+ tokener.skipTo('\r');
+ assertEquals("skipTo() improperly modifying indexes", " at 14 [character 6 line 2]", tokener.toString());
+ // verify \r\n combo doesn't increment the line twice
+ assertEquals('\r', tokener.next());
+ assertEquals(" at 15 [character 0 line 3]", tokener.toString());
+ assertEquals('\n', tokener.next());
+ assertEquals(" at 16 [character 0 line 3]", tokener.toString());
+ // verify stepping back after reading the \n of an \r\n combo doesn't increment the line incorrectly
+ tokener.back();
+ assertEquals(" at 15 [character 6 line 2]", tokener.toString());
+ assertEquals('\n', tokener.next());
+ assertEquals(" at 16 [character 0 line 3]", tokener.toString());
+ assertEquals('W', tokener.next());
+ assertEquals(" at 17 [character 1 line 3]", tokener.toString());
+ assertEquals('i', tokener.next());
+ assertEquals(" at 18 [character 2 line 3]", tokener.toString());
+ tokener.skipTo('\r');
+ assertEquals("skipTo() improperly modifying indexes", " at 35 [character 19 line 3]", tokener.toString());
+ assertEquals('\r', tokener.next());
+ assertEquals(" at 36 [character 0 line 4]", tokener.toString());
+ tokener.back();
+ assertEquals(" at 35 [character 19 line 3]", tokener.toString());
+ assertEquals('\r', tokener.next());
+ assertEquals(" at 36 [character 0 line 4]", tokener.toString());
+ assertEquals('N', tokener.next());
+ assertEquals(" at 37 [character 1 line 4]", tokener.toString());
+
+ // verify we get the same data just walking though, no calls to back
+ final JSONTokener t2 = new JSONTokener(testString);
+ for (int i = 0; i < 7; i++) {
+ assertTrue(t2.toString().startsWith(" at " + i + " "));
+ assertEquals(testString.charAt(i), t2.next());
+ }
+ assertEquals(" at 7 [character 8 line 1]", t2.toString());
+ assertEquals(testString.charAt(7), t2.next());
+ assertEquals(" at 8 [character 0 line 2]", t2.toString());
+ for (int i = 8; i < 14; i++) {
+ assertTrue(t2.toString().startsWith(" at " + i + " "));
+ assertEquals(testString.charAt(i), t2.next());
+ }
+ assertEquals(" at 14 [character 6 line 2]", t2.toString());
+ assertEquals('\r', t2.next());
+ assertEquals(" at 15 [character 0 line 3]", t2.toString());
+ assertEquals('\n', t2.next());
+ assertEquals(" at 16 [character 0 line 3]", t2.toString());
+ assertEquals('W', t2.next());
+ assertEquals(" at 17 [character 1 line 3]", t2.toString());
+ for (int i = 17; i < 37; i++) {
+ assertTrue(t2.toString().startsWith(" at " + i + " "));
+ assertEquals(testString.charAt(i), t2.next());
+ }
+ assertEquals(" at 37 [character 1 line 4]", t2.toString());
+ for (int i = 37; i < testString.length(); i++) {
+ assertTrue(t2.toString().startsWith(" at " + i + " "));
+ assertEquals(testString.charAt(i), t2.next());
+ }
+ assertEquals(" at " + testString.length() + " [character 9 line 4]", t2.toString());
+ // end of the input
+ assertEquals(0, t2.next());
+ assertFalse(t2.more());
+ }
+}
diff --git a/test/org/json/stleary/PropertyTest.java b/test/org/json/stleary/PropertyTest.java
new file mode 100644
index 000000000..a0d19e2de
--- /dev/null
+++ b/test/org/json/stleary/PropertyTest.java
@@ -0,0 +1,95 @@
+package org.json.stleary;
+
+import static org.junit.Assert.*;
+import java.util.*;
+import org.json.*;
+import org.junit.Test;
+
+/**
+ * Tests for JSON-Java Property
+ */
+public class PropertyTest {
+
+ /**
+ * JSONObject from null properties object should
+ * result in an empty JSONObject.
+ */
+ @Test
+ public void shouldHandleNullProperties() {
+ Properties properties = null;
+ JSONObject jsonObject = Property.toJSONObject(properties);
+ assertTrue("jsonObject should be empty", jsonObject.isEmpty());
+ }
+
+ /**
+ * JSONObject from empty properties object should
+ * result in an empty JSONObject.
+ */
+ @Test
+ public void shouldHandleEmptyProperties() {
+ Properties properties = new Properties();
+ JSONObject jsonObject = Property.toJSONObject(properties);
+ assertTrue("jsonObject should be empty", jsonObject.isEmpty());
+ }
+
+ /**
+ * JSONObject from simple properties object.
+ */
+ @Test
+ public void shouldHandleProperties() {
+ Properties properties = new Properties();
+
+ properties.put("Illinois", "Springfield");
+ properties.put("Missouri", "Jefferson City");
+ properties.put("Washington", "Olympia");
+ properties.put("California", "Sacramento");
+ properties.put("Indiana", "Indianapolis");
+
+ JSONObject jsonObject = Property.toJSONObject(properties);
+
+ assertTrue("jsonObject should contain 5 items", jsonObject.length() == 5);
+ assertTrue("jsonObject should contain Illinois property",
+ "Springfield".equals(jsonObject.get("Illinois")));
+ assertTrue("jsonObject should contain Missouri property",
+ "Jefferson City".equals(jsonObject.get("Missouri")));
+ assertTrue("jsonObject should contain Washington property",
+ "Olympia".equals(jsonObject.get("Washington")));
+ assertTrue("jsonObject should contain California property",
+ "Sacramento".equals(jsonObject.get("California")));
+ assertTrue("jsonObject should contain Indiana property",
+ "Indianapolis".equals(jsonObject.get("Indiana")));
+ }
+
+ /**
+ * Null JSONObject toProperties() should result in an empty
+ * Properties object.
+ */
+ @Test
+ public void shouldHandleNullJSONProperty() {
+ JSONObject jsonObject = null;
+ Properties properties = Property.toProperties(jsonObject);
+ assertTrue("properties should be empty",
+ properties.size() == 0);
+ }
+
+ /**
+ * Properties should convert to JSONObject, and back to
+ * Properties without changing.
+ */
+ @Test
+ public void shouldHandleJSONProperty() {
+ Properties properties = new Properties();
+
+ properties.put("Illinois", "Springfield");
+ properties.put("Missouri", "Jefferson City");
+ properties.put("Washington", "Olympia");
+ properties.put("California", "Sacramento");
+ properties.put("Indiana", "Indianapolis");
+
+ JSONObject jsonObject = Property.toJSONObject(properties);
+ Properties jsonProperties = Property.toProperties(jsonObject);
+
+ assertTrue("property objects should match",
+ properties.equals(jsonProperties));
+ }
+}
diff --git a/test/org/json/stleary/Util.java b/test/org/json/stleary/Util.java
new file mode 100644
index 000000000..6b1b8e8a7
--- /dev/null
+++ b/test/org/json/stleary/Util.java
@@ -0,0 +1,99 @@
+package org.json.stleary;
+
+import static org.junit.Assert.*;
+import java.util.*;
+import org.json.*;
+
+/**
+ * These are helpful utility methods that perform basic comparisons
+ * between various objects. In most cases, the comparisons are not
+ * order-dependent, or else the order is known.
+ */
+public class Util {
+
+ /**
+ * Compares two JSONArrays for equality.
+ * The arrays need not be in the same order.
+ *
+ * @param jsonArray created by the code to be tested
+ * @param expectedJsonArray created specifically for comparing
+ */
+ public static void compareActualVsExpectedJsonArrays(JSONArray jsonArray,
+ JSONArray expectedJsonArray) {
+ assertTrue("jsonArray lengths should be equal",
+ jsonArray.length() == expectedJsonArray.length());
+ for (int i = 0; i < jsonArray.length(); ++i) {
+ Object value = jsonArray.get(i);
+ Object expectedValue = expectedJsonArray.get(i);
+ compareActualVsExpectedObjects(value, expectedValue);
+ }
+ }
+
+ /**
+ * Compares two JSONObjects for equality. The objects need not be
+ * in the same order
+ *
+ * @param jsonObject created by the code to be tested
+ * @param expectedJsonObject created specifically for comparing
+ */
+ public static void compareActualVsExpectedJsonObjects(
+ JSONObject jsonObject, JSONObject expectedJsonObject) {
+ assertTrue("jsonObjects should have the same length",
+ jsonObject.length() == expectedJsonObject.length());
+ Iterator keys = jsonObject.keys();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ Object value = jsonObject.get(key);
+ Object expectedValue = expectedJsonObject.get(key);
+ compareActualVsExpectedObjects(value, expectedValue);
+ }
+ }
+
+ /**
+ * Compare two objects for equality. Might be JSONArray, JSONObject,
+ * or something else.
+ *
+ * @param value created by the code to be tested
+ * @param expectedValue created specifically for comparing
+ * @param key key to the jsonObject entry to be compared
+ */
+ private static void compareActualVsExpectedObjects(Object value,
+ Object expectedValue) {
+ if (value instanceof JSONObject && expectedValue instanceof JSONObject) {
+ // Compare JSONObjects
+ JSONObject jsonObject = (JSONObject) value;
+ JSONObject expectedJsonObject = (JSONObject) expectedValue;
+ compareActualVsExpectedJsonObjects(
+ jsonObject, expectedJsonObject);
+ } else if (value instanceof JSONArray && expectedValue instanceof JSONArray) {
+ // Compare JSONArrays
+ JSONArray jsonArray = (JSONArray) value;
+ JSONArray expectedJsonArray = (JSONArray) expectedValue;
+ compareActualVsExpectedJsonArrays(
+ jsonArray, expectedJsonArray);
+ } else {
+ /**
+ * Compare all other types using toString(). First, the types must
+ * also be equal, unless both are Number type. Certain helper
+ * classes (e.g. XML) may create Long instead of Integer for small
+ * int values.
+ */
+ if (!(value instanceof Number && expectedValue instanceof Number)) {
+ // Non-Number and non-matching types
+ assertTrue("object types should be equal for actual: "
+ + value.toString() + " ("
+ + value.getClass().toString() + ") expected: "
+ + expectedValue.toString() + " ("
+ + expectedValue.getClass().toString() + ")",
+ value.getClass().toString().equals(
+ expectedValue.getClass().toString()));
+ }
+ /**
+ * Same types or both Numbers, compare by toString()
+ */
+ assertTrue("string values should be equal for actual: "
+ + value.toString() + " expected: " + expectedValue.toString(),
+ value.toString().equals(expectedValue.toString()));
+ }
+ }
+}
diff --git a/test/org/json/stleary/data/MyLocaleBean.java b/test/org/json/stleary/data/MyLocaleBean.java
new file mode 100644
index 000000000..b2a5a0b78
--- /dev/null
+++ b/test/org/json/stleary/data/MyLocaleBean.java
@@ -0,0 +1,14 @@
+package org.json.stleary.data;
+
+public class MyLocaleBean {
+ private final String id = "beanId";
+ private final String i = "beanI";
+
+ public String getId() {
+ return id;
+ }
+
+ public String getI() {
+ return i;
+ }
+}
diff --git a/test/org/json/stleary/jsonpointer-testdoc.json b/test/org/json/stleary/jsonpointer-testdoc.json
new file mode 100644
index 000000000..657ccdd34
--- /dev/null
+++ b/test/org/json/stleary/jsonpointer-testdoc.json
@@ -0,0 +1,28 @@
+{
+ "foo":
+ [
+ "bar",
+ "baz"
+ ],
+ "": 0,
+ "a/b": 1,
+ "c%d": 2,
+ "e^f": 3,
+ "g|h": 4,
+ "i\\j": 5,
+ "k\"l": 6,
+ " ": 7,
+ "m~n": 8,
+ "obj" : {
+ "key" : "value",
+ "other~key" : {
+ "another/key" : [
+ "val"
+ ]
+ },
+ "" : {
+ "" : "empty key of an object with an empty key",
+ "subKey" : "Some other value"
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/org/json/stleary/package.html b/test/org/json/stleary/package.html
new file mode 100644
index 000000000..7436633b4
--- /dev/null
+++ b/test/org/json/stleary/package.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+ Unit tests copied from the https://github.com/stleary/JSON-Java-unit-test/ master.
+
+
diff --git a/test/org/json/testJSON.json b/test/org/json/testJSON.json
new file mode 100644
index 000000000..a1e2db764
--- /dev/null
+++ b/test/org/json/testJSON.json
@@ -0,0 +1 @@
+{"birthday":"1940-02-10","favorite_foods":["cookie","fish","chips"],"passport":{"nationality":"American","id":100001},"car":null,"name":"Tom","married":false,"age":76}
\ No newline at end of file
diff --git a/test/org/json/testJSON2.json b/test/org/json/testJSON2.json
new file mode 100644
index 000000000..a1e2db764
--- /dev/null
+++ b/test/org/json/testJSON2.json
@@ -0,0 +1 @@
+{"birthday":"1940-02-10","favorite_foods":["cookie","fish","chips"],"passport":{"nationality":"American","id":100001},"car":null,"name":"Tom","married":false,"age":76}
\ No newline at end of file
diff --git a/test/org/json/testJSON3.json b/test/org/json/testJSON3.json
new file mode 100644
index 000000000..8b20424c5
--- /dev/null
+++ b/test/org/json/testJSON3.json
@@ -0,0 +1 @@
+{"birthday":"1940-02-10","favorite_foods":["cookie","fish","chips2"],"passport":{"nationality":"American","id":100001},"car":null,"name":"Tom","married":false,"age":76}
\ No newline at end of file
diff --git a/test/org/json/testJSON4.json b/test/org/json/testJSON4.json
new file mode 100644
index 000000000..466109036
--- /dev/null
+++ b/test/org/json/testJSON4.json
@@ -0,0 +1 @@
+{"birthday":"1940-02-10","favorite_foods":["cookie","fish","chips"],"passport":{"nationality":"American","id":100001},"car":null,"name":"Tom","married":false,"age":78}
\ No newline at end of file
diff --git a/test/org/json/testJSON5.json b/test/org/json/testJSON5.json
new file mode 100644
index 000000000..cc843f573
--- /dev/null
+++ b/test/org/json/testJSON5.json
@@ -0,0 +1 @@
+{"birthday":"1940-02-10","favorite_foods":["cookie","fish","chips"],"passport":{"nationality":"American","id":100001},"car":null,"name":"Tom","married":false,"age":76.0}
\ No newline at end of file
diff --git a/test/org/json/testJSON6.json b/test/org/json/testJSON6.json
new file mode 100644
index 000000000..a15f05682
--- /dev/null
+++ b/test/org/json/testJSON6.json
@@ -0,0 +1 @@
+{"birthday":"1940-02-10","favorite_foods":null,"passport":{"nationality":"American","id":100001},"car":null,"name":"Tom","married":false,"age":76.0}
\ No newline at end of file
diff --git a/test/org/json/testJSON7.json b/test/org/json/testJSON7.json
new file mode 100644
index 000000000..bfa8569b8
--- /dev/null
+++ b/test/org/json/testJSON7.json
@@ -0,0 +1 @@
+{"birthday":"1940-02-10","favorite_foods":["cookie","fish","chips"],"passport":{"nationality":"American","id":100001},"car":null,"name":null,"married":false,"age":76}
\ No newline at end of file
diff --git a/test/org/json/testJSONArray.json b/test/org/json/testJSONArray.json
new file mode 100644
index 000000000..49987c2f9
--- /dev/null
+++ b/test/org/json/testJSONArray.json
@@ -0,0 +1 @@
+["cookie","fish","chips"]
\ No newline at end of file