Skip to content

Commit

Permalink
Add button to save logs on documents directory (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardocamaratta authored Sep 5, 2024
1 parent 098db85 commit 0dc9d5b
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 23 deletions.
51 changes: 31 additions & 20 deletions Sources/Netbob/Core/LogFileProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import UIKit

protocol LogFileProviderProtocol {
func createFullLog() throws -> URL
func saveFullLog() throws
func createSingleLog(from connection: HTTPConnection, includeBody: Bool) throws -> URL
}

Expand All @@ -27,36 +28,34 @@ class LogFileProvider: LogFileProviderProtocol {
}

func createFullLog() throws -> URL {
let deviceModel = UIDevice.current.model
let osVersion = UIDevice.current.systemVersion
let appVersion = Bundle.main.appVersion

let string = "Device: \(deviceModel)\n" +
"OS Version: \(osVersion)\n" +
"App Version: \(appVersion)\n\n" +
httpConnectionRepository
.current
.map { $0.toString(includeBody: true) }
.joined(separator: "\n\n\n\(String(repeating: "-", count: 30))\n\n\n")

let logFileUrl = fileManager.temporaryDirectory.appendingPathComponent("session.log")
try writeAction(string, logFileUrl)
try writeAction(fullLogs, logFileUrl)
return logFileUrl
}

func createSingleLog(from connection: HTTPConnection, includeBody: Bool) throws -> URL {
let deviceModel = UIDevice.current.model
let osVersion = UIDevice.current.systemVersion
let appVersion = Bundle.main.appVersion
func saveFullLog() throws {
guard let documentsUrl = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let logFileUrl = documentsUrl.appendingPathComponent("network-logs.txt")
try writeAction(fullLogs, logFileUrl)
}

let string = "Device: \(deviceModel)\n" +
"OS Version: \(osVersion)\n" +
"App Version: \(appVersion)\n\n" +
func createSingleLog(from connection: HTTPConnection, includeBody: Bool) throws -> URL {
let string = .logHeader +
connection.toString(includeBody: includeBody)

let logFileUrl = fileManager.temporaryDirectory.appendingPathComponent("single-connection.log")
try writeAction(string, logFileUrl)
return logFileUrl
}

// MARK: - Private

private var fullLogs: String {
.logHeader + httpConnectionRepository
.current
.map { $0.toString(includeBody: true) }
.joined(separator: "\n\n\n\(String(repeating: "-", count: 30))\n\n\n")
}
}

private func defaultWriteAction(string: String, url: URL) throws {
Expand Down Expand Up @@ -160,3 +159,15 @@ private extension HTTPConnection {
return string
}
}

private extension String {
static var logHeader: Self {
let deviceModel = UIDevice.current.model
let osVersion = UIDevice.current.systemVersion
let appVersion = Bundle.main.appVersion

return "Device: \(deviceModel)\n" +
"OS Version: \(osVersion)\n" +
"App Version: \(appVersion)\n\n"
}
}
5 changes: 5 additions & 0 deletions Sources/Netbob/Modules/List/ListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ struct ListView: View {
} label: {
Image(systemName: "square.and.arrow.up")
}
Button {
state.handleSaveAction()
} label: {
Image(systemName: "square.and.arrow.down")
}
NavigationLink(destination: InfoView(state: InfoViewState())) {
Image(systemName: "info.circle")
}
Expand Down
9 changes: 9 additions & 0 deletions Sources/Netbob/Modules/List/ListViewState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class ListViewStateAbstract: ObservableObject {
func onAppear() {}
func onDisappear() {}
func handleShareAction() {}
func handleSaveAction() {}
}

final class ListViewState: ListViewStateAbstract {
Expand Down Expand Up @@ -52,6 +53,14 @@ final class ListViewState: ListViewStateAbstract {
}
}

override func handleSaveAction() {
do {
try logFileProvider.saveFullLog()
} catch {
Netbob.log(String(describing: error))
}
}

// MARK: - Private

private func initViewData() {
Expand Down
22 changes: 19 additions & 3 deletions Tests/NetbobTests/Core/LogFileProviderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class LogFileProviderTests: XCTestCase {

var sut: LogFileProvider!

var writeActionURLs: [String] = []

override func setUp() {
super.setUp()

Expand All @@ -20,23 +22,37 @@ class LogFileProviderTests: XCTestCase {
sut = LogFileProvider(
fileManager: mockFileManager,
httpConnectionRepository: mockConnectionRepository,
writeAction: { _, _ in }
writeAction: { _, url in
self.writeActionURLs.append(url.absoluteString)
}
)
}

func test_singleLog() throws {
func test_createSingleLog() throws {
let url = try sut.createSingleLog(from: .fake(), includeBody: true)

XCTAssertEqual(mockFileManager.calls, [])
XCTAssertEqual(mockConnectionRepository.calls, [])
XCTAssertEqual(url.absoluteString, "tmp/single-connection.log")
XCTAssertEqual(writeActionURLs, ["tmp/single-connection.log"])
}

func test_fullLog() throws {
func test_createFullLog() throws {
let url = try sut.createFullLog()

XCTAssertEqual(mockFileManager.calls, [])
XCTAssertEqual(mockConnectionRepository.calls, [])
XCTAssertEqual(url.absoluteString, "tmp/session.log")
XCTAssertEqual(writeActionURLs, ["tmp/session.log"])
}

func test_saveFullLog() throws {
mockFileManager.urlsReturnValue = [URL(string: "Documents")!]

try sut.saveFullLog()

XCTAssertEqual(mockFileManager.calls, [.urls])
XCTAssertEqual(mockConnectionRepository.calls, [])
XCTAssertEqual(writeActionURLs, ["Documents/network-logs.txt"])
}
}
32 changes: 32 additions & 0 deletions Tests/NetbobTests/Mocks/LogFileProviderMock.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Copyright © Marc Schultz. All rights reserved.
//

import Foundation
@testable import Netbob

class LogFileProviderMock: LogFileProviderProtocol {
enum Calls: Equatable {
case createFullLog
case saveFullLog
case createSingleLog(connection: HTTPConnection, includeBody: Bool)
}

var calls: [Calls] = []

var createFullLogReturnValue = URL(string: "http://fake.fake")!
func createFullLog() throws -> URL {
calls.append(.createFullLog)
return createFullLogReturnValue
}

func saveFullLog() throws {
calls.append(.saveFullLog)
}

var createSingleLogReturnValue = URL(string: "http://fake.fake")!
func createSingleLog(from connection: HTTPConnection, includeBody: Bool) throws -> URL {
calls.append(.createSingleLog(connection: connection, includeBody: includeBody))
return createSingleLogReturnValue
}
}
16 changes: 16 additions & 0 deletions Tests/NetbobTests/Modules/List/ListViewStateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import XCTest

class ListViewStateTests: XCTestCase {
let mockHttpConnectionRepository = HTTPConnectionRepositoryMock()
let mockLogFileProvider = LogFileProviderMock()

var sut: ListViewState!

Expand All @@ -15,6 +16,7 @@ class ListViewStateTests: XCTestCase {

sut = ListViewState(
httpConnectionRepository: mockHttpConnectionRepository,
logFileProvider: mockLogFileProvider,
scheduler: .test
)
}
Expand All @@ -23,6 +25,7 @@ class ListViewStateTests: XCTestCase {
XCTAssertEqual(sut.connections.count, 0)
mockHttpConnectionRepository.connectionSubject.send(.fake())
XCTAssertEqual(sut.connections.count, 0)
XCTAssertEqual(mockLogFileProvider.calls, [])
}

func test_createsViewData() throws {
Expand All @@ -48,6 +51,7 @@ class ListViewStateTests: XCTestCase {
XCTAssertEqual(firstConnection.requestQuery, "?a=1,b=2,c=3")
XCTAssertEqual(firstConnection.responseStatusCode, "200")
XCTAssertEqual(firstConnection.status, .success)
XCTAssertEqual(mockLogFileProvider.calls, [])
}

func test_no_subscription_after_onDisappear() {
Expand All @@ -63,4 +67,16 @@ class ListViewStateTests: XCTestCase {

XCTAssertEqual(sut.connections.count, 0)
}

func test_handleSaveAction() {
sut.handleSaveAction()

XCTAssertEqual(mockLogFileProvider.calls, [.saveFullLog])
}

func test_createFullLog() {
sut.handleShareAction()

XCTAssertEqual(mockLogFileProvider.calls, [.createFullLog])
}
}

0 comments on commit 0dc9d5b

Please sign in to comment.