From 2e9d989a6cf43945ace04fd3e7eaa6d61b986097 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sun, 10 Mar 2019 00:21:52 +0100 Subject: [PATCH] Implemented exists() --- pom.xml | 34 ++- .../strangedb/server/DatabaseNodesIO.java | 214 +++++++++++++----- .../strangedb/server/DatabaseSimple.java | 4 + .../cavallium/strangedb/server/NodeType.java | 3 +- .../strangedb/server/NumberNode.java | 35 --- .../it/cavallium/strangedb/server/Server.java | 6 + .../cavallium/strangedb/server/ValueNode.java | 10 +- .../cavallium/strangedb/server/ValueType.java | 7 + .../strangedb/server/http/SizeHandler.java | 37 +++ .../strangedb/server/GetSetExistsTest.java | 67 ++++-- 10 files changed, 303 insertions(+), 114 deletions(-) delete mode 100644 src/main/java/it/cavallium/strangedb/server/NumberNode.java create mode 100644 src/main/java/it/cavallium/strangedb/server/ValueType.java create mode 100644 src/main/java/it/cavallium/strangedb/server/http/SizeHandler.java diff --git a/pom.xml b/pom.xml index 0518152..6d3f001 100644 --- a/pom.xml +++ b/pom.xml @@ -27,9 +27,15 @@ - junit - junit - 4.11 + org.junit.jupiter + junit-jupiter-api + 5.4.0 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.4.0 test @@ -110,6 +116,28 @@ maven-deploy-plugin 2.8.2 + + org.apache.maven.plugins + maven-assembly-plugin + + + jar-with-dependencies + + + + it.cavallium.strangedb.server.Server + + + + + + package + + single + + + + diff --git a/src/main/java/it/cavallium/strangedb/server/DatabaseNodesIO.java b/src/main/java/it/cavallium/strangedb/server/DatabaseNodesIO.java index ec357d3..c2717d3 100644 --- a/src/main/java/it/cavallium/strangedb/server/DatabaseNodesIO.java +++ b/src/main/java/it/cavallium/strangedb/server/DatabaseNodesIO.java @@ -4,12 +4,14 @@ import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; import it.cavallium.strangedb.database.IReferencesIO; import it.cavallium.strangedb.database.references.DatabaseReferencesMetadata; -import org.json.*; +import org.json.JSONArray; +import org.json.JSONObject; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.HashMap; import java.util.Map; import static it.cavallium.strangedb.server.TreePath.stringToNode; @@ -18,8 +20,10 @@ public class DatabaseNodesIO { private final IReferencesIO referencesIO; private static final int isArrayMask = 0b10000000000000000000000000000000; private static final int isValueMask = 0b01000000000000000000000000000000; - private static final int isNumberMask = 0b11000000000000000000000000000000; - private static final int nodeCountMask = 0b01111111111111111111111111111111; + private static final int isValueNumberMask = 0b00000000000000000000000000000001; + private static final int isValueStringMask = 0b00000000000000000000000000000010; + private static final int isValueBooleanMask = 0b00000000000000000000000000000100; + private static final int nodeCountMask = 0b01111111111111111111111111111111; private static final int arrayCountMask = 0b01111111111111111111111111111111; public DatabaseNodesIO(IReferencesIO referencesIO, DatabaseReferencesMetadata referencesMetadata) throws IOException { @@ -37,8 +41,12 @@ public class DatabaseNodesIO { } public String get(TreePath path) throws IOException { - Node foundNode = getNode(path); - return toJson(foundNode); + try { + Node foundNode = getNode(path); + return toJson(foundNode); + } catch (NullPointerException ex) { + return "null"; + } } private String toJson(Node foundNode) throws IOException { @@ -82,12 +90,7 @@ public class DatabaseNodesIO { } case VALUE: { ValueNode valueNode = (ValueNode) foundNode; - sb.append(org.json.JSONObject.quote(loadValue(valueNode.getValueReference()))); - break; - } - case NUMBER: { - NumberNode valueNode = (NumberNode) foundNode; - sb.append(loadNumber(valueNode.getNumberReference())); + sb.append(loadValue(valueNode)); break; } } @@ -98,16 +101,19 @@ public class DatabaseNodesIO { referencesIO.writeToReference(reference, valueBytes.limit(), valueBytes); } - private String loadValue(long reference) throws IOException { - ByteBuffer buffer = referencesIO.readFromReference(reference); - return StandardCharsets.UTF_8.decode(buffer).toString(); - } - - private void setNumber(long reference, double value) throws IOException { - ByteBuffer buffer = ByteBuffer.allocate(Double.BYTES); - buffer.putDouble(value); - buffer.flip(); - referencesIO.writeToReference(reference, buffer.limit(), buffer); + private String loadValue(ValueNode valueNode) throws IOException { + ByteBuffer buffer = referencesIO.readFromReference(valueNode.getReference()); + ByteBuffer valueBuffer = referencesIO.readFromReference(valueNode.getValueReference()); + switch (valueNode.getValueType()) { + case STRING: + return JSONObject.quote(StandardCharsets.UTF_8.decode(valueBuffer).toString()); + case NUMBER: + return JSONObject.doubleToString(valueBuffer.getDouble()); + case BOOLEAN: + return valueBuffer.get() == 1 ? "true" : "false"; + default: + throw new RuntimeException(); + } } private double loadNumber(long reference) throws IOException { @@ -149,7 +155,6 @@ public class DatabaseNodesIO { classNode.setProperty(propertyName, valueReference); break; } - case NUMBER: case VALUE: { throw new IOException("WTF you shouldn't be here!"); } @@ -171,6 +176,15 @@ public class DatabaseNodesIO { case '{': JSONObject obj = new JSONObject(value); return importJsonNode(obj, reference); + case 'u': + if (value.equals("undefined")) + return importJsonNode(value, reference); + case 'N': + if (value.equals("NaN")) + return importJsonNode(value, reference); + case 'n': + if (value.equals("null")) + return importJsonNode(value, reference); case '"': return importJsonNode(value.substring(1, value.length() - 1), reference); case '0': @@ -185,6 +199,12 @@ public class DatabaseNodesIO { case '9': case '.': return importJsonNode(Double.parseDouble(value), reference); + case 't': + if (value.equals("true")) + return importJsonNode(true, reference); + case 'f': + if (value.equals("false")) + return importJsonNode(false, reference); default: throw new IOException("Unrecognized input"); } @@ -199,6 +219,9 @@ public class DatabaseNodesIO { if (o instanceof ArrayList) { o = new JSONArray((ArrayList) o); } + if (o instanceof HashMap) { + o = new JSONObject((HashMap) o); + } if (o instanceof JSONArray) { JSONArray array = (JSONArray) o; int length = array.length(); @@ -217,12 +240,13 @@ public class DatabaseNodesIO { for (Map.Entry entry : jsonProperties.entrySet()) { NodeProperty nodeProperty = new NodeProperty(stringToNode(entry.getKey()), importJsonNode(entry.getValue())); properties[i] = nodeProperty; + i++; } Node node = createNewNodeNode(properties, reference); setNode(node); return node.getReference(); } else if (o instanceof String) { - Node node = createNewValueNode((String) o, reference); + Node node = createNewValueNode(o, ValueType.STRING, reference); setNode(node); return node.getReference(); } else if (o instanceof Double || o instanceof Float || o instanceof Integer || o instanceof Long) { @@ -233,12 +257,14 @@ public class DatabaseNodesIO { number = (Long) o; } else if (o instanceof Float) { number = (Float) o; - } else if (o instanceof Double) { - number = (Double) o; } else { - throw new RuntimeException(); + number = (Double) o; } - Node node = createNewNumberNode(number+0, reference); + Node node = createNewValueNode(number, ValueType.NUMBER, reference); + setNode(node); + return node.getReference(); + } else if (o instanceof Boolean) { + Node node = createNewValueNode(o, ValueType.BOOLEAN, reference); setNode(node); return node.getReference(); } else { @@ -252,6 +278,7 @@ public class DatabaseNodesIO { public boolean exists(TreePath path) throws IOException { TreePathWalker pathWalker = new TreePathWalker(path); + pathWalker.walkToRoot(); Node node = loadNode(0); while (pathWalker.hasNext()) { TreePath nodePath = pathWalker.next(); @@ -260,7 +287,7 @@ public class DatabaseNodesIO { return false; } int offset = nodePath.getArrayOffset(); - if (!((ArrayNode)node).hasItem(offset)) { + if (!((ArrayNode) node).hasItem(offset)) { return false; } long nodeReference = ((ArrayNode) node).getItem(offset); @@ -280,6 +307,52 @@ public class DatabaseNodesIO { return node != null; } + public int size(CharSequence path) throws IOException { + return size(TreePath.get(path)); + } + + public int size(TreePath path) throws IOException { + TreePathWalker pathWalker = new TreePathWalker(path); + pathWalker.walkToRoot(); + Node node = loadNode(0); + while (pathWalker.hasNext()) { + TreePath nodePath = pathWalker.next(); + if (nodePath.isArrayOffset()) { + if (node.getType() != NodeType.ARRAY) { + throw new NullPointerException("Node not found"); + } + int offset = nodePath.getArrayOffset(); + if (!((ArrayNode) node).hasItem(offset)) { + throw new NullPointerException("Node not found"); + } + long nodeReference = ((ArrayNode) node).getItem(offset); + node = loadNode(nodeReference); + } else if (nodePath.isNodeProperty()) { + if (node.getType() == NodeType.ARRAY) { + throw new NullPointerException("Node not found"); + } + byte[] propertyName = nodePath.getNodeValue(); + if (!((ClassNode) node).hasProperty(propertyName)) { + throw new NullPointerException("Node not found"); + } + long nodeReference = ((ClassNode) node).getProperty(propertyName); + node = loadNode(nodeReference); + } + } + if (node != null) { + switch (node.getType()) { + case ARRAY: + return ((ArrayNode) node).countItems(); + case CLASS: + return ((ClassNode) node).countProperties(); + default: + throw new NullPointerException("You can't get the size of this node!"); + } + } else { + throw new NullPointerException("Node not found"); + } + } + private Node getNode(TreePath path) throws IOException { TreePathWalker pathWalker = new TreePathWalker(path); pathWalker.walkToRoot(); @@ -320,27 +393,43 @@ public class DatabaseNodesIO { return new ArrayNode(reference, items); } - private Node createNewValueNode() throws IOException { + private Node createNewValueNode(ValueType type) throws IOException { long reference = referencesIO.allocateReference(); - return new ValueNode(reference, referencesIO.allocateReference()); + return new ValueNode(reference, referencesIO.allocateReference(), type); } private Node createNewValueNode(String value) throws IOException { - return createNewValueNode(value, referencesIO.allocateReference()); + return createNewValueNode(value, ValueType.STRING, referencesIO.allocateReference()); } - private Node createNewValueNode(String value, long reference) throws IOException { - byte[] string = value.getBytes(StandardCharsets.UTF_8); - long dataReference = referencesIO.allocateReference(string.length, ByteBuffer.wrap(string)); - return new ValueNode(reference, dataReference); + private Node createNewValueNode(double value) throws IOException { + return createNewValueNode(value, ValueType.NUMBER, referencesIO.allocateReference()); } - private Node createNewNumberNode(double value, long reference) throws IOException { - ByteBuffer buffer = ByteBuffer.allocate(Double.BYTES); - buffer.putDouble(value); - buffer.flip(); - long dataReference = referencesIO.allocateReference(buffer.limit(), buffer); - return new NumberNode(reference, dataReference); + private Node createNewValueNode(Object value, ValueType valueType, long reference) throws IOException { + ByteBuffer buffer = null; + switch (valueType) { + case STRING: + buffer = StandardCharsets.UTF_8.encode((String) value); + break; + case NUMBER: + buffer = ByteBuffer.allocate(Double.BYTES); + buffer.putDouble((Double) value); + buffer.flip(); + break; + case BOOLEAN: + buffer = ByteBuffer.allocate(Byte.BYTES); + buffer.put(((boolean) value) ? (byte) 1 : 0); + buffer.flip(); + break; + default: + throw new RuntimeException(); + } + long dataReference = -1; + if (buffer != null) { + dataReference = referencesIO.allocateReference(buffer.limit(), buffer); + } + return new ValueNode(reference, dataReference, valueType); } private Node createNewNodeNode() throws IOException { @@ -383,15 +472,22 @@ public class DatabaseNodesIO { buffer = ByteBuffer.wrap(dataOutput.toByteArray()); break; case VALUE: + ValueNode valueNode = (ValueNode) node; buffer = ByteBuffer.allocate(Integer.BYTES + Long.BYTES); - buffer.putInt(isValueMask); - buffer.putLong(((ValueNode) node).getValueReference()); - buffer.flip(); - break; - case NUMBER: - buffer = ByteBuffer.allocate(Integer.BYTES + Long.BYTES); - buffer.putInt(isNumberMask); - buffer.putLong(((NumberNode) node).getNumberReference()); + switch (valueNode.getValueType()) { + case STRING: + buffer.putInt(isValueMask | isValueStringMask); + break; + case NUMBER: + buffer.putInt(isValueMask | isValueNumberMask); + break; + case BOOLEAN: + buffer.putInt(isValueMask | isValueBooleanMask); + break; + default: + throw new RuntimeException(); + } + buffer.putLong(valueNode.getValueReference()); buffer.flip(); break; default: @@ -404,8 +500,7 @@ public class DatabaseNodesIO { Node node; ByteBuffer nodeData = referencesIO.readFromReference(reference); int propertiesCount = nodeData.getInt(); - boolean isNumber = (propertiesCount & isNumberMask) == isNumberMask; - boolean isArray = !isNumber && (propertiesCount & isArrayMask) != 0; + boolean isArray = (propertiesCount & isArrayMask) != 0; if (isArray) { int arrayElementsCount = propertiesCount & arrayCountMask; long[] arrayElementsReferences = new long[arrayElementsCount]; @@ -414,13 +509,18 @@ public class DatabaseNodesIO { } node = new ArrayNode(reference, arrayElementsReferences); } else { - boolean isValue = !isNumber && (propertiesCount & isValueMask) != 0; + boolean isValue = (propertiesCount & isValueMask) != 0; if (isValue) { - long valueReference = nodeData.getLong(); - node = new ValueNode(reference, valueReference); - } else if (isNumber) { - long numberReference = nodeData.getLong(); - node = new NumberNode(reference, numberReference); + long dataReference = nodeData.getLong(); + if ((propertiesCount & isValueStringMask) != 0) { + node = new ValueNode(reference, dataReference, ValueType.STRING); + } else if ((propertiesCount & isValueNumberMask) != 0) { + node = new ValueNode(reference, dataReference, ValueType.NUMBER); + } else if ((propertiesCount & isValueBooleanMask) != 0) { + node = new ValueNode(reference, dataReference, ValueType.BOOLEAN); + } else { + throw new IOException(); + } } else { NodeProperty[] nodeProperties = new NodeProperty[propertiesCount & nodeCountMask]; for (int i = 0; i < propertiesCount; i++) { diff --git a/src/main/java/it/cavallium/strangedb/server/DatabaseSimple.java b/src/main/java/it/cavallium/strangedb/server/DatabaseSimple.java index 9222ba5..e724a61 100644 --- a/src/main/java/it/cavallium/strangedb/server/DatabaseSimple.java +++ b/src/main/java/it/cavallium/strangedb/server/DatabaseSimple.java @@ -24,4 +24,8 @@ public class DatabaseSimple extends DatabaseCore { public boolean exists(CharSequence path) throws IOException { return databaseNodesIO.exists(path); } + + public int size(CharSequence path) throws IOException { + return databaseNodesIO.size(path); + } } diff --git a/src/main/java/it/cavallium/strangedb/server/NodeType.java b/src/main/java/it/cavallium/strangedb/server/NodeType.java index ca74e54..8d3113a 100644 --- a/src/main/java/it/cavallium/strangedb/server/NodeType.java +++ b/src/main/java/it/cavallium/strangedb/server/NodeType.java @@ -3,6 +3,5 @@ package it.cavallium.strangedb.server; public enum NodeType { VALUE, CLASS, - ARRAY, - NUMBER; + ARRAY } diff --git a/src/main/java/it/cavallium/strangedb/server/NumberNode.java b/src/main/java/it/cavallium/strangedb/server/NumberNode.java deleted file mode 100644 index 4248474..0000000 --- a/src/main/java/it/cavallium/strangedb/server/NumberNode.java +++ /dev/null @@ -1,35 +0,0 @@ -package it.cavallium.strangedb.server; - -public class NumberNode implements Node { - - private final long reference; - private long value; - - public NumberNode(long reference, long value) { - this.reference = reference; - this.value = value; - } - - public long getNumberReference() { - return value; - } - - public void setValue(long value) { - this.value = value; - } - - @Override - public NodeType getType() { - return NodeType.NUMBER; - } - - @Override - public long getReference() { - return reference; - } - - @Override - public Node copy() { - return new NumberNode(reference, value); - } -} diff --git a/src/main/java/it/cavallium/strangedb/server/Server.java b/src/main/java/it/cavallium/strangedb/server/Server.java index e02ff14..aa23c00 100644 --- a/src/main/java/it/cavallium/strangedb/server/Server.java +++ b/src/main/java/it/cavallium/strangedb/server/Server.java @@ -4,6 +4,7 @@ import com.sun.net.httpserver.HttpServer; import it.cavallium.strangedb.server.http.ExistsHandler; import it.cavallium.strangedb.server.http.GetHandler; import it.cavallium.strangedb.server.http.SetHandler; +import it.cavallium.strangedb.server.http.SizeHandler; import java.io.IOException; import java.net.InetSocketAddress; @@ -19,6 +20,7 @@ public class Server { server.createContext("/get", new GetHandler(this)); server.createContext("/set", new SetHandler(this)); server.createContext("/exists", new ExistsHandler(this)); + server.createContext("/size", new SizeHandler(this)); server.setExecutor(null); server.start(); } @@ -41,6 +43,10 @@ public class Server { return database.exists(path); } + public int size(CharSequence path) throws IOException { + return database.size(path); + } + public String get(CharSequence path) throws IOException { return database.get(path); } diff --git a/src/main/java/it/cavallium/strangedb/server/ValueNode.java b/src/main/java/it/cavallium/strangedb/server/ValueNode.java index 4d8a771..d01d501 100644 --- a/src/main/java/it/cavallium/strangedb/server/ValueNode.java +++ b/src/main/java/it/cavallium/strangedb/server/ValueNode.java @@ -5,11 +5,13 @@ import java.util.Arrays; public class ValueNode implements Node { private final long reference; + private final ValueType valueType; private long value; - public ValueNode(long reference, long value) { + public ValueNode(long reference, long value, ValueType valueType) { this.reference = reference; this.value = value; + this.valueType = valueType; } public long getValueReference() { @@ -25,6 +27,10 @@ public class ValueNode implements Node { return NodeType.VALUE; } + public ValueType getValueType() { + return valueType; + } + @Override public long getReference() { return reference; @@ -32,6 +38,6 @@ public class ValueNode implements Node { @Override public Node copy() { - return new ValueNode(reference, value); + return new ValueNode(reference, value, valueType); } } diff --git a/src/main/java/it/cavallium/strangedb/server/ValueType.java b/src/main/java/it/cavallium/strangedb/server/ValueType.java new file mode 100644 index 0000000..f971e9c --- /dev/null +++ b/src/main/java/it/cavallium/strangedb/server/ValueType.java @@ -0,0 +1,7 @@ +package it.cavallium.strangedb.server; + +public enum ValueType { + STRING, + NUMBER, + BOOLEAN +} diff --git a/src/main/java/it/cavallium/strangedb/server/http/SizeHandler.java b/src/main/java/it/cavallium/strangedb/server/http/SizeHandler.java new file mode 100644 index 0000000..4b96e44 --- /dev/null +++ b/src/main/java/it/cavallium/strangedb/server/http/SizeHandler.java @@ -0,0 +1,37 @@ +package it.cavallium.strangedb.server.http; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import it.cavallium.strangedb.server.Server; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; + +public class SizeHandler implements HttpHandler { + + private final Server server; + + public SizeHandler(Server server) { + this.server = server; + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + String requestPath = exchange.getRequestURI().toString().split("/size/", 2)[1].replace('(', '[').replace(')', ']'); + int responseCode = 500; + String response; + try { + response = "" + server.size(requestPath); + responseCode = 200; + } catch (Exception ex) { + ex.printStackTrace(); + response = "Error"; + } + byte[] responseBytes = response.getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(responseCode, responseBytes.length); + OutputStream os = exchange.getResponseBody(); + os.write(responseBytes); + os.close(); + } +} diff --git a/src/test/java/it/cavallium/strangedb/server/GetSetExistsTest.java b/src/test/java/it/cavallium/strangedb/server/GetSetExistsTest.java index e1349df..3e46f5b 100644 --- a/src/test/java/it/cavallium/strangedb/server/GetSetExistsTest.java +++ b/src/test/java/it/cavallium/strangedb/server/GetSetExistsTest.java @@ -1,14 +1,15 @@ package it.cavallium.strangedb.server; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import static junit.framework.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class GetSetExistsTest { @@ -17,7 +18,7 @@ public class GetSetExistsTest { private Path path3; private DatabaseSimple db; - @Before + @BeforeEach public void setUp() throws Exception { path1 = Files.createTempFile("db-tests-", ".db"); path2 = Files.createTempFile("db-tests-", ".db"); @@ -32,22 +33,58 @@ public class GetSetExistsTest { db.set("", "{}"); assertTrue(db.exists("")); assertEquals(db.get(""), "{}"); - db.set("brightness", "\"15\""); + db.set("value", "{}"); + db.set("value.int", "12"); + db.set("value.number", "12.13"); + db.set("value.null", "null"); + db.set("value.boolean", "true"); + db.set("value.undefined", "undefined"); + db.set("value.string", "\"test\""); + db.set("value.array", "[1,2,3,4,5]"); + db.set("value.object", "{a: 1, b: \"2\", c: [3], d: {}}"); } @Test public void shouldGetObject() throws IOException { - assertFalse(db.exists("brightness")); - db.set("brightness", "\"15\""); - assertTrue(db.exists("brightness")); - assertEquals(db.get("brightness"), "\"15\""); - assertEquals(db.get(""), "{brightness:\"15\"}"); - db.set("brightness", "\"16\""); - assertEquals(db.get("brightness"), "\"16\""); - assertEquals(db.get(""), "{brightness:\"16\"}"); + db.set("", "{\n" + + "\t\"value\": {\n" + + "\t\t\"int\": 12,\n" + + "\t\t\"number\": 12.13," + + "nil: null,\n" + + "\t\t\"boolean\": true,\n" + + "\t\t\"string\": \"test\",\n" + + "\t\t\"array\": [1,2,3,4],\n" + + "\t\t\"object\": {\n" + + "\t\t\t\"a\": 1,\n" + + "\t\t\t\"b\": \"2\",\n" + + "\t\t\t\"c\": [3],\n" + + "\t\t\t\"d\": {}\n" + + "\t\t}\n" + + "\t}\n" + + "}"); + assertFalse(db.exists("random")); + assertTrue(db.exists("value")); + assertEquals("12", db.get("value.int")); + assertEquals("12.13", db.get("value.number")); + assertEquals("null", db.get("value.nil")); + assertEquals("true", db.get("value.boolean")); + assertEquals("\"test\"", db.get("value.string")); + assertEquals("[1,2,3,4]", db.get("value.array")); + assertEquals("1", db.get("value.object.a")); + assertEquals("\"2\"", db.get("value.object.b")); + assertEquals("[3]", db.get("value.object.c")); + assertEquals("{}", db.get("value.object.d")); } - @After + @Test + public void shouldGetSize() throws IOException { + db.set("", "{array:[1,2,3,4,5], object: {a: 1, b: 2, c: 3}, string: \"test\"}"); + assertEquals(5, db.size("array")); + assertEquals(3, db.size("object")); + assertThrows(NullPointerException.class, () -> db.size("test")); + } + + @AfterEach public void tearDown() throws Exception { db.close(); Files.deleteIfExists(path1);