Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent mutating operations on a realm with frozen arguments #942

Merged
merged 9 commits into from
Oct 18, 2022
26 changes: 24 additions & 2 deletions lib/src/realm_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ class Realm implements Finalizable {
/// Throws [RealmException] if there is no write transaction created with [write].
T add<T extends RealmObject>(T object, {bool update = false}) {
if (object.isManaged) {
if (object.realm != this) {
throw RealmError('Object is already managed by another Realm');
}

return object;
}

Expand Down Expand Up @@ -212,19 +216,37 @@ class Realm implements Finalizable {
}

/// Deletes a [RealmObject] from this `Realm`.
void delete<T extends RealmObject>(T object) => realmCore.deleteRealmObject(object);
void delete<T extends RealmObject>(T object) {
if (!object.isManaged) {
throw RealmError('Cannot delete an unmanaged object');
}

if (object.realm != this) {
blagoev marked this conversation as resolved.
Show resolved Hide resolved
throw RealmError('Cannot delete object managed by another Realm');
}

realmCore.deleteRealmObject(object);
}

/// Deletes many [RealmObject]s from this `Realm`.
///
/// Throws [RealmException] if there is no active write transaction.
void deleteMany<T extends RealmObject>(Iterable<T> items) {
if (items is RealmResults<T>) {
if (items.realm != this) {
throw RealmError('Cannot delete objects managed by another Realm');
}
nirinchev marked this conversation as resolved.
Show resolved Hide resolved

realmCore.resultsDeleteAll(items);
} else if (items is RealmList<T>) {
if (items.realm != this) {
throw RealmError('Cannot delete objects managed by another Realm');
}

realmCore.listDeleteAll(items);
} else {
for (T realmObject in items) {
realmCore.deleteRealmObject(realmObject);
delete(realmObject);
blagoev marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down
68 changes: 68 additions & 0 deletions test/realm_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,74 @@ Future<void> main([List<String>? args]) async {
expect(stored.location.name, 'Europe/Copenhagen');
});

test('Realm.add with frozen object argument throws', () {
final realm = getRealm(Configuration.local([Person.schema]));
final frozenPeter = freezeObject(realm.write(() {
return realm.add(Person('Peter'));
}));

realm.write(() {
expect(() => realm.add(frozenPeter), throws<RealmError>('managed by another Realm'));
});
});

test('Realm.delete frozen object throws', () {
final realm = getRealm(Configuration.local([Person.schema]));
final frozenPeter = freezeObject(realm.write(() {
return realm.add(Person('Peter'));
}));

realm.write(() {
expect(() => realm.delete(frozenPeter), throws<RealmError>('managed by another Realm'));
});
});

test('Realm.delete unmanaged object throws', () {
final realm = getRealm(Configuration.local([Person.schema]));
realm.write(() {
expect(() => realm.delete(Person('Peter')), throws<RealmError>('Cannot delete an unmanaged object'));
});
});

test('Realm.deleteMany frozen results throws', () {
final realm = getRealm(Configuration.local([Person.schema]));
realm.write(() {
realm.add(Person('Peter'));
});

final frozenPeople = freezeResults(realm.all<Person>());

realm.write(() {
expect(() => realm.deleteMany(frozenPeople), throws<RealmError>('managed by another Realm'));
nirinchev marked this conversation as resolved.
Show resolved Hide resolved
});
});

test('Realm.deleteMany frozen list throws', () {
final realm = getRealm(Configuration.local([Person.schema, Team.schema]));
final team = realm.write(() {
return realm.add(Team('Team 1', players: [Person('Peter')]));
});

final frozenPlayers = freezeList(team.players);

realm.write(() {
expect(() => realm.deleteMany(frozenPlayers), throws<RealmError>('managed by another Realm'));
});
});

test('Realm.deleteMany regular list with frozen elements throws', () {
final realm = getRealm(Configuration.local([Person.schema]));
final peter = realm.write(() {
return realm.add(Person('Peter'));
});

final frozenPeter = freezeObject(peter);

realm.write(() {
expect(() => realm.deleteMany([peter, frozenPeter]), throws<RealmError>('managed by another Realm'));
});
desistefanova marked this conversation as resolved.
Show resolved Hide resolved
});

test('Realm - open local not encrypted realm with encryption key', () {
openEncryptedRealm(null, generateValidKey());
});
Expand Down