Unit test core data and a method with NSExpressionDescription - unit-testing

How do I make a unit test for the following piece code??
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
NSString *sumOfTotalPaidBySelf = #"sumOfTotalPaidBySelf";
expressionDescription.name = sumOfTotalPaidBySelf;
expressionDescription.expression = [NSExpression expressionForKeyPath:#"#sum.moneyInMainCurrency"];
expressionDescription.expressionResultType = NSDoubleAttributeType;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"MCPayment"];
fetchRequest.resultType = NSDictionaryResultType;
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"payingPerson = %#", self];
fetchRequest.propertiesToFetch = #[expressionDescription];
NSError *error = nil;
NSArray *fetchResult = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
if (error) {
NSLog(#"%#: error fetching: %#", self, error);
return nil;
}
return [[fetchResult firstObject] objectForKey:sumOfTotalPaidBySelf];
What I've learned so far is, that this code should work when querying a database that already contains data, which is stored on disk. However for the unit tests I use a persistentStoreType of NSInMemoryStoreType, which gets pre populated with some data during setup and that data still resides in the managedObjectContext.
This is the unit test I have.
MCSharedBill *tonightsBill = [MCSharedBill addSharedBillToContext:_context];
MCPerson *fred = [tonightsBill addPerson];
fred.firstName = #"Fred";
MCPerson *anna = [tonightsBill addPerson];
anna.firstName = #"Anna";
MCPayment *drinks = [tonightsBill addPayment];
drinks.payingPerson = fred;
drinks.money = #(10);
drinks.descriptionOfPayment = #"coffee";
NSNumber *totalPaidByFred = fred.totalSumPaid;
// NSError *error = nil;
// [_context save:&error];
// XCTAssertFalse(error);
XCTAssertEqualWithAccuracy(#(10).doubleValue, totalPaidByFred.doubleValue, 0.001);
Any help would be appreciated.
Cheers.

Related

Getting Crash with AWSS3PutObjectRequest

I am using the AWS SDK like this way
Properties declaration :
#property (nonatomic, strong)AWSStaticCredentialsProvider *credentialsProvider;
#property (nonatomic, strong)AWSServiceConfiguration * configuration;
#property (nonatomic, strong)AWSS3 *s3;
#property (nonatomic, strong) AWSS3PutObjectRequest *putrequest;
And Implementation like this way
AccessKeys * accessKeys = [ECSGlobals sharedInstance].accessKeys;
self.credentialsProvider = [AWSStaticCredentialsProvider credentialsWithAccessKey:accessKeys.accessKeyId secretKey:accessKeys.secretAccessKey];
self.configuration = [AWSServiceConfiguration configurationWithRegion:AWSRegionUSEast1 credentialsProvider:self.credentialsProvider];
self.s3 = [[AWSS3 alloc] initWithConfiguration:self.configuration];
self.putrequest = [AWSS3PutObjectRequest new];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:imageName];
NSData *imageData = UIImageJPEGRepresentation(image, 0.2);
[imageData writeToFile:savedImagePath atomically:NO];
long long fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:savedImagePath error:nil][NSFileSize] longLongValue];
self.putrequest.bucket = bucketName;
self.putrequest.key = imageName;
self.putrequest.contentType = #"image/jpeg";
self.putrequest.body = [NSURL fileURLWithPath:savedImagePath];
self.putrequest.contentLength = [NSNumber numberWithLongLong:fileSize];
[[self.s3 putObject:self.putrequest] continueWithBlock:^id(BFTask *task) {
NSLog(#"Amazon error : %#", [task error]);
return nil;
}];
But I am getting crash
[CFError retain]: message sent to deallocated instance 0x7f2daff0
I have checked all properties are strong. Not sure why I am getting this crash.
I found the solution. We are getting this issue as some how saved image path become nil before coming in use. So there is no image data sending to AWS.
After fixing this, images are uploading successfully.

Upgrade to Yosemite has negative impact on objectForKey mp3 image

Just updated to Yosemite and Xcode 6.0.01 and this code no longer works:
- (NSImage *)songImage {
if (!_songImage) {
AVAsset *asset = [AVAsset assetWithURL:self.fileURL];
for (AVMetadataItem *metadataItem in asset.commonMetadata) {
if ([metadataItem.commonKey isEqualToString:#"artwork"]){
NSDictionary *imageDataDictionary =
(NSDictionary *)metadataItem.value;
NSData *imageData = [imageDataDictionary objectForKey:#"data"];
_songImage =[[NSImage alloc] initWithData:imageData];
}
}
}
if (!_songImage) {
return Nil;
}
return _songImage;
}
I'm not sure if the process was replaced or removed but I now get a message:
2014-10-17 14:36:23.756 FSC Music[3317:122917] -[__NSCFData objectForKey:]: unrecognized
selector sent to instance 0x600000241cb0 2014-10-17 14:36:23.764
FSC Music[3317:122917] -[__NSCFData objectForKey:]: unrecognized selector sent to instance
0x600000241cb0
need to research a solution, but wanted to ask if anyone else has come across this?
I changed to the following code to get it working again.
-(NSImage *)songImage {
if (!_songImage) {
AVAsset *asset = [AVAsset assetWithURL:self.fileURL];
NSArray *metadata = [asset commonMetadata];
for ( AVMetadataItem *item in metadata ) {
if ([item.commonKey isEqualToString:#"artwork"]){
NSData *thePix = (NSData *)item.value;
_songImage =[[NSImage alloc] initWithData:thePix];
}
}
}
if (!_songImage) {
return Nil;
}
return _songImage;
}

How do I get element from NSArray of NSDictionary

This is NSLog of my NSArray
[{"id":16,"venueId":16,"street":"171 - 3401 Dufferin St","city":"Toronto","zipcode":"M6A 2T9","province":"ON","country":"Canada"}]
NSDictionary *dict = [myarray objectAtIndex:i]
//myarray is your array of dictionary
//if the array has just one element like in your example, i will be 0
NSNumber *venueId = [dict objectForKey:#"venueId"];
finally I found solution
NSError *error;
NSArray* jsonArray = [NSJSONSerialization JSONObjectWithData:[[venue objectForKey:#"address"] dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error] ;
NSDictionary *dict = [jsonArray objectAtIndex:0];
//myarray is your array of dictionary
NSString *street = [dict objectForKey:#"street"];
NSLog(#"street: %#", street);
Note: I used below code to check data type to make sure it returns valid kind of class.
if ([[venue objectForKey:#"address"] isKindOfClass:[NSArray class]]) {
NSLog(#"%#", #"It is NSArray");
} else if ([[venue objectForKey:#"address"] isKindOfClass:[NSString class]]) {
NSLog(#"%#", #"It is NSString");
}

Custom objects in array stored in a plist

I've got some custom class objects that i store in an array, this array is then stored in a dictionary with a key. This is then saved and will be loaded when the app is loaded/ reloaded.
Now the issues is that i can't seem to get the custom objects back out, when i load the array it comes back as empty. I must be doing something wrong with either writing or loading the data but i can't figure out what exactly.
Here's the code i have so far:
CustomClass.H file:
#import <Foundation/Foundation.h>
#interface PersonClass : NSObject <NSCoding>
#property (nonatomic,strong) NSString *personName;
#property (nonatomic,strong) NSString *personNo;
#property (nonatomic,strong) NSString *personNotes;
#property (nonatomic) BOOL switchPersonality;
#property (nonatomic) BOOL switchChemistry;
#property (nonatomic) BOOL switchLooks;
#property (nonatomic) BOOL switchHumour;
#property (nonatomic) int personRating;
#property (nonatomic,strong) NSNumber *personRecord;
- (id)initWithName:(NSString *)iPersonName PersonNo:(NSString *)iPersonNo PersonNotes:(NSString *)iPersonNotes SwitchChemistry:(BOOL *)iSwitchChemistry SwitchHumour:(BOOL *)iSwitchHumour SwitchLooks:(BOOL *)iSwitchLooks SwitchPersonality:(BOOL *)iSwitchPersonality PersonRating:(int *)iPersonRating PersonRecord:(NSNumber *)iPersonRecord;
#end
Custom Class.M file:
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:personName forKey:#"pName"];
[aCoder encodeObject:personNo forKey:#"pNo"];
[aCoder encodeObject:personNotes forKey:#"pNotes"];
[aCoder encodeInt:personRating forKey:#"pRating"];
[aCoder encodeObject:personRecord forKey:#"pRecord"];
[aCoder encodeBool:switchChemistry forKey:#"sChemistry"];
[aCoder encodeBool:switchHumour forKey:#"sHumour"];
[aCoder encodeBool:switchLooks forKey:#"sLooks"];
[aCoder encodeBool:switchPersonality forKey:#"sPersonality"];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init]){
self.personName = [aDecoder decodeObjectForKey:#"pName"];
self.personNo = [aDecoder decodeObjectForKey:#"pNo"];
self.personNotes = [aDecoder decodeObjectForKey:#"pNotes"];
self.personRating = [aDecoder decodeIntForKey:#"pRating"];
self.personRecord = [aDecoder decodeObjectForKey:#"pRecord"];
self.switchChemistry = [aDecoder decodeBoolForKey:#"sChemistry"];
self.switchHumour = [aDecoder decodeBoolForKey:#"sHumour"];
self.switchLooks = [aDecoder decodeBoolForKey:#"sLooks"];
self.switchPersonality = [aDecoder decodeBoolForKey:#"sPersonality"];
}
return self;
}
The save Method:
- (void)saveData{
// get paths from root direcory
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to our Data/plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"data.plist"];
NSLog(#"PList Path %#",plistPath);
//new array
NSMutableArray *newEntries = [[NSMutableArray alloc]init];
NSLog(#"NEW ENTRIES BEFORE %#",newEntries);
for (PersonClass *person in peopleEntries) {
//encode the object
[NSKeyedArchiver archivedDataWithRootObject:person];
// add the object to the entries
[newEntries addObject:person];
}
NSLog(#"NEW ENTRIES AFTER %#",newEntries);
[newEntries writeToFile:plistPath atomically:YES];
// create dictionary with arrays and their corresponding keys
NSDictionary *plistDict = [NSDictionary dictionaryWithObjects: [NSMutableArray arrayWithObjects:newEntries, recordId, nil] forKeys:[NSMutableArray arrayWithObjects: #"peopleEntries",#"recordId", nil]];
NSLog(#"DICTIONARY IS IN SAVE %#",plistDict);
NSString *error = nil;
// check if plistData exists
if(plistDict)
{
// write plistData to our Data.plist file
[plistDict writeToFile:plistPath atomically:YES];
}
else
{
NSLog(#"Error in saveData: %#", error);
}
NSLog(#"Save RUN");
}
The load Method:
- (void)loadData{
// get paths from root direcory
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to our Data/plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"data.plist"];
NSLog(#"PList Path %#",plistPath);
// check to see if data.plist exists in documents
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
// return without loading
NSLog(#"RETURNING");
return;
}
// get saved dictionary
NSDictionary *dictionaryTemp = [[NSDictionary alloc]initWithContentsOfFile:plistPath];
NSLog(#"DICTIONARY IS LOAD %#",dictionaryTemp);
if (!dictionaryTemp)
{
NSLog(#"Error reading plist:");
}
// temporary array
NSMutableArray *holderOne = [dictionaryTemp objectForKey:#"peopleEntries"];
// array to be populated
NSMutableArray *holderTwo = [[NSMutableArray alloc]init];
NSLog(#"HOLDER ONE IS BEFORE %#",holderOne);
NSLog(#"HOLDER TWO IS BEFORE %#",holderTwo);
// go through the array and pull out person classes
for (NSData *person in holderOne) {
// temp array
NSData *entry = [holderOne objectAtIndex:person]; // check the object at index might be an issue???
NSLog(#"ENTRY IS %#",entry);
//deencode the object
[NSKeyedUnarchiver unarchiveObjectWithData:entry];
// add the object to the entries
[holderTwo addObject:entry];
}
NSLog(#"HOLDER ONE IS AFTER %#",holderOne);
NSLog(#"HOLDER TWO IS AFTER %#",holderTwo);
// assign values
peopleEntries = [NSMutableArray arrayWithArray:holderTwo];
NSLog(#"DICTIONARY IS AFTER ADDING %#",dictionaryTemp);
recordId = [NSNumber numberWithInt:[[dictionaryTemp objectForKey:#"recordId"]integerValue]];
NSLog(#"recordId is %#",recordId);
NSLog(#"LOAD RUN");
}
OK i finally discovered the issue, i was extending my class from the NSObject subclass which does not implement the NSCoder protocol so i was encoding and decoding my object in the incorrect way. It should have been done in the following way:
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.personName = [decoder decodeObjectForKey:#"pName"];
self.personNo = [decoder decodeObjectForKey:#"pNo"];
self.personNotes = [decoder decodeObjectForKey:#"pNotes"];
self.personRating = [decoder decodeObjectForKey:#"pRating"];
self.switchChemistry = [decoder decodeBoolForKey:#"sChemistry"];
self.switchHumour = [decoder decodeBoolForKey:#"sHumour"];
self.switchLooks = [decoder decodeBoolForKey:#"sLooks"];
self.switchPersonality = [decoder decodeBoolForKey:#"sPersonality"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:personName forKey:#"pName"];
[encoder encodeObject:personNo forKey:#"pNo"];
[encoder encodeObject:personNotes forKey:#"pNotes"];
[encoder encodeObject:personRating forKey:#"pRating"];
[encoder encodeBool:switchChemistry forKey:#"sChemistry"];
[encoder encodeBool:switchHumour forKey:#"sHumour"];
[encoder encodeBool:switchLooks forKey:#"sLooks"];
[encoder encodeBool:switchPersonality forKey:#"sPersonality"];
}
These objects were then added into an array and i was looping through each object in the array and decoding. This was not correct you can simply encode or decode the entire array with te objects as so:
Decode:
NSData *peopleData;
peopleEntries = [NSKeyedUnarchiver unarchiveObjectWithData:peopleData];
Encode:
NSMutableArray *peopleEntries;
NSData *personData = [NSKeyedArchiver archivedDataWithRootObject:[[GlobalData sharedGlobalData]peopleEntries]];

subsonic 3.0 active record update

I am able to retrieve database values and insert database values, but I can't figure out what the Update() syntax should be with a where statement.
Environment -> ASP.Net, C#
Settings.ttinclude
const string Namespace = "subsonic_db.Data";
const string ConnectionStringName = "subsonic_dbConnectionString";
//This is the name of your database and is used in naming
//the repository. By default we set it to the connection string name
const string DatabaseName = "subsonic_db";
Retreive example
var product = equipment.SingleOrDefault(x => x.id == 1);
Insert Example
equipment my_equipment = new equipment();
try
{
// insert
my_equipment.parent_id = 0;
my_equipment.primary_id = 0;
my_equipment.product_code = product_code.Text;
my_equipment.product_description = product_description.Text;
my_equipment.product_type_id = Convert.ToInt32(product_type_id.SelectedItem.Value);
my_equipment.created_date = DateTime.Now;
my_equipment.serial_number = serial_number.Text;
my_equipment.Save();
}
catch (Exception err)
{
lblError.Text = err.Message;
}
Edit: Think that I was just too tired last night, it is pretty easy to update. Just use the retrieve function and use the Update() on that.
var equip = Equipment.SingleOrDefault(x => x.id == 1);
lblGeneral.Text = equip.product_description;
equip.product_description = "Test";
equip.Update();
Resolved. View answer above.