Skip to content

Commit 38337b0

Browse files
author
Dounia Berrada
committed
DouniaBerrada: On behalf of Dharani Govindan, implementation of HTML5 APIs DatabaseStorage, LocationContext and WebStorage for iPhone.
r10576
1 parent 13e156d commit 38337b0

10 files changed

+814
-70
lines changed

iphone/iWebDriver.xcodeproj/project.pbxproj

+63-15
Large diffs are not rendered by default.

iphone/src/objc/Database.h

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
Copyright 2010 WebDriver committers
3+
Copyright 2010 Google Inc.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
#import <Foundation/Foundation.h>
19+
#import <HTTPVirtualDirectory.h>
20+
#import <sqlite3.h>
21+
22+
@interface Database : HTTPVirtualDirectory {
23+
int sessionId_;
24+
}
25+
26+
- (id)initWithSessionId:(int)sessionId;
27+
28+
+ (Database *)databaseWithSessionId:(int)sessionId;
29+
30+
- (NSDictionary *)executeSql:(NSDictionary *)dict;
31+
32+
33+
@end

iphone/src/objc/Database.m

+242
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
/*
2+
Copyright 2010 WebDriver committers
3+
Copyright 2010 Google Inc.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
#import "Database.h"
19+
#import "NSException+WebDriver.h"
20+
#import "WebDriverResource.h"
21+
#import "HTTPVirtualDirectory+AccessViewController.h"
22+
#import "errorcodes.h"
23+
24+
static const NSString* kQueryDicKey = @"query";
25+
static const NSString* kQueryArgsDicKey = @"args";
26+
static const NSString* kQueryDatabaseDicKey = @"dbName";
27+
28+
@implementation Database
29+
30+
- (id)initWithSessionId:(int)sessionId {
31+
self = [super init];
32+
if (!self) {
33+
return nil;
34+
}
35+
sessionId_ = sessionId;
36+
37+
[self setIndex:
38+
[WebDriverResource resourceWithTarget:self
39+
GETAction:NULL
40+
POSTAction:@selector(executeSql:)
41+
PUTAction:NULL
42+
DELETEAction:NULL]];
43+
return self;
44+
}
45+
46+
+ (Database *)databaseWithSessionId:(int)sessionId {
47+
return [[[Database alloc] initWithSessionId:sessionId] autorelease];
48+
}
49+
50+
51+
// Get HTML5 database path + db name from local db path
52+
// return autoreleased object.
53+
// dbInfo contains 'html5 database name', 'db version', 'db display name' string
54+
- (NSString *)getDatabasePath:(NSString *)dbInfo {
55+
NSArray* dbInfoItems = [dbInfo componentsSeparatedByString:@","];
56+
NSString* name = [dbInfoItems objectAtIndex:0];
57+
NSString* displayName = [dbInfoItems objectAtIndex:2];
58+
59+
sqlite3 *database = NULL;
60+
NSString *path = @"";
61+
if ([NSHomeDirectory() length] > 0) {
62+
NSString *databasePath = [NSHomeDirectory() stringByAppendingPathComponent:
63+
@"Library/WebKit/Databases/Databases.db"];
64+
// Open the database from the users file system
65+
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
66+
NSString *sqlStatement = [NSString stringWithFormat:
67+
@"select * from Databases where"
68+
" name=%@ and displayName=%@;",
69+
name, displayName];
70+
const char* cSqlStatement = [sqlStatement // get query as char *
71+
cStringUsingEncoding:NSUTF8StringEncoding];
72+
sqlite3_stmt *compiledStatement = NULL;
73+
if (sqlite3_prepare_v2(database, cSqlStatement, -1, &compiledStatement,
74+
NULL) == SQLITE_OK) {
75+
while (sqlite3_step(compiledStatement) == SQLITE_ROW) {
76+
NSString *dbSubDir = [NSString stringWithUTF8String:(char *)
77+
sqlite3_column_text(compiledStatement, 1)];
78+
NSString *dbName = [NSString stringWithUTF8String:(char *)
79+
sqlite3_column_text(compiledStatement, 5)];
80+
NSString *dbNameAndPartPath = [NSString stringWithFormat:
81+
@"Library/WebKit/Databases/%@/%@",
82+
dbSubDir, dbName];
83+
path = [[[NSHomeDirectory() stringByAppendingPathComponent:
84+
dbNameAndPartPath] copy] autorelease];
85+
break;
86+
}
87+
if (compiledStatement) {
88+
sqlite3_finalize(compiledStatement);
89+
}
90+
}
91+
if (database) {
92+
sqlite3_close(database);
93+
}
94+
}
95+
}
96+
return path;
97+
}
98+
99+
// Bind arguments to SQL query. We support numeric and text arguments
100+
// it does not support BLOB and VVV. if there is ? argument, we try to
101+
// pass it as text.
102+
// if we detect error we thow an exception.
103+
- (NSString *)bindArgumentsToQuery:(sqlite3_stmt *)statement
104+
arguments:(NSArray *)args{
105+
NSString *result = @"";
106+
if (sqlite3_bind_parameter_count(statement) != [args count]) {
107+
result = @"Bind parameter count doesn't match number of question marks";
108+
return result;
109+
}
110+
for (unsigned i = 1; i <= [args count]; ++i) {
111+
const char *cBindName = sqlite3_bind_parameter_name(statement, i);
112+
NSString* argument = [args objectAtIndex:i - 1];
113+
int bindResult = SQLITE_ERROR;
114+
// We support only numeric and text arguments at this momemnt.
115+
if (cBindName == "?NNN") { // numeric
116+
NSScanner *sc = [NSScanner scannerWithString:argument];
117+
if ([sc scanDouble:NULL]) { // double argument
118+
double argumentAsDouble = [argument doubleValue];
119+
bindResult = sqlite3_bind_double(statement, i, argumentAsDouble);
120+
} else { // integer argument
121+
if ([sc scanInt:NULL]) {
122+
int argumentInt = [argument intValue];
123+
bindResult = sqlite3_bind_double(statement, i, argumentInt);
124+
}
125+
}
126+
} else { // "?" without a following integer have no name and are
127+
// also referred to as "anonymous parameters
128+
const char* cArgument = [argument cStringUsingEncoding:
129+
NSUTF8StringEncoding];
130+
bindResult = sqlite3_bind_text(statement, i, cArgument, -1,
131+
SQLITE_TRANSIENT);
132+
}
133+
if (bindResult != SQLITE_OK) {
134+
result = [[[NSString stringWithFormat:
135+
@"Failed to bind value index %i to statement'", i] copy]
136+
autorelease];
137+
}
138+
}
139+
return result;
140+
}
141+
142+
- (NSMutableArray *)retrieveRows:(sqlite3_stmt *)statement {
143+
NSMutableArray *rows = [NSMutableArray array];
144+
while(sqlite3_step(statement) == SQLITE_ROW) {
145+
int columnCount = sqlite3_data_count(statement);
146+
NSMutableDictionary *record = [NSMutableDictionary dictionary];
147+
148+
for(int i = 0; i < columnCount; i++) {
149+
int columnType = sqlite3_column_type(statement, i);
150+
const char *cColumnName = sqlite3_column_name(statement, i);
151+
NSString *columnNameAsKey = [NSString stringWithUTF8String:
152+
cColumnName];
153+
switch (columnType) {
154+
case SQLITE_INTEGER: {
155+
NSNumber *value = [NSNumber numberWithInt:
156+
sqlite3_column_int(statement, i)];
157+
[record setObject:value forKey:columnNameAsKey];
158+
} break;
159+
case SQLITE_FLOAT: {
160+
NSNumber *value = [NSNumber numberWithFloat:
161+
sqlite3_column_double(statement, i)];
162+
[record setObject:value forKey:columnNameAsKey];
163+
} break;
164+
case SQLITE3_TEXT: {
165+
NSString *value = [NSString stringWithUTF8String:(char *)
166+
sqlite3_column_text(statement, i)];
167+
[record setObject:value forKey:columnNameAsKey];
168+
} break;
169+
default: {
170+
// return nil string for unsupported type
171+
[record setObject:@"" forKey:columnNameAsKey];
172+
}
173+
break;
174+
} //end of switch
175+
} // end of columns loop
176+
[rows addObject:record];
177+
} // end of record loop
178+
return rows;
179+
}
180+
181+
- (NSDictionary *)executeSql:(NSDictionary *)dict {
182+
NSString *query = [dict objectForKey:kQueryDicKey];
183+
NSArray *arguments = [dict objectForKey:kQueryArgsDicKey]; // query arguments
184+
NSString *dbInfo = [dict objectForKey:kQueryDatabaseDicKey];
185+
NSString *dbPathAndName = [self getDatabasePath:dbInfo];
186+
187+
NSMutableDictionary *resultSet;
188+
sqlite3 *database = NULL;
189+
190+
if ([dbPathAndName length] > 0) {
191+
// Open the database from the users file system
192+
if(sqlite3_open([dbPathAndName UTF8String], &database) == SQLITE_OK) {
193+
const char* cSqlStatement = [query cStringUsingEncoding:
194+
NSUTF8StringEncoding];
195+
sqlite3_stmt *statement = NULL;
196+
if(sqlite3_prepare_v2(database, cSqlStatement, -1, &statement,
197+
NULL) == SQLITE_OK) {
198+
NSString *msgResult = [self bindArgumentsToQuery:statement
199+
arguments:arguments];
200+
if ([msgResult length] > 0) { // could not bind args, throw except-n
201+
if (statement) sqlite3_finalize(statement);
202+
if (database) sqlite3_close(database);
203+
@throw [NSException webDriverExceptionWithMessage:msgResult
204+
andStatusCode:EUNHANDLEDERROR];
205+
}
206+
207+
NSMutableArray *rows = [self retrieveRows:statement];
208+
209+
int lastInsertedRowId = sqlite3_last_insert_rowid(database);
210+
int rowsAffected = sqlite3_changes(database);
211+
212+
if (lastInsertedRowId == 0) {
213+
lastInsertedRowId = -1;
214+
}
215+
216+
resultSet = [NSMutableDictionary dictionaryWithObjectsAndKeys:
217+
[NSNumber numberWithInt:lastInsertedRowId], @"insertId",
218+
[NSNumber numberWithInt:rowsAffected], @"rowsAffected",
219+
rows, @"rows",
220+
nil];
221+
222+
if (statement) {
223+
sqlite3_finalize(statement);
224+
}
225+
} // end of prepare sql request
226+
} else { // end of process html5 db
227+
NSString *message = @"Could not find HTML5 database, check name and display name.";
228+
@throw [NSException webDriverExceptionWithMessage:message
229+
andStatusCode:EUNHANDLEDERROR];
230+
}
231+
} else {
232+
NSString *message = @"Could not find local Database.db.";
233+
@throw [NSException webDriverExceptionWithMessage:message
234+
andStatusCode:EUNHANDLEDERROR];
235+
}
236+
if (database) {
237+
sqlite3_close(database);
238+
}
239+
return resultSet;
240+
}
241+
242+
@end

iphone/src/objc/GeoLocation.h

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
Copyright 2010 WebDriver committers
3+
Copyright 2010 Google Inc.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
#import <CoreLocation/CoreLocation.h>
19+
20+
// We redefine coordinate and altitude getters to emulate geo location
21+
// possition. it is the same if we do lazy swizzling
22+
@interface CLLocation (Synthesize)
23+
@end
24+
25+
// mock object (singleton) to keep fake geo positions
26+
@interface GeoLocation : NSObject {
27+
CLLocationCoordinate2D coordinate_;
28+
CLLocationDistance altitude_;
29+
}
30+
31+
+ (GeoLocation *)sharedManager;
32+
- (CLLocationCoordinate2D)getCoordinate;
33+
- (CLLocationDistance)getAltitude;
34+
- (void)setCoordinate:(CLLocationDegrees)longitude
35+
latitude:(CLLocationDegrees)latitude;
36+
- (void)setAltitude:(CLLocationDistance)altitude;
37+
@end

0 commit comments

Comments
 (0)