Skip to content

Commit

Permalink
Obj-C tests 2
Browse files Browse the repository at this point in the history
  • Loading branch information
velicuvlad committed Oct 2, 2024
1 parent 612603e commit 8bef365
Show file tree
Hide file tree
Showing 9 changed files with 323 additions and 155 deletions.
10 changes: 10 additions & 0 deletions CouchbaseLite.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1784,6 +1784,10 @@
AEC806BC2C89EA68001C9723 /* CBLArrayIndexConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = AEC806B62C89EA68001C9723 /* CBLArrayIndexConfiguration.m */; };
AEC806BD2C89EA68001C9723 /* CBLArrayIndexConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = AEC806B62C89EA68001C9723 /* CBLArrayIndexConfiguration.m */; };
AEC806BE2C89EA68001C9723 /* CBLArrayIndexConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = AEC806B52C89EA68001C9723 /* CBLArrayIndexConfiguration.h */; settings = {ATTRIBUTES = (Private, ); }; };
AECA89782CAC765A00C7B6BE /* CBLIndexable+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = AECA89652CAC714800C7B6BE /* CBLIndexable+Internal.h */; };
AECA89792CAC765B00C7B6BE /* CBLIndexable+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = AECA89652CAC714800C7B6BE /* CBLIndexable+Internal.h */; };
AECA897A2CAC765C00C7B6BE /* CBLIndexable+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = AECA89652CAC714800C7B6BE /* CBLIndexable+Internal.h */; };
AECA897B2CAC765D00C7B6BE /* CBLIndexable+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = AECA89652CAC714800C7B6BE /* CBLIndexable+Internal.h */; };
AECD5A162C0E21D900B1247E /* CBLIndexUpdater+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = AECD5A0F2C0E21D900B1247E /* CBLIndexUpdater+Internal.h */; };
AECD5A172C0E21D900B1247E /* CBLIndexUpdater+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = AECD5A0F2C0E21D900B1247E /* CBLIndexUpdater+Internal.h */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -2807,6 +2811,7 @@
AE83D0832C0637ED0055D2CF /* CBLIndexUpdater.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CBLIndexUpdater.mm; sourceTree = "<group>"; };
AEC806B52C89EA68001C9723 /* CBLArrayIndexConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CBLArrayIndexConfiguration.h; sourceTree = "<group>"; };
AEC806B62C89EA68001C9723 /* CBLArrayIndexConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CBLArrayIndexConfiguration.m; sourceTree = "<group>"; };
AECA89652CAC714800C7B6BE /* CBLIndexable+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CBLIndexable+Internal.h"; sourceTree = "<group>"; };
AECD59F92C0E137200B1247E /* CBLQueryIndex+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CBLQueryIndex+Internal.h"; sourceTree = "<group>"; };
AECD5A0F2C0E21D900B1247E /* CBLIndexUpdater+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CBLIndexUpdater+Internal.h"; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -3601,6 +3606,7 @@
27CDE75E207407280082D458 /* CBLDocumentChangeNotifier.h */,
27CDE75F207407280082D458 /* CBLDocumentChangeNotifier.mm */,
1A1612A8283DE8A200AA4987 /* CBLScope+Internal.h */,
AECA89652CAC714800C7B6BE /* CBLIndexable+Internal.h */,
);
name = Database;
sourceTree = "<group>";
Expand Down Expand Up @@ -4376,6 +4382,7 @@
93EB264521DF1AE40006FB88 /* CBLDocumentFlags.h in Headers */,
9383A5961F1EEFCD0083053D /* CBLQueryResult+Internal.h in Headers */,
934A27931F30E5CA003946A7 /* CBLBinaryExpression.h in Headers */,
AECA89792CAC765B00C7B6BE /* CBLIndexable+Internal.h in Headers */,
27D7219A1F8E97F400AA4458 /* CBLFleece.hh in Headers */,
9374A8A7201FC53600BA0D9E /* CBLReplicator+Backgrounding.h in Headers */,
932565A521ED13290092F4E0 /* CBLLogFileConfiguration.h in Headers */,
Expand Down Expand Up @@ -4686,6 +4693,7 @@
40FC1BD72B928A4F00394276 /* CBLCoreMLPredictiveModel.h in Headers */,
40FC1B502B92873000394276 /* CBLEncryptionKey.h in Headers */,
9343EFE4207D611600F19A89 /* CBLDatabase+Internal.h in Headers */,
AECA897A2CAC765C00C7B6BE /* CBLIndexable+Internal.h in Headers */,
40FC1BE02B928A4F00394276 /* CBLPredictiveIndex.h in Headers */,
9343EFE5207D611600F19A89 /* CBLDictionaryFragment.h in Headers */,
40FC1C1E2B928B5000394276 /* CBLVectorEncoding+Internal.h in Headers */,
Expand Down Expand Up @@ -4890,6 +4898,7 @@
9343F0FB207D61AB00F19A89 /* CBLQueryResultSet.h in Headers */,
9343F0FC207D61AB00F19A89 /* CBLDocumentFragment.h in Headers */,
9343F0FD207D61AB00F19A89 /* CBLQueryBuilder.h in Headers */,
AECA897B2CAC765D00C7B6BE /* CBLIndexable+Internal.h in Headers */,
40FC1BEE2B928A4F00394276 /* CBLQueryFunction+Vector.h in Headers */,
9343F0FF207D61AB00F19A89 /* CBLMutableArrayFragment.h in Headers */,
1AA2EE0328A682A800DEB47E /* CBLCollectionConfiguration+Swift.h in Headers */,
Expand Down Expand Up @@ -4978,6 +4987,7 @@
1AAFB66F284A260A00878453 /* CBLCollectionChangeObservable.h in Headers */,
9384D8401FC405D200FE89D8 /* CBLQueryFullTextFunction.h in Headers */,
1A3470E9266F69220042C6BA /* CBLIndexConfiguration+Internal.h in Headers */,
AECA89782CAC765A00C7B6BE /* CBLIndexable+Internal.h in Headers */,
933208141E77415E000D9993 /* CBLQueryExpression.h in Headers */,
935A58B621AFA34D009A29CB /* CBLDocumentReplication.h in Headers */,
1AEF0585283380D500D5DDEA /* CBLScope.h in Headers */,
Expand Down
2 changes: 1 addition & 1 deletion Objective-C/CBLArrayIndexConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ - (instancetype) initWithPath: (NSString*) path
expressions: @[@""]];
} else if ([expressions count] == 0) {
[NSException raise: NSInvalidArgumentException format:
@"Expressions cannot be empty "];
@"Empty expressions is not allowed, use nil instead"];
}

