Skip to content

Implementation for XCTAssertNoThrow #6776

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jan 13, 2017
Merged

Implementation for XCTAssertNoThrow #6776

merged 14 commits into from
Jan 13, 2017

Conversation

ArtSabintsev
Copy link
Contributor

@ArtSabintsev ArtSabintsev commented Jan 13, 2017

Implements XCTAssertNoThrow, as it's available in Objective-C, but missing in Swift.

I used XCTAssertThrowsError as a guideline, implementing the bulk of this method and validation test by doing the inverse of what I saw there.

First time adding functionality to Swift, so not 100% sure on how to test any of this locally.

Is there a way to test the validation locally on my machine?

cc @slavapestov @modocache

@CodaFi
Copy link
Contributor

CodaFi commented Jan 13, 2017

You can run this particular validation test locally from the parent directory of your swift checkout:

./llvm/utils/lit/lit.py -sv ./build/Ninja-DebugAssert/swift-macosx-x86_64/validation-test-macosx-x86_64/stdlib/XCTest.swift

@@ -1030,6 +1030,40 @@ public func XCTAssertThrowsError<T>(_ expression: @autoclosure () throws -> T, _
}
}

public func XCTAssertNoThrow<T>(_ expression: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line, _ errorHandler: (_ error: Error) -> Void = { _ in }) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The indentation of this function should match the rest of this file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed this, but this request won't close, as it was done on a line of code that itself didn't need a change.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess it's a good thing because you only fixed one level of indentation! If you're using Xcode, set your indentation settings appropriately and try highlighting the regions I mentioned. Hit ^+I and it'll reindent for you.

return
}

_XCTRegisterFailure(true, "XCTAssertNoThrow failed: threw error \"\(caughtError)\"", message, file, line)
Copy link
Contributor

@CodaFi CodaFi Jan 13, 2017

Choose a reason for hiding this comment

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

Shouldn't the invariant here be that if .success is returned from the _XCTRunThrowableBlock call then caughtErrorOptional should be .none? It looks like _XCTRunThrowableBlock already handles catching Swift exceptions so you should be able to delete most of the preceding code and get down to essentially

let result = _XCTRunThrowableBlock { _ = try expression() }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Simplified, it looks like this, right?

public func XCTAssertNoThrow<T>(_ expression: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
  let assertionType = _XCTAssertionType.assertion_NoThrow

  let result = _XCTRunThrowableBlock { _ = try expression() }

  switch result {
  case .success:
      guard let error = error else {
          return
      }

  case .failedWithError(let error):
      _XCTRegisterFailure(true, "XCTAssertNoThrow failed: threw error \"\(error)\"", message, file, line)

  case .failedWithException(_, _, let reason):
      _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line)

  case .failedWithUnknownException:
      _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line)
  }
}

I got rid of some extraneous stuff as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pushed that change to make it easier for you to see.

@@ -252,6 +252,75 @@ XCTestTestSuite.test("XCTAssertThrowsError") {

}

XCTestTestSuite.test("XCTAssertNoThrow") {
class ErrorTestCase: XCTestCase {
Copy link
Contributor

Choose a reason for hiding this comment

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

Another indentation fix. We try to use 2-space indents here. The other Swift-related projects may have different styles.

@CodaFi
Copy link
Contributor

CodaFi commented Jan 13, 2017

Modulo the nits above, this LGTM.

@ArtSabintsev
Copy link
Contributor Author

Thanks - just got llvm installed. Going to try to run this locally and then address your concerns.

@ArtSabintsev
Copy link
Contributor Author

@CodaFi I pushed the change I left in the comment:

public func XCTAssertNoThrow<T>(_ expression: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
  let assertionType = _XCTAssertionType.assertion_NoThrow

  let result = _XCTRunThrowableBlock { _ = try expression() }

  switch result {
  case .success:
      guard let error = error else {
          return
      }

  case .failedWithError(let error):
      _XCTRegisterFailure(true, "XCTAssertNoThrow failed: threw error \"\(error)\"", message, file, line)

  case .failedWithException(_, _, let reason):
      _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line)

  case .failedWithUnknownException:
      _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line)
  }
}

I think that's what you were referring to.

Still having issues with running tests locally with llvm, but that's neither here nor there. Mind if we smoke test and see what CI says? If it fails, I'll try again in the morning.

