2015-11-16 23:05:50 +00:00
/ * C o p y r i g h t 2 0 1 5 R e a l m I n c - A l l R i g h t s R e s e r v e d
* Proprietary and Confidential
* /
'use strict' ;
var Realm = require ( 'realm' ) ;
var BaseTest = require ( './base-test' ) ;
var TestCase = require ( './asserts' ) ;
var schemas = require ( './schemas' ) ;
2015-11-18 00:13:52 +00:00
var typeConverters = { } ;
typeConverters [ Realm . Types . DATE ] = function ( value ) { return new Date ( value ) ; } ;
2015-11-18 01:17:54 +00:00
function runQuerySuite ( suite ) {
2015-11-18 00:13:52 +00:00
var realm = new Realm ( { schema : suite . schema } ) ;
2015-11-18 01:17:54 +00:00
var objects = suite . objects . map ( function ( obj ) {
var objSchema = suite . schema . find ( function ( el ) { return el . name == obj . type } ) ;
if ( ! objSchema ) {
throw "Object schema '" + obj . type + "' not found in test suite." ;
}
2015-11-18 00:13:52 +00:00
2015-11-18 01:17:54 +00:00
var converted = obj . value . map ( function ( propValue , index ) {
var converter = typeConverters [ objSchema . properties [ index ] . type ] ;
2015-11-18 01:50:17 +00:00
return converter ? converter ( propValue ) : propValue ;
2015-11-18 01:17:54 +00:00
} ) ;
return { type : obj . type , value : converted } ;
} ) ;
realm . write ( function ( ) {
for ( var obj of objects ) {
realm . create ( obj . type , obj . value ) ;
2015-11-18 00:13:52 +00:00
}
} ) ;
2015-11-18 01:17:54 +00:00
for ( var test of suite . tests ) {
if ( test [ 0 ] == "QueryCount" ) {
var args = test . slice ( 2 , 4 ) ;
for ( var i = 4 ; i < test . length ; i ++ ) {
var arg = test [ i ] ;
if ( Array . isArray ( arg ) ) {
args . push ( objects [ arg [ 0 ] ] . value [ arg [ 1 ] ] ) ;
}
else {
args . push ( arg ) ;
}
2015-11-18 00:13:52 +00:00
}
2015-11-18 01:17:54 +00:00
var results = realm . objects . apply ( realm , args ) ;
TestCase . assertEqual ( test [ 1 ] , results . length , "Query '" + args [ 1 ] + "' on type '" + args [ 0 ] + "' expected " + test [ 1 ] + " results, got " + results . length ) ;
}
else if ( test [ 0 ] == "QueryThrows" ) {
TestCase . assertThrows ( function ( ) {
realm . objects . apply ( realm , test . slice ( 1 ) ) ;
} ) ;
}
else {
throw "Invalid query test '" + test [ 0 ] + "'" ;
2015-11-18 00:13:52 +00:00
}
}
}
2015-11-18 19:54:45 +00:00
var testCases = {
"dateTests" : {
2015-11-18 00:13:52 +00:00
"schema" : [ {
"name" : "DateObject" ,
"properties" : [ { "name" : "date" , "type" : Realm . Types . DATE } ] ,
} ] ,
"objects" : [
{ "type" : "DateObject" , "value" : [ 10000 ] } ,
{ "type" : "DateObject" , "value" : [ 10001 ] } ,
{ "type" : "DateObject" , "value" : [ 10002 ] } ,
] ,
"tests" : [
2015-11-18 01:17:54 +00:00
[ "QueryCount" , 2 , "DateObject" , "date < $0" , [ 2 , 0 ] ] ,
[ "QueryCount" , 3 , "DateObject" , "date <= $0" , [ 2 , 0 ] ] ,
[ "QueryCount" , 2 , "DateObject" , "date > $0" , [ 0 , 0 ] ] ,
[ "QueryCount" , 3 , "DateObject" , "date >= $0" , [ 0 , 0 ] ] ,
[ "QueryCount" , 1 , "DateObject" , "date == $0" , [ 0 , 0 ] ] ,
[ "QueryCount" , 2 , "DateObject" , "date != $0" , [ 0 , 0 ] ] ,
2015-11-18 01:50:17 +00:00
[ "QueryThrows" , "DateObject" , "date == 'not a date'" ] ,
[ "QueryThrows" , "DateObject" , "date == 1" ] ,
[ "QueryThrows" , "DateObject" , "date == $0" , 1 ] ,
2015-11-18 00:13:52 +00:00
]
2015-11-18 19:54:45 +00:00
} ,
2015-11-18 00:13:52 +00:00
2015-11-18 19:54:45 +00:00
"boolTests" : {
2015-11-18 01:17:54 +00:00
"schema" : [ {
"name" : "BoolObject" ,
2015-11-18 01:50:17 +00:00
"properties" : [ { "name" : "boolCol" , "type" : Realm . Types . BOOL } ] ,
2015-11-18 01:17:54 +00:00
} ] ,
"objects" : [
{ "type" : "BoolObject" , "value" : [ false ] } ,
{ "type" : "BoolObject" , "value" : [ true ] } ,
{ "type" : "BoolObject" , "value" : [ true ] } ,
] ,
"tests" : [
2015-11-18 01:50:17 +00:00
[ "QueryCount" , 2 , "BoolObject" , "boolCol == true" ] ,
2015-11-18 19:32:52 +00:00
[ "QueryCount" , 1 , "BoolObject" , "boolCol==false" ] ,
2015-11-18 01:50:17 +00:00
[ "QueryCount" , 1 , "BoolObject" , "boolCol != true" ] ,
2015-11-18 19:32:52 +00:00
[ "QueryCount" , 2 , "BoolObject" , "true == boolCol" ] ,
2015-11-18 01:50:17 +00:00
[ "QueryCount" , 2 , "BoolObject" , "boolCol == TRUE" ] ,
[ "QueryCount" , 1 , "BoolObject" , "boolCol == FALSE" ] ,
[ "QueryCount" , 2 , "BoolObject" , "boolCol == $0" , true ] ,
[ "QueryCount" , 1 , "BoolObject" , "boolCol == $0" , false ] ,
[ "QueryCount" , 0 , "BoolObject" , "boolCol == true && boolCol == false" ] ,
[ "QueryCount" , 3 , "BoolObject" , "boolCol == true || boolCol == false" ] ,
[ "QueryThrows" , "BoolObject" , "boolCol == 0" ] ,
[ "QueryThrows" , "BoolObject" , "boolCol == 1" ] ,
[ "QueryThrows" , "BoolObject" , "boolCol == 'not a bool'" ] ,
2015-11-18 01:54:25 +00:00
[ "QueryThrows" , "BoolObject" , "boolCol == $0" , "not a bool" ] ,
2015-11-18 01:50:17 +00:00
[ "QueryThrows" , "BoolObject" , "boolCol > true" ] ,
[ "QueryThrows" , "BoolObject" , "boolCol >= true" ] ,
[ "QueryThrows" , "BoolObject" , "boolCol < true" ] ,
[ "QueryThrows" , "BoolObject" , "boolCol <= true" ] ,
[ "QueryThrows" , "BoolObject" , "boolCol BEGINSWITH true" ] ,
[ "QueryThrows" , "BoolObject" , "boolCol CONTAINS true" ] ,
[ "QueryThrows" , "BoolObject" , "boolCol ENDSWITH true" ] ,
2015-11-18 01:17:54 +00:00
]
2015-11-18 19:54:45 +00:00
} ,
2015-11-18 01:17:54 +00:00
2015-11-18 19:54:45 +00:00
"intTests" : {
2015-11-18 01:50:17 +00:00
"schema" : [ {
"name" : "IntObject" ,
"properties" : [ { "name" : "intCol" , "type" : Realm . Types . INT } ] ,
} ] ,
"objects" : [
{ "type" : "IntObject" , "value" : [ - 1 ] } ,
{ "type" : "IntObject" , "value" : [ 0 ] } ,
{ "type" : "IntObject" , "value" : [ 100 ] } ,
] ,
"tests" : [
[ "QueryCount" , 1 , "IntObject" , "intCol == -1" ] ,
2015-11-18 19:32:52 +00:00
[ "QueryCount" , 1 , "IntObject" , "intCol==0" ] ,
2015-11-18 01:54:25 +00:00
[ "QueryCount" , 0 , "IntObject" , "1 == intCol" ] ,
2015-11-18 01:50:17 +00:00
[ "QueryCount" , 2 , "IntObject" , "intCol != 0" ] ,
[ "QueryCount" , 2 , "IntObject" , "intCol > -1" ] ,
[ "QueryCount" , 3 , "IntObject" , "intCol >= -1" ] ,
[ "QueryCount" , 2 , "IntObject" , "intCol < 100" ] ,
[ "QueryCount" , 3 , "IntObject" , "intCol <= 100" ] ,
2015-11-18 01:54:25 +00:00
[ "QueryCount" , 1 , "IntObject" , "intCol > 0x1F" ] ,
[ "QueryCount" , 1 , "IntObject" , "intCol == $0" , 100 ] ,
2015-11-18 01:50:17 +00:00
2015-11-18 01:54:25 +00:00
[ "QueryThrows" , "IntObject" , "intCol == 'not an int'" ] ,
[ "QueryThrows" , "IntObject" , "intCol == true" ] ,
[ "QueryThrows" , "IntObject" , "intCol == $0" , "not an int" ] ,
2015-11-18 01:50:17 +00:00
[ "QueryThrows" , "IntObject" , "intCol BEGINSWITH 1" ] ,
[ "QueryThrows" , "IntObject" , "intCol CONTAINS 1" ] ,
[ "QueryThrows" , "IntObject" , "intCol ENDSWITH 1" ] ,
]
2015-11-18 19:54:45 +00:00
} ,
2015-11-18 01:50:17 +00:00
2015-11-18 19:54:45 +00:00
"floatTests" : {
2015-11-18 19:32:52 +00:00
"schema" : [ {
"name" : "FloatObject" ,
2015-11-18 20:17:39 +00:00
"properties" : [ { "name" : "floatCol" , "type" : Realm . Types . FLOAT } ] ,
2015-11-18 19:32:52 +00:00
} ] ,
"objects" : [
{ "type" : "FloatObject" , "value" : [ - 1.001 ] } ,
{ "type" : "FloatObject" , "value" : [ 0.0 ] } ,
{ "type" : "FloatObject" , "value" : [ 100.2 ] } ,
] ,
"tests" : [
[ "QueryCount" , 1 , "FloatObject" , "floatCol == -1.001" ] ,
2015-11-18 19:54:45 +00:00
[ "QueryCount" , 1 , "FloatObject" , "floatCol = 0" ] ,
2015-11-18 19:32:52 +00:00
[ "QueryCount" , 0 , "FloatObject" , "1 == floatCol" ] ,
[ "QueryCount" , 2 , "FloatObject" , "floatCol != 0" ] ,
[ "QueryCount" , 2 , "FloatObject" , "floatCol > -1.001" ] ,
[ "QueryCount" , 3 , "FloatObject" , "floatCol >= -1.001" ] ,
[ "QueryCount" , 2 , "FloatObject" , "floatCol < 100.2" ] ,
[ "QueryCount" , 3 , "FloatObject" , "floatCol <= 100.2" ] ,
[ "QueryCount" , 1 , "FloatObject" , "floatCol > 0x1F" ] ,
[ "QueryCount" , 1 , "FloatObject" , "floatCol == $0" , 100.2 ] ,
[ "QueryThrows" , "FloatObject" , "floatCol == 'not a float'" ] ,
[ "QueryThrows" , "FloatObject" , "floatCol == true" ] ,
[ "QueryThrows" , "FloatObject" , "floatCol == $0" , "not a float" ] ,
[ "QueryThrows" , "FloatObject" , "floatCol BEGINSWITH 1" ] ,
[ "QueryThrows" , "FloatObject" , "floatCol CONTAINS 1" ] ,
[ "QueryThrows" , "FloatObject" , "floatCol ENDSWITH 1" ] ,
2015-11-18 19:54:45 +00:00
//XCTAssertThrows(([[realm objects:[FloatObject className] where:@"floatCol = 3.5e+38"] count]), @"Too large to be a float");
//XCTAssertThrows(([[realm objects:[FloatObject className] where:@"floatCol = -3.5e+38"] count]), @"Too small to be a float");
2015-11-18 19:32:52 +00:00
]
2015-11-18 19:54:45 +00:00
} ,
2015-11-18 19:32:52 +00:00
2015-11-18 19:54:45 +00:00
"doubleTests" : {
2015-11-18 19:32:52 +00:00
"schema" : [ {
"name" : "DoubleObject" ,
2015-11-18 20:17:39 +00:00
"properties" : [ { "name" : "doubleCol" , "type" : Realm . Types . DOUBLE } ] ,
2015-11-18 19:32:52 +00:00
} ] ,
"objects" : [
{ "type" : "DoubleObject" , "value" : [ - 1.001 ] } ,
{ "type" : "DoubleObject" , "value" : [ 0.0 ] } ,
{ "type" : "DoubleObject" , "value" : [ 100.2 ] } ,
] ,
"tests" : [
[ "QueryCount" , 1 , "DoubleObject" , "doubleCol == -1.001" ] ,
[ "QueryCount" , 1 , "DoubleObject" , "doubleCol == 0" ] ,
[ "QueryCount" , 0 , "DoubleObject" , "1 == doubleCol" ] ,
[ "QueryCount" , 2 , "DoubleObject" , "doubleCol != 0" ] ,
[ "QueryCount" , 2 , "DoubleObject" , "doubleCol > -1.001" ] ,
[ "QueryCount" , 3 , "DoubleObject" , "doubleCol >= -1.001" ] ,
[ "QueryCount" , 2 , "DoubleObject" , "doubleCol < 100.2" ] ,
[ "QueryCount" , 3 , "DoubleObject" , "doubleCol <= 100.2" ] ,
[ "QueryCount" , 1 , "DoubleObject" , "doubleCol > 0x1F" ] ,
[ "QueryCount" , 1 , "DoubleObject" , "doubleCol == $0" , 100.2 ] ,
[ "QueryThrows" , "DoubleObject" , "doubleCol == 'not a double'" ] ,
[ "QueryThrows" , "DoubleObject" , "doubleCol == true" ] ,
[ "QueryThrows" , "DoubleObject" , "doubleCol == $0" , "not a double" ] ,
[ "QueryThrows" , "DoubleObject" , "doubleCol BEGINSWITH 1" ] ,
[ "QueryThrows" , "DoubleObject" , "doubleCol CONTAINS 1" ] ,
[ "QueryThrows" , "DoubleObject" , "doubleCol ENDSWITH 1" ] ,
]
2015-11-18 19:54:45 +00:00
} ,
"stringTests" : {
"schema" : [ {
2015-11-18 20:17:39 +00:00
"name" : "StringObject" ,
"properties" : [ { "name" : "stringCol" , "type" : Realm . Types . STRING } ] ,
2015-11-18 19:54:45 +00:00
} ] ,
"objects" : [
2015-11-18 20:17:39 +00:00
{ "type" : "StringObject" , "value" : [ "A" ] } ,
{ "type" : "StringObject" , "value" : [ "a" ] } ,
{ "type" : "StringObject" , "value" : [ "a" ] } ,
2015-11-18 20:27:52 +00:00
{ "type" : "StringObject" , "value" : [ "C" ] } ,
{ "type" : "StringObject" , "value" : [ "c" ] } ,
2015-11-18 20:17:39 +00:00
{ "type" : "StringObject" , "value" : [ "abc" ] } ,
2015-11-18 20:27:52 +00:00
{ "type" : "StringObject" , "value" : [ "ABC" ] } ,
2015-11-18 20:17:39 +00:00
{ "type" : "StringObject" , "value" : [ "" ] } ,
{ "type" : "StringObject" , "value" : [ "\\\"\\n\\0\\r\\\\'" ] } ,
2015-11-18 19:54:45 +00:00
] ,
"tests" : [
2015-11-18 20:17:39 +00:00
[ "QueryCount" , 2 , "StringObject" , "stringCol == 'a'" ] ,
2015-11-18 20:27:52 +00:00
[ "QueryCount" , 1 , "StringObject" , "'c' == stringCol" ] ,
2015-11-18 20:17:39 +00:00
[ "QueryCount" , 2 , "StringObject" , "stringCol == \"a\"" ] ,
2015-11-18 20:27:52 +00:00
[ "QueryCount" , 1 , "StringObject" , "stringCol=='abc'" ] ,
2015-11-18 20:17:39 +00:00
[ "QueryCount" , 1 , "StringObject" , "stringCol == ''" ] ,
2015-11-18 20:27:52 +00:00
[ "QueryCount" , 8 , "StringObject" , "stringCol != ''" ] ,
2015-11-18 20:17:39 +00:00
[ "QueryCount" , 1 , "StringObject" , "stringCol == \"\\\"\\n\\0\\r\\\\'\"" ] ,
2015-11-18 20:27:52 +00:00
[ "QueryCount" , 3 , "StringObject" , "stringCol BEGINSWITH 'a'" ] ,
[ "QueryCount" , 1 , "StringObject" , "stringCol beginswith 'ab'" ] ,
[ "QueryCount" , 0 , "StringObject" , "stringCol BEGINSWITH 'abcd'" ] ,
[ "QueryCount" , 2 , "StringObject" , "stringCol BEGINSWITH 'A'" ] ,
[ "QueryCount" , 2 , "StringObject" , "stringCol ENDSWITH 'c'" ] ,
[ "QueryCount" , 1 , "StringObject" , "stringCol endswith 'bc'" ] ,
[ "QueryCount" , 9 , "StringObject" , "stringCol ENDSWITH ''" ] ,
[ "QueryCount" , 1 , "StringObject" , "stringCol CONTAINS 'b'" ] ,
[ "QueryCount" , 2 , "StringObject" , "stringCol contains 'c'" ] ,
[ "QueryCount" , 9 , "StringObject" , "stringCol CONTAINS ''" ] ,
// ["QueryCount", 3, "StringObject", "stringCol ==[c] 'a'"],
// ["QueryCount", 5, "StringObject", "stringCol BEGINSWITH[c] 'A'"],
// ["QueryCount", 4, "StringObject", "stringCol ENDSWITH[c] 'c'"],
// ["QueryCount", 2, "StringObject", "stringCol CONTAINS[c] 'B'"],
2015-11-18 19:54:45 +00:00
]
} ,
2015-11-18 19:32:52 +00:00
} ;
2015-11-18 01:17:54 +00:00
module . exports = BaseTest . extend ( {
2015-11-18 01:50:17 +00:00
testDateQueries : function ( ) {
2015-11-18 19:54:45 +00:00
runQuerySuite ( testCases . dateTests ) ;
2015-11-18 01:50:17 +00:00
} ,
2015-11-18 01:17:54 +00:00
testBoolQueries : function ( ) {
2015-11-18 19:54:45 +00:00
runQuerySuite ( testCases . boolTests ) ;
2015-11-16 23:05:50 +00:00
} ,
2015-11-18 01:50:17 +00:00
testIntQueries : function ( ) {
2015-11-18 19:54:45 +00:00
runQuerySuite ( testCases . intTests ) ;
2015-11-18 01:50:17 +00:00
} ,
2015-11-18 19:32:52 +00:00
testFloatQueries : function ( ) {
2015-11-18 20:17:39 +00:00
runQuerySuite ( testCases . floatTests ) ;
2015-11-18 19:32:52 +00:00
} ,
testDoubleQueries : function ( ) {
2015-11-18 20:17:39 +00:00
runQuerySuite ( testCases . doubleTests ) ;
} ,
testStringQueries : function ( ) {
runQuerySuite ( testCases . stringTests ) ;
2015-11-18 19:32:52 +00:00
} ,
2015-11-16 23:05:50 +00:00
} ) ;
2015-11-18 01:17:54 +00:00
2015-11-16 23:05:50 +00:00
/ *
- ( void ) testQueryBetween
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
NSDate * date1 = [ NSDate date ] ;
NSDate * date2 = [ date1 dateByAddingTimeInterval : 1 ] ;
NSDate * date3 = [ date2 dateByAddingTimeInterval : 1 ] ;
NSDate * date33 = [ date3 dateByAddingTimeInterval : 1 ] ;
StringObject * stringObj = [ StringObject new ] ;
stringObj . stringCol = @ "string" ;
[ realm beginWriteTransaction ] ;
[ AllTypesObject createInRealm : realm withValue : @ [ @ YES , @ 1 , @ 1.0 f , @ 1.0 , @ "a" , [ @ "a" dataUsingEncoding : NSUTF8StringEncoding ] , date1 , @ YES , @ ( ( long ) 1 ) , @ 1 , stringObj ] ] ;
[ AllTypesObject createInRealm : realm withValue : @ [ @ YES , @ 2 , @ 2.0 f , @ 2.0 , @ "b" , [ @ "b" dataUsingEncoding : NSUTF8StringEncoding ] , date2 , @ YES , @ ( ( long ) 2 ) , @ "mixed" , stringObj ] ] ;
[ AllTypesObject createInRealm : realm withValue : @ [ @ NO , @ 3 , @ 3.0 f , @ 3.0 , @ "c" , [ @ "c" dataUsingEncoding : NSUTF8StringEncoding ] , date3 , @ YES , @ ( ( long ) 3 ) , @ "mixed" , stringObj ] ] ;
[ AllTypesObject createInRealm : realm withValue : @ [ @ NO , @ 33 , @ 3.3 f , @ 3.3 , @ "cc" , [ @ "cc" dataUsingEncoding : NSUTF8StringEncoding ] , date33 , @ NO , @ ( ( long ) 3.3 ) , @ "mixed" , stringObj ] ] ;
[ realm commitWriteTransaction ] ;
RLMResults * betweenResults = [ AllTypesObject objectsWithPredicate : [ NSPredicate predicateWithFormat : @ "intCol BETWEEN %@" , @ [ @ 2 , @ 3 ] ] ] ;
XCTAssertEqual ( betweenResults . count , 2 U , @ "Should equal 2" ) ;
betweenResults = [ AllTypesObject objectsWithPredicate : [ NSPredicate predicateWithFormat : @ "floatCol BETWEEN %@" , @ [ @ 1.0 f , @ 4.0 f ] ] ] ;
XCTAssertEqual ( betweenResults . count , 4 U , @ "Should equal 4" ) ;
betweenResults = [ AllTypesObject objectsWithPredicate : [ NSPredicate predicateWithFormat : @ "doubleCol BETWEEN %@" , @ [ @ 3.0 , @ 7.0 f ] ] ] ;
XCTAssertEqual ( betweenResults . count , 2 U , @ "Should equal 2" ) ;
betweenResults = [ AllTypesObject objectsWithPredicate : [ NSPredicate predicateWithFormat : @ "dateCol BETWEEN %@" , @ [ date2 , date3 ] ] ] ;
XCTAssertEqual ( betweenResults . count , 2 U , @ "Should equal 2" ) ;
betweenResults = [ AllTypesObject objectsWhere : @ "intCol BETWEEN {2, 3}" ] ;
XCTAssertEqual ( betweenResults . count , 2 U , @ "Should equal 2" ) ;
betweenResults = [ AllTypesObject objectsWhere : @ "doubleCol BETWEEN {3.0, 7.0}" ] ;
XCTAssertEqual ( betweenResults . count , 2 U , @ "Should equal 2" ) ;
betweenResults = [ AllTypesObject . allObjects objectsWhere : @ "intCol BETWEEN {2, 3}" ] ;
XCTAssertEqual ( betweenResults . count , 2 U , @ "Should equal 2" ) ;
betweenResults = [ AllTypesObject . allObjects objectsWhere : @ "doubleCol BETWEEN {3.0, 7.0}" ] ;
XCTAssertEqual ( betweenResults . count , 2 U , @ "Should equal 2" ) ;
}
- ( void ) testArrayQuery
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Fiel" , @ 27 ] ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Tim" , @ 29 ] ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Ari" , @ 33 ] ] ;
[ realm commitWriteTransaction ] ;
// query on class
RLMResults * all = [ PersonObject allObjects ] ;
XCTAssertEqual ( all . count , 3 U , @ "Expecting 3 results" ) ;
RLMResults * some = [ [ PersonObject objectsWhere : @ "age > 28" ] sortedResultsUsingProperty : @ "age" ascending : YES ] ;
// query/order on array
XCTAssertEqual ( [ all objectsWhere : @ "age == 27" ] . count , 1 U , @ "Expecting 1 result" ) ;
XCTAssertEqual ( [ all objectsWhere : @ "age == 28" ] . count , 0 U , @ "Expecting 0 results" ) ;
some = [ some sortedResultsUsingProperty : @ "age" ascending : NO ] ;
XCTAssertEqualObjects ( [ some [ 0 ] name ] , @ "Ari" , @ "Ari should be first results" ) ;
}
- ( void ) verifySort : ( RLMRealm * ) realm column : ( NSString * ) column ascending : ( BOOL ) ascending expected : ( id ) val {
RLMResults * results = [ [ AllTypesObject allObjectsInRealm : realm ] sortedResultsUsingProperty : column ascending : ascending ] ;
AllTypesObject * obj = results [ 0 ] ;
XCTAssertEqualObjects ( obj [ column ] , val , @ "Array not sorted as expected - %@ != %@" , obj [ column ] , val ) ;
RLMArray * ar = ( RLMArray * ) [ [ [ ArrayOfAllTypesObject allObjectsInRealm : realm ] firstObject ] array ] ;
results = [ ar sortedResultsUsingProperty : column ascending : ascending ] ;
obj = results [ 0 ] ;
XCTAssertEqualObjects ( obj [ column ] , val , @ "Array not sorted as expected - %@ != %@" , obj [ column ] , val ) ;
}
- ( void ) verifySortWithAccuracy : ( RLMRealm * ) realm column : ( NSString * ) column ascending : ( BOOL ) ascending getter : ( double ( ^ ) ( id ) ) getter expected : ( double ) val accuracy : ( double ) accuracy {
// test TableView query
RLMResults * results = [ [ AllTypesObject allObjectsInRealm : realm ] sortedResultsUsingProperty : column ascending : ascending ] ;
XCTAssertEqualWithAccuracy ( getter ( results [ 0 ] [ column ] ) , val , accuracy , @ "Array not sorted as expected" ) ;
// test LinkView query
RLMArray * ar = ( RLMArray * ) [ [ [ ArrayOfAllTypesObject allObjectsInRealm : realm ] firstObject ] array ] ;
results = [ ar sortedResultsUsingProperty : column ascending : ascending ] ;
XCTAssertEqualWithAccuracy ( getter ( results [ 0 ] [ column ] ) , val , accuracy , @ "Array not sorted as expected" ) ;
}
- ( void ) testQuerySorting
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
NSDate * date1 = [ NSDate date ] ;
NSDate * date2 = [ date1 dateByAddingTimeInterval : 1 ] ;
NSDate * date3 = [ date2 dateByAddingTimeInterval : 1 ] ;
NSDate * date33 = [ date3 dateByAddingTimeInterval : 1 ] ;
[ realm beginWriteTransaction ] ;
ArrayOfAllTypesObject * arrayOfAll = [ ArrayOfAllTypesObject createInRealm : realm withValue : @ { } ] ;
StringObject * stringObj = [ StringObject new ] ;
stringObj . stringCol = @ "string" ;
[ arrayOfAll . array addObject : [ AllTypesObject createInRealm : realm withValue : @ [ @ YES , @ 1 , @ 1.0 f , @ 1.0 , @ "a" , [ @ "a" dataUsingEncoding : NSUTF8StringEncoding ] , date1 , @ YES , @ 1 , @ 1 , stringObj ] ] ] ;
[ arrayOfAll . array addObject : [ AllTypesObject createInRealm : realm withValue : @ [ @ YES , @ 2 , @ 2.0 f , @ 2.0 , @ "b" , [ @ "b" dataUsingEncoding : NSUTF8StringEncoding ] , date2 , @ YES , @ 2 , @ "mixed" , stringObj ] ] ] ;
[ arrayOfAll . array addObject : [ AllTypesObject createInRealm : realm withValue : @ [ @ NO , @ 3 , @ 3.0 f , @ 3.0 , @ "c" , [ @ "c" dataUsingEncoding : NSUTF8StringEncoding ] , date3 , @ YES , @ 3 , @ "mixed" , stringObj ] ] ] ;
[ arrayOfAll . array addObject : [ AllTypesObject createInRealm : realm withValue : @ [ @ NO , @ 33 , @ 3.3 f , @ 3.3 , @ "cc" , [ @ "cc" dataUsingEncoding : NSUTF8StringEncoding ] , date33 , @ NO , @ 3 , @ "mixed" , stringObj ] ] ] ;
[ realm commitWriteTransaction ] ;
//////////// sort by boolCol
[ self verifySort : realm column : @ "boolCol" ascending : YES expected : @ NO ] ;
[ self verifySort : realm column : @ "boolCol" ascending : NO expected : @ YES ] ;
//////////// sort by intCol
[ self verifySort : realm column : @ "intCol" ascending : YES expected : @ 1 ] ;
[ self verifySort : realm column : @ "intCol" ascending : NO expected : @ 33 ] ;
//////////// sort by dateCol
double ( ^ dateGetter ) ( id ) = ^ ( NSDate * d ) { return d . timeIntervalSince1970 ; } ;
[ self verifySortWithAccuracy : realm column : @ "dateCol" ascending : YES getter : dateGetter expected : date1 . timeIntervalSince1970 accuracy : 1 ] ;
[ self verifySortWithAccuracy : realm column : @ "dateCol" ascending : NO getter : dateGetter expected : date33 . timeIntervalSince1970 accuracy : 1 ] ;
//////////// sort by doubleCol
double ( ^ doubleGetter ) ( id ) = ^ ( NSNumber * n ) { return n . doubleValue ; } ;
[ self verifySortWithAccuracy : realm column : @ "doubleCol" ascending : YES getter : doubleGetter expected : 1.0 accuracy : 0.0000001 ] ;
[ self verifySortWithAccuracy : realm column : @ "doubleCol" ascending : NO getter : doubleGetter expected : 3.3 accuracy : 0.0000001 ] ;
//////////// sort by floatCol
[ self verifySortWithAccuracy : realm column : @ "floatCol" ascending : YES getter : doubleGetter expected : 1.0 accuracy : 0.0000001 ] ;
[ self verifySortWithAccuracy : realm column : @ "floatCol" ascending : NO getter : doubleGetter expected : 3.3 accuracy : 0.0000001 ] ;
//////////// sort by stringCol
[ self verifySort : realm column : @ "stringCol" ascending : YES expected : @ "a" ] ;
[ self verifySort : realm column : @ "stringCol" ascending : NO expected : @ "cc" ] ;
// sort by mixed column
RLMAssertThrowsWithReasonMatching ( [ [ AllTypesObject allObjects ] sortedResultsUsingProperty : @ "mixedCol" ascending : YES ] , @ "'mixedCol' .* 'AllTypesObject': sorting is only supported .* type any" ) ;
XCTAssertThrows ( [ arrayOfAll . array sortedResultsUsingProperty : @ "mixedCol" ascending : NO ] ) ;
// sort invalid name
RLMAssertThrowsWithReasonMatching ( [ [ AllTypesObject allObjects ] sortedResultsUsingProperty : @ "invalidCol" ascending : YES ] , @ "'invalidCol'.* 'AllTypesObject'.* not found" ) ;
XCTAssertThrows ( [ arrayOfAll . array sortedResultsUsingProperty : @ "invalidCol" ascending : NO ] ) ;
// sort on key path
RLMAssertThrowsWithReasonMatching ( [ [ AllTypesObject allObjects ] sortedResultsUsingProperty : @ "key.path" ascending : YES ] , @ "key paths is not supported" ) ;
XCTAssertThrows ( [ arrayOfAll . array sortedResultsUsingProperty : @ "key.path" ascending : NO ] ) ;
}
- ( void ) testSortByMultipleColumns {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
DogObject * a1 = [ DogObject createInDefaultRealmWithValue : @ [ @ "a" , @ 1 ] ] ;
DogObject * a2 = [ DogObject createInDefaultRealmWithValue : @ [ @ "a" , @ 2 ] ] ;
DogObject * b1 = [ DogObject createInDefaultRealmWithValue : @ [ @ "b" , @ 1 ] ] ;
DogObject * b2 = [ DogObject createInDefaultRealmWithValue : @ [ @ "b" , @ 2 ] ] ;
[ realm commitWriteTransaction ] ;
bool ( ^ checkOrder ) ( NSArray * , NSArray * , NSArray * ) = ^ bool ( NSArray * properties , NSArray * ascending , NSArray * dogs ) {
NSArray * sort = @ [ [ RLMSortDescriptor sortDescriptorWithProperty : properties [ 0 ] ascending : [ ascending [ 0 ] boolValue ] ] ,
[ RLMSortDescriptor sortDescriptorWithProperty : properties [ 1 ] ascending : [ ascending [ 1 ] boolValue ] ] ] ;
RLMResults * actual = [ DogObject . allObjects sortedResultsUsingDescriptors : sort ] ;
return [ actual [ 0 ] isEqualToObject : dogs [ 0 ] ]
&& [ actual [ 1 ] isEqualToObject : dogs [ 1 ] ]
&& [ actual [ 2 ] isEqualToObject : dogs [ 2 ] ]
&& [ actual [ 3 ] isEqualToObject : dogs [ 3 ] ] ;
} ;
// Check each valid sort
XCTAssertTrue ( checkOrder ( @ [ @ "dogName" , @ "age" ] , @ [ @ YES , @ YES ] , @ [ a1 , a2 , b1 , b2 ] ) ) ;
XCTAssertTrue ( checkOrder ( @ [ @ "dogName" , @ "age" ] , @ [ @ YES , @ NO ] , @ [ a2 , a1 , b2 , b1 ] ) ) ;
XCTAssertTrue ( checkOrder ( @ [ @ "dogName" , @ "age" ] , @ [ @ NO , @ YES ] , @ [ b1 , b2 , a1 , a2 ] ) ) ;
XCTAssertTrue ( checkOrder ( @ [ @ "dogName" , @ "age" ] , @ [ @ NO , @ NO ] , @ [ b2 , b1 , a2 , a1 ] ) ) ;
XCTAssertTrue ( checkOrder ( @ [ @ "age" , @ "dogName" ] , @ [ @ YES , @ YES ] , @ [ a1 , b1 , a2 , b2 ] ) ) ;
XCTAssertTrue ( checkOrder ( @ [ @ "age" , @ "dogName" ] , @ [ @ YES , @ NO ] , @ [ b1 , a1 , b2 , a2 ] ) ) ;
XCTAssertTrue ( checkOrder ( @ [ @ "age" , @ "dogName" ] , @ [ @ NO , @ YES ] , @ [ a2 , b2 , a1 , b1 ] ) ) ;
XCTAssertTrue ( checkOrder ( @ [ @ "age" , @ "dogName" ] , @ [ @ NO , @ NO ] , @ [ b2 , a2 , b1 , a1 ] ) ) ;
}
- ( void ) testSortedLinkViewWithDeletion {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
NSDate * date1 = [ NSDate date ] ;
NSDate * date2 = [ date1 dateByAddingTimeInterval : 1 ] ;
NSDate * date3 = [ date2 dateByAddingTimeInterval : 1 ] ;
NSDate * date33 = [ date3 dateByAddingTimeInterval : 1 ] ;
[ realm beginWriteTransaction ] ;
ArrayOfAllTypesObject * arrayOfAll = [ ArrayOfAllTypesObject createInRealm : realm withValue : @ { } ] ;
StringObject * stringObj = [ StringObject new ] ;
stringObj . stringCol = @ "string" ;
[ arrayOfAll . array addObject : [ AllTypesObject createInRealm : realm withValue : @ [ @ YES , @ 1 , @ 1.0 f , @ 1.0 , @ "a" , [ @ "a" dataUsingEncoding : NSUTF8StringEncoding ] , date1 , @ YES , @ 1 , @ 1 , stringObj ] ] ] ;
[ arrayOfAll . array addObject : [ AllTypesObject createInRealm : realm withValue : @ [ @ YES , @ 2 , @ 2.0 f , @ 2.0 , @ "b" , [ @ "b" dataUsingEncoding : NSUTF8StringEncoding ] , date2 , @ YES , @ 2 , @ "mixed" , stringObj ] ] ] ;
[ arrayOfAll . array addObject : [ AllTypesObject createInRealm : realm withValue : @ [ @ NO , @ 3 , @ 3.0 f , @ 3.0 , @ "c" , [ @ "c" dataUsingEncoding : NSUTF8StringEncoding ] , date3 , @ YES , @ 3 , @ "mixed" , stringObj ] ] ] ;
[ arrayOfAll . array addObject : [ AllTypesObject createInRealm : realm withValue : @ [ @ NO , @ 33 , @ 3.3 f , @ 3.3 , @ "cc" , [ @ "cc" dataUsingEncoding : NSUTF8StringEncoding ] , date33 , @ NO , @ 3 , @ "mixed" , stringObj ] ] ] ;
[ realm commitWriteTransaction ] ;
RLMResults * results = [ arrayOfAll . array sortedResultsUsingProperty : @ "stringCol" ascending : NO ] ;
XCTAssertEqualObjects ( [ results [ 0 ] stringCol ] , @ "cc" ) ;
// delete cc, add d results should update
[ realm transactionWithBlock : ^ {
[ arrayOfAll . array removeObjectAtIndex : 3 ] ;
// create extra alltypesobject
[ arrayOfAll . array addObject : [ AllTypesObject createInRealm : realm withValue : @ [ @ YES , @ 1 , @ 1.0 f , @ 1.0 , @ "d" , [ @ "d" dataUsingEncoding : NSUTF8StringEncoding ] , date1 , @ YES , @ ( ( long ) 1 ) , @ 1 , stringObj ] ] ] ;
} ] ;
XCTAssertEqualObjects ( [ results [ 0 ] stringCol ] , @ "d" ) ;
XCTAssertEqualObjects ( [ results [ 1 ] stringCol ] , @ "c" ) ;
// delete from realm should be removed from results
[ realm transactionWithBlock : ^ {
[ realm deleteObject : arrayOfAll . array . lastObject ] ;
} ] ;
XCTAssertEqualObjects ( [ results [ 0 ] stringCol ] , @ "c" ) ;
}
- ( void ) testQueryingSortedQueryPreservesOrder {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
for ( int i = 0 ; i < 5 ; ++ i ) {
[ IntObject createInRealm : realm withValue : @ [ @ ( i ) ] ] ;
}
ArrayPropertyObject * array = [ ArrayPropertyObject createInRealm : realm withValue : @ [ @ "name" , @ [ ] , [ IntObject allObjects ] ] ] ;
[ realm commitWriteTransaction ] ;
RLMResults * asc = [ IntObject . allObjects sortedResultsUsingProperty : @ "intCol" ascending : YES ] ;
RLMResults * desc = [ IntObject . allObjects sortedResultsUsingProperty : @ "intCol" ascending : NO ] ;
// sanity check; would work even without sort order being preserved
XCTAssertEqual ( 2 , [ [ [ asc objectsWhere : @ "intCol >= 2" ] firstObject ] intCol ] ) ;
// check query on allObjects and query on query
XCTAssertEqual ( 4 , [ [ [ desc objectsWhere : @ "intCol >= 2" ] firstObject ] intCol ] ) ;
XCTAssertEqual ( 3 , [ [ [ [ desc objectsWhere : @ "intCol >= 2" ] objectsWhere : @ "intCol < 4" ] firstObject ] intCol ] ) ;
// same thing but on an linkview
asc = [ array . intArray sortedResultsUsingProperty : @ "intCol" ascending : YES ] ;
desc = [ array . intArray sortedResultsUsingProperty : @ "intCol" ascending : NO ] ;
XCTAssertEqual ( 2 , [ [ [ asc objectsWhere : @ "intCol >= 2" ] firstObject ] intCol ] ) ;
XCTAssertEqual ( 4 , [ [ [ desc objectsWhere : @ "intCol >= 2" ] firstObject ] intCol ] ) ;
XCTAssertEqual ( 3 , [ [ [ [ desc objectsWhere : @ "intCol >= 2" ] objectsWhere : @ "intCol < 4" ] firstObject ] intCol ] ) ;
}
- ( void ) testPredicateNotSupported
{
// These are things which are valid predicates, but which we do not support
// Aggregate operators on non-arrays
XCTAssertThrows ( [ PersonObject objectsWhere : @ "ANY age > 5" ] ) ;
XCTAssertThrows ( [ PersonObject objectsWhere : @ "ALL age > 5" ] ) ;
XCTAssertThrows ( [ PersonObject objectsWhere : @ "SOME age > 5" ] ) ;
XCTAssertThrows ( [ PersonObject objectsWhere : @ "NONE age > 5" ] ) ;
// nil on LHS of comparison with nullable property
XCTAssertThrows ( [ AllOptionalTypes objectsWhere : @ "nil = boolObj" ] ) ;
XCTAssertThrows ( [ AllOptionalTypes objectsWhere : @ "nil = intObj" ] ) ;
XCTAssertThrows ( [ AllOptionalTypes objectsWhere : @ "nil = floatObj" ] ) ;
XCTAssertThrows ( [ AllOptionalTypes objectsWhere : @ "nil = doubleObj" ] ) ;
XCTAssertThrows ( [ AllOptionalTypes objectsWhere : @ "nil = string" ] ) ;
XCTAssertThrows ( [ AllOptionalTypes objectsWhere : @ "nil = data" ] ) ;
XCTAssertThrows ( [ AllOptionalTypes objectsWhere : @ "nil = date" ] ) ;
// comparing two constants
XCTAssertThrows ( [ PersonObject objectsWhere : @ "5 = 5" ] ) ;
XCTAssertThrows ( [ PersonObject objectsWhere : @ "nil = nil" ] ) ;
// substring operations with constant on LHS
XCTAssertThrows ( [ AllOptionalTypes objectsWhere : @ "'' CONTAINS string" ] ) ;
XCTAssertThrows ( [ AllOptionalTypes objectsWhere : @ "'' BEGINSWITH string" ] ) ;
XCTAssertThrows ( [ AllOptionalTypes objectsWhere : @ "'' ENDSWITH string" ] ) ;
XCTAssertThrows ( ( [ AllOptionalTypes objectsWhere : @ "%@ CONTAINS data" , [ NSData data ] ] ) ) ;
// data is missing stuff
XCTAssertThrows ( [ AllOptionalTypes objectsWhere : @ "data = data" ] ) ;
XCTAssertThrows ( ( [ LinkToAllTypesObject objectsWhere : @ "%@ = allTypesCol.binaryCol" , [ NSData data ] ] ) ) ;
XCTAssertThrows ( ( [ LinkToAllTypesObject objectsWhere : @ "allTypesCol.binaryCol CONTAINS %@" , [ NSData data ] ] ) ) ;
// LinkList equality is unsupport since the semantics are unclear
XCTAssertThrows ( ( [ ArrayOfAllTypesObject objectsWhere : @ "ANY array = array" ] ) ) ;
// subquery
XCTAssertThrows ( ( [ ArrayOfAllTypesObject objectsWhere : @ "SUBQUERY(array, $obj, $obj.intCol = 5).@count > 1" ] ) ) ;
}
- ( void ) testPredicateMisuse
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
NSString * className = PersonObject . className ;
// invalid column/property name
RLMAssertThrowsWithReasonMatching ( [ realm objects : className where : @ "height > 72" ] , @ "'height' not found in .* 'PersonObject'" ) ;
// wrong/invalid data types
RLMAssertThrowsWithReasonMatching ( [ realm objects : className where : @ "age != xyz" ] , @ "'xyz' not found in .* 'PersonObject'" ) ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className where : @ "name == 3" ] , @ "type string .* property 'name' .* 'PersonObject'.*: 3" ) ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className where : @ "age IN {'xyz'}" ] , @ "type int .* property 'age' .* 'PersonObject'.*: xyz" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "name IN {3}" ] , @ "invalid type" ) ;
className = AllTypesObject . className ;
XCTAssertThrows ( [ realm objects : className where : @ "boolCol == Foo" ] , @ "invalid type" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "boolCol == 2" ] , @ "invalid type" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "dateCol == 7" ] , @ "invalid type" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "doubleCol == The" ] , @ "invalid type" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "floatCol == Bar" ] , @ "invalid type" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "intCol == Baz" ] , @ "invalid type" ) ;
className = PersonObject . className ;
// compare two constants
XCTAssertThrows ( [ realm objects : className where : @ "3 == 3" ] , @ "comparing 2 constants" ) ;
// invalid strings
RLMAssertThrowsWithReasonMatching ( [ realm objects : className where : @ "" ] , @ "Unable to parse" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "age" ] , @ "column name only" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "sdlfjasdflj" ] , @ "gibberish" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "age * 25" ] , @ "invalid operator" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "age === 25" ] , @ "invalid operator" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "," ] , @ "comma" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "()" ] , @ "parens" ) ;
// not a link column
RLMAssertThrowsWithReasonMatching ( [ realm objects : className where : @ "age.age == 25" ] , @ "'age' is not a link .* 'PersonObject'" ) ;
XCTAssertThrows ( [ realm objects : className where : @ "age.age.age == 25" ] ) ;
// abuse of BETWEEN
RLMAssertThrowsWithReasonMatching ( [ realm objects : className where : @ "age BETWEEN 25" ] , @ "type NSArray for BETWEEN" ) ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className where : @ "age BETWEEN Foo" ] , @ "BETWEEN operator must compare a KeyPath with an aggregate" ) ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className where : @ "age BETWEEN {age, age}" ] , @ "must be constant values" ) ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className where : @ "age BETWEEN {age, 0}" ] , @ "must be constant values" ) ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className where : @ "age BETWEEN {0, age}" ] , @ "must be constant values" ) ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className where : @ "age BETWEEN {0, {1, 10}}" ] , @ "must be constant values" ) ;
NSPredicate * pred = [ NSPredicate predicateWithFormat : @ "age BETWEEN %@" , @ [ @ 1 ] ] ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className withPredicate : pred ] , @ "exactly two objects" ) ;
pred = [ NSPredicate predicateWithFormat : @ "age BETWEEN %@" , @ [ @ 1 , @ 2 , @ 3 ] ] ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className withPredicate : pred ] , @ "exactly two objects" ) ;
pred = [ NSPredicate predicateWithFormat : @ "age BETWEEN %@" , @ [ @ "Foo" , @ "Bar" ] ] ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className withPredicate : pred ] , @ "type int for BETWEEN" ) ;
pred = [ NSPredicate predicateWithFormat : @ "age BETWEEN %@" , @ [ @ 1.5 , @ 2.5 ] ] ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className withPredicate : pred ] , @ "type int for BETWEEN" ) ;
pred = [ NSPredicate predicateWithFormat : @ "age BETWEEN %@" , @ [ @ 1 , @ [ @ 2 , @ 3 ] ] ] ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className withPredicate : pred ] , @ "type int for BETWEEN" ) ;
pred = [ NSPredicate predicateWithFormat : @ "age BETWEEN %@" , @ { @ 25 : @ 35 } ] ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className withPredicate : pred ] , @ "type NSArray for BETWEEN" ) ;
pred = [ NSPredicate predicateWithFormat : @ "height BETWEEN %@" , @ [ @ 25 , @ 35 ] ] ;
RLMAssertThrowsWithReasonMatching ( [ realm objects : className withPredicate : pred ] , @ "'height' not found .* 'PersonObject'" ) ;
// bad type in link IN
XCTAssertThrows ( [ PersonLinkObject objectsInRealm : realm where : @ "person.age IN {'Tim'}" ] ) ;
}
- ( void ) testTwoColumnComparison
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ YES , @ YES , @ 1 , @ 2 , @ 23.0 f , @ 1.7 f , @ 0.0 , @ 5.55 , @ "a" , @ "a" ] ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ YES , @ NO , @ 1 , @ 3 , @ - 5.3 f , @ 4.21 f , @ 1.0 , @ 4.44 , @ "a" , @ "A" ] ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ NO , @ NO , @ 2 , @ 2 , @ 1.0 f , @ 3.55 f , @ 99.9 , @ 6.66 , @ "a" , @ "ab" ] ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ NO , @ YES , @ 3 , @ 6 , @ 4.21 f , @ 1.0 f , @ 1.0 , @ 7.77 , @ "a" , @ "AB" ] ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ YES , @ YES , @ 4 , @ 5 , @ 23.0 f , @ 23.0 f , @ 7.4 , @ 8.88 , @ "a" , @ "b" ] ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ YES , @ NO , @ 15 , @ 8 , @ 1.0 f , @ 66.0 f , @ 1.01 , @ 9.99 , @ "a" , @ "ba" ] ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ NO , @ YES , @ 15 , @ 15 , @ 1.0 f , @ 66.0 f , @ 1.01 , @ 9.99 , @ "a" , @ "BA" ] ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "bool1 == bool1" ] . count ) ;
XCTAssertEqual ( 3 U , [ self . queryObjectClass objectsWhere : @ "bool1 == bool2" ] . count ) ;
XCTAssertEqual ( 4 U , [ self . queryObjectClass objectsWhere : @ "bool1 != bool2" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "int1 == int1" ] . count ) ;
XCTAssertEqual ( 2 U , [ self . queryObjectClass objectsWhere : @ "int1 == int2" ] . count ) ;
XCTAssertEqual ( 5 U , [ self . queryObjectClass objectsWhere : @ "int1 != int2" ] . count ) ;
XCTAssertEqual ( 1 U , [ self . queryObjectClass objectsWhere : @ "int1 > int2" ] . count ) ;
XCTAssertEqual ( 4 U , [ self . queryObjectClass objectsWhere : @ "int1 < int2" ] . count ) ;
XCTAssertEqual ( 3 U , [ self . queryObjectClass objectsWhere : @ "int1 >= int2" ] . count ) ;
XCTAssertEqual ( 6 U , [ self . queryObjectClass objectsWhere : @ "int1 <= int2" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "float1 == float1" ] . count ) ;
XCTAssertEqual ( 1 U , [ self . queryObjectClass objectsWhere : @ "float1 == float2" ] . count ) ;
XCTAssertEqual ( 6 U , [ self . queryObjectClass objectsWhere : @ "float1 != float2" ] . count ) ;
XCTAssertEqual ( 2 U , [ self . queryObjectClass objectsWhere : @ "float1 > float2" ] . count ) ;
XCTAssertEqual ( 4 U , [ self . queryObjectClass objectsWhere : @ "float1 < float2" ] . count ) ;
XCTAssertEqual ( 3 U , [ self . queryObjectClass objectsWhere : @ "float1 >= float2" ] . count ) ;
XCTAssertEqual ( 5 U , [ self . queryObjectClass objectsWhere : @ "float1 <= float2" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "double1 == double1" ] . count ) ;
XCTAssertEqual ( 0 U , [ self . queryObjectClass objectsWhere : @ "double1 == double2" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "double1 != double2" ] . count ) ;
XCTAssertEqual ( 1 U , [ self . queryObjectClass objectsWhere : @ "double1 > double2" ] . count ) ;
XCTAssertEqual ( 6 U , [ self . queryObjectClass objectsWhere : @ "double1 < double2" ] . count ) ;
XCTAssertEqual ( 1 U , [ self . queryObjectClass objectsWhere : @ "double1 >= double2" ] . count ) ;
XCTAssertEqual ( 6 U , [ self . queryObjectClass objectsWhere : @ "double1 <= double2" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "string1 == string1" ] . count ) ;
XCTAssertEqual ( 1 U , [ self . queryObjectClass objectsWhere : @ "string1 == string2" ] . count ) ;
XCTAssertEqual ( 6 U , [ self . queryObjectClass objectsWhere : @ "string1 != string2" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "string1 CONTAINS string1" ] . count ) ;
XCTAssertEqual ( 1 U , [ self . queryObjectClass objectsWhere : @ "string1 CONTAINS string2" ] . count ) ;
XCTAssertEqual ( 3 U , [ self . queryObjectClass objectsWhere : @ "string2 CONTAINS string1" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "string1 BEGINSWITH string1" ] . count ) ;
XCTAssertEqual ( 1 U , [ self . queryObjectClass objectsWhere : @ "string1 BEGINSWITH string2" ] . count ) ;
XCTAssertEqual ( 2 U , [ self . queryObjectClass objectsWhere : @ "string2 BEGINSWITH string1" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "string1 ENDSWITH string1" ] . count ) ;
XCTAssertEqual ( 1 U , [ self . queryObjectClass objectsWhere : @ "string1 ENDSWITH string2" ] . count ) ;
XCTAssertEqual ( 2 U , [ self . queryObjectClass objectsWhere : @ "string2 ENDSWITH string1" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "string1 ==[c] string1" ] . count ) ;
XCTAssertEqual ( 2 U , [ self . queryObjectClass objectsWhere : @ "string1 ==[c] string2" ] . count ) ;
XCTAssertEqual ( 5 U , [ self . queryObjectClass objectsWhere : @ "string1 !=[c] string2" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "string1 CONTAINS[c] string1" ] . count ) ;
XCTAssertEqual ( 2 U , [ self . queryObjectClass objectsWhere : @ "string1 CONTAINS[c] string2" ] . count ) ;
XCTAssertEqual ( 6 U , [ self . queryObjectClass objectsWhere : @ "string2 CONTAINS[c] string1" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "string1 BEGINSWITH[c] string1" ] . count ) ;
XCTAssertEqual ( 2 U , [ self . queryObjectClass objectsWhere : @ "string1 BEGINSWITH[c] string2" ] . count ) ;
XCTAssertEqual ( 4 U , [ self . queryObjectClass objectsWhere : @ "string2 BEGINSWITH[c] string1" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "string1 ENDSWITH[c] string1" ] . count ) ;
XCTAssertEqual ( 2 U , [ self . queryObjectClass objectsWhere : @ "string1 ENDSWITH[c] string2" ] . count ) ;
XCTAssertEqual ( 4 U , [ self . queryObjectClass objectsWhere : @ "string2 ENDSWITH[c] string1" ] . count ) ;
RLMAssertThrowsWithReasonMatching ( [ self . queryObjectClass objectsWhere : @ "int1 == float1" ] ,
@ "Property type mismatch between int and float" ) ;
RLMAssertThrowsWithReasonMatching ( [ self . queryObjectClass objectsWhere : @ "float2 >= double1" ] ,
@ "Property type mismatch between float and double" ) ;
RLMAssertThrowsWithReasonMatching ( [ self . queryObjectClass objectsWhere : @ "double2 <= int2" ] ,
@ "Property type mismatch between double and int" ) ;
RLMAssertThrowsWithReasonMatching ( [ self . queryObjectClass objectsWhere : @ "int2 != string1" ] ,
@ "Property type mismatch between int and string" ) ;
RLMAssertThrowsWithReasonMatching ( [ self . queryObjectClass objectsWhere : @ "float1 > string1" ] ,
@ "Property type mismatch between float and string" ) ;
RLMAssertThrowsWithReasonMatching ( [ self . queryObjectClass objectsWhere : @ "double1 < string1" ] ,
@ "Property type mismatch between double and string" ) ;
}
- ( void ) testBinaryComparisonInPredicate
{
NSExpression * binary = [ NSExpression expressionForConstantValue : [ [ NSData alloc ] init ] ] ;
NSUInteger ( ^ count ) ( NSPredicateOperatorType ) = ^ ( NSPredicateOperatorType type ) {
NSPredicate * pred = [ RLMPredicateUtil comparisonWithKeyPath : @ "binaryCol"
expression : binary
operatorType : type ] ;
return [ BinaryObject objectsWithPredicate : pred ] . count ;
} ;
XCTAssertEqual ( count ( NSBeginsWithPredicateOperatorType ) , 0 U ,
@ "BEGINSWITH operator in binary comparison." ) ;
XCTAssertEqual ( count ( NSEndsWithPredicateOperatorType ) , 0 U ,
@ "ENDSWITH operator in binary comparison." ) ;
XCTAssertEqual ( count ( NSContainsPredicateOperatorType ) , 0 U ,
@ "CONTAINS operator in binary comparison." ) ;
XCTAssertEqual ( count ( NSEqualToPredicateOperatorType ) , 0 U ,
@ "= or == operator in binary comparison." ) ;
XCTAssertEqual ( count ( NSNotEqualToPredicateOperatorType ) , 0 U ,
@ "!= or <> operator in binary comparison." ) ;
// Invalid operators.
XCTAssertThrowsSpecificNamed ( count ( NSLessThanPredicateOperatorType ) , NSException ,
@ "Invalid operator type" ,
@ "Invalid operator in binary comparison." ) ;
}
- ( void ) testKeyPathLocationInComparison
{
NSExpression * keyPath = [ NSExpression expressionForKeyPath : @ "intCol" ] ;
NSExpression * expr = [ NSExpression expressionForConstantValue : @ 0 ] ;
NSPredicate * predicate ;
predicate = [ RLMPredicateUtil defaultPredicateGenerator ] ( keyPath , expr ) ;
XCTAssert ( [ RLMPredicateUtil isEmptyIntColWithPredicate : predicate ] ,
@ "Key path to the left in an integer comparison." ) ;
predicate = [ RLMPredicateUtil defaultPredicateGenerator ] ( expr , keyPath ) ;
XCTAssert ( [ RLMPredicateUtil isEmptyIntColWithPredicate : predicate ] ,
@ "Key path to the right in an integer comparison." ) ;
predicate = [ RLMPredicateUtil defaultPredicateGenerator ] ( keyPath , keyPath ) ;
XCTAssert ( [ RLMPredicateUtil isEmptyIntColWithPredicate : predicate ] ,
@ "Key path in both locations in an integer comparison." ) ;
predicate = [ RLMPredicateUtil defaultPredicateGenerator ] ( expr , expr ) ;
XCTAssertThrowsSpecificNamed ( [ RLMPredicateUtil isEmptyIntColWithPredicate : predicate ] ,
NSException , @ "Invalid predicate expressions" ,
@ "Key path in absent in an integer comparison." ) ;
}
- ( void ) testLiveQueriesInsideTransaction
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
{
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ YES , @ YES , @ 1 , @ 2 , @ 23.0 f , @ 1.7 f , @ 0.0 , @ 5.55 , @ "" , @ "" ] ] ;
RLMResults * resultsQuery = [ self . queryObjectClass objectsWhere : @ "bool1 = YES" ] ;
RLMResults * resultsTableView = [ self . queryObjectClass objectsWhere : @ "bool1 = YES" ] ;
// Force resultsTableView to form the TableView to verify that it syncs
// correctly, and don't call anything but count on resultsQuery so that
// it always reruns the query count method
( void ) [ resultsTableView firstObject ] ;
XCTAssertEqual ( resultsQuery . count , 1 U ) ;
XCTAssertEqual ( resultsTableView . count , 1 U ) ;
// Delete the (only) object in result set
[ realm deleteObject : [ resultsTableView lastObject ] ] ;
XCTAssertEqual ( resultsQuery . count , 0 U ) ;
XCTAssertEqual ( resultsTableView . count , 0 U ) ;
// Add an object that does not match query
QueryObject * q1 = [ self . queryObjectClass createInRealm : realm withValue : @ [ @ NO , @ YES , @ 1 , @ 2 , @ 23.0 f , @ 1.7 f , @ 0.0 , @ 5.55 , @ "" , @ "" ] ] ;
XCTAssertEqual ( resultsQuery . count , 0 U ) ;
XCTAssertEqual ( resultsTableView . count , 0 U ) ;
// Change object to match query
q1 [ @ "bool1" ] = @ YES ;
XCTAssertEqual ( resultsQuery . count , 1 U ) ;
XCTAssertEqual ( resultsTableView . count , 1 U ) ;
// Add another object that matches
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ YES , @ NO , @ 1 , @ 3 , @ - 5.3 f , @ 4.21 f , @ 1.0 , @ 4.44 , @ "" , @ "" ] ] ;
XCTAssertEqual ( resultsQuery . count , 2 U ) ;
XCTAssertEqual ( resultsTableView . count , 2 U ) ;
}
[ realm commitWriteTransaction ] ;
}
- ( void ) testLiveQueriesBetweenTransactions
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ YES , @ YES , @ 1 , @ 2 , @ 23.0 f , @ 1.7 f , @ 0.0 , @ 5.55 , @ "" , @ "" ] ] ;
[ realm commitWriteTransaction ] ;
RLMResults * resultsQuery = [ self . queryObjectClass objectsWhere : @ "bool1 = YES" ] ;
RLMResults * resultsTableView = [ self . queryObjectClass objectsWhere : @ "bool1 = YES" ] ;
// Force resultsTableView to form the TableView to verify that it syncs
// correctly, and don't call anything but count on resultsQuery so that
// it always reruns the query count method
( void ) [ resultsTableView firstObject ] ;
XCTAssertEqual ( resultsQuery . count , 1 U ) ;
XCTAssertEqual ( resultsTableView . count , 1 U ) ;
// Delete the (only) object in result set
[ realm beginWriteTransaction ] ;
[ realm deleteObject : [ resultsTableView lastObject ] ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( resultsQuery . count , 0 U ) ;
XCTAssertEqual ( resultsTableView . count , 0 U ) ;
// Add an object that does not match query
[ realm beginWriteTransaction ] ;
QueryObject * q1 = [ self . queryObjectClass createInRealm : realm withValue : @ [ @ NO , @ YES , @ 1 , @ 2 , @ 23.0 f , @ 1.7 f , @ 0.0 , @ 5.55 , @ "" , @ "" ] ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( resultsQuery . count , 0 U ) ;
XCTAssertEqual ( resultsTableView . count , 0 U ) ;
// Change object to match query
[ realm beginWriteTransaction ] ;
q1 [ @ "bool1" ] = @ YES ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( resultsQuery . count , 1 U ) ;
XCTAssertEqual ( resultsTableView . count , 1 U ) ;
// Add another object that matches
[ realm beginWriteTransaction ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ YES , @ NO , @ 1 , @ 3 , @ - 5.3 f , @ 4.21 f , @ 1.0 , @ 4.44 , @ "" , @ "" ] ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( resultsQuery . count , 2 U ) ;
XCTAssertEqual ( resultsTableView . count , 2 U ) ;
}
- ( void ) makeDogWithName : ( NSString * ) name owner : ( NSString * ) ownerName {
RLMRealm * realm = [ self realmWithTestPath ] ;
OwnerObject * owner = [ [ OwnerObject alloc ] init ] ;
owner . name = ownerName ;
owner . dog = [ [ DogObject alloc ] init ] ;
owner . dog . dogName = name ;
[ realm beginWriteTransaction ] ;
[ realm addObject : owner ] ;
[ realm commitWriteTransaction ] ;
}
- ( void ) makeDogWithAge : ( int ) age owner : ( NSString * ) ownerName {
RLMRealm * realm = [ self realmWithTestPath ] ;
OwnerObject * owner = [ [ OwnerObject alloc ] init ] ;
owner . name = ownerName ;
owner . dog = [ [ DogObject alloc ] init ] ;
owner . dog . dogName = @ "" ;
owner . dog . age = age ;
[ realm beginWriteTransaction ] ;
[ realm addObject : owner ] ;
[ realm commitWriteTransaction ] ;
}
- ( void ) testLinkQueryString
{
RLMRealm * realm = [ self realmWithTestPath ] ;
[ self makeDogWithName : @ "Harvie" owner : @ "Tim" ] ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName = 'Harvie'" ] . count ) , 1 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName != 'Harvie'" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName = 'eivraH'" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName = 'Fido'" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName IN {'Fido', 'Harvie'}" ] . count ) , 1 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName IN {'Fido', 'eivraH'}" ] . count ) , 0 U ) ;
[ self makeDogWithName : @ "Harvie" owner : @ "Joe" ] ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName = 'Harvie'" ] . count ) , 2 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName != 'Harvie'" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName = 'eivraH'" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName = 'Fido'" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName IN {'Fido', 'Harvie'}" ] . count ) , 2 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName IN {'Fido', 'eivraH'}" ] . count ) , 0 U ) ;
[ self makeDogWithName : @ "Fido" owner : @ "Jim" ] ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName = 'Harvie'" ] . count ) , 2 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName != 'Harvie'" ] . count ) , 1 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName = 'eivraH'" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName = 'Fido'" ] . count ) , 1 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName IN {'Fido', 'Harvie'}" ] . count ) , 3 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName IN {'Fido', 'eivraH'}" ] . count ) , 1 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName = 'Harvie' and name = 'Tim'" ] . count ) , 1 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.dogName = 'Harvie' and name = 'Jim'" ] . count ) , 0 U ) ;
// test invalid operators
XCTAssertThrows ( [ realm objects : [ OwnerObject className ] where : @ "dog.dogName > 'Harvie'" ] , @ "Invalid operator should throw" ) ;
}
- ( void ) testLinkQueryInt
{
RLMRealm * realm = [ self realmWithTestPath ] ;
[ self makeDogWithAge : 5 owner : @ "Tim" ] ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age = 5" ] . count ) , 1 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age != 5" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age = 10" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age = 8" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age IN {5, 8}" ] . count ) , 1 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age IN {8, 10}" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age BETWEEN {0, 10}" ] . count ) , 1 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age BETWEEN {0, 7}" ] . count ) , 1 U ) ;
[ self makeDogWithAge : 5 owner : @ "Joe" ] ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age = 5" ] . count ) , 2 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age != 5" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age = 10" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age = 8" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age IN {5, 8}" ] . count ) , 2 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age IN {8, 10}" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age BETWEEN {0, 10}" ] . count ) , 2 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age BETWEEN {0, 7}" ] . count ) , 2 U ) ;
[ self makeDogWithAge : 8 owner : @ "Jim" ] ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age = 5" ] . count ) , 2 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age != 5" ] . count ) , 1 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age = 10" ] . count ) , 0 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age = 8" ] . count ) , 1 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age IN {5, 8}" ] . count ) , 3 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age IN {8, 10}" ] . count ) , 1 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age BETWEEN {0, 10}" ] . count ) , 3 U ) ;
XCTAssertEqual ( ( [ OwnerObject objectsInRealm : realm where : @ "dog.age BETWEEN {0, 7}" ] . count ) , 2 U ) ;
}
- ( void ) testLinkQueryAllTypes
{
RLMRealm * realm = [ self realmWithTestPath ] ;
NSDate * now = [ NSDate dateWithTimeIntervalSince1970 : 100000 ] ;
LinkToAllTypesObject * linkToAllTypes = [ [ LinkToAllTypesObject alloc ] init ] ;
linkToAllTypes . allTypesCol = [ [ AllTypesObject alloc ] init ] ;
linkToAllTypes . allTypesCol . boolCol = YES ;
linkToAllTypes . allTypesCol . intCol = 1 ;
linkToAllTypes . allTypesCol . floatCol = 1.1 f ;
linkToAllTypes . allTypesCol . doubleCol = 1.11 ;
linkToAllTypes . allTypesCol . stringCol = @ "string" ;
linkToAllTypes . allTypesCol . binaryCol = [ NSData dataWithBytes : "a" length : 1 ] ;
linkToAllTypes . allTypesCol . dateCol = now ;
linkToAllTypes . allTypesCol . cBoolCol = YES ;
linkToAllTypes . allTypesCol . longCol = 11 ;
linkToAllTypes . allTypesCol . mixedCol = @ 0 ;
StringObject * obj = [ [ StringObject alloc ] initWithValue : @ [ @ "string" ] ] ;
linkToAllTypes . allTypesCol . objectCol = obj ;
[ realm beginWriteTransaction ] ;
[ realm addObject : linkToAllTypes ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.boolCol = YES" ] count ] , 1 U ) ;
XCTAssertEqual ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.boolCol = NO" ] count ] , 0 U ) ;
XCTAssertEqual ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.intCol = 1" ] count ] , 1 U ) ;
XCTAssertEqual ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.intCol != 1" ] count ] , 0 U ) ;
XCTAssertEqual ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.intCol > 0" ] count ] , 1 U ) ;
XCTAssertEqual ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.intCol > 1" ] count ] , 0 U ) ;
NSPredicate * predEq = [ NSPredicate predicateWithFormat : @ "allTypesCol.floatCol = %f" , 1.1 ] ;
XCTAssertEqual ( [ LinkToAllTypesObject objectsInRealm : realm withPredicate : predEq ] . count , 1 U ) ;
NSPredicate * predLessEq = [ NSPredicate predicateWithFormat : @ "allTypesCol.floatCol <= %f" , 1.1 ] ;
XCTAssertEqual ( [ LinkToAllTypesObject objectsInRealm : realm withPredicate : predLessEq ] . count , 1 U ) ;
NSPredicate * predLess = [ NSPredicate predicateWithFormat : @ "allTypesCol.floatCol < %f" , 1.1 ] ;
XCTAssertEqual ( [ LinkToAllTypesObject objectsInRealm : realm withPredicate : predLess ] . count , 0 U ) ;
XCTAssertEqual ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.doubleCol = 1.11" ] count ] , 1 U ) ;
XCTAssertEqual ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.doubleCol >= 1.11" ] count ] , 1 U ) ;
XCTAssertEqual ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.doubleCol > 1.11" ] count ] , 0 U ) ;
XCTAssertEqual ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.longCol = 11" ] count ] , 1 U ) ;
XCTAssertEqual ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.longCol != 11" ] count ] , 0 U ) ;
XCTAssertEqual ( ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.dateCol = %@" , now ] count ] ) , 1 U ) ;
XCTAssertEqual ( ( [ [ realm objects : [ LinkToAllTypesObject className ] where : @ "allTypesCol.dateCol != %@" , now ] count ] ) , 0 U ) ;
}
- ( void ) testLinkQueryInvalid {
XCTAssertThrows ( [ LinkToAllTypesObject objectsWhere : @ "allTypesCol.binaryCol = 'a'" ] , @ "Binary data not supported" ) ;
XCTAssertThrows ( [ LinkToAllTypesObject objectsWhere : @ "allTypesCol.mixedCol = 'a'" ] , @ "Mixed data not supported" ) ;
XCTAssertThrows ( [ LinkToAllTypesObject objectsWhere : @ "allTypesCol.invalidCol = 'a'" ] , @ "Invalid column name should throw" ) ;
XCTAssertThrows ( [ LinkToAllTypesObject objectsWhere : @ "allTypesCol.longCol = 'a'" ] , @ "Wrong data type should throw" ) ;
XCTAssertThrows ( [ LinkToAllTypesObject objectsWhere : @ "intArray.intCol > 5" ] , @ "RLMArray query without ANY modifier should throw" ) ;
}
- ( void ) testLinkQueryMany
{
RLMRealm * realm = [ self realmWithTestPath ] ;
ArrayPropertyObject * arrPropObj1 = [ [ ArrayPropertyObject alloc ] init ] ;
arrPropObj1 . name = @ "Test" ;
for ( NSUInteger i = 0 ; i < 10 ; i ++ ) {
StringObject * sobj = [ [ StringObject alloc ] init ] ;
sobj . stringCol = [ NSString stringWithFormat : @ "%lu" , ( unsigned long ) i ] ;
[ arrPropObj1 . array addObject : sobj ] ;
IntObject * iobj = [ [ IntObject alloc ] init ] ;
iobj . intCol = ( int ) i ;
[ arrPropObj1 . intArray addObject : iobj ] ;
}
[ realm beginWriteTransaction ] ;
[ realm addObject : arrPropObj1 ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( [ [ realm objects : [ ArrayPropertyObject className ] where : @ "ANY intArray.intCol > 10" ] count ] , 0 U ) ;
XCTAssertEqual ( [ [ realm objects : [ ArrayPropertyObject className ] where : @ "ANY intArray.intCol > 5" ] count ] , 1 U ) ;
XCTAssertEqual ( [ [ realm objects : [ ArrayPropertyObject className ] where : @ "ANY array.stringCol = '1'" ] count ] , 1 U ) ;
XCTAssertEqual ( [ realm objects : [ ArrayPropertyObject className ] where : @ "NONE intArray.intCol == 5" ] . count , 0 U ) ;
XCTAssertEqual ( [ realm objects : [ ArrayPropertyObject className ] where : @ "NONE intArray.intCol > 10" ] . count , 1 U ) ;
ArrayPropertyObject * arrPropObj2 = [ [ ArrayPropertyObject alloc ] init ] ;
arrPropObj2 . name = @ "Test" ;
for ( NSUInteger i = 0 ; i < 4 ; i ++ ) {
StringObject * sobj = [ [ StringObject alloc ] init ] ;
sobj . stringCol = [ NSString stringWithFormat : @ "%lu" , ( unsigned long ) i ] ;
[ arrPropObj2 . array addObject : sobj ] ;
IntObject * iobj = [ [ IntObject alloc ] init ] ;
iobj . intCol = ( int ) i ;
[ arrPropObj2 . intArray addObject : iobj ] ;
}
[ realm beginWriteTransaction ] ;
[ realm addObject : arrPropObj2 ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( [ [ realm objects : [ ArrayPropertyObject className ] where : @ "ANY intArray.intCol > 10" ] count ] , 0 U ) ;
XCTAssertEqual ( [ [ realm objects : [ ArrayPropertyObject className ] where : @ "ANY intArray.intCol > 5" ] count ] , 1 U ) ;
XCTAssertEqual ( [ [ realm objects : [ ArrayPropertyObject className ] where : @ "ANY intArray.intCol > 2" ] count ] , 2 U ) ;
XCTAssertEqual ( [ realm objects : [ ArrayPropertyObject className ] where : @ "NONE intArray.intCol == 5" ] . count , 1 U ) ;
XCTAssertEqual ( [ realm objects : [ ArrayPropertyObject className ] where : @ "NONE intArray.intCol > 10" ] . count , 2 U ) ;
}
- ( void ) testMultiLevelLinkQuery
{
RLMRealm * realm = [ self realmWithTestPath ] ;
[ realm beginWriteTransaction ] ;
CircleObject * circle = nil ;
for ( int i = 0 ; i < 5 ; ++ i ) {
circle = [ CircleObject createInRealm : realm withValue : @ { @ "data" : [ NSString stringWithFormat : @ "%d" , i ] ,
@ "next" : circle ? : NSNull . null } ] ;
}
[ realm commitWriteTransaction ] ;
XCTAssertTrue ( [ circle isEqualToObject : [ CircleObject objectsInRealm : realm where : @ "data = '4'" ] . firstObject ] ) ;
XCTAssertTrue ( [ circle isEqualToObject : [ CircleObject objectsInRealm : realm where : @ "next.data = '3'" ] . firstObject ] ) ;
XCTAssertTrue ( [ circle isEqualToObject : [ CircleObject objectsInRealm : realm where : @ "next.next.data = '2'" ] . firstObject ] ) ;
XCTAssertTrue ( [ circle isEqualToObject : [ CircleObject objectsInRealm : realm where : @ "next.next.next.data = '1'" ] . firstObject ] ) ;
XCTAssertTrue ( [ circle isEqualToObject : [ CircleObject objectsInRealm : realm where : @ "next.next.next.next.data = '0'" ] . firstObject ] ) ;
XCTAssertTrue ( [ circle . next isEqualToObject : [ CircleObject objectsInRealm : realm where : @ "next.next.next.data = '0'" ] . firstObject ] ) ;
XCTAssertTrue ( [ circle . next . next isEqualToObject : [ CircleObject objectsInRealm : realm where : @ "next.next.data = '0'" ] . firstObject ] ) ;
XCTAssertNoThrow ( ( [ CircleObject objectsInRealm : realm where : @ "next = %@" , circle ] ) ) ;
XCTAssertThrows ( ( [ CircleObject objectsInRealm : realm where : @ "next.next = %@" , circle ] ) ) ;
XCTAssertTrue ( [ circle . next . next . next . next isEqualToObject : [ CircleObject objectsInRealm : realm where : @ "next = nil" ] . firstObject ] ) ;
}
- ( void ) testArrayMultiLevelLinkQuery
{
RLMRealm * realm = [ self realmWithTestPath ] ;
[ realm beginWriteTransaction ] ;
CircleObject * circle = nil ;
for ( int i = 0 ; i < 5 ; ++ i ) {
circle = [ CircleObject createInRealm : realm withValue : @ { @ "data" : [ NSString stringWithFormat : @ "%d" , i ] ,
@ "next" : circle ? : NSNull . null } ] ;
}
[ CircleArrayObject createInRealm : realm withValue : @ [ [ CircleObject allObjectsInRealm : realm ] ] ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( 1 U , [ CircleArrayObject objectsInRealm : realm where : @ "ANY circles.data = '4'" ] . count ) ;
XCTAssertEqual ( 0 U , [ CircleArrayObject objectsInRealm : realm where : @ "ANY circles.next.data = '4'" ] . count ) ;
XCTAssertEqual ( 1 U , [ CircleArrayObject objectsInRealm : realm where : @ "ANY circles.next.data = '3'" ] . count ) ;
XCTAssertEqual ( 1 U , [ CircleArrayObject objectsInRealm : realm where : @ "ANY circles.data = '3'" ] . count ) ;
XCTAssertEqual ( 1 U , [ CircleArrayObject objectsInRealm : realm where : @ "NONE circles.next.data = '4'" ] . count ) ;
XCTAssertEqual ( 0 U , [ CircleArrayObject objectsInRealm : realm where : @ "ANY circles.next.next.data = '3'" ] . count ) ;
XCTAssertEqual ( 1 U , [ CircleArrayObject objectsInRealm : realm where : @ "ANY circles.next.next.data = '2'" ] . count ) ;
XCTAssertEqual ( 1 U , [ CircleArrayObject objectsInRealm : realm where : @ "ANY circles.next.data = '2'" ] . count ) ;
XCTAssertEqual ( 1 U , [ CircleArrayObject objectsInRealm : realm where : @ "ANY circles.data = '2'" ] . count ) ;
XCTAssertEqual ( 1 U , [ CircleArrayObject objectsInRealm : realm where : @ "NONE circles.next.next.data = '3'" ] . count ) ;
XCTAssertThrows ( [ CircleArrayObject objectsInRealm : realm where : @ "ANY data = '2'" ] ) ;
XCTAssertThrows ( [ CircleArrayObject objectsInRealm : realm where : @ "ANY circles.next = '2'" ] ) ;
XCTAssertThrows ( [ CircleArrayObject objectsInRealm : realm where : @ "ANY data.circles = '2'" ] ) ;
XCTAssertThrows ( [ CircleArrayObject objectsInRealm : realm where : @ "circles.data = '2'" ] ) ;
XCTAssertThrows ( [ CircleArrayObject objectsInRealm : realm where : @ "NONE data.circles = '2'" ] ) ;
}
- ( void ) testQueryWithObjects
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
NSDate * date1 = [ NSDate date ] ;
NSDate * date2 = [ date1 dateByAddingTimeInterval : 1 ] ;
NSDate * date3 = [ date2 dateByAddingTimeInterval : 1 ] ;
[ realm beginWriteTransaction ] ;
StringObject * stringObj0 = [ StringObject createInRealm : realm withValue : @ [ @ "string0" ] ] ;
StringObject * stringObj1 = [ StringObject createInRealm : realm withValue : @ [ @ "string1" ] ] ;
StringObject * stringObj2 = [ StringObject createInRealm : realm withValue : @ [ @ "string2" ] ] ;
AllTypesObject * obj0 = [ AllTypesObject createInRealm : realm withValue : @ [ @ YES , @ 1 , @ 1.0 f , @ 1.0 , @ "a" , [ @ "a" dataUsingEncoding : NSUTF8StringEncoding ] , date1 , @ YES , @ 1 LL , @ 1 , stringObj0 ] ] ;
AllTypesObject * obj1 = [ AllTypesObject createInRealm : realm withValue : @ [ @ YES , @ 2 , @ 2.0 f , @ 2.0 , @ "b" , [ @ "b" dataUsingEncoding : NSUTF8StringEncoding ] , date2 , @ YES , @ 2 LL , @ "mixed" , stringObj1 ] ] ;
AllTypesObject * obj2 = [ AllTypesObject createInRealm : realm withValue : @ [ @ NO , @ 3 , @ 3.0 f , @ 3.0 , @ "c" , [ @ "c" dataUsingEncoding : NSUTF8StringEncoding ] , date3 , @ YES , @ 3 LL , @ "mixed" , stringObj0 ] ] ;
AllTypesObject * obj3 = [ AllTypesObject createInRealm : realm withValue : @ [ @ NO , @ 3 , @ 3.0 f , @ 3.0 , @ "c" , [ @ "c" dataUsingEncoding : NSUTF8StringEncoding ] , date3 , @ YES , @ 3 LL , @ "mixed" , stringObj2 ] ] ;
AllTypesObject * obj4 = [ AllTypesObject createInRealm : realm withValue : @ [ @ NO , @ 3 , @ 3.0 f , @ 3.0 , @ "c" , [ @ "c" dataUsingEncoding : NSUTF8StringEncoding ] , date3 , @ YES , @ 34359738368 LL , @ "mixed" , NSNull . null ] ] ;
[ ArrayOfAllTypesObject createInDefaultRealmWithValue : @ [ @ [ obj0 , obj1 ] ] ] ;
[ ArrayOfAllTypesObject createInDefaultRealmWithValue : @ [ @ [ obj1 ] ] ] ;
[ ArrayOfAllTypesObject createInDefaultRealmWithValue : @ [ @ [ obj0 , obj2 , obj3 ] ] ] ;
[ ArrayOfAllTypesObject createInDefaultRealmWithValue : @ [ @ [ obj4 ] ] ] ;
[ realm commitWriteTransaction ] ;
// simple queries
XCTAssertEqual ( 2 U , ( [ AllTypesObject objectsWhere : @ "objectCol = %@" , stringObj0 ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ AllTypesObject objectsWhere : @ "objectCol = %@" , stringObj1 ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ AllTypesObject objectsWhere : @ "objectCol = nil" ] . count ) ) ;
XCTAssertEqual ( 4 U , ( [ AllTypesObject objectsWhere : @ "objectCol != nil" ] . count ) ) ;
XCTAssertEqual ( 3 U , ( [ AllTypesObject objectsWhere : @ "objectCol != %@" , stringObj0 ] . count ) ) ;
NSPredicate * longPred = [ NSPredicate predicateWithFormat : @ "longCol = %lli" , 34359738368 ] ;
XCTAssertEqual ( [ AllTypesObject objectsWithPredicate : longPred ] . count , 1 U , @ "Count should be 1" ) ;
NSPredicate * longBetweenPred = [ NSPredicate predicateWithFormat : @ "longCol BETWEEN %@" , @ [ @ 34359738367 LL , @ 34359738369 LL ] ] ;
XCTAssertEqual ( [ AllTypesObject objectsWithPredicate : longBetweenPred ] . count , 1 U , @ "Count should be 1" ) ;
// check for ANY object in array
XCTAssertEqual ( 2 U , ( [ ArrayOfAllTypesObject objectsWhere : @ "ANY array = %@" , obj0 ] . count ) ) ;
XCTAssertEqual ( 2 U , ( [ ArrayOfAllTypesObject objectsWhere : @ "ANY array != %@" , obj1 ] . count ) ) ;
XCTAssertEqual ( 2 U , ( [ ArrayOfAllTypesObject objectsWhere : @ "NONE array = %@" , obj0 ] . count ) ) ;
XCTAssertEqual ( 2 U , ( [ ArrayOfAllTypesObject objectsWhere : @ "NONE array != %@" , obj1 ] . count ) ) ;
XCTAssertThrows ( ( [ ArrayOfAllTypesObject objectsWhere : @ "array = %@" , obj0 ] . count ) ) ;
XCTAssertThrows ( ( [ ArrayOfAllTypesObject objectsWhere : @ "array != %@" , obj0 ] . count ) ) ;
}
- ( void ) testCompoundOrQuery {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Tim" , @ 29 ] ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Ari" , @ 33 ] ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( 2 U , [ [ PersonObject objectsWhere : @ "name == 'Ari' or age < 30" ] count ] ) ;
XCTAssertEqual ( 1 U , [ [ PersonObject objectsWhere : @ "name == 'Ari' or age > 40" ] count ] ) ;
}
- ( void ) testCompoundAndQuery {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Tim" , @ 29 ] ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Ari" , @ 33 ] ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( 1 U , [ [ PersonObject objectsWhere : @ "name == 'Ari' and age > 30" ] count ] ) ;
XCTAssertEqual ( 0 U , [ [ PersonObject objectsWhere : @ "name == 'Ari' and age > 40" ] count ] ) ;
}
- ( void ) testClass : ( Class ) class
withNormalCount : ( NSUInteger ) normalCount
notCount : ( NSUInteger ) notCount
where : ( NSString * ) predicateFormat , ...
{
va _list args ;
va _start ( args , predicateFormat ) ;
va _end ( args ) ;
XCTAssertEqual ( normalCount , [ [ class objectsWithPredicate : [ NSPredicate predicateWithFormat : predicateFormat arguments : args ] ] count ] ) ;
predicateFormat = [ NSString stringWithFormat : @ "NOT(%@)" , predicateFormat ] ;
va _start ( args , predicateFormat ) ;
va _end ( args ) ;
XCTAssertEqual ( notCount , [ [ class objectsWithPredicate : [ NSPredicate predicateWithFormat : predicateFormat arguments : args ] ] count ] ) ;
}
- ( void ) testINPredicate
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
StringObject * so = [ StringObject createInRealm : realm withValue : ( @ [ @ "abc" ] ) ] ;
[ AllTypesObject createInRealm : realm withValue : @ [ @ YES , @ 1 , @ 1.0 f , @ 1.0 , @ "abc" , [ @ "a" dataUsingEncoding : NSUTF8StringEncoding ] , [ NSDate dateWithTimeIntervalSince1970 : 1 ] , @ YES , @ 1 LL , @ 1 , so ] ] ;
[ realm commitWriteTransaction ] ;
// Tests for each type always follow: none, some, more
////////////////////////
// Literal Predicates
////////////////////////
// BOOL
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 notCount : 1 where : @ "boolCol IN {NO}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "boolCol IN {YES}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "boolCol IN {NO, YES}" ] ;
// int
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 notCount : 1 where : @ "intCol IN {0, 2, 3}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "intCol IN {1}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "intCol IN {1, 2}" ] ;
// float
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 notCount : 1 where : @ "floatCol IN {0, 2, 3}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "floatCol IN {1}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "floatCol IN {1, 2}" ] ;
// double
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 notCount : 1 where : @ "doubleCol IN {0, 2, 3}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "doubleCol IN {1}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "doubleCol IN {1, 2}" ] ;
// NSString
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "stringCol IN {'abc'}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 notCount : 1 where : @ "stringCol IN {'def'}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 notCount : 1 where : @ "stringCol IN {'ABC'}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "stringCol IN[c] {'abc'}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "stringCol IN[c] {'ABC'}" ] ;
// NSData
// Can't represent NSData with NSPredicate literal. See format predicates below
// NSDate
// Can't represent NSDate with NSPredicate literal. See format predicates below
// bool
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 notCount : 1 where : @ "cBoolCol IN {NO}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "cBoolCol IN {YES}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "cBoolCol IN {NO, YES}" ] ;
// int64_t
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 notCount : 1 where : @ "longCol IN {0, 2, 3}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "longCol IN {1}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "longCol IN {1, 2}" ] ;
// mixed
// FIXME: Support IN predicates with mixed properties
XCTAssertThrows ( [ AllTypesObject objectsWhere : @ "mixedCol IN {0, 2, 3}" ] ) ;
XCTAssertThrows ( [ AllTypesObject objectsWhere : @ "NOT(mixedCol IN {0, 2, 3})" ] ) ;
// string subobject
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "objectCol.stringCol IN {'abc'}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 notCount : 1 where : @ "objectCol.stringCol IN {'def'}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 notCount : 1 where : @ "objectCol.stringCol IN {'ABC'}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "objectCol.stringCol IN[c] {'abc'}" ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 notCount : 0 where : @ "objectCol.stringCol IN[c] {'ABC'}" ] ;
////////////////////////
// Format Predicates
////////////////////////
// BOOL
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 U notCount : 1 U where : @ "boolCol IN %@" , @ [ @ NO ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "boolCol IN %@" , @ [ @ YES ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "boolCol IN %@" , @ [ @ NO , @ YES ] ] ;
// int
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 U notCount : 1 U where : @ "intCol IN %@" , @ [ @ 0 , @ 2 , @ 3 ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "intCol IN %@" , @ [ @ 1 ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "intCol IN %@" , @ [ @ 1 , @ 2 ] ] ;
// float
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 U notCount : 1 U where : @ "floatCol IN %@" , @ [ @ 0 , @ 2 , @ 3 ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "floatCol IN %@" , @ [ @ 1 ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "floatCol IN %@" , @ [ @ 1 , @ 2 ] ] ;
// double
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 U notCount : 1 U where : @ "doubleCol IN %@" , @ [ @ 0 , @ 2 , @ 3 ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "doubleCol IN %@" , @ [ @ 1 ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "doubleCol IN %@" , @ [ @ 1 , @ 2 ] ] ;
// NSString
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "stringCol IN %@" , @ [ @ "abc" ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 U notCount : 1 U where : @ "stringCol IN %@" , @ [ @ "def" ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 U notCount : 1 U where : @ "stringCol IN %@" , @ [ @ "ABC" ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "stringCol IN[c] %@" , @ [ @ "abc" ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "stringCol IN[c] %@" , @ [ @ "ABC" ] ] ;
// NSData
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 U notCount : 1 U where : @ "binaryCol IN %@" , @ [ [ @ "" dataUsingEncoding : NSUTF8StringEncoding ] ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "binaryCol IN %@" , @ [ [ @ "a" dataUsingEncoding : NSUTF8StringEncoding ] ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "binaryCol IN %@" , @ [ [ @ "a" dataUsingEncoding : NSUTF8StringEncoding ] , [ @ "b" dataUsingEncoding : NSUTF8StringEncoding ] ] ] ;
// NSDate
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 U notCount : 1 U where : @ "dateCol IN %@" , @ [ [ NSDate dateWithTimeIntervalSince1970 : 0 ] ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "dateCol IN %@" , @ [ [ NSDate dateWithTimeIntervalSince1970 : 1 ] ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "dateCol IN %@" , @ [ [ NSDate dateWithTimeIntervalSince1970 : 0 ] , [ NSDate dateWithTimeIntervalSince1970 : 1 ] ] ] ;
// bool
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 U notCount : 1 U where : @ "cBoolCol IN %@" , @ [ @ NO ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "cBoolCol IN %@" , @ [ @ YES ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "cBoolCol IN %@" , @ [ @ NO , @ YES ] ] ;
// int64_t
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 U notCount : 1 U where : @ "longCol IN %@" , @ [ @ 0 , @ 2 , @ 3 ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "longCol IN %@" , @ [ @ 1 ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "longCol IN %@" , @ [ @ 1 , @ 2 ] ] ;
// mixed
// FIXME: Support IN predicates with mixed properties
XCTAssertThrows ( ( [ [ AllTypesObject objectsWhere : @ "mixedCol IN %@" , @ [ @ 0 , @ 2 , @ 3 ] ] count ] ) ) ;
XCTAssertThrows ( ( [ [ AllTypesObject objectsWhere : @ "NOT(mixedCol IN %@)" , @ [ @ 0 , @ 2 , @ 3 ] ] count ] ) ) ;
// string subobject
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "objectCol.stringCol IN %@" , @ [ @ "abc" ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 U notCount : 1 U where : @ "objectCol.stringCol IN %@" , @ [ @ "def" ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 0 U notCount : 1 U where : @ "objectCol.stringCol IN %@" , @ [ @ "ABC" ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "objectCol.stringCol IN[c] %@" , @ [ @ "abc" ] ] ;
[ self testClass : [ AllTypesObject class ] withNormalCount : 1 U notCount : 0 U where : @ "objectCol.stringCol IN[c] %@" , @ [ @ "ABC" ] ] ;
}
- ( void ) testArrayIn
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
ArrayPropertyObject * arr = [ ArrayPropertyObject createInRealm : realm withValue : @ [ @ "name" , @ [ ] , @ [ ] ] ] ;
[ arr . array addObject : [ StringObject createInRealm : realm withValue : @ [ @ "value" ] ] ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( 0 U , ( [ [ ArrayPropertyObject objectsWhere : @ "ANY array.stringCol IN %@" , @ [ @ "missing" ] ] count ] ) ) ;
XCTAssertEqual ( 1 U , ( [ [ ArrayPropertyObject objectsWhere : @ "ANY array.stringCol IN %@" , @ [ @ "value" ] ] count ] ) ) ;
XCTAssertEqual ( 1 U , ( [ [ ArrayPropertyObject objectsWhere : @ "NONE array.stringCol IN %@" , @ [ @ "missing" ] ] count ] ) ) ;
XCTAssertEqual ( 0 U , ( [ [ ArrayPropertyObject objectsWhere : @ "NONE array.stringCol IN %@" , @ [ @ "value" ] ] count ] ) ) ;
XCTAssertEqual ( 0 U , ( [ [ ArrayPropertyObject objectsWhere : @ "ANY array IN %@" , [ StringObject objectsWhere : @ "stringCol = 'missing'" ] ] count ] ) ) ;
XCTAssertEqual ( 1 U , ( [ [ ArrayPropertyObject objectsWhere : @ "ANY array IN %@" , [ StringObject objectsWhere : @ "stringCol = 'value'" ] ] count ] ) ) ;
XCTAssertEqual ( 1 U , ( [ [ ArrayPropertyObject objectsWhere : @ "NONE array IN %@" , [ StringObject objectsWhere : @ "stringCol = 'missing'" ] ] count ] ) ) ;
XCTAssertEqual ( 0 U , ( [ [ ArrayPropertyObject objectsWhere : @ "NONE array IN %@" , [ StringObject objectsWhere : @ "stringCol = 'value'" ] ] count ] ) ) ;
}
- ( void ) testQueryChaining {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Tim" , @ 29 ] ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Ari" , @ 33 ] ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( 1 U , [ [ PersonObject objectsWhere : @ "name == 'Ari'" ] count ] ) ;
XCTAssertEqual ( 0 U , [ [ PersonObject objectsWhere : @ "name == 'Ari' and age == 29" ] count ] ) ;
XCTAssertEqual ( 0 U , [ [ [ PersonObject objectsWhere : @ "name == 'Ari'" ] objectsWhere : @ "age == 29" ] count ] ) ;
}
- ( void ) testLinkViewQuery {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ CompanyObject createInRealm : realm
withValue : @ [ @ "company name" , @ [ @ { @ "name" : @ "John" , @ "age" : @ 30 , @ "hired" : @ NO } ,
@ { @ "name" : @ "Joe" , @ "age" : @ 40 , @ "hired" : @ YES } ,
@ { @ "name" : @ "Jill" , @ "age" : @ 50 , @ "hired" : @ YES } ] ] ] ;
[ realm commitWriteTransaction ] ;
CompanyObject * co = [ CompanyObject allObjects ] [ 0 ] ;
XCTAssertEqual ( 1 U , [ co . employees objectsWhere : @ "hired = NO" ] . count ) ;
XCTAssertEqual ( 2 U , [ co . employees objectsWhere : @ "hired = YES" ] . count ) ;
XCTAssertEqual ( 1 U , [ co . employees objectsWhere : @ "hired = YES AND age = 40" ] . count ) ;
XCTAssertEqual ( 0 U , [ co . employees objectsWhere : @ "hired = YES AND age = 30" ] . count ) ;
XCTAssertEqual ( 3 U , [ co . employees objectsWhere : @ "hired = YES OR age = 30" ] . count ) ;
XCTAssertEqual ( 1 U , [ [ co . employees objectsWhere : @ "hired = YES" ] objectsWhere : @ "name = 'Joe'" ] . count ) ;
}
- ( void ) testLinkViewQueryLifetime {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ CompanyObject createInRealm : realm
withValue : @ [ @ "company name" , @ [ @ { @ "name" : @ "John" , @ "age" : @ 30 , @ "hired" : @ NO } ,
@ { @ "name" : @ "Jill" , @ "age" : @ 50 , @ "hired" : @ YES } ] ] ] ;
[ EmployeeObject createInRealm : realm withValue : @ { @ "name" : @ "Joe" , @ "age" : @ 40 , @ "hired" : @ YES } ] ;
[ realm commitWriteTransaction ] ;
RLMResults * subarray = nil ;
@ autoreleasepool {
_ _attribute ( ( objc _precise _lifetime ) ) CompanyObject * co = [ CompanyObject allObjects ] [ 0 ] ;
subarray = [ co . employees objectsWhere : @ "age = 40" ] ;
XCTAssertEqual ( 0 U , subarray . count ) ;
}
[ realm beginWriteTransaction ] ;
@ autoreleasepool {
_ _attribute ( ( objc _precise _lifetime ) ) CompanyObject * co = [ CompanyObject allObjects ] [ 0 ] ;
[ co . employees addObject : [ EmployeeObject createInRealm : realm withValue : @ { @ "name" : @ "Joe" , @ "age" : @ 40 , @ "hired" : @ YES } ] ] ;
}
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( 1 U , subarray . count ) ;
XCTAssertEqualObjects ( @ "Joe" , subarray [ 0 ] [ @ "name" ] ) ;
}
- ( void ) testLinkViewQueryLiveUpdate {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ CompanyObject createInRealm : realm
withValue : @ [ @ "company name" , @ [ @ { @ "name" : @ "John" , @ "age" : @ 30 , @ "hired" : @ NO } ,
@ { @ "name" : @ "Jill" , @ "age" : @ 40 , @ "hired" : @ YES } ] ] ] ;
EmployeeObject * eo = [ EmployeeObject createInRealm : realm withValue : @ { @ "name" : @ "Joe" , @ "age" : @ 40 , @ "hired" : @ YES } ] ;
[ realm commitWriteTransaction ] ;
CompanyObject * co = CompanyObject . allObjects . firstObject ;
RLMResults * basic = [ co . employees objectsWhere : @ "age = 40" ] ;
RLMResults * sort = [ co . employees sortedResultsUsingProperty : @ "name" ascending : YES ] ;
RLMResults * sortQuery = [ [ co . employees sortedResultsUsingProperty : @ "name" ascending : YES ] objectsWhere : @ "age = 40" ] ;
RLMResults * querySort = [ [ co . employees objectsWhere : @ "age = 40" ] sortedResultsUsingProperty : @ "name" ascending : YES ] ;
XCTAssertEqual ( 1 U , basic . count ) ;
XCTAssertEqual ( 2 U , sort . count ) ;
XCTAssertEqual ( 1 U , sortQuery . count ) ;
XCTAssertEqual ( 1 U , querySort . count ) ;
XCTAssertEqualObjects ( @ "Jill" , [ [ basic lastObject ] name ] ) ;
XCTAssertEqualObjects ( @ "Jill" , [ [ sortQuery lastObject ] name ] ) ;
XCTAssertEqualObjects ( @ "Jill" , [ [ querySort lastObject ] name ] ) ;
[ realm beginWriteTransaction ] ;
[ co . employees addObject : eo ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( 2 U , basic . count ) ;
XCTAssertEqual ( 3 U , sort . count ) ;
XCTAssertEqual ( 2 U , sortQuery . count ) ;
XCTAssertEqual ( 2 U , querySort . count ) ;
XCTAssertEqualObjects ( @ "Joe" , [ [ basic lastObject ] name ] ) ;
XCTAssertEqualObjects ( @ "Joe" , [ [ sortQuery lastObject ] name ] ) ;
XCTAssertEqualObjects ( @ "Joe" , [ [ querySort lastObject ] name ] ) ;
}
- ( void ) testConstantPredicates
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Fiel" , @ 27 ] ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Tim" , @ 29 ] ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Ari" , @ 33 ] ] ;
[ realm commitWriteTransaction ] ;
RLMResults * all = [ PersonObject objectsWithPredicate : [ NSPredicate predicateWithValue : YES ] ] ;
XCTAssertEqual ( all . count , 3 U , @ "Expecting 3 results" ) ;
RLMResults * none = [ PersonObject objectsWithPredicate : [ NSPredicate predicateWithValue : NO ] ] ;
XCTAssertEqual ( none . count , 0 U , @ "Expecting 0 results" ) ;
}
- ( void ) testEmptyCompoundPredicates
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Fiel" , @ 27 ] ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Tim" , @ 29 ] ] ;
[ PersonObject createInRealm : realm withValue : @ [ @ "Ari" , @ 33 ] ] ;
[ realm commitWriteTransaction ] ;
RLMResults * all = [ PersonObject objectsWithPredicate : [ NSCompoundPredicate andPredicateWithSubpredicates : @ [ ] ] ] ;
XCTAssertEqual ( all . count , 3 U , @ "Expecting 3 results" ) ;
RLMResults * none = [ PersonObject objectsWithPredicate : [ NSCompoundPredicate orPredicateWithSubpredicates : @ [ ] ] ] ;
XCTAssertEqual ( none . count , 0 U , @ "Expecting 0 results" ) ;
}
- ( void ) testComparisonsWithKeyPathOnRHS
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ YES , @ YES , @ 1 , @ 2 , @ 23.0 f , @ 1.7 f , @ 0.0 , @ 5.55 , @ "a" , @ "a" ] ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ YES , @ NO , @ 1 , @ 3 , @ - 5.3 f , @ 4.21 f , @ 1.0 , @ 4.44 , @ "a" , @ "A" ] ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ NO , @ NO , @ 2 , @ 2 , @ 1.0 f , @ 3.55 f , @ 99.9 , @ 6.66 , @ "a" , @ "ab" ] ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ NO , @ YES , @ 3 , @ 6 , @ 4.21 f , @ 1.0 f , @ 1.0 , @ 7.77 , @ "a" , @ "AB" ] ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ YES , @ YES , @ 4 , @ 5 , @ 23.0 f , @ 23.0 f , @ 7.4 , @ 8.88 , @ "a" , @ "b" ] ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ YES , @ NO , @ 15 , @ 8 , @ 1.0 f , @ 66.0 f , @ 1.01 , @ 9.99 , @ "a" , @ "ba" ] ] ;
[ self . queryObjectClass createInRealm : realm withValue : @ [ @ NO , @ YES , @ 15 , @ 15 , @ 1.0 f , @ 66.0 f , @ 1.01 , @ 9.99 , @ "a" , @ "BA" ] ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( 4 U , [ self . queryObjectClass objectsWhere : @ "TRUE == bool1" ] . count ) ;
XCTAssertEqual ( 3 U , [ self . queryObjectClass objectsWhere : @ "TRUE != bool2" ] . count ) ;
XCTAssertEqual ( 2 U , [ self . queryObjectClass objectsWhere : @ "1 == int1" ] . count ) ;
XCTAssertEqual ( 5 U , [ self . queryObjectClass objectsWhere : @ "2 != int2" ] . count ) ;
XCTAssertEqual ( 2 U , [ self . queryObjectClass objectsWhere : @ "2 > int1" ] . count ) ;
XCTAssertEqual ( 4 U , [ self . queryObjectClass objectsWhere : @ "2 < int1" ] . count ) ;
XCTAssertEqual ( 3 U , [ self . queryObjectClass objectsWhere : @ "2 >= int1" ] . count ) ;
XCTAssertEqual ( 5 U , [ self . queryObjectClass objectsWhere : @ "2 <= int1" ] . count ) ;
XCTAssertEqual ( 3 U , [ self . queryObjectClass objectsWhere : @ "1.0 == float1" ] . count ) ;
XCTAssertEqual ( 6 U , [ self . queryObjectClass objectsWhere : @ "1.0 != float2" ] . count ) ;
XCTAssertEqual ( 1 U , [ self . queryObjectClass objectsWhere : @ "1.0 > float1" ] . count ) ;
XCTAssertEqual ( 6 U , [ self . queryObjectClass objectsWhere : @ "1.0 < float2" ] . count ) ;
XCTAssertEqual ( 4 U , [ self . queryObjectClass objectsWhere : @ "1.0 >= float1" ] . count ) ;
XCTAssertEqual ( 7 U , [ self . queryObjectClass objectsWhere : @ "1.0 <= float2" ] . count ) ;
XCTAssertEqual ( 2 U , [ self . queryObjectClass objectsWhere : @ "1.0 == double1" ] . count ) ;
XCTAssertEqual ( 5 U , [ self . queryObjectClass objectsWhere : @ "1.0 != double1" ] . count ) ;
XCTAssertEqual ( 1 U , [ self . queryObjectClass objectsWhere : @ "5.0 > double2" ] . count ) ;
XCTAssertEqual ( 6 U , [ self . queryObjectClass objectsWhere : @ "5.0 < double2" ] . count ) ;
XCTAssertEqual ( 2 U , [ self . queryObjectClass objectsWhere : @ "5.55 >= double2" ] . count ) ;
XCTAssertEqual ( 6 U , [ self . queryObjectClass objectsWhere : @ "5.55 <= double2" ] . count ) ;
XCTAssertEqual ( 1 U , [ self . queryObjectClass objectsWhere : @ "'a' == string2" ] . count ) ;
XCTAssertEqual ( 6 U , [ self . queryObjectClass objectsWhere : @ "'a' != string2" ] . count ) ;
RLMAssertThrowsWithReasonMatching ( [ self . queryObjectClass objectsWhere : @ "'Realm' CONTAINS string1" ] . count ,
@ "Operator 'CONTAINS' is not supported .* right side" ) ;
RLMAssertThrowsWithReasonMatching ( [ self . queryObjectClass objectsWhere : @ "'Amazon' BEGINSWITH string2" ] . count ,
@ "Operator 'BEGINSWITH' is not supported .* right side" ) ;
RLMAssertThrowsWithReasonMatching ( [ self . queryObjectClass objectsWhere : @ "'Tuba' ENDSWITH string1" ] . count ,
@ "Operator 'ENDSWITH' is not supported .* right side" ) ;
}
@ end
@ interface NullQueryTests : QueryTests
@ end
@ implementation NullQueryTests
- ( Class ) queryObjectClass {
return [ NullQueryObject class ] ;
}
- ( void ) testQueryOnNullableStringColumn {
void ( ^ testWithStringClass ) ( Class ) = ^ ( Class stringObjectClass ) {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm transactionWithBlock : ^ {
[ stringObjectClass createInRealm : realm withValue : @ [ @ "a" ] ] ;
[ stringObjectClass createInRealm : realm withValue : @ [ NSNull . null ] ] ;
[ stringObjectClass createInRealm : realm withValue : @ [ @ "b" ] ] ;
[ stringObjectClass createInRealm : realm withValue : @ [ NSNull . null ] ] ;
[ stringObjectClass createInRealm : realm withValue : @ [ @ "" ] ] ;
} ] ;
RLMResults * allObjects = [ stringObjectClass allObjectsInRealm : realm ] ;
XCTAssertEqual ( 5 U , allObjects . count ) ;
RLMResults * nilStrings = [ stringObjectClass objectsInRealm : realm where : @ "stringCol = NULL" ] ;
XCTAssertEqual ( 2 U , nilStrings . count ) ;
XCTAssertEqualObjects ( ( @ [ NSNull . null , NSNull . null ] ) , [ nilStrings valueForKey : @ "stringCol" ] ) ;
RLMResults * nonNilStrings = [ stringObjectClass objectsInRealm : realm where : @ "stringCol != NULL" ] ;
XCTAssertEqual ( 3 U , nonNilStrings . count ) ;
XCTAssertEqualObjects ( ( @ [ @ "a" , @ "b" , @ "" ] ) , [ nonNilStrings valueForKey : @ "stringCol" ] ) ;
XCTAssertEqual ( 3 U , [ stringObjectClass objectsInRealm : realm where : @ "stringCol IN {NULL, 'a'}" ] . count ) ;
XCTAssertEqual ( 1 U , [ stringObjectClass objectsInRealm : realm where : @ "stringCol CONTAINS 'a'" ] . count ) ;
XCTAssertEqual ( 1 U , [ stringObjectClass objectsInRealm : realm where : @ "stringCol BEGINSWITH 'a'" ] . count ) ;
XCTAssertEqual ( 1 U , [ stringObjectClass objectsInRealm : realm where : @ "stringCol ENDSWITH 'a'" ] . count ) ;
XCTAssertEqual ( 0 U , [ stringObjectClass objectsInRealm : realm where : @ "stringCol CONTAINS 'z'" ] . count ) ;
XCTAssertEqual ( 1 U , [ stringObjectClass objectsInRealm : realm where : @ "stringCol = ''" ] . count ) ;
RLMResults * sorted = [ [ stringObjectClass allObjectsInRealm : realm ] sortedResultsUsingProperty : @ "stringCol" ascending : YES ] ;
XCTAssertEqualObjects ( ( @ [ NSNull . null , NSNull . null , @ "" , @ "a" , @ "b" ] ) , [ sorted valueForKey : @ "stringCol" ] ) ;
XCTAssertEqualObjects ( ( @ [ @ "b" , @ "a" , @ "" , NSNull . null , NSNull . null ] ) , [ [ sorted sortedResultsUsingProperty : @ "stringCol" ascending : NO ] valueForKey : @ "stringCol" ] ) ;
[ realm transactionWithBlock : ^ {
[ realm deleteObject : [ stringObjectClass allObjectsInRealm : realm ] . firstObject ] ;
} ] ;
XCTAssertEqual ( 2 U , nilStrings . count ) ;
XCTAssertEqual ( 2 U , nonNilStrings . count ) ;
XCTAssertEqualObjects ( [ nonNilStrings valueForKey : @ "stringCol" ] , [ [ stringObjectClass objectsInRealm : realm where : @ "stringCol CONTAINS ''" ] valueForKey : @ "stringCol" ] ) ;
XCTAssertEqualObjects ( [ nonNilStrings valueForKey : @ "stringCol" ] , [ [ stringObjectClass objectsInRealm : realm where : @ "stringCol BEGINSWITH ''" ] valueForKey : @ "stringCol" ] ) ;
XCTAssertEqualObjects ( [ nonNilStrings valueForKey : @ "stringCol" ] , [ [ stringObjectClass objectsInRealm : realm where : @ "stringCol ENDSWITH ''" ] valueForKey : @ "stringCol" ] ) ;
XCTAssertEqualObjects ( [ nonNilStrings valueForKey : @ "stringCol" ] , [ [ stringObjectClass objectsInRealm : realm where : @ "stringCol CONTAINS[c] ''" ] valueForKey : @ "stringCol" ] ) ;
XCTAssertEqualObjects ( [ nonNilStrings valueForKey : @ "stringCol" ] , [ [ stringObjectClass objectsInRealm : realm where : @ "stringCol BEGINSWITH[c] ''" ] valueForKey : @ "stringCol" ] ) ;
XCTAssertEqualObjects ( [ nonNilStrings valueForKey : @ "stringCol" ] , [ [ stringObjectClass objectsInRealm : realm where : @ "stringCol ENDSWITH[c] ''" ] valueForKey : @ "stringCol" ] ) ;
XCTAssertEqualObjects ( @ [ ] , ( [ [ stringObjectClass objectsInRealm : realm where : @ "stringCol CONTAINS %@" , @ "\0" ] valueForKey : @ "self" ] ) ) ;
XCTAssertEqualObjects ( [ [ stringObjectClass allObjectsInRealm : realm ] valueForKey : @ "stringCol" ] , ( [ [ StringObject objectsInRealm : realm where : @ "stringCol CONTAINS NULL" ] valueForKey : @ "stringCol" ] ) ) ;
} ;
testWithStringClass ( [ StringObject class ] ) ;
testWithStringClass ( [ IndexedStringObject class ] ) ;
}
- ( void ) testQueryingOnLinkToNullableStringColumn {
void ( ^ testWithStringClass ) ( Class , Class ) = ^ ( Class stringLinkClass , Class stringObjectClass ) {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm transactionWithBlock : ^ {
[ stringLinkClass createInRealm : realm withValue : @ [ [ stringObjectClass createInRealm : realm withValue : @ [ @ "a" ] ] ] ] ;
[ stringLinkClass createInRealm : realm withValue : @ [ [ stringObjectClass createInRealm : realm withValue : @ [ NSNull . null ] ] ] ] ;
[ stringLinkClass createInRealm : realm withValue : @ [ [ stringObjectClass createInRealm : realm withValue : @ [ @ "b" ] ] ] ] ;
[ stringLinkClass createInRealm : realm withValue : @ [ [ stringObjectClass createInRealm : realm withValue : @ [ NSNull . null ] ] ] ] ;
[ stringLinkClass createInRealm : realm withValue : @ [ [ stringObjectClass createInRealm : realm withValue : @ [ @ "" ] ] ] ] ;
} ] ;
RLMResults * nilStrings = [ stringLinkClass objectsInRealm : realm where : @ "objectCol.stringCol = NULL" ] ;
XCTAssertEqual ( 2 U , nilStrings . count ) ;
XCTAssertEqualObjects ( ( @ [ NSNull . null , NSNull . null ] ) , [ nilStrings valueForKeyPath : @ "objectCol.stringCol" ] ) ;
RLMResults * nonNilStrings = [ stringLinkClass objectsInRealm : realm where : @ "objectCol.stringCol != NULL" ] ;
XCTAssertEqual ( 3 U , nonNilStrings . count ) ;
XCTAssertEqualObjects ( ( @ [ @ "a" , @ "b" , @ "" ] ) , [ nonNilStrings valueForKeyPath : @ "objectCol.stringCol" ] ) ;
XCTAssertEqual ( 3 U , [ stringLinkClass objectsInRealm : realm where : @ "objectCol.stringCol IN {NULL, 'a'}" ] . count ) ;
XCTAssertEqual ( 1 U , [ stringLinkClass objectsInRealm : realm where : @ "objectCol.stringCol CONTAINS 'a'" ] . count ) ;
XCTAssertEqual ( 1 U , [ stringLinkClass objectsInRealm : realm where : @ "objectCol.stringCol BEGINSWITH 'a'" ] . count ) ;
XCTAssertEqual ( 1 U , [ stringLinkClass objectsInRealm : realm where : @ "objectCol.stringCol ENDSWITH 'a'" ] . count ) ;
XCTAssertEqual ( 0 U , [ stringLinkClass objectsInRealm : realm where : @ "objectCol.stringCol CONTAINS 'z'" ] . count ) ;
XCTAssertEqual ( 1 U , [ stringLinkClass objectsInRealm : realm where : @ "objectCol.stringCol = ''" ] . count ) ;
} ;
testWithStringClass ( [ LinkStringObject class ] , [ StringObject class ] ) ;
testWithStringClass ( [ LinkIndexedStringObject class ] , [ IndexedStringObject class ] ) ;
}
- ( void ) testSortingColumnsWithNull {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
{
NumberObject * no1 = [ NumberObject createInRealm : realm withValue : @ [ @ 1 , @ 1.1 f , @ 1.1 , @ YES ] ] ;
NumberObject * noNull = [ NumberObject createInRealm : realm withValue : @ [ NSNull . null , NSNull . null , NSNull . null , NSNull . null ] ] ;
NumberObject * no0 = [ NumberObject createInRealm : realm withValue : @ [ @ 0 , @ 0.0 f , @ 0.0 , @ NO ] ] ;
for ( RLMProperty * property in [ [ NumberObject alloc ] init ] . objectSchema . properties ) {
NSString * name = property . name ;
RLMResults * ascending = [ [ NumberObject allObjectsInRealm : realm ] sortedResultsUsingProperty : name ascending : YES ] ;
XCTAssertEqualObjects ( [ ascending valueForKey : name ] , ( [ @ [ noNull , no0 , no1 ] valueForKey : name ] ) ) ;
RLMResults * descending = [ [ NumberObject allObjectsInRealm : realm ] sortedResultsUsingProperty : name ascending : NO ] ;
XCTAssertEqualObjects ( [ descending valueForKey : name ] , ( [ @ [ no1 , no0 , noNull ] valueForKey : name ] ) ) ;
}
}
{
DateObject * doPositive = [ DateObject createInRealm : realm withValue : @ [ [ NSDate dateWithTimeIntervalSince1970 : 100 ] ] ] ;
DateObject * doNegative = [ DateObject createInRealm : realm withValue : @ [ [ NSDate dateWithTimeIntervalSince1970 : - 100 ] ] ] ;
DateObject * doZero = [ DateObject createInRealm : realm withValue : @ [ [ NSDate dateWithTimeIntervalSince1970 : 0 ] ] ] ;
DateObject * doNull = [ DateObject createInRealm : realm withValue : @ [ NSNull . null ] ] ;
RLMResults * ascending = [ [ DateObject allObjectsInRealm : realm ] sortedResultsUsingProperty : @ "dateCol" ascending : YES ] ;
XCTAssertEqualObjects ( [ ascending valueForKey : @ "dateCol" ] , ( [ @ [ doNull , doNegative , doZero , doPositive ] valueForKey : @ "dateCol" ] ) ) ;
RLMResults * descending = [ [ DateObject allObjectsInRealm : realm ] sortedResultsUsingProperty : @ "dateCol" ascending : NO ] ;
XCTAssertEqualObjects ( [ descending valueForKey : @ "dateCol" ] , ( [ @ [ doPositive , doZero , doNegative , doNull ] valueForKey : @ "dateCol" ] ) ) ;
}
{
StringObject * soA = [ StringObject createInRealm : realm withValue : @ [ @ "A" ] ] ;
StringObject * soEmpty = [ StringObject createInRealm : realm withValue : @ [ @ "" ] ] ;
StringObject * soB = [ StringObject createInRealm : realm withValue : @ [ @ "B" ] ] ;
StringObject * soNull = [ StringObject createInRealm : realm withValue : @ [ NSNull . null ] ] ;
StringObject * soAB = [ StringObject createInRealm : realm withValue : @ [ @ "AB" ] ] ;
RLMResults * ascending = [ [ StringObject allObjectsInRealm : realm ] sortedResultsUsingProperty : @ "stringCol" ascending : YES ] ;
XCTAssertEqualObjects ( [ ascending valueForKey : @ "stringCol" ] , ( [ @ [ soNull , soEmpty , soA , soAB , soB ] valueForKey : @ "stringCol" ] ) ) ;
RLMResults * descending = [ [ StringObject allObjectsInRealm : realm ] sortedResultsUsingProperty : @ "stringCol" ascending : NO ] ;
XCTAssertEqualObjects ( [ descending valueForKey : @ "stringCol" ] , ( [ @ [ soB , soAB , soA , soEmpty , soNull ] valueForKey : @ "stringCol" ] ) ) ;
}
[ realm cancelWriteTransaction ] ;
}
- ( void ) testCountOnCollection {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
IntegerArrayPropertyObject * arr = [ IntegerArrayPropertyObject createInRealm : realm withValue : @ [ @ 1234 , @ [ ] ] ] ;
[ arr . array addObject : [ IntObject createInRealm : realm withValue : @ [ @ 456 ] ] ] ;
arr = [ IntegerArrayPropertyObject createInRealm : realm withValue : @ [ @ 4567 , @ [ ] ] ] ;
[ arr . array addObject : [ IntObject createInRealm : realm withValue : @ [ @ 1 ] ] ] ;
[ arr . array addObject : [ IntObject createInRealm : realm withValue : @ [ @ 2 ] ] ] ;
[ arr . array addObject : [ IntObject createInRealm : realm withValue : @ [ @ 3 ] ] ] ;
arr = [ IntegerArrayPropertyObject createInRealm : realm withValue : @ [ @ 4567 , @ [ ] ] ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( 2 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@count > 0" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@count == 3" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@count < 1" ] . count ) ) ;
XCTAssertEqual ( 2 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "0 < array.@count" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "3 == array.@count" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "1 > array.@count" ] . count ) ) ;
// We do not yet handle collection operations with a keypath on the other side of the comparison.
RLMAssertThrowsWithReasonMatching ( ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@count != number" ] ) , @ "'array.@count' not found in object" ) ;
RLMAssertThrowsWithReasonMatching ( ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@count.foo.bar != 0" ] ) , @ "single level key" ) ;
RLMAssertThrowsWithReasonMatching ( ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@count.intCol > 0" ] ) , @ "@count does not have any properties" ) ;
RLMAssertThrowsWithReasonMatching ( ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@count != 'Hello'" ] ) , @ "@count can only be compared with a numeric value" ) ;
}
- ( void ) testAggregateCollectionOperators {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
IntegerArrayPropertyObject * arr = [ IntegerArrayPropertyObject createInRealm : realm withValue : @ [ @ 1111 , @ [ ] ] ] ;
[ arr . array addObject : [ IntObject createInRealm : realm withValue : @ [ @ 1234 ] ] ] ;
[ arr . array addObject : [ IntObject createInRealm : realm withValue : @ [ @ 2 ] ] ] ;
[ arr . array addObject : [ IntObject createInRealm : realm withValue : @ [ @ - 12345 ] ] ] ;
arr = [ IntegerArrayPropertyObject createInRealm : realm withValue : @ [ @ 2222 , @ [ ] ] ] ;
[ arr . array addObject : [ IntObject createInRealm : realm withValue : @ [ @ 100 ] ] ] ;
arr = [ IntegerArrayPropertyObject createInRealm : realm withValue : @ [ @ 3333 , @ [ ] ] ] ;
[ realm commitWriteTransaction ] ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@min.intCol == -12345" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@min.intCol == 100" ] . count ) ) ;
XCTAssertEqual ( 2 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@min.intCol < 1000" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@min.intCol > -1000" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@max.intCol == 1234" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@max.intCol == 100" ] . count ) ) ;
XCTAssertEqual ( 2 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@max.intCol > -1000" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@max.intCol > 1000" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@sum.intCol == 100" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@sum.intCol == -11109" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@sum.intCol == 0" ] . count ) ) ;
XCTAssertEqual ( 2 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@sum.intCol > -50" ] . count ) ) ;
XCTAssertEqual ( 2 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@sum.intCol < 50" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@avg.intCol == 100" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@avg.intCol == -3703.0" ] . count ) ) ;
XCTAssertEqual ( 0 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@avg.intCol == 0" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@avg.intCol < -50" ] . count ) ) ;
XCTAssertEqual ( 1 U , ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@avg.intCol > 50" ] . count ) ) ;
// We do not yet handle collection operations with a keypath on the other side of the comparison.
RLMAssertThrowsWithReasonMatching ( ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@min.intCol == number" ] ) , @ "'array.@min.intCol' not found in object" ) ;
RLMAssertThrowsWithReasonMatching ( ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@min.intCol.foo.bar == 1.23" ] ) , @ "single level key" ) ;
RLMAssertThrowsWithReasonMatching ( ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@max.intCol.foo.bar == 1.23" ] ) , @ "single level key" ) ;
RLMAssertThrowsWithReasonMatching ( ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@sum.intCol.foo.bar == 1.23" ] ) , @ "single level key" ) ;
RLMAssertThrowsWithReasonMatching ( ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@avg.intCol.foo.bar == 1.23" ] ) , @ "single level key" ) ;
// Average is omitted from this test as its result is always a double.
RLMAssertThrowsWithReasonMatching ( ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@min.intCol == 1.23" ] ) , @ "@min.*type int cannot be compared" ) ;
RLMAssertThrowsWithReasonMatching ( ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@max.intCol == 1.23" ] ) , @ "@max.*type int cannot be compared" ) ;
RLMAssertThrowsWithReasonMatching ( ( [ IntegerArrayPropertyObject objectsWhere : @ "array.@sum.intCol == 1.23" ] ) , @ "@sum.*type int cannot be compared" ) ;
}
struct NullTestData {
_ _unsafe _unretained NSString * propertyName ;
_ _unsafe _unretained NSString * nonMatchingStr ;
_ _unsafe _unretained NSString * matchingStr ;
_ _unsafe _unretained id nonMatchingValue ;
_ _unsafe _unretained id matchingValue ;
bool orderable ;
bool substringOperations ;
} ;
- ( void ) testPrimitiveOperatorsOnAllNullablePropertyTypes {
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
// nil on LHS is currently not supported by core
XCTAssertThrows ( [ AllOptionalTypes objectsWhere : @ "nil = boolObj" ] ) ;
// These need to be stored in variables because the struct does not retain them
NSData * matchingData = [ @ "" dataUsingEncoding : NSUTF8StringEncoding ] ;
NSData * notMatchingData = [ @ "a" dataUsingEncoding : NSUTF8StringEncoding ] ;
NSDate * matchingDate = [ NSDate dateWithTimeIntervalSince1970 : 1 ] ;
NSDate * notMatchingDate = [ NSDate dateWithTimeIntervalSince1970 : 2 ] ;
struct NullTestData data [ ] = {
{ @ "boolObj" , @ "YES" , @ "NO" , @ YES , @ NO } ,
{ @ "intObj" , @ "1" , @ "0" , @ 1 , @ 0 , true } ,
{ @ "floatObj" , @ "1" , @ "0" , @ 1 , @ 0 , true } ,
{ @ "doubleObj" , @ "1" , @ "0" , @ 1 , @ 0 , true } ,
{ @ "string" , @ "'a'" , @ "''" , @ "a" , @ "" , false , true } ,
{ @ "data" , nil , nil , notMatchingData , matchingData } ,
{ @ "date" , nil , nil , notMatchingDate , matchingDate , true } ,
} ;
// Assert that the query "prop op value" gives expectedCount results when
// assembled via string formatting
# define RLMAssertCountWithString ( expectedCount , op , prop , value ) \
do { \
NSString * queryStr = [ NSString stringWithFormat : @ "%@ " # op " %@" , prop , value ] ; \
NSUInteger actual = [ AllOptionalTypes objectsWhere : queryStr ] . count ; \
XCTAssertEqual ( expectedCount , actual , @ "%@: expected %@, got %@" , queryStr , @ ( expectedCount ) , @ ( actual ) ) ; \
} while ( 0 )
// Assert that the query "prop op value" gives expectedCount results when
// assembled via predicateWithFormat
# define RLMAssertCountWithPredicate ( expectedCount , op , prop , value ) \
do { \
NSPredicate * query = [ NSPredicate predicateWithFormat : @ "%K " # op " %@" , prop , value ] ; \
NSUInteger actual = [ AllOptionalTypes objectsWithPredicate : query ] . count ; \
XCTAssertEqual ( expectedCount , actual , @ "%@ " # op " %@: expected %@, got %@" , prop , value , @ ( expectedCount ) , @ ( actual ) ) ; \
} while ( 0 )
// Assert that the given operator gives the expected count for each of the
// stored value, a different value, and nil
# define RLMAssertOperator ( op , matchingCount , notMatchingCount , nilCount ) \
do { \
if ( d . matchingStr ) { \
RLMAssertCountWithString ( matchingCount , op , d . propertyName , d . matchingStr ) ; \
RLMAssertCountWithString ( notMatchingCount , op , d . propertyName , d . nonMatchingStr ) ; \
} \
RLMAssertCountWithString ( nilCount , op , d . propertyName , nil ) ; \
\
RLMAssertCountWithPredicate ( matchingCount , op , d . propertyName , d . matchingValue ) ; \
RLMAssertCountWithPredicate ( notMatchingCount , op , d . propertyName , d . nonMatchingValue ) ; \
RLMAssertCountWithPredicate ( nilCount , op , d . propertyName , nil ) ; \
} while ( 0 )
// First test with the `matchingValue` stored in each property
[ realm beginWriteTransaction ] ;
[ AllOptionalTypes createInRealm : realm withValue : @ [ @ NO , @ 0 , @ 0 , @ 0 , @ "" , matchingData , matchingDate ] ] ;
[ realm commitWriteTransaction ] ;
for ( size _t i = 0 ; i < sizeof ( data ) / sizeof ( data [ 0 ] ) ; ++ i ) {
struct NullTestData d = data [ i ] ;
RLMAssertOperator ( = , 1 U , 0 U , 0 U ) ;
RLMAssertOperator ( != , 0 U , 1 U , 1 U ) ;
if ( d . orderable ) {
RLMAssertOperator ( < , 0 U , 1 U , 0 U ) ;
RLMAssertOperator ( <= , 1 U , 1 U , 0 U ) ;
RLMAssertOperator ( > , 0 U , 0 U , 0 U ) ;
RLMAssertOperator ( >= , 1 U , 0 U , 0 U ) ;
}
if ( d . substringOperations ) {
RLMAssertOperator ( BEGINSWITH , 1 U , 0 U , 1 U ) ;
RLMAssertOperator ( ENDSWITH , 1 U , 0 U , 1 U ) ;
RLMAssertOperator ( CONTAINS , 1 U , 0 U , 1 U ) ;
}
}
// Retest with all properties nil
[ realm beginWriteTransaction ] ;
[ realm deleteAllObjects ] ;
[ AllOptionalTypes createInRealm : realm withValue : @ [ NSNull . null , NSNull . null ,
NSNull . null , NSNull . null ,
NSNull . null , NSNull . null ,
NSNull . null ] ] ;
[ realm commitWriteTransaction ] ;
for ( size _t i = 0 ; i < sizeof ( data ) / sizeof ( data [ 0 ] ) ; ++ i ) {
struct NullTestData d = data [ i ] ;
RLMAssertOperator ( = , 0 U , 0 U , 1 U ) ;
RLMAssertOperator ( != , 1 U , 1 U , 0 U ) ;
if ( d . orderable ) {
RLMAssertOperator ( < , 0 U , 0 U , 0 U ) ;
RLMAssertOperator ( <= , 0 U , 0 U , 1 U ) ;
RLMAssertOperator ( > , 0 U , 0 U , 0 U ) ;
RLMAssertOperator ( >= , 0 U , 0 U , 1 U ) ;
}
if ( d . substringOperations ) {
RLMAssertOperator ( BEGINSWITH , 0 U , 0 U , 1 U ) ;
RLMAssertOperator ( ENDSWITH , 0 U , 0 U , 1 U ) ;
RLMAssertOperator ( CONTAINS , 0 U , 0 U , 1 U ) ;
}
}
}
- ( void ) testINPredicateOnNullWithNonNullValues
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ AllOptionalTypes createInRealm : realm withValue : @ [ @ YES , @ 1 , @ 1 , @ 1 , @ "abc" ,
[ @ "a" dataUsingEncoding : NSUTF8StringEncoding ] ,
[ NSDate dateWithTimeIntervalSince1970 : 1 ] ] ] ;
[ realm commitWriteTransaction ] ;
////////////////////////
// Literal Predicates
////////////////////////
// BOOL
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 notCount : 1 where : @ "boolObj IN {NULL}" ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 notCount : 0 where : @ "boolObj IN {YES}" ] ;
// int
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 notCount : 1 where : @ "intObj IN {NULL}" ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 notCount : 0 where : @ "intObj IN {1}" ] ;
// float
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 notCount : 1 where : @ "floatObj IN {NULL}" ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 notCount : 0 where : @ "floatObj IN {1}" ] ;
// double
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 notCount : 1 where : @ "doubleObj IN {NULL}" ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 notCount : 0 where : @ "doubleObj IN {1}" ] ;
// NSString
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 notCount : 1 where : @ "string IN {NULL}" ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 notCount : 0 where : @ "string IN {'abc'}" ] ;
// NSData
// Can't represent NSData with NSPredicate literal. See format predicates below
// NSDate
// Can't represent NSDate with NSPredicate literal. See format predicates below
////////////////////////
// Format Predicates
////////////////////////
// BOOL
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "boolObj IN %@" , @ [ NSNull . null ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "boolObj IN %@" , @ [ @ YES ] ] ;
// int
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "intObj IN %@" , @ [ NSNull . null ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "intObj IN %@" , @ [ @ 1 ] ] ;
// float
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "floatObj IN %@" , @ [ NSNull . null ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "floatObj IN %@" , @ [ @ 1 ] ] ;
// double
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "doubleObj IN %@" , @ [ NSNull . null ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "doubleObj IN %@" , @ [ @ 1 ] ] ;
// NSString
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "string IN %@" , @ [ @ "abc" ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "string IN %@" , @ [ NSNull . null ] ] ;
// NSData
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "data IN %@" , @ [ NSNull . null ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "data IN %@" , @ [ [ @ "a" dataUsingEncoding : NSUTF8StringEncoding ] ] ] ;
// NSDate
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "date IN %@" , @ [ NSNull . null ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "date IN %@" , @ [ [ NSDate dateWithTimeIntervalSince1970 : 1 ] ] ] ;
}
- ( void ) testINPredicateOnNullWithNullValues
{
RLMRealm * realm = [ RLMRealm defaultRealm ] ;
[ realm beginWriteTransaction ] ;
[ AllOptionalTypes createInRealm : realm withValue : @ [ NSNull . null , NSNull . null ,
NSNull . null , NSNull . null ,
NSNull . null , NSNull . null ,
NSNull . null ] ] ;
[ realm commitWriteTransaction ] ;
////////////////////////
// Literal Predicates
////////////////////////
// BOOL
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 notCount : 0 where : @ "boolObj IN {NULL}" ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 notCount : 1 where : @ "boolObj IN {YES}" ] ;
// int
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 notCount : 0 where : @ "intObj IN {NULL}" ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 notCount : 1 where : @ "intObj IN {1}" ] ;
// float
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 notCount : 0 where : @ "floatObj IN {NULL}" ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 notCount : 1 where : @ "floatObj IN {1}" ] ;
// double
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 notCount : 0 where : @ "doubleObj IN {NULL}" ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 notCount : 1 where : @ "doubleObj IN {1}" ] ;
// NSString
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 notCount : 0 where : @ "string IN {NULL}" ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 notCount : 1 where : @ "string IN {'abc'}" ] ;
// NSData
// Can't represent NSData with NSPredicate literal. See format predicates below
// NSDate
// Can't represent NSDate with NSPredicate literal. See format predicates below
////////////////////////
// Format Predicates
////////////////////////
// BOOL
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "boolObj IN %@" , @ [ NSNull . null ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "boolObj IN %@" , @ [ @ YES ] ] ;
// int
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "intObj IN %@" , @ [ NSNull . null ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "intObj IN %@" , @ [ @ 1 ] ] ;
// float
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "floatObj IN %@" , @ [ NSNull . null ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "floatObj IN %@" , @ [ @ 1 ] ] ;
// double
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "doubleObj IN %@" , @ [ NSNull . null ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "doubleObj IN %@" , @ [ @ 1 ] ] ;
// NSString
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "string IN %@" , @ [ @ "abc" ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "string IN %@" , @ [ NSNull . null ] ] ;
// NSData
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "data IN %@" , @ [ NSNull . null ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "data IN %@" , @ [ [ @ "a" dataUsingEncoding : NSUTF8StringEncoding ] ] ] ;
// NSDate
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 1 U notCount : 0 U where : @ "date IN %@" , @ [ NSNull . null ] ] ;
[ self testClass : [ AllOptionalTypes class ] withNormalCount : 0 U notCount : 1 U where : @ "date IN %@" , @ [ [ NSDate dateWithTimeIntervalSince1970 : 1 ] ] ] ;
}
* /