self = [super initWithIndexType: kC4ArrayIndex
Expand Down
312 changes: 167 additions & 145 deletions Objective-C/CBLCollection.mm
Original file line number Diff line number Diff line change
Expand Up @@ -473,151 +473,6 @@ - (BOOL) setDocumentExpirationWithID: (NSString*)documentID
}
}

#pragma mark - Internal

- (BOOL) checkIsValid: (NSError**)error {
BOOL valid = c4coll_isValid(_c4col);
if (!valid) {
if (error)
*error = CBLCollectionErrorNotOpen;
}

return valid;
}

- (BOOL) isValid {
return [self checkIsValid: nil];
}

- (BOOL) database: (CBLDatabase*)db isValid: (NSError**)error {
BOOL valid = db != nil;
if (!valid) {
if (error)
*error = CBLDatabaseErrorNotOpen;
}

return valid;
}

- (C4CollectionSpec) c4spec {
// Convert to cString directly instead of using CBLStringBytes to avoid
// stack-use-after-scope problem when a small string is kept in the
// _local stack based buffer of the CBLStringBytes
C4Slice name = c4str([_name cStringUsingEncoding: NSUTF8StringEncoding]);
C4Slice scopeName = c4str([_scope.name cStringUsingEncoding: NSUTF8StringEncoding]);
return { .name = name, .scope = scopeName };
}

- (BOOL) isEqual: (id)object {
if (self == object)
return YES;

CBLCollection* other = $castIf(CBLCollection, object);
if (!other)
return NO;

if (!(other && [self.name isEqual: other.name] &&
[self.scope.name isEqual: other.scope.name] &&
[self.database.path isEqual: other.database.path])) {
return NO;
}

if (!self.isValid || !other.isValid)
return NO;

return YES;
}