let result = _XCTRunThrowableBlock { _ = try expression() }

switch result {
case .success:
Copy link
Contributor

@CodaFi CodaFi Jan 13, 2017

Choose a reason for hiding this comment

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

It's not enough to just outdent. If you use Xcode you can set your indentation settings appropriately, highlight these code blocks, and hit ^+I (CNTRL+I) to have it do this for you.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yup, was using xcode. Will try that now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

Copy link
Contributor

Choose a reason for hiding this comment

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

The tests need to be updated as well

case .success:
guard let error = error else {
return
}
Copy link
Contributor

@CodaFi CodaFi Jan 13, 2017

Choose a reason for hiding this comment

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

This code is dead (and won't compile). Can you remove it and make this case simply return?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, whoops!


switch result {
case .success:
guard let error = error else {
Copy link
Contributor

Choose a reason for hiding this comment

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

Re-iterating because indent changes collapsed my comment:

This code is dead (and won't compile). Can you remove it and make this case simply return?

@CodaFi
Copy link
Contributor

CodaFi commented Jan 13, 2017

Thanks for sticking with me through the review. I'll trigger CI once the changes settle down. Thank you for putting in the work for this!

@ArtSabintsev
Copy link
Contributor Author

Pushed the change to the success condition as well.

@CodaFi
Copy link
Contributor

CodaFi commented Jan 13, 2017

There are still alignment issues in the tests you added. For example.

@ArtSabintsev
Copy link
Contributor Author

you've got to be kidding me. I did the CTROL+I trick after setting everything to 2 spaces.

I'm a 4 space guy :)

Looking again.

@ArtSabintsev
Copy link
Contributor Author

ArtSabintsev commented Jan 13, 2017

Ah, that's not my code :)

Want me to fix the alignment it in this PR?

@ArtSabintsev
Copy link
Contributor Author

Oh weird, it's saying it is my code, eventhough I don't recall touching it. Fixing now.

@CodaFi
Copy link
Contributor

CodaFi commented Jan 13, 2017

You mentioned you were having trouble running the tests locally: Do you have a build of the swift compiler and standard library already?

@CodaFi
Copy link
Contributor

CodaFi commented Jan 13, 2017

Whoa! Can you please revert that last change and only unindent what you accidentally indented? We have a policy against huge whitespace changes like this.

@ArtSabintsev
Copy link
Contributor Author

sure no problem.

…ests have 2 spaces instead of 4"

This reverts commit 43a7b31.
@CodaFi
Copy link
Contributor

CodaFi commented Jan 13, 2017

I'm talking about this

dynamic func test_throws()

The entire implementation is just

dynamic func test_throws() {
  XCTAssertNoThrow(try throwSomething())
}

@ArtSabintsev
Copy link
Contributor Author

Ah, lemme make the change then.

As I said at the onset, was working blindly and on the inverse of what XCTAssertThrowsError did :\

@ArtSabintsev
Copy link
Contributor Author

Oh, right! I got rid of the block that returned errors in the definition, but forgot to do it in the test.

@ArtSabintsev
Copy link
Contributor Author

ok, @CodaFi, pushed.

@CodaFi
Copy link
Contributor

CodaFi commented Jan 13, 2017

The last thing to do is change the constant to

_XCTAssertionType.noThrow

@ArtSabintsev
Copy link
Contributor Author

Done

@CodaFi
Copy link
Contributor

CodaFi commented Jan 13, 2017

The linux tests are going to pass regardless, so

@swift-ci please smoke test Linux platform.

@ArtSabintsev
Copy link
Contributor Author

why's that?

@CodaFi
Copy link
Contributor

CodaFi commented Jan 13, 2017

Because this test is enabled explicitly only for macOS!

@swift-ci please test OS X platform.

@ArtSabintsev
Copy link
Contributor Author

Ah, good to know.

@CodaFi
Copy link
Contributor

CodaFi commented Jan 13, 2017

Welcome to Swift, @ArtSabintsev

⛵️

@CodaFi CodaFi merged commit cef4e66 into swiftlang:master Jan 13, 2017
@ArtSabintsev
Copy link
Contributor Author

Thank you so much for your assistance and for the welcome! Really appreciate it, @CodaFi.

Also, thank you @slavapestov and @modocache!

@ArtSabintsev ArtSabintsev deleted the feature/XCTAssertNoThrow branch January 13, 2017 13:19
@jrose-apple
Copy link
Contributor

Ah, @CodaFi, in the future please include an Apple XCTest person for overlay modifications. XCTest, Dispatch, and Foundation are somewhat special because of the corelibs projects, but my understanding is that their interfaces are still considered part of the Apple SDK, not part of the Swift Open Source project. I wouldn't expect any problems here given that this is merely an Objective-C API equivalent, but it's still an important part of the process. cc @mike-ferris-apple

@ArtSabintsev, I'm sorry to catch you up in this. :-)

@ArtSabintsev
Copy link
Contributor Author

no problem - this is all very interesting to me!

@jrose-apple If I wanted to implement some or all of these (https://github.com/ArtSabintsev/swift/blob/5008ed84218ba560198a74af6929dfc40f273883/stdlib/public/SDK/XCTest/XCTest.swift#L1053-L1085), what would be the appropriate way to open future PRs? Should I tag specific people and/or approach those in a different manner, since I, too, think these have Objective-C API equivalents.

@CodaFi
Copy link
Contributor

CodaFi commented Jan 13, 2017

@jrose-apple My bad

@jrose-apple
Copy link
Contributor

Generally it's always acceptable to mention the code owner for a particular component, who can then direct you to the right person. However, that file doesn't really cover the overlays (stdlib/public/SDK/) since those are mostly owned by people at Apple who don't participate in the Swift Open Source process at all. In this case you'd probably have to wait for one of us to tag in someone we know works on XCTest.

(There's always the technique of looking at who's last modified those files, and seeing who merged those pull requests too. But you shouldn't have to go looking; it should be easy.)

I'll get the file updated for Dispatch, Foundation, and XCTest, and bring this up on the swift-dev list; it should be clearer what to do.

@mike-ferris-apple, for Arthur's specific plan, who should be reviewing these? Since they're all existing functions that are marked unimplemented, do you want to consider them up for general review?

@modocache
Copy link
Contributor

/cc @briancroom as well

@ArtSabintsev
Copy link
Contributor Author

Sounds good, @jrose-apple.

By the way, I am in no way consigning myself to implementing all of those functions. Just wanted to know what the process was IF I went through with it ;)

But thanks for all the info!

@ArtSabintsev
Copy link
Contributor Author

@jrose-apple If you'd like, I can implement the same function in XCTest and Foundation, plus I think XCTestAssertThrows is missing in one or both of those.

Thoughts? If so, I can do it tonight or this weekend as I have the entire environment setup (finally), thanks to @slavapestov's guidance.

@briancroom
Copy link
Contributor

Hi @ArtSabintsev, thanks for your contribution! This looks great. Thanks also @CodaFi and others involved in the review.

Please do tag me in future PRs for XCTest changes, either here in the XCTest framework overlay, or in Corelibs!

Regarding the other assertion functions:

  • I don't think it will be possible to implement most (any?) of these in Corelibs because they are all intended to test for ObjC exceptions being thrown or not thrown, which don't exist at all on other platforms. Some of the naming around these is a bit unfortunate because the term "throws" means something a bit different in each language.
  • I'd be happy to review PRs for implementations of these in the framework overlay, though!

@modocache
Copy link
Contributor

Some of the naming around these is a bit unfortunate because the term "throws" means something a bit different in each language.

I agree. It seems like the Swift users frequently conflate Swift errors with other languages' exception semantics. Using XCTAssertThrows for both Swift errors and Objective-C exceptions muddles the distinction between the two.

@ArtSabintsev
Copy link
Contributor Author

@briancroom @modocache Thanks for that information. Makes a lot more sense. The naming is quite unfortunate and confusing at times. I will make PRs for you this weekend.

@modocache
Copy link
Contributor

Oh, just to be clear, that's just my opinion on the naming. Actually changing them would mean a source-breaking change for XCTest users, which I think would be unacceptable. So if you were planning on sending pull requests to change the names, then I think those probably couldn't be merged. Other pull requests are definitely welcome, though! And thanks again for this addition!

@ArtSabintsev
Copy link
Contributor Author

No plans to change names for the exact reason you mentioned!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants