From a53f7e32197628f28a61b59ad87cc72ef0a3cacc Mon Sep 17 00:00:00 2001 From: Tony Li Date: Thu, 28 Aug 2025 13:40:02 +1200 Subject: [PATCH 01/12] Copy the /Tests in the WordPressKit repo --- .../AppTransportSecuritySettingsTests.swift | 103 + .../CoreAPITests/Bundle+SPMSupport.swift | 25 + .../FakeInfoDictionaryObjectProvider.swift | 21 + .../HTTPRequestBuilderTests.swift | 431 ++ .../CoreAPITests/MultipartFormTests.swift | 152 + .../CoreAPITests/NonceRetrievalTests.swift | 74 + .../CoreAPITests/RSDParserTests.swift | 50 + .../Stubs/HTML/xmlrpc-response-invalid.html | 7 + ...mlrpc-response-mobile-plugin-redirect.html | 8 + ...thenticateWithIDToken2FANeededSuccess.json | 13 + ...enticateWithIDTokenBearerTokenSuccess.json | 13 + ...ithIDTokenExistingUserNeedsConnection.json | 10 + ...ordPressComOAuthAuthenticateSignature.json | 12 + .../JSON/WordPressComOAuthNeeds2FAFail.json | 4 + .../WordPressComOAuthNeedsWebauthnMFA.json | 7 + .../WordPressComOAuthRequestChallenge.json | 33 + .../Stubs/JSON/WordPressComOAuthSuccess.json | 7 + .../WordPressComOAuthWrongPasswordFail.json | 4 + .../WordPressComRestApiFailInvalidInput.json | 4 + .../WordPressComRestApiFailInvalidJSON.json | 4 + ...omRestApiFailReauthenticationRequired.json | 4 + ...ressComRestApiFailRequestInvalidToken.json | 4 + .../WordPressComRestApiFailThrottled.json | 3 + .../WordPressComRestApiFailUnauthorized.json | 4 + .../Stubs/JSON/WordPressComRestApiMedia.json | 868 +++ .../WordPressComRestApiMultipleErrors.json | 8 + .../WordPressComSocial2FACodeSuccess.json | 13 + .../Stubs/JSON/me-settings-success.json | 47 + .../CoreAPITests/Stubs/JSON/wp-forbidden.json | 7 + .../CoreAPITests/Stubs/JSON/wp-pages.json | 729 ++ .../Stubs/JSON/wp-reusable-blocks.json | 50 + .../xmlrpc-bad-username-password-error.xml | 17 + .../Stubs/XML/xmlrpc-response-getpost.xml | 39 + .../XML/xmlrpc-response-list-methods.xml | 91 + .../URLRequest+HTTPBodyText.swift | 11 + .../WordPressComOAuthClientTests.swift | 500 ++ .../WordPressComRestApiTests+Error.swift | 25 + .../WordPressComRestApiTests+Locale.swift | 97 + .../WordPressComRestApiTests.swift | 556 ++ .../CoreAPITests/WordPressOrgAPITests.swift | 204 + .../WordPressOrgRestApiTests.swift | 160 + .../WordPressOrgXMLRPCApiTests.swift | 393 + .../WordPressOrgXMLRPCValidatorTests.swift | 389 + .../WordPressKitTests/Info.plist | 22 + ...p_v2_themes_twentytwentyone-no-colors.json | 197 + .../get_wp_v2_themes_twentytwentyone.json | 248 + ...itor-v1-settings-success-NotThemeJSON.json | 605 ++ ...-editor-v1-settings-success-ThemeJSON.json | 886 +++ .../Domains/get-all-domains-response.json | 180 + .../activity-groups-bad-json-failure.json | 4 + .../Mock Data/activity-groups-success.json | 22 + .../Mock Data/activity-log-auth-failure.json | 4 + .../activity-log-bad-json-failure.json | 28 + .../Mock Data/activity-log-success-1.json | 298 + .../Mock Data/activity-log-success-2.json | 716 ++ .../Mock Data/activity-log-success-3.json | 681 ++ .../Mock Data/activity-restore-success.json | 6 + ...ctivity-rewind-status-restore-failure.json | 11 + ...tivity-rewind-status-restore-finished.json | 10 + ...ity-rewind-status-restore-in-progress.json | 10 + ...activity-rewind-status-restore-queued.json | 11 + .../activity-rewind-status-success.json | 12 + .../atomic-get-auth-cookie-success.json | 12 + ...nd-login-email-invalid-client-failure.json | 4 + ...nd-login-email-invalid-secret-failure.json | 4 + ...auth-send-login-email-no-user-failure.json | 4 + .../auth-send-login-email-success.json | 3 + ...cation-email-already-verified-failure.json | 4 + .../auth-send-verification-email-success.json | 4 + ...-complete-without-download-id-success.json | 9 + .../Mock Data/blaze-campaigns-search.json | 81 + ...ogging-prompts-settings-fetch-success.json | 15 + ...rompts-settings-update-empty-response.json | 3 + ...prompts-settings-update-with-response.json | 17 + .../Mock Data/blogging-prompts-success.json | 30 + .../Mock Data/comment-likes-success.json | 79 + .../comments-v2-edit-context-success.json | 52 + .../comments-v2-view-context-success.json | 44 + ...on-starter-site-designs-empty-designs.json | 54 + ...common-starter-site-designs-malformed.json | 447 ++ .../common-starter-site-designs-success.json | 450 ++ ...d-200-with-drafts-and-scheduled-posts.json | 31 + .../Mock Data/dashboard-400-invalid-card.json | 17 + ...-contact-information-response-success.json | 14 + .../domain-service-all-domain-types.json | 112 + .../Mock Data/domain-service-bad-json.json | 110 + .../Mock Data/domain-service-empty.json | 4 + .../domain-service-invalid-query.json | 4 + .../Mock Data/empty-array.json | 1 + .../WordPressKitTests/Mock Data/empty.json | 1 + .../Mock Data/get-multiple-themes-v1.2.json | 1 + .../Mock Data/get-purchased-themes-v1.1.json | 1 + .../Mock Data/get-single-theme-v1.1.json | 1 + .../Mock Data/is-available-email-failure.json | 5 + .../Mock Data/is-available-email-success.json | 3 + .../is-available-username-failure.json | 5 + .../is-available-username-success.json | 3 + ...passwordless-account-no-account-found.json | 4 + .../is-passwordless-account-success.json | 3 + ...etpack-capabilities-107159616-success.json | 8 + ...jetpack-capabilities-34197361-success.json | 3 + .../jetpack-capabilities-malformed.json | 3 + .../jetpack-scan-enqueue-failure.json | 1 + .../jetpack-scan-enqueue-success.json | 1 + .../jetpack-scan-idle-success-no-threats.json | 21 + .../jetpack-scan-idle-success-threats.json | 96 + .../Mock Data/jetpack-scan-in-progress.json | 19 + .../Mock Data/jetpack-scan-unavailable.json | 14 + ...tpack-service-check-site-failure-data.json | 3 + ...service-check-site-success-no-jetpack.json | 3 + .../jetpack-service-check-site-success.json | 3 + ...pack-service-error-activation-failure.json | 4 + ...pack-service-error-activation-install.json | 4 + ...ack-service-error-activation-response.json | 4 + .../jetpack-service-error-forbidden.json | 4 + ...jetpack-service-error-install-failure.json | 4 + ...etpack-service-error-install-response.json | 4 + ...ack-service-error-invalid-credentials.json | 4 + .../jetpack-service-error-login-failure.json | 4 + ...jetpack-service-error-site-is-jetpack.json | 4 + .../jetpack-service-error-unknown.json | 4 + .../Mock Data/jetpack-service-failure.json | 3 + .../Mock Data/jetpack-service-success.json | 3 + .../Mock Data/jetpack-social-403.json | 7 + .../jetpack-social-no-publicize.json | 5 + .../jetpack-social-with-publicize.json | 10 + .../Mock Data/me-auth-failure.json | 4 + .../Mock Data/me-bad-json-failure.json | 34 + .../me-settings-close-account-failure.json | 4 + .../me-settings-close-account-success.json | 3 + .../Mock Data/me-sites-auth-failure.json | 4 + .../Mock Data/me-sites-bad-json-failure.json | 158 + .../Mock Data/me-sites-empty-success.json | 3 + .../Mock Data/me-sites-success.json | 518 ++ .../me-sites-visibility-bad-json-failure.json | 2 + .../me-sites-visibility-failure.json | 4 + .../me-sites-visibility-success.json | 3 + .../Mock Data/me-success.json | 34 + .../Mock Data/notifications-last-seen.json | 4 + .../Mock Data/notifications-load-all.json | 100 + .../Mock Data/notifications-load-hash.json | 35 + .../Mock Data/notifications-mark-as-read.json | 4 + .../page-layout-blog-layouts-malformed.json | 14 + .../page-layout-blog-layouts-success.json | 1 + .../people-send-invitation-failure.json | 11 + .../people-send-invitation-success.json | 4 + .../people-validate-invitation-failure.json | 11 + .../people-validate-invitation-success.json | 4 + .../Mock Data/plans-me-sites-success.json | 44 + .../Mock Data/plans-mobile-success.json | 390 + .../plugin-directory-jetpack-beta.json | 224 + .../Mock Data/plugin-directory-jetpack.json | 223 + .../Mock Data/plugin-directory-new.json | 2265 ++++++ .../Mock Data/plugin-directory-popular.json | 6546 +++++++++++++++++ .../plugin-directory-rename-xml-rpc.json | 51 + .../plugin-install-already-installed.json | 4 + .../plugin-install-generic-error.json | 4 + .../Mock Data/plugin-install-succeeds.json | 15 + .../plugin-modify-malformed-response.json | 5 + .../plugin-service-remote-auth-failure.json | 4 + ...gin-service-remote-featured-malformed.json | 3 + ...rvice-remote-featured-plugins-invalid.json | 6 + .../plugin-service-remote-featured.json | 62 + .../plugin-state-contact-form-7.json | 14 + .../Mock Data/plugin-state-jetpack.json | 20 + .../plugin-update-gutenberg-needs-update.json | 33 + ...plugin-update-jetpack-already-updated.json | 18 + .../plugin-update-response-malformed.json | 5 + .../post-autosave-mapping-success.json | 38 + .../Mock Data/post-likes-failure.json | 4 + .../Mock Data/post-likes-success.json | 82 + .../Mock Data/post-revisions-failure.json | 4 + .../post-revisions-mapping-success.json | 57 + .../Mock Data/post-revisions-success.json | 128 + .../Mock Data/qrlogin-authenticate-200.json | 4 + .../qrlogin-authenticate-failed-400.json | 7 + .../Mock Data/qrlogin-validate-200.json | 5 + .../Mock Data/qrlogin-validate-400.json | 7 + .../qrlogin-validate-expired-401.json | 7 + .../Mock Data/reader-cards-success.json | 2098 ++++++ .../Mock Data/reader-following-mine.json | 153 + .../Mock Data/reader-interests-success.json | 7 + ...eader-post-comments-subscribe-failure.json | 4 + ...eader-post-comments-subscribe-success.json | 4 + ...-comments-subscription-status-success.json | 4 + ...der-post-comments-unsubscribe-success.json | 4 + ...-comments-update-notification-success.json | 4 + .../reader-post-related-posts-success.json | 1411 ++++ .../Mock Data/reader-posts-success.json | 2945 ++++++++ .../reader-site-search-blog-id-fallback.json | 99 + .../Mock Data/reader-site-search-failure.json | 192 + ...reader-site-search-no-blog-or-feed-id.json | 192 + .../reader-site-search-success-hasmore.json | 194 + .../reader-site-search-success-no-data.json | 29 + .../reader-site-search-success-no-icon.json | 96 + .../Mock Data/reader-site-search-success.json | 194 + .../Mock Data/remote-notification.json | 149 + .../Mock Data/rest-site-settings.json | 80 + .../Mock Data/self-hosted-plugins-get.json | 98 + .../self-hosted-plugins-install.json | 25 + .../Mock Data/share-app-content-success.json | 5 + .../site-active-purchases-auth-failure.json | 4 + ...ite-active-purchases-bad-json-failure.json | 44 + .../site-active-purchases-empty-response.json | 1 + ...-active-purchases-none-active-success.json | 91 + ...e-active-purchases-two-active-success.json | 91 + .../Mock Data/site-comment-success.json | 38 + .../Mock Data/site-comments-success.json | 44 + .../Mock Data/site-creation-success.json | 9 + .../Mock Data/site-delete-auth-failure.json | 4 + .../site-delete-bad-json-failure.json | 121 + .../site-delete-missing-status-failure.json | 121 + .../Mock Data/site-delete-success.json | 122 + .../site-delete-unexpected-json-failure.json | 1 + ...site-email-followers-get-auth-failure.json | 4 + .../site-email-followers-get-failure.json | 4 + ...mail-followers-get-success-more-pages.json | 17 + .../site-email-followers-get-success.json | 17 + .../Mock Data/site-export-auth-failure.json | 4 + .../site-export-bad-json-failure.json | 1 + .../Mock Data/site-export-failure.json | 1 + .../site-export-missing-status-failure.json | 1 + .../Mock Data/site-export-success.json | 1 + .../site-followers-delete-auth-failure.json | 4 + ...ite-followers-delete-bad-json-failure.json | 3 + .../site-followers-delete-failure.json | 4 + .../site-followers-delete-success.json | 4 + .../site-plans-bad-json-failure.json | 311 + .../site-plans-v3-bad-json-failure.json | 93 + .../site-plans-v3-empty-failure.json | 1 + .../Mock Data/site-plans-v3-success.json | 108 + .../Mock Data/site-plugins-error.json | 1 + .../Mock Data/site-plugins-malformed.json | 11 + .../Mock Data/site-plugins-success.json | 159 + .../Mock Data/site-quick-start-failure.json | 4 + .../Mock Data/site-quick-start-success.json | 3 + .../Mock Data/site-roles-auth-failure.json | 4 + .../site-roles-bad-json-failure.json | 127 + .../Mock Data/site-roles-success.json | 128 + .../Mock Data/site-segments-multiple.json | 56 + .../Mock Data/site-segments-single.json | 9 + ...-get-details-response-invalid-country.json | 15 + .../site-subscriber-get-details-response.json | 43 + .../site-subscriber-stats-response.json | 6 + .../Mock Data/site-subscribers-response.json | 20 + .../site-users-delete-auth-failure.json | 4 + .../site-users-delete-bad-json-failure.json | 2 + .../site-users-delete-not-member-failure.json | 4 + .../site-users-delete-site-owner-failure.json | 4 + .../Mock Data/site-users-delete-success.json | 3 + ...te-users-update-role-bad-json-failure.json | 13 + .../site-users-update-role-success.json | 14 + ...sers-update-role-unknown-site-failure.json | 4 + ...sers-update-role-unknown-user-failure.json | 4 + .../Mock Data/site-verticals-empty.json | 1 + .../Mock Data/site-verticals-multiple.json | 51 + .../Mock Data/site-verticals-prompt.json | 5 + .../Mock Data/site-verticals-single.json | 12 + .../site-viewers-delete-auth-failure.json | 4 + .../site-viewers-delete-bad-json.json | 3 + .../site-viewers-delete-failure.json | 4 + .../site-viewers-delete-success.json | 4 + .../site-zendesk-metadata-success.json | 5 + .../Mock Data/sites-external-services.json | 37 + .../sites-invites-links-disable-empty.json | 1 + .../sites-invites-links-disable.json | 7 + .../sites-invites-links-generate.json | 32 + .../Mock Data/sites-invites.json | 196 + .../Mock Data/sites-site-active-features.json | 163 + .../sites-site-no-active-features.json | 159 + .../Mock Data/stats-archives-data.json | 70 + .../Mock Data/stats-clicks-data.json | 231 + .../Mock Data/stats-countries-data.json | 113 + .../Mock Data/stats-email-opens.json | 6 + .../Mock Data/stats-emails-summary.json | 38 + .../Mock Data/stats-file-downloads.json | 20 + .../Mock Data/stats-post-details.json | 5454 ++++++++++++++ .../Mock Data/stats-posts-data.json | 102 + .../Mock Data/stats-published-posts.json | 20 + .../Mock Data/stats-referrer-data.json | 313 + .../stats-referrer-mark-as-spam.json | 3 + .../Mock Data/stats-search-term-result.json | 49 + .../Mock Data/stats-streak-result.json | 49 + .../Mock Data/stats-subscribers.json | 921 +++ .../Mock Data/stats-summary.json | 10 + .../Mock Data/stats-top-authors.json | 455 ++ .../Mock Data/stats-videos-data.json | 72 + .../Mock Data/stats-visits-day.json | 105 + .../Mock Data/stats-visits-hourly.json | 182 + .../stats-visits-month-unit-week.json | 60 + .../Mock Data/stats-visits-month.json | 83 + .../Mock Data/stats-visits-week.json | 105 + .../supported-countries-success.json | 1 + .../Mock Data/supported-states-empty.json | 1 + .../Mock Data/supported-states-success.json | 1 + .../Mock Data/timezones.json | 1 + ...ain-contact-information-response-fail.json | 13 + ...-contact-information-response-success.json | 3 + .../Mock Data/videopress-private-video.json | 19 + .../Mock Data/videopress-public-video.json | 19 + .../videopress-site-default-video.json | 19 + .../Mock Data/videopress-token.json | 3 + .../Mock Data/wp-admin-post-new.html | 18 + .../xmlrpc-malformed-request-xml-error.xml | 21 + ...pc-metaweblog-editpost-bad-xml-failure.xml | 9 + ...aweblog-editpost-change-format-failure.xml | 21 + ...etaweblog-editpost-change-type-failure.xml | 21 + .../xmlrpc-metaweblog-editpost-success.xml | 10 + ...rpc-metaweblog-newpost-bad-xml-failure.xml | 9 + ...eblog-newpost-invalid-posttype-failure.xml | 21 + .../xmlrpc-metaweblog-newpost-success.xml | 10 + .../Mock Data/xmlrpc-response-getprofile.xml | 136 + ...sponse-valid-but-unexpected-dictionary.xml | 20 + .../Mock Data/xmlrpc-site-comment-success.xml | 25 + .../xmlrpc-site-comments-success.xml | 31 + .../xmlrpc-wp-getpost-bad-xml-failure.xml | 50 + .../xmlrpc-wp-getpost-invalid-id-failure.xml | 17 + .../Mock Data/xmlrpc-wp-getpost-success.xml | 51 + .../Tests/AccountServiceRemoteRESTTests.swift | 754 ++ .../Tests/AccountSettingsRemoteTests.swift | 330 + .../Tests/ActivityServiceRemoteTests.swift | 442 ++ .../Tests/ActivityTests.swift | 89 + .../Tests/AllDomainsResultDomainTests.swift | 163 + .../AnnouncementServiceRemoteTests.swift | 27 + ...omicAuthenticationServiceRemoteTests.swift | 38 + .../Tests/BlazeServiceRemoteTests.swift | 96 + ...lockEditorSettingsServiceRemoteTests.swift | 337 + ...logServiceRemote+ActiveFeaturesTests.swift | 49 + .../Tests/BlogServiceRemoteRESTTests.m | 206 + .../BloggingPromptsServiceRemoteTests.swift | 213 + .../CommentServiceRemoteREST+APIv2Tests.swift | 160 + .../CommentServiceRemoteRESTLikesTests.swift | 103 + .../Tests/CommentServiceRemoteRESTTests.swift | 113 + .../CommentServiceRemoteXMLRPCTests.swift | 100 + .../Tests/DashboardServiceRemoteTests.swift | 134 + .../Tests/Date+WordPressComTests.swift | 36 + .../DateFormatter+WordPressComTests.swift | 13 + .../Tests/DomainsServiceRemoteRESTTests.swift | 328 + .../Tests/DynamicMockProvider.swift | 50 + .../Tests/EditorServiceRemoteTests.swift | 247 + .../Decodable+DictionaryTests.swift | 45 + .../Tests/IPLocationRemoteTests.swift | 80 + .../WordPressKitTests/Tests/JSONLoader.swift | 61 + .../JetpackBackupServiceRemoteTests.swift | 171 + ...etpackCapabilitiesServiceRemoteTests.swift | 48 + .../JetpackProxyServiceRemoteTests.swift | 122 + .../Tests/JetpackServiceRemoteTests.swift | 260 + .../Tests/LoadMediaLibraryTests.swift | 110 + .../Tests/MediaLibraryTestSupport.swift | 200 + .../Tests/MediaServiceRemoteRESTTests.swift | 453 ++ .../Tests/MenusServiceRemoteTests.m | 126 + .../MockPluginDirectoryEntryProvider.swift | 77 + .../Tests/MockPluginStateProvider.swift | 129 + .../Tests/MockServiceRequest.swift | 12 + .../Tests/MockWordPressComRestApi.swift | 73 + .../Tests/Models/RemotePersonTests.swift | 65 + .../Models/RemoteVideoPressVideoTests.swift | 82 + .../Emails/StatsEmailsSummaryDataTests.swift | 27 + .../MockData/stats-insight-comments.json | 71 + .../MockData/stats-insight-followers.json | 138 + .../MockData/stats-insight-last-post.json | 203 + .../MockData/stats-insight-publicize.json | 8 + .../MockData/stats-insight-streak.json | 157 + .../MockData/stats-insight-summary.json | 10 + .../stats-insight-tag-and-category.json | 105 + .../V2/Insights/MockData/stats-insight.json | 94 + .../Stats/V2/Insights/MockData/stats.json | 277 + .../StatsDotComFollowersInsightTests.swift | 121 + .../Insights/StatsInsightDecodingTests.swift | 38 + .../V2/StatsSubscribersSummaryDataTests.swift | 24 + .../Tests/NSDate+WordPressComTests.swift | 29 + .../NotificationSyncServiceRemoteTests.swift | 176 + .../Tests/PageLayoutServiceRemoteTests.swift | 75 + .../Tests/PeopleServiceRemoteTests.swift | 797 ++ .../Tests/PlanServiceRemoteTests.swift | 333 + .../Tests/PluginDirectoryTests.swift | 360 + .../Tests/PluginServiceRemoteTests.swift | 529 ++ .../Tests/PluginStateTests.swift | 228 + .../PostServiceRemoteRESTAutosaveTests.swift | 52 + .../PostServiceRemoteRESTLikesTests.swift | 103 + .../PostServiceRemoteRESTRevisionsTest.swift | 122 + .../Tests/PostServiceRemoteRESTTests.m | 401 + .../Tests/PostServiceRemoteXMLRPCTests.swift | 414 ++ ...PushAuthenticationServiceRemoteTests.swift | 57 + .../Tests/QRLoginServiceRemoteTests.swift | 124 + .../Tests/RESTTestable.swift | 13 + .../ReaderPostServiceRemote+CardsTests.swift | 325 + ...PostServiceRemote+FetchEndpointTests.swift | 41 + ...rPostServiceRemote+RelatedPostsTests.swift | 59 + ...rPostServiceRemote+SubscriptionTests.swift | 168 + .../Tests/ReaderPostServiceRemoteTests.m | 100 + .../ReaderSiteSearchServiceRemoteTests.swift | 230 + .../Tests/ReaderSiteServiceRemoteTests.swift | 353 + ...derTopicServiceRemote+InterestsTests.swift | 85 + ...TopicServiceRemoteTest+Subscriptions.swift | 110 + .../Tests/ReaderTopicServiceRemoteTests.swift | 71 + .../Tests/RemoteNotificationTests.swift | 66 + .../Tests/RemoteReaderPostTests+V2.swift | 65 + .../Tests/RemoteReaderPostTests.m | 360 + ...emoteReaderSiteInfoSubscriptionTests.swift | 20 + .../Tests/RemoteTestCase.swift | 237 + .../Scan/JetpackScanServiceRemoteTests.swift | 243 + ...elfHostedPluginManagementClientTests.swift | 115 + .../Tests/ServiceRequestTest.swift | 37 + .../ShareAppContentServiceRemoteTests.swift | 100 + .../Tests/SharingServiceRemoteTests.swift | 130 + .../SiteCreationRequestEncodingTests.swift | 274 + .../SiteCreationResponseDecodingTests.swift | 32 + .../Tests/SiteCreationSegmentsTests.swift | 34 + .../Tests/SiteDesignServiceRemoteTests.swift | 78 + .../SiteManagementServiceRemoteTests.swift | 466 ++ .../Tests/SitePluginTests.swift | 19 + .../SiteSegmentsResponseDecodingTests.swift | 53 + ...VerticalsPromptResponseDecodingTests.swift | 32 + .../SiteVerticalsRequestEncodingTests.swift | 98 + .../SiteVerticalsResponseDecodingTests.swift | 131 + .../JetpackSocialServiceRemoteTests.swift | 79 + ...dMostPopularTimeInsightDecodingTests.swift | 54 + .../Tests/StatsRemoteV2Tests.swift | 857 +++ .../Tests/SubscribersServiceRemoteTests.swift | 58 + .../Tests/TaxonomyServiceRemoteRESTTests.m | 318 + .../Tests/TestCollector+Constants.swift | 7 + .../Tests/ThemeServiceRemoteTests.m | 367 + .../Tests/TimeZoneServiceRemoteTests.swift | 55 + .../TransactionsServiceRemoteTests.swift | 33 + .../Tests/UsersServiceRemoteXMLRPCTests.swift | 90 + .../Tests/Utilities/ChecksumUtilTests.swift | 24 + .../Utilities/FeatureFlagRemoteTests.swift | 127 + .../FeatureFlagSerializationTest.swift | 14 + .../Utilities/HTTPBodyEncodingTests.swift | 24 + .../HTTPHeaderValueParserTests.swift | 79 + .../Tests/Utilities/LoggingTests.m | 85 + .../Tests/Utilities/LoggingTests.swift | 70 + .../Utilities/RemoteConfigRemoteTests.swift | 94 + .../Utilities/URLSessionHelperTests.swift | 420 ++ .../Utilities/WordPressAPIErrorTests.swift | 43 + .../WordPressComServiceRemoteRestTests.swift | 77 + ...ssComServiceRemoteTests+SiteCreation.swift | 55 + ...sComServiceRemoteTests+SiteVerticals.swift | 37 + ...rviceRemoteTests+SiteVerticalsPrompt.swift | 25 + .../Tests/XMLRPCTestable.swift | 27 + .../WordPressKitTests/UnitTests.xctestplan | 66 + .../WordPressKitTests-Bridging-Header.h | 4 + 443 files changed, 60407 insertions(+) create mode 100644 Tests/WordPressKitTests/CoreAPITests/AppTransportSecuritySettingsTests.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/Bundle+SPMSupport.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/FakeInfoDictionaryObjectProvider.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/HTTPRequestBuilderTests.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/MultipartFormTests.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/NonceRetrievalTests.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/RSDParserTests.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/HTML/xmlrpc-response-invalid.html create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/HTML/xmlrpc-response-mobile-plugin-redirect.html create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComAuthenticateWithIDToken2FANeededSuccess.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComAuthenticateWithIDTokenBearerTokenSuccess.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComAuthenticateWithIDTokenExistingUserNeedsConnection.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthAuthenticateSignature.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthNeeds2FAFail.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthNeedsWebauthnMFA.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthRequestChallenge.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthSuccess.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthWrongPasswordFail.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailInvalidInput.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailInvalidJSON.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailReauthenticationRequired.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailRequestInvalidToken.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailThrottled.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailUnauthorized.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiMedia.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiMultipleErrors.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComSocial2FACodeSuccess.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/me-settings-success.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/wp-forbidden.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/wp-pages.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/wp-reusable-blocks.json create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/XML/xmlrpc-bad-username-password-error.xml create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/XML/xmlrpc-response-getpost.xml create mode 100644 Tests/WordPressKitTests/CoreAPITests/Stubs/XML/xmlrpc-response-list-methods.xml create mode 100644 Tests/WordPressKitTests/CoreAPITests/URLRequest+HTTPBodyText.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/WordPressComOAuthClientTests.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/WordPressComRestApiTests+Error.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/WordPressComRestApiTests+Locale.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/WordPressComRestApiTests.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/WordPressOrgAPITests.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/WordPressOrgRestApiTests.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/WordPressOrgXMLRPCApiTests.swift create mode 100644 Tests/WordPressKitTests/CoreAPITests/WordPressOrgXMLRPCValidatorTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Info.plist create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/BlockEditorSettings/get_wp_v2_themes_twentytwentyone-no-colors.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/BlockEditorSettings/get_wp_v2_themes_twentytwentyone.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/BlockEditorSettings/wp-block-editor-v1-settings-success-NotThemeJSON.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/BlockEditorSettings/wp-block-editor-v1-settings-success-ThemeJSON.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/Domains/get-all-domains-response.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-groups-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-groups-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-log-auth-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-log-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-log-success-1.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-log-success-2.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-log-success-3.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-restore-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-rewind-status-restore-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-rewind-status-restore-finished.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-rewind-status-restore-in-progress.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-rewind-status-restore-queued.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/activity-rewind-status-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/atomic-get-auth-cookie-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/auth-send-login-email-invalid-client-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/auth-send-login-email-invalid-secret-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/auth-send-login-email-no-user-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/auth-send-login-email-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/auth-send-verification-email-already-verified-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/auth-send-verification-email-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/backup-get-backup-status-complete-without-download-id-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/blaze-campaigns-search.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/blogging-prompts-settings-fetch-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/blogging-prompts-settings-update-empty-response.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/blogging-prompts-settings-update-with-response.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/blogging-prompts-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/comment-likes-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/comments-v2-edit-context-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/comments-v2-view-context-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/common-starter-site-designs-empty-designs.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/common-starter-site-designs-malformed.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/common-starter-site-designs-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/dashboard-200-with-drafts-and-scheduled-posts.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/dashboard-400-invalid-card.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/domain-contact-information-response-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/domain-service-all-domain-types.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/domain-service-bad-json.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/domain-service-empty.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/domain-service-invalid-query.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/empty-array.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/empty.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/get-multiple-themes-v1.2.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/get-purchased-themes-v1.1.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/get-single-theme-v1.1.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/is-available-email-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/is-available-email-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/is-available-username-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/is-available-username-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/is-passwordless-account-no-account-found.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/is-passwordless-account-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-capabilities-107159616-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-capabilities-34197361-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-capabilities-malformed.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-scan-enqueue-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-scan-enqueue-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-scan-idle-success-no-threats.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-scan-idle-success-threats.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-scan-in-progress.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-scan-unavailable.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-check-site-failure-data.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-check-site-success-no-jetpack.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-check-site-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-error-activation-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-error-activation-install.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-error-activation-response.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-error-forbidden.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-error-install-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-error-install-response.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-error-invalid-credentials.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-error-login-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-error-site-is-jetpack.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-error-unknown.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-service-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-social-403.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-social-no-publicize.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/jetpack-social-with-publicize.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/me-auth-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/me-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/me-settings-close-account-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/me-settings-close-account-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/me-sites-auth-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/me-sites-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/me-sites-empty-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/me-sites-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/me-sites-visibility-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/me-sites-visibility-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/me-sites-visibility-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/me-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/notifications-last-seen.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/notifications-load-all.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/notifications-load-hash.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/notifications-mark-as-read.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/page-layout-blog-layouts-malformed.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/page-layout-blog-layouts-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/people-send-invitation-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/people-send-invitation-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/people-validate-invitation-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/people-validate-invitation-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plans-me-sites-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plans-mobile-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-directory-jetpack-beta.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-directory-jetpack.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-directory-new.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-directory-popular.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-directory-rename-xml-rpc.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-install-already-installed.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-install-generic-error.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-install-succeeds.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-modify-malformed-response.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-service-remote-auth-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-service-remote-featured-malformed.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-service-remote-featured-plugins-invalid.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-service-remote-featured.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-state-contact-form-7.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-state-jetpack.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-update-gutenberg-needs-update.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-update-jetpack-already-updated.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/plugin-update-response-malformed.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/post-autosave-mapping-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/post-likes-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/post-likes-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/post-revisions-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/post-revisions-mapping-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/post-revisions-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/qrlogin-authenticate-200.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/qrlogin-authenticate-failed-400.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/qrlogin-validate-200.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/qrlogin-validate-400.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/qrlogin-validate-expired-401.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-cards-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-following-mine.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-interests-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-post-comments-subscribe-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-post-comments-subscribe-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-post-comments-subscription-status-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-post-comments-unsubscribe-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-post-comments-update-notification-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-post-related-posts-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-posts-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-site-search-blog-id-fallback.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-site-search-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-site-search-no-blog-or-feed-id.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-site-search-success-hasmore.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-site-search-success-no-data.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-site-search-success-no-icon.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/reader-site-search-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/remote-notification.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/rest-site-settings.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/self-hosted-plugins-get.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/self-hosted-plugins-install.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/share-app-content-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-active-purchases-auth-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-active-purchases-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-active-purchases-empty-response.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-active-purchases-none-active-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-active-purchases-two-active-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-comment-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-comments-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-creation-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-delete-auth-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-delete-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-delete-missing-status-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-delete-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-delete-unexpected-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-email-followers-get-auth-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-email-followers-get-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-email-followers-get-success-more-pages.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-email-followers-get-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-export-auth-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-export-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-export-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-export-missing-status-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-export-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-followers-delete-auth-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-followers-delete-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-followers-delete-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-followers-delete-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-plans-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-plans-v3-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-plans-v3-empty-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-plans-v3-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-plugins-error.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-plugins-malformed.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-plugins-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-quick-start-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-quick-start-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-roles-auth-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-roles-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-roles-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-segments-multiple.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-segments-single.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-subscriber-get-details-response-invalid-country.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-subscriber-stats-response.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-subscribers-response.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-users-delete-auth-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-users-delete-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-users-delete-not-member-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-users-delete-site-owner-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-users-delete-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-users-update-role-bad-json-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-users-update-role-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-users-update-role-unknown-site-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-users-update-role-unknown-user-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-verticals-empty.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-verticals-multiple.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-verticals-prompt.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-verticals-single.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-viewers-delete-auth-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-viewers-delete-bad-json.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-viewers-delete-failure.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-viewers-delete-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/site-zendesk-metadata-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/sites-external-services.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/sites-invites-links-disable-empty.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/sites-invites-links-disable.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/sites-invites-links-generate.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/sites-invites.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/sites-site-active-features.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/sites-site-no-active-features.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-archives-data.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-clicks-data.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-countries-data.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-email-opens.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-emails-summary.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-file-downloads.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-post-details.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-posts-data.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-published-posts.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-referrer-data.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-referrer-mark-as-spam.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-search-term-result.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-streak-result.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-subscribers.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-summary.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-top-authors.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-videos-data.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-visits-day.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-visits-hourly.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-visits-month-unit-week.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-visits-month.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/stats-visits-week.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/supported-countries-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/supported-states-empty.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/supported-states-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/timezones.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/validate-domain-contact-information-response-fail.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/validate-domain-contact-information-response-success.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/videopress-private-video.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/videopress-public-video.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/videopress-site-default-video.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/videopress-token.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/wp-admin-post-new.html create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-malformed-request-xml-error.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-metaweblog-editpost-bad-xml-failure.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-metaweblog-editpost-change-format-failure.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-metaweblog-editpost-change-type-failure.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-metaweblog-editpost-success.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-metaweblog-newpost-bad-xml-failure.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-metaweblog-newpost-invalid-posttype-failure.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-metaweblog-newpost-success.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-response-getprofile.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-response-valid-but-unexpected-dictionary.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-site-comment-success.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-site-comments-success.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-wp-getpost-bad-xml-failure.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-wp-getpost-invalid-id-failure.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Mock Data/xmlrpc-wp-getpost-success.xml create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/AccountServiceRemoteRESTTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/AccountSettingsRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ActivityServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ActivityTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/AllDomainsResultDomainTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/AnnouncementServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/AtomicAuthenticationServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/BlazeServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/BlockEditorSettingsServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/BlogServiceRemote+ActiveFeaturesTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/BlogServiceRemoteRESTTests.m create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/BloggingPromptsServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/CommentServiceRemoteREST+APIv2Tests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/CommentServiceRemoteRESTLikesTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/CommentServiceRemoteRESTTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/CommentServiceRemoteXMLRPCTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/DashboardServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Date+WordPressComTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/DateFormatter+WordPressComTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/DomainsServiceRemoteRESTTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/DynamicMockProvider.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/EditorServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Extensions/Decodable+DictionaryTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/IPLocationRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/JSONLoader.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/JetpackBackupServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/JetpackCapabilitiesServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/JetpackProxyServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/JetpackServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/LoadMediaLibraryTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/MediaLibraryTestSupport.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/MediaServiceRemoteRESTTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/MenusServiceRemoteTests.m create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/MockPluginDirectoryEntryProvider.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/MockPluginStateProvider.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/MockServiceRequest.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/MockWordPressComRestApi.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/RemotePersonTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/RemoteVideoPressVideoTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/Emails/StatsEmailsSummaryDataTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/Insights/MockData/stats-insight-comments.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/Insights/MockData/stats-insight-followers.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/Insights/MockData/stats-insight-last-post.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/Insights/MockData/stats-insight-publicize.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/Insights/MockData/stats-insight-streak.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/Insights/MockData/stats-insight-summary.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/Insights/MockData/stats-insight-tag-and-category.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/Insights/MockData/stats-insight.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/Insights/MockData/stats.json create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/Insights/StatsDotComFollowersInsightTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/Insights/StatsInsightDecodingTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Models/Stats/V2/StatsSubscribersSummaryDataTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/NSDate+WordPressComTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/NotificationSyncServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/PageLayoutServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/PeopleServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/PlanServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/PluginDirectoryTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/PluginServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/PluginStateTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/PostServiceRemoteRESTAutosaveTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/PostServiceRemoteRESTLikesTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/PostServiceRemoteRESTRevisionsTest.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/PostServiceRemoteRESTTests.m create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/PostServiceRemoteXMLRPCTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/PushAuthenticationServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/QRLoginServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/RESTTestable.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ReaderPostServiceRemote+CardsTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ReaderPostServiceRemote+FetchEndpointTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ReaderPostServiceRemote+RelatedPostsTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ReaderPostServiceRemote+SubscriptionTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ReaderPostServiceRemoteTests.m create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ReaderSiteSearchServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ReaderSiteServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ReaderTopicServiceRemote+InterestsTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ReaderTopicServiceRemoteTest+Subscriptions.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ReaderTopicServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/RemoteNotificationTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/RemoteReaderPostTests+V2.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/RemoteReaderPostTests.m create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/RemoteReaderSiteInfoSubscriptionTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/RemoteTestCase.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Scan/JetpackScanServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SelfHostedPluginManagementClientTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ServiceRequestTest.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ShareAppContentServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SharingServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SiteCreationRequestEncodingTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SiteCreationResponseDecodingTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SiteCreationSegmentsTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SiteDesignServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SiteManagementServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SitePluginTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SiteSegmentsResponseDecodingTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SiteVerticalsPromptResponseDecodingTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SiteVerticalsRequestEncodingTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SiteVerticalsResponseDecodingTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Social/JetpackSocialServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/StatsAnnualAndMostPopularTimeInsightDecodingTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/StatsRemoteV2Tests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/TaxonomyServiceRemoteRESTTests.m create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/TestCollector+Constants.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/TimeZoneServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/TransactionsServiceRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/UsersServiceRemoteXMLRPCTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Utilities/ChecksumUtilTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Utilities/FeatureFlagRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Utilities/FeatureFlagSerializationTest.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Utilities/HTTPBodyEncodingTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Utilities/HTTPHeaderValueParserTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Utilities/LoggingTests.m create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Utilities/LoggingTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Utilities/RemoteConfigRemoteTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Utilities/URLSessionHelperTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/Utilities/WordPressAPIErrorTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/WordPressComServiceRemoteRestTests.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/WordPressComServiceRemoteTests+SiteCreation.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/WordPressComServiceRemoteTests+SiteVerticals.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/WordPressComServiceRemoteTests+SiteVerticalsPrompt.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/Tests/XMLRPCTestable.swift create mode 100644 Tests/WordPressKitTests/WordPressKitTests/UnitTests.xctestplan create mode 100644 Tests/WordPressKitTests/WordPressKitTests/WordPressKitTests-Bridging-Header.h diff --git a/Tests/WordPressKitTests/CoreAPITests/AppTransportSecuritySettingsTests.swift b/Tests/WordPressKitTests/CoreAPITests/AppTransportSecuritySettingsTests.swift new file mode 100644 index 000000000000..0fd612fccfc0 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/AppTransportSecuritySettingsTests.swift @@ -0,0 +1,103 @@ +import XCTest +#if SWIFT_PACKAGE +@testable import CoreAPI +#else +@testable import WordPressKit +#endif + +final class AppTransportSecuritySettingsTests: XCTestCase { + + private var exampleURL = URL(string: "https://example.com")! + + func testReturnsTrueIfAllowsLocalNetworkingIsTrue() throws { + // Given + let provider = FakeInfoDictionaryObjectProvider(appTransportSecurity: [ + "NSAllowsLocalNetworking": true, + // This will be ignored + "NSAllowsArbitraryLoads": true + ]) + let appTransportSecurity = AppTransportSecuritySettings(provider) + + // When + let secureAccessOnly = appTransportSecurity.secureAccessOnly(for: exampleURL) + + // Then + XCTAssertTrue(secureAccessOnly) + } + + func testReturnsFalseIfAllowsArbitraryLoadsIsTrue() throws { + // Given + let provider = FakeInfoDictionaryObjectProvider(appTransportSecurity: [ + "NSAllowsArbitraryLoads": true + ]) + let appTransportSecurity = AppTransportSecuritySettings(provider) + + // When + let secureAccessOnly = appTransportSecurity.secureAccessOnly(for: exampleURL) + + // Then + XCTAssertFalse(secureAccessOnly) + } + + func testReturnsTrueByDefault() throws { + // Given + let provider = FakeInfoDictionaryObjectProvider(appTransportSecurity: nil) + let appTransportSecurity = AppTransportSecuritySettings(provider) + + // When + let secureAccessOnly = appTransportSecurity.secureAccessOnly(for: exampleURL) + + // Then + XCTAssertTrue(secureAccessOnly) + } + + func testReturnsTrueIfNothingIsDefined() throws { + // Given + let provider = FakeInfoDictionaryObjectProvider(appTransportSecurity: [String: Any]()) + let appTransportSecurity = AppTransportSecuritySettings(provider) + + // When + let secureAccessOnly = appTransportSecurity.secureAccessOnly(for: exampleURL) + + // Then + XCTAssertTrue(secureAccessOnly) + } + + func testReturnsFalseIfAllowsInsecureHTTPLoadsIsTrue() throws { + // Given + let provider = FakeInfoDictionaryObjectProvider(appTransportSecurity: [ + "NSExceptionDomains": [ + "shiki.me": [ + "NSExceptionAllowsInsecureHTTPLoads": true + ] + ] + ]) + let appTransportSecurity = AppTransportSecuritySettings(provider) + let url = try XCTUnwrap(URL(string: "http://shiki.me")) + + // When + let secureAccessOnly = appTransportSecurity.secureAccessOnly(for: url) + + // Then + XCTAssertFalse(secureAccessOnly) + } + + func testReturnsTrueIfAllowsInsecureHTTPLoadsIsNotProvided() throws { + // Given + let provider = FakeInfoDictionaryObjectProvider(appTransportSecurity: [ + "NSExceptionDomains": [ + "shiki.me": [String: Any]() + ], + // This value will be ignored because there is an exception for shiki.me + "NSAllowsArbitraryLoads": true + ]) + let appTransportSecurity = AppTransportSecuritySettings(provider) + let url = try XCTUnwrap(URL(string: "http://shiki.me")) + + // When + let secureAccessOnly = appTransportSecurity.secureAccessOnly(for: url) + + // Then + XCTAssertTrue(secureAccessOnly) + } +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Bundle+SPMSupport.swift b/Tests/WordPressKitTests/CoreAPITests/Bundle+SPMSupport.swift new file mode 100644 index 000000000000..0c3d02c28c0b --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Bundle+SPMSupport.swift @@ -0,0 +1,25 @@ +import Foundation + +extension Bundle { + /// Returns the `Bundle` for the target. + /// + /// If installed via CocoaPods, this will be `.bundle`, otherwise it will be the framework bundle. + @objc public class var coreAPITestsBundle: Bundle { +#if SWIFT_PACKAGE + return Bundle.module +#else + let defaultBundle = Bundle(for: BundleFinder.self) + + guard let bundleURL = defaultBundle.resourceURL, + let resourceBundle = Bundle(url: bundleURL.appendingPathComponent("CoreAPITests.bundle")) else { + return defaultBundle + } + + return resourceBundle +#endif + } +} + +#if !SWIFT_PACKAGE +private class BundleFinder: NSObject {} +#endif diff --git a/Tests/WordPressKitTests/CoreAPITests/FakeInfoDictionaryObjectProvider.swift b/Tests/WordPressKitTests/CoreAPITests/FakeInfoDictionaryObjectProvider.swift new file mode 100644 index 000000000000..74569e5bfab6 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/FakeInfoDictionaryObjectProvider.swift @@ -0,0 +1,21 @@ +#if SWIFT_PACKAGE +@testable import CoreAPI +#else +@testable import WordPressKit +#endif + +class FakeInfoDictionaryObjectProvider: InfoDictionaryObjectProvider { + private let appTransportSecurity: [String: Any]? + + init(appTransportSecurity: [String: Any]?) { + self.appTransportSecurity = appTransportSecurity + } + + func object(forInfoDictionaryKey key: String) -> Any? { + if key == "NSAppTransportSecurity" { + return appTransportSecurity + } + + return nil + } +} diff --git a/Tests/WordPressKitTests/CoreAPITests/HTTPRequestBuilderTests.swift b/Tests/WordPressKitTests/CoreAPITests/HTTPRequestBuilderTests.swift new file mode 100644 index 000000000000..4b455c76cb3e --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/HTTPRequestBuilderTests.swift @@ -0,0 +1,431 @@ +#if SWIFT_PACKAGE +@testable import CoreAPI +#else +@testable import WordPressKit +#endif +import wpxmlrpc +import XCTest + +class HTTPRequestBuilderTests: XCTestCase { + + static let nestedParameters: [String: Any] = + [ + "number": 1, + "nsnumber-true": NSNumber(value: true), + "true": true, + "false": false, + "string": "true", + "dict": ["foo": true, "bar": "string"], + "nested-dict": [ + "outer1": [ + "inner1": "value1", + "inner2": "value2" + ], + "outer2": [ + "inner1": "value1", + "inner2": "value2" + ] + ], + "array": ["true", 1, false] + ] + static let nestedParametersEncoded = [ + "number=1", + "nsnumber-true=1", + "true=1", + "false=0", + "string=true", + "dict[foo]=1", + "dict[bar]=string", + "nested-dict[outer1][inner1]=value1", + "nested-dict[outer1][inner2]=value2", + "nested-dict[outer2][inner1]=value1", + "nested-dict[outer2][inner2]=value2", + "array[]=true", + "array[]=1", + "array[]=0", + ] + + func testURL() throws { + try XCTAssertEqual(HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!).build().url?.absoluteString, "https://wordpress.org") + try XCTAssertEqual(HTTPRequestBuilder(url: URL(string: "https://wordpress.com")!).build().url?.absoluteString, "https://wordpress.com") + } + + func testHTTPMethods() throws { + try XCTAssertEqual(HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!).build().httpMethod, "GET") + XCTAssertFalse(HTTPRequestBuilder.Method.get.allowsHTTPBody) + + try XCTAssertEqual(HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!).method(.delete).build().httpMethod, "DELETE") + XCTAssertFalse(HTTPRequestBuilder.Method.delete.allowsHTTPBody) + + try XCTAssertEqual(HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!).method(.post).build().httpMethod, "POST") + XCTAssertTrue(HTTPRequestBuilder.Method.post.allowsHTTPBody) + + try XCTAssertEqual(HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!).method(.patch).build().httpMethod, "PATCH") + XCTAssertTrue(HTTPRequestBuilder.Method.patch.allowsHTTPBody) + + try XCTAssertEqual(HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!).method(.put).build().httpMethod, "PUT") + XCTAssertTrue(HTTPRequestBuilder.Method.put.allowsHTTPBody) + } + + func testHeader() throws { + let request = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .header(name: "X-Header-1", value: "Foo") + .header(name: "X-Header-2", value: "Bar") + .build() + XCTAssertEqual(request.value(forHTTPHeaderField: "X-Header-1"), "Foo") + XCTAssertEqual(request.value(forHTTPHeaderField: "X-Header-2"), "Bar") + } + + func testPath() throws { + var request = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .append(percentEncodedPath: "hello/world") + .build() + XCTAssertEqual(request.url?.absoluteString, "https://wordpress.org/hello/world") + + request = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .append(percentEncodedPath: "/hello/world") + .build() + XCTAssertEqual(request.url?.absoluteString, "https://wordpress.org/hello/world") + + request = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org/hello")!) + .append(percentEncodedPath: "world") + .build() + XCTAssertEqual(request.url?.absoluteString, "https://wordpress.org/hello/world") + + request = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org/hello")!) + .append(percentEncodedPath: "/world") + .build() + XCTAssertEqual(request.url?.absoluteString, "https://wordpress.org/hello/world") + } + + func testQueryOverride() { + try XCTAssertEqual( + HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .query(name: "foo", value: "bar", override: true) + .build() + .url? + .absoluteString, + "https://wordpress.org?foo=bar" + ) + + try XCTAssertEqual( + HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .query(name: "foo", value: "bar", override: true) + .query(name: "foo", value: "hello", override: true) + .build() + .url? + .absoluteString, + "https://wordpress.org?foo=hello" + ) + + try XCTAssertEqual( + HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .query(name: "foo", value: "bar", override: true) + .query(name: "foo", value: "hello", override: false) + .build() + .url? + .absoluteString, + "https://wordpress.org?foo=bar&foo=hello" + ) + + try XCTAssertEqual( + HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .query(name: "foo", value: "bar") + .query(name: "foo", value: "hello") + .build() + .url? + .absoluteString, + "https://wordpress.org?foo=bar&foo=hello" + ) + } + + func testQueryOverrideMany() { + try XCTAssertEqual( + HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .query(name: "foo", value: "bar", override: true) + .build() + .url? + .absoluteString, + "https://wordpress.org?foo=bar" + ) + + try XCTAssertEqual( + HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .query(name: "foo", value: "bar", override: true) + .append(query: [URLQueryItem(name: "foo", value: "hello")], override: true) + .build() + .url? + .absoluteString, + "https://wordpress.org?foo=hello" + ) + + try XCTAssertEqual( + HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .query(name: "foo", value: "bar", override: true) + .append(query: [URLQueryItem(name: "foo", value: "hello")], override: false) + .build() + .url? + .absoluteString, + "https://wordpress.org?foo=bar&foo=hello" + ) + + try XCTAssertEqual( + HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .query(name: "foo", value: "bar") + .append(query: [URLQueryItem(name: "foo", value: "hello")]) + .build() + .url? + .absoluteString, + "https://wordpress.org?foo=bar&foo=hello" + ) + } + + @available(iOS 16.0, *) + func testSetQueryWithDictionary() throws { + let query = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .query(HTTPRequestBuilderTests.nestedParameters) + .build() + .url? + .query(percentEncoded: false)? + .split(separator: "&") + .reduce(into: Set()) { $0.insert(String($1)) } + ?? [] + + XCTAssertEqual(query.count, HTTPRequestBuilderTests.nestedParametersEncoded.count) + + for item in HTTPRequestBuilderTests.nestedParametersEncoded { + XCTAssertTrue(query.contains(item), "Missing query item: \(item)") + } + } + + func testDefaultQuery() throws { + let builder = HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .query(defaults: [URLQueryItem(name: "locale", value: "en")]) + + try XCTAssertEqual(builder.build().url?.query, "locale=en") + try XCTAssertEqual(builder.query(name: "locale", value: "zh").build().url?.query, "locale=zh") + try XCTAssertEqual(builder.query(name: "foo", value: "bar").build().url?.query, "locale=zh&foo=bar") + } + + func testDefaultQueryDoesNotOverriedQueryItemInOriginalURL() throws { + let url = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org/hello?locale=foo")!) + .query(defaults: [URLQueryItem(name: "locale", value: "en")]) + .build() + .url + + XCTAssertEqual(url?.query, "locale=foo") + } + + func testJSONBody() throws { + var request = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .method(.post) + .body(json: 42) + .build() + XCTAssertTrue(request.value(forHTTPHeaderField: "Content-Type")?.contains("application/json") == true) + try XCTAssertEqual(XCTUnwrap(request.httpBodyText), "42") + + request = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .method(.post) + .body(json: ["foo": "bar"]) + .build() + try XCTAssertEqual(XCTUnwrap(request.httpBodyText), #"{"foo":"bar"}"#) + } + + func testJSONBodyWithEncodable() throws { + struct Body: Encodable { + var foo: String + } + let body = Body(foo: "bar") + + let request = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .method(.post) + .body(json: body) + .build() + XCTAssertTrue(request.value(forHTTPHeaderField: "Content-Type")?.contains("application/json") == true) + try XCTAssertEqual(XCTUnwrap(request.httpBodyText), #"{"foo":"bar"}"#) + } + + func testFormBody() throws { + let request = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .method(.post) + .body(form: ["name": "Foo Bar"]) + .build() + XCTAssertTrue(request.value(forHTTPHeaderField: "Content-Type")?.contains("application/x-www-form-urlencoded") == true) + try XCTAssertEqual(XCTUnwrap(request.httpBodyText), #"name=Foo%20Bar"#) + } + + func testFormWithSpecialCharacters() throws { + let request = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .method(.post) + .body(form: ["text": ":#[]@!$&'()*+,;="]) + .build() + try XCTAssertEqual(XCTUnwrap(request.httpBodyText), "text=%3A%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D") + } + + func testFormWithRandomSpecialCharacters() throws { + let asciis = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + let unicodes = "表情符号😇🤔✅😎" + let randomText: () -> String = { + let chars = (1...10).map { _ in (asciis + unicodes).randomElement()! } + return String(chars) + } + // Generate a form (key-value pairs) with random characters. + let form = [ + randomText(): randomText(), + randomText(): randomText(), + randomText(): randomText(), + ] + + let request = try HTTPRequestBuilder(url: URL(string: "https://wordpress.org")!) + .method(.post) + .body(form: form) + .build() + let encoded = try XCTUnwrap(request.httpBodyText) + + // Decoding the url-encoded form, whose format should be "=&=&...". + let keyValuePairs = try encoded.split(separator: "&").map { pair in + XCTAssertEqual(pair.firstIndex(of: "="), pair.lastIndex(of: "="), "There should be only one '=' in a key-value pair") + + let firstIndex = try XCTUnwrap(pair.firstIndex(of: "=")) + let key = pair[pair.startIndex.." + XCTAssertTrue(xmlrpcContent.contains(filePart)) + } + +} diff --git a/Tests/WordPressKitTests/CoreAPITests/MultipartFormTests.swift b/Tests/WordPressKitTests/CoreAPITests/MultipartFormTests.swift new file mode 100644 index 000000000000..88d786d914a0 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/MultipartFormTests.swift @@ -0,0 +1,152 @@ +import Foundation +import XCTest +import CryptoKit +#if SWIFT_PACKAGE +@testable import CoreAPI +#else +@testable import WordPressKit +#endif + +class MutliparFormDataTests: XCTestCase { + struct Form: Codable { + struct Field: Codable { + var name: String + var content: String + } + + var fields: [Field] + + static func random(numberOfFields: Int = 10) -> Form { + let randomText: () -> String = { String(format: "%08x", Int.random(in: Int.min...Int.max)) } + let fields = (1...numberOfFields).map { _ in + Field(name: randomText(), content: randomText()) + } + return Form(fields: fields) + } + + func formData() throws -> Data { + try fields + .map { + MultipartFormField(text: $0.content, name: $0.name) + } + .multipartFormDataStream(boundary: "testboundary") + .readToEnd() + } + } + + func testRandomForm() throws { + let tempDir = FileManager.default.temporaryDirectory + let testData = tempDir.appendingPathComponent("test-form.json") + let wpOutput = tempDir.appendingPathComponent("test-form.wp.txt") + + let form = Form(fields: [ + .init(name: "key-1", content: "a"), + .init(name: "key-2", content: "b"), + ]) + try JSONEncoder().encode(form).write(to: testData) + + let encoded = try form.formData() + try encoded.write(to: wpOutput) + + add(XCTAttachment(contentsOfFile: testData)) + add(XCTAttachment(contentsOfFile: wpOutput)) + + let expected = "--testboundary\r\nContent-Disposition: form-data; name=\"key-1\"\r\n\r\na\r\n--testboundary\r\nContent-Disposition: form-data; name=\"key-2\"\r\n\r\nb\r\n--testboundary--\r\n".data(using: .utf8) + XCTAssertEqual(expected, encoded) + } + + func testPlainText() throws { + let fields = [ + MultipartFormField(text: "hello", name: "world"), + MultipartFormField(text: "foo", name: "bar"), + MultipartFormField(text: "the", name: "end"), + ] + let encoded = try fields.multipartFormDataStream(boundary: "wpkit.boundary.9d4adfc909a08bfa").readToEnd() + let expected = "--wpkit.boundary.9d4adfc909a08bfa\r\nContent-Disposition: form-data; name=\"world\"\r\n\r\nhello\r\n--wpkit.boundary.9d4adfc909a08bfa\r\nContent-Disposition: form-data; name=\"bar\"\r\n\r\nfoo\r\n--wpkit.boundary.9d4adfc909a08bfa\r\nContent-Disposition: form-data; name=\"end\"\r\n\r\nthe\r\n--wpkit.boundary.9d4adfc909a08bfa--\r\n".data(using: .utf8) + XCTAssertEqual(expected, encoded) + } + + func testEmptyForm() throws { + let formData = try [].multipartFormDataStream(boundary: "test").readToEnd() + XCTAssertTrue(formData.isEmpty) + } + + func testOneField() throws { + let formData = try [MultipartFormField(text: "hello", name: "world")] + .multipartFormDataStream(boundary: "wpkit.boundary.9d4adfc909a08bfa") + .readToEnd() + + let expected = "--wpkit.boundary.9d4adfc909a08bfa\r\nContent-Disposition: form-data; name=\"world\"\r\n\r\nhello\r\n--wpkit.boundary.9d4adfc909a08bfa--\r\n".data(using: .utf8)! + XCTAssertEqual(expected, formData) + } + + func testUploadSmallFile() throws { + let tempDir = FileManager.default.temporaryDirectory + let fileContent = Data(repeating: Character("a").asciiValue!, count: 20_000_000) + let filePath = tempDir.appendingPathComponent("file.png") + let resultPath = tempDir.appendingPathComponent("result.txt") + try fileContent.write(to: filePath) + defer { + try? FileManager.default.removeItem(at: filePath) + try? FileManager.default.removeItem(at: resultPath) + } + + let fields = [ + MultipartFormField(text: "123456", name: "site"), + try MultipartFormField(fileAtPath: filePath.path, name: "media", filename: "file.png", mimeType: "image/png"), + ] + let formData = try fields.multipartFormDataStream(boundary: "testboundary").readToEnd() + try formData.write(to: resultPath) + + // Reminder: Check the multipart form file before updating this assertion + XCTAssertTrue(SHA256.hash(data: formData).description.contains("8c985fdc03e75389b85a74996504aa10e0b054b1b5f771bd1ba0db155281bb53")) + } + + func testUploadLargeFile() throws { + let tempDir = FileManager.default.temporaryDirectory + let fileContent = Data(repeating: Character("a").asciiValue!, count: 50_000_000) + let filePath = tempDir.appendingPathComponent("file.png") + let resultPath = tempDir.appendingPathComponent("result.txt") + try fileContent.write(to: filePath) + defer { + try? FileManager.default.removeItem(at: filePath) + try? FileManager.default.removeItem(at: resultPath) + } + + let fields = [ + MultipartFormField(text: "123456", name: "site"), + try MultipartFormField(fileAtPath: filePath.path, name: "media", filename: "file.png", mimeType: "image/png"), + ] + let formData = try fields.multipartFormDataStream(boundary: "testboundary").readToEnd() + try formData.write(to: resultPath) + + // Reminder: Check the multipart form file before updating this assertion + XCTAssertTrue(SHA256.hash(data: formData).description.contains("2cedb35673a6982453a6e8e5ca901feabf92250630cdfabb961a03467f28bc8e")) + } + +} + +extension Either { + func readToEnd() -> Data { + map( + left: { $0 }, + right: { InputStream(url: $0)?.readToEnd() ?? Data() } + ) + } +} + +extension InputStream { + func readToEnd() -> Data { + open() + defer { close() } + + var data = Data() + let maxLength = 1024 + var buffer = [UInt8](repeating: 0, count: maxLength) + while hasBytesAvailable { + let bytes = read(&buffer, maxLength: maxLength) + data.append(buffer, count: bytes) + } + return data + } +} diff --git a/Tests/WordPressKitTests/CoreAPITests/NonceRetrievalTests.swift b/Tests/WordPressKitTests/CoreAPITests/NonceRetrievalTests.swift new file mode 100644 index 000000000000..eb0f54a9db3e --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/NonceRetrievalTests.swift @@ -0,0 +1,74 @@ +import Foundation +import XCTest +import OHHTTPStubs +import OHHTTPStubsSwift + +@testable import WordPressKit + +class NonceRetrievalTests: XCTestCase { + + static let nonce = "leg1tn0nce" + static let siteURL = URL(string: "https://test.com")! + static let siteLoginURL = URL(string: "https://test.com/wp-login.php")! + static let siteAdminURL = URL(string: "https://test.com/wp-admin/")! + static let newPostURL = URL(string: "https://test.com/wp-admin/post-new.php")! + static let ajaxURL = URL(string: "https://test.com/wp-admin/admin-ajax.php?action=rest-nonce")! + + override func tearDown() { + super.tearDown() + HTTPStubs.removeAllStubs() + } + + func testUsingNewPostPage() async { + stubLoginRedirect(dest: Self.newPostURL) + stubNewPostPage(statusCode: 200) + + let nonce = await NonceRetrievalMethod.newPostScrap.retrieveNonce( + username: "test", + password: .init("pass"), + loginURL: Self.siteLoginURL, + adminURL: Self.siteAdminURL, + using: URLSession(configuration: .ephemeral) + ) + XCTAssertEqual(nonce, Self.nonce) + } + + func testUsingRESTNonceAjax() async { + stubLoginRedirect(dest: Self.ajaxURL) + stubAjax(statusCode: 200) + + let nonce = await NonceRetrievalMethod.ajaxNonceRequest.retrieveNonce( + username: "test", + password: .init("pass"), + loginURL: Self.siteLoginURL, + adminURL: Self.siteAdminURL, + using: URLSession(configuration: .ephemeral) + ) + XCTAssertEqual(nonce, Self.nonce) + } + + private func stubLoginRedirect(dest: URL) { + stub(condition: isAbsoluteURLString(Self.siteLoginURL.absoluteString)) { _ in + HTTPStubsResponse(data: Data(), statusCode: 302, headers: ["Location": dest.absoluteString]) + } + } + + private func stubNewPostPage(nonceScript: String? = nil, statusCode: Int32) { + let script = nonceScript ?? """ + wp.apiFetch.nonceMiddleware = wp.apiFetch.createNonceMiddleware( "\(Self.nonce)" ); + wp.apiFetch.use( wp.apiFetch.nonceMiddleware ); + wp.apiFetch.use( wp.apiFetch.mediaUploadMiddleware ); + """ + let html = "\n\(script)\n" + stub(condition: isAbsoluteURLString(Self.newPostURL.absoluteString)) { _ in + HTTPStubsResponse(data: html.data(using: .utf8)!, statusCode: statusCode, headers: nil) + } + } + + private func stubAjax(statusCode: Int32) { + stub(condition: isAbsoluteURLString(Self.ajaxURL.absoluteString)) { _ in + HTTPStubsResponse(data: (statusCode == 200 ? Self.nonce : "...").data(using: .utf8)!, statusCode: statusCode, headers: nil) + } + } + +} diff --git a/Tests/WordPressKitTests/CoreAPITests/RSDParserTests.swift b/Tests/WordPressKitTests/CoreAPITests/RSDParserTests.swift new file mode 100644 index 000000000000..700c283ac3e5 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/RSDParserTests.swift @@ -0,0 +1,50 @@ +import Foundation +import XCTest +#if SWIFT_PACKAGE +@testable import CoreAPI +#else +@testable import WordPressKit +#endif + +class RSDParserTests: XCTestCase { + + func testSuccess() throws { + // Grabbed from https://developer.wordpress.org/xmlrpc.php?rsd + let xml = """ + + + WordPress + https://wordpress.org/ + https://developer.wordpress.org + + + + + + + + + + """ + let parser = try XCTUnwrap(WordPressRSDParser(xmlString: xml)) + try XCTAssertEqual(parser.parsedEndpoint(), "https://developer.wordpress.org/xmlrpc.php") + } + + func testWordPressEntryOnly() throws { + // Grabbed from https://developer.wordpress.org/xmlrpc.php?rsd, but removing all other api links. + let xml = """ + + + WordPress + https://wordpress.org/ + https://developer.wordpress.org + + + + + """ + let parser = try XCTUnwrap(WordPressRSDParser(xmlString: xml)) + try XCTAssertEqual(parser.parsedEndpoint(), "https://developer.wordpress.org/xmlrpc.php") + } + +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/HTML/xmlrpc-response-invalid.html b/Tests/WordPressKitTests/CoreAPITests/Stubs/HTML/xmlrpc-response-invalid.html new file mode 100644 index 000000000000..6c25e2cac0c6 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/HTML/xmlrpc-response-invalid.html @@ -0,0 +1,7 @@ + + + + website + + 👋 + diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/HTML/xmlrpc-response-mobile-plugin-redirect.html b/Tests/WordPressKitTests/CoreAPITests/Stubs/HTML/xmlrpc-response-mobile-plugin-redirect.html new file mode 100644 index 000000000000..fc8f70eaf3af --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/HTML/xmlrpc-response-mobile-plugin-redirect.html @@ -0,0 +1,8 @@ + + + + + website + + 👋 + diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComAuthenticateWithIDToken2FANeededSuccess.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComAuthenticateWithIDToken2FANeededSuccess.json new file mode 100644 index 000000000000..366fa8835ceb --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComAuthenticateWithIDToken2FANeededSuccess.json @@ -0,0 +1,13 @@ +{ + "data": { + "two_step_nonce_authenticator": "two_step_nonce_authenticator", + "two_step_nonce": "two_step_nonce", + "two_step_nonce_sms": "two_step_nonce_sms", + "two_step_nonce_backup": "two_step_nonce_backup", + "two_step_nonce_webauthn": "two_step_nonce_webauthn", + "two_step_notification_sent": "two_step_notification_sent", + "two_step_supported_auth_types": "two_step_supported_auth_types", + "phone_number": "phone_number", + "user_id": 1 + } +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComAuthenticateWithIDTokenBearerTokenSuccess.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComAuthenticateWithIDTokenBearerTokenSuccess.json new file mode 100644 index 000000000000..fe81d177cb99 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComAuthenticateWithIDTokenBearerTokenSuccess.json @@ -0,0 +1,13 @@ +{ + "data": { + "two_step_nonce_authenticator": "two_step_nonce_authenticator", + "two_step_nonce": "two_step_nonce", + "two_step_nonce_sms": "two_step_nonce_sms", + "two_step_nonce_backup": "two_step_nonce_backup", + "two_step_notification_sent": "two_step_notification_sent", + "two_step_supported_auth_types": "two_step_supported_auth_types", + "phone_number": "phone_number", + "bearer_token": "bearer_token", + "user_id": "user_id" + } +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComAuthenticateWithIDTokenExistingUserNeedsConnection.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComAuthenticateWithIDTokenExistingUserNeedsConnection.json new file mode 100644 index 000000000000..1a8f6f3a3e85 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComAuthenticateWithIDTokenExistingUserNeedsConnection.json @@ -0,0 +1,10 @@ +{ + "data": { + "errors": [{ + "code":"user_exists", + "message":"User exists but not connected" + }], + "two_step_nonce": "two_step_nonce", + "email": "email", + } +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthAuthenticateSignature.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthAuthenticateSignature.json new file mode 100644 index 000000000000..8307598d7d66 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthAuthenticateSignature.json @@ -0,0 +1,12 @@ +{ + "success": true, + "data": { + "bearer_token": "bearer_token", + "token_links": [ + "https:\/\/jetpack.com\/remote-login.php?wpcom_rem...", + "https:\/\/fieldguide.automattic.com\/remote-logi...", + "https:\/\/learn.a8c.com\/remote-login.php?wpcom_remote_login...", + "https:\/\/a8c.tv\/remote-login.php?wpcom_remote_login=vali..." + ] + } +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthNeeds2FAFail.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthNeeds2FAFail.json new file mode 100644 index 000000000000..6bfbf7d62cc9 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthNeeds2FAFail.json @@ -0,0 +1,4 @@ +{ + "error_description": "Please enter the verification code generated by your Authenticator mobile application.", + "error": "needs_2fa" +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthNeedsWebauthnMFA.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthNeedsWebauthnMFA.json new file mode 100644 index 000000000000..d68917b34253 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthNeedsWebauthnMFA.json @@ -0,0 +1,7 @@ +{ + "success": true, + "data": { + "user_id": 1234, + "two_step_nonce_webauthn": "two_step_nonce_webauthn", + } +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthRequestChallenge.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthRequestChallenge.json new file mode 100644 index 000000000000..0442814a0ae1 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthRequestChallenge.json @@ -0,0 +1,33 @@ +{ + "success": true, + "data": { + "challenge": "challenge", + "rpId": "wordpress.com", + "allowCredentials": [ + { + "type": "public-key", + "id": "credential-id", + "transports": [ + "usb", + "nfc", + "ble", + "hybrid", + "internal" + ] + }, + { + "type": "public-key", + "id": "credential-id-2", + "transports": [ + "usb", + "nfc", + "ble", + "hybrid", + "internal" + ] + } + ], + "timeout": 60000, + "two_step_nonce": "two_step_nonce" + } +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthSuccess.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthSuccess.json new file mode 100644 index 000000000000..5bc5c0a69b0c --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthSuccess.json @@ -0,0 +1,7 @@ +{ + "blog_id": 0, + "scope": "global", + "blog_url": null, + "token_type": "bearer", + "access_token": "fakeToken" +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthWrongPasswordFail.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthWrongPasswordFail.json new file mode 100644 index 000000000000..b6f3795019ff --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComOAuthWrongPasswordFail.json @@ -0,0 +1,4 @@ +{ + "error_description": "Incorrect username or password.", + "error": "invalid_request" +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailInvalidInput.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailInvalidInput.json new file mode 100644 index 000000000000..473d09f4429b --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailInvalidInput.json @@ -0,0 +1,4 @@ +{ + "message": "No media provided in input.", + "error": "invalid_input" +} \ No newline at end of file diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailInvalidJSON.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailInvalidJSON.json new file mode 100644 index 000000000000..9b4c74354223 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailInvalidJSON.json @@ -0,0 +1,4 @@ + + "message": "The OAuth2 token is invalid.", + "error": "invalid_token" +} \ No newline at end of file diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailReauthenticationRequired.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailReauthenticationRequired.json new file mode 100644 index 000000000000..63be1a7c88e8 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailReauthenticationRequired.json @@ -0,0 +1,4 @@ +{ + "message": "A fresh access token must be used to query information about the current user.", + "error": "reauthorization_required" +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailRequestInvalidToken.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailRequestInvalidToken.json new file mode 100644 index 000000000000..4d2dc0d0b16e --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailRequestInvalidToken.json @@ -0,0 +1,4 @@ +{ + "message": "The OAuth2 token is invalid.", + "error": "invalid_token" +} \ No newline at end of file diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailThrottled.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailThrottled.json new file mode 100644 index 000000000000..89bd200ebf60 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailThrottled.json @@ -0,0 +1,3 @@ + +Limit reached + \ No newline at end of file diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailUnauthorized.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailUnauthorized.json new file mode 100644 index 000000000000..0dd0fc043f69 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiFailUnauthorized.json @@ -0,0 +1,4 @@ +{ + "message": "User cannot upload media.", + "error": "unauthorized" +} \ No newline at end of file diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiMedia.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiMedia.json new file mode 100644 index 000000000000..e2991dd69884 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiMedia.json @@ -0,0 +1,868 @@ +{ + "found": 429, + "media": [ + { + "ID": 969, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb12.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb12.png", + "date": "2015-04-19T16:51:24+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb12.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb12", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb12.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb12.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb12.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb12.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/969", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/969\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 967, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb11.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb11.png", + "date": "2015-04-19T16:51:22+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb11.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb11", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb11.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb11.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb11.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb11.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/967", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/967\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 965, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb10.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb10.png", + "date": "2015-04-19T16:50:20+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb10.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb10", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb10.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb10.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb10.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb10.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/965", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/965\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 963, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb9.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb9.png", + "date": "2015-04-19T16:50:18+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb9.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb9", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb9.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb9.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb9.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb9.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/963", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/963\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 961, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb8.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb8.png", + "date": "2015-04-19T16:49:27+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb8.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb8", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb8.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb8.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb8.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb8.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/961", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/961\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 959, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb7.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb7.png", + "date": "2015-04-19T16:49:25+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb7.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb7", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb7.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb7.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb7.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb7.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/959", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/959\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 957, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb6.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb6.png", + "date": "2015-04-19T16:48:47+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb6.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb6", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb6.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb6.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb6.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb6.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/957", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/957\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 956, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb15.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb15.png", + "date": "2015-04-19T16:48:46+00:00", + "post_ID": 0, + "author_ID": 78972699, + "file": "codeispoetry-rgb15.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb15", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb15.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb15.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb15.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb15.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/956", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/956\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 955, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb5.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb5.png", + "date": "2015-04-19T16:48:45+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb5.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb5", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb5.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb5.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb5.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb5.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/955", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/955\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 953, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb4.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb4.png", + "date": "2015-04-19T16:47:36+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb4.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb4", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb4.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb4.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb4.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb4.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/953", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/953\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 952, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb13.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb13.png", + "date": "2015-04-19T16:47:35+00:00", + "post_ID": 0, + "author_ID": 78972699, + "file": "codeispoetry-rgb13.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb13", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb13.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb13.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb13.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb13.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/952", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/952\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 951, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb3.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb3.png", + "date": "2015-04-19T16:47:34+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb3.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb3", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb3.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb3.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb3.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb3.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/951", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/951\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 950, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb12.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb12.png", + "date": "2015-04-19T16:47:33+00:00", + "post_ID": 0, + "author_ID": 78972699, + "file": "codeispoetry-rgb12.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb12", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb12.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb12.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb12.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb12.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/950", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/950\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 949, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb2.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb2.png", + "date": "2015-04-19T16:47:10+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb2.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb2", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb2.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb2.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb2.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb2.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/949", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/949\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 948, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb11.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb11.png", + "date": "2015-04-19T16:47:09+00:00", + "post_ID": 0, + "author_ID": 78972699, + "file": "codeispoetry-rgb11.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb11", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb11.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb11.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb11.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb11.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/948", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/948\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 947, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb1.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb1.png", + "date": "2015-04-19T16:45:36+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb1.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb1", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb1.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb1.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb1.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb1.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/947", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/947\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 946, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb10.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb10.png", + "date": "2015-04-19T16:45:35+00:00", + "post_ID": 0, + "author_ID": 78972699, + "file": "codeispoetry-rgb10.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb10", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb10.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb10.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb10.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb10.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/946", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/946\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 945, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb.png", + "date": "2015-04-19T16:45:34+00:00", + "post_ID": 0, + "author_ID": 0, + "file": "codeispoetry-rgb.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/945", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/945\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 944, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb9.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb9.png", + "date": "2015-04-19T16:45:32+00:00", + "post_ID": 0, + "author_ID": 78972699, + "file": "codeispoetry-rgb9.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb9", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb9.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb9.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb9.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb9.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/944", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/944\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + }, + { + "ID": 943, + "URL": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb8.png", + "guid": "http:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb8.png", + "date": "2015-04-19T16:45:13+00:00", + "post_ID": 0, + "author_ID": 78972699, + "file": "codeispoetry-rgb8.png", + "mime_type": "image\/png", + "extension": "png", + "title": "codeispoetry-rgb8", + "caption": "", + "description": "", + "alt": "", + "thumbnails": { + "thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb8.png?w=150", + "medium": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb8.png?w=300", + "large": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb8.png?w=500", + "post-thumbnail": "https:\/\/apiexamples.files.wordpress.com\/2015\/04\/codeispoetry-rgb8.png?w=500&h=34&crop=1" + }, + "height": 34, + "width": 500, + "exif": { + "aperture": 0, + "credit": "", + "camera": "", + "caption": "", + "created_timestamp": 0, + "copyright": "", + "focal_length": 0, + "iso": 0, + "shutter_speed": 0, + "title": "", + "orientation": 0 + }, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/943", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409\/media\/943\/help", + "site": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/82974409" + } + } + } + ], + "meta": { + "next_page": "value=2015-04-19T16%3A45%3A13%2B00%3A00&id=943" + } +} \ No newline at end of file diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiMultipleErrors.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiMultipleErrors.json new file mode 100644 index 000000000000..a23c5e6f1e23 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComRestApiMultipleErrors.json @@ -0,0 +1,8 @@ +{ + "errors":[ + { + "message": "No media provided in input.", + "error": "upload_error" + } + ] +} \ No newline at end of file diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComSocial2FACodeSuccess.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComSocial2FACodeSuccess.json new file mode 100644 index 000000000000..fe81d177cb99 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/WordPressComSocial2FACodeSuccess.json @@ -0,0 +1,13 @@ +{ + "data": { + "two_step_nonce_authenticator": "two_step_nonce_authenticator", + "two_step_nonce": "two_step_nonce", + "two_step_nonce_sms": "two_step_nonce_sms", + "two_step_nonce_backup": "two_step_nonce_backup", + "two_step_notification_sent": "two_step_notification_sent", + "two_step_supported_auth_types": "two_step_supported_auth_types", + "phone_number": "phone_number", + "bearer_token": "bearer_token", + "user_id": "user_id" + } +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/me-settings-success.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/me-settings-success.json new file mode 100644 index 000000000000..19439786dafb --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/me-settings-success.json @@ -0,0 +1,47 @@ +{ + "enable_translator": false, + "surprise_me": true, + "post_post_flag": true, + "holidaysnow": true, + "user_login": "jimthetester", + "password": "", + "display_name": "Jim Tester", + "first_name": "Jim", + "last_name": "Tester", + "description": "Happy go lucky kind of tester.", + "user_email": "jimthetester@thetestemail.org", + "user_email_change_pending": false, + "new_user_email": "", + "user_URL": "http:\/\/jimthetester.blog", + "language": "en", + "avatar_URL": "https:\/\/2.gravatar.com\/avatar\/5c78d333444a3c12345ed8ff0e567890?s=200&d=mm", + "primary_site_ID": 321, + "comment_like_notification": true, + "mentions_notification": true, + "subscription_delivery_email_default": "instantly", + "subscription_delivery_jabber_default": false, + "subscription_delivery_mail_option": "html", + "subscription_delivery_day": 1, + "subscription_delivery_hour": 6, + "subscription_delivery_email_blocked": true, + "two_step_enabled": true, + "two_step_sms_enabled": false, + "two_step_backup_codes_printed": true, + "two_step_sms_country": "US", + "two_step_sms_phone_number": "2623536462", + "user_login_can_be_changed": false, + "calypso_preferences": { + "editor-mode": "html", + "editorAdvancedVisible": true, + "mediaModalGalleryInstructionsDismissed": true, + "recentSites": [ + 1234, + 56789, + 100234 + ] + }, + "jetpack_connect": [], + "is_desktop_app_user": true, + "locale_variant": false, + "tracks_opt_out": false +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/wp-forbidden.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/wp-forbidden.json new file mode 100644 index 000000000000..a40b581cbfd1 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/wp-forbidden.json @@ -0,0 +1,7 @@ +{ + "code": "rest_forbidden", + "data": { + "status": 401 + }, + "message": "Sorry, you are not allowed to do that." +} diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/wp-pages.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/wp-pages.json new file mode 100644 index 000000000000..9c89782e5615 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/wp-pages.json @@ -0,0 +1,729 @@ +[{ + "id": 457, + "date": "2019-02-06T00:37:47", + "date_gmt": "2019-02-06T00:37:47", + "guid": { + "rendered": "https:\/\/wordpress.org\/?page_id=457" + }, + "modified": "2019-02-06T00:45:13", + "modified_gmt": "2019-02-06T00:45:13", + "slug": "home", + "status": "publish", + "type": "page", + "link": "https:\/\/wordpress.org\/", + "title": { + "rendered": "Home" + }, + "content": { + "rendered": "", + "protected": false + }, + "excerpt": { + "rendered": "", + "protected": false + }, + "author": 5911429, + "featured_media": 0, + "parent": 0, + "menu_order": 0, + "comment_status": "closed", + "ping_status": "closed", + "template": "", + "meta": { + "spay_email": "" + }, + "jetpack_shortlink": "https:\/\/wp.me\/P1OHUb-7n", + "_links": { + "self": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/457" + }], + "collection": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages" + }], + "about": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/types\/page" + }], + "author": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/users\/5911429" + }], + "replies": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/comments?post=457" + }], + "version-history": [{ + "count": 1, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/457\/revisions" + }], + "predecessor-version": [{ + "id": 458, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/457\/revisions\/458" + }], + "wp:attachment": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/media?parent=457" + }], + "curies": [{ + "name": "wp", + "href": "https:\/\/api.w.org\/{rel}", + "templated": true + }] + } +}, { + "id": 385, + "date": "2018-07-09T21:23:48", + "date_gmt": "2018-07-09T21:23:48", + "guid": { + "rendered": "https:\/\/wordpress.org\/?page_id=385" + }, + "modified": "2018-11-26T07:14:22", + "modified_gmt": "2018-11-26T07:14:22", + "slug": "counter", + "status": "publish", + "type": "page", + "link": "https:\/\/wordpress.org\/download\/counter\/", + "title": { + "rendered": "Counter" + }, + "content": { + "rendered": "", + "protected": false + }, + "excerpt": { + "rendered": "", + "protected": false + }, + "author": 5911429, + "featured_media": 0, + "parent": 371, + "menu_order": 0, + "comment_status": "closed", + "ping_status": "closed", + "template": "page-download-counter.php", + "meta": { + "spay_email": "" + }, + "jetpack_shortlink": "https:\/\/wp.me\/P1OHUb-6d", + "_links": { + "self": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/385" + }], + "collection": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages" + }], + "about": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/types\/page" + }], + "author": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/users\/5911429" + }], + "replies": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/comments?post=385" + }], + "version-history": [{ + "count": 1, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/385\/revisions" + }], + "predecessor-version": [{ + "id": 386, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/385\/revisions\/386" + }], + "up": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/371" + }], + "wp:attachment": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/media?parent=385" + }], + "curies": [{ + "name": "wp", + "href": "https:\/\/api.w.org\/{rel}", + "templated": true + }] + } +}, { + "id": 379, + "date": "2018-07-03T02:03:10", + "date_gmt": "2018-07-03T02:03:10", + "guid": { + "rendered": "https:\/\/wordpress.org\/?page_id=379" + }, + "modified": "2018-11-26T07:14:22", + "modified_gmt": "2018-11-26T07:14:22", + "slug": "source", + "status": "publish", + "type": "page", + "link": "https:\/\/wordpress.org\/download\/source\/", + "title": { + "rendered": "Source Code" + }, + "content": { + "rendered": "", + "protected": false + }, + "excerpt": { + "rendered": "", + "protected": false + }, + "author": 5911429, + "featured_media": 0, + "parent": 371, + "menu_order": 0, + "comment_status": "closed", + "ping_status": "closed", + "template": "page-download-source.php", + "meta": { + "spay_email": "" + }, + "jetpack_shortlink": "https:\/\/wp.me\/P1OHUb-67", + "_links": { + "self": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/379" + }], + "collection": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages" + }], + "about": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/types\/page" + }], + "author": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/users\/5911429" + }], + "replies": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/comments?post=379" + }], + "version-history": [{ + "count": 2, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/379\/revisions" + }], + "predecessor-version": [{ + "id": 381, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/379\/revisions\/381" + }], + "up": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/371" + }], + "wp:attachment": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/media?parent=379" + }], + "curies": [{ + "name": "wp", + "href": "https:\/\/api.w.org\/{rel}", + "templated": true + }] + } +}, { + "id": 375, + "date": "2018-07-03T02:01:07", + "date_gmt": "2018-07-03T02:01:07", + "guid": { + "rendered": "https:\/\/wordpress.org\/?page_id=375" + }, + "modified": "2018-11-26T07:14:22", + "modified_gmt": "2018-11-26T07:14:22", + "slug": "beta-nightly", + "status": "publish", + "type": "page", + "link": "https:\/\/wordpress.org\/download\/beta-nightly\/", + "title": { + "rendered": "Beta\/Nightly" + }, + "content": { + "rendered": "", + "protected": false + }, + "excerpt": { + "rendered": "", + "protected": false + }, + "author": 5911429, + "featured_media": 0, + "parent": 371, + "menu_order": 0, + "comment_status": "closed", + "ping_status": "closed", + "template": "page-download-beta-nightly.php", + "meta": { + "spay_email": "" + }, + "jetpack_shortlink": "https:\/\/wp.me\/P1OHUb-63", + "_links": { + "self": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/375" + }], + "collection": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages" + }], + "about": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/types\/page" + }], + "author": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/users\/5911429" + }], + "replies": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/comments?post=375" + }], + "version-history": [{ + "count": 1, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/375\/revisions" + }], + "predecessor-version": [{ + "id": 376, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/375\/revisions\/376" + }], + "up": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/371" + }], + "wp:attachment": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/media?parent=375" + }], + "curies": [{ + "name": "wp", + "href": "https:\/\/api.w.org\/{rel}", + "templated": true + }] + } +}, { + "id": 373, + "date": "2018-07-02T23:57:35", + "date_gmt": "2018-07-02T23:57:35", + "guid": { + "rendered": "https:\/\/wordpress.org\/?page_id=373" + }, + "modified": "2018-11-26T07:14:22", + "modified_gmt": "2018-11-26T07:14:22", + "slug": "releases", + "status": "publish", + "type": "page", + "link": "https:\/\/wordpress.org\/download\/releases\/", + "title": { + "rendered": "Releases" + }, + "content": { + "rendered": "", + "protected": false + }, + "excerpt": { + "rendered": "", + "protected": false + }, + "author": 5911429, + "featured_media": 0, + "parent": 371, + "menu_order": 0, + "comment_status": "closed", + "ping_status": "closed", + "template": "page-download-releases.php", + "meta": { + "spay_email": "" + }, + "jetpack_shortlink": "https:\/\/wp.me\/P1OHUb-61", + "_links": { + "self": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/373" + }], + "collection": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages" + }], + "about": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/types\/page" + }], + "author": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/users\/5911429" + }], + "replies": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/comments?post=373" + }], + "version-history": [{ + "count": 1, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/373\/revisions" + }], + "predecessor-version": [{ + "id": 374, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/373\/revisions\/374" + }], + "up": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/371" + }], + "wp:attachment": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/media?parent=373" + }], + "curies": [{ + "name": "wp", + "href": "https:\/\/api.w.org\/{rel}", + "templated": true + }] + } +}, { + "id": 371, + "date": "2018-07-02T23:57:04", + "date_gmt": "2018-07-02T23:57:04", + "guid": { + "rendered": "https:\/\/wordpress.org\/?page_id=371" + }, + "modified": "2018-11-26T07:14:22", + "modified_gmt": "2018-11-26T07:14:22", + "slug": "download", + "status": "publish", + "type": "page", + "link": "https:\/\/wordpress.org\/download\/", + "title": { + "rendered": "Download" + }, + "content": { + "rendered": "", + "protected": false + }, + "excerpt": { + "rendered": "", + "protected": false + }, + "author": 5911429, + "featured_media": 0, + "parent": 0, + "menu_order": 0, + "comment_status": "closed", + "ping_status": "closed", + "template": "page-download.php", + "meta": { + "spay_email": "" + }, + "jetpack_shortlink": "https:\/\/wp.me\/P1OHUb-5Z", + "_links": { + "self": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/371" + }], + "collection": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages" + }], + "about": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/types\/page" + }], + "author": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/users\/5911429" + }], + "replies": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/comments?post=371" + }], + "version-history": [{ + "count": 1, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/371\/revisions" + }], + "predecessor-version": [{ + "id": 372, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/371\/revisions\/372" + }], + "wp:attachment": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/media?parent=371" + }], + "curies": [{ + "name": "wp", + "href": "https:\/\/api.w.org\/{rel}", + "templated": true + }] + } +}, { + "id": 329, + "date": "2018-05-30T06:49:44", + "date_gmt": "2018-05-30T06:49:44", + "guid": { + "rendered": "https:\/\/wordpress.org\/?page_id=329" + }, + "modified": "2018-05-30T06:49:44", + "modified_gmt": "2018-05-30T06:49:44", + "slug": "data-erasure-request", + "status": "publish", + "type": "page", + "link": "https:\/\/wordpress.org\/about\/privacy\/data-erasure-request\/", + "title": { + "rendered": "Data Erasure Request" + }, + "content": { + "rendered": "", + "protected": false + }, + "excerpt": { + "rendered": "", + "protected": false + }, + "author": 196012, + "featured_media": 0, + "parent": 259, + "menu_order": 0, + "comment_status": "closed", + "ping_status": "closed", + "template": "page-about-privacy-data-erasure-request.php", + "meta": { + "spay_email": "" + }, + "jetpack_shortlink": "https:\/\/wp.me\/P1OHUb-5j", + "_links": { + "self": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/329" + }], + "collection": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages" + }], + "about": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/types\/page" + }], + "author": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/users\/196012" + }], + "replies": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/comments?post=329" + }], + "version-history": [{ + "count": 2, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/329\/revisions" + }], + "predecessor-version": [{ + "id": 331, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/329\/revisions\/331" + }], + "up": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/259" + }], + "wp:attachment": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/media?parent=329" + }], + "curies": [{ + "name": "wp", + "href": "https:\/\/api.w.org\/{rel}", + "templated": true + }] + } +}, { + "id": 315, + "date": "2018-05-28T09:13:38", + "date_gmt": "2018-05-28T09:13:38", + "guid": { + "rendered": "https:\/\/wordpress.org\/?page_id=315" + }, + "modified": "2019-06-21T07:58:29", + "modified_gmt": "2019-06-21T07:58:29", + "slug": "data-export-request", + "status": "publish", + "type": "page", + "link": "https:\/\/wordpress.org\/about\/privacy\/data-export-request\/", + "title": { + "rendered": "Data Export Request" + }, + "content": { + "rendered": "", + "protected": false + }, + "excerpt": { + "rendered": "", + "protected": false + }, + "author": 5911429, + "featured_media": 0, + "parent": 259, + "menu_order": 0, + "comment_status": "closed", + "ping_status": "closed", + "template": "page-about-privacy-data-export-request.php", + "meta": { + "spay_email": "" + }, + "jetpack_shortlink": "https:\/\/wp.me\/P1OHUb-55", + "_links": { + "self": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/315" + }], + "collection": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages" + }], + "about": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/types\/page" + }], + "author": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/users\/5911429" + }], + "replies": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/comments?post=315" + }], + "version-history": [{ + "count": 1, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/315\/revisions" + }], + "predecessor-version": [{ + "id": 316, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/315\/revisions\/316" + }], + "up": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/259" + }], + "wp:attachment": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/media?parent=315" + }], + "curies": [{ + "name": "wp", + "href": "https:\/\/api.w.org\/{rel}", + "templated": true + }] + } +}, { + "id": 309, + "date": "2018-05-25T04:16:41", + "date_gmt": "2018-05-25T04:16:41", + "guid": { + "rendered": "https:\/\/wordpress.org\/?page_id=309" + }, + "modified": "2018-05-28T11:14:32", + "modified_gmt": "2018-05-28T11:14:32", + "slug": "cookies", + "status": "publish", + "type": "page", + "link": "https:\/\/wordpress.org\/about\/privacy\/cookies\/", + "title": { + "rendered": "Cookie Policy" + }, + "content": { + "rendered": "", + "protected": false + }, + "excerpt": { + "rendered": "", + "protected": false + }, + "author": 5911429, + "featured_media": 0, + "parent": 259, + "menu_order": 0, + "comment_status": "closed", + "ping_status": "closed", + "template": "page-about-privacy-cookies.php", + "meta": { + "spay_email": "" + }, + "jetpack_shortlink": "https:\/\/wp.me\/P1OHUb-4Z", + "_links": { + "self": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/309" + }], + "collection": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages" + }], + "about": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/types\/page" + }], + "author": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/users\/5911429" + }], + "replies": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/comments?post=309" + }], + "version-history": [{ + "count": 2, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/309\/revisions" + }], + "predecessor-version": [{ + "id": 311, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/309\/revisions\/311" + }], + "up": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/259" + }], + "wp:attachment": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/media?parent=309" + }], + "curies": [{ + "name": "wp", + "href": "https:\/\/api.w.org\/{rel}", + "templated": true + }] + } +}, { + "id": 281, + "date": "2018-03-28T03:08:38", + "date_gmt": "2018-03-28T03:08:38", + "guid": { + "rendered": "https:\/\/wordpress.org\/about\/accessibility\/" + }, + "modified": "2018-03-28T03:08:38", + "modified_gmt": "2018-03-28T03:08:38", + "slug": "accessibility", + "status": "publish", + "type": "page", + "link": "https:\/\/wordpress.org\/about\/accessibility\/", + "title": { + "rendered": "Accessibility" + }, + "content": { + "rendered": "", + "protected": false + }, + "excerpt": { + "rendered": "", + "protected": false + }, + "author": 5911429, + "featured_media": 0, + "parent": 251, + "menu_order": 0, + "comment_status": "closed", + "ping_status": "closed", + "template": "page-about-accessibility.php", + "meta": { + "spay_email": "" + }, + "jetpack_shortlink": "https:\/\/wp.me\/P1OHUb-4x", + "_links": { + "self": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/281" + }], + "collection": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages" + }], + "about": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/types\/page" + }], + "author": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/users\/5911429" + }], + "replies": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/comments?post=281" + }], + "version-history": [{ + "count": 0, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/281\/revisions" + }], + "up": [{ + "embeddable": true, + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/pages\/251" + }], + "wp:attachment": [{ + "href": "https:\/\/wordpress.org\/wp-json\/wp\/v2\/media?parent=281" + }], + "curies": [{ + "name": "wp", + "href": "https:\/\/api.w.org\/{rel}", + "templated": true + }] + } +}] \ No newline at end of file diff --git a/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/wp-reusable-blocks.json b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/wp-reusable-blocks.json new file mode 100644 index 000000000000..5e818f84e781 --- /dev/null +++ b/Tests/WordPressKitTests/CoreAPITests/Stubs/JSON/wp-reusable-blocks.json @@ -0,0 +1,50 @@ +{ + "id": 6, + "date": "2021-02-10T11:51:53", + "date_gmt": "2021-02-10T11:51:53", + "guid": { + "rendered": "https:\/\/test-site.org\/2021\/02\/10\/untitled-reusable-block\/", + "raw": "https:\/\/test-site.org\/2021\/02\/10\/untitled-reusable-block\/" + }, + "modified": "2021-02-10T12:31:39", + "modified_gmt": "2021-02-10T12:31:39", + "password": "", + "slug": "untitled-reusable-block", + "status": "publish", + "type": "wp_block", + "link": "https:\/\/test-site.org\/2021\/02\/10\/untitled-reusable-block\/", + "title": { + "raw": "A resuable block" + }, + "content": { + "raw": "\n

Some text<\/p>\n\n\n\n