- (id<CBLListenerToken>) addCollectionChangeListener: (void (^)(CBLCollectionChange*))listener
queue: (dispatch_queue_t)queue {
if (!_colChangeNotifier) {
_colChangeNotifier = [CBLChangeNotifier new];
C4Error c4err = {};
_colObs = c4dbobs_createOnCollection(_c4col, colObserverCallback, (__bridge void *)self, &c4err);
if (!_colObs) {
CBLWarn(Database, @"%@ Failed to create collection obs c4col=%p err=%d/%d",
self, _c4col, c4err.domain, c4err.code);
}
}

return [_colChangeNotifier addChangeListenerWithQueue: queue listener: listener delegate: self];
}

static void colObserverCallback(C4CollectionObserver* obs, void* context) {
CBLCollection *c = (__bridge CBLCollection *)context;
dispatch_async(c.dispatchQueue, ^{
[c postCollectionChanged];
});
}

- (void) postCollectionChanged {
CBL_LOCK(_mutex) {
if (!_colObs || !_c4col)
return;

const uint32_t kMaxChanges = 100u;
C4DatabaseChange changes[kMaxChanges];
bool external = false;
C4CollectionObservation obs = {};
NSMutableArray* docIDs = [NSMutableArray new];
do {
// Read changes in batches of kMaxChanges:
obs = c4dbobs_getChanges(_colObs, changes, kMaxChanges);
if (obs.numChanges == 0 || external != obs.external || docIDs.count > 1000) {
if(docIDs.count > 0) {
CBLCollectionChange* change = [[CBLCollectionChange alloc] initWithCollection: self
documentIDs: docIDs
isExternal: external];
[_colChangeNotifier postChange: change];
docIDs = [NSMutableArray new];
}
}

external = obs.external;
for(uint32_t i = 0; i < obs.numChanges; i++) {
NSString *docID =slice2string(changes[i].docID);
[docIDs addObject: docID];
}
c4dbobs_releaseChanges(changes, obs.numChanges);
} while(obs.numChanges > 0);
}
}

- (void) removeToken: (id)token {
CBL_LOCK(_mutex) {
CBLChangeListenerToken* t = (CBLChangeListenerToken*)token;
if (t.context)
[self removeDocumentChangeListenerWithToken: token];
else {
if ([_colChangeNotifier removeChangeListenerWithToken: token] == 0) {
c4dbobs_free(_colObs);
_colObs = nil;
_colChangeNotifier = nil;
}
}
}
}

- (void) removeDocumentChangeListenerWithToken: (CBLChangeListenerToken*)token {
CBL_LOCK(_mutex) {
NSString* documentID = (NSString*)token.context;
CBLDocumentChangeNotifier* notifier = _docChangeNotifiers[documentID];
if (notifier && [notifier removeChangeListenerWithToken: token] == 0) {
[notifier stop];
[_docChangeNotifiers removeObjectForKey:documentID];
}
}
}

- (void) freeC4Observer {
c4dbobs_free(_colObs);
_colObs = nullptr;
_colChangeNotifier = nil;

[_docChangeNotifiers.allValues makeObjectsPerformSelector: @selector(stop)];
_docChangeNotifiers = nil;
}

#pragma mark - Document listener

- (id<CBLListenerToken>) addDocumentChangeListenerWithDocumentID: documentID
Expand Down Expand Up @@ -976,4 +831,171 @@ - (nullable CBLQueryIndex*) indexWithName: (nonnull NSString*)name
}
}

#pragma mark - Internal

- (BOOL) checkIsValid: (NSError**)error {
BOOL valid = c4coll_isValid(_c4col);
if (!valid) {
if (error)
*error = CBLCollectionErrorNotOpen;
}

return valid;
}

- (BOOL) isValid {
return [self checkIsValid: nil];
}

- (BOOL) database: (CBLDatabase*)db isValid: (NSError**)error {
BOOL valid = db != nil;
if (!valid) {
if (error)
*error = CBLDatabaseErrorNotOpen;
}

return valid;
}

- (C4CollectionSpec) c4spec {
// Convert to cString directly instead of using CBLStringBytes to avoid
// stack-use-after-scope problem when a small string is kept in the
// _local stack based buffer of the CBLStringBytes
C4Slice name = c4str([_name cStringUsingEncoding: NSUTF8StringEncoding]);
C4Slice scopeName = c4str([_scope.name cStringUsingEncoding: NSUTF8StringEncoding]);
return { .name = name, .scope = scopeName };
}

