From a3a69a697006c3e7c3c506bde5224acefa0584c1 Mon Sep 17 00:00:00 2001
From: Alexander Schlemmer <alexander.schlemmer@ds.mpg.de>
Date: Thu, 2 May 2019 16:46:53 +0200
Subject: [PATCH] Documentation and cleanup of Utils.java. Added tests.

---
 src/main/java/caosdb/server/CaosDBServer.java |  22 ++--
 src/main/java/caosdb/server/utils/Utils.java  | 119 ++++++++----------
 .../java/caosdb/server/utils/UtilsTest.java   |  52 ++++++++
 3 files changed, 112 insertions(+), 81 deletions(-)
 create mode 100644 src/test/java/caosdb/server/utils/UtilsTest.java

diff --git a/src/main/java/caosdb/server/CaosDBServer.java b/src/main/java/caosdb/server/CaosDBServer.java
index a4e1932b..22e941db 100644
--- a/src/main/java/caosdb/server/CaosDBServer.java
+++ b/src/main/java/caosdb/server/CaosDBServer.java
@@ -846,18 +846,16 @@ class CaosDBComponent extends Component {
     setOwner(CaosDBServer.getServerProperty(ServerProperties.KEY_SERVER_OWNER));
   }
 
-    /**
-     * This function is doing the actual work as soon as a request arrives.
-     * In this case this consists in:
-     * - Logging the request, the response and the current time
-     * - The response gets updated with server info
-     * - The request gets updated with an SRID (server request ID)
-     *
-     * Apart from that super.handle will be called.
-     *
-     * The main purpose of the SRID is to allow efficient debugging by checking the error log
-     * for the request causing the error.
-     */
+  /**
+   * This function is doing the actual work as soon as a request arrives. In this case this consists
+   * in: - Logging the request, the response and the current time - The response gets updated with
+   * server info - The request gets updated with an SRID (server request ID)
+   *
+   * <p>Apart from that super.handle will be called.
+   *
+   * <p>The main purpose of the SRID is to allow efficient debugging by checking the error log for
+   * the request causing the error.
+   */
   @Override
   public void handle(final Request request, final Response response) {
     long t1 = System.currentTimeMillis();
diff --git a/src/main/java/caosdb/server/utils/Utils.java b/src/main/java/caosdb/server/utils/Utils.java
index 3ce0fc2f..2916b242 100644
--- a/src/main/java/caosdb/server/utils/Utils.java
+++ b/src/main/java/caosdb/server/utils/Utils.java
@@ -40,9 +40,7 @@ import org.jdom2.Element;
 import org.jdom2.output.Format;
 import org.jdom2.output.XMLOutputter;
 
-/**
- * Utility functions.
- */
+/** Utility functions. */
 public class Utils {
 
   /**
@@ -63,16 +61,15 @@ public class Utils {
     return true;
   }
 
-    /**
-     * Regular expression pattern that checks a mail for RFC822 compliance.
-     *
-     * Taken from: http://www.ex-parrot.com/~pdw/Mail-RFC822-Address.html
-     *
-     * This belongs to the perl module "Mail::RFC822::Address".
-     * It is copyright 2001-2002 by Paul Warren.
-     * The license can be found here:
-     * http://www.ex-parrot.com/~pdw/Mail-RFC822-Address/Mail-RFC822-Address.html#copyright%20and%20license
-     */
+  /**
+   * Regular expression pattern that checks a mail for RFC822 compliance.
+   *
+   * <p>Taken from: http://www.ex-parrot.com/~pdw/Mail-RFC822-Address.html
+   *
+   * <p>This belongs to the perl module "Mail::RFC822::Address". It is copyright 2001-2002 by Paul
+   * Warren. The license can be found here:
+   * http://www.ex-parrot.com/~pdw/Mail-RFC822-Address/Mail-RFC822-Address.html#copyright%20and%20license
+   */
   public static final Pattern EMAIL_PATTERN =
       Pattern.compile(
           "(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)|(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*:(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)(?:,\\s*(?:(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*))*)?;\\s*)");
@@ -149,17 +146,17 @@ public class Utils {
     return FileUtils.toHex(result);
   }
 
-    /**
-     * This function returns the SHA512 hash of a given string, salt and number of iterations.
-     * This function terminates the application completely with an error code when this hashing algorithm
-     * is not available.
-     *
-     * @param string The string to be hashed.
-     * @param salt Cryptographic salt.
-     * @param it Number of iterations. Zero and negative integers don't make any sense. Therefore, if
-     *     it<=1 the hashing is done once.
-     * @return Hashed string, or null if string is null
-     */
+  /**
+   * This function returns the SHA512 hash of a given string, salt and number of iterations. This
+   * function terminates the application completely with an error code when this hashing algorithm
+   * is not available.
+   *
+   * @param string The string to be hashed.
+   * @param salt Cryptographic salt.
+   * @param it Number of iterations. Zero and negative integers don't make any sense. Therefore, if
+   *     it<=1 the hashing is done once.
+   * @return Hashed string, or null if string is null
+   */
   public static String sha512(final String string, final String salt, final int it) {
     try {
       return hash(MessageDigest.getInstance("SHA-512"), string, salt, it);
@@ -171,15 +168,13 @@ public class Utils {
     }
   }
 
-    /**
-     * Random number generator initialized with the system time and used for generating UIDs.
-     */
+  /** Random number generator initialized with the system time and used for generating UIDs. */
   private static Random rand = new Random(System.currentTimeMillis());
 
   /**
    * Generate a UID (Hexadecimal).
    *
-   * Currently this generates two random long numbers and concatenates their hex representations.
+   * <p>Currently this generates two random long numbers and concatenates their hex representations.
    * This function is thread-safe.
    *
    * @return The UID as a String.
@@ -190,20 +185,17 @@ public class Utils {
     }
   }
 
-    /**
-     * Helper function calling InputStream2String for charset UTF-8.
-     */
+  /** Helper function calling InputStream2String for charset UTF-8. */
   public static String InputStream2String(final InputStream is) {
     return InputStream2String(is, "UTF-8");
   }
 
-    /**
-     * Return a string from the input stream is up to the next LF (line feed, \\A) character.
-     *
-     * @param is The input stream
-     * @return The detected string or an empty string if the stream has become empty.
-     *
-     */
+  /**
+   * Return a string from the input stream is up to the next LF (line feed, \\A) character.
+   *
+   * @param is The input stream
+   * @return The detected string or an empty string if the stream has become empty.
+   */
   public static String InputStream2String(final InputStream is, String charset) {
     try (Scanner s = new Scanner(is, charset)) {
       s.useDelimiter("\\A");
@@ -211,9 +203,7 @@ public class Utils {
     }
   }
 
-    /**
-     * Helper function to convert a String into an UTF-8 encoded ByteArrayInputStream.
-     */
+  /** Helper function to convert a String into an UTF-8 encoded ByteArrayInputStream. */
   public static InputStream String2InputStream(final String s) throws UnsupportedEncodingException {
     return new ByteArrayInputStream(s.getBytes("UTF-8"));
   }
@@ -256,20 +246,15 @@ public class Utils {
     }
   }
 
-    /**
-     * Intended to compute the maximum exponent for the required conversion.
-     * TODO: Check whether this is correct. Seems to have an additional factor of 2.
-     *
-     */
+  /** Intended to compute the maximum exponent for the required conversion. */
   public static double log(final int base, final Long x) {
-    return Math.log(x) / Math.log10(base);
+    return Math.log(x) / Math.log(base);
   }
 
-    /**
-     * Intended to convert sizes to human readably sizes.
-     * TODO: might be broken because of the log function above.
-     *
-     */
+  /**
+   * Intended to convert sizes to human readably sizes. TODO: might be broken because of the log
+   * function above.
+   */
   public static String getReadableByteSize(final Long fssize) {
     if (fssize == null) {
       return null;
@@ -277,12 +262,13 @@ public class Utils {
       return "0B";
     }
 
-    final String[] s = new String[] {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
+    final String[] s = new String[] {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"};
     final int i = (int) Math.floor(log(1024, fssize));
     String unit = "1024^" + i;
-    try {
+    if (i < s.length) {
       unit = s[i];
-    } catch (final ArrayIndexOutOfBoundsException e) {
+    } else {
+      // leave the unit as 1024^x if there is no prefix available
     }
 
     final double ret = fssize / Math.pow(1024, i);
@@ -292,20 +278,15 @@ public class Utils {
         .toString();
   }
 
-    /**
-     * Determines the strength of a password.
-     * Currently this just throws an error when the String password does not at least contain
-     * - An uppercase char
-     * - A lowercase char
-     * - A number
-     * - A punctuation char
-     * and if the length is not at least 8 characters.
-     *
-     * correcthorsebatterystaple would be rejected.
-     *
-     * @param password The password to be checked.
-     *
-     */
+  /**
+   * Determines the strength of a password. Currently this just throws an error when the String
+   * password does not at least contain - An uppercase char - A lowercase char - A number - A
+   * punctuation char and if the length is not at least 8 characters.
+   *
+   * <p>correcthorsebatterystaple would be rejected.
+   *
+   * @param password The password to be checked.
+   */
   public static void checkPasswordStrength(final String password) throws Message {
     final boolean length = password.length() >= 8;
     final boolean uppercase = password.matches(".*\\p{Upper}.*");
diff --git a/src/test/java/caosdb/server/utils/UtilsTest.java b/src/test/java/caosdb/server/utils/UtilsTest.java
new file mode 100644
index 00000000..527428ee
--- /dev/null
+++ b/src/test/java/caosdb/server/utils/UtilsTest.java
@@ -0,0 +1,52 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2018 Research Group Biomedical Physics,
+ * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+package caosdb.server.utils;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class UtilsTest {
+
+  /** Test utility functions. */
+
+  /** The log function from utils contained a typo. So here we test it for correct functionality. */
+  @Test
+  public void testFunctionLog() {
+    assert Utils.log(1024, 1024L) == 1.0;
+    assert Utils.log(1024, 1028L) > 1.0;
+    assert Utils.log(1024, (long) Math.pow(1024, 2)) == 2.0;
+  }
+
+  /** Test some cases of human readable file sizes. */
+  @Test
+  public void testConvertFileSizes() {
+    assertEquals(Utils.getReadableByteSize(1022L), "1022B");
+    assertEquals(Utils.getReadableByteSize(0L), "0B");
+    assertEquals(Utils.getReadableByteSize(-1L), "-1B");
+    assertEquals(Utils.getReadableByteSize(1024L), "1KiB");
+    assertEquals(Utils.getReadableByteSize(2048L), "2KiB");
+    assertEquals(Utils.getReadableByteSize(1024 * 1024L), "1MiB");
+    assertEquals(Utils.getReadableByteSize(1024 * 2048L), "2MiB");
+  }
+}
-- 
GitLab