Dr0ptp4kt has submitted this change and it was merged.
Change subject: merge release/4.1.1
......................................................................
merge release/4.1.1
Here's a breakdown of the conflicts:
- Wikipedia.xcodeproj/project.pbxproj
Pretty simple, just some new files
- Wikipedia/AppDelegate+DataMigrationProgressDelegate.h
- Wikipedia/AppDelegate+DataMigrationProgressDelegate.m
- Wikipedia/AppDelegate.m
Some issues w/ refactoring the crash reporting refactor and data
migration progress consolidation. I added a property to verify the alert
view is the data migration alert, just to be doubly sure.
- Wikipedia/Networking/Fetchers/MWKImageInfoFetcher.m
- Wikipedia/View Controllers/Image Gallery/WMFImageGalleryViewController.m
Had to refactor some stuff to incorporate the "no canonical filename"
fallback that Corey added.
- Wikipedia/Wikipedia-Info.plist
Version & bundle identifier conflict.
- WikipediaUnitTests/OldDataSchemaMigratorTests.m
New tests added
Change-Id: I4e0c130c3aa9e66b7e2af312294b3e21cfc26b7e
Ticket: T96452
---
M MediaWikiKit/MediaWikiKit/MWKSectionList.m
A MediaWikiKit/MediaWikiKit/MWKSectionList_Private.h
M Wikipedia.xcodeproj/project.pbxproj
M Wikipedia/AppDelegate.m
M Wikipedia/Data/DataMigrator.h
M Wikipedia/Data/DataMigrator.m
M Wikipedia/Data/OldDataSchemaMigrator.h
M Wikipedia/Data/OldDataSchemaMigrator.m
M Wikipedia/View Controllers/DataMigration/DataMigrationProgressViewController.h
M Wikipedia/View Controllers/DataMigration/DataMigrationProgressViewController.m
M Wikipedia/View Controllers/Image Gallery/WMFImageInfoController.m
M Wikipedia/View Controllers/SearchResults/SearchResultsController.m
M Wikipedia/Wikipedia-Info.plist
M Wikipedia/en.lproj/Localizable.strings
M Wikipedia/qqq.lproj/Localizable.strings
A WikipediaUnitTests/MWKSectionListTests.m
M WikipediaUnitTests/OldDataSchemaMigratorTests.m
17 files changed, 376 insertions(+), 150 deletions(-)
Approvals:
Dr0ptp4kt: Looks good to me, approved
Mhurd: Looks good to me, but someone else must approve
diff --git a/MediaWikiKit/MediaWikiKit/MWKSectionList.m
b/MediaWikiKit/MediaWikiKit/MWKSectionList.m
index e606895..57a184b 100644
--- a/MediaWikiKit/MediaWikiKit/MWKSectionList.m
+++ b/MediaWikiKit/MediaWikiKit/MWKSectionList.m
@@ -6,6 +6,7 @@
// Copyright (c) 2014 Wikimedia Foundation. All rights reserved.
//
+#import "MWKSectionList_Private.h"
#import "MediaWikiKit.h"
@implementation MWKSectionList {
@@ -27,35 +28,49 @@
_article = article;
mutationState = 0;
if (_sections == nil) {
- _sections = [@[] mutableCopy];
- NSFileManager* fm = [NSFileManager defaultManager];
- NSString* path = [[self.article.dataStore
pathForTitle:self.article.title] stringByAppendingPathComponent:@"sections"];
- NSArray* files = [fm contentsOfDirectoryAtPath:path error:nil];
- files = [files sortedArrayUsingComparator:^NSComparisonResult
(NSString* obj1, NSString* obj2) {
- int sectionId1 = [obj1 intValue];
- int sectionId2 = [obj2 intValue];
- if (sectionId1 < sectionId2) {
- return NSOrderedAscending;
- } else if (sectionId1 == sectionId2) {
- return NSOrderedSame;
- } else {
- return NSOrderedDescending;
- }
- }];
- NSRegularExpression* redigits = [NSRegularExpression
regularExpressionWithPattern:@"^\\d+$" options:0 error:nil];
- for (NSString* subpath in files) {
- NSString* filename = [subpath lastPathComponent];
- NSArray* matches = [redigits matchesInString:filename
options:0 range:NSMakeRange(0, [filename length])];
- if (matches && [matches count]) {
- int sectionId = [filename intValue];
- _sections[sectionId] = [self.article.dataStore
sectionWithId:sectionId article:self.article];
- }
- }
+ _sections = [NSMutableArray array];
+ [self importSectionsFromDisk];
}
}
return self;
}
+- (void)importSectionsFromDisk {
+ NSFileManager* fm = [NSFileManager defaultManager];
+ NSString* path = [[self.article.dataStore
pathForTitle:self.article.title] stringByAppendingPathComponent:@"sections"];
+
+ NSArray* files = [fm contentsOfDirectoryAtPath:path error:nil];
+ files = [files sortedArrayUsingComparator:^NSComparisonResult (NSString*
obj1, NSString* obj2) {
+ int sectionId1 = [obj1 intValue];
+ int sectionId2 = [obj2 intValue];
+ if (sectionId1 < sectionId2) {
+ return NSOrderedAscending;
+ } else if (sectionId1 == sectionId2) {
+ return NSOrderedSame;
+ } else {
+ return NSOrderedDescending;
+ }
+ }];
+
+ NSRegularExpression* redigits = [NSRegularExpression
regularExpressionWithPattern:@"^\\d+$" options:0 error:nil];
+ @try {
+ for (NSString* subpath in files) {
+ NSString* filename = [subpath lastPathComponent];
+ NSArray* matches = [redigits matchesInString:filename options:0
range:NSMakeRange(0, [filename length])];
+ if (matches && [matches count]) {
+ [self readAndInsertSection:[filename intValue]];
+ }
+ }
+ }@catch (NSException* e) {
+ NSLog(@"Failed to import sections at path %@, leaving list empty.",
path);
+ [_sections removeAllObjects];
+ }
+}
+
+- (void)readAndInsertSection:(int)sectionId {
+ _sections[sectionId] = [self.article.dataStore sectionWithId:sectionId
article:self.article];
+}
+
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState*)state
objects:(__unsafe_unretained id [])stackbuf
count:(NSUInteger)len {
diff --git a/MediaWikiKit/MediaWikiKit/MWKSectionList_Private.h
b/MediaWikiKit/MediaWikiKit/MWKSectionList_Private.h
new file mode 100644
index 0000000..94795ce
--- /dev/null
+++ b/MediaWikiKit/MediaWikiKit/MWKSectionList_Private.h
@@ -0,0 +1,19 @@
+//
+// MWKSectionList_Private.h
+// Wikipedia
+//
+// Created by Brian Gerstle on 4/16/15.
+// Copyright (c) 2015 Wikimedia Foundation. All rights reserved.
+//
+
+#import "MWKSectionList.h"
+
+@interface MWKSectionList ()
+
+/// Import list of sections from disk using the receiver's `article` and
`dataStore`.
+- (void)importSectionsFromDisk;
+
+/// Read `sectionId` from the receiver's `article.dataStore` and insert it
into the receiver's section list..
+- (void)readAndInsertSection:(int)sectionId;
+
+@end
diff --git a/Wikipedia.xcodeproj/project.pbxproj
b/Wikipedia.xcodeproj/project.pbxproj
index e5004fa..7e95694 100644
--- a/Wikipedia.xcodeproj/project.pbxproj
+++ b/Wikipedia.xcodeproj/project.pbxproj
@@ -225,7 +225,6 @@
BC86B9361A92966B00B4C039 /*
AFHTTPRequestOperationManager+UniqueRequests.m in Sources */ = {isa =
PBXBuildFile; fileRef = BC86B9351A92966B00B4C039 /*
AFHTTPRequestOperationManager+UniqueRequests.m */; };
BC86B93D1A929CC500B4C039 /*
UICollectionViewFlowLayout+NSCopying.m in Sources */ = {isa = PBXBuildFile;
fileRef = BC86B93C1A929CC500B4C039 /* UICollectionViewFlowLayout+NSCopying.m
*/; };
BC86B9401A929D7900B4C039 /*
UICollectionViewFlowLayout+WMFItemSizeThatFits.m in Sources */ = {isa =
PBXBuildFile; fileRef = BC86B93F1A929D7900B4C039 /*
UICollectionViewFlowLayout+WMFItemSizeThatFits.m */; };
- BC90C4B91AC201BB009F36D2 /*
AppDelegate+DataMigrationProgressDelegate.m in Sources */ = {isa =
PBXBuildFile; fileRef = BC90C4B81AC201BB009F36D2 /*
AppDelegate+DataMigrationProgressDelegate.m */; };
BC90C4BE1AC219FE009F36D2 /* UIWindow+WMFMainScreenWindow.m in
Sources */ = {isa = PBXBuildFile; fileRef = BC90C4BD1AC219FE009F36D2 /*
UIWindow+WMFMainScreenWindow.m */; };
BC955BC71A82BEFD000EF9E4 /* MWKImageInfoFetcher.m in Sources */
= {isa = PBXBuildFile; fileRef = BC955BC61A82BEFD000EF9E4 /*
MWKImageInfoFetcher.m */; };
BC955BCF1A82C2FA000EF9E4 /*
AFHTTPRequestOperationManager+WMFConfig.m in Sources */ = {isa = PBXBuildFile;
fileRef = BC955BCE1A82C2FA000EF9E4 /* AFHTTPRequestOperationManager+WMFConfig.m
*/; };
@@ -286,6 +285,7 @@
BCC185D81A9E5628005378F8 /* UILabel+WMFStyling.m in Sources */
= {isa = PBXBuildFile; fileRef = BCC185D71A9E5628005378F8 /*
UILabel+WMFStyling.m */; };
BCC185E01A9EC836005378F8 /* UIButton+FrameUtils.m in Sources */
= {isa = PBXBuildFile; fileRef = BCC185DF1A9EC836005378F8 /*
UIButton+FrameUtils.m */; };
BCC185E81A9FA498005378F8 /*
UICollectionViewFlowLayout+AttributeUtils.m in Sources */ = {isa =
PBXBuildFile; fileRef = BCC185E71A9FA498005378F8 /*
UICollectionViewFlowLayout+AttributeUtils.m */; };
+ BCCED2D01AE03BE20094EB7E /* MWKSectionListTests.m in Sources */
= {isa = PBXBuildFile; fileRef = BCCED2CF1AE03BE20094EB7E /*
MWKSectionListTests.m */; };
BCDB75C41AB0E8300005593F /* WMFSubstringUtilsTests.m in Sources
*/ = {isa = PBXBuildFile; fileRef = BCDB75C31AB0E8300005593F /*
WMFSubstringUtilsTests.m */; };
BCE912BA1ACC5E6900B74B42 /* NSIndexSet+BKReduce.m in Sources */
= {isa = PBXBuildFile; fileRef = BCE912B91ACC5E6900B74B42 /*
NSIndexSet+BKReduce.m */; };
BCE912BD1ACC629B00B74B42 /* NSIndexSet+BKReduceTests.m in
Sources */ = {isa = PBXBuildFile; fileRef = BCE912BC1ACC629B00B74B42 /*
NSIndexSet+BKReduceTests.m */; };
@@ -752,8 +752,6 @@
BC86B93C1A929CC500B4C039 /*
UICollectionViewFlowLayout+NSCopying.m */ = {isa = PBXFileReference;
fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path =
"UICollectionViewFlowLayout+NSCopying.m"; sourceTree = "<group>"; };
BC86B93E1A929D7900B4C039 /*
UICollectionViewFlowLayout+WMFItemSizeThatFits.h */ = {isa = PBXFileReference;
fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path =
"UICollectionViewFlowLayout+WMFItemSizeThatFits.h"; sourceTree = "<group>"; };
BC86B93F1A929D7900B4C039 /*
UICollectionViewFlowLayout+WMFItemSizeThatFits.m */ = {isa = PBXFileReference;
fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path =
"UICollectionViewFlowLayout+WMFItemSizeThatFits.m"; sourceTree = "<group>"; };
- BC90C4B71AC201BB009F36D2 /*
AppDelegate+DataMigrationProgressDelegate.h */ = {isa = PBXFileReference;
fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path =
"AppDelegate+DataMigrationProgressDelegate.h"; sourceTree = "<group>"; };
- BC90C4B81AC201BB009F36D2 /*
AppDelegate+DataMigrationProgressDelegate.m */ = {isa = PBXFileReference;
fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path =
"AppDelegate+DataMigrationProgressDelegate.m"; sourceTree = "<group>"; };
BC90C4BC1AC219FE009F36D2 /* UIWindow+WMFMainScreenWindow.h */ =
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h;
path = "UIWindow+WMFMainScreenWindow.h"; sourceTree = "<group>"; };
BC90C4BD1AC219FE009F36D2 /* UIWindow+WMFMainScreenWindow.m */ =
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType =
sourcecode.c.objc; path = "UIWindow+WMFMainScreenWindow.m"; sourceTree =
"<group>"; };
BC955BC51A82BEFD000EF9E4 /* MWKImageInfoFetcher.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path =
MWKImageInfoFetcher.h; sourceTree = "<group>"; };
@@ -884,6 +882,8 @@
BCC185E71A9FA498005378F8 /*
UICollectionViewFlowLayout+AttributeUtils.m */ = {isa = PBXFileReference;
fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path =
"UICollectionViewFlowLayout+AttributeUtils.m"; sourceTree = "<group>"; };
BCDB75BC1AB0D3DE0005593F /* WMFImageInfoController_Private.h */
= {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType =
sourcecode.c.h; name = WMFImageInfoController_Private.h; path = "Image
Gallery/WMFImageInfoController_Private.h"; sourceTree = "<group>"; };
BCDB75BD1AB0DFC40005593F /* WMFRangeUtils.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path =
WMFRangeUtils.h; sourceTree = "<group>"; };
+ BCCED2CF1AE03BE20094EB7E /* MWKSectionListTests.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path
= MWKSectionListTests.m; sourceTree = "<group>"; };
+ BCCED2D21AE041BD0094EB7E /* MWKSectionList_Private.h */ = {isa
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path
= MWKSectionList_Private.h; sourceTree = "<group>"; };
BCDB75C31AB0E8300005593F /* WMFSubstringUtilsTests.m */ = {isa
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc;
path = WMFSubstringUtilsTests.m; sourceTree = "<group>"; };
BCE912B81ACC5E6900B74B42 /* NSIndexSet+BKReduce.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path =
"NSIndexSet+BKReduce.h"; sourceTree = "<group>"; };
BCE912B91ACC5E6900B74B42 /* NSIndexSet+BKReduce.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path
= "NSIndexSet+BKReduce.m"; sourceTree = "<group>"; };
@@ -2041,6 +2041,7 @@
BC31B2511AB1D9DC008138CA /*
WMFImageInfoControllerTests.m */,
BCE912BC1ACC629B00B74B42 /*
NSIndexSet+BKReduceTests.m */,
0EBC56951AD5B22800E82CDD /*
BITHockeyManagerWMFExtensionsTests.m */,
+ BCCED2CF1AE03BE20094EB7E /*
MWKSectionListTests.m */,
);
path = WikipediaUnitTests;
sourceTree = "<group>";
@@ -2182,6 +2183,7 @@
BCB6699E1A83F6C300C7B1FE /* MWKImageList.h */,
BCB6699F1A83F6C300C7B1FE /* MWKImageList.m */,
BCB669A01A83F6C300C7B1FE /* MWKSectionList.h */,
+ BCCED2D21AE041BD0094EB7E /*
MWKSectionList_Private.h */,
BCB669A11A83F6C300C7B1FE /* MWKSectionList.m */,
);
name = "Data i/o";
@@ -2365,8 +2367,6 @@
D4BC22B3181E9E6300CAC673 /* empty.png */,
D4991447181D51DE00E6073C /* AppDelegate.h */,
D4991448181D51DE00E6073C /* AppDelegate.m */,
- BC90C4B71AC201BB009F36D2 /*
AppDelegate+DataMigrationProgressDelegate.h */,
- BC90C4B81AC201BB009F36D2 /*
AppDelegate+DataMigrationProgressDelegate.m */,
D499144A181D51DE00E6073C /*
Main_iPhone.storyboard */,
D46CD8C018A1AC4F0042959E /* InfoPlist.strings
*/,
D46CD8C218A1AC4F0042959E /* Localizable.strings
*/,
@@ -2857,6 +2857,7 @@
BC0FED771AAA026C002488D7 /*
WMFImageURLParsingTests.m in Sources */,
BCEC778F1AC9AEC800D9DDA5 /*
MWKImage+AssociationTestUtils.m in Sources */,
04F1226A1ACB822D002FC3B5 /*
NSString+FormattedAttributedStringTests.m in Sources */,
+ BCCED2D01AE03BE20094EB7E /*
MWKSectionListTests.m in Sources */,
BC0FED6B1AAA0268002488D7 /*
MWKDataStoreStorageTests.m in Sources */,
0484B9071ABB50FA00874073 /* WMFArticleParsing.m
in Sources */,
BC0FED751AAA026C002488D7 /*
NSArray+BKIndexTests.m in Sources */,
@@ -3002,7 +3003,6 @@
BC86B93D1A929CC500B4C039 /*
UICollectionViewFlowLayout+NSCopying.m in Sources */,
04D686C91AB28FE40009B44A /*
UIImage+WMFFocalImageDrawing.m in Sources */,
0429300A18604898002A13FC /*
SavedPagesResultCell.m in Sources */,
- BC90C4B91AC201BB009F36D2 /*
AppDelegate+DataMigrationProgressDelegate.m in Sources */,
0487048419F8262600B7D307 /* CaptchaResetter.m
in Sources */,
D407E6411A51DBDA00CCC8B1 /* SchemaConverter.m
in Sources */,
BCB669A71A83F6C400C7B1FE /* MWKSiteDataObject.m
in Sources */,
diff --git a/Wikipedia/AppDelegate.m b/Wikipedia/AppDelegate.m
index 9de2b4e..32c5e32 100644
--- a/Wikipedia/AppDelegate.m
+++ b/Wikipedia/AppDelegate.m
@@ -6,12 +6,15 @@
#import "WikipediaAppUtils.h"
#import "SessionSingleton.h"
#import "BITHockeyManager+WMFExtensions.h"
-#import "AppDelegate+DataMigrationProgressDelegate.h"
#import "UIWindow+WMFMainScreenWindow.h"
+#import "DataMigrationProgressViewController.h"
+#import "UIWindow+WMFMainScreenWindow.h"
+#import "WikipediaAppUtils.h"
@interface AppDelegate ()
-
+<DataMigrationProgressDelegate>
+@property (nonatomic, weak) UIAlertView* dataMigrationAlert;
@end
@implementation AppDelegate
@@ -132,4 +135,39 @@
// Called when the application is about to terminate. Save data if
appropriate. See also applicationDidEnterBackground:.
}
+#pragma mark - Migration
+
+- (BOOL)presentDataMigrationViewControllerIfNeeded {
+ if ([DataMigrationProgressViewController needsMigration]) {
+ UIAlertView* dialog =
+ [[UIAlertView alloc]
initWithTitle:MWLocalizedString(@"migration-prompt-title", nil)
+
message:MWLocalizedString(@"migration-prompt-message", nil)
+ delegate:self
+
cancelButtonTitle:MWLocalizedString(@"migration-skip-button-title", nil)
+
otherButtonTitles:MWLocalizedString(@"migration-confirm-button-title", nil),
nil];
+ [dialog show];
+ self.dataMigrationAlert = dialog;
+ return YES;
+ } else {
+ return NO;
+ }
+}
+
+-
(void)dataMigrationProgressComplete:(DataMigrationProgressViewController*)viewController
{
+ [self presentRootViewController:YES withSplash:NO];
+}
+
+- (void)alertView:(UIAlertView*)alertView
didDismissWithButtonIndex:(NSInteger)buttonIndex {
+ if (alertView == self.dataMigrationAlert) {
+ if (buttonIndex == alertView.cancelButtonIndex) {
+ [DataMigrationProgressViewController removeOldData];
+ [self presentRootViewController:YES withSplash:NO];
+ } else {
+ DataMigrationProgressViewController* migrationVC =
[[DataMigrationProgressViewController alloc] init];
+ migrationVC.delegate = self;
+ [self transitionToRootViewController:migrationVC animated:NO];
+ }
+ }
+}
+
@end
diff --git a/Wikipedia/Data/DataMigrator.h b/Wikipedia/Data/DataMigrator.h
index 62d37fd..e4a41fc 100644
--- a/Wikipedia/Data/DataMigrator.h
+++ b/Wikipedia/Data/DataMigrator.h
@@ -10,12 +10,13 @@
@interface DataMigrator : NSObject
-- (id)init;
+/// @return `YES` if a SQLLite file exists at the master database path,
otherwise `NO`.
++ (BOOL)hasData;
-/**
- * Is there anything that needs to be migrated?
- */
-- (BOOL)hasData;
+/// Remove the master database file.
++ (void)removeOldData;
+
+- (id)init;
/**
* Return the extracted JSON blobs from the savedPagesDB database table.
@@ -24,11 +25,5 @@
* @return (NSArray *) of (NSDictionary *)s.
*/
- (NSArray*)extractSavedPages;
-
-/**
- * Delete the old files.
- * @todo implement this
- */
-- (void)removeOldData;
@end
diff --git a/Wikipedia/Data/DataMigrator.m b/Wikipedia/Data/DataMigrator.m
index a074312..ffdbdc4 100644
--- a/Wikipedia/Data/DataMigrator.m
+++ b/Wikipedia/Data/DataMigrator.m
@@ -17,20 +17,33 @@
#pragma mark - Public methods
++ (NSString*)masterDatabasePathIfExists {
+ NSString* path = [self localLibraryPath:@"Caches/Databases.db"];
+ return [[NSFileManager defaultManager] fileExistsAtPath:path] ? path : nil;
+}
+
++ (BOOL)hasData {
+ return !![self masterDatabasePathIfExists];
+}
+
++ (void)removeOldData {
+ NSString* dbPath = [[self class] masterDatabasePathIfExists];
+ if (dbPath) {
+ NSLog(@"Deleting old app's %@", dbPath);
+ [[NSFileManager defaultManager] removeItemAtPath:dbPath error:nil];
+ }
+}
+
- (id)init {
self = [super init];
if (self) {
- NSString* dbPath = [self localLibraryPath:@"Caches/Databases.db"];
- if ([[NSFileManager defaultManager] fileExistsAtPath:dbPath]) {
+ NSString* dbPath = [[self class] masterDatabasePathIfExists];
+ if (dbPath) {
NSLog(@"Opening sqlite database from %@", dbPath);
masterDB = [[SQLiteHelper alloc] initWithPath:dbPath];
}
}
return self;
-}
-
-- (BOOL)hasData {
- return (masterDB != NULL);
}
- (NSArray*)extractSavedPages {
@@ -44,25 +57,16 @@
return [NSArray arrayWithArray:arr];
}
-- (void)removeOldData {
- if ([self hasData]) {
- NSLog(@"Deleting old app's Caches/Databases.db");
- masterDB = nil;
- NSString* dbPath = [self localLibraryPath:@"Caches/Databases.db"];
- [[NSFileManager defaultManager] removeItemAtPath:dbPath error:nil];
- }
-}
-
#pragma mark - Private methods
/**
* Return absolute path for relative path to the installed app's documents
folder.
*/
-- (NSString*)localDocumentPath:(NSString*)local {
++ (NSString*)localDocumentPath:(NSString*)local {
return [[self documentRootPath] stringByAppendingPathComponent:local];
}
-- (NSString*)documentRootPath {
++ (NSString*)documentRootPath {
NSArray* documentPaths =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentRootPath = [documentPaths objectAtIndex:0];
return documentRootPath;
@@ -71,11 +75,11 @@
/**
* Return absolute path for relative path to the installed app's Library
folder.
*/
-- (NSString*)localLibraryPath:(NSString*)local {
++ (NSString*)localLibraryPath:(NSString*)local {
return [[self libraryRootPath] stringByAppendingPathComponent:local];
}
-- (NSString*)libraryRootPath {
++ (NSString*)libraryRootPath {
NSArray* libraryPaths =
NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString* libraryRootPath = [libraryPaths objectAtIndex:0];
return libraryRootPath;
@@ -90,7 +94,7 @@
NSArray* rows = [masterDB query:@"SELECT origin, path FROM Databases
WHERE name=?" params:@[dbname]];
NSDictionary* row = rows[0];
NSLog(@"row: %@", row);
- NSString* path = [[[self localLibraryPath:@"Caches"]
stringByAppendingPathComponent:row[@"origin"]]
stringByAppendingPathComponent:row[@"path"]];
+ NSString* path = [[[[self class] localLibraryPath:@"Caches"]
stringByAppendingPathComponent:row[@"origin"]]
stringByAppendingPathComponent:row[@"path"]];
NSLog(@"opening path %@", path);
return [[SQLiteHelper alloc] initWithPath:path];
}
diff --git a/Wikipedia/Data/OldDataSchemaMigrator.h
b/Wikipedia/Data/OldDataSchemaMigrator.h
index e028df2..bf7c549 100644
--- a/Wikipedia/Data/OldDataSchemaMigrator.h
+++ b/Wikipedia/Data/OldDataSchemaMigrator.h
@@ -42,7 +42,7 @@
@property (weak) id<OldDataSchemaDelegate> delegate;
@property (weak) id<OldDataSchemaMigratorProgressDelegate> progressDelegate;
-- (BOOL)exists;
++ (BOOL)exists;
/**
* This runs asynchronously.
@@ -50,4 +50,6 @@
*/
- (void)migrateData;
++ (void)removeOldData;
+
@end
diff --git a/Wikipedia/Data/OldDataSchemaMigrator.m
b/Wikipedia/Data/OldDataSchemaMigrator.m
index 91cf595..cb45974 100644
--- a/Wikipedia/Data/OldDataSchemaMigrator.m
+++ b/Wikipedia/Data/OldDataSchemaMigrator.m
@@ -26,7 +26,7 @@
self = [super init];
if (self) {
_savedTitles = [[NSMutableSet alloc] init];
- if (self.exists) {
+ if ([[self class] exists]) {
_context = [ArticleDataContextSingleton sharedInstance];
} else {
_context = nil;
@@ -35,19 +35,19 @@
return self;
}
-- (NSString*)sqlitePath {
++ (NSString*)sqlitePath {
NSArray* documentPaths =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentRootPath = [documentPaths objectAtIndex:0];
NSString* filePath = [documentRootPath
stringByAppendingPathComponent:@"articleData6.sqlite"];
return filePath;
}
-- (BOOL)exists {
++ (BOOL)exists {
NSString* filePath = [self sqlitePath];
return [[NSFileManager defaultManager] fileExistsAtPath:filePath];
}
-- (void)removeOldData {
++ (void)removeOldData {
NSString* filePath = [self sqlitePath];
NSString* backupPath = [filePath stringByAppendingString:@".bak"];
NSError* err = nil;
@@ -106,7 +106,7 @@
}
[self.context saveContextAndPropagateChangesToStore:context
completionBlock:^(NSError* error) {
- [self removeOldData];
+ [[self class] removeOldData];
if (error) {
[self.progressDelegate oldDataSchema:self
didFinishWithError:error];
@@ -143,33 +143,34 @@
// Record for later to avoid dupe imports
[self.savedTitles addObject:key];
- MWKArticle* migratedArticle = [self.delegate oldDataSchema:self
migrateArticle:[self exportArticle:article]];
-
- Image* thumbnail = article.thumbnailImage;
- if (thumbnail) {
- [self migrateThumbnailImage:thumbnail article:article
newArticle:migratedArticle];
- }
- // HACK: setting thumbnailURL after migration prevents it from being
added to the image list twice
- migratedArticle.thumbnailURL = thumbnail.sourceUrl;
-
- for (Section* section in [article sectionsBySectionId]) {
- for (SectionImage* sectionImage in [section sectionImagesByIndex])
{
- [self migrateImage:sectionImage newArticle:migratedArticle];
- }
- }
-
- // set the lead image to the first non-thumb image
- if ([migratedArticle.images count]) {
- // thumbnail should always be first, if it's present (see above
assertion)
- NSUInteger leadImageURLIndex = (thumbnail &&
migratedArticle.images.count > 1) ? 1 : 0;
- migratedArticle.imageURL = [migratedArticle.images
imageURLAtIndex:leadImageURLIndex];
- }
-
+ MWKArticle* migratedArticle;
@try {
+ migratedArticle = [self.delegate oldDataSchema:self
migrateArticle:[self exportArticle:article]];
+
+ Image* thumbnail = article.thumbnailImage;
+ if (thumbnail) {
+ [self migrateThumbnailImage:thumbnail article:article
newArticle:migratedArticle];
+ }
+ // HACK: setting thumbnailURL after migration prevents it from
being added to the image list twice
+ migratedArticle.thumbnailURL = thumbnail.sourceUrl;
+
+ for (Section* section in [article sectionsBySectionId]) {
+ for (SectionImage* sectionImage in [section
sectionImagesByIndex]) {
+ [self migrateImage:sectionImage
newArticle:migratedArticle];
+ }
+ }
+
+ // set the lead image to the first non-thumb image
+ if ([migratedArticle.images count]) {
+ // thumbnail should always be first, if it's present (see
above assertion)
+ NSUInteger leadImageURLIndex = (thumbnail &&
migratedArticle.images.count > 1) ? 1 : 0;
+ migratedArticle.imageURL = [migratedArticle.images
imageURLAtIndex:leadImageURLIndex];
+ }
+
[migratedArticle save];
- } @catch (NSException* saveException) {
- NSLog(@"Failed to save article after importing images: %@",
saveException);
- NSParameterAssert(!saveException);
+ }@catch (NSException* exception) {
+ NSLog(@"Failed to migrate article due to exception: %@. Removing
data.", exception);
+ [migratedArticle remove];
}
}
}
diff --git a/Wikipedia/View
Controllers/DataMigration/DataMigrationProgressViewController.h
b/Wikipedia/View Controllers/DataMigration/DataMigrationProgressViewController.h
index f213130..cb3a248 100644
--- a/Wikipedia/View
Controllers/DataMigration/DataMigrationProgressViewController.h
+++ b/Wikipedia/View
Controllers/DataMigration/DataMigrationProgressViewController.h
@@ -23,6 +23,8 @@
@property (weak, nonatomic) IBOutlet UILabel* progressLabel;
@property (weak, nonatomic) id<DataMigrationProgressDelegate> delegate;
-- (BOOL)needsMigration;
+// TODO: refactor these into class methods
++ (BOOL)needsMigration;
++ (void)removeOldData;
@end
diff --git a/Wikipedia/View
Controllers/DataMigration/DataMigrationProgressViewController.m
b/Wikipedia/View Controllers/DataMigration/DataMigrationProgressViewController.m
index 15069f6..654217e 100644
--- a/Wikipedia/View
Controllers/DataMigration/DataMigrationProgressViewController.m
+++ b/Wikipedia/View
Controllers/DataMigration/DataMigrationProgressViewController.m
@@ -49,9 +49,9 @@
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
- if ([self.oldDataSchema exists]) {
+ if ([OldDataSchemaMigrator exists]) {
[self runNewMigration];
- } else if ([self.dataMigrator hasData]) {
+ } else if ([DataMigrator hasData]) {
[self runOldMigration];
}
}
@@ -77,8 +77,13 @@
return _schemaConvertor;
}
-- (BOOL)needsMigration {
- return [self.oldDataSchema exists] || [self.dataMigrator hasData];
++ (BOOL)needsMigration {
+ return [OldDataSchemaMigrator exists] || [DataMigrator hasData];
+}
+
++ (void)removeOldData {
+ [DataMigrator removeOldData];
+ [OldDataSchemaMigrator removeOldData];
}
- (void)runNewMigration {
@@ -111,7 +116,7 @@
[importer importArticles:titles];
- [self.dataMigrator removeOldData];
+ [DataMigrator removeOldData];
[self.progressIndicator setProgress:1.0 animated:YES completion:NULL];
}
diff --git a/Wikipedia/View Controllers/Image Gallery/WMFImageInfoController.m
b/Wikipedia/View Controllers/Image Gallery/WMFImageInfoController.m
index d4c38cc..b052ece 100644
--- a/Wikipedia/View Controllers/Image Gallery/WMFImageInfoController.m
+++ b/Wikipedia/View Controllers/Image Gallery/WMFImageInfoController.m
@@ -55,8 +55,30 @@
- (NSArray*)uniqueArticleImages {
if (!_uniqueArticleImages) {
NSArray* uniqueArticleImages = [self.article.images
uniqueLargestVariants];
+
+ // reverse article images if current language is RTL
_uniqueArticleImages =
[WikipediaAppUtils isDeviceLanguageRTL] ? [uniqueArticleImages
wmf_reverseArray] : uniqueArticleImages;
+
+ NSMutableArray* imageFilePageTitles = [NSMutableArray
arrayWithCapacity:_uniqueArticleImages.count];
+
+ // reduce images to only those who have valid canonical filenames
+ _uniqueArticleImages =
+ [[_uniqueArticleImages bk_reduce:[NSMutableArray
arrayWithCapacity:_uniqueArticleImages.count]
+ withBlock:^id (NSMutableArray*
uniqueArticleImages, MWKImage* image) {
+ NSAssert(image.canonicalFilename.length,
+ @"Unable to form canonical filename from image: %@",
+ image.sourceURL);
+ if (image.canonicalFilename.length) {
+ NSString* filePageTitle = [@"File:"
stringByAppendingString:image.canonicalFilename];
+ [imageFilePageTitles addObject:filePageTitle];
+ [uniqueArticleImages addObject:image];
+ }
+ return uniqueArticleImages;
+ }] copy];
+
+ // strictly evaluate iamgeFilePageTitles to filter out any images
don't have a canonicalFilename
+ _imageFilePageTitles = [imageFilePageTitles copy];
}
return _uniqueArticleImages;
}
@@ -67,18 +89,6 @@
WMFIndexImageInfo([self.dataStore
imageInfoForArticle:self.article]) ? : [NSMutableDictionary new];
}
return _indexedImageInfo;
-}
-
-- (NSArray*)imageFilePageTitles {
- if (!_imageFilePageTitles) {
- _imageFilePageTitles = [[self uniqueArticleImages]
bk_map:^NSString*(MWKImage* image) {
- NSAssert(image.canonicalFilename.length,
- @"Unable to form canonical filename from image: %@",
- image.sourceURL);
- return [@"File:" stringByAppendingString:image.canonicalFilename];
- }];
- }
- return _imageFilePageTitles;
}
- (NSUInteger)indexOfImageAssociatedWithInfo:(MWKImageInfo*)info {
diff --git a/Wikipedia/View Controllers/SearchResults/SearchResultsController.m
b/Wikipedia/View Controllers/SearchResults/SearchResultsController.m
index 61294e2..e899708 100644
--- a/Wikipedia/View Controllers/SearchResults/SearchResultsController.m
+++ b/Wikipedia/View Controllers/SearchResults/SearchResultsController.m
@@ -536,7 +536,7 @@
// Check if cell still onscreen! This is important!
NSArray* visibleRowIndexPaths = [self.searchResultsTable
indexPathsForVisibleRows];
for (NSIndexPath* thisIndexPath in visibleRowIndexPaths.copy) {
- NSDictionary* rowData =
self.searchResults[thisIndexPath.row];
+ NSDictionary* rowData = [self
searchResultForIndexPath:thisIndexPath];
NSString* url = rowData[@"thumbnail"][@"source"];
if ([url.lastPathComponent isEqualToString:fileName]) {
SearchResultCell* cell =
(SearchResultCell*)[self.searchResultsTable
cellForRowAtIndexPath:thisIndexPath];
@@ -586,11 +586,6 @@
[self.didYouMeanButton hide];
- // Show "Searching..." message.
- //[self.searchMessageLabel
showWithText:MWLocalizedString(@"search-searching", nil)];
-
- //[self showAlert:MWLocalizedString(@"search-searching", nil)
type:ALERT_TYPE_MIDDLE duration:-1];
-
(void)[[SearchResultFetcher alloc] initAndSearchForTerm:searchTerm
searchType:SEARCH_TYPE_TITLES
searchReason:reason
@@ -601,52 +596,59 @@
#pragma mark Search results table methods (requests actual thumb image data)
+- (NSDictionary*)searchResultForIndex:(NSUInteger)index {
+ if (index >= [self.searchResults count]) {
+ return nil;
+ }
+
+ return self.searchResults[index];
+}
+
+- (NSDictionary*)searchResultForIndexPath:(NSIndexPath*)indexPath {
+ return [self searchResultForIndex:indexPath.row];
+}
+
- (NSInteger)tableView:(UITableView*)tableView
numberOfRowsInSection:(NSInteger)section {
return self.searchResults.count;
}
- (CGFloat)tableView:(UITableView*)tableView
heightForRowAtIndexPath:(NSIndexPath*)indexPath {
- if ([self.searchResults[indexPath.row][@"attributedText"] length] <
kWMFMaxStringLength) {
+ NSDictionary* result = [self searchResultForIndexPath:indexPath];
+
+ //Optimization to prevent calculation to get cell size
+ if ([result[@"attributedText"] length] < kWMFMaxStringLength) {
return floor(kWMFDefaultCellHeight * MENUS_SCALE_MULTIPLIER);
}
- // Update the sizing cell with any data which could change the cell height.
- self.offScreenSizingCell.resultLabel.attributedText =
self.searchResults[indexPath.row][@"attributedText"];
+ self.offScreenSizingCell.resultLabel.attributedText =
result[@"attributedText"];
- // Determine height for the current configuration of the sizing cell.
return [tableView heightForSizingCell:self.offScreenSizingCell];
}
- (UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
SearchResultCell* cell = (SearchResultCell*)[tableView
dequeueReusableCellWithIdentifier:kWMFSearchCellID];
- NSString* thumbURL =
self.searchResults[indexPath.row][@"thumbnail"][@"source"];
+ NSDictionary* result = [self searchResultForIndexPath:indexPath];
- // For performance reasons, "attributedText" is build when data is
retrieved, not here when the cell
- // is about to be displayed.
- cell.resultLabel.attributedText =
self.searchResults[indexPath.row][@"attributedText"];
+ cell.resultLabel.attributedText = result[@"attributedText"];
+ cell.resultImageView.image = self.placeholderImage;
- // Set thumbnail placeholder
- cell.resultImageView.image = self.placeholderImage;
+ NSString* thumbURL = result[@"thumbnail"][@"source"];
+ if (thumbURL) {
+ __block NSString* fileName = [thumbURL lastPathComponent];
- if (!thumbURL) {
- // Don't bother downloading if no thumbURL
- return cell;
- }
-
- __block NSString* fileName = [thumbURL lastPathComponent];
-
- // See if cache file found, show it instead of downloading if found.
- NSString* cacheFilePath = [self.cachePath
stringByAppendingPathComponent:fileName];
- BOOL isDirectory = NO;
- BOOL fileExists = [[NSFileManager defaultManager]
fileExistsAtPath:cacheFilePath isDirectory:&isDirectory];
- if (fileExists) {
- cell.resultImageView.image = [UIImage imageWithData:[NSData
dataWithContentsOfFile:cacheFilePath]];
- } else {
- // No thumb found so fetch it.
- (void)[[ThumbnailFetcher alloc] initAndFetchThumbnailFromURL:thumbURL
-
withManager:[QueuesSingleton sharedInstance].searchResultsFetchManager
- thenNotifyDelegate:self];
+ // See if cache file found, show it instead of downloading if found.
+ NSString* cacheFilePath = [self.cachePath
stringByAppendingPathComponent:fileName];
+ BOOL isDirectory = NO;
+ BOOL fileExists = [[NSFileManager defaultManager]
fileExistsAtPath:cacheFilePath isDirectory:&isDirectory];
+ if (fileExists) {
+ cell.resultImageView.image = [UIImage imageWithData:[NSData
dataWithContentsOfFile:cacheFilePath]];
+ } else {
+ // No thumb found so fetch it.
+ (void)[[ThumbnailFetcher alloc]
initAndFetchThumbnailFromURL:thumbURL
+
withManager:[QueuesSingleton sharedInstance].searchResultsFetchManager
+ thenNotifyDelegate:self];
+ }
}
return cell;
@@ -655,12 +657,18 @@
- (void)tableView:(UITableView*)tableView
didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
[self hideKeyboard];
- NSString* title = self.searchResults[indexPath.row][@"title"];
+ NSDictionary* result = [self searchResultForIndexPath:indexPath];
+
+ NSString* title = result[@"title"];
[self loadArticleWithTitle:title];
}
- (void)loadArticleWithTitle:(NSString*)title {
+ if ([title length] == 0) {
+ return;
+ }
+
[self saveSearchTermToRecentList];
// Set CurrentArticleTitle so web view knows what to load.
diff --git a/Wikipedia/Wikipedia-Info.plist b/Wikipedia/Wikipedia-Info.plist
index 644845e..170138d 100644
--- a/Wikipedia/Wikipedia-Info.plist
+++ b/Wikipedia/Wikipedia-Info.plist
@@ -21,7 +21,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
- <string>4.0.7.1</string>
+ <string>4.1.0.2</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSLocationWhenInUseUsageDescription</key>
diff --git a/Wikipedia/en.lproj/Localizable.strings
b/Wikipedia/en.lproj/Localizable.strings
index 213906c..334092e 100644
--- a/Wikipedia/en.lproj/Localizable.strings
+++ b/Wikipedia/en.lproj/Localizable.strings
@@ -282,11 +282,18 @@
"nearby-location-general-error" = "Unable to determine location. Pull to
refresh or try again later.";
"nearby-wifi" = "Enabling Wi-Fi can help your device better determine your
location.";
-"migration-update-progress-label" = "Upgrading local data";
-"migration-update-progress-count-label" = "Migrating Article $1 of $2";
+"migration-update-progress-label" = "Migrating local data";
+"migration-update-progress-count-label" = "Migrating article $1 of $2";
+"migration-prompt-title" = "Looks like we have a history!";
+"migration-prompt-message" = "We need to move your saved & recent pages over.
This may take a minute…";
+"migration-confirm-button-title" = "Move my stuff over";
+"migration-skip-button-title" = "Delete it";
"image-gallery-unknown-owner" = "Uploader unknown.";
+"image-gallery-fetch-image-info-error-title" = "Unable to download images";
+"image-gallery-fetch-image-info-error-message" = "UNable to download the
images for this article. Please refresh the article and try again.";
+"image-gallery-fetch-image-info-error-ok" = "OK";
"hockeyapp-alert-question" = "Would you like to send a crash report to $1 so
Wikimedia can review your crash?";
"hockeyapp-alert-question-with-response-field" = "Would you like to send a
crash report to $1 so Wikimedia can review your crash? Please describe what
happened when the crash occurred:";
diff --git a/Wikipedia/qqq.lproj/Localizable.strings
b/Wikipedia/qqq.lproj/Localizable.strings
index ebd947d..c82ad0c 100644
--- a/Wikipedia/qqq.lproj/Localizable.strings
+++ b/Wikipedia/qqq.lproj/Localizable.strings
@@ -258,6 +258,10 @@
"nearby-wifi" = "Alert text telling user how to improve location accuracy";
"migration-update-progress-label" = "Label shown during automatic upgrade of
local data to new internal format. May be on screen very briefly or for a few
seconds.";
"migration-update-progress-count-label" = "Shows the progress of article
migration in text: 4 / 15, 5 / 15, etc…";
+"migration-prompt-title" = "Title of the alert shown to users before migrating
all legacy data.";
+"migration-prompt-message" = "Mesasge explaining reason for migration, and
what will happen if the users skips it.";
+"migration-confirm-button-title" = "Button within migration prompt that
confirms the user wants to proceed with migration.";
+"migration-skip-button-title" = "Button with migration prompt that indicates
user wants to skip migration and delete their data.";
"image-gallery-unknown-owner" = "Fallback text for when an item in the image
gallery doesn't have a specified owner.";
"hockeyapp-alert-question" = "Alert dialog question asking user whether to
send a crash report to HockeyApp crash reporting server. $1 will be replaced
programmatically with the constant string 'HockeyApp'";
"hockeyapp-alert-question-with-response-field" = "Alert dialog question asking
user whether to send a crash report to HockeyApp crash reporting server, and
asking the user to describe what happened when the crash occurred. $1 will be
replaced programmatically with the constant string 'HockeyApp'";
@@ -266,3 +270,6 @@
"hockeyapp-alert-always-send" = "Alert dialog button text for crash reporting
to always be sent";
"hockeyapp-alert-do-not-send" = "Alert dialog button text for crash reporting
to not send the crash report";
"hockeyapp-alert-privacy" = "Alert dialog button text for HockeyApp privacy
policy. $1 will be replaced programmatically with the constant string
'HockeyApp'";
+"image-gallery-fetch-image-info-error-title" = "Title of prompt weh image meta
download fails in gallery";
+"image-gallery-fetch-image-info-error-message" = "Message of prompt weh image
meta download fails in gallery";
+"image-gallery-fetch-image-info-error-ok" = "OK button of prompt weh image
meta download fails in gallery";
diff --git a/WikipediaUnitTests/MWKSectionListTests.m
b/WikipediaUnitTests/MWKSectionListTests.m
new file mode 100644
index 0000000..d3ccaaf
--- /dev/null
+++ b/WikipediaUnitTests/MWKSectionListTests.m
@@ -0,0 +1,80 @@
+//
+// MWKSectionListTests.m
+// Wikipedia
+//
+// Created by Brian Gerstle on 4/16/15.
+// Copyright (c) 2015 Wikimedia Foundation. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <XCTest/XCTest.h>
+#import "MWKArticle.h"
+#import "MWKSectionList.h"
+#import "MWKSection.h"
+#import "MWKDataStore.h"
+#import "WMFRandomFileUtilities.h"
+
+#define MOCKITO_SHORTHAND 1
+#import <OCMockito/OCMockito.h>
+
+#define HC_SHORTHAND 1
+#import <OCHamcrest/OCHamcrest.h>
+
+// suppress warning about passing "anything()" to "sectionWithId:"
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wint-conversion"
+
+@interface MWKSectionListTests : XCTestCase
+@end
+
+@implementation MWKSectionListTests
+
+- (void)setUp {
+ [super setUp];
+}
+
+- (void)tearDown {
+ [super tearDown];
+}
+
+- (void)testCreatingSectionListWithNoData {
+ MWKArticle* mockArticle =
+ [[MWKArticle alloc] initWithTitle:nil dataStore:mock([MWKDataStore
class])];
+ MWKSectionList* emptySectionList = [[MWKSectionList alloc]
initWithArticle:mockArticle];
+ assertThat(@(emptySectionList.count), is(equalToInt(0)));
+ [MKTVerifyCount(mockArticle.dataStore, never()) sectionWithId:anything()
article:anything()];
+}
+
+- (void)testSectionListInitializationExeptionHandling {
+ MWKArticle* mockArticle =
+ [[MWKArticle alloc] initWithTitle:nil dataStore:mock([MWKDataStore
class])];
+
+ [self addEmptyFolderForSection:0 title:anything()
mockDataStore:mockArticle.dataStore];
+
+ // mock an exception, simulating the case where required fields are missing
+ [given([mockArticle.dataStore sectionWithId:anything()
+ article:mockArticle])
+ willThrow:[NSException new]];
+
+ MWKSectionList* emptySectionList = [[MWKSectionList alloc]
initWithArticle:mockArticle];
+ assertThat(@(emptySectionList.count), is(equalToInt(0)));
+}
+
+- (void)addEmptyFolderForSection:(int)sectionId
+ title:(id)titleMatcher
+ mockDataStore:(MWKDataStore*)mockDataStore {
+ // create an empty section directory, so that our section list will reach
the code path
+ // where an exception will be thrown when trying to read the section data
+ NSString* randomDirectory = WMFRandomTemporaryPath();
+ NSString* randomPath = [randomDirectory
stringByAppendingPathComponent:@"sections/0"];
+ BOOL didCreateRandomPath = [[NSFileManager defaultManager]
createDirectoryAtPath:randomPath
+
withIntermediateDirectories:YES
+
attributes:nil
+
error:nil];
+ NSParameterAssert(didCreateRandomPath);
+ [given([mockDataStore pathForTitle:anything()])
willReturn:randomDirectory];
+}
+
+@end
+
+#pragma clang diagnostic pop
diff --git a/WikipediaUnitTests/OldDataSchemaMigratorTests.m
b/WikipediaUnitTests/OldDataSchemaMigratorTests.m
index c70ed50..f9e5cb9 100644
--- a/WikipediaUnitTests/OldDataSchemaMigratorTests.m
+++ b/WikipediaUnitTests/OldDataSchemaMigratorTests.m
@@ -73,8 +73,41 @@
[self verifyMigrationOfArticle:oldArticle];
}
+- (void)testArticleWithMissingRequiredFieldsIsGracefullySkipped {
+ Article* oldArticle = [self createOldArticleWithSections:10
imagesPerSection:5];
+ // lastModified is a required field
+ oldArticle.lastmodified = nil;
+ [self verifySkippedMigrationOfArticle:oldArticle];
+}
+
+- (void)testArticleWithInvalidSectionIsGracefullySkipped {
+ Article* oldArticle = [self createOldArticleWithSections:10
imagesPerSection:5];
+ Section* section = oldArticle.sectionsBySectionId.lastObject;
+ // sectionId is a required field
+ section.sectionId = nil;
+ [self verifySkippedMigrationOfArticle:oldArticle];
+}
+
+- (void)testArticleWithInvalidSectionImageIsGracefullySkipped {
+ Article* oldArticle = [self createOldArticleWithSections:10
imagesPerSection:5];
+ Section* section = oldArticle.sectionsBySectionId.lastObject;
+ SectionImage* image = section.sectionImagesByIndex.lastObject;
+ // sourceUrl is a required field
+ image.image.sourceUrl = nil;
+ [self verifySkippedMigrationOfArticle:oldArticle];
+}
+
#pragma mark - Test Utils
+- (void)verifySkippedMigrationOfArticle:(Article*)oldArticle {
+ XCTAssertNoThrow([self.migrator migrateArticle:oldArticle],
+ @"Failed to catch an article migration exception.");
+ MWKTitle* migratedArticleTitle = [self.migrator
migrateArticleTitle:oldArticle];
+ NSString* articleDataPath = [self.dataStore
pathForTitle:migratedArticleTitle];
+ XCTAssertFalse([[NSFileManager defaultManager]
fileExistsAtPath:articleDataPath],
+ @"Expected article to not be saved due to exception during
migration.");
+}
+
- (void)verifyMigrationOfArticle:(Article*)oldArticle {
[self.migrator migrateArticle:oldArticle];
--
To view, visit https://gerrit.wikimedia.org/r/205287
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I4e0c130c3aa9e66b7e2af312294b3e21cfc26b7e
Gerrit-PatchSet: 3
Gerrit-Project: apps/ios/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Bgerstle <[email protected]>
Gerrit-Reviewer: Dr0ptp4kt <[email protected]>
Gerrit-Reviewer: Fjalapeno <[email protected]>
Gerrit-Reviewer: Mhurd <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits