jenkins-bot has submitted this change and it was merged.

Change subject: saved & history list error handling & testing
......................................................................


saved & history list error handling & testing

- attempt to recover from bad history & saved list entries
by removing them

- test handling of add/remove invalid entries & nil

Bug: T103737
Change-Id: I88e6360bfe58dc89a3a53fea2cb43a05dac7a20a
---
M MediaWikiKit/MediaWikiKit/MWKDataObject.h
M MediaWikiKit/MediaWikiKit/MWKDataObject.m
M MediaWikiKit/MediaWikiKit/MWKHistoryEntry.m
M MediaWikiKit/MediaWikiKit/MWKHistoryList.m
M MediaWikiKit/MediaWikiKit/MWKSavedPageEntry.h
M MediaWikiKit/MediaWikiKit/MWKSavedPageEntry.m
M MediaWikiKit/MediaWikiKit/MWKSavedPageList.m
M MediaWikiKit/MediaWikiKit/MWKSiteDataObject.h
M MediaWikiKit/MediaWikiKit/MWKSiteDataObject.m
M MediaWikiKit/MediaWikiKit/MWKTitle.m
A MediaWikiKit/MediaWikiKitTests/MWKHistoryListCorruptDataTests.m
M MediaWikiKit/MediaWikiKitTests/MWKImageListTests.m
A MediaWikiKit/MediaWikiKitTests/MWKSavedPageListCorruptDataTests.m
M Wikipedia.xcodeproj/project.pbxproj
M Wikipedia/View Controllers/WebView/WebViewController.m
M WikipediaUnitTests/MWKSection+WMFSharingTests.m
M WikipediaUnitTests/MWKSectionListTests.m
M WikipediaUnitTests/Utilities/MWKImage+AssociationTestUtils.m
M WikipediaUnitTests/WMFImageInfoControllerTests.m
19 files changed, 299 insertions(+), 43 deletions(-)

Approvals:
  Fjalapeno: Looks good to me, approved
  Mhurd: Looks good to me, but someone else must approve
  jenkins-bot: Verified



diff --git a/MediaWikiKit/MediaWikiKit/MWKDataObject.h 
b/MediaWikiKit/MediaWikiKit/MWKDataObject.h
index c795730..d0acf97 100644
--- a/MediaWikiKit/MediaWikiKit/MWKDataObject.h
+++ b/MediaWikiKit/MediaWikiKit/MWKDataObject.h
@@ -14,6 +14,7 @@
 
 - (NSString*)optionalString:(NSString*)key dict:(NSDictionary*)dict;
 - (NSString*)requiredString:(NSString*)key dict:(NSDictionary*)dict;
+- (NSString*)requiredString:(NSString*)key dict:(NSDictionary*)dict 
allowEmpty:(BOOL)allowEmpty;
 
 - (NSNumber*)optionalNumber:(NSString*)key dict:(NSDictionary*)dict;
 - (NSNumber*)requiredNumber:(NSString*)key dict:(NSDictionary*)dict;
