├── .cargo
└── config.toml
├── .github
├── dependabot.yml
└── workflows
│ ├── ci.yml
│ ├── publish.yml
│ └── scorecard.yml
├── .gitignore
├── CONTRIBUTING.md
├── Cargo.lock
├── Cargo.toml
├── LICENSE
├── README.md
├── googletest
├── Cargo.toml
├── LICENSE
├── crate_docs.md
├── src
│ ├── assertions.rs
│ ├── description.rs
│ ├── fixtures.rs
│ ├── fmt.rs
│ ├── internal
│ │ ├── description_renderer.rs
│ │ ├── glob.rs
│ │ ├── mod.rs
│ │ ├── test_filter.rs
│ │ ├── test_outcome.rs
│ │ └── test_sharding.rs
│ ├── lib.rs
│ ├── matcher.rs
│ ├── matcher_support
│ │ ├── auto_eq.rs
│ │ ├── count_elements.rs
│ │ ├── edit_distance.rs
│ │ ├── match_matrix.rs
│ │ ├── mod.rs
│ │ ├── summarize_diff.rs
│ │ └── zipped_iterator.rs
│ └── matchers
│ │ ├── all_matcher.rs
│ │ ├── any_matcher.rs
│ │ ├── anything_matcher.rs
│ │ ├── bool_matcher.rs
│ │ ├── char_count_matcher.rs
│ │ ├── conjunction_matcher.rs
│ │ ├── container_eq_matcher.rs
│ │ ├── contains_matcher.rs
│ │ ├── contains_regex_matcher.rs
│ │ ├── derefs_to_matcher.rs
│ │ ├── disjunction_matcher.rs
│ │ ├── display_matcher.rs
│ │ ├── each_matcher.rs
│ │ ├── elements_are_matcher.rs
│ │ ├── empty_matcher.rs
│ │ ├── eq_matcher.rs
│ │ ├── err_matcher.rs
│ │ ├── field_matcher.rs
│ │ ├── ge_matcher.rs
│ │ ├── gt_matcher.rs
│ │ ├── has_entry_matcher.rs
│ │ ├── is_encoded_string_matcher.rs
│ │ ├── is_finite_matcher.rs
│ │ ├── is_infinite_matcher.rs
│ │ ├── is_matcher.rs
│ │ ├── is_nan_matcher.rs
│ │ ├── le_matcher.rs
│ │ ├── len_matcher.rs
│ │ ├── lt_matcher.rs
│ │ ├── matches_pattern.rs
│ │ ├── matches_regex_matcher.rs
│ │ ├── mod.rs
│ │ ├── near_matcher.rs
│ │ ├── none_matcher.rs
│ │ ├── not_matcher.rs
│ │ ├── ok_matcher.rs
│ │ ├── points_to_matcher.rs
│ │ ├── pointwise_matcher.rs
│ │ ├── predicate_matcher.rs
│ │ ├── property_matcher.rs
│ │ ├── result_of_matcher.rs
│ │ ├── some_matcher.rs
│ │ ├── str_matcher.rs
│ │ ├── subset_of_matcher.rs
│ │ ├── superset_of_matcher.rs
│ │ ├── tuple_matcher.rs
│ │ └── unordered_elements_are_matcher.rs
└── tests
│ ├── all_matcher_test.rs
│ ├── any_matcher_test.rs
│ ├── assertions_test.rs
│ ├── colorized_diff_test.rs
│ ├── composition_test.rs
│ ├── elements_are_matcher_test.rs
│ ├── field_matcher_test.rs
│ ├── fmt_test.rs
│ ├── lib.rs
│ ├── matches_pattern_enum_test.rs
│ ├── matches_pattern_struct_and_enum_test.rs
│ ├── matches_pattern_struct_test.rs
│ ├── matches_pattern_tuple_struct_test.rs
│ ├── no_color_test.rs
│ ├── no_std_test.rs
│ ├── pointwise_matcher_test.rs
│ ├── property_matcher_test.rs
│ ├── proptest_integration_test.rs
│ ├── tuple_matcher_test.rs
│ └── unordered_elements_are_matcher_test.rs
├── googletest_macro
├── Cargo.toml
├── LICENSE
├── README.md
└── src
│ ├── lib.rs
│ ├── matches_pattern.rs
│ └── verify_pred.rs
├── integration_tests
├── Cargo.toml
└── src
│ ├── abbreviated_stringify_macro.rs
│ ├── add_failure_at_macro_allows_empty_message.rs
│ ├── add_failure_at_macro_allows_formatted_arguments.rs
│ ├── add_failure_at_macro_causes_failure_but_continues_execution.rs
│ ├── add_failure_at_macro_needs_googletest_attribute.rs
│ ├── add_failure_macro_allows_empty_message.rs
│ ├── add_failure_macro_allows_formatted_arguments.rs
│ ├── add_failure_macro_causes_failure_but_continues_execution.rs
│ ├── add_failure_macro_needs_googletest_attribute.rs
│ ├── always_fails.rs
│ ├── always_panics.rs
│ ├── assert_pred_macro_on_assertion_failure_with_format_args.rs
│ ├── assert_predicate_with_failure.rs
│ ├── assertion_failure_in_subroutine.rs
│ ├── assertion_failures_with_short_structured_actual_values.rs
│ ├── async_test_with_expect_that.rs
│ ├── custom_error_message.rs
│ ├── expect_eq_supports_custom_message.rs
│ ├── expect_eq_when_not_equal_returns_error.rs
│ ├── expect_eq_with_ordered_elements_supports_custom_message.rs
│ ├── expect_eq_with_ordered_elements_when_not_equal_returns_error.rs
│ ├── expect_eq_with_unordered_elements_supports_custom_message.rs
│ ├── expect_eq_with_unordered_elements_when_not_equal_returns_error.rs
│ ├── expect_false_macro_on_true_condition_fails_test_and_continues.rs
│ ├── expect_false_macro_on_true_condition_with_format_args.rs
│ ├── expect_float_eq_supports_custom_message.rs
│ ├── expect_float_eq_when_not_equal_marks_failed.rs
│ ├── expect_ge_supports_custom_message.rs
│ ├── expect_ge_when_less_marks_failed.rs
│ ├── expect_gt_supports_custom_message.rs
│ ├── expect_gt_when_not_greater_marks_failed.rs
│ ├── expect_le_supports_custom_message.rs
│ ├── expect_le_when_greater_marks_failed.rs
│ ├── expect_lt_supports_custom_message.rs
│ ├── expect_lt_when_not_less_marks_failed.rs
│ ├── expect_ne_supports_custom_message.rs
│ ├── expect_ne_when_equal_marks_failed.rs
│ ├── expect_near_supports_custom_message.rs
│ ├── expect_near_when_not_near_marks_failed.rs
│ ├── expect_panic.rs
│ ├── expect_panic_with_expected.rs
│ ├── expect_pred_failure.rs
│ ├── expect_pred_macro_on_assertion_failure_with_format_args.rs
│ ├── expect_that_failure.rs
│ ├── expect_true_macro_on_false_condition_fails_test_and_continues.rs
│ ├── expect_true_macro_on_false_condition_with_format_args.rs
│ ├── failure_due_to_fail_macro.rs
│ ├── failure_due_to_fail_macro_with_empty_message.rs
│ ├── failure_due_to_fail_macro_with_format_arguments.rs
│ ├── failure_due_to_returned_error.rs
│ ├── failure_due_to_returned_error_with_line_numbers.rs
│ ├── fatal_and_non_fatal_failure.rs
│ ├── first_failure_aborts.rs
│ ├── google_test_with_rstest.rs
│ ├── integration_tests.rs
│ ├── macro_hygiene.rs
│ ├── non_fatal_failure_in_subroutine.rs
│ ├── passing_test_with_should_panic.rs
│ ├── simple_assertion_failure.rs
│ ├── simple_assertion_failure_with_assert_that.rs
│ ├── success_with_succeed_macro.rs
│ ├── success_with_succeed_macro_with_empty_message.rs
│ ├── success_with_succeed_macro_with_format_arguments.rs
│ ├── test_returning_anyhow_error.rs
│ ├── test_returning_option.rs
│ ├── test_returning_string_error.rs
│ ├── two_expect_pred_failures.rs
│ ├── two_expect_that_failures.rs
│ ├── two_non_fatal_failures.rs
│ ├── verify_eq_when_not_equal_returns_error.rs
│ ├── verify_eq_with_ordered_elements_when_not_equal_returns_error.rs
│ ├── verify_eq_with_unordered_elements_when_not_equal_returns_error.rs
│ ├── verify_false_macro_on_true_condition.rs
│ ├── verify_float_eq_when_not_equal_returns_error.rs
│ ├── verify_ge_when_less_returns_error.rs
│ ├── verify_gt_when_not_greater_returns_error.rs
│ ├── verify_le_when_greater_returns_error.rs
│ ├── verify_lt_when_not_less_returns_error.rs
│ ├── verify_ne_when_equal_returns_error.rs
│ ├── verify_near_when_not_near_returns_error.rs
│ ├── verify_predicate_with_failure.rs
│ ├── verify_predicate_with_failure_as_method_in_submodule.rs
│ └── verify_true_macro_on_false_condition.rs
├── run_integration_tests.sh
└── rustfmt.toml
/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | [env]
2 | NO_COLOR = "1"
3 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "daily"
7 | rebase-strategy: disabled
8 | commit-message:
9 | prefix: ":seedling:"
10 | - package-ecosystem: "cargo"
11 | directory: "/"
12 | schedule:
13 | interval: "weekly"
14 | ignore:
15 | # These are peer deps of Cargo and should not be automatically bumped
16 | - dependency-name: "semver"
17 | - dependency-name: "crates-io"
18 | rebase-strategy: "disabled"
19 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: [ "main" ]
6 | pull_request:
7 | branches: [ "main" ]
8 |
9 | concurrency:
10 | group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
11 | cancel-in-progress: true
12 |
13 | permissions: read-all
14 |
15 | env:
16 | CARGO_TERM_COLOR: always
17 |
18 | jobs:
19 |
20 | clippy:
21 | runs-on: ubuntu-latest
22 | name: clippy / ${{ matrix.toolchain }}
23 | permissions:
24 | contents: read
25 | checks: write
26 | strategy:
27 | fail-fast: false
28 | matrix:
29 | toolchain: [stable, beta]
30 | steps:
31 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
32 | - name: Install ${{ matrix.toolchain }}
33 | uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b
34 | with:
35 | toolchain: ${{ matrix.toolchain }}
36 | components: clippy
37 | - name: cargo clippy
38 | uses: actions-rs/clippy-check@b5b5f21f4797c02da247df37026fcd0a5024aa4d # v1.0.7
39 | with:
40 | args: --all-targets --all-features
41 | token: ${{ secrets.GITHUB_TOKEN }}
42 |
43 | test-latest-deps:
44 | runs-on: ubuntu-latest
45 | name: test (latest deps) / ubuntu / ${{ matrix.toolchain }}
46 | strategy:
47 | matrix:
48 | toolchain: [stable, nightly, beta]
49 | steps:
50 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
51 | - name: Install ${{ matrix.toolchain }}
52 | uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b
53 | with:
54 | toolchain: ${{ matrix.toolchain }}
55 | - name: cargo update
56 | run: cargo update
57 | - name: cargo test --locked
58 | run: cargo test --locked --all-features
59 |
60 | test:
61 | runs-on: ubuntu-latest
62 | name: test / ubuntu / ${{ matrix.toolchain }}
63 | strategy:
64 | matrix:
65 | toolchain: [stable, nightly, beta]
66 | steps:
67 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
68 | - name: Install ${{ matrix.toolchain }}
69 | uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b
70 | with:
71 | toolchain: ${{ matrix.toolchain }}
72 | - name: cargo test --locked
73 | run: cargo test --locked --all-features
74 |
75 | lint:
76 | runs-on: ubuntu-latest
77 | name: lint / ubuntu
78 | strategy:
79 | matrix:
80 | toolchain: [nightly]
81 | steps:
82 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
83 | - name: Install ${{ matrix.toolchain }}
84 | uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b
85 | with:
86 | toolchain: ${{ matrix.toolchain }}
87 | components: rustfmt
88 | - name: cargo fmt --check
89 | run: cargo fmt --check
90 |
91 | test-no-default-features:
92 | runs-on: ubuntu-latest
93 | name: test (no default features) / ubuntu / ${{ matrix.toolchain }}
94 | strategy:
95 | matrix:
96 | toolchain: [stable, 1.70.0]
97 | steps:
98 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
99 | - name: Install ${{ matrix.toolchain }}
100 | uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b
101 | with:
102 | toolchain: ${{ matrix.toolchain }}
103 | - name: cargo test --locked
104 | run: cargo test --locked --no-default-features
105 |
106 | integration-test:
107 | runs-on: ubuntu-latest
108 | name: integration-test / ubuntu / ${{ matrix.toolchain }}
109 | strategy:
110 | matrix:
111 | toolchain: [stable, 1.70.0, nightly, beta]
112 | steps:
113 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
114 | - name: Install ${{ matrix.toolchain }}
115 | uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b
116 | with:
117 | toolchain: ${{ matrix.toolchain }}
118 | - name: run_integration_tests.sh
119 | run: /bin/bash ./run_integration_tests.sh
120 |
121 | integration-test-latest-deps:
122 | runs-on: ubuntu-latest
123 | name: integration-test (latest deps) / ubuntu / ${{ matrix.toolchain }}
124 | strategy:
125 | matrix:
126 | toolchain: [stable, nightly, beta]
127 | steps:
128 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
129 | - name: Install ${{ matrix.toolchain }}
130 | uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b
131 | with:
132 | toolchain: ${{ matrix.toolchain }}
133 | - name: cargo update
134 | run: cargo update
135 | - name: run_integration_tests.sh
136 | run: /bin/bash ./run_integration_tests.sh
137 | doc:
138 | runs-on: ubuntu-latest
139 | name: doc / nightly
140 | steps:
141 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
142 | with:
143 | submodules: true
144 | - name: Install nightly
145 | uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b
146 | with:
147 | toolchain: nightly
148 | - name: cargo doc
149 | run: cargo doc --no-deps --all-features
150 | env:
151 | RUSTDOCFLAGS: -D warnings
152 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | permissions: read-all
8 |
9 | env:
10 | CARGO_TERM_COLOR: always
11 |
12 | jobs:
13 | publish_macros:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
19 | - name: Publish release of googletest_macro
20 | env:
21 | CARGO_REGISTRY_TOKEN: ${{secrets.CARGO_REGISTRY_TOKEN}}
22 | run: cargo publish -p googletest_macro
23 |
24 | publish:
25 |
26 | needs: publish_macros
27 | runs-on: ubuntu-latest
28 |
29 | steps:
30 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
31 | - name: Publish release of googletest
32 | env:
33 | CARGO_REGISTRY_TOKEN: ${{secrets.CARGO_REGISTRY_TOKEN}}
34 | run: cargo publish -p googletest
35 |
--------------------------------------------------------------------------------
/.github/workflows/scorecard.yml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub. They are provided
2 | # by a third-party and are governed by separate terms of service, privacy
3 | # policy, and support documentation.
4 |
5 | name: Scorecard supply-chain security
6 | on:
7 | # For Branch-Protection check. Only the default branch is supported. See
8 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
9 | branch_protection_rule:
10 | # To guarantee Maintained check is occasionally updated. See
11 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
12 | schedule:
13 | - cron: '37 2 * * 5'
14 | push:
15 | branches: [ "main" ]
16 |
17 | # Declare default permissions as read only.
18 | permissions: read-all
19 |
20 | jobs:
21 | analysis:
22 | name: Scorecard analysis
23 | runs-on: ubuntu-latest
24 | permissions:
25 | # Needed to upload the results to code-scanning dashboard.
26 | security-events: write
27 | # Needed to publish results and get a badge (see publish_results below).
28 | id-token: write
29 | # Uncomment the permissions below if installing in a private repository.
30 | # contents: read
31 | # actions: read
32 |
33 | steps:
34 | - name: "Checkout code"
35 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
36 | with:
37 | persist-credentials: false
38 |
39 | - name: "Run analysis"
40 | uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
41 | with:
42 | results_file: results.sarif
43 | results_format: sarif
44 | # (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
45 | # - you want to enable the Branch-Protection check on a *public* repository, or
46 | # - you are installing Scorecard on a *private* repository
47 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
48 | # repo_token: ${{ secrets.SCORECARD_TOKEN }}
49 |
50 | # Public repositories:
51 | # - Publish results to OpenSSF REST API for easy access by consumers
52 | # - Allows the repository to include the Scorecard badge.
53 | # - See https://github.com/ossf/scorecard-action#publishing-results.
54 | # For private repositories:
55 | # - `publish_results` will always be set to `false`, regardless
56 | # of the value entered here.
57 | publish_results: true
58 |
59 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
60 | # format to the repository Actions tab.
61 | - name: "Upload artifact"
62 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
63 | with:
64 | name: SARIF file
65 | path: results.sarif
66 | retention-days: 5
67 |
68 | # Upload the results to GitHub's code scanning dashboard.
69 | - name: "Upload to code-scanning"
70 | uses: github/codeql-action/upload-sarif@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
71 | with:
72 | sarif_file: results.sarif
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | coverage
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution;
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code Reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult
22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
23 | information on using pull requests.
24 |
25 | ## Community Guidelines
26 |
27 | This project follows [Google's Open Source Community
28 | Guidelines](https://opensource.google/conduct/).
29 |
30 | ## Running the autoformatter rustfmt
31 |
32 | This repository uses a custom configuration for rustfmt which currently requires
33 | that one run the *nightly* version:
34 |
35 | ```
36 | cargo +nightly fmt
37 | ```
38 |
39 | The stable version will generate error messages and modify a lot of the
40 | existing formatting, obscuring any real changes you are making.
41 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | [workspace]
16 | resolver = "2"
17 | members = [
18 | "googletest_macro",
19 | "googletest",
20 | "integration_tests",
21 | ]
22 |
--------------------------------------------------------------------------------
/googletest/Cargo.toml:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | [package]
16 | name = "googletest"
17 | version = "0.14.1"
18 | keywords = ["unit", "matcher", "testing", "assertions"]
19 | categories = ["development-tools", "development-tools::testing"]
20 | description = "A rich assertion and matcher library inspired by GoogleTest for C++"
21 | repository = "https://github.com/google/googletest-rust"
22 | readme = "../README.md"
23 | license = "Apache-2.0"
24 | edition = "2021"
25 | rust-version = "1.70.0"
26 | authors = [
27 | "Bradford Hovinen ",
28 | "Bastien Jacot-Guillarmod ",
29 | "Maciej Pietrzak ",
30 | "Martin Geisler ",
31 | ]
32 |
33 | [dependencies]
34 | googletest_macro = { path = "../googletest_macro", version = "0.14.1" }
35 | anyhow = { version = "1", optional = true }
36 | num-traits = "0.2.17"
37 | proptest = { version = "1.7.0", optional = true }
38 | regex = "1.11.1"
39 | rustversion = "1.0.21"
40 |
41 | [dev-dependencies]
42 | indoc = "2"
43 | quickcheck = "1.0.3"
44 |
--------------------------------------------------------------------------------
/googletest/LICENSE:
--------------------------------------------------------------------------------
1 | ../LICENSE
--------------------------------------------------------------------------------
/googletest/src/fmt.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2024 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// Functions for use only by the procedural macros in this module.
16 | ///
17 | /// **For internal use only. API stablility is not guaranteed!**
18 | #[doc(hidden)]
19 | pub mod internal {
20 | use std::fmt::{Debug, Write};
21 |
22 | /// Wrapper to allow for inherent-method specialization based on whether a
23 | /// type implements `Debug`.
24 | pub struct FormatWrapper<'a, T: ?Sized>(pub &'a T);
25 |
26 | /// Default implementation to render values that implement `Debug`.
27 | ///
28 | /// Used for autoref specialization to conditionally
29 | /// render only values that implement `Debug`. See also
30 | /// [`FormatNonDebugFallback`].
31 | impl FormatWrapper<'_, T> {
32 | #[track_caller]
33 | pub fn __googletest_write_expr_value(&self, output: &mut dyn Write, expr_label: &str) {
34 | write!(output, "\n {} = {:?},", expr_label, self.0)
35 | .expect("Formatting to String should never fail");
36 | }
37 | }
38 |
39 | /// Fallback implementation for rendering values for non-`Debug` types..
40 | ///
41 | /// Used for inherent-method specialization to conditionally render only
42 | /// values that implement `Debug`. See also the specialized inherent impl on
43 | /// [`FormatWrapper`] above.
44 | pub trait FormatNonDebugFallback {
45 | fn __googletest_write_expr_value(&self, output: &mut dyn Write, expr_label: &str);
46 | }
47 |
48 | impl FormatNonDebugFallback for FormatWrapper<'_, T> {
49 | #[track_caller]
50 | fn __googletest_write_expr_value(&self, output: &mut dyn Write, expr_label: &str) {
51 | write!(output, "\n {expr_label} does not implement Debug,")
52 | .expect("Formatting to String should never fail");
53 | }
54 | }
55 |
56 | #[macro_export]
57 | macro_rules! __googletest__write_expr_value(
58 | ($output:expr, $expr_str:expr, $value:expr $(,)?) => {
59 | {
60 | use $crate::fmt::internal::FormatNonDebugFallback as _;
61 | $crate::fmt::internal::FormatWrapper(&$value)
62 | .__googletest_write_expr_value(&mut $output, $expr_str)
63 | }
64 | }
65 | );
66 | pub use __googletest__write_expr_value;
67 | }
68 |
--------------------------------------------------------------------------------
/googletest/src/internal/mod.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #![doc(hidden)]
16 |
17 | pub(crate) mod description_renderer;
18 | pub mod glob;
19 | pub mod test_filter;
20 | pub mod test_outcome;
21 | pub mod test_sharding;
22 |
--------------------------------------------------------------------------------
/googletest/src/internal/test_sharding.rs:
--------------------------------------------------------------------------------
1 | /// This module implements the googletest test sharding protocol. The Google
2 | /// sharding protocol consists of the following environment variables:
3 | ///
4 | /// * GTEST_TOTAL_SHARDS: total number of shards.
5 | /// * GTEST_SHARD_INDEX: number of this shard
6 | /// * GTEST_SHARD_STATUS_FILE: touch this file to indicate support for sharding.
7 | ///
8 | /// See also
9 | use std::cell::OnceCell;
10 | use std::env::{var, var_os};
11 | use std::ffi::{OsStr, OsString};
12 | use std::fs::{self, File};
13 | use std::num::NonZeroU64;
14 | use std::path::{Path, PathBuf};
15 |
16 | /// Environment variable specifying the total number of test shards.
17 | const TEST_TOTAL_SHARDS: &[&str] = &["GTEST_TOTAL_SHARDS", "TEST_TOTAL_SHARDS"];
18 |
19 | /// Environment variable specifyign the index of this test shard.
20 | const TEST_SHARD_INDEX: &[&str] = &["GTEST_SHARD_INDEX", "TEST_SHARD_INDEX"];
21 |
22 | /// Environment variable specifying the name of the file we create (or cause a
23 | /// timestamp change on) to indicate that we support the sharding protocol.
24 | const TEST_SHARD_STATUS_FILE: &[&str] = &["GTEST_SHARD_STATUS_FILE", "TEST_SHARD_STATUS_FILE"];
25 |
26 | thread_local! {
27 | static SHARDING: OnceCell = const { OnceCell::new() };
28 | }
29 |
30 | struct Sharding {
31 | this_shard: u64,
32 | total_shards: NonZeroU64,
33 | }
34 |
35 | impl Default for Sharding {
36 | fn default() -> Self {
37 | Self { this_shard: 0, total_shards: NonZeroU64::MIN }
38 | }
39 | }
40 |
41 | pub fn test_should_run(test_case_hash: u64) -> bool {
42 | SHARDING.with(|sharding_cell| {
43 | sharding_cell.get_or_init(Sharding::from_environment).test_should_run(test_case_hash)
44 | })
45 | }
46 |
47 | fn get_var(keys: &[&str]) -> Option {
48 | for key in keys {
49 | if let Ok(value) = var(OsStr::new(key)) {
50 | return Some(value);
51 | }
52 | }
53 |
54 | None
55 | }
56 |
57 | fn get_var_os(keys: &[&str]) -> Option {
58 | for key in keys {
59 | if let Some(value) = var_os(OsStr::new(key)) {
60 | return Some(value);
61 | }
62 | }
63 |
64 | None
65 | }
66 |
67 | impl Sharding {
68 | fn test_should_run(&self, test_case_hash: u64) -> bool {
69 | (test_case_hash % self.total_shards.get()) == self.this_shard
70 | }
71 |
72 | fn from_environment() -> Sharding {
73 | let this_shard: Option =
74 | { get_var(TEST_SHARD_INDEX).and_then(|value| value.parse().ok()) };
75 | let total_shards: Option = {
76 | get_var(TEST_TOTAL_SHARDS)
77 | .and_then(|value| value.parse().ok())
78 | .and_then(NonZeroU64::new)
79 | };
80 |
81 | match (this_shard, total_shards) {
82 | (Some(this_shard), Some(total_shards)) if this_shard < total_shards.get() => {
83 | if let Some(name) = get_var_os(TEST_SHARD_STATUS_FILE) {
84 | let pathbuf = PathBuf::from(name);
85 | if let Err(e) = create_status_file(&pathbuf) {
86 | eprintln!(
87 | "failed to create $GTEST_SHARD_STATUS_FILE file {}: {}",
88 | pathbuf.display(),
89 | e
90 | );
91 | }
92 | }
93 |
94 | Sharding { this_shard, total_shards }
95 | }
96 | _ => Sharding::default(),
97 | }
98 | }
99 | }
100 |
101 | fn create_status_file(path: &Path) -> std::io::Result<()> {
102 | if let Some(parent) = path.parent() {
103 | fs::create_dir_all(parent)?;
104 | }
105 |
106 | File::create(path).map(|_| ())
107 | }
108 |
--------------------------------------------------------------------------------
/googletest/src/matcher_support/auto_eq.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2024 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #![doc(hidden)]
16 |
17 | /// Macro that wraps the expression with `eq(...)` if the expression is
18 | /// not a matcher.
19 | ///
20 | /// This is useful to let users pass expected value to macro matchers like
21 | /// `field!` and `property!`.
22 | ///`
23 | /// **For internal use only. API stablility is not guaranteed!**
24 | /// If you are interested in using it in your matcher, please file an issue to
25 | /// stabilize this.
26 | #[macro_export]
27 | macro_rules! __auto_eq {
28 | ($e:expr) => {{
29 | #[allow(unused_imports)]
30 | use $crate::matcher_support::__internal_unstable_do_not_depend_on_these::ExpectedKind as _;
31 | match $e {
32 | expected => {
33 | $crate::matcher_support::__internal_unstable_do_not_depend_on_these::Wrapper(
34 | &expected,
35 | )
36 | .kind()
37 | .matcher(expected)
38 | }
39 | }
40 | }};
41 | }
42 |
43 | // This reimplements the pattern presented in
44 | // https://github.com/dtolnay/case-studies/issues/14
45 | pub mod internal {
46 | use crate::{
47 | matcher::MatcherBase,
48 | matchers::{eq, EqMatcher},
49 | };
50 |
51 | pub struct Wrapper(pub T);
52 |
53 | impl Wrapper<&'_ T> {
54 | #[inline]
55 | pub fn kind(&self) -> MatcherTag {
56 | MatcherTag
57 | }
58 | }
59 |
60 | pub trait ExpectedKind {
61 | #[inline]
62 | fn kind(&self) -> ExpectedTag {
63 | ExpectedTag
64 | }
65 | }
66 |
67 | impl ExpectedKind for Wrapper {}
68 |
69 | pub struct MatcherTag;
70 |
71 | impl MatcherTag {
72 | #[inline]
73 | pub fn matcher(self, matcher: M) -> M {
74 | matcher
75 | }
76 | }
77 | pub struct ExpectedTag;
78 |
79 | impl ExpectedTag {
80 | #[inline]
81 | pub fn matcher(self, expected: T) -> EqMatcher {
82 | eq(expected)
83 | }
84 | }
85 | }
86 |
87 | #[cfg(test)]
88 | mod tests {
89 | use crate::prelude::*;
90 | use crate::Result;
91 |
92 | #[test]
93 | fn auto_ref_matcher() -> Result<()> {
94 | verify_that!(123, __auto_eq!(ge(9)))
95 | }
96 |
97 | #[test]
98 | fn auto_ref_expected() -> Result<()> {
99 | verify_that!(123, __auto_eq!(123))
100 | }
101 |
102 | #[test]
103 | fn auto_ref_on_ref_matcher() -> Result<()> {
104 | let matcher = eq(123);
105 | verify_that!(123, __auto_eq!(&matcher))
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/googletest/src/matcher_support/count_elements.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// Counts the number of elements in `value`.
16 | ///
17 | /// This uses [`Iterator::size_hint`] when that function returns an
18 | /// unambiguous answer, i.e., the upper bound exists and the lower and upper
19 | /// bounds agree. Otherwise it iterates through `value` and counts the
20 | /// elements.
21 | pub(crate) fn count_elements(value: ContainerT) -> usize {
22 | let iterator = value.into_iter();
23 | if let (lower, Some(higher)) = iterator.size_hint() {
24 | if lower == higher {
25 | return lower;
26 | }
27 | }
28 | iterator.count()
29 | }
30 |
31 | #[cfg(test)]
32 | mod tests {
33 | use super::*;
34 | use crate::prelude::*;
35 | use crate::Result;
36 |
37 | #[test]
38 | fn count_elements_vec() -> Result<()> {
39 | verify_that!(count_elements(vec![1, 2, 3]), eq(3))
40 | }
41 |
42 | #[test]
43 | fn count_elements_with_imprecise_hint() -> Result<()> {
44 | struct FakeIterator;
45 |
46 | impl Iterator for FakeIterator {
47 | type Item = ();
48 |
49 | fn next(&mut self) -> Option {
50 | None
51 | }
52 |
53 | fn size_hint(&self) -> (usize, Option) {
54 | (0, Some(123))
55 | }
56 | }
57 |
58 | verify_that!(count_elements(FakeIterator), eq(0))
59 | }
60 |
61 | #[test]
62 | fn count_elements_with_no_hint() -> Result<()> {
63 | struct FakeIterator;
64 |
65 | impl Iterator for FakeIterator {
66 | type Item = ();
67 |
68 | fn next(&mut self) -> Option {
69 | None
70 | }
71 |
72 | fn size_hint(&self) -> (usize, Option) {
73 | (0, None)
74 | }
75 | }
76 |
77 | verify_that!(count_elements(FakeIterator), eq(0))
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/googletest/src/matcher_support/mod.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //! Utilities to facilitate writing matchers.
16 | //!
17 | //! Tests normally do not need to import anything from this module. Some of
18 | //! these facilities could be useful to downstream users writing custom
19 | //! matchers.
20 |
21 | mod auto_eq;
22 | pub(crate) mod count_elements;
23 | pub(crate) mod edit_distance;
24 | pub(crate) mod match_matrix;
25 | pub(crate) mod summarize_diff;
26 | pub(crate) mod zipped_iterator;
27 |
28 | pub mod __internal_unstable_do_not_depend_on_these {
29 | pub use super::auto_eq::internal::{ExpectedKind, Wrapper};
30 | pub use crate::__auto_eq as auto_eq;
31 | }
32 |
--------------------------------------------------------------------------------
/googletest/src/matcher_support/zipped_iterator.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// Zips up two iterators into a single iterator of pairs.
16 | ///
17 | /// This is identical to [`Iterator::zip`] except that this version allows the
18 | /// caller to determine whether the two iterators had mismatching sizes using
19 | /// the method [`ZippedIterator::has_size_mismatch`].
20 | ///
21 | /// [`Iterator::zip`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.zip
22 | pub(crate) fn zip(left: I1, right: I2) -> ZippedIterator {
23 | ZippedIterator { left, right, has_size_mismatch: false, consumed_elements: 0 }
24 | }
25 |
26 | /// An iterator over pairs of the elements of two constituent iterators, which
27 | /// keeps track of whether the two iterators have the same size.
28 | ///
29 | /// This is identical to [`Zip`] except that it allows the caller to determine
30 | /// whether the two iterators had mismatching sizes using the method
31 | /// [`ZippedIterator::has_size_mismatch`].
32 | ///
33 | /// [`Zip`]: https://doc.rust-lang.org/std/iter/struct.Zip.html
34 | pub(crate) struct ZippedIterator {
35 | left: I1,
36 | right: I2,
37 | has_size_mismatch: bool,
38 | consumed_elements: usize,
39 | }
40 |
41 | impl ZippedIterator {
42 | /// Returns whether a mismatch in the two sizes of the two iterators was
43 | /// detected during iteration.
44 | ///
45 | /// This returns `true` if and only if, at some previous call to
46 | /// [`Iterator::next`] on this instance, one of the constituent iterators
47 | /// had a next element and the other did not.
48 | ///
49 | /// [`Iterator::next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next
50 | pub(crate) fn has_size_mismatch(&self) -> bool {
51 | self.has_size_mismatch
52 | }
53 |
54 | /// Returns the number of elements in the left iterator.
55 | ///
56 | /// This iterates through the remainder of the left iterator if necessary in
57 | /// order to get the true number of elements. It therefore consumes `self`.
58 | pub(crate) fn left_size(mut self) -> usize {
59 | self.consumed_elements + self.left.by_ref().count()
60 | }
61 | }
62 |
63 | impl Iterator for ZippedIterator {
64 | type Item = (I1::Item, I2::Item);
65 |
66 | fn next(&mut self) -> Option<(I1::Item, I2::Item)> {
67 | match (self.left.next(), self.right.next()) {
68 | (Some(v1), Some(v2)) => {
69 | self.consumed_elements += 1;
70 | Some((v1, v2))
71 | }
72 | (Some(_), None) => {
73 | // Consumed elements counts only elements from self.left
74 | self.consumed_elements += 1;
75 | self.has_size_mismatch = true;
76 | None
77 | }
78 | (None, Some(_)) => {
79 | self.has_size_mismatch = true;
80 | None
81 | }
82 | (None, None) => None,
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/googletest/src/matchers/all_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // There are no visible documentation elements in this module; the declarative
16 | // macro is documented in the matcher module.
17 | #![doc(hidden)]
18 |
19 | /// Matches a value which all of the given matchers match.
20 | ///
21 | /// Each argument is a [`Matcher`][crate::matcher::Matcher] which matches
22 | /// against the actual value.
23 | ///
24 | /// For example:
25 | ///
26 | /// ```
27 | /// # use googletest::prelude::*;
28 | /// # fn should_pass() -> Result<()> {
29 | /// verify_that!("A string", all!(starts_with("A"), ends_with("string")))?; // Passes
30 | /// # Ok(())
31 | /// # }
32 | /// # fn should_fail() -> Result<()> {
33 | /// verify_that!("A string", all!(starts_with("A"), ends_with("not a string")))?; // Fails
34 | /// # Ok(())
35 | /// # }
36 | /// # should_pass().unwrap();
37 | /// # should_fail().unwrap_err();
38 | /// ```
39 | ///
40 | /// Using this macro is equivalent to using the
41 | /// [`and`][crate::matcher::MatcherBase::and] method:
42 | ///
43 | /// ```
44 | /// # use googletest::prelude::*;
45 | /// # fn should_pass() -> Result<()> {
46 | /// verify_that!(10, gt(9).and(lt(11)))?; // Also passes
47 | /// # Ok(())
48 | /// # }
49 | /// # should_pass().unwrap();
50 | /// ```
51 | ///
52 | /// Assertion failure messages are not guaranteed to be identical, however.
53 | ///
54 | /// If an inner matcher is `eq(...)`, it can be omitted:
55 | ///
56 | /// ```
57 | /// # use googletest::prelude::*;
58 | ///
59 | /// verify_that!(123, all![123, lt(1000), gt(100)])
60 | /// # .unwrap();
61 | /// ```
62 | #[macro_export]
63 | #[doc(hidden)]
64 | macro_rules! __all {
65 | ($(,)?) => {{
66 | $crate::matchers::anything()
67 | }} ;
68 | ($matcher:expr $(,)?) => {{
69 | use $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq;
70 | auto_eq!($matcher)
71 | }};
72 | ($head:expr, $head2:expr $(,)?) => {{
73 | use $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq;
74 | $crate::matchers::__internal_unstable_do_not_depend_on_these::ConjunctionMatcher::new(auto_eq!($head), auto_eq!($head2))
75 | }};
76 | ($head:expr, $head2:expr, $($tail:expr),+ $(,)?) => {{
77 | use $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq;
78 | $crate::__all![
79 | $crate::matchers::__internal_unstable_do_not_depend_on_these::ConjunctionMatcher::new(auto_eq!($head), auto_eq!($head2)),
80 | $($tail),+
81 | ]
82 | }}
83 | }
84 |
85 | #[cfg(test)]
86 | mod tests {
87 | use crate::matcher::MatcherResult;
88 | use crate::prelude::*;
89 | use crate::Result;
90 | use indoc::indoc;
91 |
92 | #[test]
93 | fn description_shows_more_than_one_matcher() -> Result<()> {
94 | let first_matcher = starts_with("A");
95 | let second_matcher = ends_with("string");
96 | let matcher = all!(first_matcher, second_matcher);
97 |
98 | verify_that!(
99 | Matcher::<&String>::describe(&matcher, MatcherResult::Match),
100 | displays_as(eq(indoc!(
101 | "
102 | has all the following properties:
103 | * starts with prefix \"A\"
104 | * ends with suffix \"string\""
105 | )))
106 | )
107 | }
108 |
109 | #[test]
110 | fn description_shows_one_matcher_directly() -> Result<()> {
111 | let first_matcher = starts_with("A");
112 | let matcher = all!(first_matcher);
113 |
114 | verify_that!(
115 | Matcher::<&String>::describe(&matcher, MatcherResult::Match),
116 | displays_as(eq("starts with prefix \"A\""))
117 | )
118 | }
119 |
120 | #[test]
121 | fn mismatch_description_shows_which_matcher_failed_if_more_than_one_constituent() -> Result<()>
122 | {
123 | let first_matcher = starts_with("Another");
124 | let second_matcher = ends_with("string");
125 | let matcher = all!(first_matcher, second_matcher);
126 |
127 | verify_that!(
128 | matcher.explain_match("A string"),
129 | displays_as(eq("which does not start with \"Another\""))
130 | )
131 | }
132 |
133 | #[test]
134 | fn mismatch_description_is_simple_when_only_one_consistuent() -> Result<()> {
135 | let first_matcher = starts_with("Another");
136 | let matcher = all!(first_matcher);
137 |
138 | verify_that!(
139 | matcher.explain_match("A string"),
140 | displays_as(eq("which does not start with \"Another\""))
141 | )
142 | }
143 |
144 | #[test]
145 | fn all_with_auto_eq() -> Result<()> {
146 | verify_that!(42, all![eq(42), 42, lt(100)])
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/googletest/src/matchers/anything_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{
16 | description::Description,
17 | matcher::{Matcher, MatcherBase, MatcherResult},
18 | };
19 | use std::fmt::Debug;
20 |
21 | /// Matches anything. This matcher always succeeds.
22 | ///
23 | /// This is useful to check if `actual` matches the specific structure (like
24 | /// `Some(...)`) but without caring about the internal value.
25 | ///
26 | /// ```
27 | /// # use googletest::prelude::*;
28 | /// # fn should_pass() -> Result<()> {
29 | /// let option = Some("Some value");
30 | /// verify_that!(option, some(anything()))?;
31 | /// # Ok(())
32 | /// # }
33 | /// # should_pass().unwrap();
34 | /// ```
35 | pub fn anything() -> Anything {
36 | Anything
37 | }
38 |
39 | #[derive(MatcherBase)]
40 | pub struct Anything;
41 |
42 | impl Matcher for Anything {
43 | fn matches(&self, _: T) -> MatcherResult {
44 | MatcherResult::Match
45 | }
46 |
47 | fn describe(&self, matcher_result: MatcherResult) -> Description {
48 | match matcher_result {
49 | MatcherResult::Match => "is anything".into(),
50 | MatcherResult::NoMatch => "never matches".into(),
51 | }
52 | }
53 | }
54 |
55 | #[cfg(test)]
56 | mod tests {
57 | use crate::prelude::*;
58 | use crate::Result;
59 |
60 | #[test]
61 | fn anything_matches_i32() -> Result<()> {
62 | let value = 32;
63 | verify_that!(value, anything())?;
64 | Ok(())
65 | }
66 |
67 | #[test]
68 | fn anything_matches_str() -> Result<()> {
69 | let value = "32";
70 | verify_that!(value, anything())?;
71 | Ok(())
72 | }
73 |
74 | #[test]
75 | fn anything_matches_option() -> Result<()> {
76 | let value = Some(32);
77 | verify_that!(value, some(anything()))?;
78 | Ok(())
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/googletest/src/matchers/bool_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2024 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{
16 | description::Description,
17 | matcher::{Matcher, MatcherBase, MatcherResult},
18 | };
19 |
20 | /// Matches boolean value `true`.
21 | pub fn is_true() -> BoolMatcher {
22 | BoolMatcher { expected: true }
23 | }
24 |
25 | /// Matches boolean value `false`.
26 | pub fn is_false() -> BoolMatcher {
27 | BoolMatcher { expected: false }
28 | }
29 |
30 | /// Matches a bool value or bool reference.
31 | #[derive(MatcherBase)]
32 | pub struct BoolMatcher {
33 | expected: bool,
34 | }
35 |
36 | impl BoolMatcher {
37 | fn matches(&self, actual: bool) -> MatcherResult {
38 | (actual == self.expected).into()
39 | }
40 |
41 | fn describe(&self, matcher_result: MatcherResult) -> Description {
42 | match (matcher_result, self.expected) {
43 | (MatcherResult::Match, true) | (MatcherResult::NoMatch, false) => "is true".into(),
44 | (MatcherResult::Match, false) | (MatcherResult::NoMatch, true) => "is false".into(),
45 | }
46 | }
47 | }
48 |
49 | impl Matcher for BoolMatcher {
50 | fn matches(&self, actual: bool) -> MatcherResult {
51 | self.matches(actual)
52 | }
53 |
54 | fn describe(&self, matcher_result: MatcherResult) -> Description {
55 | self.describe(matcher_result)
56 | }
57 | }
58 |
59 | impl<'a> Matcher<&'a bool> for BoolMatcher {
60 | fn matches(&self, actual: &'a bool) -> MatcherResult {
61 | self.matches(*actual)
62 | }
63 | fn describe(&self, matcher_result: MatcherResult) -> Description {
64 | self.describe(matcher_result)
65 | }
66 | }
67 |
68 | #[cfg(test)]
69 | mod tests {
70 | use super::*;
71 | use crate::prelude::*;
72 | use crate::Result;
73 |
74 | #[test]
75 | fn match_value() -> Result<()> {
76 | verify_that!(true, is_true())?;
77 | verify_that!(true, not(is_false()))?;
78 | verify_that!(false, is_false())?;
79 | verify_that!(false, not(is_true()))
80 | }
81 |
82 | #[test]
83 | fn match_ref() -> Result<()> {
84 | let t = true;
85 | let f = false;
86 |
87 | verify_that!(&t, is_true())?;
88 | verify_that!(&t, not(is_false()))?;
89 | verify_that!(&f, is_false())?;
90 | verify_that!(&f, not(is_true()))
91 | }
92 |
93 | #[test]
94 | fn describe() {
95 | assert_eq!(is_true().describe(MatcherResult::Match).to_string(), "is true");
96 | assert_eq!(is_true().describe(MatcherResult::NoMatch).to_string(), "is false");
97 | assert_eq!(is_false().describe(MatcherResult::Match).to_string(), "is false");
98 | assert_eq!(is_false().describe(MatcherResult::NoMatch).to_string(), "is true");
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/googletest/src/matchers/contains_regex_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::description::Description;
16 | use crate::matcher::{Matcher, MatcherBase, MatcherResult};
17 | use regex::Regex;
18 | use std::fmt::Debug;
19 | use std::ops::Deref;
20 |
21 | /// Matches a string containing a substring which matches the given regular
22 | /// expression.
23 | ///
24 | /// Both the actual value and the expected regular expression may be either a
25 | /// `String` or a string reference.
26 | ///
27 | /// ```
28 | /// # use googletest::prelude::*;
29 | /// # fn should_pass_1() -> Result<()> {
30 | /// verify_that!("Some value", contains_regex("S.*e"))?; // Passes
31 | /// # Ok(())
32 | /// # }
33 | /// # fn should_fail() -> Result<()> {
34 | /// verify_that!("Another value", contains_regex("Some"))?; // Fails
35 | /// # Ok(())
36 | /// # }
37 | /// # fn should_pass_2() -> Result<()> {
38 | /// verify_that!("Some value".to_string(), contains_regex("v.*e"))?; // Passes
39 | /// verify_that!("Some value", contains_regex("v.*e".to_string()))?; // Passes
40 | /// # Ok(())
41 | /// # }
42 | /// # should_pass_1().unwrap();
43 | /// # should_fail().unwrap_err();
44 | /// # should_pass_2().unwrap();
45 | /// ```
46 | ///
47 | /// Panics if the given `pattern` is not a syntactically valid regular
48 | /// expression.
49 | #[track_caller]
50 | pub fn contains_regex>(pattern: PatternT) -> ContainsRegexMatcher {
51 | ContainsRegexMatcher { regex: Regex::new(pattern.deref()).unwrap() }
52 | }
53 |
54 | /// A matcher matching a string-like type containing a substring matching a
55 | /// given regular expression.
56 | ///
57 | /// Intended only to be used from the function [`contains_regex`] only.
58 | /// Should not be referenced by code outside this library.
59 | #[derive(MatcherBase)]
60 | pub struct ContainsRegexMatcher {
61 | regex: Regex,
62 | }
63 |
64 | impl + Debug + Copy> Matcher for ContainsRegexMatcher {
65 | fn matches(&self, actual: ActualT) -> MatcherResult {
66 | self.regex.is_match(actual.as_ref()).into()
67 | }
68 |
69 | fn describe(&self, matcher_result: MatcherResult) -> Description {
70 | match matcher_result {
71 | MatcherResult::Match => {
72 | format!("contains the regular expression {:#?}", self.regex.as_str()).into()
73 | }
74 | MatcherResult::NoMatch => {
75 | format!("doesn't contain the regular expression {:#?}", self.regex.as_str()).into()
76 | }
77 | }
78 | }
79 | }
80 |
81 | #[cfg(test)]
82 | mod tests {
83 | use crate::matcher::MatcherResult;
84 | use crate::prelude::*;
85 | use crate::Result;
86 |
87 | #[test]
88 | fn contains_regex_matches_string_reference_with_pattern() -> Result<()> {
89 | let matcher = contains_regex("S.*val");
90 |
91 | let result = matcher.matches("Some value");
92 |
93 | verify_that!(result, eq(MatcherResult::Match))
94 | }
95 |
96 | #[test]
97 | fn contains_regex_does_not_match_string_without_pattern() -> Result<()> {
98 | let matcher = contains_regex("Another");
99 |
100 | let result = matcher.matches("Some value");
101 |
102 | verify_that!(result, eq(MatcherResult::NoMatch))
103 | }
104 |
105 | #[test]
106 | fn contains_regex_matches_owned_string_with_pattern() -> Result<()> {
107 | let matcher = contains_regex("value");
108 |
109 | let result = matcher.matches(&"Some value".to_string());
110 |
111 | verify_that!(result, eq(MatcherResult::Match))
112 | }
113 |
114 | #[test]
115 | fn contains_regex_matches_string_reference_with_owned_string() -> Result<()> {
116 | let matcher = contains_regex("value");
117 |
118 | let result = matcher.matches("Some value");
119 |
120 | verify_that!(result, eq(MatcherResult::Match))
121 | }
122 |
123 | #[test]
124 | fn verify_that_works_with_owned_string() -> Result<()> {
125 | verify_that!("Some value".to_string(), contains_regex("value"))
126 | }
127 |
128 | #[test]
129 | fn contains_regex_displays_quoted_debug_of_pattern() -> Result<()> {
130 | let matcher = contains_regex("\n");
131 |
132 | verify_that!(
133 | Matcher::<&str>::describe(&matcher, MatcherResult::Match),
134 | displays_as(eq("contains the regular expression \"\\n\""))
135 | )
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/googletest/src/matchers/derefs_to_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2024 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{
16 | description::Description,
17 | matcher::{Matcher, MatcherBase, MatcherResult},
18 | };
19 | use std::{fmt::Debug, ops::Deref};
20 |
21 | /// Dereferences the `actual` value and verifies that the returned reference
22 | /// matches the `inner` matcher.
23 | ///
24 | /// ```
25 | /// # use googletest::{matchers::{derefs_to, eq}, verify_that};
26 | /// verify_that!(Box::new(123), derefs_to(eq(&123)))
27 | /// # .unwrap()
28 | /// ```
29 | pub fn derefs_to(inner: Inner) -> DerefsTo {
30 | DerefsTo { inner }
31 | }
32 |
33 | /// A matcher which derefs a value and verifies that the result matches the
34 | /// `inner` matcher.
35 | ///
36 | /// See [`derefs_to`].
37 | #[derive(MatcherBase)]
38 | pub struct DerefsTo {
39 | pub(crate) inner: InnerT,
40 | }
41 |
42 | impl<'a, ActualT, ExpectedT, Inner> Matcher<&'a ActualT> for DerefsTo
43 | where
44 | ActualT: Deref + Debug,
45 | ExpectedT: Copy + Debug + 'a,
46 | Inner: Matcher<&'a ExpectedT>,
47 | {
48 | fn matches(&self, actual: &'a ActualT) -> MatcherResult {
49 | self.inner.matches(actual.deref())
50 | }
51 |
52 | fn describe(&self, matcher_result: MatcherResult) -> Description {
53 | self.inner.describe(matcher_result)
54 | }
55 |
56 | fn explain_match(&self, actual: &'a ActualT) -> Description {
57 | self.inner.explain_match(actual.deref())
58 | }
59 | }
60 |
61 | #[cfg(test)]
62 | mod tests {
63 | use std::rc::Rc;
64 |
65 | use crate::prelude::*;
66 | use crate::Result;
67 | use indoc::indoc;
68 |
69 | #[test]
70 | fn deref_to_matches_box_of_int_with_int() -> Result<()> {
71 | let actual = Box::new(123);
72 | verify_that!(actual, derefs_to(eq(&123)))
73 | }
74 |
75 | #[test]
76 | fn deref_to_matches_rc_of_int_with_int() -> Result<()> {
77 | verify_that!(Rc::new(123), derefs_to(eq(&123)))
78 | }
79 |
80 | #[test]
81 | fn deref_to_combines_with_points_to_for_copy() -> Result<()> {
82 | verify_that!(Rc::new(123), derefs_to(points_to(eq(123))))
83 | }
84 |
85 | #[test]
86 | fn match_explanation_references_actual_value() -> Result<()> {
87 | let actual = Box::new(1);
88 | let result = verify_that!(actual, derefs_to(eq(&0)));
89 |
90 | verify_that!(
91 | result,
92 | err(displays_as(contains_substring(indoc!(
93 | "
94 | Actual: 1,
95 | which isn't equal to 0
96 | "
97 | ))))
98 | )
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/googletest/src/matchers/disjunction_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // There are no visible documentation elements in this module.
16 | #![doc(hidden)]
17 |
18 | use crate::{
19 | description::Description,
20 | matcher::{Matcher, MatcherBase, MatcherResult},
21 | };
22 | use std::fmt::Debug;
23 |
24 | /// Matcher created by [`Matcher::or`] and [`any!`].
25 | ///
26 | /// Both [`Matcher::or`] and [`any!`] nest on m1. In other words,
27 | /// both `x.or(y).or(z)` and `any![x, y, z]` produce:
28 | /// ```ignore
29 | /// DisjunctionMatcher {
30 | /// m1: DisjunctionMatcher {
31 | /// m1: x, m2: y
32 | /// },
33 | /// m2: z
34 | /// }
35 | /// ```
36 | /// **For internal use only. API stablility is not guaranteed!**
37 | #[doc(hidden)]
38 | #[derive(MatcherBase)]
39 | pub struct DisjunctionMatcher {
40 | m1: M1,
41 | m2: M2,
42 | }
43 |
44 | impl DisjunctionMatcher {
45 | pub fn new(m1: M1, m2: M2) -> Self {
46 | Self { m1, m2 }
47 | }
48 | }
49 |
50 | impl, M2: Matcher> Matcher for DisjunctionMatcher {
51 | fn matches(&self, actual: T) -> MatcherResult {
52 | match (self.m1.matches(actual), self.m2.matches(actual)) {
53 | (MatcherResult::NoMatch, MatcherResult::NoMatch) => MatcherResult::NoMatch,
54 | _ => MatcherResult::Match,
55 | }
56 | }
57 |
58 | fn explain_match(&self, actual: T) -> Description {
59 | match (self.m1.matches(actual), self.m2.matches(actual)) {
60 | (MatcherResult::NoMatch, MatcherResult::Match) => self.m1.explain_match(actual),
61 | (MatcherResult::Match, MatcherResult::NoMatch) => self.m2.explain_match(actual),
62 | (_, _) => {
63 | let m1_description = self.m1.explain_match(actual);
64 | if m1_description.is_disjunction_description() {
65 | m1_description.nested(self.m2.explain_match(actual))
66 | } else {
67 | Description::new()
68 | .bullet_list()
69 | .collect([m1_description, self.m2.explain_match(actual)])
70 | .disjunction_description()
71 | }
72 | }
73 | }
74 | }
75 |
76 | fn describe(&self, matcher_result: MatcherResult) -> Description {
77 | let m1_description = self.m1.describe(matcher_result);
78 | if m1_description.is_disjunction_description() {
79 | m1_description.push_in_last_nested(self.m2.describe(matcher_result))
80 | } else {
81 | let header = if matcher_result.into() {
82 | "has at least one of the following properties:"
83 | } else {
84 | "has all of the following properties:"
85 | };
86 | Description::new()
87 | .text(header)
88 | .nested(
89 | Description::new()
90 | .bullet_list()
91 | .collect([m1_description, self.m2.describe(matcher_result)]),
92 | )
93 | .disjunction_description()
94 | }
95 | }
96 | }
97 |
98 | #[cfg(test)]
99 | mod tests {
100 | use crate::prelude::*;
101 | use crate::Result;
102 | use indoc::indoc;
103 |
104 | #[test]
105 | fn or_true_true_matches() -> Result<()> {
106 | verify_that!(1, anything().or(anything()))
107 | }
108 |
109 | #[test]
110 | fn or_true_false_matches() -> Result<()> {
111 | verify_that!(1, anything().or(not(anything())))
112 | }
113 |
114 | #[test]
115 | fn or_false_true_matches() -> Result<()> {
116 | verify_that!(1, not(anything()).or(anything()))
117 | }
118 |
119 | #[test]
120 | fn or_false_false_does_not_match() -> Result<()> {
121 | let result = verify_that!(1, not(anything()).or(not(anything())));
122 | verify_that!(
123 | result,
124 | err(displays_as(contains_substring(indoc!(
125 | "
126 | Value of: 1
127 | Expected: has at least one of the following properties:
128 | * never matches
129 | * never matches
130 | Actual: 1,
131 | * which is anything
132 | * which is anything
133 | "
134 | ))))
135 | )
136 | }
137 |
138 | #[test]
139 | fn chained_or_matches() -> Result<()> {
140 | verify_that!(10, eq(1).or(eq(5)).or(ge(9)))
141 | }
142 |
143 | #[test]
144 | fn works_with_str_slices() -> Result<()> {
145 | verify_that!("A string", ends_with("A").or(ends_with("string")))
146 | }
147 |
148 | #[test]
149 | fn works_with_owned_strings() -> Result<()> {
150 | verify_that!("A string".to_string(), ends_with("A").or(ends_with("string")))
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/googletest/src/matchers/display_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::description::Description;
16 | use crate::matcher::{Matcher, MatcherBase, MatcherResult};
17 | use std::fmt::{Debug, Display};
18 |
19 | /// Matches the string representation of types that implement `Display`.
20 | ///
21 | /// ```ignore
22 | /// let result: impl Display = ...;
23 | /// verify_that!(result, displays_as(eq(format!("{}", result))))?;
24 | /// ```
25 | pub fn displays_as Matcher<&'a str>>(
26 | inner: InnerMatcher,
27 | ) -> DisplayMatcher {
28 | DisplayMatcher { inner }
29 | }
30 |
31 | #[derive(MatcherBase)]
32 | pub struct DisplayMatcher {
33 | inner: InnerMatcher,
34 | }
35 |
36 | impl Matcher<&'a str>> Matcher
37 | for DisplayMatcher
38 | {
39 | fn matches(&self, actual: T) -> MatcherResult {
40 | self.inner.matches(&format!("{actual}"))
41 | }
42 |
43 | fn explain_match(&self, actual: T) -> Description {
44 | format!(
45 | "which displays as {:?} {}",
46 | actual.to_string(),
47 | self.inner.explain_match(&format!("{actual}"))
48 | )
49 | .into()
50 | }
51 |
52 | fn describe(&self, matcher_result: MatcherResult) -> Description {
53 | match matcher_result {
54 | MatcherResult::Match => {
55 | format!("displays as a string which {}", self.inner.describe(MatcherResult::Match))
56 | .into()
57 | }
58 | MatcherResult::NoMatch => format!(
59 | "doesn't display as a string which {}",
60 | self.inner.describe(MatcherResult::Match)
61 | )
62 | .into(),
63 | }
64 | }
65 | }
66 |
67 | #[cfg(test)]
68 | mod tests {
69 | use crate::prelude::*;
70 | use crate::Result;
71 | use indoc::indoc;
72 | use std::fmt::{Debug, Display, Error, Formatter};
73 |
74 | #[test]
75 | fn display_matches_i32() -> Result<()> {
76 | let value = 32;
77 | verify_that!(value, displays_as(eq("32")))?;
78 | Ok(())
79 | }
80 |
81 | #[test]
82 | fn display_matches_str() -> Result<()> {
83 | let value = "32";
84 | verify_that!(value, displays_as(eq("32")))?;
85 | Ok(())
86 | }
87 |
88 | #[test]
89 | fn display_matches_struct() -> Result<()> {
90 | #[allow(dead_code)]
91 | #[derive(Debug)]
92 | struct Struct {
93 | a: i32,
94 | b: i64,
95 | }
96 | impl Display for Struct {
97 | fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), Error> {
98 | write!(f, "{self:?}")
99 | }
100 | }
101 | verify_that!(Struct { a: 123, b: 321 }, displays_as(eq("Struct { a: 123, b: 321 }")))?;
102 | Ok(())
103 | }
104 |
105 | #[test]
106 | fn display_displays_error_message_with_explanation_from_inner_matcher() -> Result<()> {
107 | let result = verify_that!("123\n234", displays_as(eq("123\n345")));
108 |
109 | verify_that!(
110 | result,
111 | err(displays_as(contains_substring(indoc!(
112 | "
113 | Actual: \"123\\n234\",
114 | which displays as \"123\\n234\" which isn't equal to \"123\\n345\"
115 |
116 | Difference(-actual / +expected):
117 | 123
118 | -234
119 | +345
120 | "
121 | ))))
122 | )
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/googletest/src/matchers/empty_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{
16 | description::Description,
17 | matcher::{Matcher, MatcherBase, MatcherResult},
18 | };
19 | use std::fmt::Debug;
20 |
21 | /// Matches an empty container.
22 | ///
23 | /// `T` can be any container that implements `IntoIterator`. For instance, `T`
24 | /// can be the reference of a common container like `&Vec` and
25 | /// [`&HashSet`][std::collections::HashSet].
26 | ///
27 | /// ```
28 | /// # use googletest::prelude::*;
29 | /// # use std::collections::HashSet;
30 | /// # fn should_pass() -> Result<()> {
31 | /// let value: Vec = vec![];
32 | /// verify_that!(value, empty())?;
33 | /// let value: HashSet = HashSet::new();
34 | /// verify_that!(value, empty())?;
35 | /// let value: &[u32] = &[];
36 | /// verify_that!(value, empty())?;
37 | /// # Ok(())
38 | /// # }
39 | /// # should_pass().unwrap();
40 | /// ```
41 | pub fn empty() -> EmptyMatcher {
42 | EmptyMatcher
43 | }
44 |
45 | #[derive(MatcherBase)]
46 | pub struct EmptyMatcher;
47 |
48 | impl Matcher for EmptyMatcher
49 | where
50 | T: IntoIterator,
51 | {
52 | fn matches(&self, actual: T) -> MatcherResult {
53 | actual.into_iter().next().is_none().into()
54 | }
55 |
56 | fn describe(&self, matcher_result: MatcherResult) -> Description {
57 | if matcher_result.into() { "is empty" } else { "isn't empty" }.into()
58 | }
59 | }
60 |
61 | #[cfg(test)]
62 | mod tests {
63 | use crate::prelude::*;
64 | use crate::Result;
65 | use std::collections::HashSet;
66 |
67 | #[test]
68 | fn empty_matcher_match_empty_vec() -> Result<()> {
69 | let value: Vec = vec![];
70 | verify_that!(value, empty())
71 | }
72 |
73 | #[test]
74 | fn empty_matcher_does_not_match_empty_vec() -> Result<()> {
75 | let value = vec![1, 2, 3];
76 | verify_that!(value, not(empty()))
77 | }
78 |
79 | #[test]
80 | fn empty_matcher_matches_empty_slice() -> Result<()> {
81 | let value: &[i32] = &[];
82 | verify_that!(value, empty())
83 | }
84 |
85 | #[test]
86 | fn empty_matcher_matches_empty_hash_set() -> Result<()> {
87 | let value: HashSet = HashSet::new();
88 | verify_that!(value, empty())
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/googletest/src/matchers/is_finite_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{
16 | description::Description,
17 | matcher::{Matcher, MatcherBase, MatcherResult},
18 | };
19 | use num_traits::float::Float;
20 | use std::fmt::Debug;
21 |
22 | /// Matches a floating point value which is Finite.
23 | pub fn is_finite() -> IsFiniteMatcher {
24 | IsFiniteMatcher
25 | }
26 |
27 | #[derive(MatcherBase)]
28 | pub struct IsFiniteMatcher;
29 |
30 | impl Matcher for IsFiniteMatcher {
31 | fn matches(&self, actual: T) -> MatcherResult {
32 | actual.is_finite().into()
33 | }
34 |
35 | fn describe(&self, matcher_result: MatcherResult) -> Description {
36 | if matcher_result.into() { "is Finite" } else { "isn't Finite" }.into()
37 | }
38 | }
39 |
40 | #[cfg(test)]
41 | mod tests {
42 | use crate::prelude::*;
43 | use crate::Result;
44 |
45 | #[test]
46 | fn matches_f32_number() -> Result<()> {
47 | verify_that!(0.0f32, is_finite())
48 | }
49 |
50 | #[test]
51 | fn does_not_match_f32_pos_infinity() -> Result<()> {
52 | verify_that!(f32::INFINITY, not(is_finite()))
53 | }
54 |
55 | #[test]
56 | fn does_not_match_f32_neg_infinity() -> Result<()> {
57 | verify_that!(f32::NEG_INFINITY, not(is_finite()))
58 | }
59 |
60 | #[test]
61 | fn does_not_match_f32_nan() -> Result<()> {
62 | verify_that!(f32::NAN, not(is_finite()))
63 | }
64 |
65 | #[test]
66 | fn matches_f64_number() -> Result<()> {
67 | verify_that!(0.0f64, is_finite())
68 | }
69 |
70 | #[test]
71 | fn does_not_match_f64_pos_infinity() -> Result<()> {
72 | verify_that!(f64::INFINITY, not(is_finite()))
73 | }
74 |
75 | #[test]
76 | fn does_not_match_f64_neg_infinity() -> Result<()> {
77 | verify_that!(f64::NEG_INFINITY, not(is_finite()))
78 | }
79 |
80 | #[test]
81 | fn does_not_match_f64_nan() -> Result<()> {
82 | verify_that!(f64::NAN, not(is_finite()))
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/googletest/src/matchers/is_infinite_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{
16 | description::Description,
17 | matcher::{Matcher, MatcherBase, MatcherResult},
18 | };
19 | use num_traits::float::Float;
20 | use std::fmt::Debug;
21 |
22 | /// Matches a floating point value which is Infinite.
23 | pub fn is_infinite() -> IsInfiniteMatcher {
24 | IsInfiniteMatcher
25 | }
26 |
27 | #[derive(MatcherBase)]
28 | pub struct IsInfiniteMatcher;
29 |
30 | impl Matcher for IsInfiniteMatcher {
31 | fn matches(&self, actual: T) -> MatcherResult {
32 | actual.is_infinite().into()
33 | }
34 |
35 | fn describe(&self, matcher_result: MatcherResult) -> Description {
36 | if matcher_result.into() { "is Infinite" } else { "isn't Infinite" }.into()
37 | }
38 | }
39 |
40 | #[cfg(test)]
41 | mod tests {
42 | use crate::prelude::*;
43 | use crate::Result;
44 |
45 | #[test]
46 | fn matches_f32_pos_infinity() -> Result<()> {
47 | verify_that!(f32::INFINITY, is_infinite())
48 | }
49 |
50 | #[test]
51 | fn matches_f32_neg_infinity() -> Result<()> {
52 | verify_that!(f32::NEG_INFINITY, is_infinite())
53 | }
54 |
55 | #[test]
56 | fn does_not_match_f32_number() -> Result<()> {
57 | verify_that!(0.0f32, not(is_infinite()))
58 | }
59 |
60 | #[test]
61 | fn does_not_match_f32_nan() -> Result<()> {
62 | verify_that!(f32::NAN, not(is_finite()))
63 | }
64 |
65 | #[test]
66 | fn matches_f64_pos_infinity() -> Result<()> {
67 | verify_that!(f64::INFINITY, is_infinite())
68 | }
69 |
70 | #[test]
71 | fn matches_f64_neg_infinity() -> Result<()> {
72 | verify_that!(f64::NEG_INFINITY, is_infinite())
73 | }
74 |
75 | #[test]
76 | fn does_not_match_f64_number() -> Result<()> {
77 | verify_that!(0.0f64, not(is_infinite()))
78 | }
79 |
80 | #[test]
81 | fn does_not_match_f64_nan() -> Result<()> {
82 | verify_that!(f64::NAN, not(is_finite()))
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/googletest/src/matchers/is_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #![doc(hidden)]
16 |
17 | use crate::{
18 | description::Description,
19 | matcher::{Matcher, MatcherBase, MatcherResult},
20 | };
21 | use std::fmt::Debug;
22 |
23 | /// Matches precisely values matched by `inner`.
24 | ///
25 | /// The returned matcher produces a description prefixed by the string
26 | /// `description`. This is useful in contexts where the test assertion failure
27 | /// output must include the additional description.
28 | pub fn is(description: &str, inner: InnerMatcherT) -> IsMatcher<'_, InnerMatcherT> {
29 | IsMatcher { description, inner }
30 | }
31 |
32 | #[derive(MatcherBase)]
33 | pub struct IsMatcher<'a, InnerMatcherT> {
34 | description: &'a str,
35 | inner: InnerMatcherT,
36 | }
37 |
38 | impl> Matcher
39 | for IsMatcher<'_, InnerMatcherT>
40 | {
41 | fn matches(&self, actual: ActualT) -> MatcherResult {
42 | self.inner.matches(actual)
43 | }
44 |
45 | fn describe(&self, matcher_result: MatcherResult) -> Description {
46 | match matcher_result {
47 | MatcherResult::Match => format!(
48 | "is {} which {}",
49 | self.description,
50 | self.inner.describe(MatcherResult::Match)
51 | )
52 | .into(),
53 | MatcherResult::NoMatch => format!(
54 | "is not {} which {}",
55 | self.description,
56 | self.inner.describe(MatcherResult::Match)
57 | )
58 | .into(),
59 | }
60 | }
61 |
62 | fn explain_match(&self, actual: ActualT) -> Description {
63 | self.inner.explain_match(actual)
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/googletest/src/matchers/is_nan_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{
16 | description::Description,
17 | matcher::{Matcher, MatcherBase, MatcherResult},
18 | };
19 | use num_traits::float::Float;
20 | use std::fmt::Debug;
21 |
22 | /// Matches a floating point value which is NaN.
23 | pub fn is_nan() -> IsNanMatcher {
24 | IsNanMatcher
25 | }
26 |
27 | #[derive(MatcherBase)]
28 | pub struct IsNanMatcher;
29 |
30 | impl Matcher for IsNanMatcher {
31 | fn matches(&self, actual: T) -> MatcherResult {
32 | actual.is_nan().into()
33 | }
34 |
35 | fn describe(&self, matcher_result: MatcherResult) -> Description {
36 | if matcher_result.into() { "is NaN" } else { "isn't NaN" }.into()
37 | }
38 | }
39 |
40 | #[cfg(test)]
41 | mod tests {
42 | use crate::prelude::*;
43 | use crate::Result;
44 |
45 | #[test]
46 | fn matches_f32_nan() -> Result<()> {
47 | verify_that!(f32::NAN, is_nan())
48 | }
49 |
50 | #[test]
51 | fn does_not_match_f32_number() -> Result<()> {
52 | verify_that!(0.0f32, not(is_nan()))
53 | }
54 |
55 | #[test]
56 | fn matches_f64_nan() -> Result<()> {
57 | verify_that!(f64::NAN, is_nan())
58 | }
59 |
60 | #[test]
61 | fn does_not_match_f64_number() -> Result<()> {
62 | verify_that!(0.0f64, not(is_nan()))
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/googletest/src/matchers/mod.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //! All built-in matchers of this crate are in submodules of this module.
16 |
17 | mod all_matcher;
18 | mod any_matcher;
19 | mod anything_matcher;
20 | mod bool_matcher;
21 | mod char_count_matcher;
22 | mod conjunction_matcher;
23 | mod container_eq_matcher;
24 | mod contains_matcher;
25 | mod contains_regex_matcher;
26 | mod derefs_to_matcher;
27 | mod disjunction_matcher;
28 | mod display_matcher;
29 | mod each_matcher;
30 | mod elements_are_matcher;
31 | mod empty_matcher;
32 | mod eq_matcher;
33 | mod err_matcher;
34 | mod field_matcher;
35 | mod ge_matcher;
36 | mod gt_matcher;
37 | mod has_entry_matcher;
38 | mod is_encoded_string_matcher;
39 | mod is_finite_matcher;
40 | mod is_infinite_matcher;
41 | mod is_matcher;
42 | mod is_nan_matcher;
43 | mod le_matcher;
44 | mod len_matcher;
45 | mod lt_matcher;
46 | mod matches_pattern;
47 | mod matches_regex_matcher;
48 | mod near_matcher;
49 | mod none_matcher;
50 | mod not_matcher;
51 | mod ok_matcher;
52 | mod points_to_matcher;
53 | mod pointwise_matcher;
54 | mod predicate_matcher;
55 | mod property_matcher;
56 | mod result_of_matcher;
57 | mod some_matcher;
58 | mod str_matcher;
59 | mod subset_of_matcher;
60 | mod superset_of_matcher;
61 | mod tuple_matcher;
62 | mod unordered_elements_are_matcher;
63 |
64 | pub use anything_matcher::anything;
65 | pub use bool_matcher::{is_false, is_true};
66 | pub use char_count_matcher::char_count;
67 | pub use container_eq_matcher::container_eq;
68 | pub use contains_matcher::{contains, ContainsMatcher};
69 | pub use contains_regex_matcher::contains_regex;
70 | pub use derefs_to_matcher::derefs_to;
71 | pub use display_matcher::displays_as;
72 | pub use each_matcher::each;
73 | pub use empty_matcher::empty;
74 | pub use eq_matcher::{eq, EqMatcher};
75 | pub use err_matcher::err;
76 | pub use ge_matcher::ge;
77 | pub use gt_matcher::gt;
78 | pub use has_entry_matcher::has_entry;
79 | pub use is_encoded_string_matcher::is_utf8_string;
80 | pub use is_finite_matcher::is_finite;
81 | pub use is_infinite_matcher::is_infinite;
82 | pub use is_nan_matcher::is_nan;
83 | pub use le_matcher::le;
84 | pub use len_matcher::len;
85 | pub use lt_matcher::lt;
86 | pub use matches_regex_matcher::matches_regex;
87 | pub use near_matcher::{approx_eq, near, NearMatcher};
88 | pub use none_matcher::none;
89 | pub use not_matcher::not;
90 | pub use ok_matcher::ok;
91 | pub use points_to_matcher::points_to;
92 | pub use predicate_matcher::{predicate, PredicateMatcher};
93 | pub use some_matcher::some;
94 | pub use str_matcher::{
95 | contains_substring, ends_with, starts_with, StrMatcher, StrMatcherConfigurator,
96 | };
97 | pub use subset_of_matcher::subset_of;
98 | pub use superset_of_matcher::superset_of;
99 |
100 | // Reexport and unmangle the macros.
101 | #[doc(inline)]
102 | pub use crate::{
103 | __all as all, __any as any, __contains_each as contains_each, __elements_are as elements_are,
104 | __field as field, __is_contained_in as is_contained_in, __matches_pattern as matches_pattern,
105 | __pat as pat, __pointwise as pointwise, __property as property, __result_of as result_of,
106 | __result_of_ref as result_of_ref, __unordered_elements_are as unordered_elements_are,
107 | };
108 |
109 | // Types and functions used by macros matchers.
110 | // Do not use directly.
111 | // We may perform incompatible changes without major release. These elements
112 | // should only be used through their respective macros.
113 | #[doc(hidden)]
114 | pub mod __internal_unstable_do_not_depend_on_these {
115 | pub use super::conjunction_matcher::ConjunctionMatcher;
116 | pub use super::disjunction_matcher::DisjunctionMatcher;
117 | pub use super::elements_are_matcher::internal::ElementsAre;
118 | pub use super::field_matcher::internal::field_matcher;
119 | pub use super::is_matcher::is;
120 | pub use super::matches_pattern::internal::{
121 | __googletest_macro_matches_pattern, compile_assert_and_match, pattern_only,
122 | };
123 | pub use super::pointwise_matcher::internal::PointwiseMatcher;
124 | pub use super::property_matcher::internal::{property_matcher, property_ref_matcher};
125 | pub use super::result_of_matcher::internal::{result_of, result_of_ref};
126 | pub use super::unordered_elements_are_matcher::internal::UnorderedElementsAreMatcher;
127 | pub use crate::matcher_support::match_matrix::internal::Requirements;
128 | }
129 |
--------------------------------------------------------------------------------
/googletest/src/matchers/none_matcher.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::description::Description;
16 | use crate::matcher::{Matcher, MatcherBase, MatcherResult};
17 | use std::fmt::Debug;
18 |
19 | /// Matches an `Option` containing `None`.
20 | ///
21 | /// ```
22 | /// # use googletest::prelude::*;
23 | /// # fn should_pass() -> Result<()> {
24 | /// verify_that!(None::<()>, none())?; // Passes
25 | /// # Ok(())
26 | /// # }
27 | /// # fn should_fail() -> Result<()> {
28 | /// verify_that!(Some("Some value"), none())?; // Fails
29 | /// # Ok(())
30 | /// # }
31 | /// # should_pass().unwrap();
32 | /// # should_fail().unwrap_err();
33 | /// ```
34 | pub fn none() -> NoneMatcher {
35 | NoneMatcher
36 | }
37 |
38 | #[derive(MatcherBase)]
39 | pub struct NoneMatcher;
40 |
41 | impl Matcher