diff --git a/WordPress/Classes/Models/Blog+CoreDataProperties.swift b/WordPress/Classes/Models/Blog+CoreDataProperties.swift new file mode 100644 index 000000000000..93c80482525f --- /dev/null +++ b/WordPress/Classes/Models/Blog+CoreDataProperties.swift @@ -0,0 +1,139 @@ +import Foundation +import CoreData + +extension Blog { + /// Unusued, to be removed. + @available(*, unavailable) + @NSManaged var apiKey: String? + + /// Deprecated, it used to store the blog ID, but it's useless on self hosted, so we're moving to dotComID instead for clarity. + @available(*, unavailable, message="Use dotComID instead") + @NSManaged var blogID: NSNumber + + /// The ID for the blog's current theme. Only present for WordPress.com blogs if themes have been Cached. + @NSManaged var currentThemeId: String? + + /// Unused, to be removed. + @available(*, unavailable) + @NSManaged var hasOlderPages: Bool + + /// Unused, to be removed. + @available(*, unavailable) + @NSManaged var hasOlderPosts: Bool + + /// URL for the site icon. + @NSManaged var icon: String? + + /// Unused, to ne removed. + @available(*, unavailable) + @NSManaged var isActivated: Bool + + /// Stores if the current user is an administrator of the blog. + /// - warning: This is not 100% reliable: if the API is unable to tell us if the user is an admin, we check if the user can edit the blog title and use that as an indicator. + @NSManaged var isAdmin: Bool + + /// Stores if the blog is hosted on WordPress.com. + @NSManaged var isHostedAtWPcom: Bool + + /// Stores if the blog has more than one author. + @NSManaged var isMultiAuthor: Bool + + /// Date of the last time comments were synced. + @NSManaged var lastCommentsSync: NSDate + + /// Date of the last time pages were synced. + @NSManaged var lastPagesSync: NSDate + + /// Date of the last time posts were synced. + @NSManaged var lastPostsSync: NSDate + + /// Unusued, to be removed. + @available(*, unavailable) + @NSManaged var lastStatsSync: NSDate + + /// WordPress version for which we last alerted the user about a required update. + /// When the Blog's version is lower than the required MinimumVersion, we show an alert to the user. The MinimumVersion value at that time is stored here so we only show the alert once. + @NSManaged var lastUpdateWarning: String? + + /// Stores the blog options as they come from the API. + /// + /// For legacy reasons, this currently tries to mimic the structure of the dictionary returned by XML-RPC's wp.getOptions. + /// + /// Each value in the dictionary should be a dictionary with keys: "value", "desc", and "readonly". + /// + /// For convenience, use getOptionValue(_) to get the value for a specific option. + /// + /// - seealso: getOptionValue(_) + @NSManaged var options: [String: AnyObject]? + + /// Stores the product ID of the blog's plan. + @NSManaged var planID: NSNumber? + + /// Post formats supported by the blog. + /// The key is the post format "slug", and the value is the "label". + @NSManaged var postFormats: [String: String]? + + /// Full URL to the site. + @NSManaged var url: String + + /// Stores the username for self hosted blogs. + /// - warning: for WordPress.com or Jetpack managed sites this will be `nil`. Use `usernameForSite` instead + /// - seealso: usernameForSite + @NSManaged var username: String? + + /// Stores if the blog should be visible. + /// WordPress.com supports hiding blogs from the blog list by going to the [My Blogs](https://dashboard.wordpress.com/wp-admin/index.php?page=my-blogs) section. This property defaults to `true` so self hosted blogs are always visible. + @NSManaged var visible: Bool + + /// URL for the XML-RPC endpoing + @NSManaged var xmlrpc: String + + + // MARK: - Relationships + + /// The associated WordPress.com account, if it's the default account + /// If this is a self hosted site with Jetpack connected to a WordPress.com account different than the default account, this will be `nil` and the connected WordPress.com account will be set in `jetpackAccount`. + @NSManaged var account: WPAccount? + + /// Inverse relationship to `WPAccount.defaultBlog`. Not very useful, but Core Data requires it, so added it here for completeness. + @NSManaged var accountForDefaultBlog: WPAccount? + + /// Cached categories for this blog. + @NSManaged var categories: Set + + /// Cached comments for this blog. + @NSManaged var comments: Set + + /// Cached Publicize connections for this blog. + @NSManaged var connections: Set + + /// The connected WordPress.com account for a Jetpack site, if different from the default WordPress.com account. + @NSManaged var jetpackAccount: WPAccount? + + /// Cached media items for this blog. + @NSManaged var media: Set + + /// Cached menu locations for this blog. + /// - seealso: MenuLocation + @NSManaged var menuLocations: NSOrderedSet// + + /// Cached menus for this blog. + /// - seealso: Menu + @NSManaged var menus: NSOrderedSet// + + /// Cached posts for this blog. Includes both posts and pages. + @NSManaged var posts: Set + + /// Settings for this blog, encapsulated in a BlogSettings instance + /// - seealso: BlogSettings + @NSManaged var settings: BlogSettings? + + /// Cached tags for this blog. + @NSManaged var tags: Set + + /// Cached available themes for this blog. + @NSManaged var themes: Set + + /// Cached buttons to share to a third-party service. + @NSManaged var sharingButtons: Set +} diff --git a/WordPress/Classes/Models/Blog.h b/WordPress/Classes/Models/Blog.h index 289d7a94a9c4..f430ed95b4b9 100644 --- a/WordPress/Classes/Models/Blog.h +++ b/WordPress/Classes/Models/Blog.h @@ -52,61 +52,13 @@ typedef NS_ENUM(NSInteger, SiteVisibility) { @interface Blog : NSManagedObject -@property (nonatomic, strong, readwrite) NSNumber *blogID __deprecated_msg("Use dotComID instead"); @property (nonatomic, strong, readwrite) NSNumber *dotComID; -@property (nonatomic, strong, readwrite) NSString *xmlrpc; -@property (nonatomic, strong, readwrite) NSString *apiKey; -@property (nonatomic, strong, readwrite) NSNumber *hasOlderPosts; -@property (nonatomic, strong, readwrite) NSNumber *hasOlderPages; -@property (nonatomic, strong, readwrite) NSSet *posts; -@property (nonatomic, strong, readwrite) NSSet *categories; -@property (nonatomic, strong, readwrite) NSSet *tags; -@property (nonatomic, strong, readwrite) NSSet *comments; -@property (nonatomic, strong, readwrite) NSSet *connections; -@property (nonatomic, strong, readwrite) NSSet *themes; -@property (nonatomic, strong, readwrite) NSSet *media; -@property (nonatomic, strong, readwrite) NSOrderedSet *menus; -@property (nonatomic, strong, readwrite) NSOrderedSet *menuLocations; -@property (nonatomic, strong, readwrite) NSString *currentThemeId; @property (nonatomic, assign, readwrite) BOOL isSyncingPosts; @property (nonatomic, assign, readwrite) BOOL isSyncingPages; @property (nonatomic, assign, readwrite) BOOL isSyncingMedia; -@property (nonatomic, strong, readwrite) NSDate *lastPostsSync; -@property (nonatomic, strong, readwrite) NSDate *lastPagesSync; -@property (nonatomic, strong, readwrite) NSDate *lastCommentsSync; -@property (nonatomic, strong, readwrite) NSDate *lastStatsSync; -@property (nonatomic, strong, readwrite) NSString *lastUpdateWarning; -@property (nonatomic, assign, readwrite) BOOL visible; -@property (nonatomic, weak, readwrite) NSNumber *isActivated; -@property (nonatomic, strong, readwrite) NSDictionary *options; -@property (nonatomic, strong, readwrite) NSDictionary *postFormats; -@property (nonatomic, strong, readwrite) WPAccount *account; -@property (nonatomic, strong, readwrite) WPAccount *jetpackAccount; @property (nonatomic, assign, readwrite) BOOL videoPressEnabled; -@property (nonatomic, assign, readwrite) BOOL isMultiAuthor; -@property (nonatomic, assign, readwrite) BOOL isHostedAtWPcom; -@property (nonatomic, strong, readwrite) NSString *icon; @property (nonatomic, assign, readwrite) SiteVisibility siteVisibility; -@property (nonatomic, strong, readwrite) NSNumber *planID; -@property (nonatomic, strong, readwrite) NSSet *sharingButtons; -/** - * @details Maps to a BlogSettings instance, which contains a collection of the available preferences, - * and their values. - */ -@property (nonatomic, strong, readwrite) BlogSettings *settings; - -/** - * @details Flags whether the current user is an admin on the blog. - */ -@property (nonatomic, assign, readwrite) BOOL isAdmin; - -/** - * @details Stores the username for self hosted sites - * - * @warn For WordPress.com or Jetpack Managed sites this will be nil. Use usernameForSite instead - */ -@property (nonatomic, strong, readwrite) NSString *username; @property (nonatomic, strong, readwrite) NSString *password; @@ -136,8 +88,6 @@ typedef NS_ENUM(NSInteger, SiteVisibility) { // kept for compatibilty, used as a key to store passwords @property (weak, readonly) NSString *hostURL; @property (weak, readonly) NSString *homeURL; -// http://wp.koke.me/sub -@property (nonatomic, strong) NSString *url; // Used for reachability checks (IDN encoded) // wp.koke.me @property (weak, readonly) NSString *hostname; diff --git a/WordPress/Classes/Models/Blog.m b/WordPress/Classes/Models/Blog.m index 3c947c2ba202..56ebc6be0b91 100644 --- a/WordPress/Classes/Models/Blog.m +++ b/WordPress/Classes/Models/Blog.m @@ -33,42 +33,6 @@ @interface Blog () @implementation Blog -@dynamic blogID; -@dynamic url; -@dynamic xmlrpc; -@dynamic apiKey; -@dynamic hasOlderPosts; -@dynamic hasOlderPages; -@dynamic posts; -@dynamic categories; -@dynamic tags; -@dynamic comments; -@dynamic connections; -@dynamic themes; -@dynamic media; -@dynamic menus; -@dynamic menuLocations; -@dynamic currentThemeId; -@dynamic lastPostsSync; -@dynamic lastStatsSync; -@dynamic lastPagesSync; -@dynamic lastCommentsSync; -@dynamic lastUpdateWarning; -@dynamic options; -@dynamic postFormats; -@dynamic isActivated; -@dynamic visible; -@dynamic account; -@dynamic jetpackAccount; -@dynamic isAdmin; -@dynamic isMultiAuthor; -@dynamic isHostedAtWPcom; -@dynamic icon; -@dynamic username; -@dynamic settings; -@dynamic planID; -@dynamic sharingButtons; - @synthesize api = _api; @synthesize isSyncingPosts; @synthesize isSyncingPages; diff --git a/WordPress/Classes/Models/Post.m b/WordPress/Classes/Models/Post.m index aade2de826ba..21198e399cba 100644 --- a/WordPress/Classes/Models/Post.m +++ b/WordPress/Classes/Models/Post.m @@ -6,6 +6,7 @@ #import "NSMutableDictionary+Helpers.h" #import "NSString+Helpers.h" #import "ContextManager.h" +#import "WordPress-Swift.h" #import @interface Post() diff --git a/WordPress/Classes/Models/Theme.m b/WordPress/Classes/Models/Theme.m index 39bfb54afb21..181b6c4103d6 100644 --- a/WordPress/Classes/Models/Theme.m +++ b/WordPress/Classes/Models/Theme.m @@ -4,6 +4,7 @@ #import "WPAccount.h" #import "AccountService.h" #import "NSString+Helpers.h" +#import "WordPress-Swift.h" static NSString* const ThemeAdminUrlCustomize = @"customize.php?theme=%@&hide_close=true"; static NSString* const ThemeUrlDemoParameters = @"?demo=true&iframe=true&theme_preview=true"; diff --git a/WordPress/Classes/Services/CommentService.m b/WordPress/Classes/Services/CommentService.m index 0ef42eaac6a2..2fdc5d62b5dc 100644 --- a/WordPress/Classes/Services/CommentService.m +++ b/WordPress/Classes/Services/CommentService.m @@ -12,6 +12,7 @@ #import "PostService.h" #import "AbstractPost.h" #import "NSDate+WordPressJSON.h" +#import "WordPress-Swift.h" NSUInteger const WPTopLevelHierarchicalCommentsPerPage = 20; NSInteger const WPNumberOfCommentsToSync = 100; diff --git a/WordPress/Classes/Services/PostCategoryService.m b/WordPress/Classes/Services/PostCategoryService.m index c247bdacc972..aa8d7afdda23 100644 --- a/WordPress/Classes/Services/PostCategoryService.m +++ b/WordPress/Classes/Services/PostCategoryService.m @@ -6,6 +6,7 @@ #import "TaxonomyServiceRemote.h" #import "TaxonomyServiceRemoteREST.h" #import "TaxonomyServiceRemoteXMLRPC.h" +#import "WordPress-Swift.h" @implementation PostCategoryService diff --git a/WordPress/Classes/Services/PostTagService.m b/WordPress/Classes/Services/PostTagService.m index d3985c75e80b..499d0271b8ab 100644 --- a/WordPress/Classes/Services/PostTagService.m +++ b/WordPress/Classes/Services/PostTagService.m @@ -7,6 +7,7 @@ #import "TaxonomyServiceRemoteREST.h" #import "TaxonomyServiceRemoteXMLRPC.h" #import "RemoteTaxonomyPaging.h" +#import "WordPress-Swift.h" @interface PostTagService () diff --git a/WordPress/Classes/Services/ThemeService.m b/WordPress/Classes/Services/ThemeService.m index d8519e75e35a..122fd0984abb 100644 --- a/WordPress/Classes/Services/ThemeService.m +++ b/WordPress/Classes/Services/ThemeService.m @@ -6,6 +6,7 @@ #import "ThemeServiceRemote.h" #import "WPAccount.h" #import "ContextManager.h" +#import "WordPress-Swift.h" /** * @brief Place unordered themes after loaded pages diff --git a/WordPress/Classes/System/3DTouch/WP3DTouchShortcutCreator.swift b/WordPress/Classes/System/3DTouch/WP3DTouchShortcutCreator.swift index 80b036560d08..78781fff76be 100644 --- a/WordPress/Classes/System/3DTouch/WP3DTouchShortcutCreator.swift +++ b/WordPress/Classes/System/3DTouch/WP3DTouchShortcutCreator.swift @@ -47,7 +47,7 @@ public class WP3DTouchShortcutCreator: NSObject public func loggedInShortcutArray() -> [UIApplicationShortcutItem] { var defaultBlogName: String? if blogService.blogCountForAllAccounts() > 1 { - defaultBlogName = blogService.lastUsedOrFirstBlog().settings.name + defaultBlogName = blogService.lastUsedOrFirstBlog().settings?.name } let notificationsShortcut = UIMutableApplicationShortcutItem(type: WP3DTouchShortcutHandler.ShortcutIdentifier.Notifications.type, diff --git a/WordPress/Classes/System/WordPress-Bridging-Header.h b/WordPress/Classes/System/WordPress-Bridging-Header.h index 7e1a6e6b7770..c7cb846b4090 100644 --- a/WordPress/Classes/System/WordPress-Bridging-Header.h +++ b/WordPress/Classes/System/WordPress-Bridging-Header.h @@ -4,13 +4,15 @@ #import #import +#import "AbstractPost.h" #import "AccountService.h" #import "AppRatingUtility.h" #import "Blog.h" #import "BlogService.h" -#import "CommentService.h" +#import "Comment.h" +#import "CommentService.h" #import "Constants.h" #import "ContextManager.h" #import "CustomHighlightButton.h" @@ -21,6 +23,7 @@ #import "LoginViewController.h" +#import "Media.h" #import "MediaService.h" #import "MeHeaderView.h" @@ -34,8 +37,10 @@ #import "UIApplication+Helpers.h" #import "PhotonImageURLHelper.h" +#import "PostCategory.h" #import "PostListFooterView.h" #import "PostMetaButton.h" +#import "PostTag.h" #import "WPPostViewController.h" #import "ReachabilityUtils.h" diff --git a/WordPress/Classes/ViewRelated/Blog/DiscussionSettingsViewController.swift b/WordPress/Classes/ViewRelated/Blog/DiscussionSettingsViewController.swift index 8533fb8cb7e9..659f1bebd891 100644 --- a/WordPress/Classes/ViewRelated/Blog/DiscussionSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/DiscussionSettingsViewController.swift @@ -601,7 +601,9 @@ public class DiscussionSettingsViewController : UITableViewController // MARK: - Computed Properties private var settings : BlogSettings { - return blog.settings + // FIXME: Settings is not guaranteed to be non-nil. This might crash + // @koke 2016-02-03 + return blog.settings! } // MARK: - Typealiases diff --git a/WordPress/Classes/ViewRelated/Blog/SiteManagement/StartOverViewController.swift b/WordPress/Classes/ViewRelated/Blog/SiteManagement/StartOverViewController.swift index 92b543f2f0a0..37c20dba2e56 100644 --- a/WordPress/Classes/ViewRelated/Blog/SiteManagement/StartOverViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/SiteManagement/StartOverViewController.swift @@ -91,8 +91,10 @@ public class StartOverViewController: UITableViewController tableView.deselectSelectedRowWithAnimation(true) if HelpshiftUtils.isHelpshiftEnabled() { - setupHelpshift(blog.account) - + if let account = blog.account { + setupHelpshift(account) + } + let metadata = helpshiftMetadata(blog) Helpshift.sharedInstance().showConversation(self, withOptions: metadata) } else { diff --git a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift index a09eb03c45ce..0301a56f87da 100644 --- a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift +++ b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift @@ -378,7 +378,7 @@ public protocol ThemePresenter: class return nil } - for theme in blog.themes as! Set { + for theme in blog.themes { if theme.themeId == themeId { return theme } diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index f3bfbc70746b..096e0c02c03d 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -573,6 +573,7 @@ E1E4CE0B1773C59B00430844 /* WPAvatarSource.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E4CE0A1773C59B00430844 /* WPAvatarSource.m */; }; E1E4CE0D177439D100430844 /* WPAvatarSourceTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E1E4CE0C177439D100430844 /* WPAvatarSourceTest.m */; }; E1E4CE0F1774563F00430844 /* misteryman.jpg in Resources */ = {isa = PBXBuildFile; fileRef = E1E4CE0E1774531500430844 /* misteryman.jpg */; }; + E1E7CD991C69D3D80051EE99 /* CoreDataAssumptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E7CD981C69D3D80051EE99 /* CoreDataAssumptions.swift */; }; E1EBC36F1C118EA500F638E0 /* ImmuTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1EBC36E1C118EA500F638E0 /* ImmuTable.swift */; }; E1EBC3711C118EB200F638E0 /* WPImmuTableCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1EBC3701C118EB200F638E0 /* WPImmuTableCells.swift */; }; E1EBC3731C118ED200F638E0 /* ImmuTableTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1EBC3721C118ED200F638E0 /* ImmuTableTest.swift */; }; @@ -581,6 +582,7 @@ E1F80825146420B000726BC7 /* UIImageView+Gravatar.m in Sources */ = {isa = PBXBuildFile; fileRef = E1F80824146420B000726BC7 /* UIImageView+Gravatar.m */; }; E1F8E1231B0B411E0073E628 /* JetpackService.m in Sources */ = {isa = PBXBuildFile; fileRef = E1F8E1221B0B411E0073E628 /* JetpackService.m */; }; E1F8E1261B0B422C0073E628 /* JetpackServiceRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = E1F8E1251B0B422C0073E628 /* JetpackServiceRemote.m */; }; + E1FC87B31C61E3490049CEE4 /* Blog+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FC87B21C61E3490049CEE4 /* Blog+CoreDataProperties.swift */; }; E1FD45E01C030B3800750F4C /* AccountSettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FD45DF1C030B3800750F4C /* AccountSettingsService.swift */; }; E240859C183D82AE002EB0EF /* WPAnimatedBox.m in Sources */ = {isa = PBXBuildFile; fileRef = E240859B183D82AE002EB0EF /* WPAnimatedBox.m */; }; E2AA87A518523E5300886693 /* UIView+Subviews.m in Sources */ = {isa = PBXBuildFile; fileRef = E2AA87A418523E5300886693 /* UIView+Subviews.m */; }; @@ -1673,6 +1675,7 @@ E1E4CE0A1773C59B00430844 /* WPAvatarSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPAvatarSource.m; sourceTree = ""; }; E1E4CE0C177439D100430844 /* WPAvatarSourceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPAvatarSourceTest.m; sourceTree = ""; }; E1E4CE0E1774531500430844 /* misteryman.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = misteryman.jpg; sourceTree = ""; }; + E1E7CD981C69D3D80051EE99 /* CoreDataAssumptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataAssumptions.swift; sourceTree = ""; }; E1E977BC17B0FA9A00AFB867 /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = th; path = th.lproj/Localizable.strings; sourceTree = ""; }; E1EBC36E1C118EA500F638E0 /* ImmuTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImmuTable.swift; sourceTree = ""; }; E1EBC3701C118EB200F638E0 /* WPImmuTableCells.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WPImmuTableCells.swift; sourceTree = ""; }; @@ -1686,6 +1689,7 @@ E1F8E1221B0B411E0073E628 /* JetpackService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JetpackService.m; sourceTree = ""; }; E1F8E1241B0B422C0073E628 /* JetpackServiceRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JetpackServiceRemote.h; sourceTree = ""; }; E1F8E1251B0B422C0073E628 /* JetpackServiceRemote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JetpackServiceRemote.m; sourceTree = ""; }; + E1FC87B21C61E3490049CEE4 /* Blog+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Blog+CoreDataProperties.swift"; sourceTree = ""; }; E1FD45DF1C030B3800750F4C /* AccountSettingsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountSettingsService.swift; sourceTree = ""; }; E240859A183D82AE002EB0EF /* WPAnimatedBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WPAnimatedBox.h; sourceTree = ""; }; E240859B183D82AE002EB0EF /* WPAnimatedBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPAnimatedBox.m; sourceTree = ""; }; @@ -2129,6 +2133,7 @@ 5D42A3D9175E7452005CFF05 /* BasePost.m */, CEBD3EA90FF1BA3B00C1396E /* Blog.h */, CEBD3EAA0FF1BA3B00C1396E /* Blog.m */, + E1FC87B21C61E3490049CEE4 /* Blog+CoreDataProperties.swift */, B5D889401BEBE30A007C4684 /* BlogSettings.swift */, B55F1AA71C10936600FD04D4 /* BlogSettings+Discussion.swift */, 83418AA811C9FA6E00ACF00C /* Comment.h */, @@ -3209,6 +3214,7 @@ 93E9050319E6F242005513C9 /* ContextManagerTests.swift */, C5CFDC29184F962B00097B05 /* CoreDataConcurrencyTest.m */, 931D26FF19EDAE8600114F17 /* CoreDataMigrationTests.m */, + E1E7CD981C69D3D80051EE99 /* CoreDataAssumptions.swift */, ); name = "Core Data"; sourceTree = ""; @@ -4850,6 +4856,7 @@ E1A6DBDB19DC7D080071AC1E /* RemotePost.m in Sources */, 082AB9D91C4EEEF4000CA523 /* PostTagService.m in Sources */, E1249B4619408D0F0035E895 /* CommentServiceRemoteXMLRPC.m in Sources */, + E1FC87B31C61E3490049CEE4 /* Blog+CoreDataProperties.swift in Sources */, 85AD6AEF173CCFDC002CB896 /* WPNUXSecondaryButton.m in Sources */, FFC6ADDD1B56F3D2002F3C84 /* ThemeServiceRemote.m in Sources */, B5A6CEA619FA800E009F07DE /* AccountToAccount20to21.swift in Sources */, @@ -5005,6 +5012,7 @@ buildActionMask = 2147483647; files = ( FA9E74481C50382D00C6B1D2 /* SiteManagementServiceRemoteTests.swift in Sources */, + E1E7CD991C69D3D80051EE99 /* CoreDataAssumptions.swift in Sources */, FA4ADADA1C509FE400F858D7 /* SiteManagementServiceTests.swift in Sources */, 5981FE051AB8A89A0009E080 /* WPUserAgentTests.m in Sources */, 59E2AAE81B20E3EA0051DC06 /* ServiceRemoteRESTTests.m in Sources */, diff --git a/WordPress/WordPressTest/BlogJetpackTest.m b/WordPress/WordPressTest/BlogJetpackTest.m index 710cd0aef216..42a7fc8170aa 100644 --- a/WordPress/WordPressTest/BlogJetpackTest.m +++ b/WordPress/WordPressTest/BlogJetpackTest.m @@ -10,6 +10,7 @@ #import "JetpackService.h" #import "JetpackServiceRemote.h" #import "TestContextManager.h" +#import "WordPress-Swift.h" @interface BlogJetpackTest : XCTestCase @end diff --git a/WordPress/WordPressTest/BlogServiceTest.m b/WordPress/WordPressTest/BlogServiceTest.m index 9551039a6bf7..0c59e93d83bf 100644 --- a/WordPress/WordPressTest/BlogServiceTest.m +++ b/WordPress/WordPressTest/BlogServiceTest.m @@ -6,6 +6,7 @@ #import "Blog.h" #import "WPAccount.h" #import "TestContextManager.h" +#import "WordPress-Swift.h" @interface BlogServiceTest : XCTestCase diff --git a/WordPress/WordPressTest/BlogSiteVisibilityHelperTest.m b/WordPress/WordPressTest/BlogSiteVisibilityHelperTest.m index 21c7c9faf92b..4a6ee60d1c86 100644 --- a/WordPress/WordPressTest/BlogSiteVisibilityHelperTest.m +++ b/WordPress/WordPressTest/BlogSiteVisibilityHelperTest.m @@ -5,6 +5,7 @@ #import "BlogSiteVisibilityHelper.h" #import "JetpackState.h" #import "TestContextManager.h" +#import "WordPress-Swift.h" @interface BlogSiteVisibilityHelperTest : XCTestCase @end diff --git a/WordPress/WordPressTest/ContextManagerTests.swift b/WordPress/WordPressTest/ContextManagerTests.swift index 725c2c711913..0693b40dea6a 100644 --- a/WordPress/WordPressTest/ContextManagerTests.swift +++ b/WordPress/WordPressTest/ContextManagerTests.swift @@ -1,6 +1,7 @@ import Foundation import XCTest import CoreData +@testable import WordPress class ContextManagerTests: XCTestCase { var contextManager:TestContextManager! diff --git a/WordPress/WordPressTest/CoreDataAssumptions.swift b/WordPress/WordPressTest/CoreDataAssumptions.swift new file mode 100644 index 000000000000..9bc40585246e --- /dev/null +++ b/WordPress/WordPressTest/CoreDataAssumptions.swift @@ -0,0 +1,138 @@ +import XCTest +import Nimble +@testable import WordPress + +/* +Usually, you should only test your code and not the system frameworks. + +But when you rely on certain behavior that it's either undocumented, or the +documentation doesn't clearly guarantee, it's good to be notified when that +behavior changes. +*/ +class CoreDataAssumptions: XCTestCase { + + func testOptionalStringNilOnCreation() { + let blog = createBlog() + expect(blog.name).to(beNil()) + } + + func testNonOptionalStringIsEmptyOnCreation() { + let category = createCategory() + expect(category.name).to(equal("")) + } + + func testOptionalNumberIsNilOnCreation() { + let category = createCategory() + expect(category.parentID).to(beNil()) + } + + func testNonOptionalNumberIsNilOnCreation() { + let blog = createBlog() + expect(blog.blogID).to(beNil()) + } + + func testNonOptionalCanCastToOptional() { + let blog = createBlog() + let optionalID = blog.blogID as NSNumber? + expect(optionalID).to(beNil()) + } + + func testOptionalRelationshipIsEmptySetOnCreation() { + let blog = createBlog() + expect(blog.categories).toNot(beNil()) + expect(blog.categories).to(beEmpty()) + } + + class TestBlog: NSManagedObject { + @NSManaged var blogID: NSNumber + @NSManaged var name: String? + @NSManaged var categories: Set + } + + class TestCategory: NSManagedObject { + @NSManaged var categoryID: NSNumber + @NSManaged var name: String + @NSManaged var parentID: NSNumber? + @NSManaged var blog: TestBlog + } + + private func createBlog() -> TestBlog { + let context = createManagedObjectContext() + let blog = NSEntityDescription.insertNewObjectForEntityForName("TestBlog", inManagedObjectContext: context) as! TestBlog + return blog + } + + private func createCategory() -> TestCategory { + let context = createManagedObjectContext() + let category = NSEntityDescription.insertNewObjectForEntityForName("TestCategory", inManagedObjectContext: context) as! TestCategory + return category + } + + private func createManagedObjectContext() -> NSManagedObjectContext { + let context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType) + context.persistentStoreCoordinator = persistentStore() + return context + } + + private func persistentStore() -> NSPersistentStoreCoordinator { + let store = NSPersistentStoreCoordinator(managedObjectModel: managedModel()) + try! store.addPersistentStoreWithType(NSInMemoryStoreType, configuration: nil, URL: nil, options: nil) + return store + } + + private func managedModel() -> NSManagedObjectModel { + let model = NSManagedObjectModel() + let blogEntity = NSEntityDescription() + blogEntity.name = "TestBlog" + blogEntity.managedObjectClassName = NSStringFromClass(TestBlog.self) + + let categoryEntity = NSEntityDescription() + categoryEntity.name = "TestCategory" + categoryEntity.managedObjectClassName = NSStringFromClass(TestCategory.self) + + let blogID = NSAttributeDescription() + blogID.name = "blogID" + blogID.attributeType = .Integer64AttributeType + blogID.optional = false + + let blogName = NSAttributeDescription() + blogName.name = "name" + blogName.attributeType = .StringAttributeType + blogName.optional = true + + let categoryID = NSAttributeDescription() + categoryID.name = "categoryID" + categoryID.attributeType = .Integer64AttributeType + categoryID.optional = false + + let categoryName = NSAttributeDescription() + categoryName.name = "name" + categoryName.attributeType = .StringAttributeType + categoryName.optional = false + + let categoryParent = NSAttributeDescription() + categoryParent.name = "parentID" + categoryParent.attributeType = .Integer64AttributeType + categoryParent.optional = true + + let blogCategories = NSRelationshipDescription() + let categoryBlog = NSRelationshipDescription() + blogCategories.name = "categories" + blogCategories.destinationEntity = categoryEntity + blogCategories.deleteRule = .CascadeDeleteRule + blogCategories.inverseRelationship = categoryBlog + categoryBlog.name = "blog" + categoryBlog.destinationEntity = blogEntity + categoryBlog.deleteRule = .NullifyDeleteRule + categoryBlog.minCount = 1 + categoryBlog.maxCount = 1 + categoryBlog.optional = false + categoryBlog.inverseRelationship = blogCategories + + blogEntity.properties = [blogID, blogName, blogCategories] + categoryEntity.properties = [categoryID, categoryName, categoryParent, categoryBlog] + + model.entities = [blogEntity, categoryEntity] + return model + } +} diff --git a/WordPress/WordPressTest/WPAnalyticsTrackerMixpanelTests.m b/WordPress/WordPressTest/WPAnalyticsTrackerMixpanelTests.m index 86aed6147b98..356caff7e637 100644 --- a/WordPress/WordPressTest/WPAnalyticsTrackerMixpanelTests.m +++ b/WordPress/WordPressTest/WPAnalyticsTrackerMixpanelTests.m @@ -10,6 +10,7 @@ #import "BlogService.h" #import "WPAccount.h" #import "Blog.h" +#import "WordPress-Swift.h" SpecBegin(WPAnalyticsTrackerMixpanel)