// _____ _
// |_ _| |_ _ _ ___ ___ _ __ __ _
// | | | ' \| '_/ -_) -_) ' \/ _` |_
// |_| |_||_|_| \___\___|_|_|_\__,_(_)
//
// Threema iOS Client
// Copyright (c) 2019-2020 Threema GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License, version 3,
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
import XCTest
import CoreData
class EntityDestroyerTests: XCTestCase {
var objCnx: NSManagedObjectContext!
override func setUp() {
super.setUp()
self.objCnx = TestDatabasePersistentManager.devNullContext()
// Setup DB for testing, insert 10 video messages
let testEntityManager = TestDatabaseEntityManager(context: self.objCnx)
testEntityManager.save {
let conversation = testEntityManager.createConversation()
let thumbnail = testEntityManager.createImageData()
let userCalendar = Calendar.current
let toDate = Date()
for index in 1...10 {
var addDate = DateComponents()
addDate.day = index * -1
addDate.hour = 1
let date = userCalendar.date(byAdding: addDate, to: toDate)
testEntityManager.createVideoMessage(conversation: conversation, thumbnail: thumbnail, videoData: testEntityManager.createVideoData(), date: date)
}
}
// necessary for ValidationLogger
AppGroup.setGroupId("group.ch.threema") //THREEMA_GROUP_IDENTIFIER @"group.ch.threema"
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testDeleteMedias() {
let deleteTests = [
// days diff, expected count of deleted media
[-2, 8],
[nil, 2]
]
let userCalendar = Calendar.current
for deleteTest in deleteTests {
var olderThan: Date? = nil
if let daysAdd = deleteTest[0] {
olderThan = userCalendar.date(byAdding: .day, value: daysAdd, to: Date())
}
let ed = EntityDestroyer(managedObjectContext: self.objCnx)
let count = ed.deleteMedias(olderThan: olderThan)
XCTAssertEqual(count, deleteTest[1]!, "not expected count of deleted medias")
}
}
func testDeleteMessages() {
let deleteTests = [
// days diff, expected count of deleted media
[-2, 8],
[nil, 2]
]
let userCalendar = Calendar.current
for deleteTest in deleteTests {
var olderThan: Date? = nil
if let daysAdd = deleteTest[0] {
olderThan = userCalendar.date(byAdding: .day, value: daysAdd, to: Date())
}
let ed = EntityDestroyer(managedObjectContext: self.objCnx)
let count = ed.deleteMessages(olderThan: olderThan)
XCTAssertEqual(count, deleteTest[1]!, "not expected count of deleted messages")
}
}
class TestDatabasePersistentManager {
/**
Context in memory, doesn't work with NSBatch... commands (use devNullContext)
- Returns:
DB context for testing
*/
static func inMemoryContext() -> NSManagedObjectContext {
let modelURL = BundleUtil.url(forResource:"ThreemaData", withExtension: "momd")
let managedObjectContext = NSManagedObjectModel(contentsOf: modelURL!)
let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectContext!)
do {
try persistentStoreCoordinator.addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil)
}
catch {
fatalError("Adding in memory persistent store failed")
}
let context = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.mainQueueConcurrencyType)
context.persistentStoreCoordinator = persistentStoreCoordinator
return context
}
/**
Context stored data to /dev/null, works with NSBatch... commands
- Returns:
DB context for testing
*/
static func devNullContext() -> NSManagedObjectContext {
let modelURL = BundleUtil.url(forResource:"ThreemaData", withExtension: "momd")
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL!)
let container = NSPersistentContainer(name: "TestData", managedObjectModel: managedObjectModel!)
container.persistentStoreDescriptions[0].url = URL(fileURLWithPath: "/dev/null")
container.loadPersistentStores { (description, error) in
XCTAssertNil(error)
}
return container.viewContext
}
}
class TestDatabaseEntityManager {
private let objCnx: NSManagedObjectContext
required init(context: NSManagedObjectContext) {
self.objCnx = context
}
/**
Save data modifications on DB.
- Parameters:
- dbModificationAction: Closure with data modifications
*/
func save(dbModificationAction: () -> Void) {
do {
dbModificationAction()
try self.objCnx.save()
}
catch {
print(error)
XCTFail("Could not generate test data.")
}
}
func createConversation() -> Conversation {
let conversation = createEntity(objectType: Conversation.self)
conversation.marked = false
conversation.typing = false
conversation.unreadMessageCount = 0
return conversation
}
func createImageData() -> ImageData {
let imageData = createEntity(objectType: ImageData.self)
imageData.data = Data([22])
imageData.height = 22
imageData.width = 22
return imageData
}
func createVideoData() -> VideoData {
let videoData = createEntity(objectType: VideoData.self)
videoData.data = Data([1])
return videoData
}
func createVideoMessage(conversation: Conversation, thumbnail: ImageData, videoData: VideoData?, date: Date?) -> VideoMessage {
let videoMessage = createEntity(objectType: VideoMessage.self)
videoMessage.date = date
videoMessage.delivered = 1
videoMessage.id = Data([11])
videoMessage.isOwn = true
videoMessage.read = true
videoMessage.sent = true
videoMessage.userack = false
videoMessage.conversation = conversation
videoMessage.thumbnail = thumbnail
videoMessage.duration = 10
videoMessage.video = videoData
videoMessage.remoteSentDate = Date()
return videoMessage
}
private func createEntity(objectType: T.Type) -> T {
var entityName: String
if objectType is Conversation.Type {
entityName = "Conversation"
}
else if objectType is ImageData.Type {
entityName = "ImageData"
}
else if objectType is VideoData.Type {
entityName = "VideoData"
}
else if objectType is VideoMessage.Type {
entityName = "VideoMessage"
}
else {
fatalError("objects type not defined")
}
return NSEntityDescription.insertNewObject(forEntityName: entityName, into: self.objCnx) as! T
}
}
}