If I create a new project which includes unit tests, the test cases get called. But when I'm adding tests to an existing project I'm getting the following in the log:
2013-05-21 19:41:08.814 otest[51593:7e03] Unknown Device Type. Using UIUserInterfaceIdiomPhone based on screen size
Test Suite '/Users/impadmin/Library/Developer/Xcode/DerivedData/SmartDiary-frrybdtgyyjgewbialqsmxkwvlxs/Build/Products/Debug-iphonesimulator/testSmartDiary.octest(Tests)'
started at 2013-05-21 14:11:09 +0000
Test Suite 'testShowContacts' started at 2013-05-21 14:11:09 +0000
Test Suite 'testShowContacts' finished at 2013-05-21 14:11:09 +0000.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
I've added the SenTestKit to the frameworks, and then added the testing bundle via Add Target.
Where am I going wrong?
Let me add the method and its test case here:
//the method to be tested
-(IBAction)addTask{
if(!([mPriority.text isEqualToString:#"1"] ||[mPriority.text isEqualToString:#"2"] ||[mPriority.text isEqualToString:#"3"] ||[mPriority.text isEqualToString:#"4"] ||[mPriority.text isEqualToString:#"5"]))
{
NSLog(#"Enter valid Priority value");
}
else if ([mTaskName.text isEqualToString:#""]) {
NSLog(#"Task name can't be blank");
}
else{
sqlite3_stmt *statement;
const char *dbPath = [mDatabasePath UTF8String];
//[[appViewController returnObject].mDatabasePath UTF8String];
if (sqlite3_open(dbPath, &mDiary) == SQLITE_OK)
{
NSLog(#"%#",mPriority.text);
NSString *insertSQL2=[NSString stringWithFormat:#"INSERT INTO TODO VALUES(\"%#\",\"%#\",\"%#\",\"%#\",\"%#\")",mStartDate.text,mEndDate.text,mTaskName.text,mTaskDescription.text,mPriority.text];
NSLog(#"%#",insertSQL2);
const char *insert_stmt2 = [insertSQL2 UTF8String];
sqlite3_prepare_v2(mDiary, insert_stmt2,
-1, &statement, NULL);
NSLog(#"%#",mPriority.text);
if (sqlite3_step(statement) == SQLITE_DONE )
{
mStartDate.text=#"";
mEndDate.text=#"";
mTaskName.text=#"";
mTaskDescription.text=#"";
mPriority.text=#"";
}
else {
NSLog(#"failed to add");
}
sqlite3_finalize(statement);
sqlite3_close(mDiary);
}
}
}
//here's the test:
-(void)testAddTask
{
AddTaskViewController *obj;
obj = [[AddTaskViewController alloc]init];
obj.mTaskName.text = #"t1";
obj.mTaskDescription.text = #"t2";
obj.mStartDate.text = #"56987";
obj.mEndDate.text = #"55425";
obj.mPriority.text = #"3";
[obj addTask];
sqlite3_stmt *statement;
const char *dbpath = [obj.mDatabasePath UTF8String];
if (sqlite3_open(dbpath,&mDiaryTest)== SQLITE_OK) {
NSString *selectSQL = [NSString stringWithFormat:#"SELECT * FROM TODO WHERE mTaskName = \"%#\"",obj.mTaskName.text];
const char *query_stmt = [selectSQL UTF8String];
if (sqlite3_prepare_v2(mDiaryTest,
query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if(sqlite3_step(statement) == SQLITE_ROW)
{
testString = [[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)];
}
}
}
sqlite3_finalize(statement);
sqlite3_close(mDiaryTest);
NSLog(#"%#",testString);
STAssertEquals(testString,#"t2",#"should be equal");
}
I found that in target dependencies the project was unchecked. I checked it and tested again, whereupon I'm getting the following errors:
Undefined symbols for architecture i386:
"_OBJC_CLASS_$_AddTaskViewController", referenced from:
objc-class-ref in testAddTask.o
"_sqlite3_close", referenced from:
-[testAddTask testAddTask] in testAddTask.o
"_sqlite3_column_text", referenced from:
-[testAddTask testAddTask] in testAddTask.o
"_sqlite3_finalize", referenced from:
-[testAddTask testAddTask] in testAddTask.o
"_sqlite3_open", referenced from:
-[testAddTask testAddTask] in testAddTask.o
"_sqlite3_prepare_v2", referenced from:
-[testAddTask testAddTask] in testAddTask.o
"_sqlite3_step", referenced from:
-[testAddTask testAddTask] in testAddTask.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I know this is probably going off topic, since the original question was entirely different, but can anyone please tell me why these errors are coming? I've added the necessary frameworks.
As you are testing UIKit dependent stuff, you want to run Application Tests. Make sure you have set the Bundle Loader and Test Host build settings (refer to the documentation).
Further you have to link the libsqlite3.0.dylib against your tests target too, because you are using sqlite functions in your unit tests.
Related
Im writing simple wrapper for loading leaderboards from game center and it's working like a charm on iOS, but while i build my app on macOS i'm getting this error:
"_gameCenter_loadLeaderboard", referenced from:
_LeaderboardWrapper_gameCenter_loadLeaderboard_m1E818D39D7E09691764495F877AE9D990EC4D432 in F9507B415CD33260EA533B953F7CF7A8.o
(maybe you meant: _LeaderboardWrapper_gameCenter_loadLeaderboard_m1E818D39D7E09691764495F877AE9D990EC4D432)
"_gameCenter_setLoadLeaderboardCallbackHandler", referenced from:
_LeaderboardWrapper_gameCenter_setLoadLeaderboardCallbackHandler_m622CA920AA696EFA52E1BA9706D4A1087FA4F1FF in F9507B415CD33260EA533B953F7CF7A8.o
(maybe you meant: _LeaderboardWrapper_gameCenter_setLoadLeaderboardCallbackHandler_m622CA920AA696EFA52E1BA9706D4A1087FA4F1FF)
ld: symbol(s) not found for architecture x86_64
Undefined symbols for architecture arm64:
"_gameCenter_loadLeaderboard", referenced from:
_LeaderboardWrapper_gameCenter_loadLeaderboard_m1E818D39D7E09691764495F877AE9D990EC4D432 in E59781FE06F50F58456801B2C8EBD151.o
(maybe you meant: _LeaderboardWrapper_gameCenter_loadLeaderboard_m1E818D39D7E09691764495F877AE9D990EC4D432)
"_gameCenter_setLoadLeaderboardCallbackHandler", referenced from:
_LeaderboardWrapper_gameCenter_setLoadLeaderboardCallbackHandler_m622CA920AA696EFA52E1BA9706D4A1087FA4F1FF in E59781FE06F50F58456801B2C8EBD151.o
(maybe you meant: _LeaderboardWrapper_gameCenter_setLoadLeaderboardCallbackHandler_m622CA920AA696EFA52E1BA9706D4A1087FA4F1FF)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
my LeaderboardWrapper.h looks like:
void gameCenter_setLoadLeaderboardCallbackHandler(GameCenter_LoadLeaderboardCallback handler);
void gameCenter_loadLeaderboard(const char* leaderboardId);
enum GameCenterLoadLeaderboardError
{
GCLoadLeaderboard_NoError = 0,
GCLoadLeaderboard_CallbackHandlerNotSet,
GCLoadLeaderboard_ServiceError,
GCLoadLeaderboard_LeaderboardNotFound
};
and LeaderboardWrapper.m:
#import "LeaderboardWrapper.h"
#import <GameKit/GameKit.h>
#import <Foundation/Foundation.h>
#ifdef __cplusplus
extern "C" {
#endif
GameCenter_LoadLeaderboardCallback _gameCenterLoadLeaderboardCallbackHandler = NULL;
void gameCenter_setLoadLeaderboardCallbackHandler(GameCenter_LoadLeaderboardCallback handler)
{
_gameCenterLoadLeaderboardCallbackHandler = handler;
}
void gameCenter_loadLeaderboard(const char* leaderboardId)
{
if(_gameCenterLoadLeaderboardCallbackHandler == NULL)
{
NSMutableDictionary* result = [NSMutableDictionary dictionary];
result[#"LeaderboardId"] = [NSString stringWithUTF8String:leaderboardId];
result[#"Sucess"] = [NSNumber numberWithBool:false];
result[#"Error"] = [NSNumber numberWithInt:GCLoadLeaderboard_CallbackHandlerNotSet];
_gameCenterLoadLeaderboardCallbackHandler([makeResultString(result) UTF8String]);
return;
}
}
#ifdef __cplusplus
}
#endif
Can anyone tell me what im doing wrong?
When I am trying to insert data into my table, sometimes I get this error, and my app crashes!
Crash logs :
Observation(4001,0x10dd67000) malloc: *** error for object 0x7fff3a917100: Non-aligned pointer being freed (2)
*** set a breakpoint in malloc_error_break to debug
2016-11-03 11:12:03.063 Observation[4001:46477] Insertion failed !
Printing description of dbpath:
(const char *) dbpath = 0x00007fff3b8a5690 "/Users/macbt/Library/Developer/CoreSimulator/Devices/0EEC62AE-6DF0-4FC4-9D30-1EB90CB695A5/data/Containers/Data/Application/A709E729-3162-4CC8-B9FF-2F22A32FC6BD/Documents/ObservationDB.db"
Printing description of insertSQL:
insert into table_hazard (id, name, modifiedDate) values ("1","Hazard", "03/11/2016 11:12:03 AM")
Printing description of insert_stmt:
(const char *) insert_stmt = 0x00007fff3b9291a1 "insert into table_hazard (id, name, modifiedDate) values (\"1\",\"Hazard\", \"03/11/2016 11:12:03 AM\")"
Try to set a breakpoint on malloc_error_break.
Set your variables to nil after you release them.
Go carefully over all the calls to sqlite3_prepare_v2 instructions and make sure that the matching sqlite3_finalize is called for each one of them.
Add #synchroinized block to make it thread safe
The solution of this type of problems is , you may be missing below statement.
sqlite3_finalize(statement);
sqlite3_close(database);
after every
sqlite3_open()
sqlite3_prepare_v2()
we should always finalize the statement and close the database before return statement. Don't leave database open.
without finalizing statement and without closing Database if you try to again open it sqlite3_open()
or
sqlite3_prepare_v2()
this will result in EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) regarding database .
For example:
-(BOOL) insertDropdownValues:(NSString *)tableName
andId:(NSInteger) dID
name:(NSString*) name
modifiedDate:( NSString*) modifiedDate {
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat:#"insert into %# (%#, %#, %#) values (\"%ld\",\"%#\", \"%#\")",tableName,ID,NAME,MODIFIED_DATE, dID,name,modifiedDate];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
NSLog(#"Inserted SuccessFull");
sqlite3_finalize(statement);
sqlite3_close(database);
return YES;
}
else {
NSLog(#"Insertion failed !");
sqlite3_finalize(statement);
sqlite3_close(database);
return NO;
}
}
sqlite3_reset(statement);
return NO;
}
I believe the problem might be due to accessing database in different threads at the same time. You can use thread lock to solve this problem. You can write the code for database operations inside #synchronized block for solving this problem. It can be implemented as follows.
#synchronized (self) {
// do the operation
}
Please let me know if it either works or doesn't work. Feel free to suggest edits.
Go for Fmdb for sqlite implementation https://github.com/ccgus/fmdb it's very easy to understand
I have created a table(REPORTDATA) in existing database. I am trying to insert the values in to table. But it is not inserted. I am using the following code.
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
databasePath = [docsDir stringByAppendingPathComponent:#"Album.db"];
const char *dbpath = [databasePath UTF8String];
NSString *insertSQL;
if (sqlite3_open(dbpath, & albumDB) == SQLITE_OK)
{
int rowCount = [self GetArticlesCount];
rowCount += 1;
NSString *tempcount = [NSString stringWithFormat:#"%d", rowCount];
insertSQL = [NSString stringWithFormat: #"INSERT INTO REPORTDATA (Num, Json) VALUES ('%#','%#')", tempcount, tempcount];
char *errmsg=nil;
if(sqlite3_exec(albumDB, [insertSQL UTF8String], NULL, NULL, &errmsg)==SQLITE_OK)
{
}
else
{
NSLog(#"Error Message is =%s",errmsg);
}
}
sqlite3_close(albumDB);
Get number of rows in a table:
- (int) GetArticlesCount
{
int count = 0;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
databasePath = [docsDir stringByAppendingPathComponent:#"Album.db"];
if (sqlite3_open([self.databasePath UTF8String], &albumDB) == SQLITE_OK)
{
const char* sqlStatement = "SELECT COUNT(*) FROM REPORTDATA";
sqlite3_stmt *statement;
if( sqlite3_prepare_v2(albumDB, sqlStatement, -1, &statement, NULL) == SQLITE_OK )
{
//Loop through all the returned rows (should be just one)
while( sqlite3_step(statement) == SQLITE_ROW )
{
count = sqlite3_column_int(statement, 0);
}
}
else
{
NSLog( #"Failed from sqlite3_prepare_v2. Error is: %s", sqlite3_errmsg(albumDB) );
}
sqlite3_finalize(statement);
sqlite3_close(albumDB);
}
return count;
}
I am getting
Error Message is =(null).
I'd suggest examining the actual return value of sqlite3_exec:
int rc;
char *errmsg = NULL;
if ((rc = sqlite3_exec(albumDB, [insertSQL UTF8String], NULL, NULL, &errmsg)) == SQLITE_OK) {
NSLog(#"Insert succeeded");
} else {
NSLog(#"Insert failed: %s (%ld)", errmsg, (long)rc);
if (errmsg) sqlite3_free(errmsg);
}
You report that it returned 21, which is SQLITE_MISUSE. This is typical if you called the API functions in the wrong order (e.g. performing some SQL after the database was closed).
The GetArticlesCount method is reopening a database (which is already open), replacing the albumDB variable with a new sqlite3 * pointer. Then, GetArticlesCount is closing the database, and when you return to the first method, the albumDB pointer is now referencing a closed database handle. Thus subsequent SQL calls will generate SQLITE_MISUSE.
To avoid this problem, I would advise against having each function that performs SQL from opening and closing the database. Open the database once and then have all subsequent SQLite calls use that one sqlite3 * pointer.
Try to find error by using below code.
const char *sql = "INSERT INTO REPORTDATA (Num, Json) VALUES VALUES (?,?)"
if (sqlite3_prepare_v2(albumDB, sql, -1, &statement, NULL) != SQLITE_OK)
{
NSLog(#"Prepare failure: %s", sqlite3_errmsg(albumDB));
}
if (sqlite3_bind_text(statement, 1, [commentString UTF8String], -1, NULL) != SQLITE_OK)
{
NSLog(#"Bind 1 failure: %s", sqlite3_errmsg(albumDB));
}
if (sqlite3_step(statement) != SQLITE_DONE) {
NSLog(#"Step failure: %s", sqlite3_errmsg(albumDB));
}
sqlite3_finalize(statement);
As others suggested, I also recommend you to examine the actual error message.
9 of 10, I believe it is because the database file Album.db is not in the documents directory.
Try adding a breakpoint and check the databasePath value, open that directory and confirm the file is there.
If the file has 0 bytes of size, make sure to remove it and add the correct file to your Bundle Resources in:
Project -> Targets -> right target -> Build Phases -> Copy Bundle Resources
EDIT: In your case, you closed the database in GetArticlesCount and tried to use the database pointer after closing it. So I believe Rob's answer is the right solution.
i got 2 main question.
First one; is there any database browser for sqlite that i'm using in my iOS application?
The second question - big one - is a bit complicated.
-(BOOL)createDB{
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString:
[docsDir stringByAppendingPathComponent: #"insider.db"]];
BOOL isSuccess = YES;
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: databasePath ] == NO)
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
char *errMsg;
const char *sql_stmt =
"create table if not exists userInfo (device_token text primary key, device_type text, carrier text, app_version text,os_version text, first_name text, last_name text,last_viewed_item text, last_added_item text, last_item_price_tag text, name_entered integer, login_screen integer, item_detailed_screen integer )";
if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg)
!= SQLITE_OK)
{
isSuccess = NO;
NSLog(#"Failed to create table");
}
sqlite3_close(database);
return isSuccess;
}
else {
isSuccess = NO;
NSLog(#"Failed to open/create database");
}
}
return isSuccess;
}
this is my createDB method that i call it my applicationDIdBecome active,
and i have several methods to get the items that will be saved to my database one of them ;
-(BOOL)getUserFirstName:(NSString *)firstName {
NSLog(#"User's first name is this %#",firstName);
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat:#"insert into userInfo (first_name) values (\"%#\")", firstName];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
return YES;
}
else {
return NO;
}
sqlite3_reset(statement);
}
return NO;
}
i have a lot of these kind of methods ( for each columns in my create table statement)
What i want is this;
I have a backend that use mysql as database.
I need to make the last insertion row and make it JSON format so I can manipulate it and write it to my backend server.
How can i do this?
Thanks in advance.
Cheres.
Regarding SQLite tool, the database format is binary compatible across platforms. So you can just run the app in the simulator, browse to the folder with the simulator files (which varies depending upon Xcode version: it's ~/Library/Application Support/iPhone Simulator in Xcode versions prior to 6, it's ~/Library/Developer/CoreSimulator/Devices in Xcode 6) and open up the database. If your Library folder is hidden, you can unhide it from the Terminal command line, chflags nohidden ~/Library.
You can use the Mac OS X sqlite3 command line app. Many people use the free Firefox SQLite Manager add-on. I personally use Base, a relatively inexpensive SQLite tool. Use whatever you want.
Regarding retrieving results from SQLite and creating JSON from that, the easiest approach is to build a NSDictionary with the values, which you can then pass to NSJSONSerialization method dataWithJSONObject, which can build the JSON body of the request.
So, presumably you'll have some model structure that captures the content in your thirteen columns of this local table. So, insert that data in the local table, and then write a different routine that takes that model data and creates your request to POST this to the server.
You need to determine what your web service API will look like as well as how you want to POST it (e.g. NSURLConnection, NSURLSession (for iOS 7 and later), AFNetworking, etc.), but this seems well beyond the scope of this question.
A couple of unrelated observations:
If you use sqlite3_exec, supplying a pointer to a char * for the error message, remember that you're responsible for releasing that. Also, you might as well log that error message so you know why it failed:
if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK) {
isSuccess = NO;
NSLog(#"Failed to create table: %s", errMsg);
sqlite3_free(errMsg);
}
See the sqlite3_exec documentation for more information.
I would advise against using stringWithFormat to build your INSERT statements. Always use ? placeholders in your SQL, and then manually bind values.
Also, getUserFirstName is returning immediately if the statement was successful. So, it's not freeing the memory associated with the sqlite3_prepare_v2 (which you should do via sqlite3_finalize, not sqlite3_reset). It's also not closing the database.
-(BOOL)insertUserFirstName:(NSString *)firstName
{
BOOL success = YES;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK) {
const char *insert_stmt = "insert into userInfo (first_name) values (?)";
if (sqlite3_prepare_v2(database, insert_stmt, -1, &statement, NULL) != SQLITE_OK) {
NSLog(#"prepare failure: %s", sqlite3_errmsg(database));
sqlite3_close(database);
return NO;
}
if (sqlite3_bind_text(statement, 1, [firstName UTF8String], -1, NULL) != SQLITE_OK) {
success = NO;
NSLog(#"bind 1 failure: %s", sqlite3_errmsg(database));
} else if (sqlite3_step(statement) != SQLITE_DONE) {
success = NO;
NSLog(#"step failure: %s", sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
statement = NULL;
sqlite3_close(database);
database = NULL;
}
return success;
}
Personally, I'd even advise against opening and closing the database with every SQLite call. But if you do, make sure you balance your open statements and close statements like above. You might want to also test to make sure that firstName is not nil (and if it is, call sqlite3_bind_null instead of sqlite3_bind_text).
It doesn't quite make sense to me that you're inserting only the user name. You'd presumably want to insert all of the column values at once.
When writing SQLite code, you might want to consider using FMDB, a thin Objective-C wrapper around SQLite C API, which greatly simplifies your life. When you tackle step 3, performing the sqlite3_bind_XXX calls for each of your thirteen columns, I think you'll really start to appreciate the power of something like FMDB.
I'm trying to build my simple app to run on the iPad. What my app is doing is trying to read from the on board pastebin which is having some data sent to it via a second app.
However, upon building the app on xcode I have the following linker errors:
Undefined symbols for architecture armv7: "_importString",
referenced from:
RegisterMonoModules() in RegisterMonoModules.o "_exportString", referenced from:
RegisterMonoModules() in RegisterMonoModules.o ld: symbol(s) not found for architecture armv7 clang: error: linker command failed with
exit code 1 (use -v to see invocation)
Now I know that it is looking at my import and export strings but nothing is ever started with a double underscore. Take a look at my dll file I wrote in XCode:
#define MakeStringCopy( _x_ ) ( _x_ != NULL && [_x_ isKindOfClass:[NSString class]] ) ? strdup( [_x_ UTF8String] ) : NULL
#define GetStringParam( _x_ ) ( _x_ != NULL ) ? [NSString stringWithUTF8String:_x_] : [NSString stringWithUTF8String:""]
//send clipboard to unity
extern "C" const char * importString()
{
NSString *result = [UIPasteboard generalPasteboard].string;
return MakeStringCopy(result);
}
//get clipboard from unity
extern "C" void exportString(const char * eString)
{
[UIPasteboard generalPasteboard].string = GetStringParam(eString);//#"the text to copy";
}
And the sister class I have in my Unity application:
[DllImport("__Internal")]
private static extern string _importString();
//retrieves the clipboard contents from xcode
public static string ImportString()
{
//Debug.Log ("import: "+_importString());
if( Application.platform == RuntimePlatform.IPhonePlayer )
{
return _importString();
}
else
{
return "";
}
}
[DllImport("__Internal")]
private static extern void _exportString(string exportData);
//passes string to xcode and xcode copies to clipboard
public static void ExportString(string exportData)
{
// Debug.Log ("export: "+exportData);
if( Application.platform == RuntimePlatform.IPhonePlayer )
{
_exportString(exportData);
}
}
I have stored the dll file in the following folder structor in Unity:
Assets -> Plugin -> iOS
But I'm at a loss as to how to fix my errors. Can anyone please help?
update
Based on a suggestion below I have ommited the underscore from both the import string and export string and I still have the same issues.