mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 12:07:55 +00:00
Rageshake Service (#70)
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// BugReportServiceTests.swift
|
||||
// UnitTests
|
||||
//
|
||||
// Created by Ismail on 31.05.2022.
|
||||
// Copyright © 2022 element.io. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@testable import ElementX
|
||||
import XCTest
|
||||
|
||||
class BugReportServiceTests: XCTestCase {
|
||||
|
||||
let bugReportService = MockBugReportService()
|
||||
|
||||
func testInitialStateWithMockService() {
|
||||
XCTAssertFalse(bugReportService.crashedLastRun)
|
||||
}
|
||||
|
||||
func testSubmitBugReportWithMockService() async throws {
|
||||
let result = try await bugReportService.submitBugReport(text: "i cannot send message",
|
||||
includeLogs: true,
|
||||
includeCrashLog: true,
|
||||
githubLabels: [],
|
||||
files: [])
|
||||
XCTAssertFalse(result.reportUrl.isEmpty)
|
||||
}
|
||||
|
||||
func testInitialStateWithRealService() throws {
|
||||
let service = try BugReportService(withBaseUrlString: "https://www.example.com",
|
||||
sentryEndpoint: "mock_sentry_dsn",
|
||||
applicationId: "mock_app_id",
|
||||
session: .mock)
|
||||
XCTAssertFalse(service.crashedLastRun)
|
||||
}
|
||||
|
||||
@MainActor func testSubmitBugReportWithRealService() async throws {
|
||||
let service = try BugReportService(withBaseUrlString: "https://www.example.com",
|
||||
sentryEndpoint: "mock_sentry_dsn",
|
||||
applicationId: "mock_app_id",
|
||||
session: .mock)
|
||||
|
||||
let result = try await service.submitBugReport(text: "i cannot send message",
|
||||
includeLogs: true,
|
||||
includeCrashLog: true,
|
||||
githubLabels: [],
|
||||
files: [])
|
||||
|
||||
XCTAssertEqual(result.reportUrl, "https://example.com/123")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class MockURLProtocol: URLProtocol {
|
||||
|
||||
override func startLoading() {
|
||||
let response = "{\"report_url\":\"https://example.com/123\"}"
|
||||
if let data = response.data(using: .utf8) {
|
||||
let urlResponse = URLResponse()
|
||||
client?.urlProtocol(self, didReceive: urlResponse, cacheStoragePolicy: .allowedInMemoryOnly)
|
||||
client?.urlProtocol(self, didLoad: data)
|
||||
client?.urlProtocolDidFinishLoading(self)
|
||||
}
|
||||
}
|
||||
|
||||
override func stopLoading() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
|
||||
return request
|
||||
}
|
||||
|
||||
override class func canInit(with request: URLRequest) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension URLSession {
|
||||
|
||||
static var mock: URLSession {
|
||||
let configuration = URLSessionConfiguration.default
|
||||
configuration.protocolClasses = [MockURLProtocol.self] + (configuration.protocolClasses ?? [])
|
||||
let result = URLSession(configuration: configuration)
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
@testable import ElementX
|
||||
|
||||
@MainActor
|
||||
class BugReportViewModelTests: XCTestCase {
|
||||
|
||||
func testInitialState() {
|
||||
let viewModel = BugReportViewModel(bugReportService: MockBugReportService(), screenshot: nil)
|
||||
let context = viewModel.context
|
||||
|
||||
XCTAssertEqual(context.reportText, "")
|
||||
XCTAssertNil(context.viewState.screenshot)
|
||||
XCTAssertTrue(context.sendingLogsEnabled)
|
||||
}
|
||||
|
||||
func testToggleSendingLogs() async throws {
|
||||
let viewModel = BugReportViewModel(bugReportService: MockBugReportService(), screenshot: nil)
|
||||
let context = viewModel.context
|
||||
|
||||
context.send(viewAction: .toggleSendLogs)
|
||||
await Task.yield()
|
||||
XCTAssertFalse(context.sendingLogsEnabled)
|
||||
}
|
||||
|
||||
func testClearScreenshot() async throws {
|
||||
let viewModel = BugReportViewModel(bugReportService: MockBugReportService(), screenshot: UIImage.actions)
|
||||
let context = viewModel.context
|
||||
|
||||
context.send(viewAction: .removeScreenshot)
|
||||
await Task.yield()
|
||||
XCTAssertNil(context.viewState.screenshot)
|
||||
}
|
||||
}
|
||||
@@ -19,11 +19,65 @@ import XCTest
|
||||
@testable import ElementX
|
||||
|
||||
class HomeScreenViewModelTests: XCTestCase {
|
||||
override func setUpWithError() throws {
|
||||
|
||||
var viewModel: HomeScreenViewModelProtocol!
|
||||
var context: HomeScreenViewModelType.Context!
|
||||
|
||||
@MainActor override func setUpWithError() throws {
|
||||
viewModel = HomeScreenViewModel(attributedStringBuilder: AttributedStringBuilder())
|
||||
context = viewModel.context
|
||||
}
|
||||
|
||||
func testInitialState() {
|
||||
@MainActor func testLogout() async throws {
|
||||
var correctResult = false
|
||||
viewModel.callback = { result in
|
||||
switch result {
|
||||
case .logout:
|
||||
correctResult = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
context.send(viewAction: .logout)
|
||||
await Task.yield()
|
||||
XCTAssert(correctResult)
|
||||
}
|
||||
|
||||
@MainActor func testSelectRoom() async throws {
|
||||
let mockRoomId = "mock_room_id"
|
||||
var correctResult = false
|
||||
var selectedRoomId = ""
|
||||
viewModel.callback = { result in
|
||||
switch result {
|
||||
case .selectRoom(let roomId):
|
||||
correctResult = true
|
||||
selectedRoomId = roomId
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
context.send(viewAction: .selectRoom(roomIdentifier: mockRoomId))
|
||||
await Task.yield()
|
||||
XCTAssert(correctResult)
|
||||
XCTAssertEqual(mockRoomId, selectedRoomId)
|
||||
}
|
||||
|
||||
@MainActor func testTapUserAvatar() async throws {
|
||||
var correctResult = false
|
||||
viewModel.callback = { result in
|
||||
switch result {
|
||||
case .tapUserAvatar:
|
||||
correctResult = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
context.send(viewAction: .tapUserAvatar)
|
||||
await Task.yield()
|
||||
XCTAssert(correctResult)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// ImageExtensionTests.swift
|
||||
// UnitTests
|
||||
//
|
||||
// Created by Ismail on 31.05.2022.
|
||||
// Copyright © 2022 element.io. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import ElementX
|
||||
|
||||
enum ImageAnonymizerTestsError: String, Error {
|
||||
case screenshotNotFound
|
||||
}
|
||||
|
||||
class ImageAnonymizerTests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func sampleScreenshot() throws -> UIImage {
|
||||
let bundle = Bundle(for: self.classForCoder)
|
||||
guard let path = bundle.path(forResource: "sample_screenshot", ofType: "png"),
|
||||
let image = UIImage(contentsOfFile: path) else {
|
||||
throw ImageAnonymizerTestsError.screenshotNotFound
|
||||
}
|
||||
return image
|
||||
}
|
||||
|
||||
func testImageAnonymizationConfidenceLevel() async throws {
|
||||
let image = try sampleScreenshot()
|
||||
|
||||
let anonymized5 = try await ImageAnonymizer.anonymizedImage(from: image)
|
||||
let anonymized1 = try await ImageAnonymizer.anonymizedImage(from: image, confidenceLevel: 0.1)
|
||||
|
||||
// comparing colors is a complicated process, just compare images for now
|
||||
XCTAssertNotEqual(image, anonymized5)
|
||||
XCTAssertNotEqual(anonymized1, anonymized5)
|
||||
}
|
||||
|
||||
func testImageAnonymizationFillColor() async throws {
|
||||
let image = try sampleScreenshot()
|
||||
|
||||
let anonymizedRed = try await ImageAnonymizer.anonymizedImage(from: image)
|
||||
let anonymizedBlue = try await ImageAnonymizer.anonymizedImage(from: image, fillColor: .blue)
|
||||
|
||||
// comparing colors is a complicated process, just compare images for now
|
||||
XCTAssertNotEqual(image, anonymizedRed)
|
||||
XCTAssertNotEqual(anonymizedBlue, anonymizedRed)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// LoggingTests.swift
|
||||
// UnitTests
|
||||
//
|
||||
// Created by Ismail on 31.05.2022.
|
||||
// Copyright © 2022 element.io. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import ElementX
|
||||
|
||||
class LoggingTests: XCTestCase {
|
||||
|
||||
private enum Constants {
|
||||
static let genericFailure = "Test failed"
|
||||
}
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testFileLogging() throws {
|
||||
MXLogger.deleteLogFiles()
|
||||
guard let logFiles = MXLogger.logFiles() else {
|
||||
XCTFail(Constants.genericFailure)
|
||||
return
|
||||
}
|
||||
XCTAssertTrue(logFiles.isEmpty)
|
||||
|
||||
let log = UUID().uuidString
|
||||
|
||||
let configuration = MXLogConfiguration()
|
||||
configuration.redirectLogsToFiles = true
|
||||
MXLog.configure(configuration)
|
||||
MXLog.debug(log)
|
||||
guard let logFile = MXLogger.logFiles().first else {
|
||||
XCTFail(Constants.genericFailure)
|
||||
return
|
||||
}
|
||||
|
||||
let content = try String(contentsOfFile: logFile)
|
||||
XCTAssert(content.contains(log))
|
||||
}
|
||||
|
||||
func testLogLevels() throws {
|
||||
MXLogger.deleteLogFiles()
|
||||
guard let logFiles = MXLogger.logFiles() else {
|
||||
XCTFail(Constants.genericFailure)
|
||||
return
|
||||
}
|
||||
XCTAssert(logFiles.isEmpty)
|
||||
|
||||
let log = UUID().uuidString
|
||||
|
||||
let configuration = MXLogConfiguration()
|
||||
configuration.logLevel = .error
|
||||
configuration.redirectLogsToFiles = true
|
||||
MXLog.configure(configuration)
|
||||
MXLog.debug(log)
|
||||
guard let logFile = MXLogger.logFiles().first else {
|
||||
XCTFail(Constants.genericFailure)
|
||||
return
|
||||
}
|
||||
|
||||
let content = try String(contentsOfFile: logFile)
|
||||
XCTAssertFalse(content.contains(log))
|
||||
}
|
||||
|
||||
func testSubLogName() {
|
||||
MXLogger.deleteLogFiles()
|
||||
guard let logFiles = MXLogger.logFiles() else {
|
||||
XCTFail(Constants.genericFailure)
|
||||
return
|
||||
}
|
||||
XCTAssert(logFiles.isEmpty)
|
||||
|
||||
let subLogName = "nse"
|
||||
|
||||
let configuration = MXLogConfiguration()
|
||||
configuration.subLogName = subLogName
|
||||
configuration.redirectLogsToFiles = true
|
||||
MXLog.configure(configuration)
|
||||
MXLog.debug(UUID().uuidString)
|
||||
guard let logFile = MXLogger.logFiles().first else {
|
||||
XCTFail(Constants.genericFailure)
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertTrue(logFile.contains(subLogName))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// ScreenshotDetectorTests.swift
|
||||
// UnitTests
|
||||
//
|
||||
// Created by Ismail on 31.05.2022.
|
||||
// Copyright © 2022 element.io. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@testable import ElementX
|
||||
import XCTest
|
||||
import Photos
|
||||
|
||||
class ScreenshotDetectorTests: XCTestCase {
|
||||
|
||||
@MainActor func testDetection() async {
|
||||
async { expectation in
|
||||
let detector = ScreenshotDetector()
|
||||
// disable auto request authorization
|
||||
detector.autoRequestPHAuthorization = false
|
||||
detector.callback = { image, error in
|
||||
|
||||
if PHPhotoLibrary.authorizationStatus(for: .readWrite) == .authorized {
|
||||
// if Photos already authorized on the simulator
|
||||
|
||||
// we should get an image
|
||||
XCTAssertNotNil(image)
|
||||
|
||||
// we should not get an error
|
||||
XCTAssertNil(error)
|
||||
} else {
|
||||
// otherwise we should not get an image
|
||||
XCTAssertNil(image)
|
||||
|
||||
// and get an error
|
||||
guard let error = error else {
|
||||
XCTFail("Should get an error")
|
||||
return
|
||||
}
|
||||
|
||||
switch error {
|
||||
case ScreenshotDetectorError.notAuthorized:
|
||||
break
|
||||
default:
|
||||
XCTFail("Unknown error")
|
||||
}
|
||||
}
|
||||
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
NotificationCenter.default.post(name: UIApplication.userDidTakeScreenshotNotification, object: nil)
|
||||
}
|
||||
}
|
||||
|
||||
private func async(_ timeout: TimeInterval = 0.5, _ block: @escaping (XCTestExpectation) -> Void) {
|
||||
let waiter = XCTWaiter()
|
||||
let expectation = XCTestExpectation(description: "Async operation expectation")
|
||||
block(expectation)
|
||||
waiter.wait(for: [expectation], timeout: timeout)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
@testable import ElementX
|
||||
|
||||
@MainActor
|
||||
class SettingsViewModelTests: XCTestCase {
|
||||
|
||||
var viewModel: SettingsViewModelProtocol!
|
||||
var context: SettingsViewModelType.Context!
|
||||
|
||||
@MainActor override func setUpWithError() throws {
|
||||
viewModel = SettingsViewModel()
|
||||
context = viewModel.context
|
||||
}
|
||||
|
||||
func testInitialState() {
|
||||
XCTAssert(context.viewState.crashButtonVisible)
|
||||
}
|
||||
|
||||
func testReportBug() async throws {
|
||||
var correctResult = false
|
||||
viewModel.callback = { result in
|
||||
correctResult = result == .reportBug
|
||||
}
|
||||
|
||||
context.send(viewAction: .reportBug)
|
||||
await Task.yield()
|
||||
XCTAssert(correctResult)
|
||||
}
|
||||
|
||||
func testCrash() async throws {
|
||||
var correctResult = false
|
||||
viewModel.callback = { result in
|
||||
correctResult = result == .crash
|
||||
}
|
||||
|
||||
context.send(viewAction: .crash)
|
||||
await Task.yield()
|
||||
XCTAssert(correctResult)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user