From 59191acacd412d8779e1923717546e32939202e5 Mon Sep 17 00:00:00 2001 From: Nikita Shvadlenko Date: Mon, 14 Aug 2023 10:50:21 +1200 Subject: [PATCH 1/4] Changed the iOS version to 16.0 as per requirements --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c8b8488..ee3c5ebe 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ There is more info about contributing in [CONTRIBUTING.md](CONTRIBUTING.md). ## Development -__emitron__ runs on iOS 13.3 and greater. It uses SwiftUI and Combine extensively; and since these two technologies were very new at the time of creation, there are plenty of places in the code that could benefit from some refactoring. +__emitron__ runs on iOS 16.0 and greater. It uses SwiftUI and Combine extensively; and since these two technologies were very new at the time of creation, there are plenty of places in the code that could benefit from some refactoring. Currently, only people that hold an active kodeco.com subscription may use emitron. Non-subscribers will be shown a "no access" page on login. Subscribers have access to streaming videos, and a subset of subscribers (ones with a "Professional" subscription) is allowed to download videos for offline playback. From 61b6a30627d37606b719b225bb90e28cb6d5b4a0 Mon Sep 17 00:00:00 2001 From: Nikita Shvadlenko Date: Tue, 15 Aug 2023 12:29:47 +1200 Subject: [PATCH 2/4] Updated tests --- .../EntityAdapters/ContentAdapter.swift | 6 ++- .../Models/ContentTest+Mocks.swift | 4 +- .../EntityAdapters/ContentAdapterTest.swift | 38 ++++++++++++++----- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/Emitron/Emitron/Networking/Adapters/EntityAdapters/ContentAdapter.swift b/Emitron/Emitron/Networking/Adapters/EntityAdapters/ContentAdapter.swift index 52859410..08b04cd3 100644 --- a/Emitron/Emitron/Networking/Adapters/EntityAdapters/ContentAdapter.swift +++ b/Emitron/Emitron/Networking/Adapters/EntityAdapters/ContentAdapter.swift @@ -35,8 +35,10 @@ struct ContentAdapter: EntityAdapter { guard let contentTypeString = resource.attributes["content_type"] as? String, let contentType = ContentType(string: contentTypeString) - else { return nil } - + else { + throw EntityAdapterError.invalidOrMissingAttributes + } + guard let uri = resource.attributes["uri"] as? String, let name = resource.attributes["name"] as? String, let descriptionHtml = resource.attributes["description"] as? String, diff --git a/Emitron/emitronTests/Models/ContentTest+Mocks.swift b/Emitron/emitronTests/Models/ContentTest+Mocks.swift index 70c9b266..9aca84d6 100644 --- a/Emitron/emitronTests/Models/ContentTest+Mocks.swift +++ b/Emitron/emitronTests/Models/ContentTest+Mocks.swift @@ -50,7 +50,9 @@ extension ContentTest { let document = JSONAPIDocument(json) let resource = document.data.first! - let content = try ContentAdapter.process(resource: resource) + guard let content = try ContentAdapter.process(resource: resource) else { + preconditionFailure("Failed to load mock content from JSON") + } let cacheUpdate = try DataCacheUpdate.loadFrom(document: document) return (content, cacheUpdate) diff --git a/Emitron/emitronTests/Networking/Adapters/EntityAdapters/ContentAdapterTest.swift b/Emitron/emitronTests/Networking/Adapters/EntityAdapters/ContentAdapterTest.swift index fcf065fe..308ca9cc 100644 --- a/Emitron/emitronTests/Networking/Adapters/EntityAdapters/ContentAdapterTest.swift +++ b/Emitron/emitronTests/Networking/Adapters/EntityAdapters/ContentAdapterTest.swift @@ -113,7 +113,9 @@ class ContentAdapterTest: XCTestCase { func testValidResourceProcessedCorrectly() throws { let resource = try makeJsonAPIResource(for: sampleResource) - let content = try ContentAdapter.process(resource: resource, relationships: relationships) + guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { + preconditionFailure("Failed to load content from mock Json") + } XCTAssertEqual(12, content.id) XCTAssertEqual("Some kind of content", content.name) @@ -217,7 +219,7 @@ class ContentAdapterTest: XCTestCase { sample["attributes"]["content_type"] = "movie" let resource = try makeJsonAPIResource(for: sample) - + XCTAssertThrowsError(try ContentAdapter.process(resource: resource, relationships: relationships)) { error in XCTAssertEqual(EntityAdapterError.invalidOrMissingAttributes, error as! EntityAdapterError) } @@ -262,7 +264,9 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sample) - let content = try ContentAdapter.process(resource: resource, relationships: relationships) + guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { + preconditionFailure("failed to load content") + } XCTAssertEqual(.allLevels, content.difficulty) } @@ -283,7 +287,9 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sample) - let content = try ContentAdapter.process(resource: resource, relationships: relationships) + guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { + preconditionFailure("failed to load content") + } XCTAssertNil(content.cardArtworkURL) } @@ -291,7 +297,9 @@ class ContentAdapterTest: XCTestCase { let relationships = Array(self.relationships.dropLast()) let resource = try makeJsonAPIResource(for: sampleResource) - let content = try ContentAdapter.process(resource: resource, relationships: relationships) + guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { + preconditionFailure("failed to load content") + } XCTAssertNil(content.groupID) } @@ -300,7 +308,9 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sampleResource) - let content = try ContentAdapter.process(resource: resource, relationships: relationships) + guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { + preconditionFailure("failed to load content") + } XCTAssertEqual(4321, content.groupID) } @@ -310,7 +320,9 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sample) - let content = try ContentAdapter.process(resource: resource, relationships: relationships) + guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { + preconditionFailure("failed to load content") + } XCTAssertNil(content.ordinal) } @@ -320,7 +332,9 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sample) - let content = try ContentAdapter.process(resource: resource, relationships: relationships) + guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { + preconditionFailure("failed to load content") + } XCTAssertNil(content.ordinal) } @@ -330,7 +344,9 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sample) - let content = try ContentAdapter.process(resource: resource, relationships: relationships) + guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { + preconditionFailure("failed to load content") + } XCTAssertNil(content.videoIdentifier) } @@ -340,7 +356,9 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sample) - let content = try ContentAdapter.process(resource: resource, relationships: relationships) + guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { + preconditionFailure("failed to load content") + } XCTAssertNil(content.videoIdentifier) } } From e0b3dcb225e6dbdbf2f5ef294051466165ddfc9d Mon Sep 17 00:00:00 2001 From: Nikita Shvadlenko Date: Tue, 15 Aug 2023 13:25:35 +1200 Subject: [PATCH 3/4] Revert "Updated tests" This reverts commit 61b6a30627d37606b719b225bb90e28cb6d5b4a0. --- .../EntityAdapters/ContentAdapter.swift | 6 +-- .../Models/ContentTest+Mocks.swift | 4 +- .../EntityAdapters/ContentAdapterTest.swift | 38 +++++-------------- 3 files changed, 13 insertions(+), 35 deletions(-) diff --git a/Emitron/Emitron/Networking/Adapters/EntityAdapters/ContentAdapter.swift b/Emitron/Emitron/Networking/Adapters/EntityAdapters/ContentAdapter.swift index 08b04cd3..52859410 100644 --- a/Emitron/Emitron/Networking/Adapters/EntityAdapters/ContentAdapter.swift +++ b/Emitron/Emitron/Networking/Adapters/EntityAdapters/ContentAdapter.swift @@ -35,10 +35,8 @@ struct ContentAdapter: EntityAdapter { guard let contentTypeString = resource.attributes["content_type"] as? String, let contentType = ContentType(string: contentTypeString) - else { - throw EntityAdapterError.invalidOrMissingAttributes - } - + else { return nil } + guard let uri = resource.attributes["uri"] as? String, let name = resource.attributes["name"] as? String, let descriptionHtml = resource.attributes["description"] as? String, diff --git a/Emitron/emitronTests/Models/ContentTest+Mocks.swift b/Emitron/emitronTests/Models/ContentTest+Mocks.swift index 9aca84d6..70c9b266 100644 --- a/Emitron/emitronTests/Models/ContentTest+Mocks.swift +++ b/Emitron/emitronTests/Models/ContentTest+Mocks.swift @@ -50,9 +50,7 @@ extension ContentTest { let document = JSONAPIDocument(json) let resource = document.data.first! - guard let content = try ContentAdapter.process(resource: resource) else { - preconditionFailure("Failed to load mock content from JSON") - } + let content = try ContentAdapter.process(resource: resource) let cacheUpdate = try DataCacheUpdate.loadFrom(document: document) return (content, cacheUpdate) diff --git a/Emitron/emitronTests/Networking/Adapters/EntityAdapters/ContentAdapterTest.swift b/Emitron/emitronTests/Networking/Adapters/EntityAdapters/ContentAdapterTest.swift index 308ca9cc..fcf065fe 100644 --- a/Emitron/emitronTests/Networking/Adapters/EntityAdapters/ContentAdapterTest.swift +++ b/Emitron/emitronTests/Networking/Adapters/EntityAdapters/ContentAdapterTest.swift @@ -113,9 +113,7 @@ class ContentAdapterTest: XCTestCase { func testValidResourceProcessedCorrectly() throws { let resource = try makeJsonAPIResource(for: sampleResource) - guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { - preconditionFailure("Failed to load content from mock Json") - } + let content = try ContentAdapter.process(resource: resource, relationships: relationships) XCTAssertEqual(12, content.id) XCTAssertEqual("Some kind of content", content.name) @@ -219,7 +217,7 @@ class ContentAdapterTest: XCTestCase { sample["attributes"]["content_type"] = "movie" let resource = try makeJsonAPIResource(for: sample) - + XCTAssertThrowsError(try ContentAdapter.process(resource: resource, relationships: relationships)) { error in XCTAssertEqual(EntityAdapterError.invalidOrMissingAttributes, error as! EntityAdapterError) } @@ -264,9 +262,7 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sample) - guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { - preconditionFailure("failed to load content") - } + let content = try ContentAdapter.process(resource: resource, relationships: relationships) XCTAssertEqual(.allLevels, content.difficulty) } @@ -287,9 +283,7 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sample) - guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { - preconditionFailure("failed to load content") - } + let content = try ContentAdapter.process(resource: resource, relationships: relationships) XCTAssertNil(content.cardArtworkURL) } @@ -297,9 +291,7 @@ class ContentAdapterTest: XCTestCase { let relationships = Array(self.relationships.dropLast()) let resource = try makeJsonAPIResource(for: sampleResource) - guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { - preconditionFailure("failed to load content") - } + let content = try ContentAdapter.process(resource: resource, relationships: relationships) XCTAssertNil(content.groupID) } @@ -308,9 +300,7 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sampleResource) - guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { - preconditionFailure("failed to load content") - } + let content = try ContentAdapter.process(resource: resource, relationships: relationships) XCTAssertEqual(4321, content.groupID) } @@ -320,9 +310,7 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sample) - guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { - preconditionFailure("failed to load content") - } + let content = try ContentAdapter.process(resource: resource, relationships: relationships) XCTAssertNil(content.ordinal) } @@ -332,9 +320,7 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sample) - guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { - preconditionFailure("failed to load content") - } + let content = try ContentAdapter.process(resource: resource, relationships: relationships) XCTAssertNil(content.ordinal) } @@ -344,9 +330,7 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sample) - guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { - preconditionFailure("failed to load content") - } + let content = try ContentAdapter.process(resource: resource, relationships: relationships) XCTAssertNil(content.videoIdentifier) } @@ -356,9 +340,7 @@ class ContentAdapterTest: XCTestCase { let resource = try makeJsonAPIResource(for: sample) - guard let content = try ContentAdapter.process(resource: resource, relationships: relationships) else { - preconditionFailure("failed to load content") - } + let content = try ContentAdapter.process(resource: resource, relationships: relationships) XCTAssertNil(content.videoIdentifier) } } From 2e5284f11929a98ba46008ca4ee009dbdba0ec58 Mon Sep 17 00:00:00 2001 From: Nikita Shvadlenko Date: Tue, 15 Aug 2023 13:26:02 +1200 Subject: [PATCH 4/4] Changed the return type --- .../Networking/Adapters/EntityAdapters/ContentAdapter.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Emitron/Emitron/Networking/Adapters/EntityAdapters/ContentAdapter.swift b/Emitron/Emitron/Networking/Adapters/EntityAdapters/ContentAdapter.swift index 52859410..5c8c8040 100644 --- a/Emitron/Emitron/Networking/Adapters/EntityAdapters/ContentAdapter.swift +++ b/Emitron/Emitron/Networking/Adapters/EntityAdapters/ContentAdapter.swift @@ -30,12 +30,14 @@ import struct Foundation.URL struct ContentAdapter: EntityAdapter { - static func process(resource: JSONAPIResource, relationships: [EntityRelationship] = []) throws -> Content? { + static func process(resource: JSONAPIResource, relationships: [EntityRelationship] = []) throws -> Content { guard resource.entityType == .content else { throw EntityAdapterError.invalidResourceTypeForAdapter } guard let contentTypeString = resource.attributes["content_type"] as? String, let contentType = ContentType(string: contentTypeString) - else { return nil } + else { + throw EntityAdapterError.invalidOrMissingAttributes + } guard let uri = resource.attributes["uri"] as? String, let name = resource.attributes["name"] as? String,