Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jmp/AssertThat
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0.2.0
Choose a base ref
...
head repository: jmp/AssertThat
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref

Commits on Jul 1, 2021

  1. Copy the full SHA
    67e0d9e View commit details

Commits on Jul 2, 2021

  1. Use Swift 5.4 on Linux

    jmp authored Jul 2, 2021
    Copy the full SHA
    fd80744 View commit details
  2. Remove use of recordFailure API

    jmp committed Jul 2, 2021
    Copy the full SHA
    cbc4b5d View commit details
  3. Revert to recordFailure on Linux

    jmp committed Jul 2, 2021
    Copy the full SHA
    c18d8fa View commit details
  4. Remove test discovery on Linux

    jmp authored Jul 2, 2021
    Copy the full SHA
    020ccbe View commit details
  5. Delete LinuxMain.swift

    jmp committed Jul 2, 2021
    Copy the full SHA
    dec7800 View commit details
  6. Add coverage for Linux

    jmp authored Jul 2, 2021
    Copy the full SHA
    859eb50 View commit details
  7. Remove scrub from Linux

    jmp authored Jul 2, 2021
    Copy the full SHA
    3e1e02a View commit details
  8. Install curl

    jmp authored Jul 2, 2021
    Copy the full SHA
    08c3785 View commit details
  9. Revert coverage

    jmp authored Jul 2, 2021
    Copy the full SHA
    db0e44a View commit details
  10. Copy the full SHA
    330ee25 View commit details
  11. Revert Xcode setup

    jmp authored Jul 2, 2021
    Copy the full SHA
    5c3c396 View commit details
  12. Copy the full SHA
    0befe05 View commit details
  13. Add Collection assertions

    jmp committed Jul 2, 2021
    Copy the full SHA
    c7874f9 View commit details
  14. Add note about Nimble

    jmp committed Jul 2, 2021
    Copy the full SHA
    5703102 View commit details
  15. Copy the full SHA
    f80a1bd View commit details
  16. Minor updates to README.md

    jmp committed Jul 2, 2021
    Copy the full SHA
    f48f498 View commit details
  17. Remove unnecessary test

    jmp committed Jul 2, 2021
    Copy the full SHA
    81279d9 View commit details

Commits on Oct 2, 2021

  1. Copy the full SHA
    5a92316 View commit details
  2. Use Xcode 13.0

    jmp committed Oct 2, 2021
    Copy the full SHA
    d6b281d View commit details
  3. Downgrade Swift to 5.4

    The setup-xcode@v1 action does not support Xcode 13
    jmp committed Oct 2, 2021
    Copy the full SHA
    13437cc View commit details
  4. Revert to Swift tools version 5.3

    Apparently Swift 5.4 is not available either.
    jmp committed Oct 2, 2021
    Copy the full SHA
    249e4fd View commit details
  5. Upgrade codecov-action to v2

    jmp committed Oct 2, 2021
    Copy the full SHA
    caa2cf5 View commit details

Commits on Oct 29, 2021

  1. Use newer macOS runner and Xcode

    jmp committed Oct 29, 2021
    Copy the full SHA
    456eaa5 View commit details
  2. Enable coverage on Linux

    jmp committed Oct 29, 2021
    Copy the full SHA
    c943b93 View commit details
  3. Remove codecov.yml

    jmp committed Oct 29, 2021
    Copy the full SHA
    2bc6be7 View commit details

Commits on Oct 30, 2021

  1. Simplify suppressable test case

    jmp committed Oct 30, 2021
    Copy the full SHA
    88f96bc View commit details

Commits on Feb 4, 2023

  1. Simplify closure and error assertions

    Make use of XCTAssertThrowsError and XCTAssertNoThrow.
    jmp committed Feb 4, 2023
    Copy the full SHA
    7ef651c View commit details
  2. Add some documentation

    jmp committed Feb 4, 2023
    Copy the full SHA
    96666d3 View commit details
  3. Remove trailing semicolon

    jmp committed Feb 4, 2023
    Copy the full SHA
    1f2d02f View commit details
  4. Make comparisons to zero more generic

    Comparisons to do not require the subject to conform to `Numeric`.
    jmp committed Feb 4, 2023
    Copy the full SHA
    1af4321 View commit details
  5. Remove redundant assertions for strings

    Strings conform to `Collection`, which means we
    can already do emptiness assertions for them.
    jmp committed Feb 4, 2023
    Copy the full SHA
    b85c805 View commit details
  6. Remove redundant assertions from strings

    Strings conform to `Sequence` so no specialization is needed.
    jmp committed Feb 4, 2023
    Copy the full SHA
    7853a48 View commit details
  7. Copy the full SHA
    82b1669 View commit details
  8. Copy the full SHA
    9749ddd View commit details

