Skip to content

dodobrands/DBXCResultParser

Peekie

The PeekieSDK package provides a Swift module for parsing .xcresult files generated by Xcode to produce a structured report of build and test results. It supports both XCTest and Swift Testing frameworks, and works with the modern .xcresult format (without requiring the --legacy flag). It allows developers to programmatically access detailed information about test cases, code coverage, and warnings from their CI/CD pipelines or automated scripts.

Table of Contents

Features

  • Supports XCTest and Swift Testing frameworks.
  • Parses modern .xcresult format (uses xcresulttool without --legacy flag).
  • Parses .xcresult files to create a typed model of the test results and code coverage.
  • Filters out coverage data related to test helpers and test cases.
  • Provides a detailed breakdown of modules, files, and repeatable tests.
  • Extracts build warnings from .xcresult files (Swift Compiler Warnings only).
  • Calculates total and average test durations, as well as combined test statuses.
  • Supports identifying slow tests based on average duration.
  • Includes utility functions for filtering tests based on status.
  • Can be executed as a command-line tool to generate test reports directly from the terminal.

Installation

To use PeekieSDK in your Swift package, add it to the dependencies for your Package.swift file:

let package = Package(
    name: "YourPackageName",
    dependencies: [
        .package(url: "https://github.com/dodobrands/DBXCResultParser", .upToNextMajor(from: "3.0.0"))
    ],
    targets: [
        .target(
            name: "YourTargetName",
            dependencies: ["PeekieSDK"]
        )
    ]
)

Usage

Parsing xcresult Files

To parse an .xcresult file and access the report data, initialize a Report with the path to the .xcresult file:

import PeekieSDK

let xcresultPath = URL(fileURLWithPath: "/path/to/your.xcresult")
let reportModel = try await Report(xcresultPath: xcresultPath)

// Access different parts of the report:
let modules = reportModel.modules
let coverage = reportModel.coverage // Coverage value from 0.0 to 1.0
let warnings = reportModel.warnings // Array of build warnings

// Access warnings:
for warning in warnings {
    print("Warning: \(warning.message)")
    print("  Location: \(warning.sourceURL)")
    print("  Class: \(warning.className)")
}

// Iterate over modules, files, and tests:
for module in modules {
    print("Module: \(module.name)")
    for file in module.files {
        print("  File: \(file.name)")
        for repeatableTest in file.repeatableTests {
            print("    Repeatable Test: \(repeatableTest.name)")
            for test in repeatableTest.tests {
                print("      Test: \(test.status.icon) - Duration: \(test.duration)")
            }
        }
    }
}

Formatting Test Reports

The TextFormatter class provides a way to format the data from a Report into a human-readable string. It supports two output formats: a detailed list of test results and a summary count of test results.

Usage

To format your test report data, create an instance of TextFormatter:

import PeekieSDK

// Assuming you have already created a `Report` instance as `reportModel`
let reportModel: Report = ...

// Create a text formatter
let formatter = TextFormatter()

// Format the report data into a string
let formattedOutput = formatter.format(reportModel)

// Print the formatted output
print("Formatted Output:\n\(formattedOutput)")

The format method can also take an array of Report.Module.File.RepeatableTest.Test.Status to filter which test results are included in the output. By default, it includes all test statuses.

Filtering by status:

// Only show failures
let failuresOnly = formatter.format(reportModel, include: [.failure])

// Show both failures and skipped tests
let failuresAndSkipped = formatter.format(reportModel, include: [.failure, .skipped])

// Show only successful tests
let successesOnly = formatter.format(reportModel, include: [.success])

Using count format:

// Get summary count instead of detailed list
let summary = formatter.format(reportModel, format: .count)
// Output: "12 tests (1m 23s)"

// Count only failures
let failureCount = formatter.format(reportModel, include: [.failure], format: .count)
// Output: "3 tests (45s)"

Output Formats

List Format

Outputs a detailed list of test results, including the name of each file and the status of each test.

Basic Test Statuses:

  • βœ… - Success
  • ❌ - Failure
  • ⏭️ - Skipped
  • 🀑 - Expected Failure
  • ⚠️ - Mixed (flaky test with different results across retries)
  • 🀷 - Unknown

Example output:

FileA.swift
βœ… test_success()
❌ test_failure() (Failure message)
⏭️ test_skip() (Skip message)
🀑 test_expectedFailure() (Failure is expected)
⚠️ test_flacky() (Flacky failure message)

FileB.swift
βœ… test_success()

Parameterized Tests (Swift Testing): Each argument from parameterized tests is displayed as a separate test line with its own status:

FakeSUITests
βœ… success()
❌ failure() (GenerateXCResultTests.swift:56: Issue recorded: Failure message)
⏭️ disabled() (Test 'disabled()' skipped: Disabled reason)
🀑 expectedFailure()
⚠️ flacky() (GenerateXCResultTests.swift:75: Issue recorded: Flacky failure message)
βœ… flackyParameterized(value:) (true)
❌ flackyParameterized(value:) (false)
βœ… somethingWithWarning()
Count Format

Outputs a summary count of test results, including the total number of tests and their combined duration.

12 tests (1m 23s)

When filtering by status (e.g., only failures), duration is omitted if only skipped tests are included:

5 tests

Customizing Number and Measurement Formatting

The TextFormatter allows you to specify a locale when formatting the report. This locale is used to format numbers and measurements according to the provided locale's conventions.

let formatter = TextFormatter()
let output = formatter.format(reportModel, locale: Locale(identifier: "fr_FR"))
print(output) // Will output numbers and durations formatted in French

Command-Line Tool

The package includes a command-line tool that can be executed to generate test reports. Here is an example of how to run it:

swift run peekie --xcresult-path path/to/tests.xcresult

Examples:

# Default: list format with all test statuses
swift run peekie --xcresult-path path/to/tests.xcresult

# Count format (summary)
swift run peekie --xcresult-path path/to/tests.xcresult --format count

# Show only failures
swift run peekie --xcresult-path path/to/tests.xcresult --include failure

# Show failures and skipped tests
swift run peekie --xcresult-path path/to/tests.xcresult --include failure,skipped

# Use specific locale for formatting
swift run peekie --xcresult-path path/to/tests.xcresult --locale ru-RU

# Combine options: count format with only failures, using French locale
swift run peekie --xcresult-path path/to/tests.xcresult --format count --include failure --locale fr-FR

Available options:

  • --xcresult-path: Specifies the path to the .xcresult file (required).
  • --format: Determines the output format (list or count). Default: list.
  • --locale: Sets the locale for number and measurement formatting (e.g., "en-GB", "ru-RU", "fr-FR"). Default: system locale.
  • --include: Filters the test results to include only certain statuses. Comma-separated list of: success, failure, skipped, expectedFailure, mixed, unknown. Default: all statuses.

License

This code is released under the Apache License. See LICENSE for more information.

About

XCResult parser

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 6