Skip to content

Commit

Permalink
Separated TextFormatter (#17)
Browse files Browse the repository at this point in the history
* Separated text formatter

* Formatter → TextFormatter

* Removed duplicated tests

* Removed Parser

* Introduced FormatterProtocol

* Renamed Filters to TestResults

* Replaced TestResult with ReportModel.Module.File.RepeatableTest.Test.Status

* Moved common code out of formatter

* Removed unused code

* Minr change
  • Loading branch information
AllDmeat authored Dec 15, 2023
1 parent 17dc1fd commit cb6b4d4
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 471 deletions.
215 changes: 0 additions & 215 deletions Sources/DBXCResultParser/Formatter.swift

This file was deleted.

15 changes: 15 additions & 0 deletions Sources/DBXCResultParser/Formatters/FormatterProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// FormatterProtocol.swift
//
//
// Created by Aleksey Berezka on 15.12.2023.
//

import Foundation

public protocol FormatterProtocol {
func format(
_ report: ReportModel,
testResults: [ReportModel.Module.File.RepeatableTest.Test.Status]
) -> String
}
125 changes: 125 additions & 0 deletions Sources/DBXCResultParser/Formatters/TextFormatter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
//
// TextFormatter.swift
//
//
// Created by Алексей Берёзка on 31.12.2021.
//

import Foundation

extension TextFormatter {
public enum Format {
case list
case count
}
}

class TextFormatter: FormatterProtocol {
public let format: Format
public let locale: Locale?

public init(
format: Format,
locale: Locale? = nil
) {
self.format = format
self.locale = locale
}

public func format(
_ report: ReportModel,
testResults: [ReportModel.Module.File.RepeatableTest.Test.Status] = .allCases
) -> String {
let files = report.modules
.flatMap { Array($0.files) }
.sorted { $0.name < $1.name }

switch format {
case .list:
let singleTestsMeasurementFormatter = MeasurementFormatter.singleTestDurationFormatter
singleTestsMeasurementFormatter.locale = locale
let filesReports = files.compactMap { file in
file.report(testResults: testResults,
formatter: singleTestsMeasurementFormatter)
}
return filesReports.joined(separator: "\n\n")
case .count:
let numberFormatter = NumberFormatter.testsCountFormatter
numberFormatter.locale = locale
let totalTestsMeasurementFormatter = MeasurementFormatter.totalTestsDurationFormatter
totalTestsMeasurementFormatter.locale = locale
let tests = files.flatMap { $0.repeatableTests.filtered(testResults: testResults) }
let count = tests.count
let duration = tests.totalDuration
let addDuration = testResults != [.skipped] // don't add 0ms duration if requested only skipped tests
return [
numberFormatter.string(from: NSNumber(value: count)) ?? String(count),
addDuration ? totalTestsMeasurementFormatter.string(from: duration).wrappedInBrackets : nil
]
.compactMap{ $0 }
.joined(separator: " ")
}
}
}

extension ReportModel.Module.File {
func report(testResults: [ReportModel.Module.File.RepeatableTest.Test.Status],
formatter: MeasurementFormatter) -> String? {
let tests = repeatableTests.filtered(testResults: testResults).sorted { $0.name < $1.name }

guard !tests.isEmpty else {
return nil
}

var rows = tests
.sorted { $0.name < $1.name }
.map { test in
test.report(formatter: formatter)
}

rows.insert(name, at: 0)

return rows.joined(separator: "\n")
}
}

fileprivate extension ReportModel.Module.File.RepeatableTest {
func report(formatter: MeasurementFormatter) -> String {
[
combinedStatus.icon,
name
]
.compactMap { $0 }
.joined(separator: " ")
}
}

extension String {
var wrappedInBrackets: Self {
"(" + self + ")"
}
}

extension MeasurementFormatter {
static var singleTestDurationFormatter: MeasurementFormatter {
let formatter = MeasurementFormatter()
formatter.unitOptions = [.providedUnit]
formatter.numberFormatter.maximumFractionDigits = 0
return formatter
}

static var totalTestsDurationFormatter: MeasurementFormatter {
let formatter = MeasurementFormatter()
formatter.unitOptions = [.naturalScale]
formatter.numberFormatter.maximumFractionDigits = 0
return formatter
}
}

extension NumberFormatter {
static var testsCountFormatter: NumberFormatter {
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 0
return formatter
}
}
25 changes: 25 additions & 0 deletions Sources/DBXCResultParser/Models/ReportModel+Convenience.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// ReportModel+Convenience.swift
//
//
// Created by Aleksey Berezka on 15.12.2023.
//

import Foundation

extension ReportModel {
public init(xcresultPath: URL) throws {
let overviewReport = try OverviewReportDTO(from: xcresultPath)
let detailedReport = try DetailedReportDTO(from: xcresultPath,
refId: overviewReport.testsRefId)

let coverageDTOs = try? Array<CoverageDTO>(from: xcresultPath)
.filter { !$0.name.contains("TestHelpers") && !$0.name.contains("Tests") }

self = try ReportModel(
overviewReportDTO: overviewReport,
detailedReportDTO: detailedReport,
coverageDTOs: coverageDTOs ?? []
)
}
}
Loading

0 comments on commit cb6b4d4

Please sign in to comment.