Commits on Feb 5, 2023

  1. Copy the full SHA
    f862525 View commit details
  2. Update year

    jmp committed Feb 5, 2023
    Copy the full SHA
    215a727 View commit details
  3. Add link to example repository

    jmp committed Feb 5, 2023
    Copy the full SHA
    8af7640 View commit details

Commits on Feb 9, 2023

  1. Make suppression work correctly

    jmp committed Feb 9, 2023
    Copy the full SHA
    dc32792 View commit details
  2. Fix broken super call

    jmp committed Feb 9, 2023
    Copy the full SHA
    0ec0a99 View commit details
19 changes: 13 additions & 6 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -13,28 +13,35 @@ on:
jobs:
macos:
name: macOS
runs-on: macos-latest
runs-on: macos-12
steps:
- name: Select latest available Xcode
uses: maxim-lobanov/setup-xcode@v1
with: { 'xcode-version': 'latest' }
with:
xcode-version: '14'
- name: Checkout
uses: actions/checkout@v2
- name: Run tests
run: swift test --enable-code-coverage
- name: Convert coverage to lcov
run: xcrun llvm-cov export -format=lcov .build/debug/*PackageTests.xctest/Contents/MacOS/*PackageTests -instr-profile .build/debug/codecov/default.profdata > coverage.lcov
- name: Upload coverage
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v2
with:
fail_ci_if_error: true
name: macOS
linux:
name: Linux
runs-on: ubuntu-latest
container:
image: swift:5.3
image: swift:5.7
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run tests
run: swift test --enable-test-discovery
run: swift test --enable-code-coverage
- name: Convert coverage to lcov
run: llvm-cov export -format=lcov .build/debug/*PackageTests.xctest -instr-profile .build/debug/codecov/default.profdata > coverage.lcov
- name: Upload coverage
uses: codecov/codecov-action@v2
with:
name: Linux
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2020-2021 Jarkko Piiroinen
Copyright (c) 2020-2023 Jarkko Piiroinen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
32 changes: 29 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -30,8 +30,10 @@ It should also allow the use of extensions to support custom assertions.
## Existing solutions

As far as I know, there is no port of AssertJ or similar library available for Swift. The closest match is
[Swift Hamcrest](https://github.com/nschum/SwiftHamcrest), which is quite mature and a very nice
alternative for Swift. The main difference is the syntax and how the assertions read.
probably [Swift Hamcrest](https://github.com/nschum/SwiftHamcrest), which is quite mature and a very
nice alternative for Swift. The main difference is the syntax and how the assertions read. Another
noteworthy project is [Nimble](https://github.com/Quick/Nimble), which also has slightly different way
of expressing the assertions.

## How does it work

@@ -55,6 +57,8 @@ To implement assertions for your own types, chances are some of the built-in one

## Example usage

See example repository in [AssertThatExample](https://github.com/jmp/AssertThatExample).

First, import the module:

```swift
@@ -108,10 +112,32 @@ assertThat(someString)
.doesNotMatch("^Test$")
```

Sequences:

```swift
assertThat(sequence).contains(x)
assertThat(sequence).doesNotContain(x)
```

Collections:

```swift
assertThat(collection).isEmpty()
assertThat(collection).isNotEmpty()
```

Note that since a `Collection` also conforms to the `Sequence` protocol,
you can use any of the assertions of `Sequence` with collections:

```swift
assertThat(collection).contains(x)
assertThat(collection).doesNotContain(x)
```

Errors:

```swift
assertThat { someBlockOfCode }.throws(someSpecificError)
assertThat { someBlockOfCode }.throws(SomeErrorType.someSpecificError)
assertThat { someBlockOfCode }.throws(SomeErrorType.self)
assertThat { someBlockOfCode }.doesNotThrow(someError)
assertThat { someBlockOfCode }.throwsAnError() // Throws any error
10 changes: 10 additions & 0 deletions Sources/AssertThat/AssertThat.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/// Create a new assertion for the given subject.
///
/// The function takes a subject (e.g. an integer or an expression) as its only argument and
/// returns an ``Assertion`` instance. The methods of the return value can be used to
/// verify that a wanted condition is true.
///
/// - Parameters:
/// - subject: The subject of the assertion
///
/// - Returns: A new ``Assertion`` instance for the given subject.
public func assertThat<Subject>(_ subject: Subject) -> Assertion<Subject> {
Assertion(subject: subject)
}
6 changes: 6 additions & 0 deletions Sources/AssertThat/Assertion.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/// A generic struct for making assertions.
///
/// Each `Assertion` has a subject whose type is defined by the generic parameter `Subject`.
/// Assertion methods such as `isEqualTo` can be defined in extensions. The extensions
/// may restrict `Subject` to specific protocols or types.
public struct Assertion<Subject> {
/// The subject of the assertion
public let subject: Subject
}
15 changes: 15 additions & 0 deletions Sources/AssertThat/Extensions/AdditiveArithmetic.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import XCTest

public extension Assertion where Subject: AdditiveArithmetic {
@discardableResult
func isZero(file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertEqual(subject, .zero, file: file, line: line)
return self
}

@discardableResult
func isNotZero(file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertNotEqual(subject, .zero, file: file, line: line)
return self
}
}
21 changes: 4 additions & 17 deletions Sources/AssertThat/Extensions/Closure.swift
Original file line number Diff line number Diff line change
@@ -3,20 +3,13 @@ import XCTest
public extension Assertion where Subject == () throws -> Any {
@discardableResult
func throwsAnError(file: StaticString = #filePath, line: UInt = #line) -> Self {
do {
_ = try subject()
XCTFail("no error was thrown", file: file, line: line)
} catch {}
XCTAssertThrowsError(try subject(), "no error was thrown", file: file, line: line)
return self
}

@discardableResult
func doesNotThrowAnError(file: StaticString = #filePath, line: UInt = #line) -> Self {
do {
_ = try subject()
} catch {
XCTFail("\(error) was thrown", file: file, line: line)
}
XCTAssertNoThrow(try subject(), "an error was thrown", file: file, line: line)
return self
}

@@ -26,10 +19,7 @@ public extension Assertion where Subject == () throws -> Any {
file: StaticString = #filePath,
line: UInt = #line
) -> Self {
do {
_ = try subject()
XCTFail("\(expectedError) was not thrown", file: file, line: line)
} catch {
XCTAssertThrowsError(try subject(), "\(expectedError) was not thrown", file: file, line: line) { error in
XCTAssertTrue(error as? T == expectedError, "\(error) is not \(expectedError)", file: file, line: line)
}
return self
@@ -51,10 +41,7 @@ public extension Assertion where Subject == () throws -> Any {

@discardableResult
func `throws`<T: Error>(_ expectedError: T.Type, file: StaticString = #filePath, line: UInt = #line) -> Self {
do {
_ = try subject()
XCTFail("\(expectedError) was not thrown", file: file, line: line)
} catch {
XCTAssertThrowsError(try subject(), "\(expectedError) was not thrown", file: file, line: line) { error in
XCTAssertTrue(type(of: error) == T.self, "\(error) is not \(expectedError)", file: file, line: line)
}
return self
15 changes: 15 additions & 0 deletions Sources/AssertThat/Extensions/Collection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import XCTest

public extension Assertion where Subject: Collection {
@discardableResult
func isEmpty(file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertTrue(subject.isEmpty, file: file, line: line)
return self
}

@discardableResult
func isNotEmpty(file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertFalse(subject.isEmpty, file: file, line: line)
return self
}
}
5 changes: 1 addition & 4 deletions Sources/AssertThat/Extensions/Error.swift
Original file line number Diff line number Diff line change
@@ -3,10 +3,7 @@ import XCTest
public extension Assertion where Subject: Error & Equatable {
@discardableResult
func isThrownBy<T>(_ block: () throws -> T, file: StaticString = #filePath, line: UInt = #line) -> Self {
do {
_ = try block()
XCTFail("\(subject) was not thrown", file: file, line: line)
} catch {
XCTAssertThrowsError(try block(), "\(subject) was not thrown", file: file, line: line) { error in
XCTAssertTrue(error as? Subject == subject, "\(error) is not \(subject)", file: file, line: line)
}
return self
8 changes: 4 additions & 4 deletions Sources/AssertThat/Extensions/Numeric.swift
Original file line number Diff line number Diff line change
@@ -2,14 +2,14 @@ import XCTest

public extension Assertion where Subject: Numeric {
@discardableResult
func isZero(file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertEqual(subject, 0, file: file, line: line)
func isOne(file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertEqual(subject, 1, file: file, line: line)
return self
}

@discardableResult
func isNotZero(file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertNotEqual(subject, 0, file: file, line: line)
func isNotOne(file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertNotEqual(subject, 1, file: file, line: line)
return self
}
}
59 changes: 59 additions & 0 deletions Sources/AssertThat/Extensions/Sequence.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import XCTest

public extension Assertion where Subject: Sequence, Subject.Element: Equatable {
@discardableResult
func startsWith(_ prefix: Subject, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertTrue(
subject.starts(with: prefix),
"\"\(subject)\" does not start with \"\(prefix)\"",
file: file,
line: line
)
return self
}

@discardableResult
func doesNotStartWith(_ prefix: Subject, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertFalse(
subject.starts(with: prefix),
"\"\(subject)\" starts with \"\(prefix)\"",
file: file,
line: line
)
return self
}

@discardableResult
func endsWith(_ suffix: Subject, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertTrue(
subject.reversed().starts(with: suffix.reversed()),
"\"\(subject)\" does not end with \"\(suffix)\"",
file: file,
line: line
)
return self
}

@discardableResult
func doesNotEndWith(_ suffix: Subject, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertFalse(
subject.reversed().starts(with: suffix.reversed()),
"\"\(subject)\" ends with \"\(suffix)\"",
file: file,
line: line
)
return self
}

@discardableResult
func contains(_ element: Subject.Element, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertTrue(subject.contains(element), file: file, line: line)
return self
}

@discardableResult
func doesNotContain(_ element: Subject.Element, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertFalse(subject.contains(element), file: file, line: line)
return self
}
}
58 changes: 0 additions & 58 deletions Sources/AssertThat/Extensions/StringProtocol.swift
Original file line number Diff line number Diff line change
@@ -1,64 +1,6 @@
import XCTest

public extension Assertion where Subject: StringProtocol {
@discardableResult
func isEmpty(file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertTrue(subject.isEmpty, "\"\(subject)\" is not empty", file: file, line: line)
return self
}

@discardableResult
func isNotEmpty(file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertFalse(subject.isEmpty, "\"\(subject)\" is empty", file: file, line: line)
return self
}

@discardableResult
func startsWith(_ prefix: Subject, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertTrue(
subject.starts(with: prefix),
"\"\(subject)\" does not start with \"\(prefix)\"",
file: file,
line: line
)
return self
}

@discardableResult
func doesNotStartWith(_ prefix: Subject, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertFalse(subject.starts(with: prefix), "\"\(subject)\" starts with \"\(prefix)\"", file: file, line: line)
return self
}

@discardableResult
func endsWith(_ suffix: Subject, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertTrue(
subject.hasSuffix(suffix),
"\"\(subject)\" does not end with \"\(suffix)\"",
file: file,
line: line
)
return self
}

@discardableResult
func doesNotEndWith(_ suffix: Subject, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertFalse(subject.hasSuffix(suffix), "\"\(subject)\" ends with \"\(suffix)\"", file: file, line: line)
return self
}

@discardableResult
func contains(_ other: Subject, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertTrue(subject.contains(other), "\"\(subject)\" does not contain \"\(other)\"", file: file, line: line)
return self
}

@discardableResult
func doesNotContain(_ other: Subject, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertFalse(subject.contains(other), "\"\(subject)\" contains \"\(other)\"", file: file, line: line)
return self
}

@discardableResult
func matches(_ pattern: String, file: StaticString = #filePath, line: UInt = #line) -> Self {
XCTAssertTrue(
24 changes: 24 additions & 0 deletions Tests/AssertThatTests/AdditiveArithmeticTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import XCTest
import AssertThat

final class AdditiveArithmeticTests: SuppressableTestCase {
func testIsZeroSuccess() {
suppress { assertThat(0).isZero() }
XCTAssertEqual(0, suppressedIssues)
}

func testIsZeroFailure() {
suppress { assertThat(1).isZero() }
XCTAssertEqual(1, suppressedIssues)
}

func testIsNotZeroSuccess() {
suppress { assertThat(1).isNotZero() }
XCTAssertEqual(0, suppressedIssues)
}

func testIsNotZeroFailure() {
suppress { assertThat(0).isNotZero() }
XCTAssertEqual(1, suppressedIssues)
}
}
9 changes: 0 additions & 9 deletions Tests/AssertThatTests/AssertThatTests.swift

This file was deleted.

Loading