package org.json.junit;
import static org.junit.Assert.*;
import org.json.*;
import org.junit.Test;
/**
* Tests for JSON-Java XML.java
* Note: noSpace() will be tested by JSONMLTest
*/
public class XMLTest {
@Test(expected=NullPointerException.class)
public void shouldHandleNullXML() {
String xmlStr = null;
JSONObject jsonObject = XML.toJSONObject(xmlStr);
assertTrue("jsonObject should be empty", jsonObject.length() == 0);
}
@Test
public void shouldHandleEmptyXML() {
String xmlStr = "";
JSONObject jsonObject = XML.toJSONObject(xmlStr);
assertTrue("jsonObject should be empty", jsonObject.length() == 0);
}
@Test
public void shouldHandleNonXML() {
String xmlStr = "{ \"this is\": \"not xml\"}";
JSONObject jsonObject = XML.toJSONObject(xmlStr);
assertTrue("xml string should be empty", jsonObject.length() == 0);
}
@Test(expected=JSONException.class)
public void shouldHandleInvalidSlashInTag() {
String xmlStr =
"\n"+
"\n"+
" \n"+
" \n"+
" abc street\n"+
" \n"+
"";
XML.toJSONObject(xmlStr);
}
@Test(expected=JSONException.class)
public void shouldHandleInvalidBangInTag() {
String xmlStr =
"\n"+
"\n"+
" \n"+
" \n"+
" \n"+
" \n"+
"";
XML.toJSONObject(xmlStr);
}
@Test(expected=JSONException.class)
public void shouldHandleInvalidBangNoCloseInTag() {
String xmlStr =
"\n"+
"\n"+
" \n"+
" \n"+
" \n"+
"";
XML.toJSONObject(xmlStr);
}
@Test(expected=JSONException.class)
public void shouldHandleNoCloseStartTag() {
String xmlStr =
"\n"+
"\n"+
" \n"+
" \n"+
" \n"+
"";
XML.toJSONObject(xmlStr);
}
@Test(expected=JSONException.class)
public void shouldHandleInvalidCDATABangInTag() {
String xmlStr =
"\n"+
"\n"+
" \n"+
" Joe Tester\n"+
" \n"+
" \n"+
"";
XML.toJSONObject(xmlStr);
}
@Test(expected=NullPointerException.class)
public void shouldHandleNullJSONXML() {
JSONObject jsonObject= null;
XML.toString(jsonObject);
}
@Test
public void shouldHandleEmptyJSONXML() {
JSONObject jsonObject= new JSONObject();
String xmlStr = XML.toString(jsonObject);
assertTrue("xml string should be empty", xmlStr.length() == 0);
}
@Test
public void shouldHandleNoStartTag() {
String xmlStr =
"\n"+
"\n"+
" \n"+
" \n"+
" >\n"+
" \n"+
"";
String expectedStr =
"{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\",\""+
"content\":\">\"},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+
"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}";
JSONObject jsonObject = XML.toJSONObject(xmlStr);
JSONObject expectedJsonObject = new JSONObject(expectedStr);
Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
}
@Test
public void shouldHandleSimpleXML() {
String xmlStr =
"\n"+
"\n"+
" \n"+
" Joe Tester\n"+
" [CDATA[Baker street 5]\n"+
" \n"+
" true\n"+
" false\n"+
" null\n"+
" 42\n"+
" -23\n"+
" -23.45\n"+
" -23x.45\n"+
" 1, 2, 3, 4.1, 5.2\n"+
" \n"+
"";
String expectedStr =
"{\"addresses\":{\"address\":{\"street\":\"[CDATA[Baker street 5]\","+
"\"name\":\"Joe Tester\",\"NothingHere\":\"\",TrueValue:true,\n"+
"\"FalseValue\":false,\"NullValue\":null,\"PositiveValue\":42,\n"+
"\"NegativeValue\":-23,\"DoubleValue\":-23.45,\"Nan\":-23x.45,\n"+
"\"ArrayOfNum\":\"1, 2, 3, 4.1, 5.2\"\n"+
"},\"xsi:noNamespaceSchemaLocation\":"+
"\"test.xsd\",\"xmlns:xsi\":\"http://www.w3.org/2001/"+
"XMLSchema-instance\"}}";
JSONObject expectedJsonObject = new JSONObject(expectedStr);
JSONObject jsonObject = XML.toJSONObject(xmlStr);
Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
}
@Test
public void shouldHandleCommentsInXML() {
String xmlStr =
"\n"+
"\n"+
"\n"+
" \n"+
" comment ]]>\n"+
" Joe Tester\n"+
" \n"+
" Baker street 5\n"+
" \n"+
"";
JSONObject jsonObject = XML.toJSONObject(xmlStr);
String expectedStr = "{\"addresses\":{\"address\":{\"street\":\"Baker "+
"street 5\",\"name\":\"Joe Tester\",\"content\":\" this is -- "+
" comment \"}}}";
JSONObject expectedJsonObject = new JSONObject(expectedStr);
Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
}
@Test
public void shouldHandleToString() {
String xmlStr =
"\n"+
"\n"+
" \n"+
" [CDATA[Joe & T > e < s " t ' er]]\n"+
" Baker street 5\n"+
" 1, 2, 3, 4.1, 5.2\n"+
" \n"+
"";
String expectedStr =
"{\"addresses\":{\"address\":{\"street\":\"Baker street 5\","+
"\"name\":\"[CDATA[Joe & T > e < s \\\" t \\\' er]]\","+
"\"ArrayOfNum\":\"1, 2, 3, 4.1, 5.2\"\n"+
"},\"xsi:noNamespaceSchemaLocation\":"+
"\"test.xsd\",\"xmlns:xsi\":\"http://www.w3.org/2001/"+
"XMLSchema-instance\"}}";
JSONObject jsonObject = XML.toJSONObject(xmlStr);
String xmlToStr = XML.toString(jsonObject);
JSONObject finalJsonObject = XML.toJSONObject(xmlToStr);
JSONObject expectedJsonObject = new JSONObject(expectedStr);
Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject);
}
@Test
public void shouldHandleContentNoArraytoString() {
String expectedStr =
"{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\",\""+
"content\":\">\"},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+
"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}";
JSONObject expectedJsonObject = new JSONObject(expectedStr);
String finalStr = XML.toString(expectedJsonObject);
String expectedFinalStr = ">"+
"test.xsdhttp://www.w3.org/2001/XMLSche"+
"ma-instance";
assertTrue("Should handle expectedFinal: ["+expectedStr+"] final: ["+
finalStr+"]", expectedFinalStr.equals(finalStr));
}
@Test
public void shouldHandleContentArraytoString() {
String expectedStr =
"{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\",\""+
"content\":[1, 2, 3]},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+
"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}";
JSONObject expectedJsonObject = new JSONObject(expectedStr);
String finalStr = XML.toString(expectedJsonObject);
String expectedFinalStr = ""+
"1\n2\n3"+
"test.xsdhttp://www.w3.org/2001/XMLSche"+
"ma-instance";
assertTrue("Should handle expectedFinal: ["+expectedStr+"] final: ["+
finalStr+"]", expectedFinalStr.equals(finalStr));
}
@Test
public void shouldHandleArraytoString() {
String expectedStr =
"{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\","+
"\"something\":[1, 2, 3]},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+
"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}";
JSONObject expectedJsonObject = new JSONObject(expectedStr);
String finalStr = XML.toString(expectedJsonObject);
String expectedFinalStr = ""+
"123"+
"test.xsdhttp://www.w3.org/2001/XMLSche"+
"ma-instance";
assertTrue("Should handle expectedFinal: ["+expectedStr+"] final: ["+
finalStr+"]", expectedFinalStr.equals(finalStr));
}
@Test
public void shouldHandleNestedArraytoString() {
String xmlStr =
"{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\","+
"\"outer\":[[1], [2], [3]]},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+
"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}";
JSONObject jsonObject = new JSONObject(xmlStr);
String finalStr = XML.toString(jsonObject);
JSONObject finalJsonObject = XML.toJSONObject(finalStr);
String expectedStr = ""+
"12"+
"3"+
"test.xsdhttp://www.w3.org/2001/XMLSche"+
"ma-instance";
JSONObject expectedJsonObject = XML.toJSONObject(expectedStr);
Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject);
}
/**
* Illegal node-names must be converted to legal XML-node-names.
* The given example shows 2 nodes which are valid for JSON, but not for XML.
* Therefore illegal arguments should be converted to e.g. an underscore (_).
*
*/
@Test
public void shouldHandleIllegalJSONNodeNames()
{
JSONObject inputJSON = new JSONObject();
inputJSON.append("123IllegalNode", "someValue1");
inputJSON.append("Illegal@node", "someValue2");
String result = XML.toString(inputJSON);
/**
* This is invalid XML. Names should not begin with digits or contain
* certain values, including '@'. One possible solution is to replace
* illegal chars with '_', in which case the expected output would be:
* <___IllegalNode>someValue1someValue2
*/
String expected = "<123IllegalNode>someValue1123IllegalNode>someValue2";
assertEquals(expected, result);
}
@Test
public void shouldHandleNullNodeValue()
{
JSONObject inputJSON = new JSONObject();
inputJSON.put("nullValue", JSONObject.NULL);
// This is a possible preferred result
// String expectedXML = "";
/**
* This is the current behavior. JSONObject.NULL is emitted as
* the string, "null".
*/
String actualXML = "null";
String resultXML = XML.toString(inputJSON);
assertEquals(actualXML, resultXML);
}
@Test
public void contentOperations() {
/**
* Make sure we understand exactly how the "content" keyword works
*/
/**
* When a standalone 0) then return]]>";
JSONObject jsonObject = XML.toJSONObject(xmlStr);
assertTrue("1. 3 items", 3 == jsonObject.length());
assertTrue("1. empty tag1", "".equals(jsonObject.get("tag1")));
assertTrue("1. empty tag2", "".equals(jsonObject.get("tag2")));
assertTrue("1. content found", "if (a < b && a > 0) then return".equals(jsonObject.get("content")));
// multiple consecutive standalone cdatas are accumulated into an array
xmlStr = " 0) then return]]>";
jsonObject = XML.toJSONObject(xmlStr);
assertTrue("2. 3 items", 3 == jsonObject.length());
assertTrue("2. empty tag1", "".equals(jsonObject.get("tag1")));
assertTrue("2. empty tag2", "".equals(jsonObject.get("tag2")));
assertTrue("2. content array found", jsonObject.get("content") instanceof JSONArray);
JSONArray jsonArray = jsonObject.getJSONArray("content");
assertTrue("2. array size", jsonArray.length() == 2);
assertTrue("2. content array entry 0", "if (a < b && a > 0) then return".equals(jsonArray.get(0)));
assertTrue("2. content array entry 1", "here is another cdata".equals(jsonArray.get(1)));
/**
* text content is accumulated in a "content" inside a local JSONObject.
* If there is only one instance, it is saved in the context (a different JSONObject
* from the calling code. and the content element is discarded.
*/
xmlStr = "value 1";
jsonObject = XML.toJSONObject(xmlStr);
assertTrue("3. 2 items", 1 == jsonObject.length());
assertTrue("3. value tag1", "value 1".equals(jsonObject.get("tag1")));
/**
* array-style text content (multiple tags with the same name) is
* accumulated in a local JSONObject with key="content" and value=JSONArray,
* saved in the context, and then the local JSONObject is discarded.
*/
xmlStr = "value 12true";
jsonObject = XML.toJSONObject(xmlStr);
assertTrue("4. 1 item", 1 == jsonObject.length());
assertTrue("4. content array found", jsonObject.get("tag1") instanceof JSONArray);
jsonArray = jsonObject.getJSONArray("tag1");
assertTrue("4. array size", jsonArray.length() == 3);
assertTrue("4. content array entry 0", "value 1".equals(jsonArray.get(0)));
assertTrue("4. content array entry 1", jsonArray.getInt(1) == 2);
assertTrue("4. content array entry 2", jsonArray.getBoolean(2) == true);
/**
* Complex content is accumulated in a "content" field. For example, an element
* may contain a mix of child elements and text. Each text segment is
* accumulated to content.
*/
xmlStr = "val1val2";
jsonObject = XML.toJSONObject(xmlStr);
assertTrue("5. 1 item", 1 == jsonObject.length());
assertTrue("5. jsonObject found", jsonObject.get("tag1") instanceof JSONObject);
jsonObject = jsonObject.getJSONObject("tag1");
assertTrue("5. 2 contained items", 2 == jsonObject.length());
assertTrue("5. contained tag", "".equals(jsonObject.get("tag2")));
assertTrue("5. contained content jsonArray found", jsonObject.get("content") instanceof JSONArray);
jsonArray = jsonObject.getJSONArray("content");
assertTrue("5. array size", jsonArray.length() == 2);
assertTrue("5. content array entry 0", "val1".equals(jsonArray.get(0)));
assertTrue("5. content array entry 1", "val2".equals(jsonArray.get(1)));
/**
* If there is only 1 complex text content, then it is accumulated in a
* "content" field as a string.
*/
xmlStr = "val1";
jsonObject = XML.toJSONObject(xmlStr);
assertTrue("6. 1 item", 1 == jsonObject.length());
assertTrue("6. jsonObject found", jsonObject.get("tag1") instanceof JSONObject);
jsonObject = jsonObject.getJSONObject("tag1");
assertTrue("6. contained content found", "val1".equals(jsonObject.get("content")));
assertTrue("6. contained tag2", "".equals(jsonObject.get("tag2")));
/**
* In this corner case, the content sibling happens to have key=content
* We end up with an array within an array, and no content element.
* This is probably a bug.
*/
xmlStr = "val1";
jsonObject = XML.toJSONObject(xmlStr);
assertTrue("7. 1 item", 1 == jsonObject.length());
assertTrue("7. jsonArray found", jsonObject.get("tag1") instanceof JSONArray);
jsonArray = jsonObject.getJSONArray("tag1");
assertTrue("array size 1", jsonArray.length() == 1);
assertTrue("7. contained array found", jsonArray.get(0) instanceof JSONArray);
jsonArray = jsonArray.getJSONArray(0);
assertTrue("7. inner array size 2", jsonArray.length() == 2);
assertTrue("7. inner array item 0", "val1".equals(jsonArray.get(0)));
assertTrue("7. inner array item 1", "".equals(jsonArray.get(1)));
/**
* Confirm behavior of original issue
*/
String jsonStr =
"{"+
"\"Profile\": {"+
"\"list\": {"+
"\"history\": {"+
"\"entries\": ["+
"{"+
"\"deviceId\": \"id\","+
"\"content\": {"+
"\"material\": ["+
"{"+
"\"stuff\": false"+
"}"+
"]"+
"}"+
"}"+
"]"+
"}"+
"}"+
"}"+
"}";
jsonObject = new JSONObject(jsonStr);
xmlStr = XML.toString(jsonObject);
/**
* This is the created XML. Looks like content was mistaken for
* complex (child node + text) XML.
*
*
*
*
* id
* {"material":[{"stuff":false}]}
*
*
*
*
*/
assertTrue("nothing to test here, see comment on created XML, above", true);
}
}