diff --git a/src/js_schema.hpp b/src/js_schema.hpp index 0c8c37ef..e3464de9 100644 --- a/src/js_schema.hpp +++ b/src/js_schema.hpp @@ -73,8 +73,8 @@ typename T::Object Schema::dict_for_property_array(ContextType ctx, const Obj static inline void parse_property_type(StringData object_name, Property& prop, StringData type) { using realm::PropertyType; - if (!type) { - throw std::logic_error(util::format("Property %1.%2 must have a non-empty type", object_name, prop.name)); + if (!type || !type.size()) { + throw std::logic_error(util::format("Property '%1.%2' must have a non-empty type", object_name, prop.name)); } if (type.ends_with("[]")) { prop.type |= PropertyType::Array; @@ -107,6 +107,12 @@ static inline void parse_property_type(StringData object_name, Property& prop, S prop.type |= PropertyType::Data; } else if (type == "list") { + if (is_nullable(prop.type)) { + throw std::logic_error(util::format("List property '%1.%2' cannot be optional", object_name, prop.name)); + } + if (is_array(prop.type)) { + throw std::logic_error(util::format("List property '%1.%2' must have a non-list value type", object_name, prop.name)); + } prop.type |= PropertyType::Object | PropertyType::Array; } else if (type == "linkingObjects") { diff --git a/tests/js/realm-tests.js b/tests/js/realm-tests.js index 0ce88ce0..9762ccfb 100644 --- a/tests/js/realm-tests.js +++ b/tests/js/realm-tests.js @@ -106,26 +106,21 @@ module.exports = { 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.assertThrowsContaining(() => { - new Realm({schema: [{ - name: 'InvalidObject', - properties: { - linkingObjects: {type:'linkingObjects', objectType: 'InvalidObject', property: 'nosuchproperty'} - } - }]}); - }, "Property 'InvalidObject.nosuchproperty' declared as origin of linking objects property 'InvalidObject.linkingObjects' does not exist"); + function assertPropertyInvalid(prop, message) { + TestCase.assertThrowsContaining(() => { + new Realm({schema: [{name: 'InvalidObject', properties: { int: 'int', bad: prop }}]}); + }, message, 1); + } - // linkingObjects property where the source property is not a link - TestCase.assertThrowsContaining(() => { - new Realm({schema: [{ - name: 'InvalidObject', - properties: { - integer: 'int', - linkingObjects: {type:'linkingObjects', objectType: 'InvalidObject', property: 'integer'} - } - }]}); - }, "Property 'InvalidObject.integer' declared as origin of linking objects property 'InvalidObject.linkingObjects' is not a link") + assertPropertyInvalid({type:'list[]', objectType: 'InvalidObject'}, + "List property 'InvalidObject.bad' must have a non-list value type"); + assertPropertyInvalid({type:'list?', objectType: 'InvalidObject'}, + "List property 'InvalidObject.bad' cannot be optional"); + assertPropertyInvalid('', "Property 'InvalidObject.bad' must have a non-empty type"); + assertPropertyInvalid({type:'linkingObjects', objectType: 'InvalidObject', property: 'nosuchproperty'}, + "Property 'InvalidObject.nosuchproperty' declared as origin of linking objects property 'InvalidObject.bad' does not exist"); + assertPropertyInvalid({type:'linkingObjects', objectType: 'InvalidObject', property: 'int'}, + "Property 'InvalidObject.int' declared as origin of linking objects property 'InvalidObject.bad' is not a link"); // linkingObjects property where the source property links elsewhere TestCase.assertThrowsContaining(() => { @@ -142,6 +137,16 @@ module.exports = { } }]}); }, "Property 'InvalidObject.link' declared as origin of linking objects property 'InvalidObject.linkingObjects' links to type 'IntObject'") + + { + new Realm({schema: [{ + name: 'Object', + properties: { + // weird but valid + objectList: {type:'object[]', objectType: 'Object'} + } + }]}); + } }, testRealmConstructorInMemory: function() {