Merge remote-tracking branch 'origin/master' into tg/merge-master-to-2.0.x

* origin/master: (23 commits)
  Fix api doc error
  fix progress notifications registrations
  Fix typo in Github issue template
  Fix port conflict between RN >= 0.48 and RPC server (#1294)
  Disable testAddListener when running in chrome
  Ensure RN has an event loop running for async tests
  Make permission tests better handle server delays
  Fix race conditions in testAddListener
  Separate build and test steps in xcode to reduce chance of hitting "Early unexpected exit"
  Ignore errors when sourcing nvm.sh
  Don't forward arguments to nvh.sh
  Skip sourcing nvm.sh if it's already available
  Fix some shellcheck warnings
  Ensure node 6.5.0 is installed on CI
  Build realm from source for each test-runner test
  Improve error reporting for incorrect argument counts for Realm methods
  Use the same error messages in the RPC code as the regular code
  Silence an unused variable warning when building with sync disabled
  Check the exception message in all Realm tests which assert an exception is thrown
  Don't discard the actual error message in validated_get_X
  ...
This commit is contained in:
Thomas Goyne 2017-09-25 09:40:56 -07:00
commit 2298609ce5
22 changed files with 494 additions and 456 deletions

View File

@ -40,6 +40,6 @@ Full projects that we can compile and run ourselves are ideal!
## Version of Realm and Tooling
- Realm JS SDK Version: ?
- Node or React Nattive: ?
- Node or React Native: ?
- Client OS & Version: ?
- Which debugger for React Native: ?/None

View File

@ -1,9 +1,14 @@
NEXT RELEASE
X.Y.Z Release notes
=============================================================
### Breaking changes
* None
### Enhancements
* Add a callback function used to verify SSL certificates in the sync config.
### Bug fixes
* Fixed port conflict between RN >= 0.48 inspector proxy and RPC server used for Chrome debugging (#1294).
2.0.0-rc10 Release notes (2017-9-19)
=============================================================

View File

@ -30,9 +30,6 @@ class Sync {
* _Currently only the 'change' event is supported_
* @param {function(change_event)} change_callback - called when changes are made to any Realm which
* match the given regular expression
* @param {bool} validate_ssl=true - Validate the server's SSL chertificate.
* @param {string} ssl_trust_certificate_path=None - Path to a trust/anchor certificate used by the
* client to verify the server certificate.
*/
static addListener(server_url, admin_user, regex, name, change_callback) {}

View File

@ -83,14 +83,14 @@ export default class Realm {
if (typeof item == 'function') {
let schema = item.schema;
if (!schema || typeof schema != 'object') {
throw new Error("Realm object constructor must have 'schema' property");
throw new Error("Realm object constructor must have a 'schema' property.");
}
let {name, properties} = schema;
if (!name || typeof name != 'string') {
throw new Error("Realm object schema must have 'name' property");
throw new Error(`Failed to read ObjectSchema: name must be of type 'string', got (${typeof name})`);
} else if (!properties || typeof properties != 'object') {
throw new Error("Realm object schema must have 'properties' property");
throw new Error(`Failed to read ObjectSchema: properties must be of type 'object', got (${typeof properties})`);
}
schemas.splice(i, 1, schema);

View File

@ -85,5 +85,5 @@ export function typeForConstructor(realmId, constructor) {
}
}
return null;
throw new Error("Constructor was not registered in the schema for this Realm")
}

View File

@ -59,9 +59,9 @@
"jsdoc": "npm install && npm run jsdoc:clean && jsdoc -u docs/tutorials -p package.json -c docs/conf.json",
"prenode-tests": "npm install --build-from-source=realm && cd tests && npm install",
"node-tests": "cd tests && npm run test && cd ..",
"test-runner:ava": "cd tests/test-runners/ava && npm install && npm test",
"test-runner:mocha": "cd tests/test-runners/mocha && npm install && npm test",
"test-runner:jest": "cd tests/test-runners/jest && npm install && npm test",
"test-runner:ava": "cd tests/test-runners/ava && npm install --build-from-source=realm && npm test",
"test-runner:mocha": "cd tests/test-runners/mocha && npm install --build-from-source=realm && npm test",
"test-runner:jest": "cd tests/test-runners/jest && npm install --build-from-source=realm && npm test",
"test-runners": "npm run test-runner:ava && npm run test-runner:mocha && npm run test-runner:jest",
"isMac": "node -p \"if (process.platform == 'darwin') { process.exit(0); } else { process.exit(-1); }\"",
"testMac": "npm run isMac -s && echo this is mac || echo . ",

View File

@ -22,17 +22,17 @@ apply plugin: 'com.android.library'
task forwardDebugPort(type: Exec) {
def adb = android.getAdbExe()?.toString() ?: 'false'
commandLine adb, 'forward', 'tcp:8082', 'tcp:8082'
commandLine adb, 'forward', 'tcp:8083', 'tcp:8083'
ignoreExitValue true
doLast {
if (execResult.getExitValue() != 0) {
logger.error(
'===========================================================================\n' +
'WARNING: Failed to automatically forward port 8082.\n' +
'In order to use Realm in Chrome debugging mode, port 8082 must be forwarded\n' +
'WARNING: Failed to automatically forward port 8083.\n' +
'In order to use Realm in Chrome debugging mode, port 8083 must be forwarded\n' +
'from localhost to the device or emulator being used to run the application.\n' +
'You may need to add the appropriate flags to the command that failed:\n' +
' adb forward tcp:8082 tcp:8082\n' +
' adb forward tcp:8083 tcp:8083\n' +
'===========================================================================\n'
)
}

View File

@ -23,7 +23,7 @@ import java.util.Map;
import fi.iki.elonen.NanoHTTPD;
class RealmReactModule extends ReactContextBaseJavaModule {
private static final int DEFAULT_PORT = 8082;
private static final int DEFAULT_PORT = 8083;
private static boolean sentAnalytics = false;
private AndroidWebServer webServer;

View File

@ -38,7 +38,7 @@
#import "GCDWebServerErrorResponse.h"
#import "rpc.hpp"
#define WEB_SERVER_PORT 8082
#define WEB_SERVER_PORT 8083
using namespace realm::rpc;
#endif

View File

@ -9,7 +9,7 @@ export NPM_CONFIG_PROGRESS=false
TARGET=$1
CONFIGURATION=${2:-Release}
if echo $CONFIGURATION | grep -i "^Debug$" > /dev/null ; then
if echo "$CONFIGURATION" | grep -i "^Debug$" > /dev/null ; then
CONFIGURATION="Debug"
fi
@ -17,8 +17,6 @@ IOS_SIM_DEVICE=${IOS_SIM_DEVICE:-} # use preferentially, otherwise will be set a
ios_sim_default_device_type=${IOS_SIM_DEVICE_TYPE:-iPhone 5s}
ios_sim_default_ios_version=${IOS_SIM_OS:-iOS 10.1}
ACCEPTED_LICENSES='MIT, ISC, BSD, Apache-2.0, BSD-2-Clause, BSD-3-Clause, WTFPL, Unlicense, (MIT AND CC-BY-3.0)'
PATH="/opt/android-sdk-linux/platform-tools:$PATH"
SRCROOT=$(cd "$(dirname "$0")/.." && pwd)
XCPRETTY=$(which xcpretty || true)
@ -130,13 +128,18 @@ xctest() {
echo " done"
# - Run the build and test
xcrun xcodebuild -scheme "$1" -configuration "$CONFIGURATION" -sdk iphonesimulator -destination id="$IOS_SIM_DEVICE" build || {
EXITCODE=$?
echo "*** Failure (exit code $EXITCODE). ***"
exit $EXITCODE
}
if [ -n "$XCPRETTY" ]; then
log_temp=$(mktemp build.log.XXXXXX)
if [ -e "$log_temp" ]; then
rm "$log_temp"
fi
xcrun xcodebuild -scheme "$1" -configuration "$CONFIGURATION" -sdk iphonesimulator -destination name="iPhone 5s" build test 2>&1 | tee "$log_temp" | "$XCPRETTY" -c --no-utf --report junit --output build/reports/junit.xml || {
EXITCODE=$?
xcrun xcodebuild -scheme "$1" -configuration "$CONFIGURATION" -sdk iphonesimulator -destination name="iPhone 5s" test 2>&1 | tee "$log_temp" | "$XCPRETTY" -c --no-utf --report junit --output build/reports/junit.xml || {
EXITCODE=$?
printf "*** Xcode Failure (exit code %s). The full xcode log follows: ***\n\n" "$EXITCODE"
cat "$log_temp"
printf "\n\n*** End Xcode Failure ***\n"
@ -144,11 +147,11 @@ xctest() {
}
rm "$log_temp"
else
xcrun xcodebuild -scheme "$1" -configuration "$CONFIGURATION" -sdk iphonesimulator -destination id="$IOS_SIM_DEVICE" build test || {
EXITCODE=$?
xcrun xcodebuild -scheme "$1" -configuration "$CONFIGURATION" -sdk iphonesimulator -destination id="$IOS_SIM_DEVICE" test || {
EXITCODE=$?
echo "*** Failure (exit code $EXITCODE). ***"
exit $EXITCODE
}
}
fi
}
@ -240,14 +243,22 @@ cleanup
trap cleanup EXIT
# Use a consistent version of Node if possible.
if [ -f "$NVM_DIR/nvm.sh" ]; then
. "$NVM_DIR/nvm.sh"
elif [ -x "$(command -v brew)" ] && [ -f "$(brew --prefix nvm)/nvm.sh" ]; then
# we must be on mac and nvm was installed with brew
# TODO: change the mac slaves to use manual nvm installation
. "$(brew --prefix nvm)/nvm.sh"
if [[ -z "$(command -v nvm)" ]]; then
set +e
if [ -f "$NVM_DIR/nvm.sh" ]; then
. "$NVM_DIR/nvm.sh" '' || true
elif [ -x "$(command -v brew)" ] && [ -f "$(brew --prefix nvm)/nvm.sh" ]; then
# we must be on mac and nvm was installed with brew
# TODO: change the mac slaves to use manual nvm installation
. "$(brew --prefix nvm)/nvm.sh" '' || true
elif [ -f "$HOME/.nvm/nvm.sh" ]; then
. ~/.nvm/nvm.sh ''
fi
set -e
fi
if [[ "$(command -v nvm)" ]]; then
nvm install 7.10.0
fi
[[ "$(command -v nvm)" ]] && nvm install 7.10.0 && nvm use 7.10.0 || true
# Remove cached packages
rm -rf ~/.yarn-cache/npm-realm-*
@ -406,8 +417,6 @@ case "$TARGET" in
;;
"test-runners")
npm run check-environment
# Create a fake realm module that points to the source root so that test-runner tests can require('realm')
npm install --build-from-source=realm
npm run test-runners
;;
"all")

View File

@ -33,6 +33,29 @@ using ConstructorType = void(typename T::Context, typename T::Object, size_t, co
template<typename T>
using MethodType = void(typename T::Context, typename T::Function, typename T::Object, size_t, const typename T::Value[], ReturnValue<T> &);
template<typename T>
struct Arguments {
const typename T::Context ctx;
const size_t count;
const typename T::Value* const value;
typename T::Value operator[](size_t index) const noexcept {
if (index >= count) {
return Value<T>::from_undefined(ctx);
}
return value[index];
}
void validate_maximum(size_t max) const {
if (max < count) {
throw std::invalid_argument(util::format("Invalid arguments: at most %1 expected, but %2 supplied.", max, count));
}
}
};
template<typename T>
using ArgumentsMethodType = void(typename T::Context, typename T::Function, typename T::Object, Arguments<T>, ReturnValue<T> &);
template<typename T>
struct PropertyType {
using GetterType = void(typename T::Context, typename T::Object, ReturnValue<T> &);

View File

@ -123,9 +123,7 @@ class RealmDelegate : public BindingContext {
}
ObjectType realm_object = create_object<T, RealmClass<T>>(m_context, new SharedRealm(realm));
ValueType arguments[2];
arguments[0] = realm_object;
arguments[1] = Value::from_string(m_context, notification_name);
ValueType arguments[] = {realm_object, Value::from_string(m_context, notification_name)};
std::list<Protected<FunctionType>> notifications_copy(m_notifications);
for (auto &callback : notifications_copy) {
@ -148,6 +146,7 @@ class RealmClass : public ClassDefinition<T, SharedRealm, ObservableClass<T>> {
using FunctionType = typename T::Function;
using ObjectType = typename T::Object;
using ValueType = typename T::Value;
using Arguments = js::Arguments<T>;
using String = js::String<T>;
using Object = js::Object<T>;
using Value = js::Value<T>;
@ -165,22 +164,22 @@ public:
static FunctionType create_constructor(ContextType);
// methods
static void objects(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void object_for_primary_key(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void create(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void delete_one(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void delete_all(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void write(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void begin_transaction(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue&);
static void commit_transaction(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue&);
static void cancel_transaction(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue&);
static void add_listener(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void wait_for_download_completion(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void remove_listener(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void remove_all_listeners(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void close(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void compact(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void delete_model(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void objects(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void object_for_primary_key(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void create(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void delete_one(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void delete_all(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void write(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void begin_transaction(ContextType, FunctionType, ObjectType, Arguments, ReturnValue&);
static void commit_transaction(ContextType, FunctionType, ObjectType, Arguments, ReturnValue&);
static void cancel_transaction(ContextType, FunctionType, ObjectType, Arguments, ReturnValue&);
static void add_listener(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void wait_for_download_completion(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void remove_listener(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void remove_all_listeners(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void close(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void compact(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void delete_model(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
// properties
static void get_empty(ContextType, ObjectType, ReturnValue &);
@ -198,10 +197,10 @@ public:
static void constructor(ContextType, ObjectType, size_t, const ValueType[]);
static SharedRealm create_shared_realm(ContextType, realm::Realm::Config, bool, ObjectDefaultsMap &&, ConstructorMap &&);
static void schema_version(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void clear_test_state(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void copy_bundled_realm_files(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void delete_file(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void schema_version(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void clear_test_state(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void copy_bundled_realm_files(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
static void delete_file(ContextType, FunctionType, ObjectType, Arguments, ReturnValue &);
// static properties
static void get_default_path(ContextType, ObjectType, ReturnValue &);
@ -398,7 +397,7 @@ void RealmClass<T>::constructor(ContextType ctx, ObjectType this_object, size_t
static const String schema_string = "schema";
ValueType schema_value = Object::get_property(ctx, object, schema_string);
if (!Value::is_undefined(ctx, schema_value)) {
ObjectType schema_object = Value::validated_to_object(ctx, schema_value, "schema");
ObjectType schema_object = Value::validated_to_array(ctx, schema_value, "schema");
config.schema.emplace(Schema<T>::parse_schema(ctx, schema_object, defaults, constructors));
schema_updated = true;
}
@ -504,13 +503,13 @@ SharedRealm RealmClass<T>::create_shared_realm(ContextType ctx, realm::Realm::Co
}
template<typename T>
void RealmClass<T>::schema_version(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1, 2);
void RealmClass<T>::schema_version(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(2);
realm::Realm::Config config;
config.path = normalize_realm_path(Value::validated_to_string(ctx, arguments[0]));
if (argc == 2) {
auto encryption_key = Value::validated_to_binary(ctx, arguments[1], "encryptionKey");
config.path = normalize_realm_path(Value::validated_to_string(ctx, args[0]));
if (args.count == 2) {
auto encryption_key = Value::validated_to_binary(ctx, args[1], "encryptionKey");
config.encryption_key.assign(encryption_key.data(), encryption_key.data() + encryption_key.size());
}
@ -525,23 +524,22 @@ void RealmClass<T>::schema_version(ContextType ctx, FunctionType, ObjectType thi
template<typename T>
void RealmClass<T>::clear_test_state(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
void RealmClass<T>::clear_test_state(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(0);
js::clear_test_state();
}
template<typename T>
void RealmClass<T>::copy_bundled_realm_files(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
void RealmClass<T>::copy_bundled_realm_files(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(0);
realm::copy_bundled_realm_files();
}
template<typename T>
void RealmClass<T>::delete_file(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1);
void RealmClass<T>::delete_file(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(1);
ValueType value = arguments[0];
ValueType value = args[0];
if (!Value::is_object(ctx, value)) {
throw std::runtime_error("Invalid argument, expected a Realm configuration object");
}
@ -569,9 +567,9 @@ void RealmClass<T>::delete_file(ContextType ctx, FunctionType, ObjectType this_o
}
template<typename T>
void RealmClass<T>::delete_model(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1);
ValueType value = arguments[0];
void RealmClass<T>::delete_model(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(1);
ValueType value = args[0];
SharedRealm& realm = *get_internal<T, RealmClass<T>>(this_object);
@ -643,14 +641,14 @@ void RealmClass<T>::get_sync_session(ContextType ctx, ObjectType object, ReturnV
#endif
template<typename T>
void RealmClass<T>::wait_for_download_completion(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 2, 3);
auto config_object = Value::validated_to_object(ctx, arguments[0]);
auto callback_function = Value::validated_to_function(ctx, arguments[argc - 1]);
void RealmClass<T>::wait_for_download_completion(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(3);
auto config_object = Value::validated_to_object(ctx, args[0]);
auto callback_function = Value::validated_to_function(ctx, args[1 + (args.count == 3)]);
ValueType session_callback = Value::from_null(ctx);
if (argc == 3) {
session_callback = Value::validated_to_function(ctx, arguments[1]);
if (args.count == 3) {
session_callback = Value::validated_to_function(ctx, args[1]);
}
#if REALM_ENABLE_SYNC
@ -754,31 +752,33 @@ void RealmClass<T>::wait_for_download_completion(ContextType ctx, FunctionType,
return;
}
}
#else
static_cast<void>(config_object);
#endif
Function<T>::callback(ctx, callback_function, this_object, 0, nullptr);
}
template<typename T>
void RealmClass<T>::objects(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1);
void RealmClass<T>::objects(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(1);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
std::string object_type;
validated_object_schema_for_value(ctx, realm, arguments[0], object_type);
validated_object_schema_for_value(ctx, realm, args[0], object_type);
return_value.set(ResultsClass<T>::create_instance(ctx, realm, object_type));
}
template<typename T>
void RealmClass<T>::object_for_primary_key(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 2);
void RealmClass<T>::object_for_primary_key(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(2);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
std::string object_type;
auto &object_schema = validated_object_schema_for_value(ctx, realm, arguments[0], object_type);
auto &object_schema = validated_object_schema_for_value(ctx, realm, args[0], object_type);
NativeAccessor accessor(ctx, realm, object_schema);
auto realm_object = realm::Object::get_for_primary_key(accessor, realm, object_schema, arguments[1]);
auto realm_object = realm::Object::get_for_primary_key(accessor, realm, object_schema, args[1]);
if (realm_object.is_valid()) {
return_value.set(RealmObjectClass<T>::create_instance(ctx, std::move(realm_object)));
@ -789,21 +789,22 @@ void RealmClass<T>::object_for_primary_key(ContextType ctx, FunctionType, Object
}
template<typename T>
void RealmClass<T>::create(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 2, 3);
void RealmClass<T>::create(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(3);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
realm->verify_open();
std::string object_type;
auto &object_schema = validated_object_schema_for_value(ctx, realm, arguments[0], object_type);
auto &object_schema = validated_object_schema_for_value(ctx, realm, args[0], object_type);
ObjectType object = Value::validated_to_object(ctx, arguments[1], "properties");
if (Value::is_array(ctx, arguments[1])) {
ObjectType object = Value::validated_to_object(ctx, args[1], "properties");
if (Value::is_array(ctx, args[1])) {
object = Schema<T>::dict_for_property_array(ctx, object_schema, object);
}
bool update = false;
if (argc == 3) {
update = Value::validated_to_boolean(ctx, arguments[2], "update");
if (args.count == 3) {
update = Value::validated_to_boolean(ctx, args[2], "update");
}
NativeAccessor accessor(ctx, realm, object_schema);
@ -812,15 +813,16 @@ void RealmClass<T>::create(ContextType ctx, FunctionType, ObjectType this_object
}
template<typename T>
void RealmClass<T>::delete_one(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1);
void RealmClass<T>::delete_one(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(1);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
realm->verify_open();
if (!realm->is_in_transaction()) {
throw std::runtime_error("Can only delete objects within a transaction.");
}
ObjectType arg = Value::validated_to_object(ctx, arguments[0]);
ObjectType arg = Value::validated_to_object(ctx, args[0], "object");
if (Object::template is_instance<RealmObjectClass<T>>(ctx, arg)) {
auto object = get_internal<T, RealmObjectClass<T>>(arg);
@ -859,10 +861,11 @@ void RealmClass<T>::delete_one(ContextType ctx, FunctionType, ObjectType this_ob
}
template<typename T>
void RealmClass<T>::delete_all(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
void RealmClass<T>::delete_all(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(0);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
realm->verify_open();
if (!realm->is_in_transaction()) {
throw std::runtime_error("Can only delete objects within a transaction.");
@ -874,18 +877,18 @@ void RealmClass<T>::delete_all(ContextType ctx, FunctionType, ObjectType this_ob
}
template<typename T>
void RealmClass<T>::write(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1);
void RealmClass<T>::write(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(1);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
FunctionType callback = Value::validated_to_function(ctx, arguments[0]);
FunctionType callback = Value::validated_to_function(ctx, args[0]);
realm->begin_transaction();
try {
Function<T>::call(ctx, callback, this_object, 0, nullptr);
}
catch (std::exception &e) {
catch (...) {
realm->cancel_transaction();
throw;
}
@ -894,82 +897,76 @@ void RealmClass<T>::write(ContextType ctx, FunctionType, ObjectType this_object,
}
template<typename T>
void RealmClass<T>::begin_transaction(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
void RealmClass<T>::begin_transaction(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(0);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
realm->begin_transaction();
}
template<typename T>
void RealmClass<T>::commit_transaction(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
void RealmClass<T>::commit_transaction(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(0);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
realm->commit_transaction();
}
template<typename T>
void RealmClass<T>::cancel_transaction(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
void RealmClass<T>::cancel_transaction(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(0);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
realm->cancel_transaction();
}
template<typename T>
void RealmClass<T>::add_listener(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 2);
void RealmClass<T>::add_listener(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(2);
validated_notification_name(ctx, arguments[0]);
auto callback = Value::validated_to_function(ctx, arguments[1]);
validated_notification_name(ctx, args[0]);
auto callback = Value::validated_to_function(ctx, args[1]);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
if (realm->is_closed()) {
throw ClosedRealmException();
}
realm->verify_open();
get_delegate<T>(realm.get())->add_notification(callback);
}
template<typename T>
void RealmClass<T>::remove_listener(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 2);
void RealmClass<T>::remove_listener(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(2);
validated_notification_name(ctx, arguments[0]);
auto callback = Value::validated_to_function(ctx, arguments[1]);
validated_notification_name(ctx, args[0]);
auto callback = Value::validated_to_function(ctx, args[1]);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
if (realm->is_closed()) {
throw ClosedRealmException();
}
realm->verify_open();
get_delegate<T>(realm.get())->remove_notification(callback);
}
template<typename T>
void RealmClass<T>::remove_all_listeners(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0, 1);
if (argc) {
validated_notification_name(ctx, arguments[0]);
void RealmClass<T>::remove_all_listeners(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(1);
if (args.count) {
validated_notification_name(ctx, args[0]);
}
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
if (realm->is_closed()) {
throw ClosedRealmException();
}
realm->verify_open();
get_delegate<T>(realm.get())->remove_all_notifications();
}
template<typename T>
void RealmClass<T>::close(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
void RealmClass<T>::close(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(0);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
realm->close();
}
template<typename T>
void RealmClass<T>::compact(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
void RealmClass<T>::compact(ContextType ctx, FunctionType, ObjectType this_object, Arguments args, ReturnValue &return_value) {
args.validate_maximum(0);
SharedRealm realm = *get_internal<T, RealmClass<T>>(this_object);
if (realm->is_in_transaction()) {

View File

@ -180,9 +180,9 @@ ObjectSchema Schema<T>::parse_object_schema(ContextType ctx, ObjectType object_s
ObjectDefaults object_defaults;
ObjectSchema object_schema;
object_schema.name = Object::validated_get_string(ctx, object_schema_object, name_string);
object_schema.name = Object::validated_get_string(ctx, object_schema_object, name_string, "ObjectSchema");
ObjectType properties_object = Object::validated_get_object(ctx, object_schema_object, properties_string, "ObjectSchema must have a 'properties' object.");
ObjectType properties_object = Object::validated_get_object(ctx, object_schema_object, properties_string, "ObjectSchema");
if (Value::is_array(ctx, properties_object)) {
uint32_t length = Object::validated_get_length(ctx, properties_object);
for (uint32_t i = 0; i < length; i++) {
@ -233,7 +233,8 @@ ObjectSchema Schema<T>::parse_object_schema(ContextType ctx, ObjectType object_s
}
template<typename T>
realm::Schema Schema<T>::parse_schema(ContextType ctx, ObjectType schema_object, ObjectDefaultsMap &defaults, ConstructorMap &constructors) {
realm::Schema Schema<T>::parse_schema(ContextType ctx, ObjectType schema_object,
ObjectDefaultsMap &defaults, ConstructorMap &constructors) {
std::vector<ObjectSchema> schema;
uint32_t length = Object::validated_get_length(ctx, schema_object);

View File

@ -470,7 +470,7 @@ void SessionClass<T>::add_progress_notification(ContextType ctx, FunctionType, O
progressFunc = std::move(progress_handler);
auto registrationToken = session->register_progress_notifier(std::move(progressFunc), notifierType, false);
auto registrationToken = session->register_progress_notifier(std::move(progressFunc), notifierType, is_streaming);
auto syncSession = create_object<T, SessionClass<T>>(ctx, new WeakSession(session));
PropertyAttributes attributes = ReadOnly | DontEnum | DontDelete;

View File

@ -27,6 +27,7 @@
#include <vector>
#include <realm/binary_data.hpp>
#include <realm/string_data.hpp>
#include <realm/util/to_string.hpp>
#if defined(__GNUC__) && !(defined(DEBUG) && DEBUG)
@ -223,7 +224,7 @@ struct Object {
return Value<T>::validated_to_##type(ctx, get_property(ctx, object, key), std::string(key).c_str()); \
} \
catch (std::invalid_argument &e) { \
throw message ? std::invalid_argument(message) : e; \
throw message ? std::invalid_argument(util::format("Failed to read %1: %2", message, e.what())) : e; \
} \
} \
static return_t validated_get_##type(ContextType ctx, const ObjectType &object, uint32_t index, const char *message = nullptr) { \
@ -231,7 +232,7 @@ struct Object {
return Value<T>::validated_to_##type(ctx, get_property(ctx, object, index)); \
} \
catch (std::invalid_argument &e) { \
throw message ? std::invalid_argument(message) : e; \
throw message ? std::invalid_argument(util::format("Failed to read %1: %2", message, e.what())) : e; \
} \
}

View File

@ -30,7 +30,9 @@ template<typename T>
using ClassDefinition = js::ClassDefinition<Types, T>;
using ConstructorType = js::ConstructorType<Types>;
using ArgumentsMethodType = js::ArgumentsMethodType<Types>;
using MethodType = js::MethodType<Types>;
using Arguments = js::Arguments<Types>;
using PropertyType = js::PropertyType<Types>;
using IndexPropertyType = js::IndexPropertyType<Types>;
using StringPropertyType = js::StringPropertyType<Types>;
@ -369,6 +371,19 @@ JSValueRef wrap(JSContextRef ctx, JSObjectRef function, JSObjectRef this_object,
}
}
template<jsc::ArgumentsMethodType F>
JSValueRef wrap(JSContextRef ctx, JSObjectRef function, JSObjectRef this_object, size_t argc, const JSValueRef arguments[], JSValueRef* exception) {
jsc::ReturnValue return_value(ctx);
try {
F(ctx, function, this_object, jsc::Arguments{ctx, argc, arguments}, return_value);
return return_value;
}
catch (std::exception &e) {
*exception = jsc::Exception::value(ctx, e);
return nullptr;
}
}
template<jsc::PropertyType::GetterType F>
JSValueRef wrap(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) {
jsc::ReturnValue return_value(ctx);

View File

@ -31,6 +31,8 @@ using ClassDefinition = js::ClassDefinition<Types, T>;
using ConstructorType = js::ConstructorType<Types>;
using MethodType = js::MethodType<Types>;
using ArgumentsMethodType = js::ArgumentsMethodType<Types>;
using Arguments = js::Arguments<Types>;
using PropertyType = js::PropertyType<Types>;
using IndexPropertyType = js::IndexPropertyType<Types>;
using StringPropertyType = js::StringPropertyType<Types>;
@ -308,6 +310,21 @@ void wrap(const v8::FunctionCallbackInfo<v8::Value>& info) {
}
}
template<node::ArgumentsMethodType F>
void wrap(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
node::ReturnValue return_value(info.GetReturnValue());
auto arguments = node::get_arguments(info);
try {
F(isolate, info.Callee(), info.This(), node::Arguments{isolate, arguments.size(), arguments.data()}, return_value);
}
catch (std::exception &e) {
Nan::ThrowError(node::Exception::value(isolate, e));
}
}
template<node::PropertyType::GetterType F>
void wrap(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();

View File

@ -120,6 +120,23 @@ module.exports = {
}
},
assertThrowsContaining: function(func, expectedMessage) {
var caught = false;
try {
func();
}
catch (e) {
caught = true;
if (!e.message.includes(expectedMessage)) {
throw new TestFailureError(`Expected exception "${expectedMessage}" not thrown - instead caught: "${e}"`);
}
}
if (!caught) {
throw new TestFailureError(`Expected exception "${expectedMessage}" not thrown`);
}
},
assertTrue: function(condition, errorMessage) {
if (!condition) {
throw new TestFailureError(errorMessage || `Condition ${condition} expected to be true`);

View File

@ -54,13 +54,25 @@ function wait(t) {
return new Promise(resolve => setTimeout(resolve, t));
}
function repeatUntil(fn, predicate) {
let retries = 0
function check() {
if (retries > 3) {
return Promise.reject(new Error("operation timed out"));
}
++retries;
return fn().then(x => predicate(x) ? x : wait(100).then(check));
}
return check;
}
module.exports = {
testApplyAndGetGrantedPermissions() {
return createUsersWithTestRealms(1)
.then(([user]) => {
return user.applyPermissions({ userId: '*' }, `/${user.identity}/test`, 'read')
.then(wait(100))
.then(() => user.getGrantedPermissions('any'))
.then(repeatUntil(() => user.getGrantedPermissions('any'),
permissions => permissions.length > 1))
.then(permissions => {
TestCase.assertEqual(permissions[1].path, `/${user.identity}/test`);
TestCase.assertEqual(permissions[1].mayRead, true);
@ -77,17 +89,19 @@ module.exports = {
.then(token => user2.acceptPermissionOffer(token))
.then(realmUrl => {
TestCase.assertEqual(realmUrl, `/${user1.identity}/test`);
return user2.getGrantedPermissions('any')
.then(permissions => {
TestCase.assertEqual(permissions[1].path, `/${user1.identity}/test`);
TestCase.assertEqual(permissions[1].mayRead, true);
TestCase.assertEqual(permissions[1].mayWrite, false);
TestCase.assertEqual(permissions[1].mayManage, false);
});
return realmUrl;
})
.then(repeatUntil(() => user2.getGrantedPermissions('any'),
permissions => permissions.length > 1))
.then(permissions => {
TestCase.assertEqual(permissions[1].path, `/${user1.identity}/test`);
TestCase.assertEqual(permissions[1].mayRead, true);
TestCase.assertEqual(permissions[1].mayWrite, false);
TestCase.assertEqual(permissions[1].mayManage, false);
});
});
},
testInvalidatePermissionOffer() {
return createUsersWithTestRealms(2)
.then(([user1, user2]) => {

View File

@ -18,9 +18,9 @@
'use strict';
var Realm = require('realm');
var TestCase = require('./asserts');
var schemas = require('./schemas');
const Realm = require('realm');
const TestCase = require('./asserts');
const schemas = require('./schemas');
let pathSeparator = '/';
if (typeof process === 'object' && process.platform === 'win32') {
@ -29,7 +29,7 @@ if (typeof process === 'object' && process.platform === 'win32') {
module.exports = {
testRealmConstructor: function() {
var realm = new Realm({schema: []});
const realm = new Realm({schema: []});
TestCase.assertTrue(realm instanceof Realm);
TestCase.assertEqual(typeof Realm, 'function');
@ -37,52 +37,43 @@ module.exports = {
},
testRealmConstructorPath: function() {
TestCase.assertThrows(function() {
new Realm('');
}, 'Realm cannot be created with an invalid path');
TestCase.assertThrows(function() {
new Realm('test1.realm', 'invalidArgument');
}, 'Realm constructor can only have 0 or 1 argument(s)');
TestCase.assertThrows(() => new Realm('')); // the message for this error is platform-specific
TestCase.assertThrowsContaining(() => new Realm('test1.realm', 'invalidArgument'),
"Invalid arguments when constructing 'Realm'");
var defaultRealm = new Realm({schema: []});
const defaultRealm = new Realm({schema: []});
TestCase.assertEqual(defaultRealm.path, Realm.defaultPath);
var defaultRealm2 = new Realm();
const defaultRealm2 = new Realm();
TestCase.assertEqual(defaultRealm2.path, Realm.defaultPath);
var defaultDir = Realm.defaultPath.substring(0, Realm.defaultPath.lastIndexOf(pathSeparator) + 1)
var testPath = 'test1.realm';
var realm = new Realm({schema: [], path: testPath});
const defaultDir = Realm.defaultPath.substring(0, Realm.defaultPath.lastIndexOf(pathSeparator) + 1);
const testPath = 'test1.realm';
const realm = new Realm({schema: [], path: testPath});
TestCase.assertEqual(realm.path, defaultDir + testPath);
var testPath2 = 'test2.realm';
var realm2 = new Realm({schema: [], path: testPath2});
const testPath2 = 'test2.realm';
const realm2 = new Realm({schema: [], path: testPath2});
TestCase.assertEqual(realm2.path, defaultDir + testPath2);
},
testRealmConstructorSchemaVersion: function() {
var defaultRealm = new Realm({schema: []});
const defaultRealm = new Realm({schema: []});
TestCase.assertEqual(defaultRealm.schemaVersion, 0);
TestCase.assertThrows(function() {
new Realm({schemaVersion: 1, schema: []});
}, "Realm already opened at a different schema version");
TestCase.assertThrowsContaining(() => new Realm({schemaVersion: 1, schema: []}),
"already opened with different schema version.");
TestCase.assertEqual(new Realm().schemaVersion, 0);
TestCase.assertEqual(new Realm({schemaVersion: 0}).schemaVersion, 0);
var realm = new Realm({path: 'test1.realm', schema: [], schemaVersion: 1});
let realm = new Realm({path: 'test1.realm', schema: [], schemaVersion: 1});
TestCase.assertEqual(realm.schemaVersion, 1);
TestCase.assertEqual(realm.schema.length, 0);
realm.close();
// FIXME - enable once realm initialization supports schema comparison
// TestCase.assertThrows(function() {
// realm = new Realm({path: testPath, schema: [schemas.TestObject], schemaVersion: 1});
// }, "schema changes require updating the schema version");
realm = new Realm({path: 'test1.realm', schema: [schemas.TestObject], schemaVersion: 2});
realm.write(function() {
realm.write(() => {
realm.create('TestObject', {doubleCol: 1});
});
TestCase.assertEqual(realm.objects('TestObject')[0].doubleCol, 1);
@ -91,41 +82,31 @@ module.exports = {
},
testRealmConstructorDynamicSchema: function() {
var realm = new Realm({schema: [schemas.TestObject]});
realm.write(function() {
let realm = new Realm({schema: [schemas.TestObject]});
realm.write(() => {
realm.create('TestObject', [1])
});
realm.close();
realm = new Realm();
var objects = realm.objects('TestObject');
const objects = realm.objects('TestObject');
TestCase.assertEqual(objects.length, 1);
TestCase.assertEqual(objects[0].doubleCol, 1.0);
},
testRealmConstructorSchemaValidation: function() {
TestCase.assertThrows(function() {
new Realm({schema: schemas.AllTypes});
}, 'The schema should be an array');
TestCase.assertThrows(function() {
new Realm({schema: ['SomeType']});
}, 'The schema should be an array of objects');
TestCase.assertThrows(function() {
new Realm({schema: [{}]});
}, 'The schema should be an array of ObjectSchema objects');
TestCase.assertThrows(function() {
new Realm({schema: [{name: 'SomeObject'}]});
}, 'The schema should be an array of ObjectSchema objects');
TestCase.assertThrows(function() {
new Realm({schema: [{properties: {intCol: 'int'}}]});
}, 'The schema should be an array of ObjectSchema objects');
TestCase.assertThrowsContaining(() => new Realm({schema: schemas.AllTypes}), "schema must be of type 'array', got");
TestCase.assertThrowsContaining(() => new Realm({schema: ['SomeType']}),
"Failed to read ObjectSchema: JS value must be of type 'object', got (SomeType)");
TestCase.assertThrowsContaining(() => new Realm({schema: [{}]}),
"Failed to read ObjectSchema: name must be of type 'string', got (undefined)");
TestCase.assertThrowsContaining(() => new Realm({schema: [{name: 'SomeObject'}]}),
"Failed to read ObjectSchema: properties must be of type 'object', got (undefined)");
TestCase.assertThrowsContaining(() => new Realm({schema: [{properties: {intCol: 'int'}}]}),
"Failed to read ObjectSchema: name must be of type 'string', got (undefined)");
// linkingObjects property where the source property is missing
TestCase.assertThrows(function() {
TestCase.assertThrowsContaining(() => {
new Realm({schema: [{
name: 'InvalidObject',
properties: {
@ -135,7 +116,7 @@ module.exports = {
}, "Property 'InvalidObject.nosuchproperty' declared as origin of linking objects property 'InvalidObject.linkingObjects' does not exist");
// linkingObjects property where the source property is not a link
TestCase.assertThrows(function() {
TestCase.assertThrowsContaining(() => {
new Realm({schema: [{
name: 'InvalidObject',
properties: {
@ -146,7 +127,7 @@ module.exports = {
}, "Property 'InvalidObject.integer' declared as origin of linking objects property 'InvalidObject.linkingObjects' is not a link")
// linkingObjects property where the source property links elsewhere
TestCase.assertThrows(function() {
TestCase.assertThrowsContaining(() => {
new Realm({schema: [{
name: 'InvalidObject',
properties: {
@ -165,7 +146,7 @@ module.exports = {
testRealmConstructorInMemory: function() {
// open in-memory realm instance
const realm1 = new Realm({inMemory: true, schema: [schemas.TestObject]});
realm1.write(function() {
realm1.write(() => {
realm1.create('TestObject', [1])
});
TestCase.assertEqual(realm1.inMemory, true);
@ -187,28 +168,25 @@ module.exports = {
TestCase.assertEqual(realm3.schema.length, 0);
// try to open the same realm in persistent mode (should fail as you cannot mix modes)
TestCase.assertThrows(function() {
const realm4 = new Realm({});
});
TestCase.assertThrowsContaining(() => new Realm({}), 'already opened with different inMemory settings.');
},
testRealmConstructorReadOnly: function() {
var realm = new Realm({schema: [schemas.TestObject]});
realm.write(function() {
let realm = new Realm({schema: [schemas.TestObject]});
realm.write(() => {
realm.create('TestObject', [1])
});
TestCase.assertEqual(realm.readOnly, false);
realm.close();
realm = new Realm({readOnly: true, schema: [schemas.TestObject]});
var objects = realm.objects('TestObject');
const objects = realm.objects('TestObject');
TestCase.assertEqual(objects.length, 1);
TestCase.assertEqual(objects[0].doubleCol, 1.0);
TestCase.assertEqual(realm.readOnly, true);
TestCase.assertThrows(function() {
realm.write(function() {});
});
TestCase.assertThrowsContaining(() => realm.write(() => {}),
"Can't perform transactions on read-only Realms.");
realm.close();
realm = new Realm({readOnly: true});
@ -217,12 +195,12 @@ module.exports = {
},
testDefaultPath: function() {
var defaultPath = Realm.defaultPath;
var defaultRealm = new Realm({schema: []});
const defaultPath = Realm.defaultPath;
let defaultRealm = new Realm({schema: []});
TestCase.assertEqual(defaultRealm.path, Realm.defaultPath);
try {
var newPath = Realm.defaultPath.substring(0, defaultPath.lastIndexOf(pathSeparator) + 1) + 'default2.realm';
const newPath = `${Realm.defaultPath.substring(0, defaultPath.lastIndexOf(pathSeparator) + 1)}default2.realm`;
Realm.defaultPath = newPath;
defaultRealm = new Realm({schema: []});
TestCase.assertEqual(defaultRealm.path, newPath, "should use updated default realm path");
@ -235,7 +213,7 @@ module.exports = {
testRealmSchemaVersion: function() {
TestCase.assertEqual(Realm.schemaVersion(Realm.defaultPath), -1);
var realm = new Realm({schema: []});
let realm = new Realm({schema: []});
TestCase.assertEqual(realm.schemaVersion, 0);
TestCase.assertEqual(Realm.schemaVersion(Realm.defaultPath), 0);
@ -245,69 +223,64 @@ module.exports = {
},
testRealmWrite: function() {
var realm = new Realm({schema: [schemas.IntPrimary, schemas.AllTypes, schemas.TestObject, schemas.LinkToAllTypes]});
const realm = new Realm({schema: [schemas.IntPrimary, schemas.AllTypes, schemas.TestObject, schemas.LinkToAllTypes]});
// exceptions should be propogated
TestCase.assertThrows(function() {
realm.write(function() {
realm.invalid();
});
});
TestCase.assertThrowsContaining(() => realm.write(() => { throw new Error('Inner exception message'); }),
'Inner exception message');
// writes should be possible after caught exception
realm.write(function() {
realm.write(() => {
realm.create('TestObject', {doubleCol: 1});
});
TestCase.assertEqual(1, realm.objects('TestObject').length);
realm.write(function() {
realm.write(() => {
// nested transactions not supported
TestCase.assertThrows(function() {
realm.write(function() {});
});
TestCase.assertThrowsContaining(() => realm.write(() => {}),
'The Realm is already in a write transaction');
});
},
testRealmCreate: function() {
var realm = new Realm({schema: [schemas.TestObject]});
const realm = new Realm({schema: [schemas.TestObject]});
TestCase.assertThrows(function() {
realm.create('TestObject', {doubleCol: 1});
}, 'can only create inside a write transaction');
TestCase.assertThrowsContaining(() => realm.create('TestObject', {doubleCol: 1}),
"Cannot modify managed objects outside of a write transaction.");
realm.write(function() {
realm.write(() => {
realm.create('TestObject', {doubleCol: 1});
realm.create('TestObject', {doubleCol: 2});
});
var objects = realm.objects('TestObject');
const objects = realm.objects('TestObject');
TestCase.assertEqual(objects.length, 2, 'wrong object count');
TestCase.assertEqual(objects[0].doubleCol, 1, 'wrong object property value');
TestCase.assertEqual(objects[1].doubleCol, 2, 'wrong object property value');
},
testRealmCreatePrimaryKey: function() {
var realm = new Realm({schema: [schemas.IntPrimary]});
const realm = new Realm({schema: [schemas.IntPrimary]});
realm.write(function() {
var obj0 = realm.create('IntPrimaryObject', {
realm.write(() => {
const obj0 = realm.create('IntPrimaryObject', {
primaryCol: 0,
valueCol: 'val0',
});
TestCase.assertThrows(function() {
TestCase.assertThrowsContaining(() => {
realm.create('IntPrimaryObject', {
primaryCol: 0,
valueCol: 'val0',
});
}, 'cannot create object with conflicting primary key');
}, "Attempting to create an object of type 'IntPrimaryObject' with an existing primary key value '0'.");
realm.create('IntPrimaryObject', {
primaryCol: 1,
valueCol: 'val1',
}, true);
var objects = realm.objects('IntPrimaryObject');
const objects = realm.objects('IntPrimaryObject');
TestCase.assertEqual(objects.length, 2);
realm.create('IntPrimaryObject', {
@ -324,13 +297,13 @@ module.exports = {
},
testRealmCreateOptionals: function() {
var realm = new Realm({schema: [schemas.NullableBasicTypes, schemas.LinkTypes, schemas.TestObject]});
var basic, links;
realm.write(function() {
const realm = new Realm({schema: [schemas.NullableBasicTypes, schemas.LinkTypes, schemas.TestObject]});
let basic, links;
realm.write(() => {
basic = realm.create('NullableBasicTypesObject', {});
links = realm.create('LinkTypesObject', {});
});
for (var name in schemas.NullableBasicTypes.properties) {
for (const name in schemas.NullableBasicTypes.properties) {
TestCase.assertEqual(basic[name], null);
}
TestCase.assertEqual(links.objectCol, null);
@ -338,9 +311,9 @@ module.exports = {
},
testRealmCreateUpsert: function() {
var realm = new Realm({schema: [schemas.IntPrimary, schemas.StringPrimary, schemas.AllTypes, schemas.TestObject, schemas.LinkToAllTypes]});
realm.write(function() {
var values = {
const realm = new Realm({schema: [schemas.IntPrimary, schemas.StringPrimary, schemas.AllTypes, schemas.TestObject, schemas.LinkToAllTypes]});
realm.write(() => {
const values = {
primaryCol: '0',
boolCol: true,
intCol: 1,
@ -353,13 +326,12 @@ module.exports = {
arrayCol: [],
};
var obj0 = realm.create('AllTypesObject', values);
const obj0 = realm.create('AllTypesObject', values);
TestCase.assertThrows(function() {
realm.create('AllTypesObject', values);
}, 'cannot create object with conflicting primary key');
TestCase.assertThrowsContaining(() => realm.create('AllTypesObject', values),
"Attempting to create an object of type 'AllTypesObject' with an existing primary key value '0'.");
var obj1 = realm.create('AllTypesObject', {
const obj1 = realm.create('AllTypesObject', {
primaryCol: '1',
boolCol: false,
intCol: 2,
@ -372,7 +344,7 @@ module.exports = {
arrayCol: [{doubleCol: 2}],
}, true);
var objects = realm.objects('AllTypesObject');
const objects = realm.objects('AllTypesObject');
TestCase.assertEqual(objects.length, 2);
realm.create('AllTypesObject', {
@ -427,7 +399,7 @@ module.exports = {
TestCase.assertEqual(obj1.objectCol, null);
// test with string primaries
var obj =realm.create('StringPrimaryObject', {
const obj =realm.create('StringPrimaryObject', {
primaryCol: '0',
valueCol: 0
});
@ -442,12 +414,12 @@ module.exports = {
},
testRealmWithIndexedProperties: function() {
var realm = new Realm({schema: [schemas.IndexedTypes]});
realm.write(function() {
const realm = new Realm({schema: [schemas.IndexedTypes]});
realm.write(() => {
realm.create('IndexedTypesObject', {boolCol: true, intCol: 1, stringCol: '1', dateCol: new Date(1)});
});
var NotIndexed = {
const NotIndexed = {
name: 'NotIndexedObject',
properties: {
floatCol: {type: 'float', indexed: false}
@ -456,23 +428,23 @@ module.exports = {
new Realm({schema: [NotIndexed], path: '1.realm'});
var IndexedSchema = {
const IndexedSchema = {
name: 'IndexedSchema',
};
TestCase.assertThrows(function() {
TestCase.assertThrowsContaining(() => {
IndexedSchema.properties = { floatCol: {type: 'float', indexed: true} };
new Realm({schema: [IndexedSchema], path: '2.realm'});
});
}, "Property 'IndexedSchema.floatCol' of type 'float' cannot be indexed.");
TestCase.assertThrows(function() {
TestCase.assertThrowsContaining(() => {
IndexedSchema.properties = { doubleCol: {type: 'double', indexed: true} }
new Realm({schema: [IndexedSchema], path: '3.realm'});
});
}, "Property 'IndexedSchema.doubleCol' of type 'double' cannot be indexed.");
TestCase.assertThrows(function() {
TestCase.assertThrowsContaining(() => {
IndexedSchema.properties = { dataCol: {type: 'data', indexed: true} }
new Realm({schema: [IndexedSchema], path: '4.realm'});
});
}, "Property 'IndexedSchema.dataCol' of type 'data' cannot be indexed.");
// primary key
IndexedSchema.properties = { intCol: {type: 'int', indexed: true} };
@ -483,11 +455,11 @@ module.exports = {
},
testRealmCreateWithDefaults: function() {
var realm = new Realm({schema: [schemas.DefaultValues, schemas.TestObject]});
let realm = new Realm({schema: [schemas.DefaultValues, schemas.TestObject]});
var createAndTestObject = function() {
var obj = realm.create('DefaultValuesObject', {});
var properties = schemas.DefaultValues.properties;
const createAndTestObject = () => {
const obj = realm.create('DefaultValuesObject', {});
const properties = schemas.DefaultValues.properties;
TestCase.assertEqual(obj.boolCol, properties.boolCol.default);
TestCase.assertEqual(obj.intCol, properties.intCol.default);
@ -510,17 +482,17 @@ module.exports = {
},
testRealmCreateWithChangingDefaults: function() {
var objectSchema = {
const objectSchema = {
name: 'IntObject',
properties: {
intCol: {type: 'int', default: 1},
}
};
var realm = new Realm({schema: [objectSchema]});
let realm = new Realm({schema: [objectSchema]});
var createAndTestObject = function() {
var object = realm.create('IntObject', {});
const createAndTestObject = () => {
const object = realm.create('IntObject', {});
TestCase.assertEqual(object.intCol, objectSchema.properties.intCol.default);
};
@ -533,7 +505,7 @@ module.exports = {
},
testRealmCreateWithConstructor: function() {
var customCreated = 0;
let customCreated = 0;
function CustomObject() {
customCreated++;
@ -548,9 +520,8 @@ module.exports = {
function InvalidObject() {
return {};
}
TestCase.assertThrows(function() {
new Realm({schema: [InvalidObject]});
});
TestCase.assertThrowsContaining(() => new Realm({schema: [InvalidObject]}),
"Realm object constructor must have a 'schema' property.");
InvalidObject.schema = {
name: 'InvalidObject',
@ -559,10 +530,10 @@ module.exports = {
}
};
var realm = new Realm({schema: [CustomObject, InvalidObject]});
let realm = new Realm({schema: [CustomObject, InvalidObject]});
realm.write(function() {
var object = realm.create('CustomObject', {intCol: 1});
realm.write(() => {
let object = realm.create('CustomObject', {intCol: 1});
TestCase.assertTrue(object instanceof CustomObject);
TestCase.assertTrue(Object.getPrototypeOf(object) == CustomObject.prototype);
TestCase.assertEqual(customCreated, 1);
@ -574,21 +545,21 @@ module.exports = {
TestCase.assertEqual(customCreated, 2);
});
TestCase.assertThrows(function() {
realm.write(function() {
TestCase.assertThrowsContaining(() => {
realm.write(() => {
realm.create('InvalidObject', {intCol: 1});
});
});
}, 'Realm object constructor must not return another value');
// Only the original constructor should be valid.
function InvalidCustomObject() {}
InvalidCustomObject.schema = CustomObject.schema;
TestCase.assertThrows(function() {
realm.write(function() {
TestCase.assertThrowsContaining(() => {
realm.write(() => {
realm.create(InvalidCustomObject, {intCol: 1});
});
});
}, 'Constructor was not registered in the schema for this Realm');
// The constructor should still work when creating another Realm instance.
realm = new Realm();
@ -605,9 +576,9 @@ module.exports = {
}
};
var realm = new Realm({schema: [CustomObject]});
realm.write(function() {
var object = realm.create('CustomObject', {intCol: 1});
let realm = new Realm({schema: [CustomObject]});
realm.write(() => {
const object = realm.create('CustomObject', {intCol: 1});
TestCase.assertTrue(object instanceof CustomObject);
});
@ -615,30 +586,28 @@ module.exports = {
NewCustomObject.schema = CustomObject.schema;
realm = new Realm({schema: [NewCustomObject]});
realm.write(function() {
var object = realm.create('CustomObject', {intCol: 1});
realm.write(() => {
const object = realm.create('CustomObject', {intCol: 1});
TestCase.assertTrue(object instanceof NewCustomObject);
});
},
testRealmDelete: function() {
var realm = new Realm({schema: [schemas.TestObject]});
const realm = new Realm({schema: [schemas.TestObject]});
realm.write(function() {
for (var i = 0; i < 10; i++) {
realm.write(() => {
for (let i = 0; i < 10; i++) {
realm.create('TestObject', {doubleCol: i});
}
});
var objects = realm.objects('TestObject');
TestCase.assertThrows(function() {
realm.delete(objects[0]);
}, 'can only delete in a write transaction');
const objects = realm.objects('TestObject');
TestCase.assertThrowsContaining(() => realm.delete(objects[0]),
"Can only delete objects within a transaction.");
realm.write(function() {
TestCase.assertThrows(function() {
realm.delete();
});
realm.write(() => {
TestCase.assertThrowsContaining(() => realm.delete(),
"object must be of type 'object', got (undefined)");
realm.delete(objects[0]);
TestCase.assertEqual(objects.length, 9, 'wrong object count');
@ -650,24 +619,23 @@ module.exports = {
TestCase.assertEqual(objects[0].doubleCol, 7, "wrong property value");
TestCase.assertEqual(objects[1].doubleCol, 8, "wrong property value");
var threeObjects = realm.objects('TestObject').filtered("doubleCol < 5");
const threeObjects = realm.objects('TestObject').filtered("doubleCol < 5");
TestCase.assertEqual(threeObjects.length, 3, "wrong results count");
realm.delete(threeObjects);
TestCase.assertEqual(objects.length, 4, 'wrong object count');
TestCase.assertEqual(threeObjects.length, 0, 'threeObject should have been deleted');
var o = objects[0];
const o = objects[0];
realm.delete(o);
TestCase.assertThrows(function() {
realm.delete(o);
});
TestCase.assertThrowsContaining(() => realm.delete(o),
'Object is invalid. Either it has been previously deleted or the Realm it belongs to has been closed.');
});
},
testDeleteAll: function() {
var realm = new Realm({schema: [schemas.TestObject, schemas.IntPrimary]});
const realm = new Realm({schema: [schemas.TestObject, schemas.IntPrimary]});
realm.write(function() {
realm.write(() => {
realm.create('TestObject', {doubleCol: 1});
realm.create('TestObject', {doubleCol: 2});
realm.create('IntPrimaryObject', {primaryCol: 2, valueCol: 'value'});
@ -676,11 +644,10 @@ module.exports = {
TestCase.assertEqual(realm.objects('TestObject').length, 2);
TestCase.assertEqual(realm.objects('IntPrimaryObject').length, 1);
TestCase.assertThrows(function() {
realm.deleteAll();
}, 'can only deleteAll in a write transaction');
TestCase.assertThrowsContaining(() => realm.deleteAll(),
"Can only delete objects within a transaction.");
realm.write(function() {
realm.write(() => {
realm.deleteAll();
});
@ -689,9 +656,9 @@ module.exports = {
},
testRealmObjects: function() {
var realm = new Realm({schema: [schemas.PersonObject, schemas.DefaultValues, schemas.TestObject]});
const realm = new Realm({schema: [schemas.PersonObject, schemas.DefaultValues, schemas.TestObject]});
realm.write(function() {
realm.write(() => {
realm.create('PersonObject', {name: 'Ari', age: 10});
realm.create('PersonObject', {name: 'Tim', age: 11});
realm.create('PersonObject', {name: 'Bjarne', age: 12});
@ -699,77 +666,45 @@ module.exports = {
});
// Should be able to pass constructor for getting objects.
var objects = realm.objects(schemas.PersonObject);
const objects = realm.objects(schemas.PersonObject);
TestCase.assertTrue(objects[0] instanceof schemas.PersonObject);
function InvalidPerson() {}
InvalidPerson.schema = schemas.PersonObject.schema;
TestCase.assertThrows(function() {
realm.objects();
});
TestCase.assertThrows(function() {
realm.objects([]);
});
TestCase.assertThrows(function() {
realm.objects('InvalidClass');
});
TestCase.assertThrows(function() {
realm.objects('PersonObject', 'truepredicate');
});
TestCase.assertThrows(function() {
realm.objects(InvalidPerson);
});
TestCase.assertThrowsContaining(() => realm.objects(), "objectType must be of type 'string', got (undefined)");
TestCase.assertThrowsContaining(() => realm.objects([]), "objectType must be of type 'string', got ()");
TestCase.assertThrowsContaining(() => realm.objects('InvalidClass'), "Object type 'InvalidClass' not found in schema.");
TestCase.assertThrowsContaining(() => realm.objects('PersonObject', 'truepredicate'),
"Invalid arguments: at most 1 expected, but 2 supplied.");
TestCase.assertThrowsContaining(() => realm.objects(InvalidPerson),
'Constructor was not registered in the schema for this Realm');
var person = realm.objects('PersonObject')[0];
var listenerCallback = () => {};
const person = realm.objects('PersonObject')[0];
const listenerCallback = () => {};
realm.addListener('change', listenerCallback);
// The tests below assert that everthing throws when
// operating on a closed realm
realm.close();
TestCase.assertThrows(function() {
console.log("Name: ", person.name);
});
TestCase.assertThrowsContaining(() => console.log("Name: ", person.name),
'Accessing object of type PersonObject which has been invalidated or deleted');
TestCase.assertThrows(function() {
realm.objects('PersonObject');
});
TestCase.assertThrows(function() {
realm.addListener('change', () => {});
});
TestCase.assertThrows(function() {
realm.create('PersonObject', {name: 'Ari', age: 10});
});
TestCase.assertThrows(function() {
realm.delete(person);
});
TestCase.assertThrows(function() {
realm.deleteAll();
});
TestCase.assertThrows(function() {
realm.write(() => {});
});
TestCase.assertThrows(function() {
realm.removeListener('change', listenerCallback);
});
TestCase.assertThrows(function() {
realm.removeAllListeners();
});
TestCase.assertThrowsContaining(() => realm.objects('PersonObject'), 'Cannot access realm that has been closed');
TestCase.assertThrowsContaining(() => realm.addListener('change', () => {}), 'Cannot access realm that has been closed');
TestCase.assertThrowsContaining(() => realm.create('PersonObject', {name: 'Ari', age: 10}), 'Cannot access realm that has been closed');
TestCase.assertThrowsContaining(() => realm.delete(person), 'Cannot access realm that has been closed');
TestCase.assertThrowsContaining(() => realm.deleteAll(), 'Cannot access realm that has been closed');
TestCase.assertThrowsContaining(() => realm.write(() => {}), 'Cannot access realm that has been closed');
TestCase.assertThrowsContaining(() => realm.removeListener('change', listenerCallback), 'Cannot access realm that has been closed');
TestCase.assertThrowsContaining(() => realm.removeAllListeners(), 'Cannot access realm that has been closed');
},
testRealmObjectForPrimaryKey: function() {
var realm = new Realm({schema: [schemas.IntPrimary, schemas.StringPrimary, schemas.TestObject]});
const realm = new Realm({schema: [schemas.IntPrimary, schemas.StringPrimary, schemas.TestObject]});
realm.write(function() {
realm.write(() => {
realm.create('IntPrimaryObject', {primaryCol: 0, valueCol: 'val0'});
realm.create('IntPrimaryObject', {primaryCol: 1, valueCol: 'val1'});
@ -789,36 +724,32 @@ module.exports = {
TestCase.assertEqual(realm.objectForPrimaryKey('StringPrimaryObject', 'val0').valueCol, 0);
TestCase.assertEqual(realm.objectForPrimaryKey('StringPrimaryObject', 'val1').valueCol, 1);
TestCase.assertThrows(function() {
realm.objectForPrimaryKey('TestObject', 0);
});
TestCase.assertThrows(function() {
realm.objectForPrimaryKey();
});
TestCase.assertThrows(function() {
realm.objectForPrimaryKey('IntPrimary');
});
TestCase.assertThrows(function() {
realm.objectForPrimaryKey('InvalidClass', 0);
});
TestCase.assertThrowsContaining(() => realm.objectForPrimaryKey('TestObject', 0),
"'TestObject' does not have a primary key defined");
TestCase.assertThrowsContaining(() => realm.objectForPrimaryKey(),
"objectType must be of type 'string', got (undefined)");
TestCase.assertThrowsContaining(() => realm.objectForPrimaryKey('IntPrimaryObject'),
"Invalid null value for non-nullable primary key.");
TestCase.assertThrowsContaining(() => realm.objectForPrimaryKey('InvalidClass', 0),
"Object type 'InvalidClass' not found in schema.");
},
testNotifications: function() {
var realm = new Realm({schema: []});
var notificationCount = 0;
var notificationName;
const realm = new Realm({schema: []});
let notificationCount = 0;
let notificationName;
realm.addListener('change', function(realm, name) {
realm.addListener('change', (realm, name) => {
notificationCount++;
notificationName = name;
});
TestCase.assertEqual(notificationCount, 0);
realm.write(function() {});
realm.write(() => {});
TestCase.assertEqual(notificationCount, 1);
TestCase.assertEqual(notificationName, 'change');
var secondNotificationCount = 0;
let secondNotificationCount = 0;
function secondNotification() {
secondNotificationCount++;
}
@ -827,39 +758,37 @@ module.exports = {
realm.addListener('change', secondNotification);
realm.addListener('change', secondNotification);
realm.write(function() {});
realm.write(() => {});
TestCase.assertEqual(notificationCount, 2);
TestCase.assertEqual(secondNotificationCount, 1);
realm.removeListener('change', secondNotification);
realm.write(function() {});
realm.write(() => {});
TestCase.assertEqual(notificationCount, 3);
TestCase.assertEqual(secondNotificationCount, 1);
realm.removeAllListeners();
realm.write(function() {});
realm.write(() => {});
TestCase.assertEqual(notificationCount, 3);
TestCase.assertEqual(secondNotificationCount, 1);
TestCase.assertThrows(function() {
realm.addListener('invalid', function() {});
TestCase.assertThrowsContaining(() => realm.addListener('invalid', () => {}),
"Only the 'change' notification name is supported.");
realm.addListener('change', () => {
throw new Error('expected error message');
});
realm.addListener('change', function() {
throw new Error('error');
});
TestCase.assertThrows(function() {
realm.write(function() {});
});
TestCase.assertThrowsContaining(() => realm.write(() => {}),
'expected error message');
},
testSchema: function() {
var originalSchema = [schemas.TestObject, schemas.BasicTypes, schemas.NullableBasicTypes, schemas.IndexedTypes, schemas.IntPrimary,
const originalSchema = [schemas.TestObject, schemas.BasicTypes, schemas.NullableBasicTypes, schemas.IndexedTypes, schemas.IntPrimary,
schemas.PersonObject, schemas.LinkTypes, schemas.LinkingObjectsObject];
var schemaMap = {};
originalSchema.forEach(function(objectSchema) {
const schemaMap = {};
originalSchema.forEach(objectSchema => {
if (objectSchema.schema) { // for PersonObject
schemaMap[objectSchema.schema.name] = objectSchema;
} else {
@ -867,9 +796,9 @@ module.exports = {
}
});
var realm = new Realm({schema: originalSchema});
const realm = new Realm({schema: originalSchema});
var schema = realm.schema;
const schema = realm.schema;
TestCase.assertEqual(schema.length, originalSchema.length);
function isString(val) {
@ -877,15 +806,15 @@ module.exports = {
}
function verifyObjectSchema(returned) {
var original = schemaMap[returned.name];
let original = schemaMap[returned.name];
if (original.schema) {
original = original.schema;
}
TestCase.assertEqual(returned.primaryKey, original.primaryKey);
for (var propName in returned.properties) {
var prop1 = returned.properties[propName];
var prop2 = original.properties[propName];
for (const propName in returned.properties) {
const prop1 = returned.properties[propName];
const prop2 = original.properties[propName];
if (prop1.type == 'object') {
TestCase.assertEqual(prop1.objectType, isString(prop2) ? prop2 : prop2.objectType);
TestCase.assertEqual(prop1.optional, true);
@ -908,7 +837,7 @@ module.exports = {
}
}
for (var i = 0; i < originalSchema.length; i++) {
for (let i = 0; i < originalSchema.length; i++) {
verifyObjectSchema(schema[i]);
}
},
@ -916,12 +845,12 @@ module.exports = {
testCopyBundledRealmFiles: function() {
Realm.copyBundledRealmFiles();
var realm = new Realm({path: 'dates-v5.realm', schema: [schemas.DateObject]});
let realm = new Realm({path: 'dates-v5.realm', schema: [schemas.DateObject]});
TestCase.assertEqual(realm.objects('Date').length, 2);
TestCase.assertEqual(realm.objects('Date')[0].currentDate.getTime(), 1462500087955);
var newDate = new Date(1);
realm.write(function() {
const newDate = new Date(1);
realm.write(() => {
realm.objects('Date')[0].currentDate = newDate;
});
realm.close();
@ -933,33 +862,33 @@ module.exports = {
},
testErrorMessageFromInvalidWrite: function() {
var realm = new Realm({schema: [schemas.PersonObject]});
const realm = new Realm({schema: [schemas.PersonObject]});
TestCase.assertThrowsException(function() {
realm.write(function () {
var p1 = realm.create('PersonObject', { name: 'Ari', age: 10 });
TestCase.assertThrowsException(() => {
realm.write(() => {
const p1 = realm.create('PersonObject', { name: 'Ari', age: 10 });
p1.age = "Ten";
});
}, new Error("PersonObject.age must be of type 'number', got (Ten)"));
},
testErrorMessageFromInvalidCreate: function() {
var realm = new Realm({schema: [schemas.PersonObject]});
const realm = new Realm({schema: [schemas.PersonObject]});
TestCase.assertThrowsException(function() {
realm.write(function () {
var p1 = realm.create('PersonObject', { name: 'Ari', age: 'Ten' });
TestCase.assertThrowsException(() => {
realm.write(() => {
const p1 = realm.create('PersonObject', { name: 'Ari', age: 'Ten' });
});
}, new Error("PersonObject.age must be of type 'number', got (Ten)"));
},
testValidTypesForListProperties: function() {
var realm = new Realm({schema: [schemas.PersonObject]});
realm.write(function () {
var p1 = realm.create('PersonObject', { name: 'Ari', age: 10 });
var p2 = realm.create('PersonObject', { name: 'Harold', age: 55, children: realm.objects('PersonObject').filtered('age < 15') });
const realm = new Realm({schema: [schemas.PersonObject]});
realm.write(() => {
const p1 = realm.create('PersonObject', { name: 'Ari', age: 10 });
const p2 = realm.create('PersonObject', { name: 'Harold', age: 55, children: realm.objects('PersonObject').filtered('age < 15') });
TestCase.assertEqual(p2.children.length, 1);
var p3 = realm.create('PersonObject', { name: 'Wendy', age: 52, children: p2.children });
const p3 = realm.create('PersonObject', { name: 'Wendy', age: 52, children: p2.children });
TestCase.assertEqual(p3.children.length, 1);
});
},
@ -1007,13 +936,13 @@ module.exports = {
},
testCompact: function() {
var wasCalled = false;
let wasCalled = false;
const count = 1000;
// create compactable Realm
const realm1 = new Realm({schema: [schemas.StringOnly]});
realm1.write(() => {
realm1.create('StringOnlyObject', { stringCol: 'A' });
for (var i = 0; i < count; i++) {
for (let i = 0; i < count; i++) {
realm1.create('StringOnlyObject', { stringCol: 'ABCDEFG' });
}
realm1.create('StringOnlyObject', { stringCol: 'B' });
@ -1021,7 +950,7 @@ module.exports = {
realm1.close();
// open Realm and see if it is compacted
var shouldCompact = function(totalBytes, usedBytes) {
const shouldCompact = (totalBytes, usedBytes) => {
wasCalled = true;
const fiveHundredKB = 500*1024;
return (totalBytes > fiveHundredKB) && (usedBytes / totalBytes) < 0.2;
@ -1049,9 +978,9 @@ module.exports = {
testManualCompactInWrite: function() {
const realm = new Realm({schema: [schemas.StringOnly]});
realm.write(() => {
TestCase.assertThrows(() => {
TestCase.assertThrowsContaining(() => {
realm.compact();
});
}, 'Cannot compact a Realm within a transaction.');
});
TestCase.assertTrue(realm.empty);
},
@ -1059,14 +988,14 @@ module.exports = {
testManualCompactMultipleInstances: function() {
const realm1 = new Realm({schema: [schemas.StringOnly]});
const realm2 = new Realm({schema: [schemas.StringOnly]});
TestCase.assertThrows(realm1.compact());
TestCase.assertTrue(realm1.compact());
},
testRealmDeleteFileDefaultConfigPath: function() {
const config = {schema: [schemas.TestObject]};
const realm = new Realm(config);
realm.write(function() {
realm.write(() => {
realm.create('TestObject', {doubleCol: 1});
});
@ -1084,7 +1013,7 @@ module.exports = {
const config = {schema: [schemas.TestObject], path: 'test-realm-delete-file.realm'};
const realm = new Realm(config);
realm.write(function() {
realm.write(() => {
realm.create('TestObject', {doubleCol: 1});
});

View File

@ -383,23 +383,23 @@ module.exports = {
TestCase.assertEqual(snapshot.length, 0);
});
},
testResultsFindIndexOfObject: function() {
var realm = new Realm({schema: [schemas.TestObject]});
var object1, object2, object3;
realm.write(function() {
object1 = realm.create('TestObject', {doubleCol: 1});
object2 = realm.create('TestObject', {doubleCol: 2});
object3 = realm.create('TestObject', {doubleCol: 2});
});
// Search in base table
const objects = realm.objects('TestObject');
TestCase.assertEqual(objects.indexOf(object1), 0);
TestCase.assertEqual(objects.indexOf(object2), 1);
TestCase.assertEqual(objects.indexOf(object3), 2);
// Search in filtered query
const results = objects.filtered("doubleCol == 2");
TestCase.assertEqual(results.indexOf(object1), -1);
@ -408,7 +408,7 @@ module.exports = {
const nonRealmObject = {test: "this is an object"};
TestCase.assertEqual(objects.indexOf(nonRealmObject), -1);
// Searching for object from the wrong realm
var realm2 = new Realm({path: '2.realm', schema: realm.schema});
var object4;
@ -421,29 +421,40 @@ module.exports = {
},
testAddListener: function() {
return new Promise((resolve, _reject) => {
var realm = new Realm({ schema: [schemas.TestObject] });
if (typeof navigator !== 'undefined' && /Chrome/.test(navigator.userAgent)) { // eslint-disable-line no-undef
// FIXME: async callbacks do not work correctly in Chrome debugging mode
return;
}
realm.write(() => {
realm.create('TestObject', { doubleCol: 1 });
realm.create('TestObject', { doubleCol: 2 });
realm.create('TestObject', { doubleCol: 3 });
});
const realm = new Realm({ schema: [schemas.TestObject] });
realm.write(() => {
realm.create('TestObject', { doubleCol: 1 });
realm.create('TestObject', { doubleCol: 2 });
realm.create('TestObject', { doubleCol: 3 });
});
let resolve, first = true;
return new Promise((r, _reject) => {
resolve = r;
realm.objects('TestObject').addListener((testObjects, changes) => {
// TODO: First notification is empty, so perform these
// assertions on the second call. However, there is a race condition
// in React Native, so find a way to do this in a robust way.
//TestCase.assertEqual(testObjects.length, 4);
//TestCase.assertEqual(changes.insertions.length, 1);
if (first) {
TestCase.assertEqual(testObjects.length, 3);
TestCase.assertEqual(changes.insertions.length, 0);
}
else {
TestCase.assertEqual(testObjects.length, 4);
TestCase.assertEqual(changes.insertions.length, 1);
}
first = false;
resolve();
});
realm.write(() => {
realm.create('TestObject', { doubleCol: 1 });
}).then(() => {
return new Promise((r, _reject) => {
realm.write(() => {
realm.create('TestObject', { doubleCol: 1 });
});
resolve = r;
});
})
});
}
};

View File

@ -168,6 +168,7 @@ extern NSMutableArray *RCTGetModuleClasses(void);
+ (void)waitForCondition:(BOOL *)condition description:(NSString *)description {
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:30.0];
RCTBridge *bridge = [self currentBridge];
while (!*condition) {
if ([timeout timeIntervalSinceNow] < 0) {
@ -180,6 +181,7 @@ extern NSMutableArray *RCTGetModuleClasses(void);
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
[runLoop runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
[NSThread sleepForTimeInterval:0.01]; // Bad things may happen without some sleep.
[bridge.eventDispatcher sendAppEventWithName:@"realm-dummy" body:nil]; // Ensure RN has an event loop running
}
}
}