Skip to content

Conversation

@grynspan
Copy link
Contributor

@grynspan grynspan commented Jan 31, 2025

This PR ensures that Comment, when constructed from a string literal with interpolations, stringifies interpolated values using String.init(descriptionForTest:) rather than the default behaviour (i.e. String.init(description:).)

For example:

enum E: CustomTestStringConvertible {
  case a
  case b
  case c

  var testDescription: String {
    switch self {
    case .a:
      "Once I was the King of Spain"
    case .b:
      "Now I eat humble pie"
    case .c:
      "Now I vacuum the turf at SkyDome™"
    }
  }
}

 #expect(1 == 2, "\(E.a) / \(E.b) / \(E.a) / \(E.c)")

Before:

🛑 Expectation failed: 1 == 2 - .a / .b / .a / .c

After:

🛑 Expectation failed: 1 == 2 - Once I was the King of Spain / Now I eat
humble pie / Once I was the King of Spain / Now I vacuum the turf at SkyDome™

Checklist:

  • Code and documentation should follow the style of the Style Guide.
  • If public symbols are renamed or modified, DocC references should be updated.

…nterpolation.

This PR ensures that `Comment`, when constructed from a string literal with
interpolations, stringifies interpolated values using
`String.init(descriptionForTest:)` rather than the default behaviour (i.e.
`String.init(description:)`.)

For example:

```swift
enum E: CustomTestStringConvertible {
  case a
  case b
  case c

  var testDescription: String {
    switch self {
    case .a:
      "Once I was the King of Spain"
    case .b:
      "Now I eat humble pie"
    case .c:
      "Now I vacuum the turf at SkyDome™"
    }
  }
}

 #expect(1 == 2, "\(E.a) / \(E.b) / \(E.a) / \(E.c)")
```

Before:

> 🛑 Expectation failed: 1 == 2 - .a / .b / .a / .c

After:

> 🛑 Expectation failed: 1 == 2 - Once I was the King of Spain / Now I eat
> humble pie / Once I was the King of Spain / Now I vacuum the turf at SkyDome™
@grynspan grynspan added enhancement New feature or request public-api Affects public API issue-handling Related to Issue handling within the testing library command-line experience ⌨️ enhancements to the command line interface traits Issues and PRs related to the trait subsystem or built-in traits labels Jan 31, 2025
@grynspan grynspan self-assigned this Jan 31, 2025
@grynspan
Copy link
Contributor Author

@swift-ci test

@grynspan grynspan added bug 🪲 Something isn't working and removed enhancement New feature or request labels Jan 31, 2025
Comment on lines 119 to 122
// This overload is provided so that the compiler does not emit warnings
// about optional values in string interpolations (which we are fine with
// when constructing Comment instances.)
rawValue += String(describingForTest: value)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this, might be too magical and surprising compared to how string literal interpolation usually works. Is there a strong reason to include it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My expectation here (heh) is that if you pass an optional value in a testing context, you want to see its value. Also the warning's fix-it is emitted by the compiler and tells you to use String(describing:), not String(describingForTest:), which is wrong.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't say it's wrong for the compiler to suggest that; users are welcome to call String(describing:) themselves. I think String(describingForTest:) is primarily for the testing library to call on values users provide, and (to a lesser extent) for use by test authors when writing helpers/utilities.

I think this violates the principle of least surprise. Regardless of what we think of the compiler's fix-it, users are generally accustomed to needing to handle optionals in string interpolations, and I don't know of a reason to deviate from that precedent here. It makes it seem as if the rules are more lax just because it's a test.

Copy link
Contributor Author

@grynspan grynspan Jan 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler emits that diagnostic because the default string representation of an optional value may either be "Optional(x)" (where x is the wrapped value's description) or "nil", and neither of those values is likely expected by a developer who wants to just print x. In our case, that doesn't hold because optional values already have special handling in the library.

I would expect the following code to "just work" rather than emitting any diagnostics, for instance:

let x: Int? = f()
#expect(x == 10, "\(x) should be 10!")

@grynspan grynspan requested a review from stmontgomery January 31, 2025 20:17
@stmontgomery stmontgomery added this to the Swift 6.x milestone Jan 31, 2025
Copy link
Contributor

@stmontgomery stmontgomery left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great enhancement overall. I'm still not convinced about the merit of the overload which suppresses warnings for optionals, and worry it could be surprising or confusing. But it's admittedly a minor concern and I don't want to stand in the way of the broader PR.

@grynspan
Copy link
Contributor Author

grynspan commented Feb 3, 2025

@swift-ci test

@grynspan grynspan requested a review from stmontgomery February 3, 2025 15:41
@grynspan grynspan merged commit f4abd7a into main Feb 3, 2025
3 checks passed
@grynspan grynspan deleted the jgrynspan/comment-uses-CustomTestStringConvertible branch February 3, 2025 21:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug 🪲 Something isn't working command-line experience ⌨️ enhancements to the command line interface issue-handling Related to Issue handling within the testing library public-api Affects public API traits Issues and PRs related to the trait subsystem or built-in traits

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants