diff --git a/RealmJS.xcodeproj/project.pbxproj b/RealmJS.xcodeproj/project.pbxproj index 6796a8ae..7074fcb2 100644 --- a/RealmJS.xcodeproj/project.pbxproj +++ b/RealmJS.xcodeproj/project.pbxproj @@ -42,6 +42,7 @@ 0270BCD11B7D067300010E03 /* RealmReactModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0270BCD01B7D067300010E03 /* RealmReactModule.m */; }; 02B29A311B7CF86D008A7E6B /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; }; 02B58CCE1AE99D4D009B348C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; }; + 02D456DA1B7E59A500EE1299 /* ArrayTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02D456D91B7E59A500EE1299 /* ArrayTests.js */; }; 02D8D1F71B601984006DB49D /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; }; /* End PBXBuildFile section */ @@ -115,6 +116,7 @@ 02B58CB11AE99CEC009B348C /* RealmJS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RealmJS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 02B58CBC1AE99CEC009B348C /* RealmJSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RealmJSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; + 02D456D91B7E59A500EE1299 /* ArrayTests.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ArrayTests.js; path = tests/ArrayTests.js; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -212,6 +214,7 @@ 02B58CC01AE99CEC009B348C /* RealmJSTests */ = { isa = PBXGroup; children = ( + 02D456D91B7E59A500EE1299 /* ArrayTests.js */, 0270BC781B7D020100010E03 /* Info.plist */, 0270BC791B7D020100010E03 /* ObjectTests.js */, 0270BC7A1B7D020100010E03 /* RealmJSTests.h */, @@ -366,6 +369,7 @@ files = ( 0270BC851B7D020100010E03 /* TestCase.js in Resources */, 0270BC811B7D020100010E03 /* ObjectTests.js in Resources */, + 02D456DA1B7E59A500EE1299 /* ArrayTests.js in Resources */, 0270BC861B7D020100010E03 /* TestObjects.js in Resources */, 0270BC831B7D020100010E03 /* RealmTests.js in Resources */, 0270BC841B7D020100010E03 /* ResultsTests.js in Resources */, diff --git a/src/RJSArray.cpp b/src/RJSArray.cpp index bdd733fb..69f97d39 100644 --- a/src/RJSArray.cpp +++ b/src/RJSArray.cpp @@ -22,21 +22,43 @@ using namespace realm; +size_t ObjectArray::size() { + verify_attached(); + return link_view->size(); +} + +Row ObjectArray::get(std::size_t row_ndx) { + verify_attached(); + if (row_ndx >= link_view->size()) { + throw std::range_error(std::string("Index ") + std::to_string(row_ndx) + " is outside of range 0..." + + std::to_string(link_view->size()) + "."); + } + return link_view->get(row_ndx); +} + +void ObjectArray::verify_attached() { + if (!link_view->is_attached()) { + throw std::runtime_error("Tableview is not attached"); + } + link_view->sync_if_needed(); +} + JSValueRef ArrayGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException) { try { // index subscripting ObjectArray *array = RJSGetInternal(object); + size_t size = array->size(); + std::string indexStr = RJSStringForJSString(propertyName); - size_t size = array->link_view->size(); if (indexStr == "length") { return JSValueMakeNumber(ctx, size); } - long index = std::stol(indexStr); - if (index < 0 || index >= size) { - throw std::range_error("Invalid index '" + indexStr + "'"); - } - return RJSObjectCreate(ctx, Object(array->realm, array->object_schema, array->link_view->get(index))); + return RJSObjectCreate(ctx, Object(array->realm, array->object_schema, array->get(std::stol(indexStr)))); + } + catch (std::invalid_argument &exp) { + // for stol failure this could be another property that is handled externally, so ignore + return NULL; } catch (std::exception &exp) { if (jsException) { @@ -61,7 +83,6 @@ JSObjectRef RJSArrayCreate(JSContextRef ctx, realm::ObjectArray *array) { return RJSWrapObject(ctx, RJSArrayClass(), array); } - JSClassRef RJSArrayClass() { static JSClassRef s_objectClass = RJSCreateWrapperClass("Results", ArrayGetProperty, NULL, NULL, NULL, ArrayPropertyNames); return s_objectClass; diff --git a/src/RJSArray.hpp b/src/RJSArray.hpp index 59f498ca..33c2a5c3 100644 --- a/src/RJSArray.hpp +++ b/src/RJSArray.hpp @@ -27,6 +27,10 @@ namespace realm { SharedRealm realm; ObjectSchema &object_schema; LinkViewRef link_view; + + size_t size(); + Row get(std::size_t row_ndx); + void verify_attached(); }; } diff --git a/src/RJSObject.mm b/src/RJSObject.mm index 0429932d..37284ff5 100644 --- a/src/RJSObject.mm +++ b/src/RJSObject.mm @@ -83,6 +83,7 @@ bool ObjectSetProperty(JSContextRef ctx, JSObjectRef jsObject, JSStringRef jsPro if (*exception) { *exception = RJSMakeError(ctx, ex); } + return false; } return true; } diff --git a/src/object-store/results.cpp b/src/object-store/results.cpp index 67116e8e..6b240f59 100644 --- a/src/object-store/results.cpp +++ b/src/object-store/results.cpp @@ -45,4 +45,4 @@ void Results::verify_attached() { throw std::runtime_error("Tableview is not attached"); } table_view.sync_if_needed(); -} \ No newline at end of file +} diff --git a/tests/ArrayTests.js b/tests/ArrayTests.js new file mode 100644 index 00000000..2c4387af --- /dev/null +++ b/tests/ArrayTests.js @@ -0,0 +1,107 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +'use strict'; + +var ArrayTests = { + testLinkTypesPropertySetters: function() { + var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var obj = null; + realm.write(function() { + obj = realm.create('LinkTypesObject', [[1], undefined, [[3]]]); + }); + TestCase.assertEqual(realm.objects('TestObject').length, 2); + + // set/reuse object property + realm.write(function() { + obj.objectCol1 = obj.objectCol; + }); + TestCase.assertEqual(obj.objectCol1.doubleCol, 1); + //TestCase.assertEqual(obj.objectCol, obj.objectCol1); + TestCase.assertEqual(realm.objects('TestObject').length, 2); + + realm.write(function() { + obj.objectCol = undefined; + obj.objectCol1 = null; + }); + TestCase.assertEqual(obj.objectCol, null); + TestCase.assertEqual(obj.objectCol1, null); + + // set object as JSON + realm.write(function() { + obj.objectCol = { doubleCol: 3 }; + }); + TestCase.assertEqual(obj.objectCol.doubleCol, 3); + TestCase.assertEqual(realm.objects('TestObject').length, 3); + }, + + testArrayLength: function() { + var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + realm.write(function() { + var obj = realm.create('LinkTypesObject', [[1], [2], [[3]]]); + TestCase.assertEqual(obj.arrayCol.length, 1); + + obj.arrayCol = []; + TestCase.assertEqual(obj.arrayCol.length, 0); + + obj.arrayCol = [[1], [2]]; + TestCase.assertEqual(obj.arrayCol.length, 2); + }); + }, + + testArraySubscript: function() { + var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + realm.write(function() { realm.create('LinkTypesObject', [[1], [2], [[3], [4]]]); }); + + var array = realm.objects('LinkTypesObject')[0].arrayCol; + TestCase.assertEqual(array[0].doubleCol, 3); + TestCase.assertEqual(array[1].doubleCol, 4); + TestCase.assertThrows(function() { array[2]; }, 'Invalid index'); + TestCase.assertThrows(function() { array[-1]; }, 'Invalid index'); + }, + + testArrayInvalidProperty: function() { + var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + realm.write(function() { realm.create('LinkTypesObject', [[1], [2], [[3], [4]]]); }); + + var array = realm.objects('LinkTypesObject')[0].arrayCol; + TestCase.assertEqual(undefined, array.ablasdf); + }, + + testArrayEnumerate: function() { + var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + realm.write(function() { realm.create('LinkTypesObject', [[1], [2], []]); }); + + var obj = realm.objects('LinkTypesObject')[0]; + for (var object in obj.arrayCol) { + TestCase.assertTrue(false, "No objects should have been enumerated"); + } + + realm.write(function() { + obj.arrayCol = [[0], [1]]; + TestCase.assertEqual(obj.arrayCol.length, 2); + }); + + var count = 0; + for (var object in obj.arrayCol) { + count++; + //TestCase.assertTrue(object instanceof Object); + } + TestCase.assertEqual(2, count); + }, +}; diff --git a/tests/ObjectTests.js b/tests/ObjectTests.js index be2770f2..aca1be41 100644 --- a/tests/ObjectTests.js +++ b/tests/ObjectTests.js @@ -107,9 +107,18 @@ var ObjectTests = { // set object as JSON realm.write(function() { - obj.objectCol = { doubleCol: 3 }; + obj.objectCol = { doubleCol: 1 }; }); - TestCase.assertEqual(obj.objectCol.doubleCol, 3); + TestCase.assertEqual(obj.objectCol.doubleCol, 1); TestCase.assertEqual(realm.objects('TestObject').length, 3); + + // set array property + realm.write(function() { + obj.arrayCol = [obj.arrayCol[0], obj.objectCol, realm.create('TestObject', [2])]; + }); + TestCase.assertEqual(obj.arrayCol.length, 3); + TestCase.assertEqual(obj.arrayCol[0].doubleCol, 3); + TestCase.assertEqual(obj.arrayCol[1].doubleCol, 1); + TestCase.assertEqual(obj.arrayCol[2].doubleCol, 2); }, }; diff --git a/tests/RealmJSTests.mm b/tests/RealmJSTests.mm index caa1e35d..32bf00fd 100644 --- a/tests/RealmJSTests.mm +++ b/tests/RealmJSTests.mm @@ -227,6 +227,14 @@ static JSClassRef s_globalClass; } @end +@interface RJSArrayTests : RealmJSTests +@end +@implementation RJSArrayTests ++ (NSString *)jsSuiteName { + return @"ArrayTests"; +} +@end + @interface RJSRealmTests : RealmJSTests @end @implementation RJSRealmTests diff --git a/tests/ResultsTests.js b/tests/ResultsTests.js index 330b3f6e..72fd7f04 100644 --- a/tests/ResultsTests.js +++ b/tests/ResultsTests.js @@ -49,7 +49,7 @@ var ResultsTests = { var objects = realm.objects('TestObject'); TestCase.assertEqual(undefined, objects.ablasdf); }, - testResultsEnumberate: function() { + testResultsEnumerate: function() { var realm = new Realm({schema: [TestObjectSchema]}); var objects = realm.objects('TestObject'); for (var object in objects) {