/* * RESTHeart - the Web API for MongoDB * Copyright (C) SoftInstigate Srl * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.restheart.utils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; import org.bson.BsonDocument; import org.bson.BsonDouble; import org.bson.BsonValue; import org.bson.types.ObjectId; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author Andrea Di Cesare {@literal <andrea@softinstigate.com>} */ public class JsonUtilsTest { private static final Logger LOG = LoggerFactory.getLogger(JsonUtilsTest.class); @Rule public TestRule watcher = new TestWatcher() { @Override protected void starting(Description description) { LOG.info("executing test {}", description.toString()); } }; public JsonUtilsTest() { } @BeforeClass public static void setUpClass() { } @AfterClass public static void tearDownClass() { } @Before public void setUp() { } @After public void tearDown() { } @Test public void testMinify() { String json = "{ '_id' : { '$in' : [1, 20.0, 'id']}}"; String minified = "{'_id':{'$in':[1,20.0,'id']}}"; Assert.assertEquals(minified, JsonUtils.minify(json)); } @Test public void testGetPropFromPath() throws Exception { String _json1 = "{a: {b:1, c: {d:{\"$oid\": \"550c6e62c2e62b5640673e93\"}, e:3}}, f: null}"; String _json2 = "{a: [{b:1}, {b:2,c:3}, {d:4, c:null}, true]}"; String _json3 = "{a: [{b:1}, {b:2}, {b:3}]}"; String _json4 = "{a: [[{b:1}], [{b:2}], [{b:3}]]}"; String _json5 = "{a: []}"; String _json6 = "{a1: [{f1:1, f2:2, a2:[{f1:1,f2:2}]}, {f1:1, f2:2}]}"; BsonDocument json1 = BsonDocument.parse(_json1); BsonDocument json2 = BsonDocument.parse(_json2); BsonDocument json3 = BsonDocument.parse(_json3); BsonDocument json4 = BsonDocument.parse(_json4); BsonDocument json5 = BsonDocument.parse(_json5); BsonDocument json6 = BsonDocument.parse(_json6); Assert.assertTrue(checkGetPropsFromPath(json6, "$.a1.[*].a2", "[{f1:1,f2:2}]", null)); Assert.assertTrue(checkGetPropsFromPath(json6, "$.a1.[*].a2.[*].f1", "1")); Assert.assertTrue(checkGetPropsFromPath(json5, "$.a", "[]")); Assert.assertTrue(checkGetPropsFromPath(json5, "$.a.[*]")); Assert.assertTrue(checkGetPropsFromPath(json5, "$.a.[*].*")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.notexists", (String[]) null)); Assert.assertTrue(checkGetPropsFromPath(json1, "$.f", "null")); Assert.assertTrue(checkGetPropsFromPath(json1, "$", _json1)); Assert.assertTrue(checkType(json1, "$", "object")); Assert.assertFalse(checkType(json1, "$", "number")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.a", "{b:1, c: {d:{\"$oid\": \"550c6e62c2e62b5640673e93\"}, e:3}}")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.f", "null")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.*", "{b:1, c: {d:{\"$oid\": \"550c6e62c2e62b5640673e93\"}, e:3}}", "null")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.a.b", "1")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.a.c", "{d:{\"$oid\": \"550c6e62c2e62b5640673e93\"}, e:3}")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.*.*", "1", "{d:{\"$oid\": \"550c6e62c2e62b5640673e93\"}, e:3}", null)); Assert.assertTrue(checkGetPropsFromPath(json1, "$.a", "{b:1, c: {d:{\"$oid\": \"550c6e62c2e62b5640673e93\"},e:3}}, f: null}")); Assert.assertTrue(checkType(json1, "$.a", "object")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.a.b", "1")); Assert.assertTrue(checkType(json1, "$.a.b", "number")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.a.c", "{d:{\"$oid\": \"550c6e62c2e62b5640673e93\"},e:3}")); Assert.assertTrue(checkType(json1, "$.a.c", "object")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.a.c.d", "{\"$oid\": \"550c6e62c2e62b5640673e93\"}")); Assert.assertTrue(checkType(json1, "$.a.c.d", "objectid")); Assert.assertTrue(checkGetPropsFromPath(json2, "$.a", "[{b:1}, {b:2,c:3}, {d:4, c: null}, true]")); Assert.assertTrue(checkType(json2, "$.a", "array")); Assert.assertTrue(checkGetPropsFromPath(json2, "$.a.[*]", "{b:1}", "{b:2,c:3}", "{d:4, c: null}", "true")); Assert.assertFalse(checkType(json2, "$.a.[*]", "object")); Assert.assertTrue(checkGetPropsFromPath(json2, "$.a.[*].c", null, "3", "null", null)); Assert.assertTrue(checkGetPropsFromPath(json2, "$.a.[*].c.*")); Assert.assertTrue(checkGetPropsFromPath(json3, "$.a", "[{b:1}, {b:2}, {b:3}]")); Assert.assertTrue(checkType(json3, "$.a", "array")); Assert.assertTrue(checkGetPropsFromPath(json3, "$.a.[*]", "{b:1}", "{b:2}", "{b:3}")); Assert.assertTrue(checkType(json3, "$.a.[*]", "object")); Assert.assertTrue(checkGetPropsFromPath(json3, "$.a.[*].b", "1", "2", "3")); Assert.assertTrue(checkType(json3, "$.a.[*].b", "number")); Assert.assertTrue(checkGetPropsFromPath(json4, "$", "{a: [[{b:1}], [{b:2}], [{b:3}]]}")); Assert.assertTrue(checkType(json4, "$", "object")); Assert.assertTrue(checkGetPropsFromPath(json4, "$.a", "[[{b:1}], [{b:2}], [{b:3}]]")); Assert.assertTrue(checkType(json4, "$.a", "array")); Assert.assertTrue(checkGetPropsFromPath(json4, "$.a.[*]", "[{b:1}]", "[{b:2}]", "[{b:3}]")); Assert.assertTrue(checkType(json4, "$.a.[*]", "array")); Assert.assertTrue(checkGetPropsFromPath(json4, "$.a.[*].[*].b", "1", "2", "3")); Assert.assertTrue(checkType(json4, "$.a.[*].[*].b", "number")); } @Test public void testJsonArray() throws Exception { String _json1 = "{a: []}}"; String _json2 = "{a: [{}]}}"; String _json3 = "{a: [{f: 1}]}}"; String _json4 = "{a: [{e: 1}, {e: 2}, {e: 3}]}}"; String _json5 = "{a: {'1': {e: 1}, '2': {e: 2}, '3': {e: 3}}}}"; BsonDocument json1 = BsonDocument.parse(_json1); BsonDocument json2 = BsonDocument.parse(_json2); BsonDocument json3 = BsonDocument.parse(_json3); BsonDocument json4 = BsonDocument.parse(_json4); BsonDocument json5 = BsonDocument.parse(_json5); Assert.assertTrue(checkGetPropsFromPath(json1, "$.a", "[]")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.a.[*]")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.a.[*].f")); Assert.assertTrue(checkGetPropsFromPath(json2, "$.a", "[{}]")); Assert.assertTrue(checkGetPropsFromPath(json2, "$.a.[*]", "{}")); Assert.assertTrue(checkGetPropsFromPath(json2, "$.a.[*].f", (String) null)); Assert.assertTrue(checkGetPropsFromPath(json3, "$.a", "[{f: 1}]")); Assert.assertTrue(checkGetPropsFromPath(json3, "$.a.[*]", "{f: 1}")); Assert.assertTrue(checkGetPropsFromPath(json3, "$.a.[*].f", "1")); Assert.assertTrue(checkGetPropsFromPath(json4, "$.a.[*].e", "1", "2", "3")); Assert.assertTrue(checkGetPropsFromPath(json4, "$.a.[*].e", "1", "2", "3")); Assert.assertTrue(checkGetPropsFromPath(json5, "$.a.*", "{e: 1}", "{e: 2}", "{e: 3}")); // justification of the following: even if "a! is an object, it has all numeric values // on mongodb you can use the dot notation on arrays and do the following on RESTHeart // PATCH /db/coll/doc {"a.1", {"e": 1000}} // the content turns internally to {"a": {"1": {"e":1000}}} Assert.assertTrue(checkGetPropsFromPath(json5, "$.a.[*]", "{e: 1}", "{e: 2}", "{e: 3}")); } @Test public void testJsonObject() throws Exception { String _json1 = "{o: {}}"; String _json2 = "{o: {o: {}}}"; String _json3 = "{o: {o: {f: 1}}}"; BsonDocument json1 = BsonDocument.parse(_json1); BsonDocument json2 = BsonDocument.parse(_json2); BsonDocument json3 = BsonDocument.parse(_json3); Assert.assertTrue(checkGetPropsFromPath(json1, "$.o", "{}")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.*", "{}")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.o.*")); Assert.assertTrue(checkGetPropsFromPath(json1, "$.o.*.f")); Assert.assertTrue(checkGetPropsFromPath(json2, "$.o", "{o: {}}")); Assert.assertTrue(checkGetPropsFromPath(json2, "$.*", "{o: {}}")); Assert.assertTrue(checkGetPropsFromPath(json2, "$.o.o", "{}")); Assert.assertTrue(checkGetPropsFromPath(json2, "$.o.*", "{}")); Assert.assertTrue(checkGetPropsFromPath(json2, "$.o.*.f", (String) null)); Assert.assertTrue(checkGetPropsFromPath(json3, "$.o", "{o: {f: 1}}")); Assert.assertTrue(checkGetPropsFromPath(json3, "$.*", "{o: {f: 1}}")); Assert.assertTrue(checkGetPropsFromPath(json3, "$.o.o", "{f: 1}")); Assert.assertTrue(checkGetPropsFromPath(json3, "$.o.*", "{f: 1}")); Assert.assertTrue(checkGetPropsFromPath(json3, "$.o.*.f", "1")); } @Test public void checkCountOnComplexJson() { String _json = "{\n" + " \"_id\": \"project-processes\",\n" + " \"descr\": \"Progetto - Processi\",\n" + " \"items\": {\n" + " \"manufactoring\": {\n" + " \"descr\": \"Lavorazioni e Costruzioni\",\n" + " \"items\": {\n" + " \"strobel\": {\n" + " \"descr\": \"Strobel\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"double_lasting\": {\n" + " \"descr\": \"Sacchetto o Double Lasting\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 2\n" + " }\n" + " }\n" + " },\n" + " \"mounted\": {\n" + " \"descr\": \"Montato\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"membrane_on_upper\": {\n" + " \"descr\": \"Membrana su Tomaia\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"bootie\": {\n" + " \"descr\": \"Bootie\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"tubolar\": {\n" + " \"descr\": \"Tubolare\",\n" + " \"type\": \"boolean\",\n" + " \"svalues\": [\n" + " 0,\n" + " 1.5\n" + " ]\n" + " },\n" + " \"others\": {\n" + " \"descr\": \"Altro\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"injection\": {\n" + " \"descr\": \"Iniezione\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"injection_casting\": {\n" + " \"descr\": \"Iniezione per colata\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"glue\": {\n" + " \"descr\": \"Incollata\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"blake\": {\n" + " \"descr\": \"Blake\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"california\": {\n" + " \"descr\": \"California\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"goodyear\": {\n" + " \"descr\": \"Goodyear\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"ideal\": {\n" + " \"descr\": \"Ideal\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"opanks\": {\n" + " \"descr\": \"Opanks\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"vulcanized\": {\n" + " \"descr\": \"Vulcanizzata\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.5\n" + " }\n" + " }\n" + " },\n" + " \"best_process\": {\n" + " \"descr\": \"Best process\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 3\n" + " }\n" + " }\n" + " }\n" + " }\n" + " },\n" + " \"treatments\": {\n" + " \"descr\": \"Trattamenti\",\n" + " \"items\": {\n" + " \"dye\": {\n" + " \"descr\": \"Tinta in capo/verniciatura\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1\n" + " }\n" + " }\n" + " },\n" + " \"stonewash\": {\n" + " \"descr\": \"Stone Wash\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 1.75\n" + " }\n" + " }\n" + " },\n" + " \"colours_faded\": {\n" + " \"descr\": \"Slavati\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 2.5\n" + " }\n" + " }\n" + " },\n" + " \"creams_waxes\": {\n" + " \"descr\": \"Cere e Creme\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 3.25\n" + " }\n" + " }\n" + " },\n" + " \"spray\": {\n" + " \"descr\": \"Spray\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 3.25\n" + " }\n" + " }\n" + " },\n" + " \"none\": {\n" + " \"descr\": \"Nessun Trattamento\",\n" + " \"type\": \"boolean\",\n" + " \"values\": {\n" + " \"no\": {\n" + " \"descr\": \"Si\",\n" + " \"svalue\": 0\n" + " },\n" + " \"yes\": {\n" + " \"descr\": \"No\",\n" + " \"svalue\": 4\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}"; BsonDocument json = BsonDocument.parse(_json); LOG.debug("$.*" + " -> " + JsonUtils.getPropsFromPath(json, "$.*")); LOG.debug("$._id" + " -> " + JsonUtils.getPropsFromPath(json, "$._id")); LOG.debug("$.descr" + " -> " + JsonUtils.getPropsFromPath(json, "$.descr")); LOG.debug("$.items" + " -> " + JsonUtils.getPropsFromPath(json, "$.items")); LOG.debug("$.items.*" + " -> " + JsonUtils.getPropsFromPath(json, "$.items.*")); LOG.debug("$.items.*.*" + " -> " + JsonUtils.getPropsFromPath(json, "$.items.*.*")); LOG.debug("$.items.*.descr" + " -> " + JsonUtils.getPropsFromPath(json, "$.items.*.descr")); LOG.debug("$.items.*.items" + " -> " + JsonUtils.getPropsFromPath(json, "$.items.*.items")); LOG.debug("$.items.*.items.*" + " -> " + JsonUtils.getPropsFromPath(json, "$.items.*.items.*")); LOG.debug("$.items.*.items.*.*" + " -> " + JsonUtils.getPropsFromPath(json, "$.items.*.items.*.*")); LOG.debug("$.items.*.items.*.descr" + " -> " + JsonUtils.getPropsFromPath(json, "$.items.*.items.*.descr")); LOG.debug("$.items.*.items.*.values" + " -> " + JsonUtils.getPropsFromPath(json, "$.items.*.items.*.values")); LOG.debug("$.items.*.items.*.values.*" + " -> " + JsonUtils.getPropsFromPath(json, "$.items.*.items.*.values.*")); LOG.debug("$.items.*.items.*.values.*.descr" + " -> " + JsonUtils.getPropsFromPath(json, "$.items.*.items.*.values.*.descr")); LOG.debug("$.items.*.items.*.values.*.svalue" + " -> " + JsonUtils.getPropsFromPath(json, "$.items.*.items.*.values.*.svalue")); String path = "$.items.*.*"; try { Assert.assertTrue(JsonUtils.countPropsFromPath(json, path) == 4); } catch (IllegalArgumentException ex) { Assert.fail(ex.toString()); } } @Test public void testParseToBsonObject() { String object = JsonUtils.minify("{\"a\" :1 }"); BsonValue bson = JsonUtils.parse(object); String actual = JsonUtils.toJson(bson); Assert.assertEquals(object, actual); } @Test public void testParseToBsonArray() { String array = "[\"a\", \"b\", 2 ]"; BsonValue bson = JsonUtils.parse(array); String actual = JsonUtils.toJson(bson); Assert.assertEquals(JsonUtils.minify(array), actual); } @Test public void testParseObjectId() { ObjectId id = new ObjectId(); BsonValue parsed = JsonUtils.parse( "{'$oid':'" .concat(id.toString()) .concat("'}")); Assert.assertTrue(parsed.isObjectId()); Assert.assertEquals(parsed.asObjectId().getValue(), id); } @Test public void testParseFloat() { BsonValue parsed = JsonUtils.parse("3.1415"); Assert.assertTrue(parsed.isNumber()); Assert.assertEquals(parsed.asDouble(), new BsonDouble(3.1415)); } @Test public void testParseToBsonArrayOfObjectets() { String arrayOfObjs = "[{\"a\" :1 },{\"b\" :2 }]"; BsonValue bson = JsonUtils.parse(arrayOfObjs); String actual = JsonUtils.toJson(bson); Assert.assertEquals(JsonUtils.minify(arrayOfObjs), actual); } private boolean eq(List<Optional<BsonValue>> left, List<Optional<BsonValue>> right) { if (left == null && right != null) { return false; } if (left != null && right == null) { return false; } if (left == null && right == null) { return true; } if (left.size() != right.size()) { return false; } boolean ret = true; for (int cont = 0; cont < left.size(); cont++) { Optional<BsonValue> lo = left.get(cont); Optional<BsonValue> ro = right.get(cont); if (lo == null && ro != null) { ret = false; break; } if (lo != null && ro == null) { ret = false; break; } if (lo != null && ro != null) { if (lo.isPresent() && !ro.isPresent()) { ret = false; break; } if (!lo.isPresent() && ro.isPresent()) { ret = false; break; } if (lo.isPresent() && ro.isPresent() && !lo.get().equals(ro.get())) { ret = false; break; } } } return ret; } private boolean checkGetPropsFromPath(BsonValue json, String path, String... expected) { List<Optional<BsonValue>> gots; try { gots = JsonUtils.getPropsFromPath(json, path); } catch (IllegalArgumentException ex) { Assert.fail(ex.toString()); return false; } if (expected == null) { LOG.debug(json + " | " + path + " -> " + gots + " exprected null result (missing field)"); return gots == null; } List<Optional<BsonValue>> exps = new ArrayList<>(); for (String exp : expected) { if (exp == null) { exps.add(null); } else { BsonValue _exp = JsonUtils.parse(exp); if (_exp.isNull()) { exps.add(Optional.empty()); } else { exps.add(Optional.ofNullable(_exp)); } } } LOG.debug(json + " | " + path + " -> " + gots + " exprected " + Arrays.toString(expected)); return eq(exps, gots); } private boolean checkType(BsonDocument json, String path, String expectedType) { List<Optional<BsonValue>> gots; try { gots = JsonUtils.getPropsFromPath(json, path); } catch (IllegalArgumentException ex) { Assert.fail(ex.toString()); return false; } // null means that the path does not exist if (gots == null) { return false; } boolean typeMatch = true; for (Optional<BsonValue> got : gots) { typeMatch = typeMatch && JsonUtils.checkType(got, expectedType); } return typeMatch; } }