File: PrettyPrintTestCase.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (115 lines) | stat: -rw-r--r-- 4,728 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import SwiftFormat
import SwiftOperators
import SwiftSyntax
import SwiftParser
import XCTest

@_spi(Rules) @_spi(Testing) import SwiftFormat
@_spi(Testing) import _SwiftFormatTestSupport

class PrettyPrintTestCase: DiagnosingTestCase {
  /// Asserts that the input string, when pretty printed, is equal to the expected string.
  ///
  /// - Parameters:
  ///   - input: The input text to pretty print.
  ///   - expected: The expected pretty-printed output.
  ///   - linelength: The maximum allowed line length of the output.
  ///   - configuration: The formatter configuration.
  ///   - whitespaceOnly: If true, the pretty printer should only apply whitespace changes and omit
  ///     changes that insert or remove non-whitespace characters (like trailing commas).
  ///   - findings: A list of `FindingSpec` values that describe the findings that are expected to
  ///     be emitted. These are currently only checked if `whitespaceOnly` is true.
  ///   - file: The file in which failure occurred. Defaults to the file name of the test case in
  ///     which this function was called.
  ///   - line: The line number on which failure occurred. Defaults to the line number on which this
  ///     function was called.
  final func assertPrettyPrintEqual(
    input: String,
    expected: String,
    linelength: Int,
    configuration: Configuration = Configuration.forTesting,
    whitespaceOnly: Bool = false,
    findings: [FindingSpec] = [],
    file: StaticString = #file,
    line: UInt = #line
  ) {
    var configuration = configuration
    configuration.lineLength = linelength

    let markedInput = MarkedText(textWithMarkers: input)
    var emittedFindings = [Finding]()

    // Assert that the input, when formatted, is what we expected.
    let (formatted, context) = prettyPrintedSource(
      markedInput.textWithoutMarkers,
      configuration: configuration,
      selection: markedInput.selection,
      whitespaceOnly: whitespaceOnly,
      findingConsumer: { emittedFindings.append($0) })
    assertStringsEqualWithDiff(
      formatted, expected,
      "Pretty-printed result was not what was expected",
      file: file, line: line)

    // FIXME: It would be nice to check findings when whitespaceOnly == false, but their locations
    // are wrong.
    if whitespaceOnly {
      assertFindings(
        expected: findings,
        markerLocations: markedInput.markers,
        emittedFindings: emittedFindings,
        context: context,
        file: file,
        line: line)
    }

    // Idempotency check: Running the formatter multiple times should not change the outcome.
    // Assert that running the formatter again on the previous result keeps it the same.
    // But if we have ranges, they aren't going to be valid for the formatted text.
    if case .infinite = markedInput.selection {
      let (reformatted, _) = prettyPrintedSource(
        formatted,
        configuration: configuration,
        selection: markedInput.selection,
        whitespaceOnly: whitespaceOnly,
        findingConsumer: { _ in }  // Ignore findings during the idempotence check.
      )
      assertStringsEqualWithDiff(
        reformatted, formatted, "Pretty printer is not idempotent", file: file, line: line)
    }
  }

  /// Returns the given source code reformatted with the pretty printer.
  ///
  /// - Parameters:
  ///   - source: The source text to pretty print.
  ///   - configuration: The formatter configuration.
  ///   - whitespaceOnly: If true, the pretty printer should only apply whitespace changes and omit
  ///     changes that insert or remove non-whitespace characters (like trailing commas).
  ///   - findingConsumer: A function called for each finding that is emitted by the pretty printer.
  /// - Returns: The pretty-printed text, or nil if an error occurred and a test failure was logged.
  private func prettyPrintedSource(
    _ source: String,
    configuration: Configuration,
    selection: Selection,
    whitespaceOnly: Bool,
    findingConsumer: @escaping (Finding) -> Void
  ) -> (String, Context) {
    // Ignore folding errors for unrecognized operators so that we fallback to a reasonable default.
    let sourceFileSyntax =
      OperatorTable.standardOperators.foldAll(Parser.parse(source: source)) { _ in }
        .as(SourceFileSyntax.self)!
    let context = makeContext(
      sourceFileSyntax: sourceFileSyntax,
      configuration: configuration,
      selection: selection,
      findingConsumer: findingConsumer)
    let printer = PrettyPrinter(
      context: context,
      source: source,
      node: Syntax(sourceFileSyntax),
      printTokenStream: false,
      whitespaceOnly: whitespaceOnly)
    return (printer.prettyPrint(), context)
  }
}