diff --git a/MediaWikiKit/MediaWikiKit/MWKDataObject.m 
b/MediaWikiKit/MediaWikiKit/MWKDataObject.m
index a3e348c..d29424d 100644
--- a/MediaWikiKit/MediaWikiKit/MWKDataObject.m
+++ b/MediaWikiKit/MediaWikiKit/MWKDataObject.m
@@ -34,8 +34,12 @@
 }
 
 - (NSString*)requiredString:(NSString*)key dict:(NSDictionary*)dict {
+    return [self requiredString:key dict:dict allowEmpty:YES];
+}
+
+- (NSString*)requiredString:(NSString*)key dict:(NSDictionary*)dict 
allowEmpty:(BOOL)allowEmpty {
     NSString* str = [self optionalString:key dict:dict];
-    if (str == nil) {
+    if (str == nil || (str.length == 0 && !allowEmpty)) {
         @throw [NSException exceptionWithName:@"MWKDataObjectException"
                                        reason:@"expected string, got nothing"
                                      userInfo:@{@"key": key}];
diff --git a/MediaWikiKit/MediaWikiKit/MWKHistoryEntry.m 
b/MediaWikiKit/MediaWikiKit/MWKHistoryEntry.m
index 15e7699..9688f1a 100644
--- a/MediaWikiKit/MediaWikiKit/MWKHistoryEntry.m
+++ b/MediaWikiKit/MediaWikiKit/MWKHistoryEntry.m
@@ -36,7 +36,7 @@
 
     self = [self initWithSite:[MWKSite siteWithDomain:domain 
language:language]];
     if (self) {
-        self.title           = [self requiredTitle:@"title" dict:dict];
+        self.title           = [self requiredTitle:@"title" dict:dict 
allowEmpty:NO];
         self.date            = [self requiredDate:@"date" dict:dict];
         self.discoveryMethod = [MWKHistoryEntry discoveryMethodForString:[self 
requiredString:@"discoveryMethod" dict:dict]];
         self.scrollPosition  = [[self requiredNumber:@"scrollPosition" 
dict:dict] intValue];
@@ -74,10 +74,24 @@
     [dict wmf_maybeSetObject:[self iso8601DateString:self.date] 
forKey:@"date"];
     [dict wmf_maybeSetObject:[MWKHistoryEntry 
stringForDiscoveryMethod:self.discoveryMethod] forKey:@"discoveryMethod"];
     [dict wmf_maybeSetObject:@(self.scrollPosition) forKey:@"scrollPosition"];
-    
+
     return [NSDictionary dictionaryWithDictionary:dict];
 }
 
+- (NSString*)description {
+    return [NSString stringWithFormat:@"%@: {\n"
+            "\ttitle: %@,\n"
+            "\tdate: %@,\n"
+            "\tdiscoveryMethod: %@,\n"
+            "\tscrollPosition: %d\n"
+            "}",
+            [super description],
+            self.title,
+            self.date,
+            [MWKHistoryEntry stringForDiscoveryMethod:self.discoveryMethod],
+            self.scrollPosition];
+}
+
 + 
(NSString*)stringForDiscoveryMethod:(MWKHistoryDiscoveryMethod)discoveryMethod {
     switch (discoveryMethod) {
         case MWKHistoryDiscoveryMethodSearch:
diff --git a/MediaWikiKit/MediaWikiKit/MWKHistoryList.m 
b/MediaWikiKit/MediaWikiKit/MWKHistoryList.m
index 10a5e79..24bf69d 100644
--- a/MediaWikiKit/MediaWikiKit/MWKHistoryList.m
+++ b/MediaWikiKit/MediaWikiKit/MWKHistoryList.m
@@ -111,9 +111,13 @@
         if (arr) {
             self.entries = [[NSMutableArray alloc] init];
             for (NSDictionary* entryDict in arr) {
-                MWKHistoryEntry* entry = [[MWKHistoryEntry alloc] 
initWithDict:entryDict];
-                [self.entries addObject:entry];
-                self.entriesByTitle[entry.title] = entry;
+                @try {
+                    MWKHistoryEntry* entry = [[MWKHistoryEntry alloc] 
initWithDict:entryDict];
+                    [self.entries addObject:entry];
+                    self.entriesByTitle[entry.title] = entry;
+                } @catch (NSException* e) {
+                    NSLog(@"Encountered exception reading history data %@: 
%@", e, entryDict);
+                }
             }
         }
         self.dirty = NO;
diff --git a/MediaWikiKit/MediaWikiKit/MWKSavedPageEntry.h 
b/MediaWikiKit/MediaWikiKit/MWKSavedPageEntry.h
index ab888f4..90dcd7a 100644
--- a/MediaWikiKit/MediaWikiKit/MWKSavedPageEntry.h
+++ b/MediaWikiKit/MediaWikiKit/MWKSavedPageEntry.h
@@ -11,7 +11,6 @@
 @interface MWKSavedPageEntry : MWKSiteDataObject
 
 @property (readonly, strong, nonatomic) MWKTitle* title;
-@property (readwrite, strong, nonatomic) NSDate* date;
 
 - (instancetype)initWithTitle:(MWKTitle*)title;
 - (instancetype)initWithDict:(NSDictionary*)dict;
diff --git a/MediaWikiKit/MediaWikiKit/MWKSavedPageEntry.m 
b/MediaWikiKit/MediaWikiKit/MWKSavedPageEntry.m
index c9f4a67..9bfa6e4 100644
--- a/MediaWikiKit/MediaWikiKit/MWKSavedPageEntry.m
+++ b/MediaWikiKit/MediaWikiKit/MWKSavedPageEntry.m
@@ -7,6 +7,7 @@
 //
 
 #import "MediaWikiKit.h"
+#import "NSMutableDictionary+WMFMaybeSet.h"
 
 @interface MWKSavedPageEntry ()
 
@@ -16,10 +17,10 @@
 @implementation MWKSavedPageEntry
 
 - (instancetype)initWithTitle:(MWKTitle*)title {
+    NSParameterAssert(title);
     self = [self initWithSite:title.site];
     if (self) {
         self.title = title;
-        self.date  = [[NSDate alloc] init];
     }
     return self;
 }
@@ -31,7 +32,7 @@
 
     self = [self initWithSite:[MWKSite siteWithDomain:domain 
language:language]];
     if (self) {
-        self.title = [self requiredTitle:@"title" dict:dict];
+        self.title = [self requiredTitle:@"title" dict:dict allowEmpty:NO];
     }
     return self;
 }
@@ -39,9 +40,9 @@
 - (id)dataExport {
     NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
 
-    dict[@"domain"]   = self.site.domain;
-    dict[@"language"] = self.site.language;
-    dict[@"title"]    = self.title.text;
+    [dict wmf_maybeSetObject:self.site.domain forKey:@"domain"];
+    [dict wmf_maybeSetObject:self.site.language forKey:@"language"];
+    [dict wmf_maybeSetObject:self.title.text forKey:@"title"];
 
     return [NSDictionary dictionaryWithDictionary:dict];
 }
diff --git a/MediaWikiKit/MediaWikiKit/MWKSavedPageList.m 
b/MediaWikiKit/MediaWikiKit/MWKSavedPageList.m
index 711b142..5aeafef 100644
--- a/MediaWikiKit/MediaWikiKit/MWKSavedPageList.m
+++ b/MediaWikiKit/MediaWikiKit/MWKSavedPageList.m
@@ -27,13 +27,15 @@
 }
 
 - (MWKSavedPageEntry*)entryForTitle:(MWKTitle*)title {
+    if (!title) {
+        return nil;
+    }
     MWKSavedPageEntry* entry = self.entriesByTitle[title];
     return entry;
 }
 
 - (BOOL)isSaved:(MWKTitle*)title {
-    MWKSavedPageEntry* entry = [self entryForTitle:title];
-    return (entry != nil);
+    return ([self entryForTitle:title] != nil);
 }
 
 - (NSUInteger)indexForEntry:(MWKHistoryEntry*)entry {
@@ -43,7 +45,9 @@
 #pragma mark - update methods
 
 - (void)addEntry:(MWKSavedPageEntry*)entry {
-    if ([self entryForTitle:entry.title] == nil) {
+    if (entry
+        && ![self entryForTitle:entry.title]
+        && entry.title.text.length > 0) {
         // there can be only one
         [self.entries insertObject:entry atIndex:0];
         self.entriesByTitle[entry.title] = entry;
@@ -52,6 +56,9 @@
 }
 
 - (void)removeEntry:(MWKSavedPageEntry*)entry {
+    if (entry.title.text.length == 0) {
+        return;
+    }
     [self.entries removeObject:entry];
     [self.entriesByTitle removeObjectForKey:entry.title];
     self.dirty = YES;
@@ -79,9 +86,13 @@
     if (self) {
         NSArray* array = dict[@"entries"];
         for (NSDictionary* entryDict in array) {
-            MWKSavedPageEntry* entry = [[MWKSavedPageEntry alloc] 
initWithDict:entryDict];
-            [self.entries addObject:entry];
-            self.entriesByTitle[entry.title] = entry;
+            @try {
+                MWKSavedPageEntry* entry = [[MWKSavedPageEntry alloc] 
initWithDict:entryDict];
+                [self.entries addObject:entry];
+                self.entriesByTitle[entry.title] = entry;
+            } @catch (NSException* e) {
+                NSLog(@"Encountered exception while reading entry %@: %@", e, 
entryDict);
+            }
         }
         self.dirty = NO;
     }
diff --git a/MediaWikiKit/MediaWikiKit/MWKSiteDataObject.h 
b/MediaWikiKit/MediaWikiKit/MWKSiteDataObject.h
index bd9c367..55d4854 100644
--- a/MediaWikiKit/MediaWikiKit/MWKSiteDataObject.h
+++ b/MediaWikiKit/MediaWikiKit/MWKSiteDataObject.h
@@ -20,6 +20,7 @@
 
 - (MWKTitle*)optionalTitle:(NSString*)key dict:(NSDictionary*)dict;
 - (MWKTitle*)requiredTitle:(NSString*)key dict:(NSDictionary*)dict;
+- (MWKTitle*)requiredTitle:(NSString*)key dict:(NSDictionary*)dict 
allowEmpty:(BOOL)allowEmpty;
 
 - (MWKUser*)optionalUser:(NSString*)key dict:(NSDictionary*)dict;
 - (MWKUser*)requiredUser:(NSString*)key dict:(NSDictionary*)dict;
diff --git a/MediaWikiKit/MediaWikiKit/MWKSiteDataObject.m 
b/MediaWikiKit/MediaWikiKit/MWKSiteDataObject.m
index fc3e366..2b7ee0c 100644
--- a/MediaWikiKit/MediaWikiKit/MWKSiteDataObject.m
+++ b/MediaWikiKit/MediaWikiKit/MWKSiteDataObject.m
@@ -41,7 +41,11 @@
 }
 
 - (MWKTitle*)requiredTitle:(NSString*)key dict:(NSDictionary*)dict {
-    NSString* str = [self requiredString:key dict:dict];
+    return [self requiredTitle:key dict:dict allowEmpty:YES];
+}
+
+- (MWKTitle*)requiredTitle:(NSString*)key dict:(NSDictionary*)dict 
allowEmpty:(BOOL)allowEmpty {
+    NSString* str = [self requiredString:key dict:dict allowEmpty:allowEmpty];
     return [self.site titleWithString:str];
 }
 
diff --git a/MediaWikiKit/MediaWikiKit/MWKTitle.m 
b/MediaWikiKit/MediaWikiKit/MWKTitle.m
index 2d4cef1..898b31c 100644
--- a/MediaWikiKit/MediaWikiKit/MWKTitle.m
+++ b/MediaWikiKit/MediaWikiKit/MWKTitle.m
@@ -29,7 +29,7 @@
     NSParameterAssert(site);
     self = [super init];
     if (self) {
-        self.site     = site;
+        self.site = site;
         // HAX: fall back to empty strings in case of nil text to handle API 
edge cases & prevent crashes
         self.text     = text.length ? text : @"";
         self.fragment = fragment;
diff --git a/MediaWikiKit/MediaWikiKitTests/MWKHistoryListCorruptDataTests.m 
b/MediaWikiKit/MediaWikiKitTests/MWKHistoryListCorruptDataTests.m
new file mode 100644
index 0000000..0e09d76
--- /dev/null
+++ b/MediaWikiKit/MediaWikiKitTests/MWKHistoryListCorruptDataTests.m
@@ -0,0 +1,110 @@
+//
+//  MWKHistoryListCorruptDataTests.m
+//  Wikipedia
+//
+//  Created by Brian Gerstle on 6/29/15.
+//  Copyright (c) 2015 Wikimedia Foundation. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <XCTest/XCTest.h>
+#import "MWKHistoryList.h"
+#import "MWKHistoryEntry.h"
+
+#define HC_SHORTHAND 1
+#import <OCHamcrest/OCHamcrest.h>
+
+@interface MWKHistoryListCorruptDataTests : XCTestCase
+@property (strong, nonatomic) MWKHistoryList* historyList;
+
+@end
+
+@implementation MWKHistoryListCorruptDataTests
+
+- (void)testPrunesEntriesWithEmptyOrAbsentTitles {
+    MWKHistoryEntry* validEntry =
+        [[MWKHistoryEntry alloc] initWithTitle:[[MWKSite 
siteWithCurrentLocale] titleWithString:@"Foo"]
+                               discoveryMethod :MWKHistoryDiscoveryMethodLink];
+
+    NSDictionary* validEntryExport = [validEntry dataExport];
+
+    NSDictionary* absentTitleExport = ^{
+        NSMutableDictionary* d = [validEntryExport mutableCopy];
+        [d removeObjectForKey:@"title"];
+        return [d copy];
+    } ();
+
+    NSDictionary* emptyTitleExport = ^{
+        NSMutableDictionary* d = [validEntryExport mutableCopy];
+        d[@"title"] = @"";
+        return [d copy];
+    } ();
+
+    MWKHistoryList* list;
+    XCTAssertNoThrow((list = [[MWKHistoryList alloc] initWithDict:@{
+                                  @"entries": @[validEntryExport, 
absentTitleExport, emptyTitleExport]
+                              }]));
+
+    assertThat(@(list.length), is(@1));
+    // TODO: change to comparison when date equality is fixed...
+    assertThat([[list mostRecentEntry] dataExport], is(equalTo([validEntry 
dataExport])));
+}
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
+
+- (void)testIgnoresInvalidEntries {
+    MWKHistoryList* list = [MWKHistoryList new];
+
+    MWKHistoryEntry* validEntry =
+        [[MWKHistoryEntry alloc] initWithTitle:[[MWKSite 
siteWithCurrentLocale] titleWithString:@"Foo"]
+                               discoveryMethod :MWKHistoryDiscoveryMethodLink];
+
+    [list addEntry:validEntry];
+
+    void (^ assertUnaltered)() = ^{
+        assertThat(@(list.length), is(@1));
+        assertThat(list.mostRecentEntry, is(validEntry));
+    };
+
+    MWKHistoryEntry* nilEntry =
+        [[MWKHistoryEntry alloc] initWithTitle:[[MWKSite 
siteWithCurrentLocale] titleWithString:nil]
+                               discoveryMethod :MWKHistoryDiscoveryMethodLink];
+
+    MWKHistoryEntry* emptyEntry =
+        [[MWKHistoryEntry alloc] initWithTitle:[[MWKSite 
siteWithCurrentLocale] titleWithString:@""]
+                               discoveryMethod :MWKHistoryDiscoveryMethodLink];
+
+    NSArray* invalidEntries = @[nilEntry, emptyEntry];
+
+    for (MWKHistoryEntry* invalidEntry in invalidEntries) {
+        XCTAssertNoThrow(([list addEntry:invalidEntry]));
+        assertUnaltered();
+        XCTAssertNoThrow(([list removeEntry:invalidEntry]));
+        assertUnaltered();
+    }
+}
+
+#pragma clang diagnostic pop
+
+- (void)testIgnoresNil {
+    MWKHistoryList* list = [MWKHistoryList new];
+
+    MWKHistoryEntry* validEntry =
+        [[MWKHistoryEntry alloc] initWithTitle:[[MWKSite 
siteWithCurrentLocale] titleWithString:@"Foo"]
+                               discoveryMethod :MWKHistoryDiscoveryMethodLink];
+
+    [list addEntry:validEntry];
+
+    void (^ assertUnaltered)() = ^{
+        assertThat(@(list.length), is(@1));
+        assertThat(list.mostRecentEntry, is(validEntry));
+    };
+
+    XCTAssertNoThrow(([list addEntry:nil]));
+    assertUnaltered();
+    XCTAssertNoThrow(([list removeEntry:nil]));
+    assertUnaltered();
+}
+
+@end
diff --git a/MediaWikiKit/MediaWikiKitTests/MWKImageListTests.m 
b/MediaWikiKit/MediaWikiKitTests/MWKImageListTests.m
index b9253dc..21637f1 100644
--- a/MediaWikiKit/MediaWikiKitTests/MWKImageListTests.m
+++ b/MediaWikiKit/MediaWikiKitTests/MWKImageListTests.m
@@ -42,7 +42,7 @@
     MWKDataStore* tmpDataStore = [[MWKDataStore alloc] 
initWithBasePath:self.tempDataStoreDir];
 
     // create article w/ mock section to prevent crashing due to image import 
side effects
-    MWKTitle* title = [[MWKSite siteWithCurrentLocale] titleWithString:@"foo"];
+    MWKTitle* title     = [[MWKSite siteWithCurrentLocale] 
titleWithString:@"foo"];
     MWKArticle* article = [[MWKArticle alloc] initWithTitle:title 
dataStore:tmpDataStore];
     [article.sections setSections:[NSMutableArray 
arrayWithObject:mock([MWKSection class])]];
 
diff --git a/MediaWikiKit/MediaWikiKitTests/MWKSavedPageListCorruptDataTests.m 
b/MediaWikiKit/MediaWikiKitTests/MWKSavedPageListCorruptDataTests.m
new file mode 100644
index 0000000..1989c27
--- /dev/null
+++ b/MediaWikiKit/MediaWikiKitTests/MWKSavedPageListCorruptDataTests.m
@@ -0,0 +1,106 @@
+//
+//  MWKSavedPageListCorruptDataTests.m
+//  Wikipedia
+//
+//  Created by Brian Gerstle on 6/29/15.
+//  Copyright (c) 2015 Wikimedia Foundation. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <XCTest/XCTest.h>
+#import "MWKSavedPageList.h"
+#import "MWKSavedPageEntry.h"
+
+
+#define HC_SHORTHAND 1
+#import <OCHamcrest/OCHamcrest.h>
+
+@interface MWKSavedPageListCorruptDataTests : XCTestCase
+
+@end
+
+@implementation MWKSavedPageListCorruptDataTests
+
+- (void)testPrunesEntriesWithEmptyOrAbsentTitles {
+    MWKSavedPageEntry* validEntry =
+        [[MWKSavedPageEntry alloc] initWithTitle:
+         [[MWKSite siteWithCurrentLocale] titleWithString:@"Foo"]];
+
+    NSDictionary* validEntryExport = [validEntry dataExport];
+
+    NSDictionary* absentTitleExport = ^{
+        NSMutableDictionary* d = [validEntryExport mutableCopy];
+        [d removeObjectForKey:@"title"];
+        return [d copy];
+    } ();
+
+    NSDictionary* emptyTitleExport = ^{
+        NSMutableDictionary* d = [validEntryExport mutableCopy];
+        d[@"title"] = @"";
+        return [d copy];
+    } ();
+
+    MWKSavedPageList* list;
+    XCTAssertNoThrow((list = [[MWKSavedPageList alloc] initWithDict:@{
+                                  @"entries": @[validEntryExport, 
absentTitleExport, emptyTitleExport]
+                              }]));
+
+    assertThat(@(list.length), is(@1));
+    // TODO: change to comparison when date equality is fixed...
+    assertThat([[list entryAtIndex:0] dataExport], is(equalTo([validEntry 
dataExport])));
+}
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
+
+- (void)testIgnoresInvalidEntries {
+    MWKSavedPageList* list = [MWKSavedPageList new];
+
+    MWKSavedPageEntry* validEntry =
+        [[MWKSavedPageEntry alloc] initWithTitle:[[MWKSite 
siteWithCurrentLocale] titleWithString:@"Foo"]];
+
+    [list addEntry:validEntry];
+
+    void (^ assertUnaltered)() = ^{
+        assertThat(@(list.length), is(@1));
+        assertThat([list entryAtIndex:0], is(validEntry));
+    };
+
+    MWKSavedPageEntry* nilEntry =
+        [[MWKSavedPageEntry alloc] initWithTitle:[[MWKSite 
siteWithCurrentLocale] titleWithString:nil]];
+
+    MWKSavedPageEntry* emptyEntry =
+        [[MWKSavedPageEntry alloc] initWithTitle:[[MWKSite 
siteWithCurrentLocale] titleWithString:@""]];
+
+    NSArray* invalidEntries = @[nilEntry, emptyEntry];
+
+    for (MWKSavedPageEntry* invalidEntry in invalidEntries) {
+        XCTAssertNoThrow(([list addEntry:invalidEntry]));
+        assertUnaltered();
+        XCTAssertNoThrow(([list removeEntry:invalidEntry]));
+        assertUnaltered();
+    }
+}
+
+#pragma clang diagnostic pop
+
+- (void)testIgnoresNil {
+    MWKSavedPageList* list = [MWKSavedPageList new];
+
+    MWKSavedPageEntry* validEntry =
+        [[MWKSavedPageEntry alloc] initWithTitle:[[MWKSite 
siteWithCurrentLocale] titleWithString:@"Foo"]];
+
+    [list addEntry:validEntry];
+
+    void (^ assertUnaltered)() = ^{
+        assertThat(@(list.length), is(@1));
+        assertThat([list entryAtIndex:0], is(validEntry));
+    };
+
+    XCTAssertNoThrow(([list addEntry:nil]));
+    assertUnaltered();
+    XCTAssertNoThrow(([list removeEntry:nil]));
+    assertUnaltered();
+}
+
+@end
diff --git a/Wikipedia.xcodeproj/project.pbxproj 
b/Wikipedia.xcodeproj/project.pbxproj
index 04c4794..5e52831 100644
--- a/Wikipedia.xcodeproj/project.pbxproj
+++ b/Wikipedia.xcodeproj/project.pbxproj
@@ -330,6 +330,8 @@
                BCEC77921AC9B6AD00D9DDA5 /* 
HCIsCollectionContainingInAnyOrder+WMFCollectionMatcherUtils.m in Sources */ = 
{isa = PBXBuildFile; fileRef = BCEC77911AC9B6AD00D9DDA5 /* 
HCIsCollectionContainingInAnyOrder+WMFCollectionMatcherUtils.m */; };
                BCEC77951AC9C74700D9DDA5 /* NSArray+WMFShuffle.m in Sources */ 
= {isa = PBXBuildFile; fileRef = BCEC77941AC9C74700D9DDA5 /* 
NSArray+WMFShuffle.m */; };
                BCF012331AD2FA38008D3675 /* assets in Resources */ = {isa = 
PBXBuildFile; fileRef = BCF012321AD2FA38008D3675 /* assets */; };
+               BCFE026A1B41ABB5003752B7 /* MWKHistoryListCorruptDataTests.m in 
Sources */ = {isa = PBXBuildFile; fileRef = BCFE02691B41ABB5003752B7 /* 
MWKHistoryListCorruptDataTests.m */; };
+               BCFE026F1B41B482003752B7 /* MWKSavedPageListCorruptDataTests.m 
in Sources */ = {isa = PBXBuildFile; fileRef = BCFE026E1B41B482003752B7 /* 
MWKSavedPageListCorruptDataTests.m */; };
                C42D947E1A937DAC00A4871A /* SavedArticlesFetcher.m in Sources 
*/ = {isa = PBXBuildFile; fileRef = C42D947D1A937DAC00A4871A /* 
SavedArticlesFetcher.m */; };
                C42D94861A937DE000A4871A /* WMFBorderButton.m in Sources */ = 
{isa = PBXBuildFile; fileRef = C42D94831A937DE000A4871A /* WMFBorderButton.m 
*/; };
                C42D94871A937DE000A4871A /* WMFProgressLineView.m in Sources */ 
= {isa = PBXBuildFile; fileRef = C42D94851A937DE000A4871A /* 
WMFProgressLineView.m */; };
@@ -975,6 +977,8 @@
                BCEC77931AC9C74700D9DDA5 /* NSArray+WMFShuffle.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
"NSArray+WMFShuffle.h"; sourceTree = "<group>"; };
                BCEC77941AC9C74700D9DDA5 /* NSArray+WMFShuffle.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= "NSArray+WMFShuffle.m"; sourceTree = "<group>"; };
                BCF012321AD2FA38008D3675 /* assets */ = {isa = 
PBXFileReference; lastKnownFileType = folder; name = assets; path = 
../Wikipedia/assets; sourceTree = "<group>"; };
+               BCFE02691B41ABB5003752B7 /* MWKHistoryListCorruptDataTests.m */ 
= {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.objc; path = MWKHistoryListCorruptDataTests.m; sourceTree = 
"<group>"; };
+               BCFE026E1B41B482003752B7 /* MWKSavedPageListCorruptDataTests.m 
*/ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.objc; path = MWKSavedPageListCorruptDataTests.m; sourceTree = 
"<group>"; };
                C42D947C1A937DAC00A4871A /* SavedArticlesFetcher.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
SavedArticlesFetcher.h; sourceTree = "<group>"; };
                C42D947D1A937DAC00A4871A /* SavedArticlesFetcher.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= SavedArticlesFetcher.m; sourceTree = "<group>"; };
                C42D94821A937DE000A4871A /* WMFBorderButton.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
WMFBorderButton.h; sourceTree = "<group>"; };
@@ -2304,6 +2308,8 @@
                                BCB669D01A83F6D300C7B1FE /* 
MWKHistoryListTests.m */,
                                BCB66A0F1A851C9B00C7B1FE /* MWKImageListTests.m 
*/,
                                BCB58F7D1A8D1B8400465627 /* 
MWKImageInfo+MWKImageComparisonTests.m */,
+                               BCFE02691B41ABB5003752B7 /* 
MWKHistoryListCorruptDataTests.m */,
+                               BCFE026E1B41B482003752B7 /* 
MWKSavedPageListCorruptDataTests.m */,
                        );
                        name = MediaWikiKitTests;
                        path = ../MediaWikiKit/MediaWikiKitTests;
@@ -2981,6 +2987,7 @@
                                BC0FED6B1AAA0268002488D7 /* 
MWKDataStoreStorageTests.m in Sources */,
                                0484B9071ABB50FA00874073 /* WMFArticleParsing.m 
in Sources */,
                                BC0FED751AAA026C002488D7 /* 
NSArray+BKIndexTests.m in Sources */,
+                               BCFE026A1B41ABB5003752B7 /* 
MWKHistoryListCorruptDataTests.m in Sources */,
                                BC31B2521AB1D9DC008138CA /* 
WMFImageInfoControllerTests.m in Sources */,
                                BC0FED641AAA0263002488D7 /* 
MWKArticleStoreTestCase.m in Sources */,
                                BCA676561AC05FE200A16160 /* 
NSBundle+TestAssets.m in Sources */,
@@ -2990,6 +2997,7 @@
                                BC0FED741AAA026C002488D7 /* 
CircularBitwiseRotationTests.m in Sources */,
                                BCEC77951AC9C74700D9DDA5 /* 
NSArray+WMFShuffle.m in Sources */,
                                BCE912BD1ACC629B00B74B42 /* 
NSIndexSet+BKReduceTests.m in Sources */,
+                               BCFE026F1B41B482003752B7 /* 
MWKSavedPageListCorruptDataTests.m in Sources */,
                                BCB3AE8A1AC11458004AD205 /* 
NSManagedObjectContext+WMFTempContext.m in Sources */,
                                BC49B3641AEECFD8009F55BE /* 
ArticleLoadingTests.m in Sources */,
                                BCEC77921AC9B6AD00D9DDA5 /* 
HCIsCollectionContainingInAnyOrder+WMFCollectionMatcherUtils.m in Sources */,
diff --git a/Wikipedia/View Controllers/WebView/WebViewController.m 
b/Wikipedia/View Controllers/WebView/WebViewController.m
index 47e8997..da8259f 100644
--- a/Wikipedia/View Controllers/WebView/WebViewController.m
+++ b/Wikipedia/View Controllers/WebView/WebViewController.m
@@ -1332,18 +1332,16 @@
 
 - (void)navigateToPage:(MWKTitle*)title
        discoveryMethod:(MWKHistoryDiscoveryMethod)discoveryMethod {
-
     NSParameterAssert(title);
-    if([title.text length] == 0){
-        
+    if ([title.text length] == 0) {
         [self showAlert:MWLocalizedString(@"article-unable-to-load-article", 
nil) type:ALERT_TYPE_TOP duration:2];
         return;
     }
-    
+
     NSString* cleanTitle = title.text;
     NSParameterAssert(cleanTitle.length);
     [self hideKeyboard];
-    
+
     self.jumpToFragment = title.fragment;
 
     if (discoveryMethod != MWKHistoryDiscoveryMethodBackForward && 
discoveryMethod != MWKHistoryDiscoveryMethodReloadFromNetwork && 
discoveryMethod != MWKHistoryDiscoveryMethodReloadFromCache) {
@@ -1352,7 +1350,6 @@
 
     [self retrieveArticleForPageTitle:title
                       discoveryMethod:discoveryMethod];
-
 }
 
 - (void)reloadCurrentArticleFromNetwork {
@@ -1382,10 +1379,8 @@
 
 - (void)retrieveArticleForPageTitle:(MWKTitle*)pageTitle
                     discoveryMethod:(MWKHistoryDiscoveryMethod)discoveryMethod 
{
-    
     NSParameterAssert(pageTitle);
-    if([pageTitle.text length] == 0){
-        
+    if ([pageTitle.text length] == 0) {
         [self showAlert:MWLocalizedString(@"article-unable-to-load-article", 
nil) type:ALERT_TYPE_TOP duration:2];
         return;
     }
@@ -1471,13 +1466,12 @@
 
                 self.isFetchingArticle = NO;
 
-                if([article.title.text length] == 0){
-                    
+                if ([article.title.text length] == 0) {
                     [self 
showAlert:MWLocalizedString(@"article-unable-to-load-article", nil) 
type:ALERT_TYPE_TOP duration:2];
 
                     return;
                 }
-                
+
                 // Update the toc and web view.
                 [self displayArticle:article.title];
 
@@ -1649,9 +1643,8 @@
 #pragma mark Display article from data store
 
 - (void)displayArticle:(MWKTitle*)title {
-    
     NSParameterAssert(title.text);
-    if([title.text length] == 0){
+    if ([title.text length] == 0) {
         return;
     }
 
diff --git a/WikipediaUnitTests/MWKSection+WMFSharingTests.m 
b/WikipediaUnitTests/MWKSection+WMFSharingTests.m
index 1c181c8..a211579 100644
--- a/WikipediaUnitTests/MWKSection+WMFSharingTests.m
+++ b/WikipediaUnitTests/MWKSection+WMFSharingTests.m
@@ -24,7 +24,7 @@
 }
 
 - (void)testSimpleSnippet {
-    MWKTitle* title = [[MWKSite siteWithCurrentLocale] titleWithString:@"foo"];
+    MWKTitle* title     = [[MWKSite siteWithCurrentLocale] 
titleWithString:@"foo"];
     MWKArticle* article = [[MWKArticle alloc] initWithTitle:title 
dataStore:nil];
     self.section = [[MWKSection alloc] initWithArticle:article
                                                   dict:@{
@@ -35,7 +35,7 @@
 }
 
 - (void)testSimpleSnippetIncludingTable {
-    MWKTitle* title = [[MWKSite siteWithCurrentLocale] titleWithString:@"foo"];
+    MWKTitle* title     = [[MWKSite siteWithCurrentLocale] 
titleWithString:@"foo"];
     MWKArticle* article = [[MWKArticle alloc] initWithTitle:title 
dataStore:nil];
     self.section = [[MWKSection alloc] initWithArticle:article
                                                   dict:@{
diff --git a/WikipediaUnitTests/MWKSectionListTests.m 
b/WikipediaUnitTests/MWKSectionListTests.m
index 5ff8af8..88f3dec 100644
--- a/WikipediaUnitTests/MWKSectionListTests.m
+++ b/WikipediaUnitTests/MWKSectionListTests.m
@@ -41,7 +41,7 @@
 }
 
 - (void)testCreatingSectionListWithNoData {
-    MWKTitle* title = [[MWKSite siteWithCurrentLocale] titleWithString:@"foo"];
+    MWKTitle* title         = [[MWKSite siteWithCurrentLocale] 
titleWithString:@"foo"];
     MWKArticle* mockArticle =
         [[MWKArticle alloc] initWithTitle:title dataStore:self.dataStore];
     MWKSectionList* emptySectionList = [[MWKSectionList alloc] 
initWithArticle:mockArticle];
@@ -50,7 +50,7 @@
 }
 
 - (void)testSectionListInitializationExeptionHandling {
-    MWKTitle* title = [[MWKSite siteWithCurrentLocale] titleWithString:@"foo"];
+    MWKTitle* title         = [[MWKSite siteWithCurrentLocale] 
titleWithString:@"foo"];
     MWKArticle* mockArticle =
         [[MWKArticle alloc] initWithTitle:title dataStore:self.dataStore];
 
diff --git a/WikipediaUnitTests/Utilities/MWKImage+AssociationTestUtils.m 
b/WikipediaUnitTests/Utilities/MWKImage+AssociationTestUtils.m
index a7c793d..225f984 100644
--- a/WikipediaUnitTests/Utilities/MWKImage+AssociationTestUtils.m
+++ b/WikipediaUnitTests/Utilities/MWKImage+AssociationTestUtils.m
@@ -12,7 +12,7 @@
 @implementation MWKImage (AssociationTestUtils)
 
 + (instancetype)imageAssociatedWithSourceURL:(NSString*)imageURL {
-    MWKTitle* title = [[MWKSite siteWithCurrentLocale] titleWithString:@"foo"];
+    MWKTitle* title     = [[MWKSite siteWithCurrentLocale] 
titleWithString:@"foo"];
     MWKArticle* article = [[MWKArticle alloc] initWithTitle:title 
dataStore:nil];
     return [[self alloc] initWithArticle:article sourceURL:imageURL];
 }
diff --git a/WikipediaUnitTests/WMFImageInfoControllerTests.m 
b/WikipediaUnitTests/WMFImageInfoControllerTests.m
index 7400927..f9579a0 100644
--- a/WikipediaUnitTests/WMFImageInfoControllerTests.m
+++ b/WikipediaUnitTests/WMFImageInfoControllerTests.m
@@ -72,10 +72,10 @@
 - (void)testReadsFromDataStoreLazilyAndPopulatesFetchedIndices {
     MWKImageList* mockImageList = mock([MWKImageList class]);
     MWKDataStore* mockDataStore = mock([MWKDataStore class]);
-    MWKTitle* title = [[MWKSite siteWithCurrentLocale] titleWithString:@"foo"];
-    MWKArticle* article = [[MWKArticle alloc] initWithTitle:title 
dataStore:mockDataStore];
+    MWKTitle* title             = [[MWKSite siteWithCurrentLocale] 
titleWithString:@"foo"];
+    MWKArticle* article         = [[MWKArticle alloc] initWithTitle:title 
dataStore:mockDataStore];
 
-    NSArray* testImages         = [[self generateSourceURLs:5] 
bk_map:^MWKImage*(NSString* sourceURL) {
+    NSArray* testImages = [[self generateSourceURLs:5] 
bk_map:^MWKImage*(NSString* sourceURL) {
         return [[MWKImage alloc] initWithArticle:article sourceURL:sourceURL];
     }];
     NSRange preFetchedRange    = NSMakeRange(0, 2);

-- 
To view, visit https://gerrit.wikimedia.org/r/221669
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I88e6360bfe58dc89a3a53fea2cb43a05dac7a20a
Gerrit-PatchSet: 1
Gerrit-Project: apps/ios/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Bgerstle <bgers...@wikimedia.org>
Gerrit-Reviewer: Fjalapeno <cfl...@wikimedia.org>
Gerrit-Reviewer: Mhurd <mh...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to