/*
* Copyright 2016 Realm Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.realm.rule;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import io.realm.DynamicRealm;
import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmMigration;
import io.realm.RealmObject;
import io.realm.TestHelper;
import io.realm.annotations.RealmModule;
import static org.junit.Assert.assertTrue;
/**
* Rule that creates the {@link RealmConfiguration } in a temporary directory and deletes the Realm created with that
* configuration once the test finishes. Be sure to close all Realm instances before finishing the test. Otherwise
* {@link Realm#deleteRealm(RealmConfiguration)} will throw an exception in the {@link #after()} method.
* The temp directory will be deleted regardless if the {@link Realm#deleteRealm(RealmConfiguration)} fails or not.
*/
public class TestRealmConfigurationFactory extends TemporaryFolder {
private final Map<RealmConfiguration, Boolean> map = new ConcurrentHashMap<RealmConfiguration, Boolean>();
private final Set<RealmConfiguration> configurations = Collections.newSetFromMap(map);
private boolean unitTestFailed = false;
@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
before();
try {
base.evaluate();
} catch (Throwable throwable) {
setUnitTestFailed();
throw throwable;
} finally {
after();
}
}
};
}
@Override
protected void before() throws Throwable {
super.before();
Realm.init(InstrumentationRegistry.getTargetContext());
}
@Override
protected void after() {
try {
for (RealmConfiguration configuration : configurations) {
Realm.deleteRealm(configuration);
}
} catch (IllegalStateException e) {
// Only throws the exception caused by deleting the opened Realm if the test case itself doesn't throw.
if (!isUnitTestFailed()) {
throw e;
}
} finally {
// This will delete the temp directory.
super.after();
}
}
public synchronized void setUnitTestFailed() {
this.unitTestFailed = true;
}
private synchronized boolean isUnitTestFailed() {
return this.unitTestFailed;
}
// This builder creates a configuration that is *NOT* managed.
// You have to delete it yourself.
public RealmConfiguration.Builder createConfigurationBuilder() {
return new RealmConfiguration.Builder().directory(getRoot());
}
public RealmConfiguration createConfiguration() {
return createConfiguration(null);
}
public RealmConfiguration createConfiguration(String name) {
return createConfiguration(null, name);
}
public RealmConfiguration createConfiguration(String subDir, String name) {
return createConfiguration(subDir, name, null, null);
}
public RealmConfiguration createConfiguration(String name, byte[] key) {
return createConfiguration(null, name, null, key);
}
public RealmConfiguration createConfiguration(String name, Object module) {
return createConfiguration(null, name, module, null);
}
public RealmConfiguration createConfiguration(String subDir, String name, Object module, byte[] key) {
RealmConfiguration.Builder builder = createConfigurationBuilder();
File folder = getRoot();
if (subDir != null) {
folder = new File(folder, subDir);
assertTrue(folder.mkdirs());
}
builder.directory(folder);
if (name != null) {
builder.name(name);
}
if (module != null) {
builder.modules(module);
}
if (key != null) {
builder.encryptionKey(key);
}
RealmConfiguration configuration = builder.build();
configurations.add(configuration);
return configuration;
}
// Copies a Realm file from assets to temp dir
public void copyRealmFromAssets(Context context, String realmPath, String newName) throws IOException {
RealmConfiguration config = new RealmConfiguration.Builder()
.directory(getRoot())
.name(newName)
.build();
copyRealmFromAssets(context, realmPath, config);
}
public void copyRealmFromAssets(Context context, String realmPath, RealmConfiguration config) throws IOException {
// Deletes the existing file before copy
Realm.deleteRealm(config);
File outFile = new File(config.getRealmDirectory(), config.getRealmFileName());
InputStream is = null;
FileOutputStream os = null;
try {
is = context.getAssets().open(realmPath);
os = new FileOutputStream(outFile);
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(buf)) > -1) {
os.write(buf, 0, bytesRead);
}
} finally {
if (is != null) {
try { is.close(); } catch (IOException ignore) {}
}
if (os != null) {
try { os.close(); } catch (IOException ignore) {}
}
}
}
}