| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- //
- // FMDatabaseQueueTests.m
- // fmdb
- //
- // Created by Graham Dennis on 24/11/2013.
- //
- //
- #import <XCTest/XCTest.h>
- #import "FMDatabaseQueue.h"
- #if FMDB_SQLITE_STANDALONE
- #import <sqlite3/sqlite3.h>
- #else
- #import <sqlite3.h>
- #endif
- @interface FMDatabaseQueueTests : FMDBTempDBTests
- @property FMDatabaseQueue *queue;
- @end
- @implementation FMDatabaseQueueTests
- + (void)populateDatabase:(FMDatabase *)db
- {
- [db executeUpdate:@"create table easy (a text)"];
-
- [db executeUpdate:@"create table qfoo (foo text)"];
- [db executeUpdate:@"insert into qfoo values ('hi')"];
- [db executeUpdate:@"insert into qfoo values ('hello')"];
- [db executeUpdate:@"insert into qfoo values ('not')"];
- }
- - (void)setUp
- {
- [super setUp];
- // Put setup code here. This method is called before the invocation of each test method in the class.
-
- self.queue = [FMDatabaseQueue databaseQueueWithPath:self.databasePath];
- }
- - (void)tearDown
- {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
- [super tearDown];
- }
- - (void)testURLOpenNoPath {
- FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] init];
- XCTAssert(queue, @"Database queue should be returned");
- queue = nil;
- }
- - (void)testURLOpenNoURL {
- FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] initWithURL:nil];
- XCTAssert(queue, @"Database queue should be returned");
- queue = nil;
- }
- - (void)testInvalidURL {
- NSURL *tempFolder = [NSURL fileURLWithPath:NSTemporaryDirectory()];
- NSURL *folderURL = [tempFolder URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
- NSURL *fileURL = [folderURL URLByAppendingPathComponent:@"test.sqlite"];
-
- FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] initWithURL:fileURL];
- XCTAssertNil(queue, @"Database queue should not be returned for invalid path");
- queue = nil;
- }
- - (void)testInvalidPath {
- NSURL *tempFolder = [NSURL fileURLWithPath:NSTemporaryDirectory()];
- NSURL *folderURL = [tempFolder URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
- NSURL *fileURL = [folderURL URLByAppendingPathComponent:@"test.sqlite"];
-
- FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] initWithPath:fileURL.path];
- XCTAssertNil(queue, @"Database queue should not be returned for invalid path");
- queue = nil;
- }
- - (void)testReopenFailure {
- NSFileManager *manager = [NSFileManager defaultManager];
-
- NSURL *tempFolder = [NSURL fileURLWithPath:NSTemporaryDirectory()];
- NSURL *folderURL = [tempFolder URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
- BOOL success = [manager createDirectoryAtURL:folderURL withIntermediateDirectories:true attributes:nil error:nil];
- NSAssert(success, @"Unable to create folder");
-
- NSURL *fileURL = [folderURL URLByAppendingPathComponent:@"test.sqlite"];
-
- FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] initWithURL:fileURL];
- XCTAssert(queue, @"Database queue was unable to be created");
-
- [queue close];
-
- success = [manager removeItemAtURL:fileURL error:nil];
- XCTAssert(success, @"Unable to remove database");
-
- success = [manager removeItemAtURL:folderURL error:nil];
- XCTAssert(success, @"Unable to remove folder");
-
- [queue inDatabase:^(FMDatabase *db) {
- XCTAssertNil(db, @"Should be `nil` or never have reached here because database couldn't be reopened");
- }];
-
- queue = nil;
- }
- - (void)testURLOpen {
- NSURL *tempFolder = [NSURL fileURLWithPath:NSTemporaryDirectory()];
- NSURL *fileURL = [tempFolder URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
-
- FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithURL:fileURL];
- XCTAssert(queue, @"Database queue should be returned");
- queue = nil;
- [[NSFileManager defaultManager] removeItemAtURL:fileURL error:nil];
- }
- - (void)testURLOpenInit {
- NSURL *tempFolder = [NSURL fileURLWithPath:NSTemporaryDirectory()];
- NSURL *fileURL = [tempFolder URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
-
- FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] initWithURL:fileURL];
- XCTAssert(queue, @"Database queue should be returned");
- queue = nil;
- [[NSFileManager defaultManager] removeItemAtURL:fileURL error:nil];
- }
- - (void)testURLOpenWithOptions {
- NSURL *tempFolder = [NSURL fileURLWithPath:NSTemporaryDirectory()];
- NSURL *fileURL = [tempFolder URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
-
- FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithURL:fileURL flags:SQLITE_OPEN_READWRITE];
- XCTAssertNil(queue, @"Database queue should not have been created");
- }
- - (void)testURLOpenInitWithOptions {
- NSURL *tempFolder = [NSURL fileURLWithPath:NSTemporaryDirectory()];
- NSURL *fileURL = [tempFolder URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
-
- FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] initWithURL:fileURL flags:SQLITE_OPEN_READWRITE];
- XCTAssertNil(queue, @"Database queue should not have been created");
- queue = [[FMDatabaseQueue alloc] initWithURL:fileURL flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE];
- XCTAssert(queue, @"Database queue should have been created");
-
- [queue inDatabase:^(FMDatabase * _Nonnull db) {
- BOOL success = [db executeUpdate:@"CREATE TABLE foo (bar INT)"];
- XCTAssert(success, @"Create failed");
- success = [db executeUpdate:@"INSERT INTO foo (bar) VALUES (?)", @42];
- XCTAssert(success, @"Insert failed");
- }];
- queue = nil;
- queue = [[FMDatabaseQueue alloc] initWithURL:fileURL flags:SQLITE_OPEN_READONLY];
- XCTAssert(queue, @"Now database queue should open have been created");
- [queue inDatabase:^(FMDatabase * _Nonnull db) {
- BOOL success = [db executeUpdate:@"CREATE TABLE baz (qux INT)"];
- XCTAssertFalse(success, @"But updates should fail on read only database");
- }];
- queue = nil;
-
- [[NSFileManager defaultManager] removeItemAtURL:fileURL error:nil];
- }
- - (void)testURLOpenWithOptionsVfs {
- sqlite3_vfs vfs = *sqlite3_vfs_find(NULL);
- vfs.zName = "MyCustomVFS";
- XCTAssertEqual(SQLITE_OK, sqlite3_vfs_register(&vfs, 0));
- NSURL *tempFolder = [NSURL fileURLWithPath:NSTemporaryDirectory()];
- NSURL *fileURL = [tempFolder URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
-
- FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] initWithURL:fileURL flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE vfs:@"MyCustomVFS"];
- XCTAssert(queue, @"Database queue should not have been created");
- queue = nil;
- XCTAssertEqual(SQLITE_OK, sqlite3_vfs_unregister(&vfs));
- }
- - (void)testQueueSelect
- {
- [self.queue inDatabase:^(FMDatabase *adb) {
- int count = 0;
- FMResultSet *rsl = [adb executeQuery:@"select * from qfoo where foo like 'h%'"];
- while ([rsl next]) {
- count++;
- }
-
- XCTAssertEqual(count, 2);
-
- count = 0;
- rsl = [adb executeQuery:@"select * from qfoo where foo like ?", @"h%"];
- while ([rsl next]) {
- count++;
- }
-
- XCTAssertEqual(count, 2);
- }];
- }
- - (void)testReadOnlyQueue
- {
- FMDatabaseQueue *queue2 = [FMDatabaseQueue databaseQueueWithPath:self.databasePath flags:SQLITE_OPEN_READONLY];
- XCTAssertNotNil(queue2);
- {
- [queue2 inDatabase:^(FMDatabase *db2) {
- FMResultSet *rs1 = [db2 executeQuery:@"SELECT * FROM qfoo"];
- XCTAssertNotNil(rs1);
- [rs1 close];
-
- XCTAssertFalse(([db2 executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:3]]), @"Insert should fail because this is a read-only database");
- }];
-
- [queue2 close];
-
- // Check that when we re-open the database, it's still read-only
- [queue2 inDatabase:^(FMDatabase *db2) {
- FMResultSet *rs1 = [db2 executeQuery:@"SELECT * FROM qfoo"];
- XCTAssertNotNil(rs1);
-
- [rs1 close];
-
- XCTAssertFalse(([db2 executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:3]]), @"Insert should fail because this is a read-only database");
- }];
- }
- }
- - (void)testStressTest
- {
- size_t ops = 16;
-
- dispatch_queue_t dqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
-
- dispatch_apply(ops, dqueue, ^(size_t nby) {
-
- // just mix things up a bit for demonstration purposes.
- if (nby % 2 == 1) {
- [NSThread sleepForTimeInterval:.01];
-
- [self.queue inTransaction:^(FMDatabase *adb, BOOL *rollback) {
- FMResultSet *rsl = [adb executeQuery:@"select * from qfoo where foo like 'h%'"];
- while ([rsl next]) {
- ;// whatever.
- }
- }];
-
- }
-
- if (nby % 3 == 1) {
- [NSThread sleepForTimeInterval:.01];
- }
-
- [self.queue inTransaction:^(FMDatabase *adb, BOOL *rollback) {
- XCTAssertTrue([adb executeUpdate:@"insert into qfoo values ('1')"]);
- XCTAssertTrue([adb executeUpdate:@"insert into qfoo values ('2')"]);
- XCTAssertTrue([adb executeUpdate:@"insert into qfoo values ('3')"]);
- }];
- });
-
- [self.queue close];
-
- [self.queue inDatabase:^(FMDatabase *adb) {
- XCTAssertTrue([adb executeUpdate:@"insert into qfoo values ('1')"]);
- }];
- }
- - (void)testTransaction
- {
- [self.queue inDatabase:^(FMDatabase *adb) {
- [adb executeUpdate:@"create table transtest (a integer)"];
- XCTAssertTrue([adb executeUpdate:@"insert into transtest values (1)"]);
- XCTAssertTrue([adb executeUpdate:@"insert into transtest values (2)"]);
-
- int rowCount = 0;
- FMResultSet *ars = [adb executeQuery:@"select * from transtest"];
- while ([ars next]) {
- rowCount++;
- }
-
- XCTAssertEqual(rowCount, 2);
- }];
-
- [self.queue inTransaction:^(FMDatabase *adb, BOOL *rollback) {
- XCTAssertTrue([adb executeUpdate:@"insert into transtest values (3)"]);
-
- if (YES) {
- // uh oh!, something went wrong (not really, this is just a test
- *rollback = YES;
- return;
- }
-
- XCTFail(@"This shouldn't be reached");
- }];
-
- [self.queue inDatabase:^(FMDatabase *adb) {
-
- int rowCount = 0;
- FMResultSet *ars = [adb executeQuery:@"select * from transtest"];
- while ([ars next]) {
- rowCount++;
- }
-
- XCTAssertFalse([adb hasOpenResultSets]);
-
- XCTAssertEqual(rowCount, 2);
- }];
-
- }
- - (void)testSavePoint
- {
- [self.queue inDatabase:^(FMDatabase *adb) {
- [adb executeUpdate:@"create table transtest (a integer)"];
- XCTAssertTrue([adb executeUpdate:@"insert into transtest values (1)"]);
- XCTAssertTrue([adb executeUpdate:@"insert into transtest values (2)"]);
-
- int rowCount = 0;
- FMResultSet *ars = [adb executeQuery:@"select * from transtest"];
- while ([ars next]) {
- rowCount++;
- }
-
- XCTAssertEqual(rowCount, 2);
- }];
-
- [self.queue inSavePoint:^(FMDatabase *adb, BOOL *rollback) {
- XCTAssertTrue([adb executeUpdate:@"insert into transtest values (3)"]);
-
- if (YES) {
- // uh oh!, something went wrong (not really, this is just a test
- *rollback = YES;
- return;
- }
-
- XCTFail(@"This shouldn't be reached");
- }];
-
- [self.queue inDatabase:^(FMDatabase *adb) {
-
- int rowCount = 0;
- FMResultSet *ars = [adb executeQuery:@"select * from transtest"];
- while ([ars next]) {
- rowCount++;
- }
-
- XCTAssertFalse([adb hasOpenResultSets]);
-
- XCTAssertEqual(rowCount, 2);
- }];
-
- }
- @end
|