From ac7f9f62d4f4465461c14bf4f79ce67bd8afbead Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 15 Oct 2018 11:16:29 -0600 Subject: [PATCH] factories for tests --- .../src/Tests/TestUtil/Factories.swift | 315 ++++++++++++++++++ .../Tests/TestUtil}/SSKSwiftTests.swift | 0 2 files changed, 315 insertions(+) create mode 100644 SignalServiceKit/src/Tests/TestUtil/Factories.swift rename SignalServiceKit/{tests/Util => src/Tests/TestUtil}/SSKSwiftTests.swift (100%) diff --git a/SignalServiceKit/src/Tests/TestUtil/Factories.swift b/SignalServiceKit/src/Tests/TestUtil/Factories.swift new file mode 100644 index 000000000..b5abe3704 --- /dev/null +++ b/SignalServiceKit/src/Tests/TestUtil/Factories.swift @@ -0,0 +1,315 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +import Foundation +import SignalServiceKit + +/// Factories for creating some default TSYapDatabaseObjects. +/// +/// To customize properties applied by the factory (e.g. `someProperty`) +/// the factory needs a `var somePropertyBuilder: () -> (SomePropertyType)` +/// which is then used in the `create` method. +/// +/// Examples: +/// +/// Create one empty thread: +/// +/// let oneThread = ContactThreadFactory().create() +/// +/// Create 12 thread's with 100 messages each +/// +/// let factory = ContractThreadFactory() +/// factory.messageCount = 100 +/// factory.create(count: 12) +/// +/// Create 100 messages in an existing thread +/// +/// let existingThread: TSThread = getSomeExistingThread() +/// let messageFactory = TSIncomingMessageFactory() +/// messageFactory.threadCreator = { _ in return existingThread } +/// messageFactory.create(count: 100) +/// +protocol Factory { + associatedtype ObjectType: TSYapDatabaseObject + + var dbConnection: YapDatabaseConnection { get } + + func readWrite(block: @escaping (YapDatabaseReadWriteTransaction) -> Void) + + // MARK: Factory Methods + func create() -> ObjectType + func create(transaction: YapDatabaseReadWriteTransaction) -> ObjectType + + func create(count: UInt) -> [ObjectType] + func create(count: UInt, transaction: YapDatabaseReadWriteTransaction) -> [ObjectType] +} + +extension Factory { + var dbConnection: YapDatabaseConnection { + return OWSPrimaryStorage.shared().dbReadWriteConnection + } + + func readWrite(block: @escaping (YapDatabaseReadWriteTransaction) -> Void) { + dbConnection.readWrite(block) + } + + // MARK: Factory Methods + + func create() -> ObjectType { + var item: ObjectType! + self.readWrite { transaction in + item = self.create(transaction: transaction) + } + return item + } + + func create(count: UInt) -> [ObjectType] { + var items: [ObjectType] = [] + self.readWrite { transaction in + items = self.create(count: count, transaction: transaction) + } + return items + } + + func create(count: UInt, transaction: YapDatabaseReadWriteTransaction) -> [ObjectType] { + return (0.. TSContactThread { + let threadId = generateContactThreadId() + let thread = TSContactThread.getOrCreateThread(withContactId: threadId, transaction: transaction) + + let incomingMessageFactory = IncomingMessageFactory() + incomingMessageFactory.threadCreator = { _ in return thread } + + let outgoingMessageFactory = OutgoingMessageFactory() + outgoingMessageFactory.threadCreator = { _ in return thread } + + (0.. String { + return CommonGenerator.contactId + } +} + +class OutgoingMessageFactory: Factory { + + // MARK: Factory + + func create(transaction: YapDatabaseReadWriteTransaction) -> TSOutgoingMessage { + let item = TSOutgoingMessage(outgoingMessageWithTimestamp: timestampBuilder(), + in: threadCreator(transaction), + messageBody: messageBodyBuilder(), + attachmentIds: [], + expiresInSeconds: 0, + expireStartedAt: 0, + isVoiceMessage: false, + groupMetaMessage: .unspecified, + quotedMessage: nil, + contactShare: nil) + item.save(with: transaction) + + return item + } + + // MARK: Dependent Factories + + var threadCreator: (YapDatabaseReadWriteTransaction) -> TSThread = { transaction in + ContactThreadFactory().create(transaction: transaction) + } + + // MARK: Generators + + var timestampBuilder: () -> UInt64 = { + return NSDate.ows_millisecondTimeStamp() + } + + var messageBodyBuilder: () -> String = { + return CommonGenerator.paragraph + } +} + +class IncomingMessageFactory: Factory { + + // MARK: Factory + + func create(transaction: YapDatabaseReadWriteTransaction) -> TSIncomingMessage { + let item = TSIncomingMessage(incomingMessageWithTimestamp: timestampBuilder(), + in: threadCreator(transaction), + authorId: authorIdBuilder(), + sourceDeviceId: 1, + messageBody: messageBodyBuilder(), + attachmentIds: [], + expiresInSeconds: 0, + quotedMessage: nil, + contactShare: nil, + serverTimestamp: nil, + wasReceivedByUD: false) + + item.save(with: transaction) + + return item + } + + // MARK: Dependent Factories + + var threadCreator: (YapDatabaseReadWriteTransaction) -> TSThread = { transaction in + ContactThreadFactory().create(transaction: transaction) + } + + // MARK: Generators + + var timestampBuilder: () -> UInt64 = { + return NSDate.ows_millisecondTimeStamp() + } + + var messageBodyBuilder: () -> String = { + return CommonGenerator.paragraph + } + + var authorIdBuilder: () -> String = { + return CommonGenerator.contactId + } +} + +class GroupThreadFactory: Factory { + + var messageCount: UInt = 0 + + func create(transaction: YapDatabaseReadWriteTransaction) -> TSGroupThread { + let thread = TSGroupThread.getOrCreateThread(with: groupModelBuilder(self), + transaction: transaction) + thread.save(with: transaction) + + let incomingMessageFactory = IncomingMessageFactory() + incomingMessageFactory.threadCreator = { _ in return thread } + + let outgoingMessageFactory = OutgoingMessageFactory() + outgoingMessageFactory.threadCreator = { _ in return thread } + + (0.. TSGroupModel = { groupThreadFactory in + return TSGroupModel(title: groupThreadFactory.titleBuilder(), + memberIds: groupThreadFactory.memberIdsBuilder(), + image: groupThreadFactory.imageBuilder(), + groupId: groupThreadFactory.groupIdBuilder()) + } + + var titleBuilder: () -> String? = { + return CommonGenerator.words(count: 3) + } + + var groupIdBuilder: () -> Data = { + return Randomness.generateRandomBytes(Int32(kGroupIdLength))! + } + + var imageBuilder: () -> UIImage? = { + return nil + } + + var memberIdsBuilder: () -> [RecipientIdentifier] = { + let groupSize = (1..<10).randomElement()! + return (0.. String { + var result: [String] = [] + + while result.count < count { + let remaining = count - result.count + result += sentence.split(separator: " ").prefix(remaining).map { String($0) } + } + + return result.joined(separator: " ") + } + + static var sentence: String { + return sentences.randomElement()! + } + + static func sentences(count: UInt) -> [String] { + return (0.. = (2..<9) + static var paragraph: String { + let sentenceCount = sentenceCountInParagraph.randomElement()! + return paragraph(sentenceCount: sentenceCount) + } + + static func paragraph(sentenceCount: UInt) -> String { + return sentences(count: sentenceCount).joined(separator: " ") + } +} diff --git a/SignalServiceKit/tests/Util/SSKSwiftTests.swift b/SignalServiceKit/src/Tests/TestUtil/SSKSwiftTests.swift similarity index 100% rename from SignalServiceKit/tests/Util/SSKSwiftTests.swift rename to SignalServiceKit/src/Tests/TestUtil/SSKSwiftTests.swift