2013-11-24 01:43:02 +00:00
//
// FMDatabaseQueueTests . m
// fmdb
//
// Created by Graham Dennis on 24 / 11 / 2013.
//
//
# import < XCTest / XCTest . h >
# import "FMDatabaseQueue.h"
2015-12-29 07:37:43 +00:00
# if FMDB_SQLITE _STANDALONE
# import < sqlite3 / sqlite3 . h >
# else
# import < sqlite3 . h >
# endif
2013-11-24 01:43:02 +00:00
@ 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 ] ;
}
2017-01-11 22:17:49 +00:00
- ( 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 ;
}
2017-10-24 07:09:25 +00:00
- ( 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 ;
}
2017-01-11 22:17:49 +00:00
- ( 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 ) ) ;
}
2013-11-24 01:43:02 +00:00
- ( 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 ) ;
} ] ;
2017-10-24 07:09:25 +00:00
}
2013-11-24 01:43:02 +00:00
2017-10-24 07:09:25 +00:00
- ( 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 ) ;
} ] ;
2013-11-24 01:43:02 +00:00
}
2017-12-18 23:59:18 +00:00
- ( void ) testClose
{
[ self . queue inDatabase : ^ ( FMDatabase * adb ) {
XCTAssertTrue ( [ adb executeUpdate : @ "CREATE TABLE close_test (a INTEGER)" ] ) ;
XCTAssertTrue ( [ adb executeUpdate : @ "INSERT INTO close_test VALUES (1)" ] ) ;
[ adb close ] ;
} ] ;
[ self . queue inDatabase : ^ ( FMDatabase * adb ) {
FMResultSet * ars = [ adb executeQuery : @ "select * from close_test" ] ;
XCTAssertNotNil ( ars ) ;
} ] ;
}
2013-11-24 01:43:02 +00:00
@ end