diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b8522b5..a33a8c97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +X.Y.Z Release notes +============================================================= +### Breaking changes +* None. + +### Enhancements +* None. + +### Bug fixes +* [Object Server] A use-after-free bug was fixed which could cause arrays of primitives to behave unexpectedly. + +### Internal +* Updated to Realm Sync 2.2.12. + + 2.2.9 Release notes (2018-2-19) ============================================================= ### Breaking changes diff --git a/dependencies.list b/dependencies.list index 2c1f2364..7ebcc893 100644 --- a/dependencies.list +++ b/dependencies.list @@ -1,5 +1,5 @@ PACKAGE_NAME=realm-js VERSION=2.2.9 REALM_CORE_VERSION=5.1.2 -REALM_SYNC_VERSION=2.2.11 +REALM_SYNC_VERSION=2.2.12 REALM_OBJECT_SERVER_VERSION=2.5.1 diff --git a/tests/js/index.js b/tests/js/index.js index 7aab4946..f7f52436 100644 --- a/tests/js/index.js +++ b/tests/js/index.js @@ -44,7 +44,7 @@ var TESTS = { MigrationTests: require('./migration-tests'), EncryptionTests: require('./encryption-tests'), ObjectIDTests: require('./object-id-tests'), - // GarbageCollectionTests: require('./garbage-collection'), + // Garbagecollectiontests: require('./garbage-collection'), }; // If sync is enabled, run the sync tests diff --git a/tests/js/list-tests.js b/tests/js/list-tests.js index 417cd5b6..72349803 100644 --- a/tests/js/list-tests.js +++ b/tests/js/list-tests.js @@ -37,7 +37,7 @@ module.exports = { TestCase.assertInstanceOf(obj.list, Realm.List); TestCase.assertInstanceOf(obj.list, Realm.Collection); }); - + TestCase.assertThrowsContaining(() => new Realm.List(), 'constructor'); TestCase.assertInstanceOf(Realm.List, Function); }, @@ -1223,4 +1223,83 @@ module.exports = { TestCase.assertThrowsContaining(() => object.list.avg(), "JS value must be of type 'string', got (undefined)"); }, + + testListNested: function() { + const realm = new Realm({schema: [schemas.ParentObject, schemas.NameObject]}); + realm.write(() => { + realm.create('ParentObject', { + id: 1, + name: [ + { family: 'Larsen', given: ['Hans', 'Jørgen'], prefix: [] }, + { family: 'Hansen', given: ['Ib'], prefix: [] } + ] + }); + realm.create('ParentObject', { + id: 2, + name: [ + {family: 'Petersen', given: ['Gurli', 'Margrete'], prefix: [] } + ] + }); + }); + + let objects = realm.objects('ParentObject'); + TestCase.assertEqual(objects.length, 2); + TestCase.assertEqual(objects[0].name.length, 2); + TestCase.assertEqual(objects[0].name[0].given.length, 2); + TestCase.assertEqual(objects[0].name[0].prefix.length, 0); + TestCase.assertEqual(objects[0].name[0].given[0], 'Hans'); + TestCase.assertEqual(objects[0].name[0].given[1], 'Jørgen') + TestCase.assertEqual(objects[0].name[1].given.length, 1); + TestCase.assertEqual(objects[0].name[1].given[0], 'Ib'); + TestCase.assertEqual(objects[0].name[1].prefix.length, 0); + + TestCase.assertEqual(objects[1].name.length, 1); + TestCase.assertEqual(objects[1].name[0].given.length, 2); + TestCase.assertEqual(objects[1].name[0].prefix.length, 0); + TestCase.assertEqual(objects[1].name[0].given[0], 'Gurli'); + TestCase.assertEqual(objects[1].name[0].given[1], 'Margrete'); + }, + + testListNestedFromJSON: function() { + let json = '{"id":1, "name": [{ "family": "Larsen", "given": ["Hans", "Jørgen"], "prefix": [] }, { "family": "Hansen", "given": ["Ib"], "prefix": [] }] }'; + let parent = JSON.parse(json); + const realm = new Realm({schema: [schemas.ParentObject, schemas.NameObject]}); + realm.write(() => { + realm.create('ParentObject', parent); + }); + + let objects = realm.objects('ParentObject'); + TestCase.assertEqual(objects.length, 1); + TestCase.assertEqual(objects[0].name.length, 2); + TestCase.assertEqual(objects[0].name[0].given.length, 2); + TestCase.assertEqual(objects[0].name[0].prefix.length, 0); + TestCase.assertEqual(objects[0].name[0].given[0], 'Hans'); + TestCase.assertEqual(objects[0].name[0].given[1], 'Jørgen'); + + TestCase.assertEqual(objects[0].name[1].given.length, 1); + TestCase.assertEqual(objects[0].name[1].prefix.length, 0); + TestCase.assertEqual(objects[0].name[1].given[0], 'Ib'); + }, + + testMultipleLists: function() { + const realm = new Realm({schema: [schemas.MultiListObject]}); + realm.write(() => { + realm.create('MultiListObject', { id: 0, list1: ["Hello"], list2: ["World"] }); + realm.create('MultiListObject', { id: 1, list1: ["Foo"], list2: ["Bar"] }); + }); + + let objects = realm.objects('MultiListObject'); + TestCase.assertEqual(objects.length, 2); + TestCase.assertEqual(objects[0].id, 0); + TestCase.assertEqual(objects[0].list1.length, 1); + TestCase.assertEqual(objects[0].list1[0], "Hello"); + TestCase.assertEqual(objects[0].list2.length, 1); + TestCase.assertEqual(objects[0].list2[0], "World"); + + TestCase.assertEqual(objects[1].id, 1); + TestCase.assertEqual(objects[1].list1.length, 1); + TestCase.assertEqual(objects[1].list1[0], "Foo"); + TestCase.assertEqual(objects[1].list2.length, 1); + TestCase.assertEqual(objects[1].list2[0], "Bar"); + } }; diff --git a/tests/js/nested-list-helper.js b/tests/js/nested-list-helper.js new file mode 100644 index 00000000..e4b0803c --- /dev/null +++ b/tests/js/nested-list-helper.js @@ -0,0 +1,67 @@ +/* +This script creates new nested objects into a new Realm. +*/ + +'use strict'; +console.log("nested-list-helper started"); +const username = process.argv[3]; +const realmName = process.argv[4]; +const realmModule = process.argv[5]; + +const Realm = require(realmModule); +let schemas = require(process.argv[2]); + +function createObjects(user) { + const config = { + sync: { user, + url: `realm://localhost:9080/~/${realmName}`, + error: err => console.log(err) + }, + schema: [schemas.ParentObject, schemas.NameObject], + }; + + const realm = new Realm(config); + + realm.write(() => { + realm.create('ParentObject', { + id: 1, + name: [ + { family: 'Larsen', given: ['Hans', 'Jørgen'], prefix: [] }, + { family: 'Hansen', given: ['Ib'], prefix: [] } + ] + }); + realm.create('ParentObject', { + id: 2, + name: [ + {family: 'Petersen', given: ['Gurli', 'Margrete'], prefix: [] } + ] + }); + }); + + console.log("JSON: " + JSON.stringify(realm.objects('ParentObject'))); + + let session = realm.syncSession; + return new Promise((resolve, reject) => { + let callback = (transferred, total) => { + if (transferred === total) { + session.removeProgressNotification(callback); + resolve(realm); + } + } + session.addProgressNotification('upload', 'forCurrentlyOutstandingWork', callback); + }); +} + +let registrationError; +Realm.Sync.User.register('http://localhost:9080', username, 'password') + .catch((error) => { + registrationError = JSON.stringify(error); + return Realm.Sync.User.login('http://localhost:9080', username, 'password') + }) + .catch((error) => { + const loginError = JSON.stringify(error); + console.error(`nested-list-helper failed:\n User.register() error:\n${registrationError}\n User.login() error:\n${registrationError}`); + process.exit(-2); + }) + .then((user) => createObjects(user)) + .then(() => process.exit(0)); diff --git a/tests/js/schemas.js b/tests/js/schemas.js index 6d9ecc75..8c153603 100644 --- a/tests/js/schemas.js +++ b/tests/js/schemas.js @@ -280,4 +280,30 @@ exports.LinkingObjectsObject = { links: 'LinkingObjectsObject[]', linkingObjects: {type: 'linkingObjects', objectType: 'LinkingObjectsObject', property: 'links'} } -} +}; + +exports.ParentObject = { + name: 'ParentObject', + properties: { + id: 'int', + name: 'NameObject[]' + } +}; + +exports.NameObject = { + name: 'NameObject', + properties: { + family: 'string', + given: 'string[]', + prefix: 'string[]' + } +}; + +exports.MultiListObject = { + name: 'MultiListObject', + properties: { + 'id': 'int', + 'list1': 'string[]', + 'list2': 'string[]' + } +}; diff --git a/tests/js/session-tests.js b/tests/js/session-tests.js index a127937c..cd0fc323 100644 --- a/tests/js/session-tests.js +++ b/tests/js/session-tests.js @@ -24,6 +24,7 @@ const Realm = require('realm'); const TestCase = require('./asserts'); +let schemas = require('./schemas'); const isNodeProccess = (typeof process === 'object' && process + '' === '[object process]'); @@ -402,6 +403,49 @@ module.exports = { }); }, + testListNestedSync() { + if (!isNodeProccess) { + return; + } + + const username = uuid(); + const realmName = uuid(); + + return runOutOfProcess(__dirname + '/nested-list-helper.js', __dirname + '/schemas.js', username, realmName, REALM_MODULE_PATH) + .then(() => { + return Realm.Sync.User.login('http://localhost:9080', username, 'password').then(user => { + return new Promise((resolve, reject) => { + let config = { + schema: [schemas.ParentObject, schemas.NameObject], + sync: { user, url: `realm://localhost:9080/~/${realmName}` } + }; + Realm.open(config).then(realm => { + let objects = realm.objects('ParentObject'); + + let json = JSON.stringify(objects); + TestCase.assertEqual(json, '{"0":{"id":1,"name":{"0":{"family":"Larsen","given":{"0":"Hans","1":"Jørgen"},"prefix":{}},"1":{"family":"Hansen","given":{"0":"Ib"},"prefix":{}}}},"1":{"id":2,"name":{"0":{"family":"Petersen","given":{"0":"Gurli","1":"Margrete"},"prefix":{}}}}}'); + TestCase.assertEqual(objects.length, 2); + TestCase.assertEqual(objects[0].name.length, 2); + TestCase.assertEqual(objects[0].name[0].given.length, 2); + TestCase.assertEqual(objects[0].name[0].prefix.length, 0); + TestCase.assertEqual(objects[0].name[0].given[0], 'Hans'); + TestCase.assertEqual(objects[0].name[0].given[1], 'Jørgen') + TestCase.assertEqual(objects[0].name[1].given.length, 1); + TestCase.assertEqual(objects[0].name[1].given[0], 'Ib'); + TestCase.assertEqual(objects[0].name[1].prefix.length, 0); + + TestCase.assertEqual(objects[1].name.length, 1); + TestCase.assertEqual(objects[1].name[0].given.length, 2); + TestCase.assertEqual(objects[1].name[0].prefix.length, 0); + TestCase.assertEqual(objects[1].name[0].given[0], 'Gurli'); + TestCase.assertEqual(objects[1].name[0].given[1], 'Margrete'); + resolve(); + }).catch(() => reject()); + }); + }); + }); + }, + testIncompatibleSyncedRealmOpen() { let realm = "sync-v1.realm"; if (isNodeProccess) {