Skip to content
Browse files

Added exception catch to main thread block executor.

Deleted SIState.
Got single story execution working.
Removed selectNone from SiStorySources.
Added storing of search criteria to SIStorySources.
  • Loading branch information...
1 parent 8e52aff commit 16b4953b943f322f4146ea650201d7dddba46b94 @drekka committed Aug 15, 2012
View
12 Simon.xcodeproj/project.pbxproj
@@ -30,6 +30,7 @@
322DA95315A18A4B005CFC83 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 653D0E8D13A782AD00A5AB82 /* Foundation.framework */; };
322DA95615A18A4B005CFC83 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 322DA95515A18A4B005CFC83 /* main.m */; };
322DA95A15A18A4B005CFC83 /* PieMan.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 322DA95915A18A4B005CFC83 /* PieMan.1 */; };
+ 32326CD715DA8F6D00C8B1DC /* NSObject+SimonTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32326CD615DA8F6D00C8B1DC /* NSObject+SimonTests.m */; };
324108B61509C19400AFBF66 /* SIUIViewDescriptionVisitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 324108B41509C19400AFBF66 /* SIUIViewDescriptionVisitor.h */; settings = {ATTRIBUTES = (Private, ); }; };
324108B71509C19400AFBF66 /* SIUIViewDescriptionVisitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 324108B51509C19400AFBF66 /* SIUIViewDescriptionVisitor.m */; };
324108BA1509C23200AFBF66 /* SIUIViewDescriptionVisitorDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 324108B91509C23200AFBF66 /* SIUIViewDescriptionVisitorDelegate.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -77,8 +78,6 @@
32A9D11014C907BC00B0CFBD /* NSInvocations.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A9D10F14C907BC00B0CFBD /* NSInvocations.m */; };
32A9D11314C914B500B0CFBD /* SIMacroTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A9D11214C914B500B0CFBD /* SIMacroTests.m */; };
32AF044215CE36C500501B1E /* SIAppBackpackTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32AF044115CE36C500501B1E /* SIAppBackpackTests.m */; };
- 32AF044715CE5E4800501B1E /* SIState.h in Headers */ = {isa = PBXBuildFile; fileRef = 32AF044515CE5E4800501B1E /* SIState.h */; settings = {ATTRIBUTES = (Private, ); }; };
- 32AF044815CE5E4800501B1E /* SIState.m in Sources */ = {isa = PBXBuildFile; fileRef = 32AF044615CE5E4800501B1E /* SIState.m */; };
32AF045215CEB73600501B1E /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32AF045115CEB73600501B1E /* CFNetwork.framework */; };
32AF045415CEB75F00501B1E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32AF045315CEB75F00501B1E /* Security.framework */; };
32AF045915CEB7BA00501B1E /* SIIncomingHTTPConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 32AF045515CEB7BA00501B1E /* SIIncomingHTTPConnection.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -246,6 +245,7 @@
322DA95515A18A4B005CFC83 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
322DA95815A18A4B005CFC83 /* PieMan-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PieMan-Prefix.pch"; sourceTree = "<group>"; };
322DA95915A18A4B005CFC83 /* PieMan.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = PieMan.1; sourceTree = "<group>"; };
+ 32326CD615DA8F6D00C8B1DC /* NSObject+SimonTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SimonTests.m"; sourceTree = "<group>"; };
324108B41509C19400AFBF66 /* SIUIViewDescriptionVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = SIUIViewDescriptionVisitor.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
324108B51509C19400AFBF66 /* SIUIViewDescriptionVisitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = SIUIViewDescriptionVisitor.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
324108B91509C23200AFBF66 /* SIUIViewDescriptionVisitorDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SIUIViewDescriptionVisitorDelegate.h; sourceTree = "<group>"; };
@@ -294,8 +294,6 @@
32A9D10F14C907BC00B0CFBD /* NSInvocations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = NSInvocations.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
32A9D11214C914B500B0CFBD /* SIMacroTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = SIMacroTests.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
32AF044115CE36C500501B1E /* SIAppBackpackTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = SIAppBackpackTests.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
- 32AF044515CE5E4800501B1E /* SIState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = SIState.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
- 32AF044615CE5E4800501B1E /* SIState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = SIState.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
32AF045115CEB73600501B1E /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
32AF045315CEB75F00501B1E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
32AF045515CEB7BA00501B1E /* SIIncomingHTTPConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SIIncomingHTTPConnection.h; sourceTree = "<group>"; };
@@ -557,6 +555,7 @@
isa = PBXGroup;
children = (
65D35BC213A8BA130007A8AD /* NSString+SimonTests.m */,
+ 32326CD615DA8F6D00C8B1DC /* NSObject+SimonTests.m */,
);
name = Categories;
sourceTree = "<group>";
@@ -699,8 +698,6 @@
65FCD12513AF622300A90FCA /* SIRuntime.m */,
32AF045715CEB7BA00501B1E /* SIServerException.h */,
32AF045815CEB7BA00501B1E /* SIServerException.m */,
- 32AF044515CE5E4800501B1E /* SIState.h */,
- 32AF044615CE5E4800501B1E /* SIState.m */,
328DE14815D39945009A16C1 /* SIUIAppBackpack.h */,
328DE14915D39945009A16C1 /* SIUIAppBackpack.m */,
659E629B13DAFC4000ACD34C /* SIUIApplication.h */,
@@ -898,7 +895,6 @@
0BF2104515D25412006BB2CA /* SIResultListener.h in Headers */,
32AF045B15CEB7BA00501B1E /* SIServerException.h in Headers */,
3265B02715144DB400BE0930 /* SIUIAbstractEventGenerator.h in Headers */,
- 32AF044715CE5E4800501B1E /* SIState.h in Headers */,
321A346A1519FA9E00B22EDD /* NSObject+Simon.h in Headers */,
328DE14615D3792C009A16C1 /* SIHttpResultSender.h in Headers */,
328DE14A15D39946009A16C1 /* SIUIAppBackpack.h in Headers */,
@@ -1111,7 +1107,6 @@
3265B02815144DB400BE0930 /* SIUIAbstractEventGenerator.m in Sources */,
321A346B1519FA9E00B22EDD /* NSObject+Simon.m in Sources */,
3260B811151CB81C005A5AAA /* SIUINotAnInputViewException.m in Sources */,
- 32AF044815CE5E4800501B1E /* SIState.m in Sources */,
32AF045A15CEB7BA00501B1E /* SIIncomingHTTPConnection.m in Sources */,
32AF045C15CEB7BA00501B1E /* SIServerException.m in Sources */,
0BF2104615D25412006BB2CA /* SIResultListener.m in Sources */,
@@ -1154,6 +1149,7 @@
328DE14015D368D2009A16C1 /* SIResultListenerTests.m in Sources */,
328DE14315D37566009A16C1 /* GHTestCase+GHTestCase_TestUtils.m in Sources */,
3210989115D6896C00567D6D /* SIStorySourcesTests.m in Sources */,
+ 32326CD715DA8F6D00C8B1DC /* NSObject+SimonTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
13 classes/NSObject+Simon.m
@@ -22,10 +22,21 @@ -(void) executeBlockOnMainThread:(void (^)()) block {
} else {
// Goto the main Q.
DC_LOG(@"Dispatching to main thread");
+ __block NSException *exception = nil;
dispatch_queue_t mainQ = dispatch_get_main_queue();
dispatch_sync(mainQ, ^{
- block();
+ @try {
+ block();
+ }
+ @catch (NSException *e) {
+ DC_LOG(@"Exception caught: %@", e);
+ exception = [e retain];
+ }
});
+ if (exception != nil) {
+ DC_LOG(@"throwing exception");
+ @throw [exception autorelease];
+ }
}
}
View
4 classes/SIAppBackpack.h
@@ -9,7 +9,6 @@
#import <Foundation/Foundation.h>
#import "SIStoryRunner.h"
-#import "SIState.h"
#import "SIStoryLogger.h"
#import "SIAppBackpackImplementation.h"
#import "SIStorySources.h"
@@ -22,9 +21,6 @@
/// @name Properties
-/// The current state of Simon.
-@property (nonatomic, readonly) SIState *state;
-
/// Readonly reference to the story sources.
@property (nonatomic, readonly) SIStorySources *storySources;
View
3 classes/SIAppBackpack.m
@@ -26,7 +26,6 @@ @interface SIAppBackpack (){
@implementation SIAppBackpack
-@synthesize state = _state;
@synthesize runner = _runner;
@synthesize mappings = _mappings;
@synthesize reader = _reader;
@@ -41,7 +40,6 @@ -(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
self.reader = nil;
DC_DEALLOC(_runner);
- DC_DEALLOC(_state);
DC_DEALLOC(logger);
DC_DEALLOC(_mappings);
[super dealloc];
@@ -83,7 +81,6 @@ - (id)init {
// Instantiate required instances
DC_LOG(@"Simon initialising");
self.reader = [[[SIStoryFileReader alloc] init] autorelease];
- _state = [[SIState alloc] init];
_runner = [[SIStoryRunner alloc] init];
logger = [[SIStoryLogger alloc] init];
View
24 classes/SIState.h
@@ -1,24 +0,0 @@
-//
-// SIState.h
-// Simon
-//
-// Created by Derek Clarkson on 5/08/12.
-// Copyright (c) 2012 Sensis. All rights reserved.
-//
-
-#import "SIStory.h"
-
-/**
- This data object tracks the state and data necessary to ensure that Simon knows what it has been instructed to do between runs and displays.
- */
-@interface SIState : NSObject
-
-/// @name Properties
-
-/// The search terms entered by the user in the UI.
-@property (nonatomic, retain) NSString *searchTerms;
-
-/// If not nil, then the UI should return to viewing the details of this story next time it is displayed.
-@property (nonatomic, retain) SIStory *viewStory;
-
-@end
View
16 classes/SIState.m
@@ -1,16 +0,0 @@
-//
-// SIState.m
-// Simon
-//
-// Created by Derek Clarkson on 5/08/12.
-// Copyright (c) 2012 Sensis. All rights reserved.
-//
-
-#import "SIState.h"
-
-@implementation SIState
-
-@synthesize searchTerms = _searchTerms;
-@synthesize viewStory = _viewStory;
-
-@end
View
77 classes/SIStoryListController.m
@@ -16,7 +16,8 @@
#import "SIAppBackpack.h"
@interface SIStoryListController (_private)
--(void) runSingleStory;
+-(void) runStories;
+-(void) backToStoryList;
-(NSArray *) sourcesToDisplay;
-(void) filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope;
@end
@@ -32,7 +33,7 @@ -(void) dealloc {
}
-(NSArray *) sourcesToDisplay {
- return searchController.isActive ? [SIAppBackpack backpack].storySources.selectedSources : [SIAppBackpack backpack].storySources.sources;
+ return [SIAppBackpack backpack].storySources.selectedSources;
}
#pragma mark - UIView methods
@@ -41,8 +42,6 @@ -(void) viewDidLoad {
DC_LOG(@"Loading report controller");
- SIState *state = [SIAppBackpack backpack].state;
-
// This should stop extra divider lines from appearing down the screen when
// there are not enough cells.
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 1)];
@@ -63,43 +62,33 @@ -(void) viewDidLoad {
searchController.searchResultsDelegate = self;
self.tableView.tableHeaderView = searchBar;
-
+
+ SIStorySources *storySources = [SIAppBackpack backpack].storySources;
+
// If search terms have been passed in then setup a search.
- if (![NSString isEmpty:state.searchTerms]) {
- DC_LOG(@"Initialising with search terms: %@", state.searchTerms);
+ NSString *searchTerms = storySources.selectionCriteria;
+ if (![NSString isEmpty:searchTerms]) {
+ DC_LOG(@"Initialising with search terms: %@", searchTerms);
[searchController setActive:YES animated:YES];
- searchBar.text = state.searchTerms;
+ searchBar.text = searchTerms;
}
[searchBar release];
// If we are being asked to show details then do so.
- if (state.viewStory != nil) {
+ if (storySources.currentIndexPath != nil) {
- DC_LOG(@"Showing details for story: %@", state.viewStory);
+ DC_LOG(@"Showing details for story at index path: %@", storySources.currentIndexPath);
- // Find the indexs we need
- __block NSUInteger storyIndex = NSNotFound;
- NSUInteger sourceIndex = [[self sourcesToDisplay] indexOfObjectPassingTest: ^BOOL (id srcObj, NSUInteger srcIdx, BOOL *srcStop) {
- storyIndex = [((SIStorySource *) srcObj).stories indexOfObjectPassingTest: ^BOOL (id obj, NSUInteger idx, BOOL *stop) {
- return [((SIStory *) obj).title isEqualToString:state.viewStory.title];
- }];
- return storyIndex != NSNotFound;
- }];
-
- // Build a path.
- NSIndexPath *storyIndexPath = [NSIndexPath indexPathForRow:storyIndex inSection:sourceIndex];
- DC_LOG(@"Index path of story: %@", storyIndexPath);
-
// And scroll to it.
if (searchController.isActive) {
DC_LOG(@"Selecting in search table view");
- [searchController.searchResultsTableView selectRowAtIndexPath:storyIndexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
- [searchController.searchResultsTableView.delegate tableView:searchController.searchResultsTableView didSelectRowAtIndexPath:storyIndexPath];
+ [searchController.searchResultsTableView selectRowAtIndexPath:storySources.currentIndexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
+ [searchController.searchResultsTableView.delegate tableView:searchController.searchResultsTableView didSelectRowAtIndexPath:storySources.currentIndexPath];
} else {
DC_LOG(@"Selecting in full table view");
- [self.tableView selectRowAtIndexPath:storyIndexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
- [self.tableView.delegate tableView:self.tableView didSelectRowAtIndexPath:storyIndexPath];
+ [self.tableView selectRowAtIndexPath:storySources.currentIndexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
+ [self.tableView.delegate tableView:self.tableView didSelectRowAtIndexPath:storySources.currentIndexPath];
}
}
@@ -170,6 +159,9 @@ -(NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInte
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+ // Track the selected story.
+ [SIAppBackpack backpack].storySources.currentIndexPath = indexPath;
+
// Load the controller.
detailsController = [[SIStoryDetailsController alloc] initWithStyle:UITableViewStylePlain];
@@ -181,20 +173,33 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
UIBarButtonItem *rerunButton = [[UIBarButtonItem alloc] initWithTitle:@"Run"
style:UIBarButtonItemStylePlain
target:self
- action:@selector(runSingleStory)];
-
+ action:@selector(runStories)];
detailsController.navigationItem.rightBarButtonItem = rerunButton;
[rerunButton release];
-
+
+ UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Back"
+ style:UIBarButtonItemStylePlain
+ target:self
+ action:@selector(backToStoryList)];
+ detailsController.navigationItem.leftBarButtonItem = backButton;
+ [backButton release];
+
DC_LOG(@"Loading details for story %@", detailsController.story.title);
DC_LOG(@"nav %@", super.navigationController);
[super.navigationController pushViewController:detailsController animated:YES];
}
-#pragma mark - Running stories
+#pragma mark - Button actions
+
+-(void) backToStoryList {
+ // Coming back so clear the selected story. This is the only time we do this.
+ DC_LOG(@"Clearing current story and returning to story list");
+ [SIAppBackpack backpack].storySources.currentIndexPath = nil;
+ [super.navigationController popViewControllerAnimated:YES];
+}
--(void) runSingleStory {
- DC_LOG(@"Rerunning story");
+-(void) runStories {
+ DC_LOG(@"Rerunning stories, run single story only indexPath: %@", [SIAppBackpack backpack].storySources.currentIndexPath);
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:SI_RUN_STORIES_NOTIFICATION object:self userInfo:nil]];
}
@@ -207,8 +212,6 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
DC_LOG(@"Filtering sources for text: %@", searchText);
- SIState *state = [SIAppBackpack backpack].state;
- state.searchTerms = searchText;
[[SIAppBackpack backpack].storySources selectWithPrefix:searchText];
}
@@ -218,9 +221,7 @@ - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
DC_LOG(@"Cancelling search function");
- SIState *state = [SIAppBackpack backpack].state;
- state.searchTerms = nil;
- [[SIAppBackpack backpack].runner.storySources selectAll];
+ [[SIAppBackpack backpack].storySources selectAll];
[self.searchDisplayController setActive:NO animated:YES];
[self.tableView reloadData];
}
View
58 classes/SIStoryRunner.m
@@ -13,11 +13,14 @@
#import "SIStory.h"
#import "SIStepMapping.h"
#import "NSString+Simon.h"
+#import <UIKit/UIKit.h>
-typedef void (^StoryBlock)(SIStorySource *, SIStory *);
+typedef void (^StoryBlock)(SIStorySource *, NSUInteger sourceIdx, BOOL *sourceStop, SIStory *, NSUInteger storyIdx, BOOL *storyStop);
@interface SIStoryRunner(_private)
-(void) executeOnSources:(NSArray *) sources block:(StoryBlock) block;
+-(void) runAllSelected;
+-(void) runCurrentStory;
@end
@implementation SIStoryRunner
@@ -30,27 +33,62 @@ -(void) run {
// First reset all the stories we are going to run.
DC_LOG(@"Starting run");
+ if (self.storySources.currentIndexPath == nil) {
+ [self runAllSelected];
+ } else {
+ [self runCurrentStory];
+ }
+
+ // Let the backpack know we have finished running stories.
+ [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:SI_RUN_FINISHED_NOTIFICATION object:nil]];
+}
+
+-(void) runAllSelected {
+ DC_LOG(@"Running all selected stories");
DC_LOG(@"Resetting stories");
- [self executeOnSources:_storySources.selectedSources block:^(SIStorySource *source, SIStory *story){
+ [self executeOnSources:self.storySources.selectedSources block:^(SIStorySource *source, NSUInteger sourceIdx, BOOL *sourceStop, SIStory *story, NSUInteger storyIdx, BOOL *storyStop){
[story reset];
}];
// Now execute them.
DC_LOG(@"Executing");
- [self executeOnSources:_storySources.selectedSources block:^(SIStorySource *source, SIStory *story){
+ [self executeOnSources:self.storySources.selectedSources block:^(SIStorySource *source, NSUInteger sourceIdx, BOOL *sourceStop, SIStory *story, NSUInteger storyIdx, BOOL *storyStop){
[story invokeWithSource:source];
}];
+}
+
+-(void) runCurrentStory {
+ NSIndexPath *indexPath = self.storySources.currentIndexPath;
+ DC_LOG(@"Running current story at indexPath: %@", indexPath);
+ DC_LOG(@"Resetting story");
+ [self executeOnSources:self.storySources.selectedSources block:^(SIStorySource *source, NSUInteger sourceIdx, BOOL *sourceStop, SIStory *story, NSUInteger storyIdx, BOOL *storyStop){
+ if (indexPath.section == sourceIdx && indexPath.row == storyIdx) {
+ [story reset];
+ *storyStop = YES;
+ *sourceStop = YES;
+ }
+ }];
+
+ // Now execute them.
+ DC_LOG(@"Executing");
+ [self executeOnSources:self.storySources.selectedSources block:^(SIStorySource *source, NSUInteger sourceIdx, BOOL *sourceStop, SIStory *story, NSUInteger storyIdx, BOOL *storyStop){
+ if (indexPath.section == sourceIdx && indexPath.row == storyIdx) {
+ [story invokeWithSource:source];
+ *storyStop = YES;
+ *sourceStop = YES;
+ }
+ }];
- // Let the backpack know we have finished running stories.
- [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:SI_RUN_FINISHED_NOTIFICATION object:nil]];
}
-(void) executeOnSources:(NSArray *) sources block:(StoryBlock) block {
- for (SIStorySource *source in sources) {
- for (SIStory *story in source.stories) {
- block(source, story);
- }
- }
+ [sources enumerateObjectsUsingBlock:^(id sourceObj, NSUInteger sourceIdx, BOOL *sourceStop) {
+ SIStorySource *source = (SIStorySource *) sourceObj;
+ [source.stories enumerateObjectsUsingBlock:^(id storyObj, NSUInteger storyIdx, BOOL *storyStop) {
+ SIStory *story = (SIStory *) storyObj;
+ block(source, sourceIdx, sourceStop, story, storyIdx, storyStop);
+ }];
+ }];
}
@end
View
11 classes/SIStorySources.h
@@ -20,6 +20,12 @@
/// Only the sources which contain selected stories.
@property (nonatomic, readonly) NSArray *selectedSources;
+/// Returns the text used as a criteria for selecting stories.
+@property (nonatomic, readonly) NSString *selectionCriteria;
+
+/// If not nil, indicates the index path to the story for individual viewing. Usually this is set and retrieved by the UI. Setting it does not effect selection. This is mainly a place to store this value between displays.
+@property (nonatomic, retain) NSIndexPath *currentIndexPath;
+
/// @name Tasks
/**
@@ -36,10 +42,7 @@
*/
-(void) selectWithPrefix:(NSString *) prefix;
-/// Selects all stories and therefore all sources.
+/// Selects all stories and therefore all sources. This automatically clears any search criteria.
-(void) selectAll;
-// Deselects all stories.
--(void) selectNone;
-
@end
View
16 classes/SIStorySources.m
@@ -20,10 +20,14 @@ @implementation SIStorySources
@synthesize sources = _sources;
@synthesize selectedSources = _selectedSources;
+@synthesize selectionCriteria = _selectionCriteria;
+@synthesize currentIndexPath = _currentIndexPath;
-(void) dealloc {
+ self.currentIndexPath = nil;
DC_DEALLOC(_sources);
DC_DEALLOC(_selectedSources);
+ DC_DEALLOC(_selectionCriteria);
[super dealloc];
}
@@ -58,10 +62,11 @@ -(void) selectWithPrefix:(NSString *) prefix {
}
}];
- // Clear any old cached data.
DC_DEALLOC(_selectedSources);
_selectedSources = [[_sources objectsAtIndexes:selectedIndexes] retain];
DC_DEALLOC(selectedIndexes);
+ DC_DEALLOC(_selectionCriteria);
+ _selectionCriteria = [prefix retain];
}
-(void) selectAll {
@@ -70,14 +75,7 @@ -(void) selectAll {
[(SIStorySource *) obj selectAll];
}];
_selectedSources = [[NSArray arrayWithArray:_sources] retain];
-}
-
--(void) selectNone {
- DC_DEALLOC(_selectedSources);
- [_sources enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- [(SIStorySource *) obj selectNone];
- }];
- _selectedSources = [[NSArray alloc] init];
+ _selectionCriteria = nil;
}
@end
View
1 classes/SIUIReportManager.m
@@ -11,7 +11,6 @@
#import <UIKit/UIKit.h>
#import <dUsefulStuff/DCCommon.h>
#import "NSObject+Simon.h"
-#import "SIState.h"
typedef void (^completion)();
View
32 tests/NSObject+SimonTests.m
@@ -0,0 +1,32 @@
+//
+// NSObject+SimonTests.m
+// Simon
+//
+// Created by Derek Clarkson on 14/08/12.
+// Copyright (c) 2012. All rights reserved.
+//
+
+#import <GHUnitIOS/GHUnit.h>
+#import <Simon/NSObject+Simon.h>
+@interface NSObject_SimonTests : GHTestCase
+
+@end
+
+@implementation NSObject_SimonTests
+
+-(void) testExecuteOnMainThreadCatchesExceptions {
+ BOOL caught = NO;
+ @try {
+ [self executeBlockOnMainThread:^() {
+ @throw [NSException exceptionWithName:@"Fred" reason:@"A reason" userInfo:nil];
+ }];
+ }
+ @catch (NSException *exception) {
+ // Good.
+ caught = YES;
+ GHAssertEqualStrings(exception.name, @"Fred", nil);
+ }
+ GHAssertTrue(caught, nil);
+}
+
+@end
View
72 tests/SIStoryRunnerTests.m
@@ -16,6 +16,13 @@ @interface SIStoryRunnerTests : GHTestCase {
BOOL startSent;
BOOL endSent;
SIStoryRunner *runner;
+ SIStorySources *sources;
+ SIStorySource *source1;
+ SIStorySource *source2;
+ id mockStory1;
+ id mockStory2;
+ id mockStory3;
+
}
-(void) runStart:(NSNotification *) notification;
-(void) runEnd:(NSNotification *) notification;
@@ -34,35 +41,76 @@ -(void) setUp {
selector:@selector(runEnd:)
name:SI_RUN_FINISHED_NOTIFICATION
object:nil];
+
+ sources = [[SIStorySources alloc] init];
+
+ source1 = [[SIStorySource alloc] init];
+ [sources addSource:source1];
+
+ source2 = [[SIStorySource alloc] init];
+ [sources addSource:source2];
+
+ mockStory1 = [OCMockObject mockForClass:[SIStory class]];
+ [source1 addStory:mockStory1];
+
+ mockStory2 = [OCMockObject mockForClass:[SIStory class]];
+ [source2 addStory:mockStory2];
+
+ mockStory3 = [OCMockObject mockForClass:[SIStory class]];
+ [source2 addStory:mockStory3];
+
runner = [[SIStoryRunner alloc] init];
+ runner.storySources = sources;
}
-(void) tearDown {
+ [mockStory1 verify];
+ [mockStory2 verify];
+ [mockStory3 verify];
DC_DEALLOC(runner);
+ DC_DEALLOC(sources);
+ DC_DEALLOC(source1);
+ DC_DEALLOC(source2);
+ DC_DEALLOC(mockStory1);
+ DC_DEALLOC(mockStory2);
+ DC_DEALLOC(mockStory3);
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
--(void) testExecuting {
-
- SIStorySources *sources = [[[SIStorySources alloc] init] autorelease];
- SIStorySource *source = [[[SIStorySource alloc] init] autorelease];
- [sources addSource:source];
- id mockStory = [OCMockObject mockForClass:[SIStory class]];
- [[mockStory expect] reset];
+-(void) testExecutingAllStories {
+
+ [[mockStory1 expect] reset];
+ [[mockStory2 expect] reset];
+ [[mockStory3 expect] reset];
BOOL yes = YES;
- [[[mockStory expect] andReturnValue:OCMOCK_VALUE(yes)] invokeWithSource:source];
- [source addStory:mockStory];
- runner.storySources = sources;
+ [[[mockStory1 expect] andReturnValue:OCMOCK_VALUE(yes)] invokeWithSource:source1];
+ [[[mockStory2 expect] andReturnValue:OCMOCK_VALUE(yes)] invokeWithSource:source2];
+ [[[mockStory3 expect] andReturnValue:OCMOCK_VALUE(yes)] invokeWithSource:source2];
[runner run];
- [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
+ [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
+ [NSThread sleepForTimeInterval:0.2];
- [mockStory verify];
GHAssertTrue(startSent, nil);
GHAssertTrue(endSent, nil);
}
+-(void) testRunCurrentStoryOnly {
+ [[mockStory2 expect] reset];
+ BOOL yes = YES;
+ [[[mockStory2 expect] andReturnValue:OCMOCK_VALUE(yes)] invokeWithSource:source2];
+
+ NSIndexPath *currentStory = [NSIndexPath indexPathForRow:0 inSection:1];
+ sources.currentIndexPath = currentStory;
+ [runner run];
+
+ [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
+ [NSThread sleepForTimeInterval:0.2];
+
+ GHAssertTrue(startSent, nil);
+ GHAssertTrue(endSent, nil);
+}
-(void) runStart:(NSNotification *) notification {
startSent = YES;
View
13 tests/SIStorySourcesTests.m
@@ -72,10 +72,15 @@ -(void) testSelectAll {
GHAssertEquals([sourcesList count], (NSUInteger) 2, nil);
}
--(void) testSelectNone {
- [sources selectNone];
- NSArray *sourcesList = sources.selectedSources;
- GHAssertEquals([sourcesList count], (NSUInteger) 0, nil);
+-(void) testSelectAllClearsCriteria {
+ [sources selectWithPrefix:@"ab"];
+ [sources selectAll];
+ GHAssertNil(sources.selectionCriteria, nil);
+}
+
+-(void) testSelectingStoriesReturnsSelectionCriteria {
+ [sources selectWithPrefix:@"ab"];
+ GHAssertEquals(sources.selectionCriteria, @"ab", nil);
}
@end

0 comments on commit 16b4953

Please sign in to comment.
Something went wrong with that request. Please try again.