Skip to content

Commit 472a757

Browse files
committed
Updated unit tests
1 parent b87011a commit 472a757

2 files changed

Lines changed: 360 additions & 1 deletion

File tree

Tests/CoreModelTests/CoreDataTests.swift

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ final class CoreDataTests: XCTestCase {
1919

2020
func testCoreData() async throws {
2121

22-
let model = Model(entities: Person.self, Event.self)
22+
let model = Model(
23+
entities:
24+
Person.self,
25+
Event.self,
26+
Campground.self,
27+
Campground.RentalUnit.self
28+
)
2329

2430
let store = NSPersistentContainer(
2531
name: "Test\(UUID())",
@@ -50,6 +56,36 @@ final class CoreDataTests: XCTestCase {
5056
event1Data = try await store.fetch(Event.entityName, for: ObjectID(event1.id))!
5157
event1 = try .init(from: event1Data, log: { print("Decoder:", $0) })
5258
XCTAssertEqual(event1.people, [person1.id])
59+
60+
var campground = Campground(
61+
name: "Fair Play RV Park",
62+
address: """
63+
243 Fisher Cove Rd,
64+
Fair Play, SC
65+
""",
66+
location: .init(latitude: 34.51446212994721, longitude: -83.01371101951648),
67+
descriptionText: """
68+
At Fair Play RV Park, we are committed to providing a clean, safe and fun environment for all of our guests, including your fur-babies! We look forward to meeting you and having you stay with us!
69+
""",
70+
officeHours: Campground.Schedule(start: 60 * 8, end: 60 * 18)
71+
)
72+
73+
let rentalUnit = Campground.RentalUnit(
74+
campground: campground.id,
75+
name: "A1",
76+
amenities: [.amp50, .water, .mail, .river, .laundry],
77+
checkout: campground.officeHours
78+
)
79+
80+
var campgroundData = try campground.encode(log: { print("Encoder:", $0) })
81+
try await store.insert(campgroundData)
82+
let rentalUnitData = try rentalUnit.encode(log: { print("Encoder:", $0) })
83+
try await store.insert(rentalUnit)
84+
campgroundData = try await store.fetch(Campground.entityName, for: ObjectID(campground.id))!
85+
campground = try .init(from: campgroundData, log: { print("Decoder:", $0) })
86+
XCTAssertEqual(campground.units, [rentalUnit.id])
87+
let fetchedRentalUnit = try await store.fetch(Campground.RentalUnit.self, for: rentalUnit.id)
88+
XCTAssertEqual(fetchedRentalUnit, rentalUnit)
5389
}
5490
}
5591

Tests/CoreModelTests/TestModel.swift

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,326 @@ extension Event: Entity {
177177
]
178178
}
179179
}
180+
181+
/// Campground Location
182+
public struct Campground: Equatable, Hashable, Codable, Identifiable {
183+
184+
public let id: UUID
185+
186+
public let created: Date
187+
188+
public let updated: Date
189+
190+
public var name: String
191+
192+
public var address: String
193+
194+
public var location: LocationCoordinates
195+
196+
public var amenities: [Amenity]
197+
198+
public var phoneNumber: String?
199+
200+
public var descriptionText: String
201+
202+
/// The number of seconds from GMT.
203+
public var timeZone: Int
204+
205+
public var notes: String?
206+
207+
public var directions: String?
208+
209+
public var units: [RentalUnit.ID]
210+
211+
public var officeHours: Schedule
212+
213+
public init(
214+
id: UUID = UUID(),
215+
created: Date = Date(),
216+
updated: Date = Date(),
217+
name: String,
218+
address: String,
219+
location: LocationCoordinates,
220+
amenities: [Amenity] = [],
221+
phoneNumber: String? = nil,
222+
descriptionText: String,
223+
notes: String? = nil,
224+
directions: String? = nil,
225+
units: [RentalUnit.ID] = [],
226+
timeZone: Int = 0,
227+
officeHours: Schedule
228+
) {
229+
self.id = id
230+
self.created = created
231+
self.updated = updated
232+
self.name = name
233+
self.address = address
234+
self.location = location
235+
self.amenities = amenities
236+
self.phoneNumber = phoneNumber
237+
self.descriptionText = descriptionText
238+
self.notes = notes
239+
self.directions = directions
240+
self.units = units
241+
self.timeZone = timeZone
242+
self.officeHours = officeHours
243+
}
244+
245+
public enum CodingKeys: CodingKey {
246+
case id
247+
case created
248+
case updated
249+
case name
250+
case address
251+
case location
252+
case amenities
253+
case phoneNumber
254+
case descriptionText
255+
case timeZone
256+
case notes
257+
case directions
258+
case units
259+
case officeHours
260+
}
261+
}
262+
263+
extension Campground: Entity {
264+
265+
public static var entityName: EntityName { "Campground" }
266+
267+
public static var attributes: [CodingKeys: AttributeType] {
268+
[
269+
.name : .string,
270+
.created : .date,
271+
.updated : .date,
272+
.address : .string,
273+
.location: .string,
274+
.amenities: .string,
275+
.phoneNumber: .string,
276+
.descriptionText: .string,
277+
.timeZone: .int32,
278+
.notes: .string,
279+
.directions: .string,
280+
.officeHours: .string
281+
]
282+
}
283+
284+
public static var relationships: [CodingKeys: Relationship] {
285+
[
286+
.units : Relationship(
287+
id: PropertyKey(CodingKeys.units),
288+
type: .toMany,
289+
destinationEntity: RentalUnit.entityName,
290+
inverseRelationship: PropertyKey(RentalUnit.CodingKeys.campground)
291+
)
292+
]
293+
}
294+
}
295+
296+
public extension Campground {
297+
298+
/// Campground Amenities
299+
enum Amenity: String, Codable, CaseIterable {
300+
301+
case water
302+
case amp30
303+
case amp50
304+
case wifi
305+
case laundry
306+
case mail
307+
case dumpStation
308+
case picnicArea
309+
case storage
310+
case cabins
311+
case showers
312+
case restrooms
313+
case pool
314+
case fishing
315+
case beach
316+
case lake
317+
case river
318+
case rv
319+
case tent
320+
case pets
321+
}
322+
}
323+
324+
extension Array: AttributeEncodable where Self.Element == Campground.Amenity {
325+
326+
public var attributeValue: AttributeValue {
327+
let string = self.reduce("", { $0 + ($0.isEmpty ? "" : ",") + $1.rawValue })
328+
return .string(string)
329+
}
330+
}
331+
332+
extension Array: AttributeDecodable where Self.Element == Campground.Amenity {
333+
334+
public init?(attributeValue: AttributeValue) {
335+
guard let string = String(attributeValue: attributeValue) else {
336+
return nil
337+
}
338+
let components = string
339+
.components(separatedBy: ",")
340+
.filter { $0.isEmpty == false }
341+
var values = [Campground.Amenity]()
342+
values.reserveCapacity(components.count)
343+
for element in components {
344+
guard let value = Self.Element(rawValue: element) else {
345+
return nil
346+
}
347+
values.append(value)
348+
}
349+
self = values
350+
}
351+
}
352+
353+
public extension Campground {
354+
355+
/// Location Coordinates
356+
struct LocationCoordinates: Equatable, Hashable, Codable {
357+
358+
/// Latitude
359+
public var latitude: Double
360+
361+
/// Longitude
362+
public var longitude: Double
363+
364+
public init(latitude: Double, longitude: Double) {
365+
self.latitude = latitude
366+
self.longitude = longitude
367+
}
368+
}
369+
}
370+
371+
extension Campground.LocationCoordinates: AttributeEncodable {
372+
373+
public var attributeValue: AttributeValue {
374+
return .string("\(latitude),\(longitude)")
375+
}
376+
}
377+
378+
extension Campground.LocationCoordinates: AttributeDecodable {
379+
380+
public init?(attributeValue: AttributeValue) {
381+
guard let string = String(attributeValue: attributeValue) else {
382+
return nil
383+
}
384+
let components = string.components(separatedBy: ",")
385+
guard components.count == 2,
386+
let latitude = Double(components[0]),
387+
let longitude = Double(components[1]) else {
388+
return nil
389+
}
390+
self.init(latitude: latitude, longitude: longitude)
391+
}
392+
}
393+
394+
public extension Campground {
395+
396+
/// Schedule (e.g. Check in, Check Out)
397+
struct Schedule: Equatable, Hashable, Codable {
398+
399+
public var start: UInt
400+
401+
public var end: UInt
402+
403+
public init(start: UInt, end: UInt) {
404+
assert(start < end)
405+
self.start = start
406+
self.end = end
407+
}
408+
}
409+
}
410+
411+
extension Campground.Schedule: AttributeEncodable {
412+
413+
public var attributeValue: AttributeValue {
414+
return .string("\(start),\(end)")
415+
}
416+
}
417+
418+
extension Campground.Schedule: AttributeDecodable {
419+
420+
public init?(attributeValue: AttributeValue) {
421+
guard let string = String(attributeValue: attributeValue) else {
422+
return nil
423+
}
424+
let components = string.components(separatedBy: ",")
425+
guard components.count == 2,
426+
let start = UInt(components[0]),
427+
let end = UInt(components[1]) else {
428+
return nil
429+
}
430+
self.init(start: start, end: end)
431+
}
432+
}
433+
434+
public extension Campground {
435+
436+
/// Campground Rental Unit
437+
struct RentalUnit: Equatable, Hashable, Codable, Identifiable {
438+
439+
public let id: UUID
440+
441+
public let campground: Campground.ID
442+
443+
public var name: String
444+
445+
public var notes: String?
446+
447+
public var amenities: [Amenity]
448+
449+
public var checkout: Schedule
450+
451+
public init(
452+
id: UUID = UUID(),
453+
campground: Campground.ID,
454+
name: String,
455+
notes: String? = nil,
456+
amenities: [Amenity] = [],
457+
checkout: Schedule
458+
) {
459+
self.id = id
460+
self.campground = campground
461+
self.name = name
462+
self.notes = notes
463+
self.amenities = amenities
464+
self.checkout = checkout
465+
}
466+
467+
public enum CodingKeys: CodingKey {
468+
469+
case id
470+
case campground
471+
case name
472+
case notes
473+
case amenities
474+
case checkout
475+
}
476+
}
477+
}
478+
479+
extension Campground.RentalUnit: Entity {
480+
481+
public static var entityName: EntityName { "RentalUnit" }
482+
483+
public static var attributes: [CodingKeys: AttributeType] {
484+
[
485+
.name : .string,
486+
.notes : .string,
487+
.amenities : .string,
488+
.checkout : .string
489+
]
490+
}
491+
492+
public static var relationships: [CodingKeys: Relationship] {
493+
[
494+
.campground : Relationship(
495+
id: PropertyKey(CodingKeys.campground),
496+
type: .toOne,
497+
destinationEntity: Campground.entityName,
498+
inverseRelationship: PropertyKey(Campground.CodingKeys.units)
499+
)
500+
]
501+
}
502+
}

0 commit comments

Comments
 (0)