diff --git a/src/RJSArray.cpp b/src/RJSArray.cpp index ca24a36a..b11f1446 100644 --- a/src/RJSArray.cpp +++ b/src/RJSArray.cpp @@ -66,14 +66,6 @@ static inline ObjectArray * RJSVerifiedMutableArray(JSObjectRef object) { return array; } -static inline size_t RJSVerifiedPositiveIndex(std::string indexStr) { - long index = std::stol(indexStr); - if (index < 0) { - throw std::out_of_range(std::string("Index ") + indexStr + " cannot be less than zero."); - } - return index; -} - JSValueRef ArrayGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException) { try { // index subscripting @@ -85,7 +77,7 @@ JSValueRef ArrayGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef pr return JSValueMakeNumber(ctx, size); } - return RJSObjectCreate(ctx, Object(array->realm, array->object_schema, array->get(RJSVerifiedPositiveIndex(indexStr)))); + return RJSObjectCreate(ctx, Object(array->realm, array->object_schema, array->get(RJSValidatedPositiveIndex(indexStr)))); } catch (std::out_of_range &exp) { // getters for nonexistent properties in JS should always return undefined @@ -111,7 +103,7 @@ bool ArraySetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef property throw std::runtime_error("The 'length' property is readonly."); } - array->set(RJSVerifiedPositiveIndex(indexStr), RJSAccessor::to_object_index(ctx, array->realm, const_cast(value), array->object_schema.name, false)); + array->set(RJSValidatedPositiveIndex(indexStr), RJSAccessor::to_object_index(ctx, array->realm, const_cast(value), array->object_schema.name, false)); return true; } catch (std::invalid_argument &exp) { diff --git a/src/RJSResults.mm b/src/RJSResults.mm index 5be3cf37..9443af85 100644 --- a/src/RJSResults.mm +++ b/src/RJSResults.mm @@ -34,7 +34,11 @@ JSValueRef ResultsGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef return JSValueMakeNumber(ctx, size); } - return RJSObjectCreate(ctx, Object(results->realm, results->object_schema, results->get(std::stol(indexStr)))); + return RJSObjectCreate(ctx, Object(results->realm, results->object_schema, results->get(RJSValidatedPositiveIndex(indexStr)))); + } + catch (std::out_of_range &exp) { + // getters for nonexistent properties in JS should always return undefined + return JSValueMakeUndefined(ctx); } catch (std::invalid_argument &exp) { // for stol failure this could be another property that is handled externally, so ignore diff --git a/src/RJSUtil.hpp b/src/RJSUtil.hpp index 1c74a105..f6369ac5 100644 --- a/src/RJSUtil.hpp +++ b/src/RJSUtil.hpp @@ -179,6 +179,14 @@ static inline size_t RJSValidatedArrayLength(JSContextRef ctx, JSObjectRef objec return RJSValidatedValueToNumber(ctx, lengthValue); } +static inline size_t RJSValidatedPositiveIndex(std::string indexStr) { + long index = std::stol(indexStr); + if (index < 0) { + throw std::out_of_range(std::string("Index ") + indexStr + " cannot be less than zero."); + } + return index; +} + static inline bool RJSIsValueObjectOfType(JSContextRef ctx, JSValueRef value, JSStringRef type) { JSObjectRef globalObject = JSContextGetGlobalObject(ctx); diff --git a/src/object-store/results.cpp b/src/object-store/results.cpp index f33fc465..e4ad126e 100644 --- a/src/object-store/results.cpp +++ b/src/object-store/results.cpp @@ -43,7 +43,7 @@ Row Results::get(std::size_t row_ndx) { verify_attached(); if (row_ndx >= table_view.size()) { - throw std::range_error(std::string("Index ") + std::to_string(row_ndx) + " is outside of range 0..." + + throw std::out_of_range(std::string("Index ") + std::to_string(row_ndx) + " is outside of range 0..." + std::to_string(table_view.size()) + "."); } return table_view.get(row_ndx); diff --git a/tests/ResultsTests.js b/tests/ResultsTests.js index 7c953bb5..b0db81ad 100644 --- a/tests/ResultsTests.js +++ b/tests/ResultsTests.js @@ -40,8 +40,8 @@ var ResultsTests = { var people = realm.objects('PersonObject'); TestCase.assertEqual(people[0].age, 1); TestCase.assertEqual(people[1].age, 2); - TestCase.assertThrows(function() { people[2]; }, 'Invalid index'); - TestCase.assertThrows(function() { people[-1]; }, 'Invalid index'); + TestCase.assertEqual(people[2], undefined); + TestCase.assertEqual(people[-1], undefined); TestCase.assertTrue(Object.getPrototypeOf(people[0]) === PersonObject.prototype); }, testResultsInvalidProperty: function() {