diff --git a/.travis.yml b/.travis.yml index 91c94f5..0956bb0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,16 +2,35 @@ language: android android: components: - - tools - - build-tools-23.0.2 + - build-tools-23.0.1 - android-23 licenses: - 'android-sdk-license-.+' -notifications: - email: true +addons: + apt_packages: + - pandoc -sudo: false +before_install: + echo "MAVEN_OPTS='-Xmx2048m -XX:MaxPermSize=1024m'" > ~/.mavenrc script: -- ./gradlew test \ No newline at end of file +- ./gradlew ciCheck + +notifications: + email: false + +sudo: true + +before_cache: + - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock + +cache: + directories: + - $HOME/.m2 + - $HOME/.gradle/caches/ + - $HOME/.gradle/wrapper/ + +after_failure: + - pandoc app/build/outputs/lint-results.html -t plain + - pandoc app/build/reports/debug/index.html -t plain \ No newline at end of file diff --git a/build.gradle b/build.gradle index 11b7f9f..d5e0694 100644 --- a/build.gradle +++ b/build.gradle @@ -19,3 +19,13 @@ allprojects { jcenter() } } + +subprojects { + task ciCheck { + group 'verification' + } +} + +// Added specific declaration here because :sdk doesn't have testDebugUnitTest +project(':hawk').ciCheck.dependsOn(['checkstyle']) +project(':hawk').ciCheck.dependsOn(['testDebugUnitTest']) diff --git a/checkstyle.xml b/checkstyle.xml index 2b95aba..bb47644 100755 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -49,7 +49,7 @@ - + @@ -105,10 +105,10 @@ - + - + diff --git a/hawk/build.gradle b/hawk/build.gradle index 5044ea9..ff3d6e5 100644 --- a/hawk/build.gradle +++ b/hawk/build.gradle @@ -16,7 +16,7 @@ task checkstyle(type: Checkstyle) { android { compileSdkVersion 23 - buildToolsVersion "23.0.2" + buildToolsVersion "23.0.1" defaultConfig { minSdkVersion 9 @@ -35,7 +35,7 @@ task sourcesJar(type: Jar) { } task javadoc(type: Javadoc) { - failOnError false + failOnError false source = android.sourceSets.main.java.sourceFiles classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) } diff --git a/hawk/src/main/java/com/orhanobut/hawk/Base64Encryption.java b/hawk/src/main/java/com/orhanobut/hawk/Base64Encryption.java index 4bcf814..e5a87db 100644 --- a/hawk/src/main/java/com/orhanobut/hawk/Base64Encryption.java +++ b/hawk/src/main/java/com/orhanobut/hawk/Base64Encryption.java @@ -1,22 +1,43 @@ package com.orhanobut.hawk; +import android.util.Base64; + /** - * Provides Base64 Algorithm + * Provides Base64 encoding as non-encryption option. + * This doesn't provide any encryption */ -public class Base64Encryption implements Encryption { +class Base64Encryption implements Encryption { @Override public boolean init() { return true; } @Override public String encrypt(byte[] value) { - return DataHelper.encodeBase64(value); + return encodeBase64(value); } @Override public byte[] decrypt(String value) { - return DataHelper.decodeBase64(value); + return decodeBase64(value); } @Override public boolean reset() { return true; } + + String encodeBase64(byte[] bytes) { + try { + return Base64.encodeToString(bytes, Base64.DEFAULT); + } catch (Exception e) { + Logger.w(e.getMessage()); + return null; + } + } + + byte[] decodeBase64(String value) { + try { + return Base64.decode(value, Base64.DEFAULT); + } catch (Exception e) { + Logger.w(e.getMessage()); + return null; + } + } } diff --git a/hawk/src/main/java/com/orhanobut/hawk/DataHelper.java b/hawk/src/main/java/com/orhanobut/hawk/DataHelper.java index b419df2..cf3f937 100644 --- a/hawk/src/main/java/com/orhanobut/hawk/DataHelper.java +++ b/hawk/src/main/java/com/orhanobut/hawk/DataHelper.java @@ -1,7 +1,6 @@ package com.orhanobut.hawk; import android.text.TextUtils; -import android.util.Base64; import java.util.HashMap; import java.util.Iterator; @@ -11,12 +10,10 @@ final class DataHelper { - private static final String DELIMITER = "@"; + private static final char DELIMITER = '@'; private static final String INFO_DELIMITER = "#"; private static final char NEW_VERSION = 'V'; - @Deprecated private static final char FLAG_SERIALIZABLE = '1'; - private static final Map TYPE_MAP = new HashMap<>(); static { @@ -37,13 +34,13 @@ private DataHelper() { * @return the DataInfo object which contains all necessary information */ static DataInfo getDataInfo(String storedText) { - if (TextUtils.isEmpty(storedText)) { - throw new NullPointerException("Text should not be null or empty"); - } + HawkUtils.checkNullOrEmpty("Text", storedText); + int index = storedText.indexOf(DELIMITER); if (index == -1) { throw new IllegalArgumentException("Text should contain delimiter"); } + String text = storedText.substring(0, index); String cipherText = storedText.substring(index + 1); if (TextUtils.isEmpty(text) || TextUtils.isEmpty(cipherText)) { @@ -53,7 +50,8 @@ static DataInfo getDataInfo(String storedText) { if (firstChar == NEW_VERSION) { return getNewDataInfo(text, cipherText); } else { - return getOldDataInfo(text, cipherText); + // old data is no longer supported + throw new IllegalStateException("storedText is not valid"); } } @@ -87,30 +85,11 @@ static DataInfo getNewDataInfo(String text, String cipherText) { return new DataInfo(dataType, cipherText, keyClazz, valueClazz); } - @Deprecated static DataInfo getOldDataInfo(String text, String cipherText) { - boolean serializable = text.charAt(text.length() - 1) == FLAG_SERIALIZABLE; - char type = text.charAt(text.length() - 2); - DataType dataType = TYPE_MAP.get(type); - - String className = text.substring(0, text.length() - 2); - - Class clazz = null; - try { - clazz = Class.forName(className); - } catch (ClassNotFoundException e) { - Logger.d(e.getMessage()); - } - - return new DataInfo(dataType, serializable, cipherText, clazz); - } - + //TODO optimize static String addType(String cipherText, T t) { - if (TextUtils.isEmpty(cipherText)) { - throw new NullPointerException("Cipher text should not be null or empty"); - } - if (t == null) { - throw new NullPointerException("Value should not be null"); - } + HawkUtils.checkNullOrEmpty("Cipher text", cipherText); + HawkUtils.checkNull("Value", t); + String keyClassName = ""; String valueClassName = ""; DataType dataType; @@ -150,22 +129,4 @@ static String addType(String cipherText, T t) { cipherText; } - static String encodeBase64(byte[] bytes) { - try { - return Base64.encodeToString(bytes, Base64.DEFAULT); - } catch (Exception e) { - Logger.w(e.getMessage()); - return null; - } - } - - static byte[] decodeBase64(String value) { - try { - return Base64.decode(value, Base64.DEFAULT); - } catch (Exception e) { - Logger.w(e.getMessage()); - return null; - } - } - } diff --git a/hawk/src/main/java/com/orhanobut/hawk/DataInfo.java b/hawk/src/main/java/com/orhanobut/hawk/DataInfo.java index 45242bd..a38cdf3 100644 --- a/hawk/src/main/java/com/orhanobut/hawk/DataInfo.java +++ b/hawk/src/main/java/com/orhanobut/hawk/DataInfo.java @@ -2,52 +2,15 @@ final class DataInfo { - private final DataType dataType; - private final String cipherText; - private final Class keyClazz; - private final Class valueClazz; - private final boolean serializable; - private final boolean isNewVersion; - - DataInfo(DataType dataType, boolean serializable, String cipherText, Class keyClazz) { - this.cipherText = cipherText; - this.keyClazz = keyClazz; - this.valueClazz = null; - this.dataType = dataType; - this.serializable = serializable; - this.isNewVersion = false; - } + final DataType dataType; + final String cipherText; + final Class keyClazz; + final Class valueClazz; DataInfo(DataType dataType, String cipherText, Class keyClazz, Class valueClazz) { this.cipherText = cipherText; this.keyClazz = keyClazz; this.valueClazz = valueClazz; this.dataType = dataType; - this.serializable = false; - this.isNewVersion = true; - } - - public DataType getDataType() { - return dataType; - } - - String getCipherText() { - return cipherText; - } - - Class getKeyClazz() { - return keyClazz; - } - - public Class getValueClazz() { - return valueClazz; - } - - public boolean isSerializable() { - return serializable; - } - - public boolean isNewVersion() { - return isNewVersion; } } diff --git a/hawk/src/main/java/com/orhanobut/hawk/DataType.java b/hawk/src/main/java/com/orhanobut/hawk/DataType.java index 08ae608..215ee92 100644 --- a/hawk/src/main/java/com/orhanobut/hawk/DataType.java +++ b/hawk/src/main/java/com/orhanobut/hawk/DataType.java @@ -12,10 +12,6 @@ enum DataType { this.type = type; } - @Override public String toString() { - return super.toString(); - } - char getType() { return type; } diff --git a/hawk/src/main/java/com/orhanobut/hawk/Hawk.java b/hawk/src/main/java/com/orhanobut/hawk/Hawk.java index 6e4b95d..806de3f 100644 --- a/hawk/src/main/java/com/orhanobut/hawk/Hawk.java +++ b/hawk/src/main/java/com/orhanobut/hawk/Hawk.java @@ -12,28 +12,34 @@ public final class Hawk { - private static HawkInternal internal; - - private Hawk() { - // no instance + static Hawk HAWK; + + private final Storage storage; + private final Encoder encoder; + private final Encryption encryption; + private final LogLevel logLevel; + + private Hawk(HawkBuilder builder) { + storage = builder.getStorage(); + encoder = builder.getEncoder(); + encryption = builder.getEncryption(); + logLevel = builder.getLogLevel(); } /** * This will init the hawk without password protection. * - * @param context is used to instantiate context based objects. ApplicationContext will be used + * @param context is used to instantiate context based objects. + * ApplicationContext will be used */ public static HawkBuilder init(Context context) { - if (context == null) { - throw new NullPointerException("Context should not be null"); - } - - internal = null; + HawkUtils.checkNull("Context", context); + HAWK = null; return new HawkBuilder(context); } - static void onHawkBuilt(HawkBuilder builder) { - Hawk.internal = new HawkInternal(builder); + static void build(HawkBuilder hawkBuilder) { + HAWK = new Hawk(hawkBuilder); } /** @@ -44,10 +50,8 @@ static void onHawkBuilt(HawkBuilder builder) { * @return true if put is successful */ public static boolean put(String key, T value) { - if (key == null) { - throw new NullPointerException("Key cannot be null"); - } - Utils.validateBuild(); + HawkUtils.checkNull("Key", key); + HawkUtils.validateBuild(); //if the value is null, simply remove it if (value == null) { @@ -56,7 +60,7 @@ public static boolean put(String key, T value) { String encodedText = zip(value); //if any exception occurs during encoding, encodedText will be null and thus operation is unsuccessful - return encodedText != null && internal.getStorage().put(key, encodedText); + return encodedText != null && HAWK.storage.put(key, encodedText); } /** @@ -66,7 +70,7 @@ public static boolean put(String key, T value) { * @return Observable */ public static Observable putObservable(final String key, final T value) { - Utils.checkRx(); + HawkUtils.checkRx(); return Observable.create(new Observable.OnSubscribe() { @Override public void call(Subscriber subscriber) { @@ -85,49 +89,28 @@ public void call(Subscriber subscriber) { }); } - /** - * Encodes the given value as full text (cipher + data info) - * - * @param value is the given value to encode - * @return full text as string - */ - private static String zip(T value) { - if (value == null) { - throw new NullPointerException("Value cannot be null"); - } - byte[] encodedValue = internal.getEncoder().encode(value); - - String cipherText = internal.getEncryption().encrypt(encodedValue); - - if (cipherText == null) { - return null; - } - return DataHelper.addType(cipherText, value); - } - /** * @param key is used to get the saved data * @return the saved object */ public static T get(String key) { - if (key == null) { - throw new NullPointerException("Key cannot be null"); - } - Utils.validateBuild(); - String fullText = internal.getStorage().get(key); + HawkUtils.checkNull("Key", key); + HawkUtils.validateBuild(); + + String fullText = HAWK.storage.get(key); if (fullText == null) { return null; } DataInfo dataInfo = DataHelper.getDataInfo(fullText); - byte[] bytes = internal.getEncryption().decrypt(dataInfo.getCipherText()); + byte[] bytes = HAWK.encryption.decrypt(dataInfo.cipherText); if (bytes == null) { return null; } try { - return internal.getEncoder().decode(bytes, dataInfo); + return HAWK.encoder.decode(bytes, dataInfo); } catch (Exception e) { Logger.d(e.getMessage()); } @@ -158,7 +141,7 @@ public static T get(String key, T defaultValue) { * @return Observable */ public static Observable getObservable(String key) { - Utils.checkRx(); + HawkUtils.checkRx(); return getObservable(key, null); } @@ -172,7 +155,7 @@ public static Observable getObservable(String key) { * @return Observable */ public static Observable getObservable(final String key, final T defaultValue) { - Utils.checkRx(); + HawkUtils.checkRx(); return Observable.create(new Observable.OnSubscribe() { @Override public void call(Subscriber subscriber) { @@ -216,8 +199,8 @@ public static Chain chain(int capacity) { * @return the size */ public static long count() { - Utils.validateBuild(); - return internal.getStorage().count(); + HawkUtils.validateBuild(); + return HAWK.storage.count(); } /** @@ -227,8 +210,8 @@ public static long count() { * @return true if clear is successful */ public static boolean clear() { - Utils.validateBuild(); - return internal.getStorage().clear(); + HawkUtils.validateBuild(); + return HAWK.storage.clear(); } /** @@ -238,8 +221,8 @@ public static boolean clear() { * @return true if remove is successful */ public static boolean remove(String key) { - Utils.validateBuild(); - return internal.getStorage().remove(key); + HawkUtils.validateBuild(); + return HAWK.storage.remove(key); } /** @@ -249,8 +232,8 @@ public static boolean remove(String key) { * @return true if all removals are successful */ public static boolean remove(String... keys) { - Utils.validateBuild(); - return internal.getStorage().remove(keys); + HawkUtils.validateBuild(); + return HAWK.storage.remove(keys); } /** @@ -260,8 +243,8 @@ public static boolean remove(String... keys) { * @return true if it exists in the storage */ public static boolean contains(String key) { - Utils.validateBuild(); - return internal.getStorage().contains(key); + HawkUtils.validateBuild(); + return HAWK.storage.contains(key); } /** @@ -270,15 +253,15 @@ public static boolean contains(String key) { * @return true if reset is successful */ public static boolean resetCrypto() { - Utils.validateBuild(); - return internal.getEncryption().reset(); + HawkUtils.validateBuild(); + return HAWK.encryption.reset(); } public static LogLevel getLogLevel() { - if (internal == null) { + if (HAWK == null) { return LogLevel.NONE; } - return internal.getLogLevel(); + return HAWK.logLevel; } /** @@ -287,7 +270,7 @@ public static LogLevel getLogLevel() { * @return true if correctly initialised and built. False otherwise. */ public static boolean isBuilt() { - return internal != null; + return HAWK != null; } /** @@ -297,7 +280,34 @@ public static boolean isBuilt() { * commit() writes the chain values to persistent storage. Omitting it will * result in all chained data being lost. */ - public static final class Chain { + /** + * Encodes the given value as full text (cipher + data info) + * + * @param value is the given value to encode + * @return full text as string + */ + private static String zip(T value) { + HawkUtils.checkNull("Value", value); + + byte[] encodedValue = HAWK.encoder.encode(value); + + if (encodedValue == null || encodedValue.length == 0) { + return null; + } + + String cipherText = HAWK.encryption.encrypt(encodedValue); + + if (cipherText == null) { + return null; + } + return DataHelper.addType(cipherText, value); + } + + public static void destroy() { + HAWK = null; + } + + public static class Chain { private final List> items; @@ -316,10 +326,8 @@ public Chain(int capacity) { * @param value is the data that is gonna be saved. Value can be object, list type, primitives */ public Chain put(String key, T value) { - if (key == null) { - throw new NullPointerException("Key cannot be null"); - } - Utils.validateBuild(); + HawkUtils.checkNullOrEmpty("Key", key); + HawkUtils.validateBuild(); String encodedText = zip(value); if (encodedText == null) { Log.d("HAWK", "Key : " + key + " is not added, encryption failed"); @@ -335,7 +343,7 @@ public Chain put(String key, T value) { * @return true if successfully saved, false otherwise. */ public boolean commit() { - return internal.getStorage().put(items); + return HAWK.storage.put(items); } } diff --git a/hawk/src/main/java/com/orhanobut/hawk/HawkBuilder.java b/hawk/src/main/java/com/orhanobut/hawk/HawkBuilder.java index 0e9e79d..47d4351 100644 --- a/hawk/src/main/java/com/orhanobut/hawk/HawkBuilder.java +++ b/hawk/src/main/java/com/orhanobut/hawk/HawkBuilder.java @@ -1,11 +1,13 @@ package com.orhanobut.hawk; import android.content.Context; -import android.os.Handler; import android.text.TextUtils; import com.google.gson.Gson; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + import rx.Observable; import rx.Subscriber; import rx.functions.Func0; @@ -13,17 +15,16 @@ public class HawkBuilder { /** - * never ever change this value since it will break backward compatibility in terms of keeping previous data + * NEVER ever change TAG and TAG_INFO. + * It will break backward compatibility in terms of keeping previous data */ private static final String TAG = "HAWK"; - - /** - * never ever change this value since it will break backward compatibility in terms of keeping previous data - */ private static final String TAG_INFO = "324909sdfsd98098"; /** - * Key to store if the device does not support crypto + * Key to store if the device does not support crypto. + * This key has nothing to do with encryption key, + * This is merely used for the key tag for preferences value. */ private static final String KEY_NO_CRYPTO = "dfsklj2342nasdfoasdfcrpknasdf"; @@ -35,16 +36,14 @@ public class HawkBuilder { private Encoder encoder; private Parser parser; private Encryption encryption; - private Callback callback; public enum EncryptionMethod { HIGHEST, MEDIUM, NO_ENCRYPTION } public HawkBuilder(Context context) { - if (context == null) { - throw new NullPointerException("Context should not be null"); - } + HawkUtils.checkNull("Context", context); + this.context = context.getApplicationContext(); } @@ -71,13 +70,18 @@ public HawkBuilder setStorage(Storage storage) { return this; } - public HawkBuilder setCallback(Callback callback) { - this.callback = callback; + public HawkBuilder setParser(Parser parser) { + this.parser = parser; return this; } - public HawkBuilder setParser(Parser parser) { - this.parser = parser; + HawkBuilder setEncoder(Encoder encoder) { + this.encoder = encoder; + return this; + } + + HawkBuilder setEncryption(Encryption encryption) { + this.encryption = encryption; return this; } @@ -138,26 +142,53 @@ private void validate() { } public void build() { - if (callback != null) { - new Handler().post(new Runnable() { - @Override public void run() { - try { - startBuild(); - callback.onSuccess(); - } catch (Exception e) { - callback.onFail(e); - } - } - }); - return; - } startBuild(); } - private void startBuild() { + public void build(final Callback callback) { + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(new Runnable() { + @Override public void run() { + try { + startBuild(); + callback.onSuccess(); + } catch (Exception e) { + callback.onFail(e); + } + } + }); + executor.shutdown(); + } + + /** + * Callback interface to make actions on another place and execute code + * based on a result of action + * onSuccess function will be called when action is successful + * onFail function will be called when action fails due to a reason + */ + public Observable buildRx() { + HawkUtils.checkRx(); + return Observable.defer(new Func0>() { + @Override public Observable call() { + return Observable.create(new Observable.OnSubscribe() { + @Override public void call(Subscriber subscriber) { + try { + startBuild(); + subscriber.onNext(true); + subscriber.onCompleted(); + } catch (Exception e) { + subscriber.onError(e); + } + } + }); + } + }); + } + + void startBuild() { validate(); setEncryption(); - Hawk.onHawkBuilt(this); + Hawk.build(this); } private void setEncryption() { @@ -175,10 +206,13 @@ private void setEncryption() { case MEDIUM: encryption = new AesEncryption(getStorage(), null); if (!getEncryption().init()) { + //fallback to no encryption getInfoStorage().put(KEY_NO_CRYPTO, true); encryption = new Base64Encryption(); } break; + default: + throw new IllegalStateException("encryption mode should be valid"); } } @@ -190,35 +224,11 @@ public static Storage newSqliteStorage(Context context) { return new SqliteStorage(context); } - /** - * Callback interface to make actions on another place and execute code - * based on a result of action - * onSuccess function will be called when action is successful - * onFail function will be called when action fails due to a reason - */ public interface Callback { void onSuccess(); void onFail(Exception e); - } - public Observable buildRx() { - Utils.checkRx(); - return Observable.defer(new Func0>() { - @Override public Observable call() { - return Observable.create(new Observable.OnSubscribe() { - @Override public void call(Subscriber subscriber) { - try { - startBuild(); - subscriber.onNext(true); - subscriber.onCompleted(); - } catch (Exception e) { - subscriber.onError(e); - } - } - }); - } - }); } } diff --git a/hawk/src/main/java/com/orhanobut/hawk/HawkEncoder.java b/hawk/src/main/java/com/orhanobut/hawk/HawkEncoder.java index 54a993c..e0e9b76 100644 --- a/hawk/src/main/java/com/orhanobut/hawk/HawkEncoder.java +++ b/hawk/src/main/java/com/orhanobut/hawk/HawkEncoder.java @@ -2,9 +2,6 @@ import com.google.gson.reflect.TypeToken; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -45,43 +42,15 @@ public HawkEncoder(Parser parser) { if (bytes == null) { return null; } - if (info == null) { - throw new NullPointerException("data info should not be null"); - } - if (info.isNewVersion()) { - return decodeNew(bytes, info); - } else { - return decodeOld(bytes, info); - } - } - - @Deprecated private T decodeOld(byte[] bytes, DataInfo info) throws Exception { - boolean isList = info.getDataType() == DataType.LIST; - - // if the value is not list and serializable, then use the normal deserialize - if (!isList && info.isSerializable()) { - return toSerializable(bytes); - } - - // convert to the string json - String json = new String(bytes); - - Class type = info.getKeyClazz(); - if (!isList) { - return parser.fromJson(json, type); - } + HawkUtils.checkNull("data info", info); - return toList(json, type); - } - - private T decodeNew(byte[] bytes, DataInfo info) throws Exception { // convert to the string json String json = new String(bytes); - Class keyType = info.getKeyClazz(); - Class valueType = info.getValueClazz(); + Class keyType = info.keyClazz; + Class valueType = info.valueClazz; - switch (info.getDataType()) { + switch (info.dataType) { case OBJECT: return toObject(json, keyType); case LIST: @@ -154,33 +123,4 @@ private T toMap(String json, Class keyType, Class valueType) thr return (T) resultMap; } - /** - * Converts byte[] to a serializable object - * - * @param bytes the data - * @param object type - * @return the serializable object - */ - @SuppressWarnings("unchecked") - @Deprecated private T toSerializable(byte[] bytes) { - ObjectInputStream inputStream = null; - try { - inputStream = new ObjectInputStream(new ByteArrayInputStream(bytes)); - } catch (IOException e) { - Logger.d(e.getMessage()); - } - - if (inputStream == null) { - return null; - } - - T result = null; - try { - result = (T) inputStream.readObject(); - } catch (ClassNotFoundException | IOException e) { - Logger.d(e.getMessage()); - } - return result; - } - } diff --git a/hawk/src/main/java/com/orhanobut/hawk/HawkInternal.java b/hawk/src/main/java/com/orhanobut/hawk/HawkInternal.java deleted file mode 100644 index 58474e0..0000000 --- a/hawk/src/main/java/com/orhanobut/hawk/HawkInternal.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.orhanobut.hawk; - -public class HawkInternal { - - private Storage cryptoStorage; - private Encoder encoder; - private Encryption encryption; - private LogLevel logLevel; - - HawkInternal(HawkBuilder hawkBuilder) { - cryptoStorage = hawkBuilder.getStorage(); - encoder = hawkBuilder.getEncoder(); - encryption = hawkBuilder.getEncryption(); - logLevel = hawkBuilder.getLogLevel(); - } - - Storage getStorage() { - return cryptoStorage; - } - - Encoder getEncoder() { - return encoder; - } - - Encryption getEncryption() { - return encryption; - } - - LogLevel getLogLevel() { - return logLevel; - } - -} diff --git a/hawk/src/main/java/com/orhanobut/hawk/Utils.java b/hawk/src/main/java/com/orhanobut/hawk/HawkUtils.java similarity index 57% rename from hawk/src/main/java/com/orhanobut/hawk/Utils.java rename to hawk/src/main/java/com/orhanobut/hawk/HawkUtils.java index d8a2908..2f05db3 100644 --- a/hawk/src/main/java/com/orhanobut/hawk/Utils.java +++ b/hawk/src/main/java/com/orhanobut/hawk/HawkUtils.java @@ -1,6 +1,6 @@ package com.orhanobut.hawk; -final class Utils { +final class HawkUtils { static boolean hasRxJavaOnClasspath() { try { @@ -12,7 +12,7 @@ static boolean hasRxJavaOnClasspath() { return false; } - private Utils() { + private HawkUtils() { //no instance } @@ -29,4 +29,20 @@ static void validateBuild() { "Please call build() and wait the initialisation finishes."); } } + + public static void checkNull(String message, Object value) { + if (value == null) { + throw new NullPointerException(message + " should not be null"); + } + } + + public static void checkNullOrEmpty(String message, String value) { + if (isEmpty(value)) { + throw new NullPointerException(message + " should not be null or empty"); + } + } + + public static boolean isEmpty(String text) { + return text == null || text.trim().length() == 0; + } } diff --git a/hawk/src/main/java/com/orhanobut/hawk/SharedPreferencesStorage.java b/hawk/src/main/java/com/orhanobut/hawk/SharedPreferencesStorage.java index 21799b0..9092c5e 100644 --- a/hawk/src/main/java/com/orhanobut/hawk/SharedPreferencesStorage.java +++ b/hawk/src/main/java/com/orhanobut/hawk/SharedPreferencesStorage.java @@ -14,7 +14,12 @@ final class SharedPreferencesStorage implements Storage { preferences = context.getSharedPreferences(tag, Context.MODE_PRIVATE); } + SharedPreferencesStorage(SharedPreferences preferences) { + this.preferences = preferences; + } + @Override public boolean put(String key, T value) { + HawkUtils.checkNull("key", key); return getEditor().putString(key, String.valueOf(value)).commit(); } diff --git a/hawk/src/main/java/com/orhanobut/hawk/SqliteStorage.java b/hawk/src/main/java/com/orhanobut/hawk/SqliteStorage.java index d77f5a0..d0fcd30 100644 --- a/hawk/src/main/java/com/orhanobut/hawk/SqliteStorage.java +++ b/hawk/src/main/java/com/orhanobut/hawk/SqliteStorage.java @@ -5,24 +5,28 @@ import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; -import android.text.TextUtils; import android.util.Pair; import java.util.List; class SqliteStorage implements Storage { + private static final String DB_NAME = "Hawk"; + private final SqliteHelper helper; SqliteStorage(Context context) { - if (context == null) { - throw new NullPointerException("Context should not be null"); - } - helper = new SqliteHelper(context); + HawkUtils.checkNull("Context", context); + + helper = new SqliteHelper(context, DB_NAME); + } + + SqliteStorage(SqliteHelper sqliteHelper) { + helper = sqliteHelper; } @Override public boolean put(String key, T value) { - checkKey(key); + HawkUtils.checkNullOrEmpty("key", key); return helper.put(key, String.valueOf(value)); } @@ -32,13 +36,13 @@ class SqliteStorage implements Storage { @SuppressWarnings("unchecked") @Override public T get(String key) { - checkKey(key); + HawkUtils.checkNullOrEmpty("key", key); return (T) helper.get(key); } @SuppressWarnings("SimplifiableIfStatement") @Override public boolean remove(String key) { - if (TextUtils.isEmpty(key)) { + if (HawkUtils.isEmpty(key)) { return true; } return helper.delete(key); @@ -66,22 +70,15 @@ public long count() { return helper.contains(key); } - private void checkKey(String key) { - if (TextUtils.isEmpty(key)) { - throw new NullPointerException("Key cannot be null or empty"); - } - } - - private static class SqliteHelper extends SQLiteOpenHelper { + static class SqliteHelper extends SQLiteOpenHelper { - private static final String DB_NAME = "Hawk"; private static final String TABLE_NAME = "hawk"; private static final String COL_KEY = "hawk_key"; private static final String COL_VALUE = "hawk_value"; private static final int VERSION = 1; - public SqliteHelper(Context context) { - super(context, DB_NAME, null, VERSION); + public SqliteHelper(Context context, String dbName) { + super(context, dbName, null, VERSION); } @Override public void onCreate(SQLiteDatabase db) { @@ -93,7 +90,7 @@ public SqliteHelper(Context context) { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } - public boolean put(String key, String value) { + public synchronized boolean put(String key, String value) { SQLiteDatabase db = this.getWritableDatabase(); db.execSQL("INSERT OR REPLACE INTO " + TABLE_NAME + " (" + COL_KEY + ", " + COL_VALUE + ") " + @@ -102,7 +99,7 @@ public boolean put(String key, String value) { return true; } - public boolean put(List> list) { + public synchronized boolean put(List> list) { SQLiteDatabase db = this.getWritableDatabase(); boolean result = true; try { @@ -123,14 +120,14 @@ public boolean put(List> list) { return result; } - public boolean delete(String key) { + public synchronized boolean delete(String key) { SQLiteDatabase db = this.getWritableDatabase(); int count = db.delete(TABLE_NAME, COL_KEY + "='" + key + "'", null); db.close(); return count != -1; } - public boolean delete(String... keys) { + public synchronized boolean delete(String... keys) { SQLiteDatabase db = this.getWritableDatabase(); boolean result = true; try { @@ -151,11 +148,11 @@ public boolean delete(String... keys) { return result; } - public boolean contains(String key) { + public synchronized boolean contains(String key) { return get(key) != null; } - public String get(String key) { + public synchronized String get(String key) { SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_NAME + " WHERE " + COL_KEY + " = '" + key + "'", null); @@ -172,14 +169,14 @@ public String get(String key) { return value; } - public boolean clearAll() { + public synchronized boolean clearAll() { SQLiteDatabase db = this.getWritableDatabase(); db.execSQL("DELETE FROM " + TABLE_NAME); db.close(); return true; } - public long count() { + public synchronized long count() { SQLiteDatabase db = this.getWritableDatabase(); long count = DatabaseUtils.queryNumEntries(db, TABLE_NAME); db.close(); diff --git a/hawk/src/test/java/com/orhanobut/hawk/Base64EncryptionTest.java b/hawk/src/test/java/com/orhanobut/hawk/Base64EncryptionTest.java new file mode 100644 index 0000000..5b9a0ee --- /dev/null +++ b/hawk/src/test/java/com/orhanobut/hawk/Base64EncryptionTest.java @@ -0,0 +1,68 @@ +package com.orhanobut.hawk; + +import android.util.Base64; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Spy; +import org.robolectric.RobolectricGradleTestRunner; +import org.robolectric.annotation.Config; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +@RunWith(RobolectricGradleTestRunner.class) +@Config(sdk = 21, constants = BuildConfig.class) +public class Base64EncryptionTest { + + @Spy Base64Encryption encryption; + + @Before public void setup() { + encryption = new Base64Encryption(); + + initMocks(this); + } + + @Test public void init() throws Exception { + assertThat(encryption.init()).isTrue(); + } + + @Test public void encrypt() throws Exception { + encryption.encrypt(new byte[2]); + + verify(encryption).encodeBase64(any(byte[].class)); + } + + @Test public void decrypt() throws Exception { + encryption.decrypt("test"); + + verify(encryption).decrypt("test"); + } + + @Test public void reset() throws Exception { + assertThat(encryption.reset()).isTrue(); + } + + @Test public void encodeBase64() { + String text = "hawk"; + String expected = Base64.encodeToString(text.getBytes(), Base64.DEFAULT); + String actual = encryption.encodeBase64(text.getBytes()); + + assertThat(actual).isNotNull(); + assertThat(actual).isEqualTo(expected); + assertThat(encryption.encodeBase64(null)).isNull(); + } + + @Test public void decodeBase64() { + String text = "hawk"; + byte[] expected = Base64.decode(text, Base64.DEFAULT); + byte[] actual = encryption.decodeBase64(text); + + assertThat(actual).isNotNull(); + assertThat(actual).isEqualTo(expected); + assertThat(encryption.decodeBase64(null)).isNull(); + } +} \ No newline at end of file diff --git a/hawk/src/test/java/com/orhanobut/hawk/DataHelperTest.java b/hawk/src/test/java/com/orhanobut/hawk/DataHelperTest.java index 418c32e..55a881a 100644 --- a/hawk/src/test/java/com/orhanobut/hawk/DataHelperTest.java +++ b/hawk/src/test/java/com/orhanobut/hawk/DataHelperTest.java @@ -1,10 +1,8 @@ package com.orhanobut.hawk; -import android.util.Base64; - import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricGradleTestRunner; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import java.util.ArrayList; @@ -18,7 +16,7 @@ import static junit.framework.Assert.fail; import static org.assertj.core.api.Assertions.assertThat; -@RunWith(RobolectricGradleTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(constants = BuildConfig.class, sdk = 18) public class DataHelperTest { @@ -30,23 +28,30 @@ static class Foo { @Test public void testNewVersionCheck() { DataInfo info = DataHelper.getDataInfo("java.lang.String##00V@asdfjasdf"); - assertThat(info.isNewVersion()).isTrue(); + + assertThat(info).isNotNull(); } @Test public void testOldVersionCheck() { - DataInfo info = DataHelper.getDataInfo("java.lang.String##00@asdfjasdf"); - assertThat(info.isNewVersion()).isFalse(); + try { + DataHelper.getDataInfo("java.lang.String##00@asdfjasdf"); + fail("old data is not supported anymore"); + } catch (Exception e) { + assertThat(e).hasMessage("storedText is not valid"); + } } @Test public void addTypeAsObject() { String text = "test"; String actual = DataHelper.addType(CIPHER_TEXT, text); String expected = text.getClass().getName() + "##0V@" + CIPHER_TEXT; + assertThat(actual).isEqualTo(expected); Foo foo = new Foo(); String actualFoo = DataHelper.addType(CIPHER_TEXT, foo); String expectedFoo = foo.getClass().getName() + "##0V@" + CIPHER_TEXT; + assertThat(actualFoo).isEqualTo(expectedFoo); } @@ -55,12 +60,14 @@ static class Foo { list.add("test"); String actual = DataHelper.addType(CIPHER_TEXT, list); String expected = list.get(0).getClass().getName() + "##1V@" + CIPHER_TEXT; + assertThat(actual).isEqualTo(expected); List list2 = new ArrayList<>(); list2.add(new Foo()); String actual2 = DataHelper.addType(CIPHER_TEXT, list2); String expected2 = list2.get(0).getClass().getName() + "##1V@" + CIPHER_TEXT; + assertThat(actual2).isEqualTo(expected2); } @@ -70,6 +77,7 @@ static class Foo { String actual = DataHelper.addType(CIPHER_TEXT, map); String expected = String.class.getName() + "#" + String.class.getName() + "#2V@" + CIPHER_TEXT; + assertThat(actual).isEqualTo(expected); Map map2 = new HashMap<>(); @@ -77,6 +85,7 @@ static class Foo { String actual2 = DataHelper.addType(CIPHER_TEXT, map2); String expected2 = String.class.getName() + "#" + Foo.class.getName() + "#2V@" + CIPHER_TEXT; + assertThat(actual2).isEqualTo(expected2); } @@ -103,12 +112,14 @@ static class Foo { set.add("key"); String actual = DataHelper.addType(CIPHER_TEXT, set); String expected = String.class.getName() + "##3V@" + CIPHER_TEXT; + assertThat(actual).isEqualTo(expected); Set set2 = new HashSet<>(); set2.add(new Foo()); String actual2 = DataHelper.addType(CIPHER_TEXT, set2); String expected2 = Foo.class.getName() + "##3V@" + CIPHER_TEXT; + assertThat(actual2).isEqualTo(expected2); } @@ -117,11 +128,11 @@ static class Foo { String info = "00V"; String cipher = "cipher"; DataInfo dataInfo = DataHelper.getDataInfo(clazz + "#" + clazz + "#" + info + "@" + cipher); + assertThat(dataInfo).isNotNull(); - assertThat(dataInfo.isNewVersion()).isTrue(); - assertThat(dataInfo.getKeyClazz().getName()).isEqualTo(clazz); - assertThat(dataInfo.getValueClazz().getName()).isEqualTo(clazz); - assertThat(dataInfo.getDataType()).isEqualTo(DataType.OBJECT); + assertThat(dataInfo.keyClazz.getName()).isEqualTo(clazz); + assertThat(dataInfo.valueClazz.getName()).isEqualTo(clazz); + assertThat(dataInfo.dataType).isEqualTo(DataType.OBJECT); } @Test public void getDataInfoAsList() { @@ -129,11 +140,11 @@ static class Foo { String info = "1V"; String cipher = "cipher"; DataInfo dataInfo = DataHelper.getDataInfo(clazz + "##" + info + "@" + cipher); + assertThat(dataInfo).isNotNull(); - assertThat(dataInfo.isNewVersion()).isTrue(); - assertThat(dataInfo.getKeyClazz().getName()).isEqualTo(clazz); - assertThat(dataInfo.getValueClazz()).isNull(); - assertThat(dataInfo.getDataType()).isEqualTo(DataType.LIST); + assertThat(dataInfo.keyClazz.getName()).isEqualTo(clazz); + assertThat(dataInfo.valueClazz).isNull(); + assertThat(dataInfo.dataType).isEqualTo(DataType.LIST); } @Test public void getDataInfoAsMap() { @@ -141,11 +152,11 @@ static class Foo { String info = "2V"; String cipher = "cipher"; DataInfo dataInfo = DataHelper.getDataInfo(clazz + "#" + clazz + "#" + info + "@" + cipher); + assertThat(dataInfo).isNotNull(); - assertThat(dataInfo.isNewVersion()).isTrue(); - assertThat(dataInfo.getKeyClazz().getName()).isEqualTo(clazz); - assertThat(dataInfo.getValueClazz().getName()).isEqualTo(clazz); - assertThat(dataInfo.getDataType()).isEqualTo(DataType.MAP); + assertThat(dataInfo.keyClazz.getName()).isEqualTo(clazz); + assertThat(dataInfo.valueClazz.getName()).isEqualTo(clazz); + assertThat(dataInfo.dataType).isEqualTo(DataType.MAP); } @Test public void getDataInfoAsSet() { @@ -153,11 +164,11 @@ static class Foo { String info = "3V"; String cipher = "cipher"; DataInfo dataInfo = DataHelper.getDataInfo(clazz + "##" + info + "@" + cipher); + assertThat(dataInfo).isNotNull(); - assertThat(dataInfo.isNewVersion()).isTrue(); - assertThat(dataInfo.getKeyClazz().getName()).isEqualTo(clazz); - assertThat(dataInfo.getValueClazz()).isNull(); - assertThat(dataInfo.getDataType()).isEqualTo(DataType.SET); + assertThat(dataInfo.keyClazz.getName()).isEqualTo(clazz); + assertThat(dataInfo.valueClazz).isNull(); + assertThat(dataInfo.dataType).isEqualTo(DataType.SET); } @Test public void getDataInfoAsInvalidValues() { @@ -212,40 +223,4 @@ static class Foo { } } - @Test public void getOldDataInfo() { - try { - DataHelper.getOldDataInfo(null, null); - fail(); - } catch (Exception e) { - assertTrue(true); - } - try { - DataHelper.getOldDataInfo("", null); - fail(); - } catch (Exception e) { - assertTrue(true); - } - } - - @Test public void encodeBase64() { - String text = "hawk"; - String expected = Base64.encodeToString(text.getBytes(), Base64.DEFAULT); - String actual = DataHelper.encodeBase64(text.getBytes()); - assertThat(actual).isNotNull(); - assertThat(actual).isEqualTo(expected); - - assertThat(DataHelper.encodeBase64(null)).isNull(); - } - - @Test public void decodeBase64() { - String text = "hawk"; - byte[] expected = Base64.decode(text, Base64.DEFAULT); - byte[] actual = DataHelper.decodeBase64(text); - assertThat(actual).isNotNull(); - assertThat(actual).isEqualTo(expected); - - assertThat(DataHelper.decodeBase64(null)).isNull(); - } - - } diff --git a/hawk/src/test/java/com/orhanobut/hawk/HawkBuilderTest.java b/hawk/src/test/java/com/orhanobut/hawk/HawkBuilderTest.java index 0cc6468..1531d2f 100644 --- a/hawk/src/test/java/com/orhanobut/hawk/HawkBuilderTest.java +++ b/hawk/src/test/java/com/orhanobut/hawk/HawkBuilderTest.java @@ -1,41 +1,38 @@ package com.orhanobut.hawk; -import android.app.Activity; import android.content.Context; import android.text.TextUtils; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.Robolectric; +import org.mockito.Spy; import org.robolectric.RobolectricGradleTestRunner; +import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.lang.reflect.Type; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import static junit.framework.Assert.assertTrue; +import rx.Observable; + +import static java.util.concurrent.TimeUnit.SECONDS; import static junit.framework.Assert.fail; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; @RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class, sdk = 21) public class HawkBuilderTest { - private static final long LATCH_TIMEOUT_IN_SECONDS = 5; - - private HawkBuilder builder; - private Context context; + static final long LATCH_TIMEOUT_IN_SECONDS = 3; - public HawkBuilderTest() { - context = Robolectric.buildActivity(Activity.class).create().get(); - builder = Hawk.init(context); - } + @Spy HawkBuilder builder; + Context context; static class CustomParser implements Parser { private final Gson gson; @@ -58,35 +55,39 @@ public CustomParser(Gson gson) { } @Before public void setup() { + context = RuntimeEnvironment.application; builder = new HawkBuilder(context); - } - @After public void tearDown() { - builder = null; + initMocks(this); } - @Test public void createInstanceWithInvalidValues() { + @Test public void contextShouldNotBeNullOnInit() { try { new HawkBuilder(null); - fail(); + fail("Context should not be null"); } catch (Exception e) { assertThat(e).hasMessage("Context should not be null"); } } @Test public void testDefaultEncryptionMode() { - assertThat(builder.getEncryptionMethod()).isEqualTo(HawkBuilder.EncryptionMethod.MEDIUM); + assertThat(builder.getEncryptionMethod()) + .isEqualTo(HawkBuilder.EncryptionMethod.MEDIUM); } - @Test public void testNoEncrpytionMode() { - builder.setEncryptionMethod(HawkBuilder.EncryptionMethod.NO_ENCRYPTION).build(); + @Test public void testNoEncryptionMode() { + builder.setEncryptionMethod(HawkBuilder.EncryptionMethod.NO_ENCRYPTION) + .build(); + assertThat(builder.getEncryptionMethod()) .isEqualTo(HawkBuilder.EncryptionMethod.NO_ENCRYPTION); } - @Test public void testHighestEncryptionModeWithoutPassword() { + @Test public void highestEncryptionModeShouldHavePassword() { try { - builder.setEncryptionMethod(HawkBuilder.EncryptionMethod.HIGHEST).build(); + builder.setEncryptionMethod(HawkBuilder.EncryptionMethod.HIGHEST) + .build(); + fail(); } catch (Exception e) { assertThat(e).hasMessage("Password cannot be null " + @@ -94,11 +95,13 @@ public CustomParser(Gson gson) { } } - @Test public void testHighestEncryptionMethodWithPasword() { + @Test public void testHighestEncryptionMethod() { builder.setEncryptionMethod(HawkBuilder.EncryptionMethod.HIGHEST) - .setPassword("test"); - assertThat(builder.getEncryptionMethod()).isEqualTo( - HawkBuilder.EncryptionMethod.HIGHEST); + .setPassword("password") + .build(); + + assertThat(builder.getEncryptionMethod()) + .isEqualTo(HawkBuilder.EncryptionMethod.HIGHEST); } @Test public void testPassword() { @@ -116,31 +119,38 @@ public CustomParser(Gson gson) { } builder.setPassword("password"); + assertThat(builder.getPassword()).isEqualTo("password"); } @Test public void testDefaultLogLevel() { builder.build(); + assertThat(builder.getLogLevel()).isEqualTo(LogLevel.NONE); } @Test public void testCustomLogLevel() { builder.setLogLevel(LogLevel.FULL).build(); + assertThat(builder.getLogLevel()).isEqualTo(LogLevel.FULL); } @Test public void testDefaultStorage() { builder.build(); + assertThat(builder.getStorage()).isInstanceOf(SharedPreferencesStorage.class); } @Test public void testCustomStorage() { - builder.setStorage(HawkBuilder.newSqliteStorage(context)).build(); + builder.setStorage(HawkBuilder.newSqliteStorage(context)) + .build(); + assertThat(builder.getStorage()).isInstanceOf(SqliteStorage.class); } @Test public void testDefaultParser() { builder.build(); + assertThat(builder.getParser()).isInstanceOf(GsonParser.class); } @@ -148,40 +158,43 @@ public CustomParser(Gson gson) { CustomParser parser = new CustomParser(new Gson()); builder.setParser(parser) .build(); + assertThat(builder.getParser()).isInstanceOf(CustomParser.class); } @Test public void testDefaultEncoded() { builder.build(); + assertThat(builder.getEncoder()).isInstanceOf(HawkEncoder.class); } - @Test public void testDefaultEncryption() { + @Test public void testBuild() { builder.build(); - try { - assertThat(builder.getEncryption()).isInstanceOf(AesEncryption.class); - } catch (AssertionError e) { - assertThat(builder.getEncryptionMethod()).isEqualTo(HawkBuilder.EncryptionMethod.MEDIUM); - assertThat(builder.getEncryption()).isInstanceOf(Base64Encryption.class); - } + + verify(builder).startBuild(); } - @Test public void initWithCallback() throws InterruptedException { + @Test public void testBuildWithCallback() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); HawkBuilder.Callback callback = new HawkBuilder.Callback() { @Override public void onSuccess() { - assertTrue(true); latch.countDown(); } @Override public void onFail(Exception e) { - assertTrue(true); latch.countDown(); } }; - builder.setCallback(callback).build(); - assertThat(latch.await(LATCH_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)).isTrue(); + builder.build(callback); + + assertThat(latch.await(LATCH_TIMEOUT_IN_SECONDS, SECONDS)).isTrue(); + } + + @Test public void testRxBuild() { + Observable observable = builder.buildRx(); + + assertThat(observable).isNotNull(); } } diff --git a/hawk/src/test/java/com/orhanobut/hawk/HawkEncoderTest.java b/hawk/src/test/java/com/orhanobut/hawk/HawkEncoderTest.java index 4c82f76..bb65795 100644 --- a/hawk/src/test/java/com/orhanobut/hawk/HawkEncoderTest.java +++ b/hawk/src/test/java/com/orhanobut/hawk/HawkEncoderTest.java @@ -2,6 +2,7 @@ import com.google.gson.Gson; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricGradleTestRunner; @@ -21,18 +22,18 @@ @Config(constants = BuildConfig.class, sdk = 18) public class HawkEncoderTest { - private final Encoder encoder; - private final Parser parser; - - public HawkEncoderTest() { - parser = new GsonParser(new Gson()); - encoder = new HawkEncoder(parser); - } + Encoder encoder; + Parser parser; static class Foo { String name = "hawk"; } + @Before public void setup() { + parser = new GsonParser(new Gson()); + encoder = new HawkEncoder(parser); + } + @Test public void createInstanceWithInvalidValues() { try { new HawkEncoder(null); diff --git a/hawk/src/test/java/com/orhanobut/hawk/HawkEncryptionHighestTest.java b/hawk/src/test/java/com/orhanobut/hawk/HawkEncryptionHighestTest.java deleted file mode 100644 index c2258d1..0000000 --- a/hawk/src/test/java/com/orhanobut/hawk/HawkEncryptionHighestTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.orhanobut.hawk; - -public class HawkEncryptionHighestTest extends HawkTest { - - @Override public void init() { - Hawk.init(context) - .setEncryptionMethod(HawkBuilder.EncryptionMethod.HIGHEST) - .setPassword("password") - .build(); - - } -} diff --git a/hawk/src/test/java/com/orhanobut/hawk/HawkEncryptionMediumTest.java b/hawk/src/test/java/com/orhanobut/hawk/HawkEncryptionMediumTest.java deleted file mode 100644 index 0dd5d9c..0000000 --- a/hawk/src/test/java/com/orhanobut/hawk/HawkEncryptionMediumTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.orhanobut.hawk; - -public class HawkEncryptionMediumTest extends HawkTest { - - @Override public void init() { - Hawk.init(context) - .setEncryptionMethod(HawkBuilder.EncryptionMethod.MEDIUM) - .build(); - } -} diff --git a/hawk/src/test/java/com/orhanobut/hawk/HawkIntegrationTest.java b/hawk/src/test/java/com/orhanobut/hawk/HawkIntegrationTest.java new file mode 100644 index 0000000..53329e7 --- /dev/null +++ b/hawk/src/test/java/com/orhanobut/hawk/HawkIntegrationTest.java @@ -0,0 +1,360 @@ +package com.orhanobut.hawk; + +import android.content.Context; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricGradleTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import rx.Observable; +import rx.Observer; +import rx.Subscriber; +import rx.functions.Func1; +import rx.schedulers.Schedulers; + +import static junit.framework.Assert.fail; +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(RobolectricGradleTestRunner.class) +@Config(constants = BuildConfig.class, sdk = 21) +public class HawkIntegrationTest { + + static final String KEY = "TAG"; + static final long LATCH_TIMEOUT_IN_SECONDS = 3; + + Context context; + + @Before public void setUp() { + context = RuntimeEnvironment.application; + Hawk.init(context).build(); + } + + @After public void tearDown() { + if (Hawk.isBuilt()) { + Hawk.clear(); + } + Hawk.destroy(); + } + + @Test public void testSingleItem() { + Hawk.put("boolean", true); + assertThat(Hawk.get("boolean")).isEqualTo(true); + + Hawk.put("string", "string"); + assertThat(Hawk.get("string")).isEqualTo("string"); + + Hawk.put("float", 1.5f); + assertThat(Hawk.get("float")).isEqualTo(1.5f); + + Hawk.put("integer", 10); + assertThat(Hawk.get("integer")).isEqualTo(10); + + Hawk.put("char", 'A'); + assertThat(Hawk.get("char")).isEqualTo('A'); + + Hawk.put("object", new FooBar()); + FooBar fooBar = Hawk.get("object"); + + assertThat(fooBar).isNotNull(); + assertThat(fooBar.name).isEqualTo("hawk"); + + assertThat(Hawk.put("innerClass", new FooBar.InnerFoo())).isTrue(); + FooBar.InnerFoo innerFoo = Hawk.get("innerClass"); + assertThat(innerFoo).isNotNull(); + assertThat(innerFoo.name).isEqualTo("hawk"); + } + + @Test public void testSingleItemDefault() { + boolean result = Hawk.get("tag", true); + assertThat(result).isEqualTo(true); + } + + @Test public void testList() { + List list = new ArrayList<>(); + list.add("foo"); + list.add("bar"); + + Hawk.put("tag", list); + + List list1 = Hawk.get("tag"); + + assertThat(list1).isNotNull(); + assertThat(list1.get(0)).isEqualTo("foo"); + assertThat(list1.get(1)).isEqualTo("bar"); + } + + @Test public void testEmptyList() { + List list = new ArrayList<>(); + Hawk.put("tag", list); + + List list1 = Hawk.get("tag"); + + assertThat(list1).isNotNull(); + } + + @Test public void testMap() { + Map map = new HashMap<>(); + map.put("key", "value"); + Hawk.put("map", map); + + Map map1 = Hawk.get("map"); + + assertThat(map1).isNotNull(); + assertThat(map1.get("key")).isEqualTo("value"); + } + + @Test public void testEmptyMap() { + Map map = new HashMap<>(); + Hawk.put("tag", map); + + Map map1 = Hawk.get("tag"); + + assertThat(map1).isNotNull(); + } + + @Test public void testSet() { + Set set = new HashSet<>(); + set.add("foo"); + Hawk.put("set", set); + + Set set1 = Hawk.get("set"); + + assertThat(set1).isNotNull(); + assertThat(set1.contains("foo")).isTrue(); + } + + @Test public void testEmptySet() { + Set set = new HashSet<>(); + Hawk.put("tag", set); + + Set set1 = Hawk.get("tag"); + + assertThat(set1).isNotNull(); + } + + @Test public void testCount() { + Hawk.clear(); + String value = "test"; + Hawk.put("tag", value); + Hawk.put("tag1", value); + Hawk.put("tag2", value); + Hawk.put("tag3", value); + Hawk.put("tag4", value); + + assertThat(Hawk.count()).isEqualTo(5); + } + + @Test public void testClear() { + String value = "test"; + Hawk.put("tag", value); + Hawk.put("tag1", value); + Hawk.put("tag2", value); + + Hawk.clear(); + + assertThat(Hawk.count()).isEqualTo(0); + } + + @Test public void testRemove() { + Hawk.clear(); + String value = "test"; + Hawk.put("tag", value); + Hawk.put("tag1", value); + Hawk.put("tag2", value); + + Hawk.remove("tag"); + + String result = Hawk.get("tag"); + + assertThat(result).isNull(); + assertThat(Hawk.count()).isEqualTo(2); + } + + @Test public void testBulkRemoval() { + Hawk.clear(); + Hawk.put("tag", "test"); + Hawk.put("tag1", 1); + Hawk.put("tag2", Boolean.FALSE); + + Hawk.remove("tag", "tag1"); + + String result = Hawk.get("tag"); + + assertThat(result).isNull(); + assertThat(Hawk.count()).isEqualTo(1); + } + + @Test public void testContains() { + String value = "test"; + String key = "tag"; + Hawk.put(key, value); + + assertThat(Hawk.contains(key)).isTrue(); + + Hawk.remove(key); + + assertThat(Hawk.contains(key)).isFalse(); + } + + @Test public void testChain() { + Hawk.chain() + .put("tag", 1) + .put("tag1", "yes") + .put("tag2", Boolean.FALSE) + .commit(); + + assertThat(Hawk.get("tag")).isEqualTo(1); + assertThat(Hawk.get("tag1")).isEqualTo("yes"); + assertThat(Hawk.get("tag2")).isEqualTo(false); + } + + @Test public void testChainWithCapacity() { + Hawk.chain(10) + .put("tag", 1) + .put("tag1", "yes") + .put("tag2", Boolean.FALSE) + .commit(); + + assertThat(Hawk.get("tag")).isEqualTo(1); + assertThat(Hawk.get("tag1")).isEqualTo("yes"); + assertThat(Hawk.get("tag2")).isEqualTo(false); + } + + @Test public void testChainWithLists() { + List items = new ArrayList<>(); + items.add("fst"); + items.add("snd"); + items.add("trd"); + + Hawk.chain() + .put("tag", 1) + .put("tag1", "yes") + .put("tag2", Boolean.FALSE) + .put("lst", items) + .commit(); + + assertThat(Hawk.get("tag")).isEqualTo(1); + assertThat(Hawk.get("tag1")).isEqualTo("yes"); + assertThat(Hawk.get("tag2")).isEqualTo(false); + + List stored = Hawk.get("lst"); + + assertThat(stored).isNotNull(); + assertThat(stored.isEmpty()).isFalse(); + + for (int i = 0, s = stored.size(); i < s; i++) { + assertThat(stored.get(i)).isEqualTo(items.get(i)); + } + } + + @Test public void testHugeData() { + for (int i = 0; i < 100; i++) { + Hawk.put("" + i, "" + i); + } + assertThat(true).isTrue(); + } + + @Test public void testHugeDataWithBulk() { + Hawk.Chain chain = Hawk.chain(); + for (int i = 0; i < 10000; i++) { + chain.put("" + i, "" + i); + } + chain.commit(); + assertThat(true).isTrue(); + } + + @Test public void resetCrypto() { + assertThat(Hawk.resetCrypto()).isTrue(); + } + + @Test public void getRxString() throws Exception { + Hawk.put(KEY, "hawk"); + + final CountDownLatch latch = new CountDownLatch(1); + Hawk.getObservable(KEY) + .observeOn(Schedulers.io()) + .subscribe(new Subscriber() { + @Override public void onCompleted() { + latch.countDown(); + } + + @Override public void onError(Throwable e) { + fail(); + latch.countDown(); + } + + @Override public void onNext(String s) { + assertThat(s).isEqualTo("hawk"); + } + }); + + assertThat(latch.await(LATCH_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)).isTrue(); + } + + @Test public void getRxStringDefaultValue() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + Hawk.getObservable(KEY, "test") + .observeOn(Schedulers.io()) + .subscribe(new Subscriber() { + @Override public void onCompleted() { + latch.countDown(); + } + + @Override public void onError(Throwable e) { + fail(); + latch.countDown(); + } + + @Override public void onNext(String s) { + assertThat(s).isEqualTo("test"); + } + }); + + assertThat(latch.await(LATCH_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)).isTrue(); + } + + @Test public void testBuildRx() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + Hawk.init(context) + .buildRx() + .concatMap(new Func1>() { + @Override public Observable call(Boolean aBoolean) { + return Hawk.putObservable(KEY, "hawk"); + } + }) + .concatMap(new Func1>() { + @Override public Observable call(Boolean aBoolean) { + return Hawk.getObservable(KEY); + } + }) + .subscribe(new Observer() { + @Override public void onCompleted() { + latch.countDown(); + } + + @Override public void onError(Throwable throwable) { + fail(); + latch.countDown(); + } + + @Override public void onNext(String storedValue) { + assertThat(storedValue).isEqualTo("hawk"); + } + }); + + assertThat(latch.await(LATCH_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)).isTrue(); + } +} diff --git a/hawk/src/test/java/com/orhanobut/hawk/HawkNoEncryptionTest.java b/hawk/src/test/java/com/orhanobut/hawk/HawkNoEncryptionTest.java deleted file mode 100644 index 67bf0b2..0000000 --- a/hawk/src/test/java/com/orhanobut/hawk/HawkNoEncryptionTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.orhanobut.hawk; - -public class HawkNoEncryptionTest extends HawkTest { - - @Override public void init() { - Hawk.init(context) - .setEncryptionMethod(HawkBuilder.EncryptionMethod.NO_ENCRYPTION) - .build(); - } -} diff --git a/hawk/src/test/java/com/orhanobut/hawk/HawkSharedPrefsTest.java b/hawk/src/test/java/com/orhanobut/hawk/HawkSharedPrefsTest.java deleted file mode 100644 index 1351ac7..0000000 --- a/hawk/src/test/java/com/orhanobut/hawk/HawkSharedPrefsTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.orhanobut.hawk; - -public class HawkSharedPrefsTest extends HawkTest { - - @Override public void init() { - Hawk.init(context) - .setStorage(HawkBuilder.newSharedPrefStorage(context)) - .build(); - } -} diff --git a/hawk/src/test/java/com/orhanobut/hawk/HawkSqliteTest.java b/hawk/src/test/java/com/orhanobut/hawk/HawkSqliteTest.java deleted file mode 100644 index 25ec95c..0000000 --- a/hawk/src/test/java/com/orhanobut/hawk/HawkSqliteTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.orhanobut.hawk; - -public class HawkSqliteTest extends HawkTest { - - @Override public void init() { - Hawk.init(context) - .setStorage(HawkBuilder.newSqliteStorage(context)) - .build(); - } -} diff --git a/hawk/src/test/java/com/orhanobut/hawk/HawkTest.java b/hawk/src/test/java/com/orhanobut/hawk/HawkTest.java index 226af4f..02e0128 100644 --- a/hawk/src/test/java/com/orhanobut/hawk/HawkTest.java +++ b/hawk/src/test/java/com/orhanobut/hawk/HawkTest.java @@ -1,515 +1,373 @@ package com.orhanobut.hawk; -import android.app.Activity; import android.content.Context; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.Robolectric; +import org.mockito.InOrder; +import org.mockito.Mock; import org.robolectric.RobolectricGradleTestRunner; +import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import rx.Observable; -import rx.Observer; -import rx.Subscriber; -import rx.functions.Func1; -import rx.schedulers.Schedulers; - import static junit.framework.Assert.fail; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyList; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; -/** - * @author Orhan Obut - */ @RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class, sdk = 21) public class HawkTest { - private static final String KEY = "TAG"; - private static final long LATCH_TIMEOUT_IN_SECONDS = 5; + final String key = "key"; + final String value = "foo"; + final String cipherText = "123345"; + final String withType = "java.lang.String##0V@123345"; - protected final Context context; + Context context; - public HawkTest() { - context = Robolectric.buildActivity(Activity.class).create().get(); - } + @Mock Encoder encoder; + @Mock Storage storage; + @Mock Encryption encryption; @Before public void setUp() { - init(); - } + context = RuntimeEnvironment.application; - public void init() { - Hawk.init(context).build(); + initMocks(this); + + Hawk.build( + new HawkBuilder(context) + .setEncoder(encoder) + .setStorage(storage) + .setEncryption(encryption) + ); } @After public void tearDown() { - if (Hawk.isBuilt()) { - Hawk.clear(); - } + Hawk.destroy(); } - @Test public void initWithInvalidValues() { + //region INIT + @Test public void initRequiresContext() { try { Hawk.init(null); - fail(); + fail("context should not be null"); } catch (Exception e) { assertThat(e).hasMessage("Context should not be null"); } } - @Test public void testSingleItem() { - Hawk.put("boolean", true); - assertThat(Hawk.get("boolean")).isEqualTo(true); + @Test public void returnHawkBuilderOnInitAndDestroyHawkInternal() { + HawkBuilder builder = Hawk.init(context); - Hawk.put("string", "string"); - assertThat(Hawk.get("string")).isEqualTo("string"); + assertThat(builder).isNotNull(); + assertThat(Hawk.HAWK).isNull(); + } - Hawk.put("float", 1.5f); - assertThat(Hawk.get("float")).isEqualTo(1.5f); + @Test public void testIsBuilt() { + assertThat(Hawk.isBuilt()).isTrue(); + } + //endregion - Hawk.put("integer", 10); - assertThat(Hawk.get("integer")).isEqualTo(10); + //region OTHERS + @Test public void testDestroy() { + Hawk.destroy(); - Hawk.put("char", 'A'); - assertThat(Hawk.get("char")).isEqualTo('A'); + assertThat(Hawk.HAWK).isNull(); + } - Hawk.put("object", new FooBar()); - FooBar fooBar = Hawk.get("object"); + @Test public void testResetCrypto() { + when(encryption.reset()).thenReturn(true); - assertThat(fooBar).isNotNull(); - assertThat(fooBar.name).isEqualTo("hawk"); + assertThat(Hawk.resetCrypto()).isTrue(); - assertThat(Hawk.put("innerClass", new FooBar.InnerFoo())).isTrue(); - FooBar.InnerFoo innerFoo = Hawk.get("innerClass"); - assertThat(innerFoo).isNotNull(); - assertThat(innerFoo.name).isEqualTo("hawk"); + verify(encryption).reset(); + verifyZeroInteractions(storage, encoder); } + //endregion - @Test public void testSingleItemDefault() { - boolean result = Hawk.get("tag", true); - assertThat(result).isEqualTo(true); - } + //region PUT + @Test public void testPut() { + when(encoder.encode(value)).thenReturn(value.getBytes()); + when(encryption.encrypt(value.getBytes())).thenReturn(cipherText); + when(storage.put(key, withType)).thenReturn(true); - @Test public void testList() { - List list = new ArrayList<>(); - list.add("foo"); - list.add("bar"); + assertThat(Hawk.put(key, value)).isTrue(); - Hawk.put("tag", list); + InOrder inOrder = inOrder(storage, encoder, encryption); + inOrder.verify(encoder).encode(value); + inOrder.verify(encryption).encrypt(any(byte[].class)); + inOrder.verify(storage).put(key, withType); + } - List list1 = Hawk.get("tag"); + @Test public void testNullKeyOnPut() { + try { + Hawk.put(null, "foo"); + fail("Key should not be null"); + } catch (Exception e) { + assertThat(e).hasMessage("Key should not be null"); + } + } - assertThat(list1).isNotNull(); - assertThat(list1.get(0)).isEqualTo("foo"); - assertThat(list1.get(1)).isEqualTo("bar"); + @Test public void validateBuildOnPut() { + try { + Hawk.destroy(); + Hawk.init(context); + Hawk.put(key, value); + fail("build is not complete"); + } catch (Exception e) { + } } - @Test public void testEmptyList() { - List list = new ArrayList<>(); - Hawk.put("tag", list); + @Test public void removeWhenValueIsNullOnPut() { + when(storage.remove(key)).thenReturn(true); - List list1 = Hawk.get("tag"); + assertThat(Hawk.put(key, null)).isTrue(); - assertThat(list1).isNotNull(); + verify(storage).remove(key); } - @Test public void testMap() { - Map map = new HashMap<>(); - map.put("key", "value"); - Hawk.put("map", map); + @Test public void returnFalseAndNotAddToStorageWhenEncryptionFailsOnPut() { + when(encoder.encode(value)).thenReturn(value.getBytes()); + when(encryption.encrypt(value.getBytes())).thenReturn(null); - Map map1 = Hawk.get("map"); + assertThat(Hawk.put(key, value)).isFalse(); - assertThat(map1).isNotNull(); - assertThat(map1.get("key")).isEqualTo("value"); + InOrder inOrder = inOrder(storage, encoder, encryption); + inOrder.verify(encoder).encode(value); + inOrder.verify(encryption).encrypt(any(byte[].class)); + verifyZeroInteractions(storage); } - @Test public void testEmptyMap() { - Map map = new HashMap<>(); - Hawk.put("tag", map); + @Test public void returnFalseAndNotAddToStorageWhenEncodingFailsOnPut() { + when(encoder.encode(value)).thenReturn(null); - Map map1 = Hawk.get("tag"); + assertThat(Hawk.put(key, value)).isFalse(); - assertThat(map1).isNotNull(); + verify(encoder).encode(value); + verifyZeroInteractions(storage, encryption); } - @Test public void testSet() { - Set set = new HashSet<>(); - set.add("foo"); - Hawk.put("set", set); + @Test public void testObservablePut() { + assertThat(Hawk.putObservable(key, value)).isNotNull(); + } + //endregion - Set set1 = Hawk.get("set"); + //region GET - assertThat(set1).isNotNull(); - assertThat(set1.contains("foo")).isTrue(); - } + @Test public void returnValueOnGet() throws Exception { + when(storage.get(key)).thenReturn(withType); + when(encryption.decrypt(cipherText)).thenReturn(value.getBytes()); - @Test public void testEmptySet() { - Set set = new HashSet<>(); - Hawk.put("tag", set); + Hawk.get(key); - Set set1 = Hawk.get("tag"); + InOrder inOrder = inOrder(storage, encoder, encryption); + inOrder.verify(storage).get(key); + inOrder.verify(encryption).decrypt(cipherText); + inOrder.verify(encoder).decode(eq(value.getBytes()), any(DataInfo.class)); + } - assertThat(set1).isNotNull(); + @Test public void returnDefaultValueOnGetWithDefault() throws Exception { + assertThat(Hawk.get(key, "default")).isEqualTo("default"); + + verify(storage).get(key); + verifyZeroInteractions(encoder, encryption); } - @Test public void testNullKeyPut() { - try { - Hawk.put(null, "test"); - fail(); - } catch (Exception e) { - assertThat(e).hasMessage("Key cannot be null"); - } + @Test public void returnValueOnGetWithDefault() throws Exception { + when(storage.get(key)).thenReturn(withType); + when(encryption.decrypt(cipherText)).thenReturn(value.getBytes()); + when(encoder.decode(eq(value.getBytes()), any(DataInfo.class))).thenReturn(value); + + assertThat(Hawk.get(key, "default")).isEqualTo(value); + + verify(storage).get(key); + verify(encoder).decode(any(byte[].class), any(DataInfo.class)); + verify(encryption).decrypt(cipherText); } - @Test public void testNullKeyGet() { + @Test public void keyShouldBeValidOnGet() { try { Hawk.get(null); - fail(); + fail("Key should not be null"); } catch (Exception e) { - assertThat(e).hasMessage("Key cannot be null"); + assertThat(e).hasMessage("Key should not be null"); } } - @Test public void testNullValuePut() { + @Test public void validateBuildOnGet() { try { - Hawk.put("tag", "something"); - assertThat(Hawk.get("tag")).isNotNull(); + Hawk.destroy(); - assertThat(Hawk.put("tag", null)).isTrue(); - assertThat(Hawk.get("tag")).isNull(); + Hawk.init(context); + Hawk.get(key); + fail("should throw exception"); } catch (Exception e) { - fail(); } } - @Test public void testCount() { - Hawk.clear(); - String value = "test"; - Hawk.put("tag", value); - Hawk.put("tag1", value); - Hawk.put("tag2", value); - Hawk.put("tag3", value); - Hawk.put("tag4", value); - - assertThat(Hawk.count()).isEqualTo(5); - } - - @Test public void testClear() { - String value = "test"; - Hawk.put("tag", value); - Hawk.put("tag1", value); - Hawk.put("tag2", value); + @Test public void returnNullIfKeyIsNotInStorageOnGet() { + when(storage.get(key)).thenReturn(null); - Hawk.clear(); + assertThat(Hawk.get(key)).isNull(); - assertThat(Hawk.count()).isEqualTo(0); + verify(storage).get(key); + verifyZeroInteractions(encoder, encryption); } - @Test public void testRemove() { - Hawk.clear(); - String value = "test"; - Hawk.put("tag", value); - Hawk.put("tag1", value); - Hawk.put("tag2", value); - - Hawk.remove("tag"); + @Test public void throwExceptionIfDataIsCorruptedOnGet() { + when(storage.get(key)).thenReturn("234234"); - String result = Hawk.get("tag"); + try { + Hawk.get(key); + fail("Text should contain delimiter"); + } catch (Exception e) { + } - assertThat(result).isNull(); - assertThat(Hawk.count()).isEqualTo(2); + verify(storage).get(key); + verifyZeroInteractions(encoder, encryption); } - @Test public void testBulkRemoval() { - Hawk.clear(); - Hawk.put("tag", "test"); - Hawk.put("tag1", 1); - Hawk.put("tag2", Boolean.FALSE); + @Test public void returnNullIfEncryptionFailsOnGet() { + when(storage.get(key)).thenReturn(withType); - Hawk.remove("tag", "tag1"); + assertThat(Hawk.get(key)).isNull(); - String result = Hawk.get("tag"); + verify(storage).get(key); + verify(encryption).decrypt(cipherText); - assertThat(result).isNull(); - assertThat(Hawk.count()).isEqualTo(1); + verifyZeroInteractions(encoder); } - @Test public void testContains() { - String value = "test"; - String key = "tag"; - Hawk.put(key, value); - - assertThat(Hawk.contains(key)).isTrue(); - - Hawk.remove(key); - - assertThat(Hawk.contains(key)).isFalse(); - } + @Test public void returnNullIfEncodingFailsOnGet() throws Exception { + when(storage.get(key)).thenReturn(withType); + when(encryption.decrypt(cipherText)).thenReturn(value.getBytes()); - @Test public void testChain() { - Hawk.chain() - .put("tag", 1) - .put("tag1", "yes") - .put("tag2", Boolean.FALSE) - .commit(); + assertThat(Hawk.get(key)).isNull(); - assertThat(Hawk.get("tag")).isEqualTo(1); - assertThat(Hawk.get("tag1")).isEqualTo("yes"); - assertThat(Hawk.get("tag2")).isEqualTo(false); + verify(storage).get(key); + verify(encryption).decrypt(cipherText); + verify(encoder).decode(eq(value.getBytes()), any(DataInfo.class)); } - @Test public void testChainWithCapacity() { - Hawk.chain(10) - .put("tag", 1) - .put("tag1", "yes") - .put("tag2", Boolean.FALSE) - .commit(); - - assertThat(Hawk.get("tag")).isEqualTo(1); - assertThat(Hawk.get("tag1")).isEqualTo("yes"); - assertThat(Hawk.get("tag2")).isEqualTo(false); + @Test public void testGetObservable() { + assertThat(Hawk.getObservable(key)).isNotNull(); } - @Test public void testChainWithLists() { - List items = new ArrayList<>(); - items.add("fst"); - items.add("snd"); - items.add("trd"); - - Hawk.chain() - .put("tag", 1) - .put("tag1", "yes") - .put("tag2", Boolean.FALSE) - .put("lst", items) - .commit(); + //endregion - assertThat(Hawk.get("tag")).isEqualTo(1); - assertThat(Hawk.get("tag1")).isEqualTo("yes"); - assertThat(Hawk.get("tag2")).isEqualTo(false); - - List stored = Hawk.get("lst"); + //region REMOVE + @Test public void testRemove() { + when(storage.remove(key)).thenReturn(true); - assertThat(stored).isNotNull(); - assertThat(stored.isEmpty()).isFalse(); + assertThat(Hawk.remove(key)).isTrue(); - for (int i = 0, s = stored.size(); i < s; i++) { - assertThat(stored.get(i)).isEqualTo(items.get(i)); - } + verify(storage).remove(key); + verifyZeroInteractions(encoder, encryption); } - @Test public void testHugeData() { - for (int i = 0; i < 100; i++) { - Hawk.put("" + i, "" + i); - } - assertThat(true).isTrue(); + @Test public void testRemoveMultiple() { + //TODO } - @Test public void testHugeDataWithBulk() { - Hawk.Chain chain = Hawk.chain(); - for (int i = 0; i < 10000; i++) { - chain.put("" + i, "" + i); + @Test public void validateBuildOnRemove() { + try { + Hawk.destroy(); + Hawk.init(context); + Hawk.remove(key); + fail(""); + } catch (Exception e) { } - chain.commit(); - assertThat(true).isTrue(); } + //endregion - @Test public void testLogLevel() { - Hawk.init(context) - .setLogLevel(LogLevel.NONE) - .build(); - - assertThat(Hawk.getLogLevel()).isEqualTo(LogLevel.NONE); - - Hawk.init(context) - .setLogLevel(LogLevel.FULL) - .build(); - - assertThat(Hawk.getLogLevel()).isEqualTo(LogLevel.FULL); - } + //region COUNT + @Test public void testCount() { + when(storage.count()).thenReturn(10L); - @Test public void resetCrypto() { - assertThat(Hawk.resetCrypto()).isTrue(); - } + assertThat(Hawk.count()).isEqualTo(10); - @Test public void getRxString() throws Exception { - Hawk.put(KEY, "hawk"); - - final CountDownLatch latch = new CountDownLatch(1); - Hawk.getObservable(KEY) - .observeOn(Schedulers.io()) - .subscribe(new Subscriber() { - @Override public void onCompleted() { - latch.countDown(); - } - - @Override public void onError(Throwable e) { - fail(); - latch.countDown(); - } - - @Override public void onNext(String s) { - assertThat(s).isEqualTo("hawk"); - } - }); - - assertThat(latch.await(LATCH_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)).isTrue(); - } - - @Test public void getRxStringDefaultValue() throws Exception { - final CountDownLatch latch = new CountDownLatch(1); - Hawk.getObservable(KEY, "test") - .observeOn(Schedulers.io()) - .subscribe(new Subscriber() { - @Override public void onCompleted() { - latch.countDown(); - } - - @Override public void onError(Throwable e) { - fail(); - latch.countDown(); - } - - @Override public void onNext(String s) { - assertThat(s).isEqualTo("test"); - } - }); - - assertThat(latch.await(LATCH_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)).isTrue(); - } - - @Test public void testBuildRx() throws InterruptedException { - final CountDownLatch latch = new CountDownLatch(1); - Hawk.init(context) - .buildRx() - .observeOn(Schedulers.io()) - .concatMap(new Func1>() { - @Override public Observable call(Boolean aBoolean) { - return Hawk.putObservable(KEY, "hawk"); - } - }) - .concatMap(new Func1>() { - @Override public Observable call(Boolean aBoolean) { - return Hawk.getObservable(KEY); - } - }) - .subscribe(new Observer() { - @Override public void onCompleted() { - latch.countDown(); - } - - @Override public void onError(Throwable throwable) { - fail(); - latch.countDown(); - } - - @Override public void onNext(String storedValue) { - assertThat(storedValue).isEqualTo("hawk"); - } - }); - - assertThat(latch.await(LATCH_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)).isTrue(); - } - - @Test public void statusNotBuiltBeforeBuild() { - Hawk.init(context); - assertThat(Hawk.isBuilt()).isFalse(); - } - - @Test public void statusBuiltAfterBuild() { - Hawk.init(context).build(); - assertThat(Hawk.isBuilt()).isTrue(); + verify(storage).count(); + verifyZeroInteractions(encoder, encryption); } - @Test public void testGetThrowsExceptionWhenNotBuilt() { - Hawk.init(context); + @Test public void validateBuildOnCount() { try { - Hawk.get(KEY); - fail("Did not throw an exception"); - } catch (IllegalStateException ignored) { + Hawk.destroy(); + Hawk.init(context); + Hawk.count(); + fail(""); + } catch (Exception e) { } } + //endregion - @Test public void testPutThrowsExceptionWhenNotBuilt() { - Hawk.init(context); - try { - Hawk.put(KEY, "value"); - fail("Did not throw an exception"); - } catch (IllegalStateException ignored) { - } + //region CLEAR + @Test public void testClear() { + when(storage.clear()).thenReturn(true); + + assertThat(Hawk.clear()).isTrue(); + + verify(storage).clear(); + verifyZeroInteractions(encoder, encryption); } - @Test public void testClearThrowsExceptionWhenNotBuilt() { - Hawk.init(context); + @Test public void validateBuildOnClear() { try { + Hawk.destroy(); + Hawk.init(context); Hawk.clear(); - fail("Did not throw an exception"); - } catch (IllegalStateException ignored) { + fail(""); + } catch (Exception e) { } } + //endregion - @Test public void testContainsThrowsExceptionWhenNotBuilt() { - Hawk.init(context); - try { - Hawk.contains(KEY); - fail("Did not throw an exception"); - } catch (IllegalStateException ignored) { - } - } + //region CONTAINS + @Test public void testContains() { + when(storage.contains(key)).thenReturn(true); - @Test public void testRemoveThrowsExceptionWhenNotBuilt() { - Hawk.init(context); - try { - Hawk.remove(KEY); - fail("Did not throw an exception"); - } catch (IllegalStateException ignored) { - } - } + assertThat(Hawk.contains(key)).isTrue(); - @Test public void testRemoveMultiKeysThrowsExceptionWhenNotBuilt() { - Hawk.init(context); - try { - Hawk.remove(KEY, KEY); - fail("Did not throw an exception"); - } catch (IllegalStateException ignored) { - } + verify(storage).contains(key); + verifyZeroInteractions(encoder, encryption); } - @Test public void testResetCryptoThrowsExceptionWhenNotBuilt() { - Hawk.init(context); + @Test public void validateBuildOnContains() { try { - Hawk.resetCrypto(); - fail("Did not throw an exception"); - } catch (IllegalStateException ignored) { + Hawk.destroy(); + Hawk.init(context); + Hawk.contains(key); + fail(""); + } catch (Exception e) { } } + //endregion - @Test public void testCountThrowsExceptionWhenNotBuilt() { - Hawk.init(context); - try { - Hawk.count(); - fail("Did not throw an exception"); - } catch (IllegalStateException ignored) { - } - } + //region CHAIN + @Test public void testChain() { + when(encoder.encode(value)).thenReturn(value.getBytes()); + when(encryption.encrypt(value.getBytes())).thenReturn(cipherText); + when(storage.put(anyList())).thenReturn(true); - @Test public void testPutInChainThrowsExceptionWhenNotBuilt() { - Hawk.init(context); - try { - Hawk.chain().put(KEY, "value"); - fail("Did not throw an exception"); - } catch (IllegalStateException ignored) { - } + Hawk.Chain chain = spy(Hawk.chain()); + + assertThat(chain.put(key, value).commit()).isTrue(); + + InOrder inOrder = inOrder(storage, encoder, encryption, chain); + inOrder.verify(encoder).encode(value); + inOrder.verify(encryption).encrypt(any(byte[].class)); + inOrder.verify(chain).commit(); + inOrder.verify(storage).put(anyList()); } + //endregion } diff --git a/hawk/src/test/java/com/orhanobut/hawk/HawkUtilsTest.java b/hawk/src/test/java/com/orhanobut/hawk/HawkUtilsTest.java new file mode 100644 index 0000000..d350b2d --- /dev/null +++ b/hawk/src/test/java/com/orhanobut/hawk/HawkUtilsTest.java @@ -0,0 +1,84 @@ +package com.orhanobut.hawk; + +import android.content.Context; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricGradleTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +@RunWith(RobolectricGradleTestRunner.class) +@Config(sdk = 21, constants = BuildConfig.class) +public class HawkUtilsTest { + + Context context; + + @Before public void setup() { + context = RuntimeEnvironment.application; + } + + @Test public void hasRxJavaOnClasspath() throws Exception { + //TODO + } + + @Test public void checkRx() throws Exception { + //TODO + } + + @Test public void validateBuild() throws Exception { + try { + Hawk.init(context); + HawkUtils.validateBuild(); + fail("should throw exception"); + } catch (Exception e) { + assertThat(e).hasMessage("Hawk is not built. " + + "Please call build() and wait the initialisation finishes."); + } + } + + @Test public void checkNullShouldDoNothing() { + try { + HawkUtils.checkNull("foo", "test"); + } catch (Exception e) { + fail("it should not throw exception"); + } + } + + @Test public void checkNullShouldThrowException() throws Exception { + try { + HawkUtils.checkNull("foo", null); + fail("should throw exception"); + } catch (Exception e) { + assertThat(e).hasMessage("foo should not be null"); + } + } + + @Test public void checkNullOrEmptyThrowException() throws Exception { + try { + HawkUtils.checkNullOrEmpty("foo", null); + fail("should throw exception"); + } catch (Exception e) { + assertThat(e).hasMessage("foo should not be null or empty"); + } + } + + @Test public void checkNullOrEmptyShouldDoNothing() throws Exception { + try { + HawkUtils.checkNullOrEmpty("foo", "bar"); + } catch (Exception e) { + fail("should not throw exception"); + } + } + + @Test public void isEmpty() throws Exception { + assertThat(HawkUtils.isEmpty(null)).isTrue(); + assertThat(HawkUtils.isEmpty("")).isTrue(); + assertThat(HawkUtils.isEmpty(" ")).isTrue(); + assertThat(HawkUtils.isEmpty("foo")).isFalse(); + } +} \ No newline at end of file diff --git a/hawk/src/test/java/com/orhanobut/hawk/SharedPreferencesStorageTest.java b/hawk/src/test/java/com/orhanobut/hawk/SharedPreferencesStorageTest.java new file mode 100644 index 0000000..7237e7a --- /dev/null +++ b/hawk/src/test/java/com/orhanobut/hawk/SharedPreferencesStorageTest.java @@ -0,0 +1,195 @@ +package com.orhanobut.hawk; + +import android.content.SharedPreferences; +import android.util.Pair; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.fail; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class SharedPreferencesStorageTest { + + SharedPreferencesStorage storage; + SharedPreferences.Editor editor; + SharedPreferences preferences; + + @Before public void setup() { + editor = spy(new SharedPreferences.Editor() { + @Override public SharedPreferences.Editor putString(String key, String value) { + return this; + } + + @Override public SharedPreferences.Editor putStringSet(String key, Set values) { + return this; + } + + @Override public SharedPreferences.Editor putInt(String key, int value) { + return this; + } + + @Override public SharedPreferences.Editor putLong(String key, long value) { + return this; + } + + @Override public SharedPreferences.Editor putFloat(String key, float value) { + return this; + } + + @Override public SharedPreferences.Editor putBoolean(String key, boolean value) { + return this; + } + + @Override public SharedPreferences.Editor remove(String key) { + return this; + } + + @Override public SharedPreferences.Editor clear() { + return this; + } + + @Override public boolean commit() { + return true; + } + + @Override public void apply() { + } + }); + preferences = spy(new SharedPreferences() { + @Override public Map getAll() { + Map map = new HashMap<>(); + map.put("key", "value"); + return map; + } + + @Override public String getString(String key, String defValue) { + return null; + } + + @Override public Set getStringSet(String key, Set defValues) { + return null; + } + + @Override public int getInt(String key, int defValue) { + return 0; + } + + @Override public long getLong(String key, long defValue) { + return 0; + } + + @Override public float getFloat(String key, float defValue) { + return 0; + } + + @Override public boolean getBoolean(String key, boolean defValue) { + return false; + } + + @Override public boolean contains(String key) { + return false; + } + + @Override public Editor edit() { + return editor; + } + + @Override public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { + + } + + @Override public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { + + } + }); + storage = new SharedPreferencesStorage(preferences); + } + + @Test public void putObject() throws Exception { + storage.put("key", "value"); + + verify(preferences).edit(); + verify(editor).putString("key", "value"); + verify(editor).commit(); + } + + @Test public void throwExceptionOnNullKeysPassedOnPut() { + try { + storage.put(null, "value"); + fail("key should not be null"); + } catch (Exception e) { + assertThat(e).hasMessage("key should not be null"); + } + } + + @Test public void putList() throws Exception { + List> list = new ArrayList<>(); + list.add(new Pair("f1", "s1")); + list.add(new Pair("f2", "s2")); + + storage.put(list); + + verify(preferences).edit(); + verify(editor).putString("f1", "s1"); + verify(editor).putString("f2", "s2"); + verify(editor).commit(); + } + + @Test public void get() throws Exception { + storage.get("key"); + + verify(preferences).getString("key", null); + } + + @Test public void remove() throws Exception { + storage.remove("key"); + + verify(preferences).edit(); + verify(editor).remove("key"); + verify(editor).commit(); + } + + @Test public void removeMultiple() throws Exception { + storage.remove("k1", "k2"); + + verify(preferences).edit(); + verify(editor).remove("k1"); + verify(editor).remove("k2"); + verify(editor).commit(); + } + + @Test public void contains() throws Exception { + storage.contains("key"); + + verify(preferences).contains("key"); + } + + @Test public void clear() throws Exception { + storage.clear(); + + verify(preferences).edit(); + verify(editor).clear(); + verify(editor).commit(); + } + + @Test public void count() throws Exception { + long count = storage.count(); + + verify(preferences).getAll(); + assertThat(count).isEqualTo(1); + } +} \ No newline at end of file diff --git a/hawk/src/test/java/com/orhanobut/hawk/SqliteStorageIntegrationTest.java b/hawk/src/test/java/com/orhanobut/hawk/SqliteStorageIntegrationTest.java new file mode 100644 index 0000000..614099b --- /dev/null +++ b/hawk/src/test/java/com/orhanobut/hawk/SqliteStorageIntegrationTest.java @@ -0,0 +1,151 @@ +package com.orhanobut.hawk; + +import android.content.Context; +import android.util.Pair; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; +import java.util.List; + +import static junit.framework.Assert.fail; +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class SqliteStorageIntegrationTest { + + Context context; + Storage storage; + + @Before public void setUp() throws Exception { + context = RuntimeEnvironment.application; + + storage = new SqliteStorage( + new SqliteStorage.SqliteHelper(context, "TestHawk") + ); + } + + @After public void tearDown() { + storage.clear(); + } + + @Test public void init() { + assertThat(context).isNotNull(); + assertThat(storage).isNotNull(); + } + + @Test public void clearAll() { + storage.put("a1", "String"); + storage.put("a2", "String"); + + assertThat(storage.get("a1")).isNotNull(); + assertThat(storage.get("a2")).isNotNull(); + + storage.clear(); + assertThat(storage.get("a1")).isNull(); + assertThat(storage.get("a2")).isNull(); + } + + @Test public void put() { + storage.put("string", "String"); + assertThat(storage.get("string")).isEqualTo("String"); + } + + @Test public void putInvalidValues() { + try { + storage.put(null, "test"); + fail(); + } catch (Exception e) { + assertThat(e).hasMessage("key should not be null or empty"); + } + try { + storage.put("", "test"); + fail(); + } catch (Exception e) { + assertThat(e).hasMessage("key should not be null or empty"); + } + } + + @Test public void putBulk() { + List> list = new ArrayList<>(); + Pair pair = new Pair<>("a1", "b1"); + Pair pair2 = new Pair<>("a2", "b2"); + list.add(pair); + list.add(pair2); + + storage.put(list); + assertThat(storage.get("a1")).isEqualTo("b1"); + assertThat(storage.get("a2")).isEqualTo("b2"); + } + + @Test public void getInvalidValues() { + try { + storage.get(null); + fail(); + } catch (Exception e) { + assertThat(e).hasMessage("key should not be null or empty"); + } + try { + storage.get(""); + fail(); + } catch (Exception e) { + assertThat(e).hasMessage("key should not be null or empty"); + } + } + + @Test public void contains() { + storage.put("string", "String"); + + assertThat(storage.contains("string")).isTrue(); + assertThat(storage.contains(null)).isFalse(); + } + + @Test public void remove() { + storage.put("string", "string"); + + assertThat(storage.get("string")).isNotNull(); + + storage.remove("string"); + assertThat(storage.get("string")).isNull(); + } + + @Test public void removeInvalid() { + assertThat(storage.remove(null, null)).isTrue(); + assertThat(storage.remove("")).isTrue(); + } + + @Test public void bulkRemove() { + storage.put("a1", "string"); + storage.put("a2", "string"); + assertThat(storage.get("a1")).isNotNull(); + assertThat(storage.get("a2")).isNotNull(); + + storage.remove("a1", "a2"); + assertThat(storage.get("a1")).isNull(); + assertThat(storage.get("a2")).isNull(); + } + + @Test public void count() { + storage.put("a1", "string"); + storage.put("a2", "string"); + assertThat(storage.get("a1")).isNotNull(); + assertThat(storage.get("a2")).isNotNull(); + + assertThat(storage.count()).isEqualTo(2); + } + + @Test public void update() { + storage.put("a1", "b1"); + assertThat(storage.get("a1")).isEqualTo("b1"); + + storage.put("a1", "b2"); + assertThat(storage.get("a1")).isEqualTo("b2"); + } +} diff --git a/hawk/src/test/java/com/orhanobut/hawk/SqliteStorageTest.java b/hawk/src/test/java/com/orhanobut/hawk/SqliteStorageTest.java index 12240da..868c323 100644 --- a/hawk/src/test/java/com/orhanobut/hawk/SqliteStorageTest.java +++ b/hawk/src/test/java/com/orhanobut/hawk/SqliteStorageTest.java @@ -1,160 +1,89 @@ package com.orhanobut.hawk; -import android.app.Activity; -import android.content.Context; import android.util.Pair; -import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricGradleTestRunner; -import org.robolectric.annotation.Config; +import org.mockito.Mock; import java.util.ArrayList; import java.util.List; -import static junit.framework.Assert.fail; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.fail; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; -@RunWith(RobolectricGradleTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 18) public class SqliteStorageTest { - private final Context context; + @Mock SqliteStorage.SqliteHelper helper; - private Storage storage; - - public SqliteStorageTest() { - context = Robolectric.buildActivity(Activity.class).create().get(); - } + SqliteStorage storage; @Before public void setUp() throws Exception { - storage = new SqliteStorage(context); - } - - @Test public void init() { - assertThat(context).isNotNull(); - assertThat(storage).isNotNull(); - } - - @Test public void createInstanceWithInvalidValues() { - try { - new SqliteStorage(null); - fail(); - } catch (Exception e) { - assertThat(e).hasMessage("Context should not be null"); - } - } + initMocks(this); - @After public void tearDown() { - storage = null; + storage = new SqliteStorage(helper); } - @Test public void clearAll() { - storage.put("a1", "String"); - storage.put("a2", "String"); - - assertThat(storage.get("a1")).isNotNull(); - assertThat(storage.get("a2")).isNotNull(); - - storage.clear(); - assertThat(storage.get("a1")).isNull(); - assertThat(storage.get("a2")).isNull(); - } + @Test public void putObject() throws Exception { + storage.put("key", "value"); - @Test public void put() { - storage.put("string", "String"); - assertThat(storage.get("string")).isEqualTo("String"); + verify(helper).put("key", "value"); } - @Test public void putInvalidValues() { + @Test public void throwExceptionOnNullKeysPassedOnPut() { try { - storage.put(null, "test"); - fail(); + storage.put(null, "value"); + fail("key should not be null"); } catch (Exception e) { - assertThat(e).hasMessage("Key cannot be null or empty"); - } - try { - storage.put("", "test"); - fail(); - } catch (Exception e) { - assertThat(e).hasMessage("Key cannot be null or empty"); + assertThat(e).hasMessage("key should not be null or empty"); } } - @Test public void putBulk() { + @Test public void putList() throws Exception { List> list = new ArrayList<>(); - Pair pair = new Pair<>("a1", "b1"); - Pair pair2 = new Pair<>("a2", "b2"); - list.add(pair); - list.add(pair2); + list.add(new Pair("f1", "s1")); + list.add(new Pair("f2", "s2")); storage.put(list); - assertThat(storage.get("a1")).isEqualTo("b1"); - assertThat(storage.get("a2")).isEqualTo("b2"); - } - @Test public void getInvalidValues() { - try { - storage.get(null); - fail(); - } catch (Exception e) { - assertThat(e).hasMessage("Key cannot be null or empty"); - } - try { - storage.get(""); - fail(); - } catch (Exception e) { - assertThat(e).hasMessage("Key cannot be null or empty"); - } + verify(helper).put(list); } - @Test public void contains() { - storage.put("string", "String"); - assertThat(storage.contains("string")).isTrue(); - assertThat(storage.contains(null)).isFalse(); + @Test public void get() throws Exception { + storage.get("key"); + + verify(helper).get("key"); } - @Test public void remove() { - storage.put("string", "string"); - assertThat(storage.get("string")).isNotNull(); + @Test public void remove() throws Exception { + storage.remove("key"); - storage.remove("string"); - assertThat(storage.get("string")).isNull(); + verify(helper).delete("key"); } - @Test public void removeInvalid() { - assertThat(storage.remove(null, null)).isTrue(); - assertThat(storage.remove("")).isTrue(); + @Test public void removeMultiple() throws Exception { + storage.remove("k1", "k2"); + + verify(helper).delete("k1", "k2"); } - @Test public void bulkRemove() { - storage.put("a1", "string"); - storage.put("a2", "string"); - assertThat(storage.get("a1")).isNotNull(); - assertThat(storage.get("a2")).isNotNull(); + @Test public void contains() throws Exception { + storage.contains("key"); - storage.remove("a1", "a2"); - assertThat(storage.get("a1")).isNull(); - assertThat(storage.get("a2")).isNull(); + verify(helper).contains("key"); } - @Test public void count() { - storage.put("a1", "string"); - storage.put("a2", "string"); - assertThat(storage.get("a1")).isNotNull(); - assertThat(storage.get("a2")).isNotNull(); + @Test public void clear() throws Exception { + storage.clear(); - assertThat(storage.count()).isEqualTo(2); + verify(helper).clearAll(); } - @Test public void update() { - storage.put("a1", "b1"); - assertThat(storage.get("a1")).isEqualTo("b1"); + @Test public void count() throws Exception { + storage.count(); - storage.put("a1", "b2"); - assertThat(storage.get("a1")).isEqualTo("b2"); + verify(helper).count(); } -} +} \ No newline at end of file