Skip to content

Commit

Permalink
- Fix #1
Browse files Browse the repository at this point in the history
- Added few more tests
- Some code optimisations
  • Loading branch information
Aron Balog committed Feb 28, 2018
1 parent 20a75b5 commit 83cd6f2
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 33 deletions.
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Vox is a Swift JSONAPI standard implementation.

[![Build Status](https://travis-ci.org/aronbalog/Vox.svg?branch=master)](https://travis-ci.org/aronbalog/Vox)
[![codecov](https://codecov.io/gh/aronbalog/Vox/branch/master/graph/badge.svg)](https://codecov.io/gh/aronbalog/Vox)
[![Platform](https://img.shields.io/cocoapods/p/Vox.svg?style=flat)](https://github.com/aronbalog/Vox)
[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/Vox.svg)](https://img.shields.io/cocoapods/v/Vox.svg)

- 🎩 [The magic behind](#the-magic-behind)
- 💻 [Installation](#motivation-)
Expand Down Expand Up @@ -623,16 +625,36 @@ dataSource
- [x] DataSource with path and client when creating resource client receives correct data for execution
- [x] DataSource with path and client when fetching single resource invokes execute request on client
- [x] DataSource with path and client when fetching single resource client receives correct data for execution
- [x] DataSource with path and client when fetching resource collection invokes execute request on client
- [x] DataSource with path and client when fetching resource collection client receives correct data for execution
- [x] DataSource with path and client when fetching resource collection with custom pagination invokes execute request on client
- [x] DataSource with path and client when fetching resource collection with custom pagination client receives correct data for execution
- [x] DataSource with path and client when fetching resource collection with page based pagination invokes execute request on client
- [x] DataSource with path and client when fetching resource collection with page based pagination client receives correct data for execution
- [x] DataSource with path and client when fetching resource collection with offset based pagination invokes execute request on client
- [x] DataSource with path and client when fetching resource collection with offset based pagination client receives correct data for execution
- [x] DataSource with path and client when fetching resource collection with cursor based pagination invokes execute request on client
- [x] DataSource with path and client when fetching resource collection with cursor based pagination client receives correct data for execution
- [x] DataSource with path and client when updating resource invokes execute request on client
- [x] DataSource with path and client when updating resource client receives correct data for execution
- [x] DataSource with path and client when deleting resource invokes execute request on client
- [x] DataSource with path and client when deleting resource client receives correct data for execution
- [x] Deserializer when deserializing resource collection maps correctly
- [x] Deserializer when deserializing single resource and error data provided maps to errors object
- [x] Deserializer when deserializing single resource and error data provided with source object included in errors maps to errors object
- [x] Deserializer when deserializing single resource and error data provided with source object included in errors maps to errors object 2
- [x] Deserializer when deserializing document with polymorphic objects in relationships maps correctly
- [x] Deserializer when deserializing single resource maps correctly
- [x] Paginated DataSource when fetching first page returns first page document
- [x] Paginated DataSource when fetching first page when fetching next page returns next page document
- [x] Paginated DataSource when fetching first page returns first page document 2
- [x] Paginated DataSource when fetching first page when fetching first page of document returns first page document
- [x] Paginated DataSource when fetching first page returns first page document 3
- [x] Paginated DataSource when fetching first page when appending next page document is appended
- [x] Paginated DataSource when fetching first page when appending next page included is appended
- [x] Paginated DataSource when fetching first page returns first page document 4
- [x] Paginated DataSource when fetching first page when reloading current page receives page
- [x] Paginated DataSource when fetching first page returns first page document 5
- [x] Paginated DataSource when fetching first page when fetching previous page receives page
- [x] Paginated DataSource when fetching first page returns first page document 6
- [x] Paginated DataSource when fetching first page when fetching last page returns last page document
- [x] Serializer when serializing resource collection maps correctly
- [x] Serializer when serializing resource collection returns document data
- [x] Serializer when serializing resource collection returns document dictionary
Expand Down
14 changes: 7 additions & 7 deletions Vox.playground/Contents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ class Cellphone: Resource {
}
}

class Weed: Resource {
class Wallet: Resource {
override class var resourceType: String {
return "Weed"
return "Wallet"
}
}

Expand All @@ -24,7 +24,7 @@ class Person: Resource {
@objc dynamic var goodFriends: [Person]?
@objc dynamic var favoriteWords: [String]?
@objc dynamic var items: [Resource]?
@objc dynamic var favoriteWeed: Resource?
@objc dynamic var favoriteItem: Resource?
}

Resource.load()
Expand All @@ -46,13 +46,13 @@ anotherFriend.id = "ANOTHER-FRIEND-ID"
person.bestFriend = bestFriend
person.goodFriends = [bestFriend, anotherFriend]

let weed = Weed()
weed.id = "weed"
let wallet = Wallet()
wallet.id = "wallet"
let cellphone = Cellphone()
cellphone.id = "cellphone"
person.items = [weed, cellphone]
person.items = [wallet, cellphone]

person.favoriteWeed = weed
person.favoriteItem = wallet

let documentDictionary = try! person.documentDictionary()

Expand Down
2 changes: 1 addition & 1 deletion Vox.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = 'Vox'
spec.version = '1.0.3'
spec.version = '1.0.4'
spec.license = 'MIT'
spec.summary = 'A Swift JSONAPI framework'
spec.author = 'Aron Balog'
Expand Down
17 changes: 6 additions & 11 deletions Vox/Class/BaseResource.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,14 @@ + (SEL)getterForPropertyWithName:(NSString*)name {

+ (SEL)setterForPropertyWithName:(NSString*)name {
const char* propertyName = [name cStringUsingEncoding:NSASCIIStringEncoding];
objc_property_t prop = class_getProperty(self, propertyName);

char *selectorName = property_copyAttributeValue(prop, "S");
NSString* selectorString;
if (selectorName == NULL) {
char firstChar = (char)toupper(propertyName[0]);
NSString* capitalLetter = [NSString stringWithFormat:@"%c", firstChar];
NSString* reminder = [NSString stringWithCString: propertyName+1
encoding: NSASCIIStringEncoding];
selectorString = [@[@"set", capitalLetter, reminder, @":"] componentsJoinedByString:@""];
} else {
selectorString = [NSString stringWithCString:selectorName encoding:NSASCIIStringEncoding];
}

char firstChar = (char)toupper(propertyName[0]);
NSString* capitalLetter = [NSString stringWithFormat:@"%c", firstChar];
NSString* reminder = [NSString stringWithCString: propertyName+1
encoding: NSASCIIStringEncoding];
selectorString = [@[@"set", capitalLetter, reminder, @":"] componentsJoinedByString:@""];

return NSSelectorFromString(selectorString);
}
Expand Down
2 changes: 2 additions & 0 deletions Vox/Class/Deserializer_Collection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Foundation

extension Deserializer {
public class Collection<ResourceType: Resource> {
public init() {}

public func deserialize(data: Data) throws -> Document<[ResourceType]> {
return try JSONAPIDecoder.decode(data: data)
}
Expand Down
9 changes: 5 additions & 4 deletions VoxTests/DataSource/DataSourceSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ class DataSourceSpec: QuickSpec {
context("when fetching single resource", {
let client = MockClient()
let filterStrategy = MockFilterStrategy()
let sut = DataSource<MockResource>(strategy: .path(immutablePath), client: client)
let sut = DataSource<MockResource>(strategy: .path("path/<type>/<id>"), client: client)
try! sut
.fetch(id: "mock")
.fields([
Expand All @@ -368,7 +368,7 @@ class DataSourceSpec: QuickSpec {
})

it("client receives correct data for execution", closure: {
expect(client.executeRequestInspector.path).to(equal("path/mock-resource"))
expect(client.executeRequestInspector.path).to(equal("path/mock-resource/mock"))

let queryItems = client.executeRequestInspector.queryItems

Expand Down Expand Up @@ -527,8 +527,9 @@ class DataSourceSpec: QuickSpec {

context("when updating resource", {
let client = MockClient()
let sut = DataSource(strategy: .path(immutablePath), client: client)
let sut = DataSource(strategy: .path("path/<type>/<id>"), client: client)
let resource = MockResource()
resource.id = "mock"

try! sut.update(resource).result({ (document) in

Expand All @@ -541,7 +542,7 @@ class DataSourceSpec: QuickSpec {
})

it("client receives correct data for execution", closure: {
expect(client.executeRequestInspector.path).to(equal("path/mock-resource"))
expect(client.executeRequestInspector.path).to(equal("path/mock-resource/mock"))
})
})

Expand Down
158 changes: 157 additions & 1 deletion VoxTests/DataSource/PaginationSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ class PaginationSpec: QuickSpec {
it("returns first page document", closure: {
expect(error).toEventually(beNil())
expect(document).toEventuallyNot(beNil())
expect(error).toEventually(beNil())
expect(client.firstPath).toEventually(equal(router.fetch(type: Article3.self)))
})

context("when fetching next page", {
Expand All @@ -128,6 +130,44 @@ class PaginationSpec: QuickSpec {
})
}

describe("Paginated DataSource") {
let router = MockRouter()
let client = MockClient()
let dataSource: DataSource = DataSource<Article3>(strategy: .router(router), client: client)

var document: Document<[Article3]>?
var firstDocument: Document<[Article3]>?
var error: Error?

context("when fetching first page", {
try! dataSource.fetch().result({ (_document) in
document = _document
}, { (_error) in
error = _error
})

it("returns first page document", closure: {
expect(error).toEventually(beNil())
expect(document).toEventuallyNot(beNil())
expect(error).toEventually(beNil())
expect(client.firstPath).toEventually(equal(router.fetch(type: Article3.self)))
})

context("when fetching first page of document", {
try! document?.first?.result({ (_firstDocument) in
firstDocument = _firstDocument
}, { (_error) in
error = _error
})

it("returns first page document", closure: {
expect(error).toEventually(beNil())
expect(firstDocument).toEventuallyNot(beNil())
})
})
})
}

describe("Paginated DataSource") {
let router = MockRouter()
let client = MockClient()
Expand Down Expand Up @@ -159,7 +199,7 @@ class PaginationSpec: QuickSpec {
error = _error
})

it("receives page", closure: {
it("receives pagination", closure: {
expect(error).toEventually(beNil())
expect(pagination).toEventuallyNot(beNil())
expect(pagination?.new).toEventually(haveCount(1))
Expand All @@ -183,6 +223,122 @@ class PaginationSpec: QuickSpec {
})
})
}

describe("Paginated DataSource") {
let router = MockRouter()
let client = MockClient()
let dataSource: DataSource = DataSource<Article3>(strategy: .router(router), client: client)

var document: Document<[Article3]>?
var reloadedDocument: Document<[Article3]>?
var error: Error?

context("when fetching first page", {
try! dataSource.fetch().result({ (_document) in
document = _document
}, { (_error) in
error = _error
})

it("returns first page document", closure: {
expect(document).toEventuallyNot(beNil())
expect(document?.links).toEventuallyNot(beNil())
expect(error).toEventually(beNil())
expect(client.firstPath).toEventually(equal(router.fetch(type: Article3.self)))
})


context("when reloading current page", {
try! document?.reload?.result({ (document) in
reloadedDocument = document
}, { (_error) in
error = _error
})

it("receives page", closure: {
expect(error).toEventually(beNil())
expect(reloadedDocument).toEventuallyNot(beNil())
})
})
})
}

describe("Paginated DataSource") {
let router = MockRouter()
let client = MockClient()
let dataSource: DataSource = DataSource<Article3>(strategy: .router(router), client: client)

var document: Document<[Article3]>?
var previousDocument: Document<[Article3]>?
var error: Error?

context("when fetching first page", {
try! dataSource.fetch().result({ (_document) in
document = _document
}, { (_error) in
error = _error
})

it("returns first page document", closure: {
expect(document).toEventuallyNot(beNil())
expect(document?.links).toEventuallyNot(beNil())
expect(error).toEventually(beNil())
expect(client.firstPath).toEventually(equal(router.fetch(type: Article3.self)))
})


context("when fetching previous page", {
try! document?.previous?.result({ (document) in
previousDocument = document
}, { (_error) in
error = _error
})

it("receives page", closure: {
expect(error).toEventually(beNil())
expect(previousDocument).toEventuallyNot(beNil())
})
})
})
}

describe("Paginated DataSource") {
let router = MockRouter()
let client = MockClient()
let dataSource: DataSource = DataSource<Article3>(strategy: .router(router), client: client)

var document: Document<[Article3]>?
var lastDocument: Document<[Article3]>?
var error: Error?

context("when fetching first page", {
try! dataSource.fetch().result({ (_document) in
document = _document
}, { (_error) in
error = _error
})

it("returns first page document", closure: {
expect(error).toEventually(beNil())
expect(document).toEventuallyNot(beNil())
expect(error).toEventually(beNil())
expect(client.firstPath).toEventually(equal(router.fetch(type: Article3.self)))
})

context("when fetching last page", {
try! document?.last?.result({ (_lastDocument) in
lastDocument = _lastDocument
}, { (_error) in
error = _error
})

it("returns last page document", closure: {
expect(error).toEventually(beNil())
expect(lastDocument).toEventuallyNot(beNil())
})
})
})
}
}
}

12 changes: 6 additions & 6 deletions VoxTests/PropertyAccessorSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ fileprivate class Cellphone: Resource {
}
}

fileprivate class Weed: Resource {
fileprivate class Wallet: Resource {
override class var resourceType: String {
return "Weed"
return "Wallet"
}
}

Expand All @@ -51,12 +51,12 @@ class PropertyAccessorSpec: QuickSpec {
person.bestFriend = bestFriend
person.goodFriends = [bestFriend, anotherFriend]

let weed = Weed(context: person.context)
weed.id = "weed id"
let wallet = Wallet(context: person.context)
wallet.id = "wallet id"
let cellphone = Cellphone()
cellphone.id = "cellphone id"

person.items = [weed, cellphone]
person.items = [wallet, cellphone]

it("values are accessible", closure: {
expect(person.name).to(equal("MOCK"))
Expand All @@ -79,7 +79,7 @@ class PropertyAccessorSpec: QuickSpec {
expect(person.goodFriends?[1] === anotherFriend).to(beTrue())

expect(person.items).to(haveCount(2))
expect(person.items?[0] === weed).to(beTrue())
expect(person.items?[0] === wallet).to(beTrue())
expect(person.items?[1] === cellphone).to(beTrue())

})
Expand Down

0 comments on commit 83cd6f2

Please sign in to comment.