- (BOOL) isEqual: (id)object {
if (self == object)
return YES;

CBLCollection* other = $castIf(CBLCollection, object);
if (!other)
return NO;

if (!(other && [self.name isEqual: other.name] &&
[self.scope.name isEqual: other.scope.name] &&
[self.database.path isEqual: other.database.path])) {
return NO;
}

if (!self.isValid || !other.isValid)
return NO;

return YES;
}

- (id<CBLListenerToken>) addCollectionChangeListener: (void (^)(CBLCollectionChange*))listener
queue: (dispatch_queue_t)queue {
if (!_colChangeNotifier) {
_colChangeNotifier = [CBLChangeNotifier new];
C4Error c4err = {};
_colObs = c4dbobs_createOnCollection(_c4col, colObserverCallback, (__bridge void *)self, &c4err);
if (!_colObs) {
CBLWarn(Database, @"%@ Failed to create collection obs c4col=%p err=%d/%d",
self, _c4col, c4err.domain, c4err.code);
}
}

return [_colChangeNotifier addChangeListenerWithQueue: queue listener: listener delegate: self];
}

static void colObserverCallback(C4CollectionObserver* obs, void* context) {
CBLCollection *c = (__bridge CBLCollection *)context;
dispatch_async(c.dispatchQueue, ^{
[c postCollectionChanged];
});
}

- (void) postCollectionChanged {
CBL_LOCK(_mutex) {
if (!_colObs || !_c4col)
return;

const uint32_t kMaxChanges = 100u;
C4DatabaseChange changes[kMaxChanges];
bool external = false;
C4CollectionObservation obs = {};
NSMutableArray* docIDs = [NSMutableArray new];
do {
// Read changes in batches of kMaxChanges:
obs = c4dbobs_getChanges(_colObs, changes, kMaxChanges);
if (obs.numChanges == 0 || external != obs.external || docIDs.count > 1000) {
if(docIDs.count > 0) {
CBLCollectionChange* change = [[CBLCollectionChange alloc] initWithCollection: self
documentIDs: docIDs
isExternal: external];
[_colChangeNotifier postChange: change];
docIDs = [NSMutableArray new];
}
}

external = obs.external;
for(uint32_t i = 0; i < obs.numChanges; i++) {
NSString *docID =slice2string(changes[i].docID);
[docIDs addObject: docID];
}
c4dbobs_releaseChanges(changes, obs.numChanges);
} while(obs.numChanges > 0);
}
}

- (void) removeToken: (id)token {
CBL_LOCK(_mutex) {
CBLChangeListenerToken* t = (CBLChangeListenerToken*)token;
if (t.context)
[self removeDocumentChangeListenerWithToken: token];
else {
if ([_colChangeNotifier removeChangeListenerWithToken: token] == 0) {
c4dbobs_free(_colObs);
_colObs = nil;
_colChangeNotifier = nil;
}
}
}
}

- (void) removeDocumentChangeListenerWithToken: (CBLChangeListenerToken*)token {
CBL_LOCK(_mutex) {
NSString* documentID = (NSString*)token.context;
CBLDocumentChangeNotifier* notifier = _docChangeNotifiers[documentID];
if (notifier && [notifier removeChangeListenerWithToken: token] == 0) {
[notifier stop];
[_docChangeNotifiers removeObjectForKey:documentID];
}
}
}

- (void) freeC4Observer {
c4dbobs_free(_colObs);
_colObs = nullptr;
_colChangeNotifier = nil;

[_docChangeNotifiers.allValues makeObjectsPerformSelector: @selector(stop)];
_docChangeNotifiers = nil;
}

- (nullable NSArray*) _indexesInfo: (NSError**)error {
CBL_LOCK(_mutex) {
if (![self checkIsValid: error])
return nil;

C4Error err = {};
C4SliceResult res = c4coll_getIndexesInfo(_c4col, &err);
if (err.code != 0){
convertError(err, error);
return nil;
}

FLDoc doc = FLDoc_FromResultData(res, kFLTrusted, nullptr, nullslice);
FLSliceResult_Release(res);

NSArray* indexes = FLValue_GetNSObject(FLDoc_GetRoot(doc), nullptr);
FLDoc_Release(doc);

return indexes;
}
}

@end
Loading

0 comments on commit 8bef365

Please sign in to comment.