From patchwork Sun Mar 17 15:59:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Covrig X-Patchwork-Id: 61910 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id AF74C27BBEB; Sun, 17 Mar 2024 16:03:46 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id AB4C727BBEA for ; Sun, 17 Mar 2024 16:03:39 +0000 (GMT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rlsyt-0006Hm-Nb; Sun, 17 Mar 2024 12:03:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rlsyr-0006G2-SH for guix-patches@gnu.org; Sun, 17 Mar 2024 12:03:25 -0400 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rlsyr-0007SB-Hu for guix-patches@gnu.org; Sun, 17 Mar 2024 12:03:25 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1rlszS-0003uL-Dk; Sun, 17 Mar 2024 12:04:02 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#69859] [PATCH rust-team] gnu: Adds rust-pcap version 1.3, 0.11, and 0.10 Resent-From: Aaron Covrig Original-Sender: "Debbugs-submit" Resent-CC: efraim@flashner.co.il, guix-patches@gnu.org Resent-Date: Sun, 17 Mar 2024 16:04:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 69859 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 69859@debbugs.gnu.org Cc: Aaron Covrig , efraim@flashner.co.il X-Debbugs-Original-To: guix-patches@gnu.org X-Debbugs-Original-Xcc: efraim@flashner.co.il Received: via spool by submit@debbugs.gnu.org id=B.171069139514961 (code B ref -1); Sun, 17 Mar 2024 16:04:02 +0000 Received: (at submit) by debbugs.gnu.org; 17 Mar 2024 16:03:15 +0000 Received: from localhost ([127.0.0.1]:58773 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rlsyh-0003tF-Du for submit@debbugs.gnu.org; Sun, 17 Mar 2024 12:03:15 -0400 Received: from lists.gnu.org ([209.51.188.17]:60222) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rlsyf-0003t5-De for submit@debbugs.gnu.org; Sun, 17 Mar 2024 12:03:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rlsy3-0005vg-CG for guix-patches@gnu.org; Sun, 17 Mar 2024 12:02:35 -0400 Received: from mail-qk1-x72a.google.com ([2607:f8b0:4864:20::72a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rlsxx-0007Lw-Ty for guix-patches@gnu.org; Sun, 17 Mar 2024 12:02:35 -0400 Received: by mail-qk1-x72a.google.com with SMTP id af79cd13be357-781753f52afso205456285a.2 for ; Sun, 17 Mar 2024 09:02:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ieee.org; s=google; t=1710691347; x=1711296147; darn=gnu.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=tr7GPYWT9oLHAb/RfjVloRUSKYE2Mdg4gS0xcsO/fTQ=; b=URPSm/KSjRpcnWI9cp2eyLx0s55MRhrlCsrwBycxg4w7WtVnVDE+rJpEEPPMCXnZ4a YDiFQ2Ty9CY8Oq4uQqyJruG/ITx0CVB2UgIc+aMID+M7wIMxoRuOvEx+Fglvw4TtS8rm iRVfghGQ6ZE5GfIVBfVehCzfOpKI312wqC4Cg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710691347; x=1711296147; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=tr7GPYWT9oLHAb/RfjVloRUSKYE2Mdg4gS0xcsO/fTQ=; b=A6nSMTTJMPh4XY1oUiqbzZlVMpaL2yOAYAVbZj7sqvrYGaYXnty9k9F9usNrfb3CLj rQ5tJs2PnbhWvNiZHETzSPoSRXw0KZY6s89Q5TKO8HZRcaBEIf5tHR/FxiFhkZWqqv4T 24bPy1fDos61CdYQJFEzae5P0l3f8FW/IwasnhPwaiwRyRopuZRTjcwWrnceVt9fDd/9 FaEx1fl4+1NINiFcXLog5kK611FFpKaJTK5fI9KIt7C1D+tdML3Ev3+duFyuFR4ogcuG C9PvIhHlybmmGTASog8PbJzp4ujyBmxosr+V7GOrhihDa58Y/5+w2dPhg1axhWed/WfG dwvQ== X-Gm-Message-State: AOJu0YyxtWnx+tmm5viLJFuKpcuX/ZwmhhMY/SzBG+GAxl3ESfbPY3N5 Z5Q0KeFGhBpGyu0fSVDtyecBd0Qr5WlKApgm2xohX9cZGesA7awsxdeleQotksdgIg7Hymkg/Vu 0w31r/7rghrZ3DId1islQXcfgFLBDwOcDbSaTYZpzGNfURqENE3PSDAtdVVtQPiHjS1CPNn/zIU pnfJGvjvWf8i+HVeCOkxJpHTd6yT9GJTHYPUPVmA== X-Google-Smtp-Source: AGHT+IFlVw7mWFeyB/RczNexdIaHeqYjRa6bFAtT7yxQ38VCYeXHvtE3BXMBwwAUHYLNTGbwQ70J7Q== X-Received: by 2002:a05:620a:4011:b0:789:ed4c:88aa with SMTP id h17-20020a05620a401100b00789ed4c88aamr5762174qko.61.1710691344867; Sun, 17 Mar 2024 09:02:24 -0700 (PDT) Received: from mobile-dev.fios-router.home (pool-71-244-152-222.bltmmd.fios.verizon.net. [71.244.152.222]) by smtp.gmail.com with ESMTPSA id g7-20020a05620a40c700b00787ce45ed49sm3785360qko.67.2024.03.17.09.02.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 17 Mar 2024 09:02:24 -0700 (PDT) Date: Sun, 17 Mar 2024 11:59:17 -0400 Message-ID: <20240317160155.2039604-1-aaron.covrig.us@ieee.org> X-Mailer: git-send-email 2.41.0 MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::72a; envelope-from=aaron.covrig.us@ieee.org; helo=mail-qk1-x72a.google.com X-Spam_score_int: -23 X-Spam_score: -2.4 X-Spam_bar: -- X-Spam_report: (-2.4 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.316, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Aaron Covrig X-ACL-Warn: , Aaron Covrig via Guix-patches X-Patchwork-Original-From: Aaron Covrig via Guix-patches via From: Aaron Covrig Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org X-getmail-retrieved-from-mailbox: Patches * gnu/packages/crates-io.scm (rust-pcap-1): New variable * gnu/packages/crates-io.scm (rust-pcap-0.11): New variable * gnu/packages/crates-io.scm (rust-pcap-0.10): New variable * gnu/packages/crates-io.scm (rust-gat-std-0.1): New variable * gnu/packages/crates-io.scm (rust-gat-std-proc-0.1): New variable * gnu/packages/crates-io.scm (rust-etherparse-0.14): New variable * gnu/packages/crates-io.scm (rust-etherparse-0.9): New variable * gnu/packages/crates-io.scm (rust-eui48-1): New variable * gnu/packages/crates-io.scm (rust-tun-tap-0.1): New variable * gnu/packages/patches/rust-mockall-restore-examples-and-tests.patch: New file (provides tests and examples rust-mockall) * gnu/packages/crates-io.scm (rust-mockall-0.12): New variable * gnu/packages/crates-io.scm (rust-mockall-derive-0.12): New variable * gnu/packages/crates-io.scm (rust-mockall-0.11): Bumps to 0.11.4 * gnu/packages/crates-io.scm (rust-mockall-derive-0.11): Bumps to 0.11.4 * gnu/packages/crates-io.scm (rust-mockall-double-0.3): Bumps to 0.3.1 * gnu/packages/crates-io.scm (rust-fragile-2): New variable * gnu/packages/crates-io.scm (rust-fragile-1): Bumps to 1.2.2 * gnu/packages/crates-io.scm (rust-slab-0.4): Bumps to 0.4.9 --- gnu/packages/crates-io.scm | 453 +- ...t-mockall-restore-examples-and-tests.patch | 7611 +++++++++++++++++ 2 files changed, 7976 insertions(+), 88 deletions(-) create mode 100644 gnu/packages/patches/rust-mockall-restore-examples-and-tests.patch base-commit: aec00d246ecc12846560d15eae2c9fc9c6e6cc74 diff --git a/gnu/packages/crates-io.scm b/gnu/packages/crates-io.scm index e99f0f991b..34916d251e 100644 --- a/gnu/packages/crates-io.scm +++ b/gnu/packages/crates-io.scm @@ -24519,25 +24519,41 @@ (define-public rust-form-urlencoded-1 syntax, as used by HTML forms.") (license (list license:expat license:asl2.0)))) -(define-public rust-fragile-1 +(define-public rust-fragile-2 (package (name "rust-fragile") - (version "1.0.0") + (version "2.0.0") (source (origin (method url-fetch) (uri (crate-uri "fragile" version)) (file-name (string-append name "-" version ".tar.gz")) (sha256 - (base32 "1wlihmkjyhvl5rckal32p010piy1l15s6l81h7z31jcd971kk839")))) + (base32 "1ajfdnwdn921bhjlzyvsqvdgci8ab40ln6w9ly422lf8svb428bc")))) (build-system cargo-build-system) - (arguments `(#:skip-build? #t)) - (home-page "https://github.com/mitsuhiko/rust-fragile") + (arguments + `(#:cargo-inputs (("rust-slab" ,rust-slab-0.4)))) + (home-page "https://github.com/mitsuhiko/fragile") (synopsis "Wrapper types for sending non-send values to other threads") (description "This package provides wrapper types for sending non-send values to other threads.") (license license:asl2.0))) +(define-public rust-fragile-1 + (package + (inherit rust-fragile-2) + (name "rust-fragile") + (version "1.2.2") + (source + (origin + (method url-fetch) + (uri (crate-uri "fragile" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "1s2rz4cmmba5zi0gf2h6hprrcrf0wm83c1y45sdls09z99f4qimp")))) + (arguments + `(#:cargo-inputs (("rust-fragile" ,rust-fragile-2)))))) + (define-public rust-freetype-0.7 (package (name "rust-freetype") @@ -25974,6 +25990,48 @@ (define-public rust-galil-seiferas-0.1 time, for nonorderable alphabets.") (license (list license:expat license:asl2.0)))) +(define-public rust-gat-std-0.1 + (package + (name "rust-gat-std") + (version "0.1.1") + (source + (origin + (method url-fetch) + (uri (crate-uri "gat-std" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "14v4ldnzi8y8zkcj2qq7rj4af5ygk0s9iklflssxpcdgqzsfp3p0")))) + (build-system cargo-build-system) + (arguments + `(#:cargo-inputs (("rust-gat-std-proc" ,rust-gat-std-proc-0.1)))) + (home-page "https://github.com/CraftSpider/gat-std") + (synopsis "Variants of Rust std traits that use GATs") + (description + "A variant of Rust std traits that use GATs, as well as a macro to allow +rewriting code to use these traits instead of the std equivalents.") + (license (list license:expat license:asl2.0)))) + +(define-public rust-gat-std-proc-0.1 + (package + (name "rust-gat-std-proc") + (version "0.1.0") + (source + (origin + (method url-fetch) + (uri (crate-uri "gat-std-proc" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "0br6d92fg4g7s81lsms6q3ayss1bl19fanqxc7v1csnic2vaw84c")))) + (build-system cargo-build-system) + (arguments + `(#:cargo-inputs (("rust-proc-macro2" ,rust-proc-macro2-1) + ("rust-quote" ,rust-quote-1) + ("rust-syn" ,rust-syn-1)))) + (home-page "https://github.com/CraftSpider/gat-std") + (synopsis "Proc macros for gat-std") + (description "Proc macros for gat-std.") + (license (list license:expat license:asl2.0)))) + (define-public rust-gcc-0.3 (package (name "rust-gcc") @@ -38529,85 +38587,136 @@ (define-public rust-mock-instant-0.2 "This package provides a simple way to mock an std::time::Instant in rust.") (license license:bsd-0))) -(define-public rust-mockall-0.11 +(define-public rust-mockall-0.12 (package (name "rust-mockall") - (version "0.11.1") - (source (origin - (method url-fetch) - (uri (crate-uri "mockall" version)) - (file-name (string-append name "-" version ".tar.gz")) - (sha256 - (base32 - "0k3g3xxf195vsnzmwza047dv89zlg6h5yj5774wjlndgpdvf8han")))) + (version "0.12.1") + (source + (origin + (method url-fetch) + (uri (crate-uri "mockall" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "0j0a1wx6sb8yimjgg3q1svrn8jsnaiz9zqgz93ihvc83a8mnqxj3")) + (patches (search-patches + "rust-mockall-restore-examples-and-tests.patch")))) (build-system cargo-build-system) + ;; Tests depend on additional includes, only running examples (arguments - `(#:tests? #f ; Not all files included. - #:cargo-inputs - (("rust-cfg-if" ,rust-cfg-if-1) - ("rust-downcast" ,rust-downcast-0.11) - ("rust-fragile" ,rust-fragile-1) - ("rust-lazy-static" ,rust-lazy-static-1) - ("rust-mockall-derive" ,rust-mockall-derive-0.11) - ("rust-predicates" ,rust-predicates-2) - ("rust-predicates-tree" ,rust-predicates-tree-1)) - #:cargo-development-inputs - (("rust-async-trait" ,rust-async-trait-0.1) - ("rust-futures" ,rust-futures-0.3) - ("rust-mockall-double" ,rust-mockall-double-0.3) - ("rust-serde" ,rust-serde-1) - ("rust-serde-derive" ,rust-serde-derive-1) - ("rust-serde-json" ,rust-serde-json-1) - ("rust-tracing" ,rust-tracing-0.1)))) + `(#:cargo-test-flags '("--release" "--examples" "--lib") + #:cargo-inputs (("rust-cfg-if" ,rust-cfg-if-1) + ("rust-downcast" ,rust-downcast-0.11) + ("rust-fragile" ,rust-fragile-2) + ("rust-lazy-static" ,rust-lazy-static-1) + ("rust-mockall-derive" ,rust-mockall-derive-0.12) + ("rust-predicates" ,rust-predicates-3) + ("rust-predicates-tree" ,rust-predicates-tree-1)) + #:cargo-development-inputs (("rust-async-trait" ,rust-async-trait-0.1) + ("rust-futures" ,rust-futures-0.3) + ("rust-mockall-double" ,rust-mockall-double-0.3) + ("rust-serde" ,rust-serde-1) + ("rust-serde-derive" ,rust-serde-derive-1) + ("rust-serde-json" ,rust-serde-json-1) + ("rust-tracing" ,rust-tracing-0.1)))) (home-page "https://github.com/asomers/mockall") (synopsis "Mock object library for Rust") (description "Mockall is a rich mocking library with a terse and ergonomic interface.") (license (list license:expat license:asl2.0)))) -(define-public rust-mockall-derive-0.11 +(define-public rust-mockall-0.11 + (package + (inherit rust-mockall-0.12) + (name "rust-mockall") + (version "0.11.4") + (source + (origin + (method url-fetch) + (uri (crate-uri "mockall" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "15kww0a3wv300wkksc6zj0kz1jwk0hyly48daxs2vvpj300lk12c")) + (patches (search-patches + "rust-mockall-restore-examples-and-tests.patch")))) + (build-system cargo-build-system) + ;; Tests depend on additional includes, only running examples + (arguments + `(#:cargo-test-flags '("--release" "--examples" "--lib") + #:cargo-inputs (("rust-cfg-if" ,rust-cfg-if-1) + ("rust-downcast" ,rust-downcast-0.11) + ("rust-fragile" ,rust-fragile-2) + ("rust-lazy-static" ,rust-lazy-static-1) + ("rust-mockall-derive" ,rust-mockall-derive-0.11) + ("rust-predicates" ,rust-predicates-2) + ("rust-predicates-tree" ,rust-predicates-tree-1)) + #:cargo-development-inputs (("rust-async-trait" ,rust-async-trait-0.1) + ("rust-futures" ,rust-futures-0.3) + ("rust-mockall-double" ,rust-mockall-double-0.3) + ("rust-serde" ,rust-serde-1) + ("rust-serde-derive" ,rust-serde-derive-1) + ("rust-serde-json" ,rust-serde-json-1) + ("rust-tracing" ,rust-tracing-0.1)))))) + +(define-public rust-mockall-derive-0.12 (package (name "rust-mockall-derive") - (version "0.11.1") - (source (origin - (method url-fetch) - (uri (crate-uri "mockall_derive" version)) - (file-name (string-append name "-" version ".tar.gz")) - (sha256 - (base32 - "1ixhmsrg5ky4b2jlvbxhlpr3mbv7frd6wr8msm005vijb5rmcb96")))) + (version "0.12.1") + (source + (origin + (method url-fetch) + (uri (crate-uri "mockall_derive" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "1qhal0m997vy5vv8admrrbcibsq1cjkr1ajbypaa31f3kvkvqz5g")))) (build-system cargo-build-system) (arguments - `(#:cargo-inputs - (("rust-cfg-if" ,rust-cfg-if-1) - ("rust-proc-macro2" ,rust-proc-macro2-1) - ("rust-quote" ,rust-quote-1) - ("rust-syn" ,rust-syn-1)) - #:cargo-development-inputs - (("rust-pretty-assertions" ,rust-pretty-assertions-0.7)))) + `(#:cargo-inputs (("rust-cfg-if" ,rust-cfg-if-1) + ("rust-proc-macro2" ,rust-proc-macro2-1) + ("rust-quote" ,rust-quote-1) + ("rust-syn" ,rust-syn-2)) + #:cargo-development-inputs (("rust-pretty-assertions" ,rust-pretty-assertions-1)))) (home-page "https://github.com/asomers/mockall") (synopsis "Procedural macros for the Mockall crate") (description "This package procides procedural macros for the Mockall crate.") (license (list license:expat license:asl2.0)))) +(define-public rust-mockall-derive-0.11 + (package + (inherit rust-mockall-derive-0.12) + (name "rust-mockall-derive") + (version "0.11.4") + (source + (origin + (method url-fetch) + (uri (crate-uri "mockall_derive" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "1fvc9kwjcc9ia6ng7z9z02b4qkl9dvsx9m4z51xz9i0mj1k7bki2")))) + (arguments + `(#:cargo-inputs (("rust-cfg-if" ,rust-cfg-if-1) + ("rust-proc-macro2" ,rust-proc-macro2-1) + ("rust-quote" ,rust-quote-1) + ("rust-syn" ,rust-syn-1)) + #:cargo-development-inputs (("rust-pretty-assertions" ,rust-pretty-assertions-1)))))) + (define-public rust-mockall-double-0.3 (package (name "rust-mockall-double") - (version "0.3.0") - (source (origin - (method url-fetch) - (uri (crate-uri "mockall_double" version)) - (file-name (string-append name "-" version ".tar.gz")) - (sha256 - (base32 - "1xk6hjr7m73zly4hg3zmma437vqvrwnjxy2wfxy1hxbk52xwfwdf")))) + (version "0.3.1") + (source + (origin + (method url-fetch) + (uri (crate-uri "mockall_double" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "1s0k85929bf8afvdgq8m2vs8haqpkg9ysdimw7inl99mmkjrdjpi")))) (build-system cargo-build-system) (arguments `(#:cargo-inputs (("rust-cfg-if" ,rust-cfg-if-1) ("rust-proc-macro2" ,rust-proc-macro2-1) ("rust-quote" ,rust-quote-1) - ("rust-syn" ,rust-syn-1)))) + ("rust-syn" ,rust-syn-2)))) (home-page "https://github.com/asomers/mockall") (synopsis "Double test adapter that works well with Mockall") (description @@ -46217,8 +46326,91 @@ (define-public rust-pathdiff-0.2 path.") (license (list license:asl2.0 license:expat)))) +(define-public rust-pcap-1 + (package + (name "rust-pcap") + (version "1.3.0") + (source + (origin + (method url-fetch) + (uri (crate-uri "pcap" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "0ygzsi7v2x9ld5cb61dfg8jgifs2rln6qlknypzqjjnmfgy3bscr")))) + (build-system cargo-build-system) + (arguments + `(#:cargo-inputs (("rust-bitflags" ,rust-bitflags-1) + ("rust-errno" ,rust-errno-0.2) + ("rust-etherparse" ,rust-etherparse-0.13) + ("rust-gat-std" ,rust-gat-std-0.1) + ("rust-futures" ,rust-futures-0.3) + ("rust-libc" ,rust-libc-0.2) + ("rust-tokio" ,rust-tokio-1) + ("rust-tun-tap" ,rust-tun-tap-0.1) + ("rust-windows-sys" ,rust-windows-sys-0.36)) + #:cargo-development-inputs (("rust-eui48" ,rust-eui48-1) + ("rust-mockall" ,rust-mockall-0.11) + ("rust-once-cell" ,rust-once-cell-1) + ("rust-tempdir" ,rust-tempdir-0.3)))) + (inputs (list libpcap)) + (home-page "https://github.com/rust-pcap/pcap") + (synopsis "Rust packet capture API around pcap/wpcap") + (description "This is a Rust language crate for accessing the packet +sniffing capabilities of libpcap (or Npcap on Windows).") + (license (list license:asl2.0 license:expat)))) + +(define-public rust-pcap-0.11 + (package + (inherit rust-pcap-1) + (name "rust-pcap") + (version "0.11.0") + (source + (origin + (method url-fetch) + (uri (crate-uri "pcap" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "0sk9d0ygqgpwn6rpdclx8lqxcz8gm470pyfspbdjcgjvyr5jvncq")))) + (arguments + `(#:cargo-inputs (("rust-bitflags" ,rust-bitflags-1) + ("rust-errno" ,rust-errno-0.2) + ("rust-futures" ,rust-futures-0.3) + ("rust-libc" ,rust-libc-0.2) + ("rust-windows-sys" ,rust-windows-sys-0.36) + ("rust-tokio" ,rust-tokio-1)) + #:cargo-development-inputs (("rust-libloading" ,rust-libloading-0.6) + ("rust-pkg-config" ,rust-pkg-config-0.3) + ("rust-regex" ,rust-regex-1) + ("rust-eui48" ,rust-eui48-1) + ("rust-tempdir" ,rust-tempdir-0.3)))))) + +(define-public rust-pcap-0.10 + (package + (inherit rust-pcap-1) + (name "rust-pcap") + (version "0.10.1") + (source + (origin + (method url-fetch) + (uri (crate-uri "pcap" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "0yp1akb8y53faf993xv7l7va957waiv9qmjl8m3mpijw2744999d")))) + (arguments + `(#:cargo-inputs (("rust-bitflags" ,rust-bitflags-1) + ("rust-errno" ,rust-errno-0.2) + ("rust-futures" ,rust-futures-0.3) + ("rust-libc" ,rust-libc-0.2) + ("rust-windows-sys" ,rust-windows-sys-0.36) + ("rust-tokio" ,rust-tokio-1)) + #:cargo-development-inputs (("rust-eui48" ,rust-eui48-1) + ("rust-libloading" ,rust-libloading-0.6) + ("rust-regex" ,rust-regex-1) + ("rust-tempdir" ,rust-tempdir-0.3)))))) + (define-public rust-pcap-0.7 (package + (inherit rust-pcap-0.10) (name "rust-pcap") (version "0.7.0") (source @@ -46228,8 +46420,6 @@ (define-public rust-pcap-0.7 (file-name (string-append name "-" version ".tar.gz")) (sha256 (base32 "14blflnbj87z3ajlj1hszsl6k7rwa338y4aw2yjm2j0xdpjvj4pr")))) - (native-inputs (list libpcap)) - (build-system cargo-build-system) (arguments `(#:tests? #f ; can't find crate for `futures` #:cargo-inputs @@ -46239,11 +46429,7 @@ (define-public rust-pcap-0.7 ("rust-mio" ,rust-mio-0.6) ("rust-tokio-core" ,rust-tokio-core-0.1)) #:cargo-development-inputs - (("rust-tempdir" ,rust-tempdir-0.3)))) - (home-page "https://github.com/rust-pcap/pcap") - (synopsis "Packet capture API around pcap/wpcap") - (description "This package provides a packet capture API around pcap/wpcap.") - (license (list license:expat license:asl2.0)))) + (("rust-tempdir" ,rust-tempdir-0.3)))))) (define-public rust-pcap-sys-0.1 (package @@ -57118,29 +57304,91 @@ (define-public rust-ethtool-0.2 (description "Linux Ethtool Communication Library.") (license license:expat))) -(define-public rust-etherparse-0.13 + +(define-public rust-etherparse-0.14 (package (name "rust-etherparse") - (version "0.13.0") + (version "0.14.2") (source (origin (method url-fetch) (uri (crate-uri "etherparse" version)) (file-name (string-append name "-" version ".tar.gz")) (sha256 - (base32 "146rcbnhlpcbl6c6csfhvz0227wbiwhk13md6acq8211b7m94wl2")))) + (base32 "1cf9qf089c8a5xlr7az2wcrr0i0l2zi1q9h2ixwalhsbxc1hd294")))) (build-system cargo-build-system) (arguments `(#:cargo-inputs (("rust-arrayvec" ,rust-arrayvec-0.7)) - #:cargo-development-inputs (("rust-assert-matches" ,rust-assert-matches-1) - ("rust-proptest" ,rust-proptest-1)))) + #:cargo-development-inputs (("rust-proptest" ,rust-proptest-1)))) (home-page "https://github.com/JulianSchmid/etherparse") - (synopsis "Library for parsing & writing a bunch of packet based protocols") + (synopsis + "Library for parsing & writing a bunch of packet based protocols") (description - "This package provides a library for parsing & writing a bunch of packet -based protocols (@code{EthernetII}, IPv4, IPv6, UDP, TCP ...).") + "A zero allocation library for parsing & writing a bunch of +packet based protocols (EthernetII, IPv4, IPv6, UDP, TCP ...).") (license (list license:expat license:asl2.0)))) +(define-public rust-etherparse-0.13 + (package + (inherit rust-etherparse-0.14) + (name "rust-etherparse") + (version "0.13.0") + (source + (origin + (method url-fetch) + (uri (crate-uri "etherparse" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "146rcbnhlpcbl6c6csfhvz0227wbiwhk13md6acq8211b7m94wl2")))) + (arguments + `(#:cargo-inputs (("rust-arrayvec" ,rust-arrayvec-0.7)) + #:cargo-development-inputs (("rust-assert-matches" ,rust-assert-matches-1) + ("rust-proptest" ,rust-proptest-1)))))) + +(define-public rust-etherparse-0.9 + (package + (inherit rust-etherparse-0.13) + (name "rust-etherparse") + (version "0.9.0") + (source + (origin + (method url-fetch) + (uri (crate-uri "etherparse" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "01s86nj0k663mgxpj3r7y5wr50l5c3aq0pm4rpzyb7hz50i0k8ig")))) + (arguments + `(#:cargo-inputs (("rust-byteorder" ,rust-byteorder-1)) + #:cargo-development-inputs (("rust-assert-matches" ,rust-assert-matches-1) + ("rust-proptest" ,rust-proptest-0.9)))))) + +(define-public rust-eui48-1 + (package + (name "rust-eui48") + (version "1.1.0") + (source + (origin + (method url-fetch) + (uri (crate-uri "eui48" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "00cpf25kc3mxhqnahm0bw9xl19gr2pzc5g84dvkc4mwdbsn1hx48")))) + (build-system cargo-build-system) + (arguments + `(#:cargo-inputs (("rust-regex" ,rust-regex-1) + ("rust-rustc-serialize" ,rust-rustc-serialize-0.3) + ("rust-serde" ,rust-serde-1) + ("rust-serde-json" ,rust-serde-json-1)) + #:cargo-development-inputs (("rust-bincode" ,rust-bincode-1)))) + (home-page "https://github.com/abaumhauer/eui48") + (synopsis "Rust implementation of IEEE EUI-48 (MAC-48) datatype") + (description + "A library to generate and parse IEEE EUI-48 and EUI-64, also +known as MAC-48 media access control addresses. The IEEE claims trademarks on +the names EUI-48 and EUI-64, in which EUI is an abbreviation for Extended Unique +Identifier.") + (license (list license:asl2.0 license:expat)))) + (define-public rust-rust-hawktracer-0.7 (package (name "rust-rust-hawktracer") @@ -62931,26 +63179,23 @@ (define-public rust-skim-0.7 (define-public rust-slab-0.4 (package (name "rust-slab") - (version "0.4.8") + (version "0.4.9") (source - (origin - (method url-fetch) - (uri (crate-uri "slab" version)) - (file-name (string-append name "-" version ".tar.gz")) - (sha256 - (base32 - "0bgwxig8gkqp6gz8rvrpdj6qwa10karnsxwx7wsj5ay8kcf3aa35")))) + (origin + (method url-fetch) + (uri (crate-uri "slab" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "0rxvsgir0qw5lkycrqgb1cxsvxzjv9bmx73bk5y42svnzfba94lg")))) (build-system cargo-build-system) (arguments - `(#:cargo-development-inputs - (("rust-rustversion" ,rust-rustversion-1) - ("rust-serde" ,rust-serde-1) - ("rust-serde-test" ,rust-serde-test-1)) - #:cargo-inputs (("rust-autocfg" ,rust-autocfg-1) - ("rust-serde" ,rust-serde-1)))) - (native-inputs - (list rust-autocfg-1)) - (home-page "https://github.com/carllerche/slab") + `(#:cargo-development-inputs (("rust-rustversion" ,rust-rustversion-1) + ("rust-serde" ,rust-serde-1) + ("rust-serde-test" ,rust-serde-test-1) + ("rust-autocfg" ,rust-autocfg-1)) + #:cargo-inputs (("rust-serde" ,rust-serde-1) + ("rust-autocfg" ,rust-autocfg-1)))) + (home-page "https://github.com/tokio-rs/slab") (synopsis "Pre-allocated storage for a uniform data type") (description "This create provides a pre-allocated storage for a uniform data type.") @@ -74935,6 +75180,38 @@ (define-public rust-tuikit-0.2 #:cargo-development-inputs (("rust-env-logger" ,rust-env-logger-0.6)))))) +(define-public rust-tun-tap-0.1 + (package + (name "rust-tun-tap") + (version "0.1.4") + (source + (origin + (method url-fetch) + (uri (crate-uri "tun-tap" version)) + (file-name (string-append name "-" version ".tar.gz")) + (sha256 + (base32 "0l5yp9xs5kyhzrkqfhnqjwj97ylzr5xd0g6jfp42miv7jd77liws")))) + (build-system cargo-build-system) + (arguments + `(#:cargo-test-flags '("--" + ;; Network access not allowed in build environment + "--skip=it_receives_packets" + "--skip=it_sents_packets") + #:cargo-inputs (("rust-futures" ,rust-futures-0.1) + ("rust-libc" ,rust-libc-0.2) + ("rust-mio" ,rust-mio-0.6) + ("rust-tokio-core" ,rust-tokio-core-0.1)) + #:cargo-development-inputs (("rust-cc" ,rust-cc-1) + ("rust-etherparse" ,rust-etherparse-0.9) + ("rust-serial-test" ,rust-serial-test-0.4) + ("rust-version-sync" ,rust-version-sync-0.9)))) + (home-page "https://github.com/vorner/tuntap") + (synopsis "TUN/TAP interface wrapper") + (description + "Rust TUN/TAP wrapper allowing the implementation of virtual network adaptors in +userspace.") + (license (list license:expat license:asl2.0)))) + (define-public rust-twoway-0.2 (package (name "rust-twoway") diff --git a/gnu/packages/patches/rust-mockall-restore-examples-and-tests.patch b/gnu/packages/patches/rust-mockall-restore-examples-and-tests.patch new file mode 100644 index 0000000000..1c1f77eb0d --- /dev/null +++ b/gnu/packages/patches/rust-mockall-restore-examples-and-tests.patch @@ -0,0 +1,7611 @@ +This patch restores the tests and examples that were removed from +mockall when it was bundled for distribution. They are required +to enable testing of the built packages. + +--- +diff --git a/examples/ffi.rs b/examples/ffi.rs +new file mode 100644 +index 0000000..6b7c9d0 +--- /dev/null ++++ b/examples/ffi.rs +@@ -0,0 +1,34 @@ ++// vim: tw=80 ++//! An example of unit testing involving mocked FFI functions ++ ++#[cfg(test)] ++use mockall::automock; ++use mockall_double::double; ++ ++#[cfg_attr(test, automock)] ++pub mod mockable_ffi { ++ extern "C" { ++ pub fn abs(i: i32) -> i32; ++ } ++} ++ ++#[double] ++use mockable_ffi as ffi; ++ ++fn abs(i: i32) -> i32 { ++ unsafe { ffi::abs(i) } ++} ++ ++fn main() { ++ let i: i32 = -42; ++ println!("abs({}) = {}", i, abs(i) ); ++} ++ ++ ++#[test] ++fn time_test() { ++ let ctx = ffi::abs_context(); ++ ctx.expect() ++ .return_const(42); ++ assert_eq!(42, abs(-42)) ++} +diff --git a/examples/serde.rs b/examples/serde.rs +new file mode 100644 +index 0000000..4498449 +--- /dev/null ++++ b/examples/serde.rs +@@ -0,0 +1,102 @@ ++// vim: tw=80 ++//! Mock a struct that implements Serde traits ++//! ++//! Serde defines to popular traits that look like this: ++//! ```ignore ++//! trait Serialize { ++//! fn serialize(&self, serializer: S) -> Result; ++//! } ++//! trait Deserialize { ++//! fn deserialize(deserializer: D) -> Result; ++//! } ++//! ``` ++//! ++//! Mockall can usually implement traits with generic methods. However, ++//! `serde::Serializer` isn't `'static`, and the definition of ++//! `Serialize::serialize` doesn't require `S` to be static. That's a problem, ++//! because Mockall requires that all generic methods' generic types be ++//! `'static` so that they can implement `std::any::Any`. ++//! ++//! There's no getting around that requirement. But there's still hope! You ++//! can mock a struct that implements Serde traits by manually implementing ++//! `Serialize` and `Deserialize` in terms of non-generic methods, using a ++//! surrogate object for the expectations. ++#![deny(warnings)] ++ ++use mockall::*; ++use serde::{Deserialize, Deserializer}; ++use serde_derive::*; ++ ++/// A serializable surrogate for `Thing`. It should serialize and deserialize ++/// in exactly the same way as `Thing`. In fact, it may even be `Thing`. ++#[derive(Deserialize, Serialize)] ++pub struct SurrogateThing { ++ x: u32 ++} ++ ++mock! { ++ pub Thing { ++ // MockThing's private deserialize method. The name is not important, ++ // but you probably don't want to call it `deserialize` because then ++ // you'll have to call the real deserialize method using ++ // `::deserialize` syntax. ++ // ++ // This method must always succeed (or panic), because `Deserialize`'s ++ // error type is neither `'static` nor `Default`. ++ fn private_deserialize(deserializable: Result) -> Self; ++ // MockThing's private serialize method. The name is not important, ++ // but you probably don't want to call it `serialize` because then ++ // you'll have to call the real serialize method using ++ // `::serialize` syntax. ++ // ++ // This method must always succeed (or panic), because `Serialize`'s ++ // error type is neither `'static` nor `Default`. ++ fn private_serialize(&self) -> SurrogateThing; ++ } ++} ++ ++// Manually implement Serialize for MockThing ++impl serde::Serialize for MockThing { ++ fn serialize(&self, s: S) -> Result { ++ self.private_serialize().serialize(s) ++ } ++} ++ ++// Manually implement Deserialize for MockThing ++impl<'de> Deserialize<'de> for MockThing { ++ fn deserialize(deserializer: D) -> Result ++ where ++ D: Deserializer<'de>, ++ { ++ let serializable = SurrogateThing::deserialize(deserializer) ++ .map_err(|_| ()); ++ Ok(MockThing::private_deserialize(serializable)) ++ } ++} ++ ++// In your tests, set an expectation for `private_serialize` and return a ++// suitable `SurrogateThing` ++#[test] ++fn serialize() { ++ let mut mock = MockThing::default(); ++ mock.expect_private_serialize() ++ .returning(|| SurrogateThing{x: 42} ); ++ ++ let json = serde_json::to_string(&mock).unwrap(); ++ assert_eq!("{\"x\":42}", json); ++} ++ ++// In your tests, set an expectation for `private_deserialize`, which will ++// receive an already-deserialized `SurrogateThing` object. ++#[test] ++fn deserialize() { ++ let ctx = MockThing::private_deserialize_context(); ++ ctx.expect() ++ .withf(|st: &Result| ++ st.as_ref().unwrap().x == 42 ++ ).once() ++ .returning(|_| MockThing::default()); ++ ++ let json = "{\"x\":42}"; ++ let _thing: MockThing = serde_json::from_str(json).unwrap(); ++} +diff --git a/examples/synchronization.rs b/examples/synchronization.rs +new file mode 100644 +index 0000000..a943b88 +--- /dev/null ++++ b/examples/synchronization.rs +@@ -0,0 +1,64 @@ ++// vim: tw=80 ++//! Add synchronization to multiple tests that are accessing the same mock ++//! ++//! When mockall mocks a function or static method, it does so globally. This ++//! can cause hard to debug and non-deterministic failures when one test ++//! overwrites the mock that another test is depending on. The solution to this ++//! is to add some form of synchronization so that tests that depend on a ++//! specific mock will not run in parallel. This is easily achieved using a ++//! Mutex. ++#![deny(warnings)] ++ ++use mockall_double::double; ++ ++pub mod my_mock { ++ #[cfg(test)] ++ use mockall::automock; ++ ++ pub struct Thing; ++ #[cfg_attr(test, automock)] ++ impl Thing { ++ pub fn one() -> u32 { ++ 1 ++ } ++ } ++} ++ ++#[double] ++use my_mock::Thing; ++ ++fn main() { ++ println!("1 == {}", Thing::one()); ++} ++ ++#[cfg(test)] ++mod test { ++ use crate::my_mock::MockThing; ++ use std::sync::Mutex; ++ ++ static MTX: Mutex<()> = Mutex::new(()); ++ ++ #[test] ++ fn test_1() { ++ // The mutex might be poisoned if another test fails. But we don't ++ // care, because it doesn't hold any data. So don't unwrap the Result ++ // object; whether it's poisoned or not, we'll still hold the ++ // MutexGuard. ++ let _m = MTX.lock(); ++ ++ let ctx = MockThing::one_context(); ++ ctx.expect().returning(|| 1); ++ let expected = 1; ++ assert_eq!(expected, MockThing::one()) ++ } ++ ++ #[test] ++ fn test_2() { ++ let _m = MTX.lock(); ++ ++ let ctx = MockThing::one_context(); ++ ctx.expect().returning(|| 2); ++ let expected = 2; ++ assert_eq!(expected, MockThing::one()) ++ } ++} +diff --git a/tests/anyhow.rs b/tests/anyhow.rs +new file mode 100644 +index 0000000..f4f0fd4 +--- /dev/null ++++ b/tests/anyhow.rs +@@ -0,0 +1,86 @@ ++// vim: tw=80 ++//! Mockall should be compatible with crates like Anyhow that redefine `Ok`. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++// Define Error, Result, and Ok similarly to how anyhow defines them ++pub struct Error(); ++impl Error { ++ pub fn new(_e: E) -> Self { ++ Self() ++ } ++} ++#[allow(non_snake_case)] ++pub fn Ok(t: T) -> Result { ++ Result::Ok(t) ++} ++pub type Result = std::result::Result; ++ ++#[automock] ++pub trait Foo { ++ fn foo(&self) -> Result<(), Error>; ++ fn reffoo(&self) -> &Result<(), Error>; ++ fn refmutfoo(&mut self) -> &mut Result<(), Error>; ++ fn staticfoo() -> Result<(), Error>; ++} ++ ++mod static_method { ++ use super::*; ++ ++ #[test] ++ fn ok() { ++ let mut foo = MockFoo::new(); ++ foo.expect_foo() ++ .returning(|| Ok(())); ++ assert!(foo.foo().is_ok()); ++ } ++ ++ #[test] ++ fn err() { ++ let mut foo = MockFoo::new(); ++ foo.expect_foo() ++ .returning(|| Err(Error::new(std::io::Error::last_os_error()))); ++ assert!(foo.foo().is_err()); ++ } ++} ++ ++mod ref_method { ++ use super::*; ++ ++ #[test] ++ fn ok() { ++ let mut foo = MockFoo::new(); ++ foo.expect_reffoo() ++ .return_const(Ok(())); ++ assert!(foo.reffoo().is_ok()); ++ } ++ ++ #[test] ++ fn err() { ++ let mut foo = MockFoo::new(); ++ foo.expect_reffoo() ++ .return_const(Err(Error::new(std::io::Error::last_os_error()))); ++ assert!(foo.reffoo().is_err()); ++ } ++} ++ ++mod refmut_method { ++ use super::*; ++ ++ #[test] ++ fn ok() { ++ let mut foo = MockFoo::new(); ++ foo.expect_refmutfoo() ++ .return_var(Ok(())); ++ assert!(foo.refmutfoo().is_ok()); ++ } ++ ++ #[test] ++ fn err() { ++ let mut foo = MockFoo::new(); ++ foo.expect_refmutfoo() ++ .return_var(Err(Error::new(std::io::Error::last_os_error()))); ++ assert!(foo.refmutfoo().is_err()); ++ } ++} +diff --git a/tests/automock_associated_const.rs b/tests/automock_associated_const.rs +new file mode 100644 +index 0000000..b7c14cf +--- /dev/null ++++ b/tests/automock_associated_const.rs +@@ -0,0 +1,56 @@ ++// vim: tw=80 ++//! A trait with an associated constant ++//! ++//! It's not possible to automock the trait, like: ++//! ``` ++//! #[automock] ++//! trait Foo { ++//! const X: i32; ++//! } ++//! ``` ++//! because there's no way to set the value of X on MockFoo. ++//! ++//! But it _is_ possible to automock the trait implementation, like this: ++//! ``` ++//! struct Bar {} ++//! #[automock] ++//! impl Foo for Bar { ++//! const X: i32; ++//! } ++//! ``` ++//! ++//! https://github.com/asomers/mockall/issues/97 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Foo { ++ const X: i32; ++ ++ fn x_plus_one(&self) -> i32 { ++ Self::X + 1 ++ } ++} ++ ++pub struct Bar {} ++ ++#[automock] ++impl Foo for Bar { ++ const X: i32 = 42; ++} ++ ++pub struct Baz {} ++#[automock] ++impl Baz { ++ pub const Y: i32 = 69; ++} ++ ++#[test] ++fn default_method() { ++ assert_eq!(MockBar::new().x_plus_one(), 43); ++} ++ ++#[test] ++fn on_a_struct() { ++ assert_eq!(MockBaz::Y, 69); ++} +diff --git a/tests/automock_associated_type_constructor.rs b/tests/automock_associated_type_constructor.rs +new file mode 100644 +index 0000000..c9a5a1a +--- /dev/null ++++ b/tests/automock_associated_type_constructor.rs +@@ -0,0 +1,36 @@ ++// vim: tw=80 ++//! A constructor that returns Self as an associated type of some other trait. ++//! This is very useful when working with Futures. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub trait MyIterator { ++ type Item; ++} ++ ++pub struct Foo{} ++ ++#[automock] ++impl Foo { ++ pub fn open() -> impl MyIterator { ++ struct Bar {} ++ impl MyIterator for Bar { ++ type Item=Foo; ++ } ++ Bar{} ++ } ++} ++ ++#[test] ++fn returning() { ++ let ctx = MockFoo::open_context(); ++ ctx.expect().returning(|| { ++ struct Baz {} ++ impl MyIterator for Baz { ++ type Item = MockFoo; ++ } ++ Box::new(Baz{}) ++ }); ++ let _a = MockFoo::open(); ++} +diff --git a/tests/automock_associated_types.rs b/tests/automock_associated_types.rs +new file mode 100644 +index 0000000..82ffa78 +--- /dev/null ++++ b/tests/automock_associated_types.rs +@@ -0,0 +1,19 @@ ++// vim: tw=80 ++//! automatic-style mocking with associated types ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock(type T=u32;)] ++trait A { ++ type T: Clone; ++ fn foo(&self, x: Self::T) -> Self::T; ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockA::new(); ++ mock.expect_foo() ++ .returning(|x| x); ++ assert_eq!(4, mock.foo(4)); ++} +diff --git a/tests/automock_associated_types_with_qself.rs b/tests/automock_associated_types_with_qself.rs +new file mode 100644 +index 0000000..937e5b4 +--- /dev/null ++++ b/tests/automock_associated_types_with_qself.rs +@@ -0,0 +1,23 @@ ++// vim: tw=80 ++//! automatic-style mocking with associated types, with QSelf ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait SomeTrait{} ++struct Foo {} ++impl SomeTrait for Foo {} ++ ++#[automock(type T=u32;)] ++trait A { ++ type T: Clone; ++ fn baz(&self) -> Box::T>>; ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockA::new(); ++ mock.expect_baz() ++ .returning(|| Box::new(Foo{})); ++ mock.baz(); ++} +diff --git a/tests/automock_async_trait.rs b/tests/automock_async_trait.rs +new file mode 100644 +index 0000000..4e642b5 +--- /dev/null ++++ b/tests/automock_async_trait.rs +@@ -0,0 +1,31 @@ ++// vim: tw=80 ++//! An async trait, for use with Futures ++#![deny(warnings)] ++ ++use async_trait::async_trait; ++use futures::executor::block_on; ++use mockall::*; ++ ++#[automock] ++#[async_trait] ++pub trait Foo { ++ async fn foo(&self) -> u32; ++ async fn bar() -> u32; ++} ++ ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .return_const(42u32); ++ assert_eq!(block_on(mock.foo()), 42); ++} ++ ++#[test] ++fn static_method() { ++ let ctx = MockFoo::bar_context(); ++ ctx.expect() ++ .return_const(42u32); ++ assert_eq!(block_on(MockFoo::bar()), 42); ++} +diff --git a/tests/automock_attrs.rs b/tests/automock_attrs.rs +new file mode 100644 +index 0000000..bbae260 +--- /dev/null ++++ b/tests/automock_attrs.rs +@@ -0,0 +1,57 @@ ++// vim: tw=80 ++//! Attributes are applied to the mock object, too. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++pub mod m { ++ #[cfg(target_os = "multics")] ++ pub fn bloob(x: DoesNotExist) -> i64 {unimplemented!()} ++ #[cfg(not(target_os = "multics"))] ++ pub fn blarg(_x: i32) -> i64 {unimplemented!()} ++} ++ ++#[test] ++fn returning() { ++ let ctx = mock_m::blarg_context(); ++ ctx.expect() ++ .returning(|x| i64::from(x) + 1); ++ assert_eq!(5, mock_m::blarg(4)); ++} ++ ++pub struct A{} ++#[automock] ++impl A { ++ // Neither A::foo nor MockA::foo should be defined ++ #[cfg(target_os = "multics")] pub fn foo(&self, x: DoesNotExist) {} ++ // Both A::bar and MockA::bar should be defined ++ #[cfg(not(target_os = "multics"))] pub fn bar(&self, _x: i32) -> i32 {0} ++} ++ ++#[automock] ++pub mod ffi { ++ extern "C" { ++ // mock_ffi::baz should not be defined ++ #[cfg(target_os = "multics")] ++ pub fn baz(x: DoesNotExist) -> i64; ++ // mock_ffi::bean should be defined ++ #[cfg(not(target_os = "multics"))] ++ pub fn bean(x: u32) -> i64; ++ } ++} ++ ++#[test] ++fn method() { ++ let mut mock = MockA::new(); ++ mock.expect_bar() ++ .returning(|x| x); ++ assert_eq!(4, mock.bar(4)); ++} ++ ++#[test] ++fn foreign() { ++ let ctx = mock_ffi::bean_context(); ++ ctx.expect().returning(i64::from); ++ assert_eq!(42, unsafe{mock_ffi::bean(42)}); ++} +diff --git a/tests/automock_boxed_constructor.rs b/tests/automock_boxed_constructor.rs +new file mode 100644 +index 0000000..f0d13c9 +--- /dev/null ++++ b/tests/automock_boxed_constructor.rs +@@ -0,0 +1,17 @@ ++// vim: tw=80 ++//! A trait with a constructor method that returns Box ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++pub trait A { ++ fn new() -> Box; ++} ++ ++#[test] ++fn returning() { ++ let ctx = MockA::new_context(); ++ ctx.expect().returning(Box::default); ++ let _a: Box = ::new(); ++} +diff --git a/tests/automock_concretize.rs b/tests/automock_concretize.rs +new file mode 100644 +index 0000000..f169a20 +--- /dev/null ++++ b/tests/automock_concretize.rs +@@ -0,0 +1,50 @@ ++// vim: tw=80 ++//! #[concretize] works with #[automock], too. ++#![deny(warnings)] ++ ++use mockall::*; ++use std::path::{Path, PathBuf}; ++ ++#[automock] ++trait Foo { ++ #[concretize] ++ fn foo>(&self, x: P); ++} ++ ++#[automock] ++pub mod mymod { ++ #[mockall::concretize] ++ pub fn bang>(_x: P) { unimplemented!() } ++} ++ ++mod generic_arg { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_foo() ++ .withf(|p| p.as_ref() == Path::new("/tmp")) ++ .times(3) ++ .return_const(()); ++ foo.foo(Path::new("/tmp")); ++ foo.foo(PathBuf::from(Path::new("/tmp"))); ++ foo.foo("/tmp"); ++ } ++} ++ ++mod module { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let ctx = mock_mymod::bang_context(); ++ ctx.expect() ++ .withf(|p| p.as_ref() == Path::new("/tmp")) ++ .times(3) ++ .return_const(()); ++ mock_mymod::bang(Path::new("/tmp")); ++ mock_mymod::bang(PathBuf::from(Path::new("/tmp"))); ++ mock_mymod::bang("/tmp"); ++ } ++} +diff --git a/tests/automock_constructor_impl_trait.rs b/tests/automock_constructor_impl_trait.rs +new file mode 100644 +index 0000000..7384e11 +--- /dev/null ++++ b/tests/automock_constructor_impl_trait.rs +@@ -0,0 +1,30 @@ ++// vim: tw=80 ++//! A trait with a constructor method that returns impl Trait ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub trait Foo {} ++ ++pub struct A{} ++ ++struct Bar {} ++impl Foo for Bar {} ++ ++#[automock] ++impl A { ++ pub fn build() -> impl Foo { ++ Bar{} ++ } ++} ++ ++#[test] ++fn returning() { ++ let ctx = MockA::build_context(); ++ ctx.expect().returning(|| { ++ struct Baz {} ++ impl Foo for Baz {} ++ Box::new(Baz{}) ++ }); ++ let _a = MockA::build(); ++} +diff --git a/tests/automock_constructor_in_generic_trait.rs b/tests/automock_constructor_in_generic_trait.rs +new file mode 100644 +index 0000000..550fcb3 +--- /dev/null ++++ b/tests/automock_constructor_in_generic_trait.rs +@@ -0,0 +1,21 @@ ++// vim: tw=80 ++//! A generic trait with a non-generic constructor method. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait Foo { ++ fn new(t: T) -> Self; ++} ++ ++#[test] ++fn return_once() { ++ let mock = MockFoo::::default(); ++ ++ let ctx = MockFoo::::new_context(); ++ ctx.expect() ++ .return_once(move |_| mock); ++ ++ let _mock = MockFoo::new(5u32); ++} +diff --git a/tests/automock_constructor_in_struct.rs b/tests/automock_constructor_in_struct.rs +new file mode 100644 +index 0000000..1c3a895 +--- /dev/null ++++ b/tests/automock_constructor_in_struct.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++//! A struct with a constructor method ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct A {} ++ ++#[automock] ++#[allow(clippy::new_without_default)] ++impl A { ++ pub fn new() -> Self { ++ unimplemented!() ++ } ++} ++ ++#[test] ++fn returning() { ++ let ctx = MockA::new_context(); ++ ctx.expect().returning(MockA::default); ++ let _a: MockA = MockA::new(); ++} +diff --git a/tests/automock_constructor_in_trait.rs b/tests/automock_constructor_in_trait.rs +new file mode 100644 +index 0000000..1bd0189 +--- /dev/null ++++ b/tests/automock_constructor_in_trait.rs +@@ -0,0 +1,17 @@ ++// vim: tw=80 ++//! A trait with a constructor method ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++pub trait A { ++ fn new() -> Self; ++} ++ ++#[test] ++fn returning() { ++ let ctx = MockA::new_context(); ++ ctx.expect().returning(MockA::default); ++ let _a: MockA = ::new(); ++} +diff --git a/tests/automock_constructor_in_trait_with_args.rs b/tests/automock_constructor_in_trait_with_args.rs +new file mode 100644 +index 0000000..f7373ba +--- /dev/null ++++ b/tests/automock_constructor_in_trait_with_args.rs +@@ -0,0 +1,23 @@ ++// vim: tw=80 ++//! A struct with a constructor method named "new" that has arguments. ++//! mockall should mock the provided method, and not autogenerate a 0-argument ++//! "new" method. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait Foo { ++ fn new(x: u32) -> Self; ++} ++ ++#[test] ++fn return_once() { ++ let mock = MockFoo::default(); ++ let ctx = MockFoo::new_context(); ++ ++ ctx.expect() ++ .return_once(|_| mock); ++ ++ let _mock = MockFoo::new(5); ++} +diff --git a/tests/automock_constructor_with_args.rs b/tests/automock_constructor_with_args.rs +new file mode 100644 +index 0000000..5a6f563 +--- /dev/null ++++ b/tests/automock_constructor_with_args.rs +@@ -0,0 +1,25 @@ ++// vim: tw=80 ++//! A struct with a constructor method named "new" that has arguments. ++//! mockall should mock the provided method, and not autogenerate a 0-argument ++//! "new" method. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct Foo{} ++ ++#[automock] ++impl Foo { ++ pub fn new(_x: u32) -> Self {unimplemented!()} ++} ++ ++#[test] ++fn return_once() { ++ let mock = MockFoo::default(); ++ let ctx = MockFoo::new_context(); ++ ++ ctx.expect() ++ .return_once(|_| mock); ++ ++ let _mock = MockFoo::new(5); ++} +diff --git a/tests/automock_consume_arguments.rs b/tests/automock_consume_arguments.rs +new file mode 100644 +index 0000000..eb47fe8 +--- /dev/null ++++ b/tests/automock_consume_arguments.rs +@@ -0,0 +1,19 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++struct NonCopy{} ++ ++#[automock] ++trait T { ++ fn foo(&self, x: NonCopy); ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockT::new(); ++ mock.expect_foo() ++ .returning(|_x: NonCopy| ()); ++ mock.foo(NonCopy{}); ++} +diff --git a/tests/automock_custom_result.rs b/tests/automock_custom_result.rs +new file mode 100644 +index 0000000..89f7591 +--- /dev/null ++++ b/tests/automock_custom_result.rs +@@ -0,0 +1,42 @@ ++// vim: tw=80 ++//! It should be possible to use a custom Result type in the signature of a ++//! mocked method. Regression test for ++//! https://github.com/asomers/mockall/issues/73 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub type Result = std::result::Result; ++ ++pub struct MyStruct {} ++ ++#[automock] ++impl MyStruct { ++ pub fn ret_static(&self) -> Result { unimplemented!() } ++ pub fn ret_ref(&self) -> &Result { unimplemented!() } ++ pub fn ret_refmut(&mut self) -> &mut Result { unimplemented!() } ++} ++ ++#[test] ++fn ret_ref() { ++ let mut s = MockMyStruct::new(); ++ s.expect_ret_ref() ++ .return_const(Ok(42)); ++ assert_eq!(Ok(42), *s.ret_ref()); ++} ++ ++#[test] ++fn ret_ref_mut() { ++ let mut s = MockMyStruct::new(); ++ s.expect_ret_refmut() ++ .return_var(Ok(42)); ++ assert_eq!(Ok(42), *s.ret_refmut()); ++} ++ ++#[test] ++fn ret_static() { ++ let mut s = MockMyStruct::new(); ++ s.expect_ret_static() ++ .return_const(Ok(42)); ++ assert_eq!(Ok(42), s.ret_static()); ++} +diff --git a/tests/automock_debug.rs b/tests/automock_debug.rs +new file mode 100644 +index 0000000..6341c75 +--- /dev/null ++++ b/tests/automock_debug.rs +@@ -0,0 +1,35 @@ ++// vim: tw=80 ++//! A mocked struct should implement Debug ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++pub trait Foo {} ++ ++pub trait Bar {} ++pub struct Baz {} ++#[automock] ++impl Bar for Baz{} ++ ++pub struct Bean {} ++#[automock] ++impl Bean{} ++ ++#[test] ++fn automock_trait() { ++ let foo = MockFoo::new(); ++ assert_eq!("MockFoo", format!("{foo:?}")); ++} ++ ++#[test] ++fn automock_struct_impl() { ++ let bean = MockBean::new(); ++ assert_eq!("MockBean", format!("{bean:?}")); ++} ++ ++#[test] ++fn automock_trait_impl() { ++ let baz = MockBaz::new(); ++ assert_eq!("MockBaz", format!("{baz:?}")); ++} +diff --git a/tests/automock_deref.rs b/tests/automock_deref.rs +new file mode 100644 +index 0000000..61c55b3 +--- /dev/null ++++ b/tests/automock_deref.rs +@@ -0,0 +1,74 @@ ++// vim: tw=80 ++//! A method that returns a type which is a common target for std::ops::Deref ++#![deny(warnings)] ++ ++use mockall::*; ++use std::{ ++ ffi::{CStr, CString, OsStr, OsString}, ++ path::{Path, PathBuf}, ++}; ++ ++#[automock] ++trait Foo { ++ fn name(&self) -> &CStr; ++ fn alias(&self) -> &str; ++ fn desc(&self) -> &OsStr; ++ fn path(&self) -> &Path; ++ fn text(&self) -> &'static str; ++ fn slice(&self) -> &[i32]; ++} ++ ++mod return_const { ++ use super::*; ++ ++ #[test] ++ fn cstr() { ++ let mut mock = MockFoo::new(); ++ let name = CString::new("abcd").unwrap(); ++ mock.expect_name().return_const(name.clone()); ++ assert_eq!(name.as_c_str(), mock.name()); ++ } ++ ++ #[test] ++ fn osstr() { ++ let mut mock = MockFoo::new(); ++ let desc = OsString::from("abcd"); ++ mock.expect_desc().return_const(desc.clone()); ++ assert_eq!(desc.as_os_str(), mock.desc()); ++ } ++ ++ #[test] ++ fn path() { ++ let mut mock = MockFoo::new(); ++ let mut pb = PathBuf::new(); ++ pb.push("foo"); ++ pb.push("bar"); ++ pb.push("baz"); ++ mock.expect_path().return_const(pb.clone()); ++ assert_eq!(pb.as_path(), mock.path()); ++ } ++ ++ #[test] ++ fn str() { ++ let mut mock = MockFoo::new(); ++ mock.expect_alias().return_const("abcd".to_owned()); ++ assert_eq!("abcd", mock.alias()); ++ } ++ ++ #[allow(clippy::redundant_static_lifetimes)] ++ #[test] ++ fn static_str() { ++ const TEXT: &'static str = "abcd"; ++ let mut mock = MockFoo::new(); ++ mock.expect_text().return_const(TEXT); ++ assert_eq!("abcd", mock.text()); ++ } ++ ++ #[test] ++ fn slice() { ++ let r = vec![1, 2, 3]; ++ let mut mock = MockFoo::new(); ++ mock.expect_slice().return_const(r); ++ assert_eq!(&[1, 2, 3], mock.slice()); ++ } ++} +diff --git a/tests/automock_extern_std.rs b/tests/automock_extern_std.rs +new file mode 100644 +index 0000000..3b67c68 +--- /dev/null ++++ b/tests/automock_extern_std.rs +@@ -0,0 +1,19 @@ ++// vim: tw=80 ++//! automocking a trait when std is only an extern crate (eg., as a testing ++//! support mod for a no_std library). This setup requires some extra "use"s ++//! to make, eg., Box, available. ++ ++#![no_std] ++extern crate std; ++ ++use mockall::*; ++ ++#[automock] ++pub trait SimpleTrait { ++ fn foo(&self, x: u32) -> u32; ++} ++ ++#[test] ++fn creating() { ++ let _ = MockSimpleTrait::new(); ++} +diff --git a/tests/automock_foreign_c.rs b/tests/automock_foreign_c.rs +new file mode 100644 +index 0000000..07eb47d +--- /dev/null ++++ b/tests/automock_foreign_c.rs +@@ -0,0 +1,52 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++use std::sync::Mutex; ++ ++#[automock] ++mod ffi { ++ extern "C" { ++ pub(super) fn foo(x: u32) -> i64; ++ } ++} ++ ++static FOO_MTX: Mutex<()> = Mutex::new(()); ++ ++// Ensure we can still use the original mocked function ++pub fn normal_usage() { ++ let _m = FOO_MTX.lock(); ++ unsafe { ++ ffi::foo(42); ++ } ++} ++ ++#[test] ++#[should_panic(expected = "mock_ffi::foo(5): No matching expectation found")] ++fn with_no_matches() { ++ let _m = FOO_MTX.lock(); ++ let ctx = mock_ffi::foo_context(); ++ ctx.expect() ++ .with(predicate::eq(4)) ++ .returning(i64::from); ++ unsafe{ mock_ffi::foo(5) }; ++} ++ ++#[test] ++fn returning() { ++ let _m = FOO_MTX.lock(); ++ let ctx = mock_ffi::foo_context(); ++ ctx.expect().returning(i64::from); ++ assert_eq!(42, unsafe{mock_ffi::foo(42)}); ++} ++ ++/// Ensure that the mock function can be called from C by casting it to a C ++/// function pointer. ++#[test] ++fn c_abi() { ++ let _m = FOO_MTX.lock(); ++ let ctx = mock_ffi::foo_context(); ++ ctx.expect().returning(i64::from); ++ let p: unsafe extern "C" fn(u32) -> i64 = mock_ffi::foo; ++ assert_eq!(42, unsafe{p(42)}); ++} +diff --git a/tests/automock_foreign_c_variadic.rs b/tests/automock_foreign_c_variadic.rs +new file mode 100644 +index 0000000..71a62ed +--- /dev/null ++++ b/tests/automock_foreign_c_variadic.rs +@@ -0,0 +1,23 @@ ++// vim: tw=80 ++#![cfg_attr(feature = "nightly", feature(c_variadic))] ++#![deny(warnings)] ++ ++#[cfg(feature = "nightly")] ++use mockall::*; ++ ++#[automock] ++#[cfg(feature = "nightly")] ++pub mod ffi { ++ extern "C" { ++ pub fn foo(x: i32, y: i32, ...) -> i32; ++ } ++} ++ ++#[test] ++#[cfg(feature = "nightly")] ++#[cfg_attr(miri, ignore)] ++fn mocked_c_variadic() { ++ let ctx = mock_ffi::foo_context(); ++ ctx.expect().returning(|x, y| x * y); ++ assert_eq!(6, unsafe{mock_ffi::foo(2, 3, 1, 4, 1)}); ++} +diff --git a/tests/automock_foreign_rust.rs b/tests/automock_foreign_rust.rs +new file mode 100644 +index 0000000..ccc7ee5 +--- /dev/null ++++ b/tests/automock_foreign_rust.rs +@@ -0,0 +1,18 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++pub mod ffi { ++ extern "Rust" { ++ pub fn foo(_x: u32) -> i64; ++ } ++} ++ ++#[test] ++fn returning() { ++ let ctx = mock_ffi::foo_context(); ++ ctx.expect().returning(i64::from); ++ assert_eq!(42, unsafe{mock_ffi::foo(42)}); ++} +diff --git a/tests/automock_gat.rs b/tests/automock_gat.rs +new file mode 100644 +index 0000000..4fd4938 +--- /dev/null ++++ b/tests/automock_gat.rs +@@ -0,0 +1,35 @@ ++#! vim: tw=80 ++//! automock a trait with Generic Associated Types ++#![deny(warnings)] ++ ++use cfg_if::cfg_if; ++ ++cfg_if! { ++ if #[cfg(feature = "nightly")] { ++ use mockall::*; ++ ++ // The lifetime must have the same name as in the next() method. ++ #[automock(type Item=&'a u32;)] ++ trait LendingIterator { ++ type Item<'a> where Self: 'a; ++ ++ // Clippy doesn't know that Mockall will need the lifetime when it ++ // expands the macro. ++ #[allow(clippy::needless_lifetimes)] ++ fn next<'a>(&'a mut self) -> Option>; ++ } ++ ++ // It isn't possible to safely set an expectation for a non-'static ++ // return value (because the mock object doesn't have any lifetime ++ // parameters itself), but unsafely setting such an expectation is a ++ // common use case. ++ #[test] ++ fn return_const() { ++ let mut mock = MockLendingIterator::new(); ++ let x = 42u32; ++ let xstatic: &'static u32 = unsafe{ std::mem::transmute(&x) }; ++ mock.expect_next().return_const(Some(xstatic)); ++ assert_eq!(42u32, *mock.next().unwrap()); ++ } ++ } ++} +diff --git a/tests/automock_generic_arguments.rs b/tests/automock_generic_arguments.rs +new file mode 100644 +index 0000000..5b8a9e6 +--- /dev/null ++++ b/tests/automock_generic_arguments.rs +@@ -0,0 +1,21 @@ ++// vim: tw=80 ++//! generic methods with generic arguments ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait A { ++ fn foo(&self, t: T); ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockA::new(); ++ mock.expect_foo::() ++ .returning(|_x: u32| ()); ++ mock.expect_foo::() ++ .returning(|_x: i16| ()); ++ mock.foo(5u32); ++ mock.foo(-1i16); ++} +diff --git a/tests/automock_generic_arguments_returning_references.rs b/tests/automock_generic_arguments_returning_references.rs +new file mode 100644 +index 0000000..de1f5c1 +--- /dev/null ++++ b/tests/automock_generic_arguments_returning_references.rs +@@ -0,0 +1,17 @@ ++// vim: tw=80 ++//! generic methods with generic arguments returning immutable references ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait A { ++ fn foo(&self, t: T) -> &u32; ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockA::new(); ++ mock.expect_foo::().return_const(5); ++ assert_eq!(5, *mock.foo(42u32)); ++} +diff --git a/tests/automock_generic_arguments_with_where_clause.rs b/tests/automock_generic_arguments_with_where_clause.rs +new file mode 100644 +index 0000000..2d619d9 +--- /dev/null ++++ b/tests/automock_generic_arguments_with_where_clause.rs +@@ -0,0 +1,21 @@ ++// vim: tw=80 ++//! A method with generic arguments bounded by a where clause ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait A { ++ fn foo(&self, t: T) where T: Clone + 'static; ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockA::new(); ++ mock.expect_foo::() ++ .returning(|_x: u32| ()); ++ mock.expect_foo::() ++ .returning(|_x: i16| ()); ++ mock.foo(5u32); ++ mock.foo(-1i16); ++} +diff --git a/tests/automock_generic_constructor.rs b/tests/automock_generic_constructor.rs +new file mode 100644 +index 0000000..d9f7286 +--- /dev/null ++++ b/tests/automock_generic_constructor.rs +@@ -0,0 +1,19 @@ ++// vim: tw=80 ++//! A non-generic struct can have a generic constructor method ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait Foo { ++ fn build(t: T) -> Self; ++} ++ ++#[test] ++fn returning_once() { ++ let ctx = MockFoo::build_context(); ++ ctx.expect::() ++ .return_once(|_| MockFoo::default()); ++ ++ let _mock: MockFoo = MockFoo::build::(-1); ++} +diff --git a/tests/automock_generic_future.rs b/tests/automock_generic_future.rs +new file mode 100644 +index 0000000..de26d92 +--- /dev/null ++++ b/tests/automock_generic_future.rs +@@ -0,0 +1,36 @@ ++// vim: tw=80 ++//! A generic mock object that implements Future ++//! ++//! This is tricky because the Context object has a lifetime parameter, yet the ++//! poll method must not be treated as a generic method. ++#![deny(warnings)] ++ ++use futures::executor::block_on; ++use mockall::*; ++use std::{ ++ future::Future, ++ pin::Pin, ++ task::{Context, Poll}, ++}; ++ ++struct Foo(T); ++ ++#[automock] ++impl Future for Foo { ++ type Output = (); ++ ++ fn poll<'a>(self: Pin<&mut Self>, _cx: &mut Context<'a>) ++ -> Poll ++ { ++ unimplemented!() ++ } ++} ++ ++#[test] ++fn ready() { ++ let mut mock = MockFoo::::new(); ++ mock.expect_poll() ++ .once() ++ .return_const(Poll::Ready(())); ++ block_on(mock); ++} +diff --git a/tests/automock_generic_future_with_where_clause.rs b/tests/automock_generic_future_with_where_clause.rs +new file mode 100644 +index 0000000..45e80d8 +--- /dev/null ++++ b/tests/automock_generic_future_with_where_clause.rs +@@ -0,0 +1,36 @@ ++// vim: tw=80 ++//! A generic mock object with a method that has only lifetime generic ++//! parameters, and a where clause that bounds a generic type not used by the ++//! method. ++//! ++//! Mockall must not emit the where clause for the method's Expectation. ++#![deny(warnings)] ++#![allow(clippy::needless_lifetimes)] ++ ++use mockall::*; ++ ++struct Foo((T, V)); ++trait MyTrait { ++ type Item; ++ ++ fn myfunc(&self, cx: &NonStatic) -> Self::Item; ++} ++#[allow(dead_code)] ++pub struct NonStatic<'ns>(&'ns i32); ++ ++#[automock] ++impl MyTrait for Foo where T: Clone { ++ type Item = V; ++ ++ fn myfunc<'a>(&self, _cx: &NonStatic<'a>) -> V { unimplemented!() } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::::new(); ++ let x = 5i32; ++ let ns = NonStatic(&x); ++ mock.expect_myfunc() ++ .return_const(42u32); ++ assert_eq!(42u32, mock.myfunc(&ns)); ++} +diff --git a/tests/automock_generic_method_with_bounds.rs b/tests/automock_generic_method_with_bounds.rs +new file mode 100644 +index 0000000..6bc68b1 +--- /dev/null ++++ b/tests/automock_generic_method_with_bounds.rs +@@ -0,0 +1,23 @@ ++// vim: tw=80 ++//! generic methods with bounds on their generic parameters ++#![deny(warnings)] ++ ++use mockall::*; ++use std::fmt::Debug; ++ ++struct X(T); ++ ++#[automock] ++trait Foo { ++ fn foo(&self, x: X); ++} ++ ++#[test] ++fn withf() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::() ++ .withf(|x| x.0 == 42u32) ++ .return_const(()); ++ ++ mock.foo(X(42u32)); ++} +diff --git a/tests/automock_generic_method_with_lifetime_parameter.rs b/tests/automock_generic_method_with_lifetime_parameter.rs +new file mode 100644 +index 0000000..0c1b65d +--- /dev/null ++++ b/tests/automock_generic_method_with_lifetime_parameter.rs +@@ -0,0 +1,48 @@ ++// vim: tw=80 ++//! A generic method whose only generic parameter is a lifetime parameter is, ++//! from Mockall's perspective, pretty much the same as a non-generic method. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[derive(Debug, Eq)] ++struct X<'a>(&'a u32); ++ ++impl<'a> PartialEq for X<'a> { ++ fn eq(&self, other: &X<'a>) -> bool { ++ self.0 == other.0 ++ } ++} ++ ++#[automock] ++trait Foo { ++ fn foo<'a>(&self, x: &'a X<'a>) -> u32; ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .return_const(42u32); ++ let x = X(&5); ++ assert_eq!(42, mock.foo(&x)); ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|f| *f.0); ++ let x = X(&5); ++ assert_eq!(5, mock.foo(&x)); ++} ++ ++#[test] ++fn withf() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .withf(|f| *f.0 == 5) ++ .return_const(42u32); ++ let x = X(&5); ++ assert_eq!(42, mock.foo(&x)); ++} +diff --git a/tests/automock_generic_method_with_unknown_size_bounds.rs b/tests/automock_generic_method_with_unknown_size_bounds.rs +new file mode 100644 +index 0000000..4182b2e +--- /dev/null ++++ b/tests/automock_generic_method_with_unknown_size_bounds.rs +@@ -0,0 +1,34 @@ ++// vim: tw=80 ++//! generic methods with unknown size bounds on their generic parameters ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait Foo { ++ fn foo(&self, input: Box); ++} ++ ++trait Bar { ++ fn get(&self) -> u32; ++} ++ ++struct Foobar { ++ value: u32, ++} ++ ++impl Bar for Foobar { ++ fn get(&self) -> u32 { ++ self.value ++ } ++} ++ ++#[test] ++fn withf() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::() ++ .withf(|x| x.get() == 42) ++ .return_const(()); ++ ++ mock.foo::(Box::new(Foobar { value: 42 })); ++} +diff --git a/tests/automock_generic_method_without_generic_args_or_return.rs b/tests/automock_generic_method_without_generic_args_or_return.rs +new file mode 100644 +index 0000000..63b297b +--- /dev/null ++++ b/tests/automock_generic_method_without_generic_args_or_return.rs +@@ -0,0 +1,44 @@ ++// vim: tw=80 ++//! generic methods whose generic parameters appear in neither inputs nor return ++//! types should still be mockable, and it should be possible to set ++//! simultaneous expectations for different generic types on the same object. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct Foo{} ++ ++#[automock] ++impl Foo { ++ #[allow(clippy::extra_unused_type_parameters)] ++ pub fn foo(&self) -> i32 { ++ unimplemented!() ++ } ++ /// A static method ++ #[allow(clippy::extra_unused_type_parameters)] ++ pub fn bar() -> i32 { ++ unimplemented!() ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::() ++ .return_const(42); ++ mock.expect_foo::() ++ .return_const(69); ++ assert_eq!(42, mock.foo::()); ++ assert_eq!(69, mock.foo::()); ++} ++ ++#[test] ++fn static_method() { ++ let ctx = MockFoo::bar_context(); ++ ctx.expect::() ++ .return_const(42); ++ ctx.expect::() ++ .return_const(69); ++ assert_eq!(42, MockFoo::bar::()); ++ assert_eq!(69, MockFoo::bar::()); ++} +diff --git a/tests/automock_generic_return.rs b/tests/automock_generic_return.rs +new file mode 100644 +index 0000000..9ea8944 +--- /dev/null ++++ b/tests/automock_generic_return.rs +@@ -0,0 +1,21 @@ ++// vim: tw=80 ++//! generic methods with generic return values ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait A { ++ fn foo(&self, t: T) -> T; ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockA::new(); ++ mock.expect_foo::() ++ .returning(|_x: u32| 42u32); ++ mock.expect_foo::() ++ .returning(|_x: i16| 42i16); ++ assert_eq!(42u32, mock.foo(5u32)); ++ assert_eq!(42i16, mock.foo(-1i16)); ++} +diff --git a/tests/automock_generic_static_method.rs b/tests/automock_generic_static_method.rs +new file mode 100644 +index 0000000..3afc95e +--- /dev/null ++++ b/tests/automock_generic_static_method.rs +@@ -0,0 +1,33 @@ ++// vim: tw=80 ++//! generic static methods with generic arguments ++#![deny(warnings)] ++ ++use mockall::*; ++use std::sync::Mutex; ++ ++static A_MTX: Mutex<()> = Mutex::new(()); ++ ++#[automock] ++trait A { ++ fn bar(t: T) -> u32; ++} ++ ++#[test] ++fn returning() { ++ let _m = A_MTX.lock().unwrap(); ++ ++ let ctx = MockA::bar_context(); ++ ctx.expect::() ++ .returning(|_| 42); ++ assert_eq!(42, MockA::bar(-1i16)); ++} ++ ++#[test] ++fn return_const() { ++ let _m = A_MTX.lock().unwrap(); ++ ++ let ctx = MockA::bar_context(); ++ ctx.expect::() ++ .return_const(42u32); ++ assert_eq!(42, MockA::bar(-1i16)); ++} +diff --git a/tests/automock_generic_struct.rs b/tests/automock_generic_struct.rs +new file mode 100644 +index 0000000..2efaba3 +--- /dev/null ++++ b/tests/automock_generic_struct.rs +@@ -0,0 +1,24 @@ ++// vim: tw=80 ++//! generic structs ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct GenericStruct { ++ _t: T, ++ _v: V ++} ++#[automock] ++impl GenericStruct { ++ pub fn foo(&self, _x: u32) -> i64 { ++ 42 ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockGenericStruct::::new(); ++ mock.expect_foo() ++ .returning(|x| i64::from(x) + 1); ++ assert_eq!(5, mock.foo(4)); ++} +diff --git a/tests/automock_generic_struct_with_bounds.rs b/tests/automock_generic_struct_with_bounds.rs +new file mode 100644 +index 0000000..b7ba3b4 +--- /dev/null ++++ b/tests/automock_generic_struct_with_bounds.rs +@@ -0,0 +1,24 @@ ++// vim: tw=80 ++//! generic structs with bounds on their generic parameters ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct GenericStruct { ++ _t: T, ++ _v: V ++} ++#[automock] ++impl GenericStruct { ++ pub fn foo(&self, _x: u32) -> i64 { ++ 42 ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockGenericStruct::::new(); ++ mock.expect_foo() ++ .returning(|x| i64::from(x) + 1); ++ assert_eq!(5, mock.foo(4)); ++} +diff --git a/tests/automock_generic_struct_with_static_method.rs b/tests/automock_generic_struct_with_static_method.rs +new file mode 100644 +index 0000000..1410113 +--- /dev/null ++++ b/tests/automock_generic_struct_with_static_method.rs +@@ -0,0 +1,20 @@ ++// vim: tw=80 ++//! static non-generic methods of generic structs shouldn't require any special ++//! treatment when mocking. Prior to version 0.3.0, the struct's generic ++//! parameters had to be duplicated as generic parameters of the method. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait Foo { ++ fn foo(t: T); ++} ++ ++#[test] ++fn returning() { ++ let ctx = MockFoo::::foo_context(); ++ ctx.expect() ++ .returning(|_| ()); ++ MockFoo::foo(42u32); ++} +diff --git a/tests/automock_generic_struct_with_where_clause.rs b/tests/automock_generic_struct_with_where_clause.rs +new file mode 100644 +index 0000000..f62996f +--- /dev/null ++++ b/tests/automock_generic_struct_with_where_clause.rs +@@ -0,0 +1,26 @@ ++// vim: tw=80 ++//! A struct with generic parameters bounded by a where clause ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct GenericStruct { ++ _t: T, ++} ++#[automock] ++impl GenericStruct ++ where T: Clone + Default ++{ ++ #[allow(clippy::redundant_clone)] ++ pub fn foo(&self, x: T) -> T { ++ x.clone() ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockGenericStruct::::default(); ++ mock.expect_foo() ++ .returning(|x| x); ++ assert_eq!(4, mock.foo(4u8)); ++} +diff --git a/tests/automock_generic_trait.rs b/tests/automock_generic_trait.rs +new file mode 100644 +index 0000000..499ef08 +--- /dev/null ++++ b/tests/automock_generic_trait.rs +@@ -0,0 +1,30 @@ ++// vim: tw=80 ++//! generic traits ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait A { ++ fn foo(&self, t: T); ++ fn bar(&self) -> T; ++} ++ ++#[test] ++fn generic_arguments() { ++ let mut mock = MockA::::new(); ++ mock.expect_foo() ++ .with(mockall::predicate::eq(16u32)) ++ .once() ++ .returning(|_| ()); ++ mock.foo(16u32); ++} ++ ++#[test] ++fn generic_return() { ++ let mut mock = MockA::::new(); ++ mock.expect_bar() ++ .returning(|| 42u32); ++ assert_eq!(42u32, mock.bar()); ++} ++ +diff --git a/tests/automock_generic_trait_with_bounds.rs b/tests/automock_generic_trait_with_bounds.rs +new file mode 100644 +index 0000000..a99e824 +--- /dev/null ++++ b/tests/automock_generic_trait_with_bounds.rs +@@ -0,0 +1,18 @@ ++// vim: tw=80 ++//! generic traits with bounds on the generic parameters ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait A { ++ fn foo(&self); ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockA::::new(); ++ mock.expect_foo() ++ .returning(|| ()); ++ mock.foo(); ++} +diff --git a/tests/automock_generic_trait_with_where_clause.rs b/tests/automock_generic_trait_with_where_clause.rs +new file mode 100644 +index 0000000..e12be15 +--- /dev/null ++++ b/tests/automock_generic_trait_with_where_clause.rs +@@ -0,0 +1,18 @@ ++// vim: tw=80 ++//! A trait with generic parameters bounded by a where clause ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait Foo where T: Clone + Copy { ++ fn foo(&self); ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::::default(); ++ mock.expect_foo() ++ .returning(|| ()); ++ mock.foo(); ++} +diff --git a/tests/automock_impl_future.rs b/tests/automock_impl_future.rs +new file mode 100644 +index 0000000..26086af +--- /dev/null ++++ b/tests/automock_impl_future.rs +@@ -0,0 +1,50 @@ ++// vim: tw=80 ++//! A trait with a constructor method that returns impl Future<...>. ++//! ++//! This needs special handling, because Box> is pretty useless. ++//! You need Pin>> instead. ++#![deny(warnings)] ++ ++use futures::{Future, FutureExt, Stream, StreamExt, future, stream}; ++use mockall::*; ++ ++pub struct Foo{} ++ ++#[automock] ++impl Foo { ++ pub fn foo(&self) -> impl Future ++ { ++ future::ready(42) ++ } ++ ++ pub fn bar(&self) -> impl Stream ++ { ++ stream::empty() ++ } ++} ++ ++#[test] ++fn returning_future() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|| { ++ Box::pin(future::ready(42)) ++ }); ++ mock.foo() ++ .now_or_never() ++ .unwrap(); ++} ++ ++#[test] ++fn returning_stream() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .returning(|| { ++ Box::pin(stream::iter(vec![42])) ++ }); ++ let all = mock.bar() ++ .collect::>() ++ .now_or_never() ++ .unwrap(); ++ assert_eq!(&all[..], &[42][..]); ++} +diff --git a/tests/automock_impl_generic_trait_for.rs b/tests/automock_impl_generic_trait_for.rs +new file mode 100644 +index 0000000..6bd218a +--- /dev/null ++++ b/tests/automock_impl_generic_trait_for.rs +@@ -0,0 +1,28 @@ ++// vim: tw=80 ++//! A generic struct that implements a generic trait ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Foo { ++ fn foo(&self, t: T) -> T; ++} ++ ++pub struct SomeStruct { ++ _t: std::marker::PhantomData ++} ++ ++#[automock] ++impl Foo for SomeStruct { ++ fn foo(&self, t: T) -> T { ++ t ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockSomeStruct::::new(); ++ mock.expect_foo() ++ .returning(|t| t); ++ assert_eq!(4, as Foo>::foo(&mock, 4)); ++} +diff --git a/tests/automock_impl_trait.rs b/tests/automock_impl_trait.rs +new file mode 100644 +index 0000000..eb14a13 +--- /dev/null ++++ b/tests/automock_impl_trait.rs +@@ -0,0 +1,20 @@ ++// vim: tw=80 ++//! A method that returns "impl Trait" ++#![deny(warnings)] ++ ++use mockall::*; ++use std::fmt::Debug; ++ ++pub struct Foo {} ++ ++#[automock] ++impl Foo { ++ pub fn foo(&self) -> impl Debug + Send { unimplemented!()} ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo().returning(|| Box::new(4)); ++ format!("{:?}", mock.foo()); ++} +diff --git a/tests/automock_impl_trait_for.rs b/tests/automock_impl_trait_for.rs +new file mode 100644 +index 0000000..6dc153a +--- /dev/null ++++ b/tests/automock_impl_trait_for.rs +@@ -0,0 +1,26 @@ ++// vim: tw=80 ++//! A struct that implements a trait ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub trait Foo { ++ fn foo(&self, x: u32) -> i64; ++} ++ ++pub struct SomeStruct {} ++ ++#[automock] ++impl Foo for SomeStruct { ++ fn foo(&self, _x: u32) -> i64 { ++ 42 ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockSomeStruct::new(); ++ mock.expect_foo() ++ .returning(|x| i64::from(x) + 1); ++ assert_eq!(5, ::foo(&mock, 4)); ++} +diff --git a/tests/automock_impl_trait_for_generic.rs b/tests/automock_impl_trait_for_generic.rs +new file mode 100644 +index 0000000..7d50ef4 +--- /dev/null ++++ b/tests/automock_impl_trait_for_generic.rs +@@ -0,0 +1,28 @@ ++// vim: tw=80 ++//! A generic struct that implements a trait ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Foo { ++ fn foo(&self, x: u32) -> i64; ++} ++ ++pub struct SomeStruct { ++ _t: std::marker::PhantomData ++} ++ ++#[automock] ++impl Foo for SomeStruct { ++ fn foo(&self, _x: u32) -> i64 { ++ 42 ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockSomeStruct::::new(); ++ mock.expect_foo() ++ .returning(|x| i64::from(x) + 1); ++ assert_eq!(5, mock.foo(4)); ++} +diff --git a/tests/automock_impl_trait_with_associated_types_for.rs b/tests/automock_impl_trait_with_associated_types_for.rs +new file mode 100644 +index 0000000..17bcca7 +--- /dev/null ++++ b/tests/automock_impl_trait_with_associated_types_for.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++//! A struct implements a trait with associated types ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct Foo {} ++#[automock] ++impl Iterator for Foo { ++ type Item = u32; ++ ++ fn next(&mut self) -> Option { ++ unimplemented!() ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_next().returning(|| None); ++ assert!(mock.next().is_none()); ++} +diff --git a/tests/automock_inline.rs b/tests/automock_inline.rs +new file mode 100644 +index 0000000..6ba2991 +--- /dev/null ++++ b/tests/automock_inline.rs +@@ -0,0 +1,52 @@ ++// vim: tw=80 ++//! Mockall should ignore and not emit attributes like "inline" that affect ++//! code generation. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct Foo {} ++ ++#[automock] ++impl Foo { ++ #[inline] ++ pub fn foo(&self) -> i32 {unimplemented!()} ++ #[inline] ++ pub fn bar() -> i32 {unimplemented!()} ++ #[cold] ++ pub fn baz(&self) -> i32 {unimplemented!()} ++ #[cold] ++ pub fn bean() -> i32 {unimplemented!()} ++} ++ ++#[test] ++fn inline_method() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .return_const(42i32); ++ assert_eq!(mock.foo(), 42); ++} ++ ++#[test] ++fn inline_static_method() { ++ let ctx = MockFoo::bar_context(); ++ ctx.expect() ++ .return_const(42i32); ++ assert_eq!(MockFoo::bar(), 42); ++} ++ ++#[test] ++fn cold_method() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .return_const(42i32); ++ assert_eq!(mock.baz(), 42); ++} ++ ++#[test] ++fn cold_static_method() { ++ let ctx = MockFoo::bean_context(); ++ ctx.expect() ++ .return_const(42i32); ++ assert_eq!(MockFoo::bean(), 42); ++} +diff --git a/tests/automock_instrument.rs b/tests/automock_instrument.rs +new file mode 100644 +index 0000000..4f210ff +--- /dev/null ++++ b/tests/automock_instrument.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++//! A trait that uses tracing::instrument should be automockable. The mock ++//! method won't be instrumented, though. ++#![deny(warnings)] ++ ++use mockall::*; ++use tracing::instrument; ++ ++#[derive(Debug)] ++pub struct Foo {} ++ ++#[automock] ++impl Foo { ++ #[instrument] ++ fn foo(&self) {} ++ #[instrument] ++ fn bar() {} ++ #[tracing::instrument] ++ fn fooz(&self) {} ++ #[tracing::instrument] ++ fn barz() {} ++} +diff --git a/tests/automock_many_args.rs b/tests/automock_many_args.rs +new file mode 100644 +index 0000000..8393130 +--- /dev/null ++++ b/tests/automock_many_args.rs +@@ -0,0 +1,81 @@ ++// vim: tw=80 ++//! mockall should be able to mock methods with at least 16 arguments ++#![allow(clippy::too_many_arguments)] // Good job, Clippy! ++#![allow(clippy::type_complexity)] ++#![deny(warnings)] ++ ++use mockall::{automock, predicate::*}; ++ ++#[automock] ++trait ManyArgs { ++ fn foo(&self, _a0: u8, _a1: u8, _a2: u8, _a3: u8, _a4: u8, _a5: u8, ++ _a6: u8, _a7: u8, _a8: u8, _a9: u8, _a10: u8, _a11: u8, ++ _a12: u8, _a13: u8, _a14: u8, _a15: u8); ++ fn bar(&self, _a0: u8, _a1: u8, _a2: u8, _a3: u8, _a4: u8, _a5: u8, ++ _a6: u8, _a7: u8, _a8: u8, _a9: u8, _a10: u8, _a11: u8, ++ _a12: u8, _a13: u8, _a14: u8, _a15: u8) -> &u32; ++ fn baz(&mut self, _a0: u8, _a1: u8, _a2: u8, _a3: u8, _a4: u8, _a5: u8, ++ _a6: u8, _a7: u8, _a8: u8, _a9: u8, _a10: u8, _a11: u8, ++ _a12: u8, _a13: u8, _a14: u8, _a15: u8) -> &mut u32; ++ fn bean(_a0: u8, _a1: u8, _a2: u8, _a3: u8, _a4: u8, _a5: u8, ++ _a6: u8, _a7: u8, _a8: u8, _a9: u8, _a10: u8, _a11: u8, ++ _a12: u8, _a13: u8, _a14: u8, _a15: u8); ++} ++ ++#[test] ++#[should_panic( ++ expected = "MockManyArgs::foo: Expectation(true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) called 0 time(s) which is fewer than expected 1" ++)] ++fn not_yet_satisfied() { ++ let mut mock = MockManyArgs::new(); ++ mock.expect_foo() ++ .with(always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), ) ++ .times(1) ++ .returning(|_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _| ()); ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockManyArgs::new(); ++ mock.expect_foo() ++ .returning(|_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _| ()); ++ mock.foo(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockManyArgs::new(); ++ mock.expect_bar() ++ .return_const(42); ++ mock.bar(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); ++} ++ ++#[test] ++fn return_var() { ++ let mut mock = MockManyArgs::new(); ++ mock.expect_baz() ++ .return_var(42); ++ mock.baz(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); ++} ++ ++#[test] ++fn static_method_returning() { ++ let ctx = MockManyArgs::bean_context(); ++ ctx.expect() ++ .returning(|_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _| ()); ++ MockManyArgs::bean(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); ++} ++ ++#[test] ++#[should_panic( ++ expected = "MockManyArgs::foo: Expectation(true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) called 2 times which is more than the expected 1" ++)] ++fn too_many() { ++ let mut mock = MockManyArgs::new(); ++ mock.expect_foo() ++ .with(always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), always(), ) ++ .times(1) ++ .returning(|_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _| ()); ++ mock.foo(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); ++ mock.foo(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); ++} +diff --git a/tests/automock_module.rs b/tests/automock_module.rs +new file mode 100644 +index 0000000..ddfe53e +--- /dev/null ++++ b/tests/automock_module.rs +@@ -0,0 +1,50 @@ ++// vim: tw=80 ++//! Mocking an entire module of functions ++#![deny(warnings)] ++ ++ ++pub mod m { ++ use std::sync::Mutex; ++ use mockall::*; ++ type T = u32; ++ ++ static BAR_MTX: Mutex<()> = Mutex::new(()); ++ ++ #[automock] ++ pub mod foo { ++ use super::T; ++ pub fn bar(_x: T) -> i64 {unimplemented!()} ++ // Module functions should be able to use impl Trait, too ++ pub fn baz() -> impl std::fmt::Debug + Send { unimplemented!()} ++ // Module functions can use mutable arguments ++ pub fn bean(mut _x: u32) { unimplemented!() } ++ } ++ ++ #[test] ++ #[should_panic(expected = "mock_foo::bar(5): No matching expectation found")] ++ fn with_no_matches() { ++ let _m = BAR_MTX.lock(); ++ let ctx = mock_foo::bar_context(); ++ ctx.expect() ++ .with(predicate::eq(4)) ++ .return_const(0); ++ mock_foo::bar(5); ++ } ++ ++ #[test] ++ fn returning() { ++ let _m = BAR_MTX.lock(); ++ let ctx = mock_foo::bar_context(); ++ ctx.expect() ++ .returning(|x| i64::from(x) + 1); ++ assert_eq!(5, mock_foo::bar(4)); ++ } ++ ++ #[test] ++ fn impl_trait() { ++ let ctx = mock_foo::baz_context(); ++ ctx.expect() ++ .returning(|| Box::new(4)); ++ format!("{:?}", mock_foo::baz()); ++ } ++} +diff --git a/tests/automock_module_nonpub.rs b/tests/automock_module_nonpub.rs +new file mode 100644 +index 0000000..d131197 +--- /dev/null ++++ b/tests/automock_module_nonpub.rs +@@ -0,0 +1,45 @@ ++// vim: tw=80 ++//! bare functions can use non-public types, as long as the object's visibility is compatible. ++#![deny(warnings)] ++#![allow(dead_code)] ++ ++mod outer { ++ struct SuperT(); ++ ++ mod inner { ++ use mockall::automock; ++ ++ pub(crate) struct PubCrateT(); ++ struct PrivT(); ++ ++ #[automock] ++ mod m { ++ use super::*; ++ ++ pub(crate) fn foo(_x: PubCrateT) -> PubCrateT { ++ unimplemented!() ++ } ++ pub(super) fn bar(_x: PrivT) -> PrivT { ++ unimplemented!() ++ } ++ pub(in super::super) fn baz(_x: super::super::SuperT) ++ -> super::super::SuperT ++ { ++ unimplemented!() ++ } ++ pub(in crate::outer) fn bang(_x: crate::outer::SuperT) ++ -> crate::outer::SuperT ++ { ++ unimplemented!() ++ } ++ } ++ ++ #[test] ++ fn returning() { ++ let ctx = mock_m::foo_context(); ++ ctx.expect() ++ .returning(|x| x); ++ mock_m::foo(PubCrateT()); ++ } ++ } ++} +diff --git a/tests/automock_module_unused_import.rs b/tests/automock_module_unused_import.rs +new file mode 100644 +index 0000000..7f09b43 +--- /dev/null ++++ b/tests/automock_module_unused_import.rs +@@ -0,0 +1,26 @@ ++// vim: tw=80 ++//! Mocking modules should not generated "unused_imports" warnings for imports ++//! used by the bodies of the mocked functions. ++//! https://github.com/asomers/mockall/issues/343 ++#![deny(warnings)] ++ ++use mockall::automock; ++ ++#[automock] ++pub mod foo { ++ use std::convert::TryInto; ++ ++ pub fn bar() { ++ let x = 42i32; ++ let _y: u32 = x.try_into().unwrap_or(0); ++ } ++} ++ ++#[test] ++fn return_const() { ++ let ctx = mock_foo::bar_context(); ++ ctx.expect() ++ .once() ++ .return_const(()); ++ mock_foo::bar(); ++} +diff --git a/tests/automock_multiple_lifetime_parameters.rs b/tests/automock_multiple_lifetime_parameters.rs +new file mode 100644 +index 0000000..8bdae38 +--- /dev/null ++++ b/tests/automock_multiple_lifetime_parameters.rs +@@ -0,0 +1,15 @@ ++// vim: tw=80 ++//! Methods with multiple generic lifetime parameters should produce their ++//! generated code deterministically. ++//! ++//! This test is designed to work with "--cfg reprocheck" ++ ++#![deny(warnings)] ++#![allow(clippy::needless_lifetimes)] ++ ++use mockall::*; ++ ++#[automock] ++pub trait Foo { ++ fn foo<'a, 'b, 'c, 'd, 'e, 'f>(&self, x: &'a &'b &'c &'d &'e &'f i32); ++} +diff --git a/tests/automock_must_use.rs b/tests/automock_must_use.rs +new file mode 100644 +index 0000000..d661fd4 +--- /dev/null ++++ b/tests/automock_must_use.rs +@@ -0,0 +1,60 @@ ++// vim: tw=80 ++//! Mockall should be able to mock #[must_use] methods. The generated code ++//! should contain #[must_use] on the mock method, but not the expect method. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct Foo {} ++ ++#[automock] ++impl Foo { ++ #[must_use] ++ pub fn bloob(&self) -> i32 {unimplemented!()} ++ #[must_use] ++ pub fn blarg() -> i32 {unimplemented!()} ++} ++ ++// test that basic code generation works with must_use structs and traits. The ++// exact output will be verified by the unit tests. ++#[must_use] ++pub struct MustUseStruct {} ++#[automock] ++impl MustUseStruct {} ++#[automock] ++#[must_use] ++pub trait MustUseTrait {} ++ ++#[test] ++fn must_use_method() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bloob() ++ .return_const(42i32); ++ assert_eq!(42, mock.bloob()); ++} ++ ++#[cfg(feature = "nightly")] ++#[test] ++fn may_not_use_expectation() { ++ let mut mock = MockFoo::new(); ++ // This should not produce a "must_use" warning. ++ mock.expect_bloob(); ++} ++ ++#[test] ++fn must_use_static_method() { ++ let ctx = MockFoo::blarg_context(); ++ ctx.expect() ++ .return_const(42i32); ++ assert_eq!(MockFoo::blarg(), 42); ++} ++ ++#[cfg(feature = "nightly")] ++#[test] ++fn may_not_use_static_expectation() { ++ let ctx = MockFoo::blarg_context(); ++ // This should not produce a "must_use" warning. ++ ctx.expect(); ++} ++ ++ +diff --git a/tests/automock_mutable_args.rs b/tests/automock_mutable_args.rs +new file mode 100644 +index 0000000..6bdb5f4 +--- /dev/null ++++ b/tests/automock_mutable_args.rs +@@ -0,0 +1,34 @@ ++// vim: tw=80 ++//! A method with mutable arguments ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct Foo {} ++ ++#[automock] ++impl Foo { ++ pub fn foo(&self, mut _x: u32) {} ++ pub fn bar(&mut self, _x: i32) -> i32 {0} ++} ++ ++#[test] ++fn mutable_self() { ++ let mut mock = MockFoo::new(); ++ let mut count = 0; ++ mock.expect_bar() ++ .returning(move |x| { ++ count += x; ++ count ++ }); ++ assert_eq!(5, mock.bar(5)); ++ assert_eq!(10, mock.bar(5)); ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| ()); ++ mock.foo(42); ++} +diff --git a/tests/automock_nondebug.rs b/tests/automock_nondebug.rs +new file mode 100644 +index 0000000..d6e2690 +--- /dev/null ++++ b/tests/automock_nondebug.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++//! A method may have non-Debug arguments and/or return values. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++// Don't derive Debug ++pub struct NonDebug{} ++ ++#[automock] ++pub trait Foo { ++ fn foo(&self, x: NonDebug); ++} ++ ++#[test] ++#[should_panic(expected = "MockFoo::foo(?): No matching expectation found")] ++fn with_no_matches() { ++ let mock = MockFoo::new(); ++ mock.foo(NonDebug{}); ++} ++ ++ +diff --git a/tests/automock_nonpub_methods.rs b/tests/automock_nonpub_methods.rs +new file mode 100644 +index 0000000..c534858 +--- /dev/null ++++ b/tests/automock_nonpub_methods.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++//! Using automock on a struct with private methods should not result in any ++//! "dead_code" warnings. Such methods are often private helpers used only by ++//! other public methods. ++#[deny(dead_code)] ++ ++pub mod mymod { ++ use mockall::automock; ++ ++ pub struct Foo{} ++ ++ #[automock] ++ impl Foo { ++ fn private_helper(&self) {} ++ fn static_private_helper() {} ++ ++ pub fn pubfunc(&self) { ++ Self::static_private_helper(); ++ self.private_helper() ++ } ++ } ++} +diff --git a/tests/automock_nonsend.rs b/tests/automock_nonsend.rs +new file mode 100644 +index 0000000..059879f +--- /dev/null ++++ b/tests/automock_nonsend.rs +@@ -0,0 +1,146 @@ ++// vim: tw=80 ++//! A method may have non-Send arguments and/or return values. ++#![deny(warnings)] ++ ++use mockall::*; ++// Rc is not Send ++use std::rc::Rc; ++ ++// Neither Send nor Clone ++pub struct NonSend(Rc); ++ ++mod normal_method { ++ use super::*; ++ ++ #[automock] ++ trait Foo { ++ fn foo(&self, x: Rc); ++ fn bar(&self) -> Rc; ++ fn baz(&self) -> NonSend; ++ } ++ ++ #[test] ++ fn return_once_st() { ++ let mut mock = MockFoo::new(); ++ let r = NonSend(Rc::new(42u32)); ++ mock.expect_baz() ++ .return_once_st(move || r); ++ assert_eq!(42, *mock.baz().0); ++ } ++ ++ #[test] ++ fn return_const_st() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .return_const_st(Rc::new(43u32)); ++ assert_eq!(43, *mock.bar()); ++ } ++ ++ #[test] ++ fn returning_st() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .returning_st(|| Rc::new(43u32)); ++ assert_eq!(43, *mock.bar()); ++ } ++ ++ #[test] ++ fn withf_st() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .withf_st(|x| **x == 42) ++ .return_const(()); ++ mock.foo(Rc::new(42)); ++ } ++} ++ ++mod ref_method { ++ // ref methods don't have return_once_st because they don't return owned ++ // values, and they don't have returning_st because they don't have ++ // returning. Instead, they only have return_const, which does not require ++ // Send. ++ // fn foo(&self) -> &Rc; ++} ++ ++mod refmut_method { ++ use super::*; ++ ++ #[automock] ++ trait Foo { ++ fn foo(&mut self, x: Rc); ++ fn bar(&mut self) -> &mut Rc; ++ } ++ ++ // refmut methods don't have return_once_st because they don't return owned ++ // values. ++ #[test] ++ fn returning_st() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .returning_st(|| Rc::new(43u32)); ++ assert_eq!(43, **mock.bar()); ++ } ++ ++ #[test] ++ fn withf_st() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .withf_st(|x| **x == 42) ++ .return_const(()); ++ mock.foo(Rc::new(42)); ++ } ++} ++ ++pub mod static_method { ++ use super::*; ++ use std::sync::Mutex; ++ ++ static FOO_MTX: Mutex<()> = Mutex::new(()); ++ static BAR_MTX: Mutex<()> = Mutex::new(()); ++ static BAZ_MTX: Mutex<()> = Mutex::new(()); ++ ++ #[automock] ++ trait Foo { ++ fn foo(x: Rc); ++ fn bar() -> Rc; ++ fn baz() -> NonSend; ++ } ++ ++ #[test] ++ fn return_once_st() { ++ let _guard = BAZ_MTX.lock().unwrap(); ++ let ctx = MockFoo::baz_context(); ++ let r = NonSend(Rc::new(42u32)); ++ ctx.expect() ++ .return_once_st(move || r); ++ assert_eq!(42, *MockFoo::baz().0); ++ } ++ ++ #[test] ++ fn returning_st() { ++ let _guard = BAR_MTX.lock().unwrap(); ++ let ctx = MockFoo::bar_context(); ++ ctx.expect() ++ .returning_st(|| Rc::new(42)); ++ assert_eq!(42, *MockFoo::bar()); ++ } ++ ++ #[test] ++ fn return_const_st() { ++ let _guard = BAR_MTX.lock().unwrap(); ++ let ctx = MockFoo::bar_context(); ++ ctx.expect() ++ .return_const_st(Rc::new(42)); ++ assert_eq!(42, *MockFoo::bar()); ++ } ++ ++ #[test] ++ fn withf_st() { ++ let _guard = FOO_MTX.lock().unwrap(); ++ let ctx = MockFoo::foo_context(); ++ ctx.expect() ++ .withf_st(|x| **x == 42) ++ .return_const(()); ++ MockFoo::foo(Rc::new(42)); ++ } ++} +diff --git a/tests/automock_nonstatic_struct.rs b/tests/automock_nonstatic_struct.rs +new file mode 100644 +index 0000000..ecb3399 +--- /dev/null ++++ b/tests/automock_nonstatic_struct.rs +@@ -0,0 +1,53 @@ ++// vim: tw=80 ++//! Mock a struct with a lifetime parameter ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct NonStaticStruct<'nss> { ++ _x: &'nss i32 ++} ++ ++#[automock] ++impl<'nss> NonStaticStruct<'nss> { ++ pub fn foo(&self) -> i64 { ++ 42 ++ } ++ pub fn bar() -> i64{ ++ 42 ++ } ++ // XXX Constructors aren't yet supported for non-static Structs ++ //pub fn new(x: &'nss i32) -> Self { ++ //NonStaticStruct{x} ++ //} ++} ++ ++#[test] ++fn normal_method() { ++ // This function serves to define a named lifetime ++ #[allow(clippy::trivially_copy_pass_by_ref)] ++ fn has_lt<'a>(_x: &'a i8) { ++ let mut mock = MockNonStaticStruct::<'a>::default(); ++ mock.expect_foo() ++ .returning(|| 5); ++ assert_eq!(5, mock.foo()); ++ } ++ ++ let x = 42i8; ++ has_lt(&x); ++} ++ ++#[test] ++fn static_method() { ++ // This function serves to define a named lifetime ++ #[allow(clippy::trivially_copy_pass_by_ref)] ++ fn has_lt<'a>(_x: &'a i8) { ++ let ctx = MockNonStaticStruct::<'a>::bar_context(); ++ ctx.expect() ++ .returning(|| 5); ++ assert_eq!(5, MockNonStaticStruct::bar()); ++ } ++ ++ let x = 42i8; ++ has_lt(&x); ++} +diff --git a/tests/automock_partial_eq.rs b/tests/automock_partial_eq.rs +new file mode 100644 +index 0000000..2618b4e +--- /dev/null ++++ b/tests/automock_partial_eq.rs +@@ -0,0 +1,39 @@ ++// vim: tw=80 ++//! Mockall should deselfify `Self` types, even if they aren't named `self`. ++use mockall::*; ++ ++mock! { ++ #[derive(Debug)] ++ pub Foo { ++ fn compare(&self, other: &Self) -> bool; ++ } ++ impl PartialEq for Foo { ++ fn eq(&self, other: &Self) -> bool; ++ } ++} ++ ++#[test] ++fn inherent_method() { ++ let mut x = MockFoo::default(); ++ let mut y = MockFoo::default(); ++ x.expect_compare() ++ .return_const(true); ++ y.expect_compare() ++ .return_const(false); ++ ++ assert!(x.compare(&y)); ++ assert!(!y.compare(&x)); ++} ++ ++#[test] ++fn trait_method() { ++ let mut x = MockFoo::default(); ++ let mut y = MockFoo::default(); ++ x.expect_eq() ++ .return_const(true); ++ y.expect_eq() ++ .return_const(false); ++ ++ assert_eq!(x, y); ++ assert!(y != x); ++} +diff --git a/tests/automock_qself.rs b/tests/automock_qself.rs +new file mode 100644 +index 0000000..2b10034 +--- /dev/null ++++ b/tests/automock_qself.rs +@@ -0,0 +1,54 @@ ++// vim: tw=80 ++//! Using QSelf in an argument, a where clause, or a return type ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub trait Foo { ++ type Output; ++} ++ ++pub struct SendFoo {} ++impl Foo for SendFoo { ++ type Output = u32; ++} ++ ++pub struct A{} ++#[automock] ++impl A { ++ pub fn foo(&self, _q: ::Output) { ++ } ++ pub fn bar(&self, _t: T) -> ::Output { ++ unimplemented!() ++ } ++ pub fn bean(&self, _t: T) ++ where T: Foo + 'static, ++ ::Output: Send ++ { ++ } ++} ++ ++#[test] ++fn arguments() { ++ let mut mock = MockA::new(); ++ mock.expect_foo::() ++ .with(predicate::eq(42u32)) ++ .return_const(()); ++ mock.foo::(42u32); ++} ++ ++#[test] ++fn where_clause() { ++ let mut mock = MockA::new(); ++ mock.expect_bean::() ++ .return_const(()); ++ mock.bean(SendFoo{}); ++} ++ ++#[test] ++fn return_value() { ++ let mut mock = MockA::new(); ++ mock.expect_bar::() ++ .return_const(42u32); ++ assert_eq!(42, mock.bar(SendFoo{})); ++} +diff --git a/tests/automock_refmut_arguments.rs b/tests/automock_refmut_arguments.rs +new file mode 100644 +index 0000000..d65a00e +--- /dev/null ++++ b/tests/automock_refmut_arguments.rs +@@ -0,0 +1,23 @@ ++// vim: tw=80 ++//! A method that takes mutable reference arguments, returning information ++//! through its arguments like C functions often do. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait T { ++ fn foo(&self, x: &mut u32); ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockT::new(); ++ let mut x = 5; ++ mock.expect_foo() ++ .returning(|x: &mut u32| { ++ *x = 42; ++ }); ++ mock.foo(&mut x); ++ assert_eq!(42, x); ++} +diff --git a/tests/automock_return_mutable_ref.rs b/tests/automock_return_mutable_ref.rs +new file mode 100644 +index 0000000..705a3eb +--- /dev/null ++++ b/tests/automock_return_mutable_ref.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++//! A method that returns a mutable reference ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait A { ++ fn foo(&mut self) -> &mut u32; ++} ++ ++#[test] ++fn return_var() { ++ let mut mock = MockA::new(); ++ mock.expect_foo().return_var(5); ++ { ++ let r = mock.foo(); ++ assert_eq!(5, *r); ++ *r = 6; ++ } ++ assert_eq!(6, *mock.foo()); ++} +diff --git a/tests/automock_return_owned.rs b/tests/automock_return_owned.rs +new file mode 100644 +index 0000000..826d711 +--- /dev/null ++++ b/tests/automock_return_owned.rs +@@ -0,0 +1,32 @@ ++// vim: tw=80 ++//! A method that returns ownership of a value, rather than returning by Copy ++#![deny(warnings)] ++ ++use mockall::*; ++ ++struct NonCopy {} ++ ++#[automock] ++trait T { ++ fn foo(&self) -> NonCopy; ++} ++ ++#[test] ++fn return_once() { ++ let mut mock = MockT::new(); ++ let r = NonCopy{}; ++ mock.expect_foo() ++ .return_once(|| r); ++ mock.foo(); ++} ++ ++#[test] ++#[should_panic(expected = "MockT::foo: Expectation() called twice, but it returns by move")] ++fn return_once_too_many_times() { ++ let mut mock = MockT::new(); ++ let r = NonCopy{}; ++ mock.expect_foo() ++ .return_once(|| r); ++ mock.foo(); ++ mock.foo(); ++} +diff --git a/tests/automock_return_reference.rs b/tests/automock_return_reference.rs +new file mode 100644 +index 0000000..f312217 +--- /dev/null ++++ b/tests/automock_return_reference.rs +@@ -0,0 +1,17 @@ ++// vim: tw=80 ++//! A method that returns an immutable reference ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait A { ++ fn foo(&self) -> &u32; ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockA::new(); ++ mock.expect_foo().return_const(5); ++ assert_eq!(5, *mock.foo()); ++} +diff --git a/tests/automock_return_static_ref.rs b/tests/automock_return_static_ref.rs +new file mode 100644 +index 0000000..1f8c533 +--- /dev/null ++++ b/tests/automock_return_static_ref.rs +@@ -0,0 +1,18 @@ ++// vim: tw=80 ++//! A method that returns an immutable 'static reference ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait A { ++ fn foo(&self) -> &'static u32; ++} ++ ++#[test] ++fn return_const() { ++ const X: u32 = 5; ++ let mut mock = MockA::new(); ++ mock.expect_foo().return_const(&X); ++ assert_eq!(5, *mock.foo()); ++} +diff --git a/tests/automock_rpitit.rs b/tests/automock_rpitit.rs +new file mode 100644 +index 0000000..4bf2974 +--- /dev/null ++++ b/tests/automock_rpitit.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++//! Return position Impl Trait in Traits ++//! https://rust-lang.github.io/rfcs/3425-return-position-impl-trait-in-traits.html ++#![cfg(feature = "nightly")] ++#![deny(warnings)] ++ ++use std::fmt::Debug; ++ ++use mockall::*; ++ ++#[automock] ++trait Foo { ++ fn bar(&self) -> impl Debug; ++} ++ ++#[test] ++fn returning() { ++ let mut foo = MockFoo::default(); ++ foo.expect_bar() ++ .returning(|| Box::new(42u32)); ++ assert_eq!("42", format!("{:?}", foo.bar())); ++} +diff --git a/tests/automock_self_by_value.rs b/tests/automock_self_by_value.rs +new file mode 100644 +index 0000000..45af055 +--- /dev/null ++++ b/tests/automock_self_by_value.rs +@@ -0,0 +1,30 @@ ++// vim: tw=80 ++//! A method that consumes self ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct MethodByValue {} ++ ++#[automock] ++impl MethodByValue { ++ pub fn foo(self, _x: u32) -> i64 {0} ++ #[allow(unused_mut)] ++ pub fn bar(mut self) {} ++} ++ ++#[test] ++fn immutable() { ++ let mut mock = MockMethodByValue::new(); ++ mock.expect_foo() ++ .returning(|x| i64::from(x) + 1); ++ assert_eq!(5, mock.foo(4)); ++} ++ ++#[test] ++fn mutable() { ++ let mut mock = MockMethodByValue::new(); ++ mock.expect_bar() ++ .returning(|| ()); ++ mock.bar(); ++} +diff --git a/tests/automock_send.rs b/tests/automock_send.rs +new file mode 100644 +index 0000000..1f7d468 +--- /dev/null ++++ b/tests/automock_send.rs +@@ -0,0 +1,17 @@ ++// vim: tw=80 ++//! A mock object should be Send ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++pub trait T { ++ fn foo(&self) -> u32; ++} ++ ++#[test] ++#[allow(clippy::unnecessary_operation)] // The cast is the whole point ++fn cast_to_send() { ++ let mock = MockT::new(); ++ let _m = Box::new(mock) as Box; ++} +diff --git a/tests/automock_seven_args.rs b/tests/automock_seven_args.rs +new file mode 100644 +index 0000000..6760f02 +--- /dev/null ++++ b/tests/automock_seven_args.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++//! When mocking static functions just at the threshold of Clippy's type ++//! complexity limit, no warnings should be emitted regarding the generated ++//! code. ++#![deny(warnings)] ++ ++use mockall::automock; ++ ++#[automock] ++trait ManyArgs { ++ fn foo(_a0: u8, _a1: u8, _a2: u8, _a3: u8, _a4: u8, _a5: u8, _a6: u8); ++} ++ ++#[test] ++fn static_method_returning() { ++ let ctx = MockManyArgs::foo_context(); ++ ctx.expect() ++ .returning(|_, _, _, _, _, _, _| ()); ++ MockManyArgs::foo(0, 0, 0, 0, 0, 0, 0); ++} ++ ++ +diff --git a/tests/automock_slice_arguments.rs b/tests/automock_slice_arguments.rs +new file mode 100644 +index 0000000..37044ac +--- /dev/null ++++ b/tests/automock_slice_arguments.rs +@@ -0,0 +1,35 @@ ++// vim: tw=80 ++//! a method with slice arguments ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait Foo { ++ fn foo(&self, x: &[u8]); ++} ++ ++mod withf { ++ use super::*; ++ ++ #[test] ++ #[should_panic(expected = "MockFoo::foo([1, 2, 3, 4]): No matching expectation found")] ++ fn fail() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .withf(|sl| sl == [1, 2, 3]) ++ .returning(|_| ()); ++ let x = vec![1, 2, 3, 4]; ++ mock.foo(&x); ++ } ++ ++ #[test] ++ fn ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .withf(|sl| sl == [1, 2, 3]) ++ .returning(|_| ()); ++ let x = vec![1, 2, 3]; ++ mock.foo(&x); ++ } ++} +diff --git a/tests/automock_specializing_method_of_nongeneric_struct.rs b/tests/automock_specializing_method_of_nongeneric_struct.rs +new file mode 100644 +index 0000000..8f82f57 +--- /dev/null ++++ b/tests/automock_specializing_method_of_nongeneric_struct.rs +@@ -0,0 +1,29 @@ ++// vim: tw=80 ++//! Non-generic structs can have specializing methods, too. For example, some ++//! methods place constraints on Self. It's even possible for a where clause to ++//! place a constraint on types that appear nowhere in the struct's signatures. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait Bar { ++ fn bar(&self) where Self: Sized; ++ fn baz() where Self: Sized; ++} ++ ++#[test] ++fn nonstatic() { ++ let mut mock = MockBar::default(); ++ mock.expect_bar() ++ .return_const(()); ++ mock.bar(); ++} ++ ++#[test] ++fn static_method() { ++ let ctx = MockBar::baz_context(); ++ ctx.expect() ++ .return_const(()); ++ MockBar::baz(); ++} +diff --git a/tests/automock_specializing_methods.rs b/tests/automock_specializing_methods.rs +new file mode 100644 +index 0000000..e4f3af4 +--- /dev/null ++++ b/tests/automock_specializing_methods.rs +@@ -0,0 +1,33 @@ ++// vim: tw=80 ++//! A specializing method is a non-generic method of a generic struct that ++//! places additional bounds on the struct's generic types via a where ++//! clause. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++struct G(T); ++ ++#[derive(Clone, Copy)] ++struct NonDefault{} ++ ++#[automock] ++trait Foo where T: Copy { ++ fn foo(&self, t: T) -> G where T: Default + 'static; ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::::default(); ++ mock.expect_foo() ++ .returning(G); ++ assert_eq!(42u32, mock.foo(42u32).0); ++ ++ // It's possible to instantiate a mock object that doesn't satisfy the ++ // specializing method's requirements: ++ let _mock2 = MockFoo::::default(); ++ // But you can't call the specializing method. This won't work: ++ // _mock2.expect_foo() ++ // .returning(|h| G(h)); ++ // _mock2.foo(NonDefault{}); ++} +diff --git a/tests/automock_static_method.rs b/tests/automock_static_method.rs +new file mode 100644 +index 0000000..bcdff4d +--- /dev/null ++++ b/tests/automock_static_method.rs +@@ -0,0 +1,18 @@ ++// vim: tw=80 ++//! automocking a trait with a static method ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait A { ++ fn bar() -> u32; ++} ++ ++#[test] ++fn returning() { ++ let ctx = MockA::bar_context(); ++ ctx.expect() ++ .returning(|| 42); ++ assert_eq!(42, MockA::bar()); ++} +diff --git a/tests/automock_struct.rs b/tests/automock_struct.rs +new file mode 100644 +index 0000000..d344167 +--- /dev/null ++++ b/tests/automock_struct.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++//! automocking a struct ++#![deny(warnings)] ++ ++use mockall::*; ++ ++pub struct SimpleStruct {} ++ ++#[automock] ++impl SimpleStruct { ++ pub fn foo(&self, _x: u32) -> i64 { ++ 42 ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockSimpleStruct::new(); ++ mock.expect_foo() ++ .returning(|x| i64::from(x) + 1); ++ assert_eq!(5, mock.foo(4)); ++} +diff --git a/tests/automock_trait.rs b/tests/automock_trait.rs +new file mode 100644 +index 0000000..81261d6 +--- /dev/null ++++ b/tests/automock_trait.rs +@@ -0,0 +1,18 @@ ++// vim: tw=80 ++//! automocking a trait ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait SimpleTrait { ++ fn foo(&self, x: u32) -> u32; ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockSimpleTrait::new(); ++ mock.expect_foo() ++ .returning(|x| x + 1); ++ assert_eq!(5, mock.foo(4)); ++} +diff --git a/tests/automock_trait_object.rs b/tests/automock_trait_object.rs +new file mode 100644 +index 0000000..78f93a0 +--- /dev/null ++++ b/tests/automock_trait_object.rs +@@ -0,0 +1,42 @@ ++// vim: tw=80 ++//! a method that uses unboxed trait object arguments ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++trait Foo { ++ fn foo(&self, x: &dyn PartialEq); ++} ++ ++// It's almost impossible to construct a Predicate object that will work with ++// trait objects for two reasons: ++// * Mockall requires the predicates to be Debug, and any useful predicate will ++// also be Eq, Ord, or similar, but Rust only allows up to one non-auto trait ++// per trait object. ++// * The predicate is requird to meet the HRTB ++// for<'a> Predicate<(dyn Trait + 'a)> ++// That's not impossible, but Mockall doesn't provide any way to construct ++// such a predicate. ++// So, use of `with` is pretty much limited to predicates like `always` and ++// `function`. ++#[test] ++fn with() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .with(predicate::always()) ++ .return_const(()); ++ mock.foo(&42u32) ++} ++ ++/// trait object arguments can't be matched with `predicate::eq`, because ++/// `PartialEq` cannot be made into a trait object. But withf still ++/// works. ++#[test] ++fn withf() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .withf(|x| *x == 42u32) ++ .return_const(()); ++ mock.foo(&42u32); ++} +diff --git a/tests/automock_unsafe_trait.rs b/tests/automock_unsafe_trait.rs +new file mode 100644 +index 0000000..ff64eb7 +--- /dev/null ++++ b/tests/automock_unsafe_trait.rs +@@ -0,0 +1,37 @@ ++// vim: ts=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++#[allow(clippy::missing_safety_doc)] ++pub unsafe trait Foo { ++ fn foo(&self) -> i32; ++} ++ ++pub struct Baz{} ++ ++#[automock] ++unsafe impl Foo for Baz { ++ fn foo(&self) -> i32 { ++ unimplemented!() ++ } ++} ++ ++#[test] ++fn automock_trait() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .return_const(42); ++ ++ assert_eq!(42, mock.foo()); ++} ++ ++#[test] ++fn automock_trait_impl() { ++ let mut mock = MockBaz::new(); ++ mock.expect_foo() ++ .return_const(42); ++ ++ assert_eq!(42, mock.foo()); ++} +diff --git a/tests/automock_where_self.rs b/tests/automock_where_self.rs +new file mode 100644 +index 0000000..eedf34f +--- /dev/null ++++ b/tests/automock_where_self.rs +@@ -0,0 +1,29 @@ ++// vim: ts=80 ++//! Methods with a "where Self: ..." where clause should be mocked as concrete, ++//! not generic. ++#![deny(warnings)] ++#![allow(clippy::needless_lifetimes)] ++ ++// Enclose the mocked trait within a non-public module. With some versions of ++// rustc, that causes "unused method" errors for the generic code, but not the ++// concrete code. ++// rustc 1.66.0-nightly (e7119a030 2022-09-22) ++mod mymod { ++ ++ #[mockall::automock] ++ pub trait Server { ++ fn version<'a>(&'a self) -> Option<&'static str> where Self: Sized; ++ } ++ ++} ++ ++use mymod::{MockServer, Server}; ++ ++#[test] ++fn return_const() { ++ let mut mock = MockServer::new(); ++ mock.expect_version() ++ .return_const(None); ++ ++ mock.version(); ++} +diff --git a/tests/cfg_attr_concretize.rs b/tests/cfg_attr_concretize.rs +new file mode 100644 +index 0000000..93af750 +--- /dev/null ++++ b/tests/cfg_attr_concretize.rs +@@ -0,0 +1,26 @@ ++// vim: tw=80 ++//! #[concretize] can be used inside of #[cfg_attr()]` ++#![deny(warnings)] ++ ++use std::path::{Path, PathBuf}; ++ ++use mockall::{automock, concretize}; ++ ++#[automock] ++trait Foo { ++ #[cfg_attr(not(target_os = "ia64-unknown-multics"), concretize)] ++ fn foo>(&self, p: P); ++} ++ ++ ++#[test] ++fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_foo() ++ .withf(|p| p.as_ref() == Path::new("/tmp")) ++ .times(3) ++ .return_const(()); ++ foo.foo(Path::new("/tmp")); ++ foo.foo(PathBuf::from(Path::new("/tmp"))); ++ foo.foo("/tmp"); ++} +diff --git a/tests/clear_expectations_on_panic.rs b/tests/clear_expectations_on_panic.rs +new file mode 100644 +index 0000000..a70df15 +--- /dev/null ++++ b/tests/clear_expectations_on_panic.rs +@@ -0,0 +1,50 @@ ++// vim: tw=80 ++//! Static methods' expectations should be dropped during panic. ++//! ++//! https://github.com/asomers/mockall/issues/442 ++#![deny(warnings)] ++ ++use std::panic; ++ ++use mockall::*; ++ ++#[automock] ++pub trait Foo { ++ fn foo() -> i32; ++ fn bar() -> i32; ++} ++ ++#[test] ++fn too_few_calls() { ++ panic::catch_unwind(|| { ++ let ctx = MockFoo::foo_context(); ++ ctx.expect() ++ .times(1) ++ .return_const(42); ++ }).unwrap_err(); ++ ++ // The previously set expectation should've been cleared during the panic, ++ // so we must set a new one. ++ let ctx = MockFoo::foo_context(); ++ ctx.expect() ++ .times(1) ++ .return_const(42); ++ assert_eq!(42, MockFoo::foo()); ++} ++ ++// We shouldn't panic during drop in this case. Regression test for ++// https://github.com/asomers/mockall/issues/491 ++#[cfg_attr(not(feature = "nightly"), ignore)] ++#[test] ++fn too_many_calls() { ++ panic::catch_unwind(|| { ++ let ctx = MockFoo::bar_context(); ++ ctx.expect() ++ .times(0); ++ MockFoo::bar(); ++ }).unwrap_err(); ++ ++ // This line will panic with a PoisonError, at least until issue #515 is ++ // complete. ++ let _ctx = MockFoo::bar_context(); ++} +diff --git a/tests/link_name.rs b/tests/link_name.rs +new file mode 100644 +index 0000000..0987cce +--- /dev/null ++++ b/tests/link_name.rs +@@ -0,0 +1,19 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[automock] ++pub mod ffi { ++ extern "C" { ++ #[link_name = "foo__extern"] ++ pub fn foo() -> u32; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let ctx = mock_ffi::foo_context(); ++ ctx.expect().return_const(42u32); ++ assert_eq!(42, unsafe{mock_ffi::foo()}); ++} +diff --git a/tests/mock_associated_const.rs b/tests/mock_associated_const.rs +new file mode 100644 +index 0000000..eae84ff +--- /dev/null ++++ b/tests/mock_associated_const.rs +@@ -0,0 +1,34 @@ ++// vim: tw=80 ++//! A trait with an associated constant ++//! ++//! https://github.com/asomers/mockall/issues/97 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Foo { ++ const X: i32; ++ ++ fn x_plus_one(&self) -> i32 { ++ Self::X + 1 ++ } ++} ++ ++mock! { ++ Foo { ++ const Y: i32 = 69; ++ } ++ impl Foo for Foo { ++ const X: i32 = 42; ++ } ++} ++ ++#[test] ++fn default_method() { ++ assert_eq!(MockFoo::new().x_plus_one(), 43); ++} ++ ++#[test] ++fn on_the_struct() { ++ assert_eq!(MockFoo::Y, 69); ++} +diff --git a/tests/mock_associated_types.rs b/tests/mock_associated_types.rs +new file mode 100644 +index 0000000..8cf7aa9 +--- /dev/null ++++ b/tests/mock_associated_types.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ MyIter {} ++ impl Iterator for MyIter { ++ type Item=u32; ++ ++ fn next(&mut self) -> Option; ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockMyIter::new(); ++ mock.expect_next() ++ .returning(|| Some(5)); ++ assert_eq!(5, mock.next().unwrap()); ++} ++ +diff --git a/tests/mock_async_fn.rs b/tests/mock_async_fn.rs +new file mode 100644 +index 0000000..0988559 +--- /dev/null ++++ b/tests/mock_async_fn.rs +@@ -0,0 +1,39 @@ ++// vim: tw=80 ++//! A struct with an async function ++#![deny(warnings)] ++ ++use futures::executor::block_on; ++use mockall::*; ++ ++mock! { ++ pub Foo { ++ async fn foo(&self) -> u32; ++ async fn bar() -> u32; ++ async fn baz(&self, t: T) -> T; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .return_const(42u32); ++ assert_eq!(block_on(mock.foo()), 42); ++} ++ ++#[test] ++fn static_method() { ++ let ctx = MockFoo::bar_context(); ++ ctx.expect() ++ .return_const(42u32); ++ assert_eq!(block_on(MockFoo::bar()), 42); ++} ++ ++#[test] ++fn generic_method() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .with(predicate::eq(69u32)) ++ .return_const(42u32); ++ assert_eq!(block_on(mock.baz(69u32)), 42u32); ++} +diff --git a/tests/mock_async_trait.rs b/tests/mock_async_trait.rs +new file mode 100644 +index 0000000..7493dd9 +--- /dev/null ++++ b/tests/mock_async_trait.rs +@@ -0,0 +1,28 @@ ++// vim: tw=80 ++//! An async trait, for use with Futures ++#![deny(warnings)] ++ ++use async_trait::async_trait; ++use futures::executor::block_on; ++use mockall::*; ++ ++#[async_trait] ++pub trait Foo { ++ async fn foo(&self) -> u32; ++} ++ ++mock! { ++ pub Bar { } ++ #[async_trait] ++ impl Foo for Bar { ++ async fn foo(&self) -> u32; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockBar::new(); ++ mock.expect_foo() ++ .return_const(42u32); ++ assert_eq!(block_on(mock.foo()), 42); ++} +diff --git a/tests/mock_box_self.rs b/tests/mock_box_self.rs +new file mode 100644 +index 0000000..8d17754 +--- /dev/null ++++ b/tests/mock_box_self.rs +@@ -0,0 +1,68 @@ ++// vim: tw=80 ++//! Methods that take receivers like Box instead of &self ++#![allow(clippy::borrowed_box, clippy::boxed_local)] ++#![deny(warnings)] ++ ++use mockall::*; ++use std::sync::Arc; ++use std::pin::Pin; ++use std::rc::Rc; ++ ++mock! { ++ Foo { ++ fn foo(self: &Box); ++ fn baz(mut self: Box); ++ fn bar(self: Box); ++ fn bean(self: Arc); ++ fn booz(self: Pin>); ++ fn blez(self: Rc); ++ } ++} ++ ++#[test] ++fn arc() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bean() ++ .returning(|| ()); ++ Arc::new(mock).bean(); ++} ++ ++#[test] ++fn pin() { ++ let mut mock = MockFoo::new(); ++ mock.expect_booz() ++ .returning(|| ()); ++ Pin::new(Box::new(mock)).booz(); ++} ++ ++#[test] ++fn rc() { ++ let mut mock = MockFoo::new(); ++ mock.expect_blez() ++ .returning(|| ()); ++ Rc::new(mock).blez(); ++} ++ ++#[test] ++fn ref_box() { ++ let mut mock = Box::new(MockFoo::new()); ++ mock.expect_foo() ++ .returning(|| ()); ++ mock.foo(); ++} ++ ++#[test] ++fn mutable() { ++ let mut mock = Box::new(MockFoo::new()); ++ mock.expect_baz() ++ .returning(|| ()); ++ mock.baz(); ++} ++ ++#[test] ++fn owned() { ++ let mut mock = Box::new(MockFoo::new()); ++ mock.expect_bar() ++ .returning(|| ()); ++ mock.bar(); ++} +diff --git a/tests/mock_cfg.rs b/tests/mock_cfg.rs +new file mode 100644 +index 0000000..b846a87 +--- /dev/null ++++ b/tests/mock_cfg.rs +@@ -0,0 +1,65 @@ ++// vim: tw=80 ++//! mock's methods and trait impls can be conditionally compiled ++#![deny(warnings)] ++ ++use mockall::*; ++ ++// For this test, use the "nightly" feature as the cfg gate, because it's tested ++// both ways in CI. ++#[cfg(feature = "nightly")] ++pub trait Beez { ++ fn beez(&self); ++} ++#[cfg(not(feature = "nightly"))] ++pub trait Beez { ++ fn beez(&self, x: i32) -> i32; ++} ++ ++mock! { ++ pub Foo { ++ #[cfg(feature = "nightly")] ++ pub fn foo(&self); ++ #[cfg(not(feature = "nightly"))] ++ pub fn foo(&self, x: i32) -> i32; ++ } ++ #[cfg(feature = "nightly")] ++ impl Beez for Foo { ++ fn beez(&self); ++ } ++ #[cfg(not(feature = "nightly"))] ++ impl Beez for Foo { ++ fn beez(&self, x: i32) -> i32; ++ } ++} ++ ++#[test] ++#[cfg(feature = "nightly")] ++fn test_nightly_method() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|| ()); ++} ++ ++#[test] ++#[cfg(feature = "nightly")] ++fn test_nightly_trait() { ++ let mut mock = MockFoo::new(); ++ mock.expect_beez() ++ .returning(|| ()); ++} ++ ++#[test] ++#[cfg(not(feature = "nightly"))] ++fn test_not_nightly_method() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|x| x + 1); ++} ++ ++#[test] ++#[cfg(not(feature = "nightly"))] ++fn test_not_nightly_trait() { ++ let mut mock = MockFoo::new(); ++ mock.expect_beez() ++ .returning(|x| x + 1); ++} +diff --git a/tests/mock_clone.rs b/tests/mock_clone.rs +new file mode 100644 +index 0000000..8f4a227 +--- /dev/null ++++ b/tests/mock_clone.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++//! Clone-like methods (non-static method with Self return type) need the return ++//! type to be deselfified. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ pub A {} ++ impl Clone for A { ++ fn clone(&self) -> Self; ++ } ++} ++ ++#[allow(clippy::redundant_clone)] ++#[test] ++fn returning() { ++ let mut mock0 = MockA::new(); ++ mock0.expect_clone() ++ .returning(MockA::new); ++ let _mock1 = mock0.clone(); ++} +diff --git a/tests/mock_closure.rs b/tests/mock_closure.rs +new file mode 100644 +index 0000000..412f0f4 +--- /dev/null ++++ b/tests/mock_closure.rs +@@ -0,0 +1,89 @@ ++// vim: tw=80 ++//! A method with a closure argument can be mocked, by turning the closure into ++//! a Boxed Fn. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++struct NonCopy(u32); ++ ++mock!{ ++ Foo { ++ fn foo u32 + 'static>(&self, f: F) -> u32; ++ fn bar u32 + 'static>(&self, f: F) -> u32; ++ fn baz NonCopy + 'static>(&self, f: F) -> NonCopy; ++ fn bean u32 + 'static>(f: F) -> u32; ++ // Not technically a closure, but it should work too ++ fn bang(&self, f: fn(u32) -> u32) -> u32; ++ // Identical to foo, but it uses a where clause ++ fn food(&self, f: F) -> u32 where F: Fn(u32) -> u32 + 'static; ++ // Identical to foo, but with extra unrelated where predicates ++ fn foody(&self, f: F, g:G) -> u32 ++ where F: Fn(u32) -> u32 + 'static, ++ G: 'static; ++ } ++} ++ ++mod returning { ++ use super::*; ++ ++ #[test] ++ fn bare_fn() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bang() ++ .returning(|f| f(42)); ++ assert_eq!(84, mock.bang(|x| 2 * x)); ++ } ++ ++ #[test] ++ fn immutable() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|f| f(42)); ++ assert_eq!(84, mock.foo(|x| 2 * x)); ++ } ++ ++ #[test] ++ fn mutable() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .returning(|mut f| {f(42); f(5) } ); ++ let mut counter = 0; ++ assert_eq!(47, mock.bar(move |x| { counter += x; counter } )); ++ } ++ ++ #[test] ++ fn once() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .returning(|f| f(42)); ++ let initial = NonCopy(5); ++ assert_eq!(47, mock.baz(move |x| NonCopy(initial.0 + x)).0); ++ } ++ ++ #[test] ++ fn static_method() { ++ let ctx = MockFoo::bean_context(); ++ ctx.expect() ++ .returning(|f| f(42)); ++ assert_eq!(84, MockFoo::bean(|x| 2 * x)); ++ } ++ ++ // food's where clause should be completely deleted in the mock ++ // implementation. ++ #[test] ++ fn deleted_where_clause() { ++ let mut mock = MockFoo::new(); ++ mock.expect_food() ++ .returning(|f| f(42)); ++ assert_eq!(84, mock.food(|x| 2 * x)); ++ } ++ ++ #[test] ++ fn where_clause() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foody() ++ .returning(|f, _g: u32| f(42)); ++ assert_eq!(84, mock.foody(|x| 2u32 * x, 0u32)); ++ } ++} +diff --git a/tests/mock_concrete_struct_with_generic_trait.rs b/tests/mock_concrete_struct_with_generic_trait.rs +new file mode 100644 +index 0000000..2fd07f5 +--- /dev/null ++++ b/tests/mock_concrete_struct_with_generic_trait.rs +@@ -0,0 +1,24 @@ ++// vim: tw=80 ++//! A concrete struct that implements a generic trait ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Foo { ++ fn foo(&self, x: T) -> T; ++} ++mock! { ++ Bar {} ++ impl Foo for Bar { ++ fn foo(&self, x: i32) -> i32; ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockBar::new(); ++ mock.expect_foo() ++ .with(predicate::eq(42)) ++ .returning(|x| x + 1); ++ assert_eq!(43, mock.foo(42)); ++} +diff --git a/tests/mock_concretize.rs b/tests/mock_concretize.rs +new file mode 100644 +index 0000000..f9d73ef +--- /dev/null ++++ b/tests/mock_concretize.rs +@@ -0,0 +1,140 @@ ++// vim: tw=80 ++//! Some generic methods with non-`'static` generic parameters can be mocked by ++//! transforming the function arguments into trait objects. ++#![deny(warnings)] ++ ++use mockall::*; ++use std::path::{Path, PathBuf}; ++ ++trait AsRefMut: AsRef + AsMut {} ++impl AsRefMut for Q where Q: AsRef + AsMut, T: ?Sized {} ++ ++mock! { ++ Foo { ++ /// Base concretized function ++ #[mockall::concretize] ++ fn foo>(&self, x: P); ++ ++ /// With a where clause ++ #[mockall::concretize] ++ fn boom

(&self, x: P) where P: AsRef; ++ ++ /// Static function ++ #[mockall::concretize] ++ fn bang>(x: P); ++ ++ /// Reference argument ++ #[mockall::concretize] ++ fn boomref>(&self, x: &P); ++ ++ /// Mutable reference argument ++ #[mockall::concretize] ++ fn boom_mutref>(&self, x: &mut T); ++ ++ /// Slice argument ++ #[mockall::concretize] ++ fn boomv

(&self, x: &[P]) where P: AsRef; ++ ++ /// Public visiblity ++ #[mockall::concretize] ++ pub fn foopub>(&self, x: P); ++ } ++} ++ ++mod generic_arg { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_foo() ++ .withf(|p| p.as_ref() == Path::new("/tmp")) ++ .times(3) ++ .return_const(()); ++ foo.foo(Path::new("/tmp")); ++ foo.foo(PathBuf::from(Path::new("/tmp"))); ++ foo.foo("/tmp"); ++ } ++} ++ ++mod where_clause { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_boom() ++ .withf(|p| p.as_ref() == Path::new("/tmp")) ++ .times(3) ++ .return_const(()); ++ foo.boom(Path::new("/tmp")); ++ foo.boom(PathBuf::from(Path::new("/tmp"))); ++ foo.boom("/tmp"); ++ } ++} ++ ++mod mutable_reference_arg { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_boom_mutref() ++ .withf(|p| p.as_ref() == "/tmp") ++ .once() ++ .returning(|s| s.as_mut().make_ascii_uppercase()); ++ let mut s = String::from("/tmp"); ++ foo.boom_mutref(&mut s); ++ assert_eq!(s, "/TMP"); ++ } ++} ++ ++mod reference_arg { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_boomref() ++ .withf(|p| p.as_ref() == Path::new("/tmp")) ++ .times(3) ++ .return_const(()); ++ foo.boomref(&Path::new("/tmp")); ++ foo.boomref(&PathBuf::from(Path::new("/tmp"))); ++ foo.boomref(&"/tmp"); ++ } ++} ++ ++mod slice { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_boomv() ++ .withf(|v| ++ v[0].as_ref() == Path::new("/tmp") && ++ v[1].as_ref() == Path::new("/mnt") ++ ).times(3) ++ .return_const(()); ++ foo.boomv(&[Path::new("/tmp"), Path::new("/mnt")]); ++ foo.boomv(&[PathBuf::from("/tmp"), PathBuf::from("/mnt")]); ++ foo.boomv(&["/tmp", "/mnt"]); ++ } ++} ++ ++mod static_method { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let ctx = MockFoo::bang_context(); ++ ctx.expect() ++ .withf(|p| p.as_ref() == Path::new("/tmp")) ++ .times(3) ++ .return_const(()); ++ MockFoo::bang(Path::new("/tmp")); ++ MockFoo::bang(PathBuf::from(Path::new("/tmp"))); ++ MockFoo::bang("/tmp"); ++ } ++} +diff --git a/tests/mock_concretize_with_bounds.rs b/tests/mock_concretize_with_bounds.rs +new file mode 100644 +index 0000000..76b55a8 +--- /dev/null ++++ b/tests/mock_concretize_with_bounds.rs +@@ -0,0 +1,135 @@ ++// vim: tw=80 ++//! Using #[concretize] on generic types with trait bounds ++#![deny(warnings)] ++ ++use mockall::*; ++use std::path::{Path, PathBuf}; ++ ++trait AsRefMut: AsRef + AsMut {} ++impl AsRefMut for Q where Q: AsRef + AsMut, T: ?Sized {} ++ ++mock! { ++ Foo { ++ /// Base concretized function ++ #[mockall::concretize] ++ fn foo + Send>(&self, x: P); ++ ++ /// With a where clause ++ #[mockall::concretize] ++ fn boom

(&self, x: P) where P: AsRef + Send; ++ ++ /// Static function ++ #[mockall::concretize] ++ fn bang + Send>(x: P); ++ ++ /// Reference argument ++ #[mockall::concretize] ++ fn boomref + Send>(&self, x: &P); ++ ++ /// Mutable reference argument ++ #[mockall::concretize] ++ fn boom_mutref + Send>(&self, x: &mut T); ++ ++ /// Slice argument ++ #[mockall::concretize] ++ fn boomv

(&self, x: &[P]) where P: AsRef + Send; ++ } ++} ++ ++mod generic_arg { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_foo() ++ .withf(|p| p.as_ref() == Path::new("/tmp")) ++ .times(3) ++ .return_const(()); ++ foo.foo(Path::new("/tmp")); ++ foo.foo(PathBuf::from(Path::new("/tmp"))); ++ foo.foo("/tmp"); ++ } ++} ++ ++mod where_clause { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_boom() ++ .withf(|p| p.as_ref() == Path::new("/tmp")) ++ .times(3) ++ .return_const(()); ++ foo.boom(Path::new("/tmp")); ++ foo.boom(PathBuf::from(Path::new("/tmp"))); ++ foo.boom("/tmp"); ++ } ++} ++ ++mod mutable_reference_arg { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_boom_mutref() ++ .withf(|p| p.as_ref() == "/tmp") ++ .once() ++ .returning(|s| s.as_mut().make_ascii_uppercase()); ++ let mut s = String::from("/tmp"); ++ foo.boom_mutref(&mut s); ++ assert_eq!(s, "/TMP"); ++ } ++} ++ ++mod reference_arg { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_boomref() ++ .withf(|p| p.as_ref() == Path::new("/tmp")) ++ .times(3) ++ .return_const(()); ++ foo.boomref(&Path::new("/tmp")); ++ foo.boomref(&PathBuf::from(Path::new("/tmp"))); ++ foo.boomref(&"/tmp"); ++ } ++} ++ ++mod slice { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_boomv() ++ .withf(|v| ++ v[0].as_ref() == Path::new("/tmp") && ++ v[1].as_ref() == Path::new("/mnt") ++ ).times(3) ++ .return_const(()); ++ foo.boomv(&[Path::new("/tmp"), Path::new("/mnt")]); ++ foo.boomv(&[PathBuf::from("/tmp"), PathBuf::from("/mnt")]); ++ foo.boomv(&["/tmp", "/mnt"]); ++ } ++} ++ ++mod static_method { ++ use super::*; ++ ++ #[test] ++ fn withf() { ++ let ctx = MockFoo::bang_context(); ++ ctx.expect() ++ .withf(|p| p.as_ref() == Path::new("/tmp")) ++ .times(3) ++ .return_const(()); ++ MockFoo::bang(Path::new("/tmp")); ++ MockFoo::bang(PathBuf::from(Path::new("/tmp"))); ++ MockFoo::bang("/tmp"); ++ } ++} +diff --git a/tests/mock_constructor_with_args.rs b/tests/mock_constructor_with_args.rs +new file mode 100644 +index 0000000..c12c442 +--- /dev/null ++++ b/tests/mock_constructor_with_args.rs +@@ -0,0 +1,24 @@ ++// vim: tw=80 ++//! A struct with a constructor method named "new" that has arguments. ++//! mockall should mock the provided method, and not autogenerate a 0-argument ++//! "new" method. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ pub Foo { ++ fn new(x: u32) -> Self; ++ } ++} ++ ++#[test] ++fn returning_once() { ++ let mock = MockFoo::default(); ++ ++ let ctx = MockFoo::new_context(); ++ ctx.expect() ++ .return_once(|_| mock); ++ ++ let _mock = MockFoo::new(5); ++} +diff --git a/tests/mock_debug.rs b/tests/mock_debug.rs +new file mode 100644 +index 0000000..81e30cd +--- /dev/null ++++ b/tests/mock_debug.rs +@@ -0,0 +1,40 @@ ++// vim: tw=80 ++//! A mocked struct should implement Debug ++#![deny(warnings)] ++ ++use mockall::*; ++use std::fmt::{self, Debug, Formatter}; ++ ++// using derive(Debug) tells mockall to generate the Debug impl automatically ++mock!{ ++ #[derive(Debug)] ++ pub Bar { } ++ impl Clone for Bar { ++ fn clone(&self) -> Self; ++ } ++} ++ ++// With no derive(Debug), mockall won't genetate the debug impl automatically ++mock!{ ++ pub Baz { } ++ impl Clone for Baz { ++ fn clone(&self) -> Self; ++ } ++} ++impl Debug for MockBaz { ++ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { ++ f.debug_struct("XXX").finish() ++ } ++} ++ ++#[test] ++fn automatic() { ++ let bar = MockBar::new(); ++ assert_eq!("MockBar", format!("{bar:?}")); ++} ++ ++#[test] ++fn manual() { ++ let baz = MockBaz::new(); ++ assert_eq!("XXX", format!("{baz:?}")); ++} +diff --git a/tests/mock_deref.rs b/tests/mock_deref.rs +new file mode 100644 +index 0000000..852b891 +--- /dev/null ++++ b/tests/mock_deref.rs +@@ -0,0 +1,19 @@ ++// vim: tw=80 ++//! A method that returns a type which is a common target for std::ops::Deref ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ Foo { ++ fn foo(&self) -> &str; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .return_const("Stuff".to_owned()); ++ assert_eq!("Stuff", mock.foo()); ++} +diff --git a/tests/mock_deref_args.rs b/tests/mock_deref_args.rs +new file mode 100644 +index 0000000..d0789d6 +--- /dev/null ++++ b/tests/mock_deref_args.rs +@@ -0,0 +1,120 @@ ++// vim: tw=80 ++//! A method whose argument is a common `Deref` implementor ++#![deny(warnings)] ++ ++use mockall::*; ++use std::{ ++ ffi::{CStr, CString, OsStr, OsString}, ++ path::{Path, PathBuf}, ++}; ++ ++mock! { ++ Foo { ++ fn foo(&self, x: Vec); ++ fn bar(&self, x: String); ++ fn baz(&self, x: CString); ++ fn bean(&self, x: OsString); ++ fn boom(&self, x: PathBuf); ++ } ++} ++ ++mod with { ++ use super::*; ++ ++ #[test] ++ fn cstr() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .with(predicate::eq(CString::new("xxx").unwrap())) ++ .return_const(()); ++ mock.baz(CString::new("xxx").unwrap()); ++ } ++ ++ #[test] ++ fn osstr() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bean() ++ .with(predicate::eq(OsStr::new("xxx").to_owned())) ++ .return_const(()); ++ mock.bean(OsString::from("xxx")); ++ } ++ ++ #[test] ++ fn path() { ++ let mut mock = MockFoo::new(); ++ mock.expect_boom() ++ .with(predicate::eq(Path::new("dir/file").to_owned())) ++ .return_const(()); ++ mock.boom(PathBuf::from("dir/file")); ++ } ++ ++ #[test] ++ fn string() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .with(predicate::eq("xxx".to_owned())) ++ .return_const(()); ++ mock.bar(String::from("xxx")); ++ } ++ ++ #[test] ++ fn vec() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::() ++ .with(predicate::eq(vec![1, 2, 3])) ++ .return_const(()); ++ mock.foo(vec![1, 2, 3]); ++ } ++} ++ ++mod withf { ++ use super::*; ++ ++ #[test] ++ fn cstr() { ++ let mut mock = MockFoo::new(); ++ const WANT: [u8; 4] = [120u8, 120, 120, 0]; ++ let want = CStr::from_bytes_with_nul(&WANT[..]).unwrap(); ++ mock.expect_baz() ++ .withf(move |s| s.as_c_str() == want) ++ .return_const(()); ++ mock.baz(CString::new("xxx").unwrap()); ++ } ++ ++ #[test] ++ fn osstr() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bean() ++ .withf(move |s| s.as_os_str() == OsStr::new("xxx")) ++ .return_const(()); ++ mock.bean(OsString::from("xxx")); ++ } ++ ++ #[test] ++ fn path() { ++ let mut mock = MockFoo::new(); ++ mock.expect_boom() ++ .withf(move |s| s.as_path() == Path::new("dir/file")) ++ .return_const(()); ++ mock.boom(PathBuf::from("dir/file")); ++ } ++ ++ #[test] ++ fn string() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .withf(|sl: &String| sl == "xxx") ++ .return_const(()); ++ mock.bar(String::from("xxx")); ++ } ++ ++ #[test] ++ fn vec() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::() ++ .withf(|sl: &Vec| sl == &[1, 2, 3]) ++ .return_const(()); ++ mock.foo(vec![1, 2, 3]); ++ } ++ ++} +diff --git a/tests/mock_docs.rs b/tests/mock_docs.rs +new file mode 100644 +index 0000000..f1fd7ce +--- /dev/null ++++ b/tests/mock_docs.rs +@@ -0,0 +1,26 @@ ++// vim: tw=80 ++#![deny(missing_docs)] ++#![deny(warnings)] ++ ++use mockall::*; ++ ++// mock! should allow doc comments in all reasonable positions. This test ++// ensures that the code will compile. mockall_derive has a unit test to ensure ++// that the doc comments are correctly placed. ++ ++pub trait Tr { ++ fn bar(&self); ++} ++ ++mock!{ ++ /// Struct docs ++ pub Foo { ++ /// Method docs ++ fn foo(&self); ++ } ++ /// Trait docs ++ impl Tr for Foo { ++ /// Trait method docs ++ fn bar(&self); ++ } ++} +diff --git a/tests/mock_generic_and_reference_arguments.rs b/tests/mock_generic_and_reference_arguments.rs +new file mode 100644 +index 0000000..02f3767 +--- /dev/null ++++ b/tests/mock_generic_and_reference_arguments.rs +@@ -0,0 +1,20 @@ ++// vim: tw=80 ++//! A generic method may have non-generic reference arguments ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ Foo { ++ fn foo(&self, t: T, x: &i16) -> u32; ++ } ++} ++ ++#[test] ++fn with() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::() ++ .with(predicate::eq(4), predicate::eq(5)) ++ .return_const(42u32); ++ assert_eq!(42, mock.foo(4i32, &5i16)); ++} +diff --git a/tests/mock_generic_arguments.rs b/tests/mock_generic_arguments.rs +new file mode 100644 +index 0000000..aa3aaf4 +--- /dev/null ++++ b/tests/mock_generic_arguments.rs +@@ -0,0 +1,68 @@ ++// vim: tw=80 ++//! A struct with a generic method that has generic arguments ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ Foo { ++ fn foo(&self, t: T) -> i32; ++ fn bar(&self, t: T) -> i32; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::() ++ .return_const(0); ++ assert_eq!(0, mock.foo(0i16)); ++} ++ ++mod with { ++ use super::*; ++ ++ /// Multiple generic methods with the same set of generic parameters are in ++ /// scope at the same time. Their expectations should not get scrambled. ++ #[test] ++ fn multiple_methods() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::() ++ .with(predicate::eq(4)) ++ .return_const(0); ++ mock.expect_bar::() ++ .with(predicate::eq(5)) ++ .return_const(0); ++ mock.bar(5i16); ++ mock.foo(4i16); ++ } ++ ++ #[test] ++ fn ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::() ++ .with(predicate::eq(4)) ++ .return_const(0); ++ mock.foo(4i16); ++ } ++ ++ #[test] ++ #[should_panic(expected = "MockFoo::foo(4): No matching expectation found")] ++ fn wrong_generic_type() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::() ++ .with(predicate::eq(4)) ++ .return_const(0); ++ mock.foo(4i32); ++ } ++ ++ #[test] ++ #[should_panic(expected = "MockFoo::bar(?): No matching expectation found")] ++ fn no_debug_trait_bound() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar::() ++ .with(predicate::eq(4)) ++ .return_const(0); ++ mock.bar(4i32); ++ } ++} +diff --git a/tests/mock_generic_arguments_returning_reference.rs b/tests/mock_generic_arguments_returning_reference.rs +new file mode 100644 +index 0000000..ea0ea31 +--- /dev/null ++++ b/tests/mock_generic_arguments_returning_reference.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Foo { ++ fn foo(&self, t: T) -> &u32; ++} ++ ++mock!{ ++ MyStruct {} ++ impl Foo for MyStruct { ++ fn foo(&self, t: T) -> &u32; ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockMyStruct::new(); ++ mock.expect_foo::().return_const(5u32); ++ assert_eq!(5u32, *mock.foo(99i16)); ++} +diff --git a/tests/mock_generic_constructor.rs b/tests/mock_generic_constructor.rs +new file mode 100644 +index 0000000..c81b0cf +--- /dev/null ++++ b/tests/mock_generic_constructor.rs +@@ -0,0 +1,21 @@ ++// vim: tw=80 ++//! A generic struct with bounds on its generic parameters can have a ++//! constructor method ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ pub Foo { ++ fn build() -> MockFoo; ++ } ++} ++ ++#[test] ++fn returning_once() { ++ let ctx = MockFoo::::build_context(); ++ ctx.expect() ++ .return_once(MockFoo::::default); ++ ++ let _mock: MockFoo = MockFoo::::build(); ++} +diff --git a/tests/mock_generic_constructor_with_where_clause.rs b/tests/mock_generic_constructor_with_where_clause.rs +new file mode 100644 +index 0000000..2298ccc +--- /dev/null ++++ b/tests/mock_generic_constructor_with_where_clause.rs +@@ -0,0 +1,21 @@ ++// vim: tw=80 ++//! A generic struct with a where clause on its generic parameters can have a ++//! constructor method ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ pub Foo where T: Default + 'static { ++ fn build() -> MockFoo; ++ } ++} ++ ++#[test] ++fn returning_once() { ++ let ctx = MockFoo::::build_context(); ++ ctx.expect() ++ .return_once(MockFoo::::default); ++ ++ let _mock: MockFoo = MockFoo::::build(); ++} +diff --git a/tests/mock_generic_method_on_generic_struct_returning_nonstatic.rs b/tests/mock_generic_method_on_generic_struct_returning_nonstatic.rs +new file mode 100644 +index 0000000..819e70a +--- /dev/null ++++ b/tests/mock_generic_method_on_generic_struct_returning_nonstatic.rs +@@ -0,0 +1,116 @@ ++//! Mocking a generic method whose return value's lifetime is a generic ++//! parameter on a generic struct requires extra care for the Expectation ++//! object's type generics. ++//! https://github.com/asomers/mockall/issues/306 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[derive(Clone)] ++struct X<'a>(&'a u32); ++ ++trait Bong { ++ fn trait_foo<'a>(&self) -> X<'a>; ++ fn trait_baz<'a>(&self) -> &X<'a>; ++} ++ ++mock! { ++ Thing { ++ fn foo<'a>(&self) -> X<'a>; ++ ++ // XXX static methods don't work yet. ++ // fn bar<'a>() -> X<'a>; ++ ++ fn baz<'a>(&self) -> &X<'a>; ++ ++ // Methods returning a mutable reference to a non-static value won't ++ // work unless 'a is static. I doubt there are any real-life methods ++ // that fit this pattern; open an issue if you find one. ++ //fn bang<'a>(&mut self) -> &mut X<'a>; ++ ++ // Generic methods can't return non-static values either, because ++ // Mockall requires generic methods' generic parameters to implement ++ // std::any::Any, which means they must be 'static. ++ //fn bean<'a, T: 'static>(&self, t: T) -> X<'a>; ++ } ++ // The same types of methods should work if they are Trait methods. ++ impl Bong for Thing { ++ fn trait_foo<'a>(&self) -> X<'a>; ++ fn trait_baz<'a>(&self) -> &X<'a>; ++ } ++} ++ ++#[test] ++fn return_static() { ++ const D: u32 = 42; ++ let x = X(&D); ++ let mut thing = MockThing::::new(); ++ thing.expect_foo() ++ .return_const(x); ++ ++ assert_eq!(42u32, *thing.foo().0); ++} ++ ++#[test] ++fn return_static_ref() { ++ const D: u32 = 42; ++ let x = X(&D); ++ let mut thing = MockThing::::new(); ++ thing.expect_baz() ++ .return_const(x); ++ ++ assert_eq!(42u32, *thing.baz().0); ++} ++ ++// It isn't possible to safely set an expectation for a non-'static return value ++// (because the mock object doesn't have any lifetime parameters itself), but ++// unsafely setting such an expectation is a common use case. ++#[test] ++fn return_nonstatic() { ++ let d = 42u32; ++ let x = X(&d); ++ let xstatic: X<'static> = unsafe{ std::mem::transmute(x) }; ++ let mut thing = MockThing::::new(); ++ thing.expect_foo() ++ .returning(move || xstatic.clone()); ++ ++ assert_eq!(42u32, *thing.foo().0); ++} ++ ++mod trait_methods { ++ use super::*; ++ ++ #[test] ++ fn return_static() { ++ const D: u32 = 42; ++ let x = X(&D); ++ let mut thing = MockThing::::new(); ++ thing.expect_trait_foo() ++ .return_const(x); ++ ++ assert_eq!(42u32, *thing.trait_foo().0); ++ } ++ ++ #[test] ++ fn return_static_ref() { ++ const D: u32 = 42; ++ let x = X(&D); ++ let mut thing = MockThing::::new(); ++ thing.expect_trait_baz() ++ .return_const(x); ++ ++ assert_eq!(42u32, *thing.trait_baz().0); ++ } ++ ++ #[test] ++ fn return_nonstatic() { ++ let d = 42u32; ++ let x = X(&d); ++ let xstatic: X<'static> = unsafe{ std::mem::transmute(x) }; ++ let mut thing = MockThing::::new(); ++ thing.expect_trait_foo() ++ .returning(move || xstatic.clone()); ++ ++ assert_eq!(42u32, *thing.trait_foo().0); ++ } ++} +diff --git a/tests/mock_generic_method_returning_nonstatic.rs b/tests/mock_generic_method_returning_nonstatic.rs +new file mode 100644 +index 0000000..7b85ee1 +--- /dev/null ++++ b/tests/mock_generic_method_returning_nonstatic.rs +@@ -0,0 +1,117 @@ ++// vim: tw=80 ++//! A generic method whose return value's lifetime is a generic parameter is a ++//! special case. Mockall can only mock such methods if the expectation is ++//! 'static. ++//! https://github.com/asomers/mockall/issues/76 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[derive(Clone)] ++struct X<'a>(&'a u32); ++ ++trait Bong { ++ fn trait_foo<'a>(&self) -> X<'a>; ++ fn trait_baz<'a>(&self) -> &X<'a>; ++} ++ ++mock! { ++ Thing { ++ fn foo<'a>(&self) -> X<'a>; ++ ++ // XXX static methods don't work yet. ++ // fn bar<'a>() -> X<'a>; ++ ++ fn baz<'a>(&self) -> &X<'a>; ++ ++ // Methods returning a mutable reference to a non-static value won't ++ // work unless 'a is static. I doubt there are any real-life methods ++ // that fit this pattern; open an issue if you find one. ++ // fn bang<'a>(&mut self) -> &mut X<'a>; ++ ++ // Generic methods can't return non-static values either, because ++ // Mockall requires generic methods' generic parameters to implement ++ // std::any::Any, which means they must be 'static. ++ //fn bean<'a, T: 'static>(&self, t: T) -> X<'a>; ++ } ++ // The same types of methods should work if they are Trait methods. ++ impl Bong for Thing { ++ fn trait_foo<'a>(&self) -> X<'a>; ++ fn trait_baz<'a>(&self) -> &X<'a>; ++ } ++} ++ ++#[test] ++fn return_static() { ++ const D: u32 = 42; ++ let x = X(&D); ++ let mut thing = MockThing::new(); ++ thing.expect_foo() ++ .return_const(x); ++ ++ assert_eq!(42u32, *thing.foo().0); ++} ++ ++#[test] ++fn return_static_ref() { ++ const D: u32 = 42; ++ let x = X(&D); ++ let mut thing = MockThing::new(); ++ thing.expect_baz() ++ .return_const(x); ++ ++ assert_eq!(42u32, *thing.baz().0); ++} ++ ++// It isn't possible to safely set an expectation for a non-'static return value ++// (because the mock object doesn't have any lifetime parameters itself), but ++// unsafely setting such an expectation is a common use case. ++#[test] ++fn return_nonstatic() { ++ let d = 42u32; ++ let x = X(&d); ++ let xstatic: X<'static> = unsafe{ std::mem::transmute(x) }; ++ let mut thing = MockThing::new(); ++ thing.expect_foo() ++ .returning(move || xstatic.clone()); ++ ++ assert_eq!(42u32, *thing.foo().0); ++} ++ ++mod trait_methods { ++ use super::*; ++ ++ #[test] ++ fn return_static() { ++ const D: u32 = 42; ++ let x = X(&D); ++ let mut thing = MockThing::new(); ++ thing.expect_trait_foo() ++ .return_const(x); ++ ++ assert_eq!(42u32, *thing.trait_foo().0); ++ } ++ ++ #[test] ++ fn return_static_ref() { ++ const D: u32 = 42; ++ let x = X(&D); ++ let mut thing = MockThing::new(); ++ thing.expect_trait_baz() ++ .return_const(x); ++ ++ assert_eq!(42u32, *thing.trait_baz().0); ++ } ++ ++ #[test] ++ fn return_nonstatic() { ++ let d = 42u32; ++ let x = X(&d); ++ let xstatic: X<'static> = unsafe{ std::mem::transmute(x) }; ++ let mut thing = MockThing::new(); ++ thing.expect_trait_foo() ++ .returning(move || xstatic.clone()); ++ ++ assert_eq!(42u32, *thing.trait_foo().0); ++ } ++} +diff --git a/tests/mock_generic_method_with_lifetime_parameter.rs b/tests/mock_generic_method_with_lifetime_parameter.rs +new file mode 100644 +index 0000000..3a3d97d +--- /dev/null ++++ b/tests/mock_generic_method_with_lifetime_parameter.rs +@@ -0,0 +1,65 @@ ++// vim: tw=80 ++//! A generic method whose only generic parameter is a lifetime parameter is, ++//! from Mockall's perspective, pretty much the same as a non-generic method. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[derive(Debug, Eq)] ++struct X<'a>(&'a u32); ++ ++impl<'a> PartialEq for X<'a> { ++ fn eq(&self, other: &X<'a>) -> bool { ++ self.0 == other.0 ++ } ++} ++ ++mock!{ ++ Foo { ++ fn foo<'a>(&self, x: &'a X<'a>) -> u32; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .return_const(42u32); ++ let x = X(&5); ++ assert_eq!(42, mock.foo(&x)); ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|f| *f.0); ++ let x = X(&5); ++ assert_eq!(5, mock.foo(&x)); ++} ++ ++// I can't get this to work. How can I create a Predicate that's valid for all ++// lifetimes? 'static should be reduceable to any other lifetime, but rustc ++// doesn't seem to understand that. ++//#[test] ++//fn with() { ++ //const X1: u32 = 5; ++ //const OTHER: X<'static> = X(&X1); ++ //let mut mock = MockFoo::new(); ++ //mock.expect_foo() ++ //.with(mockall::predicate::eq(&OTHER)) ++ //.return_const(42u32); ++ //let inner = 5; ++ //let x = X(&5); ++ //assert_eq!(42, mock.foo(&x)); ++//} ++ ++#[test] ++fn withf() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .withf(|f| *f.0 == 5) ++ .return_const(42u32); ++ let x = X(&5); ++ assert_eq!(42, mock.foo(&x)); ++} +diff --git a/tests/mock_generic_method_with_where_clause.rs b/tests/mock_generic_method_with_where_clause.rs +new file mode 100644 +index 0000000..8aaa7cb +--- /dev/null ++++ b/tests/mock_generic_method_with_where_clause.rs +@@ -0,0 +1,43 @@ ++// vim: tw=80 ++#![deny(warnings)] ++use mockall::*; ++ ++struct G where T: Copy {t: T} ++ ++mock! { ++ Foo { ++ fn foo(&self, t: T) -> G where T: Copy + 'static; ++ fn bar(&self, g: G) -> T where T: Copy + 'static; ++ fn baz(&self) -> &G where T: Copy + 'static; ++ fn bean(&mut self) -> &mut G where T: Copy + 'static; ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::() ++ .returning(|t| G{t}); ++ assert_eq!(42, mock.foo(42u32).t); ++ ++ mock.expect_bar::() ++ .returning(|g| g.t); ++ assert_eq!(42u32, mock.bar(G{t: 42})); ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz::() ++ .return_const(G{t: 42}); ++ assert_eq!(42u32, mock.baz().t); ++} ++ ++#[test] ++fn return_var() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bean::() ++ .return_var(G{t: 42}); ++ mock.bean::().t += 1; ++ assert_eq!(43u32, mock.bean().t); ++} +diff --git a/tests/mock_generic_methods_returning_mutable_reference.rs b/tests/mock_generic_methods_returning_mutable_reference.rs +new file mode 100644 +index 0000000..1e708b6 +--- /dev/null ++++ b/tests/mock_generic_methods_returning_mutable_reference.rs +@@ -0,0 +1,18 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock!{ ++ MyStruct { ++ fn foo(&mut self, t: T) -> &mut u32; ++ } ++} ++ ++#[test] ++fn return_var() { ++ let mut mock = MockMyStruct::new(); ++ mock.expect_foo::().return_var(5u32); ++ *mock.foo(1i16) += 1; ++ assert_eq!(6u32, *mock.foo(2i16)); ++} +diff --git a/tests/mock_generic_return.rs b/tests/mock_generic_return.rs +new file mode 100644 +index 0000000..8fd2a0a +--- /dev/null ++++ b/tests/mock_generic_return.rs +@@ -0,0 +1,19 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ Foo { ++ fn foo(&self) -> O; ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::().return_const(42i32); ++ mock.expect_foo::().return_const(69u16); ++ assert_eq!(42i32, mock.foo()); ++ assert_eq!(69u16, mock.foo()); ++} +diff --git a/tests/mock_generic_static_method_with_where_clause.rs b/tests/mock_generic_static_method_with_where_clause.rs +new file mode 100644 +index 0000000..f70d4c7 +--- /dev/null ++++ b/tests/mock_generic_static_method_with_where_clause.rs +@@ -0,0 +1,24 @@ ++// vim: tw=80 ++#![deny(warnings)] ++// multiple bound locations is deliberate; we want to ensure that Mockall can ++// handle it correctly. ++#![allow(clippy::multiple_bound_locations)] ++ ++use mockall::*; ++ ++struct G where T: Copy {t: T} ++ ++mock! { ++ Foo { ++ fn make_g(x: T) -> G where T: Copy; ++ } ++} ++ ++#[test] ++fn returning() { ++ let ctx = MockFoo::make_g_context(); ++ ctx.expect::() ++ .returning(|t| G{t}); ++ let g = MockFoo::make_g(42i16); ++ assert_eq!(g.t, 42i16); ++} +diff --git a/tests/mock_generic_struct.rs b/tests/mock_generic_struct.rs +new file mode 100644 +index 0000000..0863b44 +--- /dev/null ++++ b/tests/mock_generic_struct.rs +@@ -0,0 +1,33 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[derive(Clone)] ++struct NonCopy(u32); ++ ++// A struct with a definition like this: ++// pub struct ExtGenericStruct { ++// _x: i16 ++// } ++// impl ExtGenericStruct { ++// fn foo(&self, _x: T) -> T { ++// 42 ++// } ++// } ++// Could be mocked like this: ++mock!{ ++ pub ExtGenericStruct { ++ fn foo(&self, x: T) -> T; ++ } ++} ++ ++#[test] ++#[allow(clippy::redundant_clone)] ++fn returning() { ++ let mut mock = MockExtGenericStruct::::new(); ++ // An explicit .clone() is required so as not to return by move ++ mock.expect_foo() ++ .returning(|x| x.clone()); ++ assert_eq!(5, mock.foo(NonCopy(5)).0); ++} +diff --git a/tests/mock_generic_struct_with_bounds.rs b/tests/mock_generic_struct_with_bounds.rs +new file mode 100644 +index 0000000..4f15836 +--- /dev/null ++++ b/tests/mock_generic_struct_with_bounds.rs +@@ -0,0 +1,17 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ pub Foo { ++ fn foo(&self, x: u32) -> i64; ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::::new(); ++ mock.expect_foo().returning(i64::from); ++ assert_eq!(5, mock.foo(5)); ++} +diff --git a/tests/mock_generic_struct_with_generic_method.rs b/tests/mock_generic_struct_with_generic_method.rs +new file mode 100644 +index 0000000..92fc46f +--- /dev/null ++++ b/tests/mock_generic_struct_with_generic_method.rs +@@ -0,0 +1,18 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock!{ ++ pub Foo { ++ fn foo(&self, q: Q) -> T; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::::new(); ++ mock.expect_foo::() ++ .return_const(100_000u32); ++ assert_eq!(100_000, mock.foo(-5i16)); ++} +diff --git a/tests/mock_generic_struct_with_generic_static_method.rs b/tests/mock_generic_struct_with_generic_static_method.rs +new file mode 100644 +index 0000000..1f93f3f +--- /dev/null ++++ b/tests/mock_generic_struct_with_generic_static_method.rs +@@ -0,0 +1,102 @@ ++// vim: tw=80 ++//! A generic struct with a generic method on a different parameter ++#![deny(warnings)] ++ ++use mockall::*; ++use std::sync::Mutex; ++ ++mock! { ++ Foo { ++ fn foo(t: T, q: Q) -> u64; ++ } ++} ++ ++static FOO_MTX: Mutex<()> = Mutex::new(()); ++ ++// Checkpointing the mock object should not checkpoint static methods too ++#[test] ++fn checkpoint() { ++ let _m = FOO_MTX.lock(); ++ ++ let mut mock = MockFoo::::new(); ++ let ctx = MockFoo::::foo_context(); ++ ctx.expect::() ++ .returning(|_, _| 0) ++ .times(1..3); ++ mock.checkpoint(); ++ MockFoo::foo(42u32, 69i16); ++} ++ ++// It should also be possible to checkpoint just the context object ++#[test] ++#[should_panic(expected = ++ "MockFoo::foo: Expectation() called 0 time(s) which is fewer than expected 1")] ++fn ctx_checkpoint() { ++ let _m = FOO_MTX.lock(); ++ let ctx = MockFoo::::foo_context(); ++ ctx.expect::() ++ .returning(|_, _| 0) ++ .times(1..3); ++ ctx.checkpoint(); ++ panic!("Shouldn't get here!"); ++} ++ ++// Expectations should be cleared when a context object drops ++#[test] ++#[should_panic(expected = "MockFoo::foo(42, 69): No matching expectation found")] ++fn ctx_hygiene() { ++ let _m = FOO_MTX.lock(); ++ { ++ let ctx0 = MockFoo::::foo_context(); ++ ctx0.expect::() ++ .returning(|_, _| 0); ++ } ++ MockFoo::foo(42, 69); ++} ++ ++#[cfg_attr(not(feature = "nightly"), ignore)] ++#[cfg_attr(not(feature = "nightly"), allow(unused_must_use))] ++#[test] ++fn return_default() { ++ let _m = FOO_MTX.lock(); ++ ++ let ctx = MockFoo::::foo_context(); ++ ctx.expect::(); ++ MockFoo::foo(5u32, 6i16); ++} ++ ++#[test] ++fn returning() { ++ let _m = FOO_MTX.lock(); ++ ++ let ctx = MockFoo::::foo_context(); ++ ctx.expect::() ++ .returning(|_, _| 0); ++ MockFoo::foo(41u32, 42i16); ++} ++ ++#[test] ++fn two_matches() { ++ let _m = FOO_MTX.lock(); ++ ++ let ctx = MockFoo::::foo_context(); ++ ctx.expect::() ++ .with(predicate::eq(42u32), predicate::eq(0i16)) ++ .return_const(99u64); ++ ctx.expect::() ++ .with(predicate::eq(69u32), predicate::eq(0i16)) ++ .return_const(101u64); ++ assert_eq!(101, MockFoo::foo(69u32, 0i16)); ++ assert_eq!(99, MockFoo::foo(42u32, 0i16)); ++} ++ ++#[test] ++fn with() { ++ let _m = FOO_MTX.lock(); ++ ++ let ctx = MockFoo::::foo_context(); ++ ctx.expect::() ++ .with(predicate::eq(42u32), predicate::eq(99i16)) ++ .returning(|_, _| 0); ++ MockFoo::foo(42u32, 99i16); ++} +diff --git a/tests/mock_generic_struct_with_generic_trait.rs b/tests/mock_generic_struct_with_generic_trait.rs +new file mode 100644 +index 0000000..c955441 +--- /dev/null ++++ b/tests/mock_generic_struct_with_generic_trait.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Foo { ++ fn foo(&self, x: T) -> T; ++} ++mock! { ++ Bar {} ++ impl Foo for Bar { ++ fn foo(&self, x: T) -> T; ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockBar::::new(); ++ mock.expect_foo() ++ .returning(|x| x); ++ assert_eq!(5u32, mock.foo(5u32)); ++} +diff --git a/tests/mock_generic_struct_with_generic_trait_with_different_bounds.rs b/tests/mock_generic_struct_with_generic_trait_with_different_bounds.rs +new file mode 100644 +index 0000000..efb0d58 +--- /dev/null ++++ b/tests/mock_generic_struct_with_generic_trait_with_different_bounds.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Foo { ++ fn foo(&self, x: T) -> T; ++} ++mock! { ++ Bar {} ++ impl Foo for Bar { ++ fn foo(&self, x: T) -> T; ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockBar::::new(); ++ mock.expect_foo() ++ .returning(|x| x); ++ assert_eq!(5u32, mock.foo(5u32)); ++} +diff --git a/tests/mock_generic_struct_with_nondefault_parameter.rs b/tests/mock_generic_struct_with_nondefault_parameter.rs +new file mode 100644 +index 0000000..40bfd82 +--- /dev/null ++++ b/tests/mock_generic_struct_with_nondefault_parameter.rs +@@ -0,0 +1,37 @@ ++// vim: tw=80 ++//! mock a generic struct and instantiate it with a parameter type that does not ++//! implement Default ++#![deny(warnings)] ++ ++use mockall::*; ++ ++struct NonDefault(); ++ ++trait Foo { ++ fn foo(&self) -> T; ++} ++mock! { ++ ExternalStruct {} ++ impl Foo for ExternalStruct { ++ fn foo(&self) -> T; ++ } ++} ++ ++#[test] ++#[should_panic(expected = ++ "MockExternalStruct::foo: Expectation() Can only return default values for types that impl std::Default")] ++#[cfg_attr(not(feature = "nightly"), ignore)] ++#[cfg_attr(not(feature = "nightly"), allow(unused_must_use))] ++fn return_default() { ++ let mut mock = MockExternalStruct::::new(); ++ mock.expect_foo(); ++ mock.foo(); ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockExternalStruct::::new(); ++ mock.expect_foo() ++ .returning(NonDefault); ++ mock.foo(); ++} +diff --git a/tests/mock_generic_struct_with_static_method.rs b/tests/mock_generic_struct_with_static_method.rs +new file mode 100644 +index 0000000..6b2928b +--- /dev/null ++++ b/tests/mock_generic_struct_with_static_method.rs +@@ -0,0 +1,21 @@ ++// vim: tw=80 ++//! static non-generic methods of generic structs shouldn't require any special ++//! treatment when mocking. Prior to version 0.3.0, the struct's generic ++//! parameters had to be duplicated as generic parameters of the method. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ Foo { ++ fn foo(t: T); ++ } ++} ++ ++#[test] ++fn returning() { ++ let ctx = MockFoo::::foo_context(); ++ ctx.expect() ++ .returning(|_| ()); ++ MockFoo::foo(42u32); ++} +diff --git a/tests/mock_generic_struct_with_trait.rs b/tests/mock_generic_struct_with_trait.rs +new file mode 100644 +index 0000000..a772c99 +--- /dev/null ++++ b/tests/mock_generic_struct_with_trait.rs +@@ -0,0 +1,23 @@ ++// vim: ts=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Foo { ++ fn foo(&self, x: u32) -> u32; ++} ++ ++mock! { ++ Bar {} ++ impl Foo for Bar { ++ fn foo(&self, x: u32) -> u32; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockBar::::new(); ++ mock.expect_foo() ++ .return_const(43u32); ++ assert_eq!(43, mock.foo(42)); ++} +diff --git a/tests/mock_generic_struct_with_trait_with_associated_types.rs b/tests/mock_generic_struct_with_trait_with_associated_types.rs +new file mode 100644 +index 0000000..ced6e9e +--- /dev/null ++++ b/tests/mock_generic_struct_with_trait_with_associated_types.rs +@@ -0,0 +1,20 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ Foo {} ++ impl Iterator for Foo { ++ type Item=T; ++ fn next(&mut self) -> Option; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::::new(); ++ mock.expect_next() ++ .return_const(None); ++ assert!(mock.next().is_none()); ++} +diff --git a/tests/mock_generic_struct_with_where_clause.rs b/tests/mock_generic_struct_with_where_clause.rs +new file mode 100644 +index 0000000..14a8e10 +--- /dev/null ++++ b/tests/mock_generic_struct_with_where_clause.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++//! A generic struct with a where clause ++#![deny(warnings)] ++ ++// An explicit clone is required so as not to return by move ++#![allow(clippy::clone_on_copy)] ++ ++use mockall::*; ++ ++mock! { ++ Foo where T:Clone { ++ fn foo(&self, t: T) -> T; ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|t: u32| t.clone()); ++ assert_eq!(5u32, mock.foo(5u32)); ++} +diff --git a/tests/mock_generic_struct_with_where_clause_and_trait.rs b/tests/mock_generic_struct_with_where_clause_and_trait.rs +new file mode 100644 +index 0000000..fd9b5ac +--- /dev/null ++++ b/tests/mock_generic_struct_with_where_clause_and_trait.rs +@@ -0,0 +1,31 @@ ++// vim: tw=80 ++//! A generic struct with a where clause, that also implements a trait ++#![deny(warnings)] ++ ++// An explicit clone is required so as not to return by move ++#![allow(clippy::clone_on_copy)] ++ ++use mockall::*; ++ ++trait Bar { ++ fn bar(&self); ++} ++mock! { ++ Foo where T: Clone { ++ fn foo(&self, t: T) -> T; ++ } ++ impl Bar for Foo where T: Clone { ++ fn bar(&self); ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|t: u32| t.clone()); ++ mock.expect_bar() ++ .returning(|| ()); ++ assert_eq!(5u32, mock.foo(5u32)); ++ mock.bar(); ++} +diff --git a/tests/mock_generic_trait.rs b/tests/mock_generic_trait.rs +new file mode 100644 +index 0000000..24413bc +--- /dev/null ++++ b/tests/mock_generic_trait.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Foo { ++ fn foo(&self); ++} ++ ++mock! { ++ Bar {} ++ impl Foo for Bar { ++ fn foo(&self); ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockBar::::new(); ++ mock.expect_foo().return_const(()); ++ mock.foo(); ++} +diff --git a/tests/mock_impl_generic_trait.rs b/tests/mock_impl_generic_trait.rs +new file mode 100644 +index 0000000..6819c81 +--- /dev/null ++++ b/tests/mock_impl_generic_trait.rs +@@ -0,0 +1,22 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait MyTrait {} ++ ++struct MyStruct(T); ++impl MyTrait for MyStruct {} ++ ++mock!{ ++ Foo { ++ fn foo(&self) -> impl MyTrait; ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::().returning(|| Box::new(MyStruct(42u32))); ++ let _mto: Box> = mock.foo(); ++} +diff --git a/tests/mock_impl_trait.rs b/tests/mock_impl_trait.rs +new file mode 100644 +index 0000000..fb1bb7a +--- /dev/null ++++ b/tests/mock_impl_trait.rs +@@ -0,0 +1,19 @@ ++// vim: tw=80 ++//! a method that returns impl Trait ++#![deny(warnings)] ++ ++use mockall::*; ++use std::fmt::Debug; ++ ++mock!{ ++ Foo { ++ fn foo(&self) -> impl Debug + Send; ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo().returning(|| Box::new(4)); ++ format!("{:?}", mock.foo()); ++} +diff --git a/tests/mock_inherited_traits.rs b/tests/mock_inherited_traits.rs +new file mode 100644 +index 0000000..940b822 +--- /dev/null ++++ b/tests/mock_inherited_traits.rs +@@ -0,0 +1,32 @@ ++// vim: tw=80 ++//! A struct that implements a trait that inherits another trait ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait A { ++ fn foo(&self); ++} ++ ++trait B: A { ++ fn bar(&self); ++} ++ ++mock!{ ++ B {} ++ impl A for B { ++ fn foo(&self); ++ } ++ impl B for B { ++ fn bar(&self); ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockB::new(); ++ mock.expect_foo().returning(|| ()); ++ mock.expect_bar().returning(|| ()); ++ mock.foo(); ++ mock.bar(); ++} +diff --git a/tests/mock_life0.rs b/tests/mock_life0.rs +new file mode 100644 +index 0000000..722f78e +--- /dev/null ++++ b/tests/mock_life0.rs +@@ -0,0 +1,16 @@ ++// vim: tw=80 ++//! mock a method whose self parameter has an explicit lifetime ++//! https://github.com/asomers/mockall/issues/95 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock!{ ++ Foo { ++ fn foo<'life0>(&'life0 self, x: u32) -> u32; ++ } ++} ++ ++// TODO: test that the mock method respects the lifetime bound, once Mockall ++// supports mocking non-static structs ++// (https://github.com/asomers/mockall/issues/4) +diff --git a/tests/mock_multiple_generic_arguments.rs b/tests/mock_multiple_generic_arguments.rs +new file mode 100644 +index 0000000..1221c71 +--- /dev/null ++++ b/tests/mock_multiple_generic_arguments.rs +@@ -0,0 +1,18 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++ ++mock! { ++ Foo { ++ fn foo(&self, t: T, q: Q); ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo::().return_const(()); ++ mock.foo(0i16, 1i32) ++} +diff --git a/tests/mock_multiple_traits.rs b/tests/mock_multiple_traits.rs +new file mode 100644 +index 0000000..df4c0e1 +--- /dev/null ++++ b/tests/mock_multiple_traits.rs +@@ -0,0 +1,21 @@ ++// vim: tw=80 ++//! A struct that implements multiple traits ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait A {} ++trait B {} ++mock!{ ++ MultiTrait {} ++ impl A for MultiTrait {} ++ impl B for MultiTrait {} ++} ++ ++#[test] ++fn new() { ++ fn foo(_t: T) {} ++ ++ let mock = MockMultiTrait::new(); ++ foo(mock); ++} +diff --git a/tests/mock_nonlocal_trait.rs b/tests/mock_nonlocal_trait.rs +new file mode 100644 +index 0000000..5a140c6 +--- /dev/null ++++ b/tests/mock_nonlocal_trait.rs +@@ -0,0 +1,28 @@ ++// vim: tw=80 ++//! A trait that isn't imported directly into the local namespace ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mod my_module { ++ pub trait Foo { ++ fn foo(&self) -> i32; ++ } ++} ++ ++mock! { ++ Bar {} ++ impl my_module::Foo for Bar { ++ fn foo(&self) -> i32; ++ } ++} ++ ++#[test] ++fn returning() { ++ use my_module::Foo; ++ ++ let mut mock = MockBar::new(); ++ mock.expect_foo() ++ .returning(|| 42); ++ assert_eq!(42, mock.foo()); ++} +diff --git a/tests/mock_nonpub.rs b/tests/mock_nonpub.rs +new file mode 100644 +index 0000000..a349175 +--- /dev/null ++++ b/tests/mock_nonpub.rs +@@ -0,0 +1,37 @@ ++// vim: tw=80 ++//! methods can use non-public types, as long as the object's visibility is ++//! compatible. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mod outer { ++ struct SuperT(); ++ trait SuperTrait {} ++ ++ mod inner { ++ use super::super::mock; ++ ++ pub(crate) struct PubCrateT(); ++ struct PrivT(); ++ ++ mock! { ++ Foo { ++ fn foo(&self, x: PubCrateT) -> PubCrateT; ++ fn bar(&self, x: PrivT) -> PrivT; ++ fn baz(&self, x: super::SuperT) -> super::SuperT; ++ fn refbaz(&self, x: super::SuperT) -> &super::SuperT; ++ fn refmutbaz(&mut self, x: super::SuperT) -> &mut super::SuperT; ++ fn staticbaz(x: super::SuperT) -> super::SuperT; ++ fn bang(&self, x: crate::outer::SuperT) -> crate::outer::SuperT; ++ fn bean(&self, x: self::PrivT) -> self::PrivT; ++ fn goo(t: T); ++ fn goo_wc(t: T) where T: super::SuperTrait + 'static; ++ fn boob super::SuperT + 'static>(&self, f: F) ++ -> u32; ++ fn boobwc(&self, f: F) -> u32 ++ where F: Fn(u32) -> super::SuperT + 'static; ++ } ++ } ++ } ++} +diff --git a/tests/mock_ref_and_nonref_arguments.rs b/tests/mock_ref_and_nonref_arguments.rs +new file mode 100644 +index 0000000..b5330df +--- /dev/null ++++ b/tests/mock_ref_and_nonref_arguments.rs +@@ -0,0 +1,34 @@ ++// vim: tw=80 ++//! A method that has both a reference and a nonreference argument ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock!{ ++ Foo { ++ fn foo(&self, i0: i32, i1: &u16) -> i32; ++ } ++} ++ ++#[test] ++fn with() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .with(predicate::eq(42), predicate::eq(1)) ++ .returning(|x, y| x + i32::from(*y)); ++ let x = 42i32; ++ let y = 1u16; ++ assert_eq!(43i32, mock.foo(x, &y)); ++} ++ ++#[test] ++fn withf() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .withf(|x, y| *x == i32::from(*y)) ++ .returning(|x, y| x + i32::from(*y)); ++ let x = 42i32; ++ let y = 42u16; ++ assert_eq!(84i32, mock.foo(x, &y)); ++} ++ +diff --git a/tests/mock_reference_arguments.rs b/tests/mock_reference_arguments.rs +new file mode 100644 +index 0000000..53761b5 +--- /dev/null ++++ b/tests/mock_reference_arguments.rs +@@ -0,0 +1,142 @@ ++// vim: tw=80 ++//! A struct with methods that take arguments by reference ++#![deny(warnings)] ++ ++use mockall::*; ++ ++const X: u32 = 99; ++ ++mock!{ ++ Foo { ++ fn foo(&self, x: &u32) -> u32; ++ fn bar(&self, y: &'static u32); ++ } ++} ++ ++mod r#match { ++ use super::*; ++ ++ #[test] ++ fn with() { ++ const Y: u32 = 5; ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .with(predicate::eq(5u32)) ++ .returning(|x| *x); ++ mock.expect_bar() ++ .with(predicate::eq(99u32)) ++ .returning(|_| ()); ++ let r = mock.foo(&Y); ++ assert_eq!(5, r); ++ mock.bar(&X); ++ } ++ ++ #[test] ++ fn withf() { ++ const Y: u32 = 5; ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .withf(|x| *x == 5) ++ .returning(|x| *x); ++ mock.expect_bar() ++ .withf(|x| *x == 99) ++ .returning(|_| ()); ++ let r = mock.foo(&Y); ++ assert_eq!(5, r); ++ mock.bar(&X); ++ } ++} ++ ++mod times { ++ use super::*; ++ const X: u32 = 42; ++ ++ #[test] ++ fn ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| 0) ++ .times(2); ++ mock.foo(&X); ++ mock.foo(&X); ++ } ++ ++ #[test] ++ #[should_panic( ++ expected = "MockFoo::foo: Expectation() called 1 time(s) which is fewer than expected 2" ++ )] ++ fn too_few() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| 0) ++ .times(2); ++ mock.foo(&X); ++ } ++ ++ #[test] ++ #[should_panic( ++ expected = "MockFoo::foo: Expectation() called 3 times which is more than the expected 2" ++ )] ++ fn too_many() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| 0) ++ .times(2); ++ mock.foo(&X); ++ mock.foo(&X); ++ mock.foo(&X); ++ // Verify that we panic quickly and don't reach code below this point. ++ panic!("Shouldn't get here!"); ++ } ++ ++ #[test] ++ fn range_ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| 0) ++ .times(2..4); ++ mock.foo(&X); ++ mock.foo(&X); ++ } ++ ++ #[test] ++ #[should_panic( ++ expected = "MockFoo::foo: Expectation() called 1 time(s) which is fewer than expected 2" ++ )] ++ fn range_too_few() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| 0) ++ .times(2..4); ++ mock.foo(&X); ++ } ++ ++ #[test] ++ #[should_panic( ++ expected = "MockFoo::foo: Expectation() called 4 times which is more than the expected 3" ++ )] ++ fn range_too_many() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| 0) ++ .times(2..4); ++ mock.foo(&X); ++ mock.foo(&X); ++ mock.foo(&X); ++ mock.foo(&X); ++ // Verify that we panic quickly and don't reach code below this point. ++ panic!("Shouldn't get here!"); ++ } ++} ++ ++#[test] ++fn times_full() { ++ const X: u32 = 42; ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| 0) ++ .times(1) ++ .times(..); ++ mock.foo(&X); ++ mock.foo(&X); ++} +diff --git a/tests/mock_refmut_arguments.rs b/tests/mock_refmut_arguments.rs +new file mode 100644 +index 0000000..66589c4 +--- /dev/null ++++ b/tests/mock_refmut_arguments.rs +@@ -0,0 +1,52 @@ ++// vim: tw=80 ++//! A struct with methods that take arguments by mutable reference. ++#![deny(warnings)] ++ ++use std::mem; ++ ++use mockall::*; ++ ++mock!{ ++ Foo { ++ fn foo(&self, x: &mut u32); ++ // This is almost never safe, but it should still work. ++ fn bar(&self, y: &'static mut u32); ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut x: u32 = 5; ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .withf(|x| *x == 5) ++ .returning(|x| { *x = 42;} ); ++ mock.foo(&mut x); ++ assert_eq!(x, 42); ++} ++ ++#[test] ++fn with() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .with(predicate::eq(0u32)) ++ .returning(|x| {*x = 6;}); ++ mock.expect_foo() ++ .with(predicate::eq(42u32)) ++ .returning(|x| {*x = 5;}); ++ let mut x = 42u32; ++ mock.foo(&mut x); ++ assert_eq!(5, x); ++} ++ ++#[test] ++fn static_mut() { ++ let mut x: u32 = 5; ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .withf(|x| *x == 5) ++ .returning(|x| { *x = 42;} ); ++ // Safe because mock leaves scope before x ++ unsafe { mock.bar(mem::transmute(&mut x)); } ++ assert_eq!(x, 42); ++} +diff --git a/tests/mock_return_anonymous_lifetime.rs b/tests/mock_return_anonymous_lifetime.rs +new file mode 100644 +index 0000000..1713c57 +--- /dev/null ++++ b/tests/mock_return_anonymous_lifetime.rs +@@ -0,0 +1,54 @@ ++// vim: tw=80 ++//! A mock method should be able to return an object parameterized on the ++//! anonymous lifetime. ++//! https://github.com/asomers/mockall/issues/87 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[derive(Clone)] ++struct X<'a>(&'a u32); ++ ++trait T { ++ fn trait_method(&self) -> X<'_>; ++} ++ ++mock! { ++ Foo { ++ fn inherent_method(&self) -> X<'_>; ++ } ++ impl T for Foo { ++ fn trait_method(&self) -> X<'_>; ++ } ++} ++ ++// It isn't possible to safely set an expectation for a non-'static return value ++// (because the mock object doesn't have any lifetime parameters itself), but ++// unsafely setting such an expectation is a common use case. ++mod return_nonstatic { ++ use super::*; ++ ++ #[test] ++ fn inherent_method() { ++ let d = 42u32; ++ let x = X(&d); ++ let xstatic: X<'static> = unsafe{ std::mem::transmute(x) }; ++ let mut mock = MockFoo::new(); ++ mock.expect_inherent_method() ++ .returning(move || xstatic.clone()); ++ ++ assert_eq!(42u32, *mock.inherent_method().0); ++ } ++ #[test] ++ fn trait_method() { ++ let d = 42u32; ++ let x = X(&d); ++ let xstatic: X<'static> = unsafe{ std::mem::transmute(x) }; ++ let mut mock = MockFoo::new(); ++ mock.expect_trait_method() ++ .returning(move || xstatic.clone()); ++ ++ assert_eq!(42u32, *mock.trait_method().0); ++ } ++ ++} +diff --git a/tests/mock_return_dyn_trait.rs b/tests/mock_return_dyn_trait.rs +new file mode 100644 +index 0000000..a22ea60 +--- /dev/null ++++ b/tests/mock_return_dyn_trait.rs +@@ -0,0 +1,57 @@ ++// vim: tw=80 ++//! a method that returns a reference to a trait object ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Test: Sync { ++ fn value(&self) -> i32; ++ fn mutate(&mut self); ++} ++ ++impl Test for i32 { ++ fn value(&self) -> i32 { ++ *self ++ } ++ ++ fn mutate(&mut self) { ++ *self = 0; ++ } ++} ++ ++mock! { ++ Foo { ++ fn ref_dyn(&self) -> &dyn Test; ++ fn static_dyn(&self) -> &'static dyn Test; ++ fn mut_dyn(&mut self) -> &mut dyn Test; ++ } ++} ++ ++#[test] ++fn ref_dyn() { ++ let mut mock = MockFoo::new(); ++ mock.expect_ref_dyn() ++ .return_const(Box::new(42) as Box); ++ ++ assert_eq!(42, mock.ref_dyn().value()); ++} ++ ++#[test] ++fn static_dyn() { ++ let mut mock = MockFoo::new(); ++ mock.expect_static_dyn() ++ .return_const(&42 as &'static dyn Test); ++ ++ assert_eq!(42, mock.static_dyn().value()); ++} ++ ++#[test] ++fn mut_dyn() { ++ let mut mock = MockFoo::new(); ++ mock.expect_mut_dyn() ++ .return_var(Box::new(42) as Box); ++ ++ assert_eq!(42, mock.mut_dyn().value()); ++ mock.mut_dyn().mutate(); ++ assert_eq!(0, mock.mut_dyn().value()); ++} +diff --git a/tests/mock_return_mutable_reference.rs b/tests/mock_return_mutable_reference.rs +new file mode 100644 +index 0000000..7bc0ed4 +--- /dev/null ++++ b/tests/mock_return_mutable_reference.rs +@@ -0,0 +1,89 @@ ++// vim: tw=80 ++//! A struct with a method that returns a mutable reference ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ Foo { ++ fn foo(&mut self, i: u32) -> &mut u32; ++ } ++} ++ ++#[test] ++#[cfg_attr(not(feature = "nightly"), ++ should_panic(expected = "MockFoo::foo: Expectation() Returning default values requires"))] ++#[cfg_attr(not(feature = "nightly"), allow(unused_must_use))] ++fn return_default() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo(); ++ let r = mock.foo(0); ++ assert_eq!(u32::default(), *r); ++} ++ ++#[test] ++fn return_var() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .return_var(5u32); ++ { ++ let r = mock.foo(0); ++ assert_eq!(5, *r); ++ *r = 6; ++ } ++ assert_eq!(6, *mock.foo(0)); ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| 5u32); ++ let r = mock.foo(0); ++ assert_eq!(5, *r); ++} ++ ++mod sequence { ++ use super::*; ++ ++ #[test] ++ #[should_panic(expected = "MockFoo::foo(4): Method sequence violation")] ++ fn fail() { ++ let mut seq = Sequence::new(); ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .with(predicate::eq(3)) ++ .times(1) ++ .return_var(0) ++ .in_sequence(&mut seq); ++ ++ mock.expect_foo() ++ .with(predicate::eq(4)) ++ .times(1) ++ .return_var(0) ++ .in_sequence(&mut seq); ++ ++ mock.foo(4); ++ } ++ ++ #[test] ++ fn ok() { ++ let mut seq = Sequence::new(); ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .with(predicate::eq(3)) ++ .times(1) ++ .return_var(0) ++ .in_sequence(&mut seq); ++ ++ mock.expect_foo() ++ .with(predicate::eq(4)) ++ .times(1) ++ .return_var(0) ++ .in_sequence(&mut seq); ++ ++ mock.foo(3); ++ mock.foo(4); ++ } ++ ++} +diff --git a/tests/mock_return_reference.rs b/tests/mock_return_reference.rs +new file mode 100644 +index 0000000..d3fc71d +--- /dev/null ++++ b/tests/mock_return_reference.rs +@@ -0,0 +1,105 @@ ++// vim: tw=80 ++//! A struct with a method that returns an immutable reference ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ Foo { ++ fn foo(&self, x: i32) -> &u32; ++ fn bar(&self) -> &u32; ++ } ++} ++ ++mod never { ++ use super::*; ++ ++ #[test] ++ #[should_panic(expected = ++ "MockFoo::bar: Expectation() should not have been called")] ++ fn fail() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .return_const(0) ++ .never(); ++ mock.bar(); ++ } ++ ++ #[test] ++ fn ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .never(); ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .return_const(5u32); ++ assert_eq!(5, *mock.foo(4)); ++} ++ ++#[test] ++#[cfg_attr(not(feature = "nightly"), ++ should_panic(expected = "MockFoo::foo: Expectation() Returning default values requires"))] ++#[cfg_attr(not(feature = "nightly"), allow(unused_must_use))] ++fn return_default() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo(); ++ let r = mock.foo(4); ++ assert_eq!(u32::default(), *r); ++} ++ ++mod sequence { ++ use super::*; ++ ++ #[test] ++ #[should_panic(expected = "exact call count")] ++ fn ambiguous() { ++ let mut seq = Sequence::new(); ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .times(1..3) ++ .in_sequence(&mut seq); ++ mock.foo(4); ++ } ++ ++ #[test] ++ #[should_panic(expected = "MockFoo::foo(4): Method sequence violation")] ++ fn fail() { ++ let mut seq = Sequence::new(); ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .times(1) ++ .return_const(0) ++ .in_sequence(&mut seq); ++ ++ mock.expect_foo() ++ .times(1) ++ .return_const(0) ++ .in_sequence(&mut seq); ++ ++ mock.foo(4); ++ mock.bar(); ++ } ++ ++ #[test] ++ fn ok() { ++ let mut seq = Sequence::new(); ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .times(1) ++ .return_const(0) ++ .in_sequence(&mut seq); ++ ++ mock.expect_bar() ++ .times(1) ++ .return_const(0) ++ .in_sequence(&mut seq); ++ ++ mock.foo(4); ++ mock.bar(); ++ } ++} +diff --git a/tests/mock_same_trait_twice_on_generic_struct.rs b/tests/mock_same_trait_twice_on_generic_struct.rs +new file mode 100644 +index 0000000..51dd88f +--- /dev/null ++++ b/tests/mock_same_trait_twice_on_generic_struct.rs +@@ -0,0 +1,32 @@ ++// vim: ts=80 ++//! Mock the same generic trait twice on a single struct (with different generic ++//! arguments, of course). ++//! ++#![deny(warnings)] ++#![allow(clippy::from_over_into)] ++ ++use mockall::*; ++ ++mock! { ++ pub Foo {} ++ impl Into for Foo { ++ fn into(self) -> u32; ++ } ++ impl Into for Foo { ++ fn into(self) -> i32; ++ } ++} ++ ++/// Ensure we can set expectations for both methods simultaneously ++#[test] ++fn return_once() { ++ let mut mocku = MockFoo::::new(); ++ mocku.expect_into() ++ .return_once(|| 42); ++ let mut mocki = MockFoo::::new(); ++ mocki.expect_into() ++ .return_once(|| -42); ++ ++ assert_eq!( as Into>::into(mocku), 42u32); ++ assert_eq!( as Into>::into(mocki), -42); ++} +diff --git a/tests/mock_specializing_methods.rs b/tests/mock_specializing_methods.rs +new file mode 100644 +index 0000000..f2c0256 +--- /dev/null ++++ b/tests/mock_specializing_methods.rs +@@ -0,0 +1,34 @@ ++// vim: tw=80 ++//! A specializing method is a non-generic method of a generic struct that ++//! places additional bounds on the struct's generic types via a where ++//! clause. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++struct G(T); ++ ++#[derive(Clone, Copy)] ++struct NonDefault{} ++ ++mock!{ ++ Foo where T: Copy { ++ fn foo(&self, t: T) -> G where T: Default + 'static; ++ } ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::::default(); ++ mock.expect_foo() ++ .returning(G); ++ assert_eq!(42u32, mock.foo(42u32).0); ++ ++ // It's possible to instantiate a mock object that doesn't satisfy the ++ // specializing method's requirements: ++ let _mock2 = MockFoo::::default(); ++ // But you can't call the specializing method. This won't work: ++ // _mock2.expect_foo() ++ // .returning(|h| G(h)); ++ // _mock2.foo(NonDefault{}); ++} +diff --git a/tests/mock_static_method_with_generic_args.rs b/tests/mock_static_method_with_generic_args.rs +new file mode 100644 +index 0000000..5a8d0fe +--- /dev/null ++++ b/tests/mock_static_method_with_generic_args.rs +@@ -0,0 +1,17 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ Foo { ++ fn bar(x: T); ++ } ++} ++ ++#[test] ++fn returning() { ++ let ctx = MockFoo::bar_context(); ++ ctx.expect::().returning(|_| ()); ++ MockFoo::bar(0i16) ++} +diff --git a/tests/mock_static_method_with_generic_return.rs b/tests/mock_static_method_with_generic_return.rs +new file mode 100644 +index 0000000..98c0cae +--- /dev/null ++++ b/tests/mock_static_method_with_generic_return.rs +@@ -0,0 +1,18 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ Foo { ++ fn bar(x: T) -> Vec; ++ } ++} ++ ++#[test] ++fn returning() { ++ let ctx = MockFoo::bar_context(); ++ ctx.expect::().returning(|x| vec![x]); ++ let v = MockFoo::bar(42i16); ++ assert_eq!(v[0], 42i16); ++} +diff --git a/tests/mock_static_method_with_lifetime_parameters.rs b/tests/mock_static_method_with_lifetime_parameters.rs +new file mode 100644 +index 0000000..c71ece5 +--- /dev/null ++++ b/tests/mock_static_method_with_lifetime_parameters.rs +@@ -0,0 +1,57 @@ ++// vim: tw=80 ++//! A static generic method whose only generic parameter is a lifetime parameter ++#![deny(warnings)] ++ ++use mockall::*; ++use std::sync::Mutex; ++ ++#[derive(Debug, Eq)] ++struct X<'a>(&'a u32); ++ ++impl<'a> PartialEq for X<'a> { ++ fn eq(&self, other: &X<'a>) -> bool { ++ self.0 == other.0 ++ } ++} ++ ++mock!{ ++ Foo { ++ fn foo<'a>(x: &'a X<'a>) -> u32; ++ } ++} ++ ++static FOO_MTX: Mutex<()> = Mutex::new(()); ++ ++#[test] ++fn return_const() { ++ let _m = FOO_MTX.lock().unwrap(); ++ ++ let ctx = MockFoo::foo_context(); ++ ctx.expect() ++ .return_const(42u32); ++ let x = X(&5); ++ assert_eq!(42, MockFoo::foo(&x)); ++} ++ ++#[test] ++fn returning() { ++ let _m = FOO_MTX.lock().unwrap(); ++ ++ let ctx = MockFoo::foo_context(); ++ ctx.expect() ++ .returning(|f| *f.0); ++ let x = X(&5); ++ assert_eq!(5, MockFoo::foo(&x)); ++} ++ ++#[test] ++fn withf() { ++ let _m = FOO_MTX.lock().unwrap(); ++ ++ let ctx = MockFoo::foo_context(); ++ ctx.expect() ++ .withf(|f| *f.0 == 5) ++ .return_const(42u32); ++ let x = X(&5); ++ assert_eq!(42, MockFoo::foo(&x)); ++} +diff --git a/tests/mock_static_method_with_reference_arguments.rs b/tests/mock_static_method_with_reference_arguments.rs +new file mode 100644 +index 0000000..1785ddc +--- /dev/null ++++ b/tests/mock_static_method_with_reference_arguments.rs +@@ -0,0 +1,19 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock!{ ++ Foo { ++ fn bar(x: &u32) -> u64; ++ } ++} ++ ++#[test] ++fn with() { ++ let ctx = MockFoo::bar_context(); ++ ctx.expect() ++ .with(predicate::eq(42)) ++ .return_const(99u64); ++ assert_eq!(99, MockFoo::bar(&42)); ++} +diff --git a/tests/mock_struct.rs b/tests/mock_struct.rs +new file mode 100644 +index 0000000..71b91e8 +--- /dev/null ++++ b/tests/mock_struct.rs +@@ -0,0 +1,461 @@ ++// vim: tw=80 ++//! Structs can be mocked with mock! This is useful when the struct's original ++//! definition is not accessible. ++#![deny(warnings)] ++ ++use mockall::*; ++ ++// A struct with a definition like this: ++// struct Foo { ++// _x: i16 ++// } ++// impl Foo { ++// fn foo(&self, _x: u32) -> u32 { ++// 42 ++// } ++// } ++// Could be mocked like this: ++mock!{ ++ Foo { ++ fn foo(&self, x: u32) -> u32; ++ fn bar(&self, x: u32); ++ fn baz(&self); ++ } ++} ++ ++mod checkpoint { ++ use std::panic; ++ use super::*; ++ ++ #[test] ++ fn expect_again() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| 5) ++ .times(1..3); ++ mock.foo(0); ++ mock.checkpoint(); ++ ++ mock.expect_foo() ++ .returning(|_| 25); ++ assert_eq!(25, mock.foo(0)); ++ } ++ ++ #[test] ++ #[should_panic(expected = ++ "MockFoo::foo: Expectation() called 0 time(s) which is fewer than expected 1")] ++ fn not_yet_satisfied() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| 42) ++ .times(1); ++ mock.checkpoint(); ++ panic!("Shouldn't get here!"); ++ } ++ ++ #[test] ++ #[should_panic(expected = ++ "MockFoo::foo: Expectation() called 1 time(s) which is more than expected 0")] ++ fn too_many_calls() { ++ let mut mock = MockFoo::default(); ++ mock.expect_foo() ++ .returning(|_| 42) ++ .times(0); ++ let _ = panic::catch_unwind(|| { ++ mock.foo(0); ++ }); ++ mock.checkpoint(); ++ panic!("Shouldn't get here!"); ++ } ++ ++ #[test] ++ fn ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| 5) ++ .times(1..3); ++ mock.foo(0); ++ mock.checkpoint(); ++ } ++ ++ #[test] ++ #[should_panic(expected = "MockFoo::foo(0): No matching expectation found")] ++ fn removes_old_expectations() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|_| 42) ++ .times(1..3); ++ mock.foo(0); ++ mock.checkpoint(); ++ mock.foo(0); ++ panic!("Shouldn't get here!"); ++ } ++} ++ ++mod r#match { ++ use super::*; ++ ++ /// Unlike Mockers, Mockall calls should use the oldest matching ++ /// expectation, if multiple expectations match ++ #[test] ++ fn fifo_order() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .with(predicate::eq(5)) ++ .returning(|_| 99); ++ mock.expect_foo() ++ .with(predicate::always()) ++ .returning(|_| 42); ++ ++ assert_eq!(99, mock.foo(5)); ++ } ++ ++ #[test] ++ fn one_match() { ++ let mut mock0 = MockFoo::new(); ++ mock0.expect_foo() ++ .with(predicate::eq(5)) ++ .returning(|_| 99); ++ mock0.expect_foo() ++ .with(predicate::eq(6)) ++ .returning(|_| 42); ++ assert_eq!(42, mock0.foo(6)); ++ ++ // And in reverse order ++ let mut mock1 = MockFoo::new(); ++ mock1.expect_foo() ++ .with(predicate::eq(5)) ++ .returning(|_| 99); ++ mock1.expect_foo() ++ .with(predicate::eq(6)) ++ .returning(|_| 42); ++ assert_eq!(99, mock0.foo(5)); ++ } ++ ++ #[test] ++ #[should_panic(expected = "MockFoo::bar(5): No matching expectation found")] ++ fn with_no_matches() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .with(predicate::eq(4)) ++ .return_const(()); ++ mock.bar(5); ++ } ++ ++ #[test] ++ fn with_ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .with(predicate::eq(5)) ++ .return_const(()); ++ mock.bar(5); ++ } ++ ++ #[test] ++ fn withf_ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .withf(|x: &u32| *x == 5) ++ .return_const(()); ++ mock.bar(5); ++ } ++ ++ #[test] ++ #[should_panic(expected = "MockFoo::bar(5): No matching expectation found")] ++ fn withf_no_matches() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .withf(|x: &u32| *x == 6) ++ .return_const(()); ++ mock.bar(5); ++ } ++ ++} ++ ++mod never { ++ use super::*; ++ ++ #[test] ++ #[should_panic(expected = ++ "MockFoo::bar: Expectation() should not have been called")] ++ fn fail() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .returning(|_| ()) ++ .never(); ++ mock.bar(0); ++ } ++ ++ #[test] ++ fn ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .never(); ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .return_const(42u32); ++ assert_eq!(42, mock.foo(5)); ++} ++ ++#[cfg_attr(not(feature = "nightly"), ++ should_panic(expected = "MockFoo::foo: Expectation() Returning default values requires"))] ++#[cfg_attr(not(feature = "nightly"), allow(unused_must_use))] ++#[test] ++fn return_default() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo(); ++ let r = mock.foo(5); ++ assert_eq!(u32::default(), r); ++} ++ ++#[test] ++fn returning() { ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .returning(|x| x + 1); ++ assert_eq!(6, mock.foo(5)); ++} ++ ++mod sequence { ++ use super::*; ++ ++ #[test] ++ #[should_panic(expected = "exact call count")] ++ fn ambiguous() { ++ let mut seq = Sequence::new(); ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .times(1..3) ++ .in_sequence(&mut seq); ++ mock.baz(); ++ } ++ ++ #[test] ++ #[should_panic(expected = "MockFoo::baz(): Method sequence violation")] ++ fn fail() { ++ let mut seq = Sequence::new(); ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .times(1) ++ .returning(|_| ()) ++ .in_sequence(&mut seq); ++ ++ mock.expect_baz() ++ .times(1) ++ .returning(|| ()) ++ .in_sequence(&mut seq); ++ ++ mock.baz(); ++ mock.bar(0); ++ } ++ ++ #[test] ++ fn ok() { ++ let mut seq = Sequence::new(); ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .times(1) ++ .returning(|| ()) ++ .in_sequence(&mut seq); ++ ++ mock.expect_bar() ++ .times(1) ++ .returning(|_| ()) ++ .in_sequence(&mut seq); ++ ++ mock.baz(); ++ mock.bar(0); ++ } ++ ++ /// When adding multiple calls of a single method, with the same arguments, ++ /// to a sequence, expectations should not be called after they are done if ++ /// there are more expectations to follow. ++ #[test] ++ fn single_method() { ++ let mut seq = Sequence::new(); ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .times(1) ++ .in_sequence(&mut seq) ++ .returning(|_| 1); ++ mock.expect_foo() ++ .times(1) ++ .in_sequence(&mut seq) ++ .returning(|_| 2); ++ mock.expect_foo() ++ .times(1) ++ .in_sequence(&mut seq) ++ .returning(|_| 3); ++ ++ assert_eq!(1, mock.foo(0)); ++ assert_eq!(2, mock.foo(0)); ++ assert_eq!(3, mock.foo(0)); ++ } ++ ++} ++ ++mod times { ++ use super::*; ++ ++ #[test] ++ fn ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .returning(|| ()) ++ .times(2); ++ mock.baz(); ++ mock.baz(); ++ } ++ ++ #[test] ++ #[should_panic(expected = ++ "MockFoo::bar: Expectation(var == 5) called 1 time(s) which is fewer than expected 2")] ++ fn too_few() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .with(predicate::eq(5)) ++ .returning(|_| ()) ++ .times(2); ++ mock.bar(5); ++ } ++ ++ #[test] ++ #[should_panic(expected = ++ "MockFoo::baz: Expectation() called 3 times which is more than the expected 2")] ++ fn too_many() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .returning(|| ()) ++ .times(2); ++ mock.baz(); ++ mock.baz(); ++ mock.baz(); ++ // Verify that we panic quickly and don't reach code below this point. ++ panic!("Shouldn't get here!"); ++ } ++ ++ #[test] ++ fn range_ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .returning(|| ()) ++ .times(2..4); ++ mock.baz(); ++ mock.baz(); ++ ++ mock.expect_bar() ++ .returning(|_| ()) ++ .times(2..4); ++ mock.bar(0); ++ mock.bar(0); ++ mock.bar(0); ++ } ++ ++ #[test] ++ #[should_panic(expected = ++ "MockFoo::baz: Expectation() called 1 time(s) which is fewer than expected 2")] ++ fn range_too_few() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .returning(|| ()) ++ .times(2..4); ++ mock.baz(); ++ } ++ ++ #[test] ++ #[should_panic(expected = ++ "MockFoo::baz: Expectation() called 4 times which is more than the expected 3")] ++ fn range_too_many() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .returning(|| ()) ++ .times(2..4); ++ mock.baz(); ++ mock.baz(); ++ mock.baz(); ++ mock.baz(); ++ // Verify that we panic quickly and don't reach code below this point. ++ panic!("Shouldn't get here!"); ++ } ++ ++ #[test] ++ fn rangeto_ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .returning(|_| ()) ++ .times(..4); ++ mock.bar(0); ++ mock.bar(0); ++ mock.bar(0); ++ } ++ ++ #[test] ++ #[should_panic(expected = ++ "MockFoo::baz: Expectation() called 4 times which is more than the expected 3")] ++ fn rangeto_too_many() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .returning(|| ()) ++ .times(..4); ++ mock.baz(); ++ mock.baz(); ++ mock.baz(); ++ mock.baz(); ++ } ++ ++ #[test] ++ fn rangeinclusive_ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .returning(|_| ()) ++ .times(2..=4); ++ mock.bar(0); ++ mock.bar(0); ++ mock.bar(0); ++ mock.bar(0); ++ } ++ ++ #[test] ++ fn rangefrom_ok() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .returning(|| ()) ++ .times(2..); ++ mock.baz(); ++ mock.baz(); ++ ++ mock.expect_bar() ++ .returning(|_| ()) ++ .times(2..); ++ mock.bar(0); ++ mock.bar(0); ++ mock.bar(0); ++ } ++ ++ #[test] ++ #[should_panic(expected = ++ "MockFoo::baz: Expectation() called 1 time(s) which is fewer than expected 2")] ++ fn rangefrom_too_few() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .returning(|| ()) ++ .times(2..); ++ mock.baz(); ++ } ++} ++ ++#[test] ++fn times_full() { ++ let mut mock = MockFoo::new(); ++ mock.expect_baz() ++ .returning(|| ()) ++ .times(1) ++ .times(..); ++ mock.baz(); ++ mock.baz(); ++} +diff --git a/tests/mock_struct_with_static_method.rs b/tests/mock_struct_with_static_method.rs +new file mode 100644 +index 0000000..ffaebd0 +--- /dev/null ++++ b/tests/mock_struct_with_static_method.rs +@@ -0,0 +1,103 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++use std::sync::Mutex; ++ ++mock!{ ++ Foo { ++ fn bar(x: u32) -> u64; ++ } ++} ++ ++static BAR_MTX: Mutex<()> = Mutex::new(()); ++ ++// Checkpointing the mock object should not checkpoint static methods ++#[test] ++fn checkpoint() { ++ let _m = BAR_MTX.lock(); ++ ++ let mut mock = MockFoo::new(); ++ let ctx = MockFoo::bar_context(); ++ ctx.expect() ++ .returning(|_| 32) ++ .times(1..3); ++ mock.checkpoint(); ++ MockFoo::bar(0); ++} ++ ++// It should also be possible to checkpoint just the context object ++#[test] ++#[should_panic(expected = ++ "MockFoo::bar: Expectation() called 0 time(s) which is fewer than expected 1")] ++fn ctx_checkpoint() { ++ let _m = BAR_MTX.lock(); ++ ++ let ctx = MockFoo::bar_context(); ++ ctx.expect() ++ .returning(|_| 32) ++ .times(1..3); ++ ctx.checkpoint(); ++ panic!("Shouldn't get here!"); ++} ++ ++// Expectations should be cleared when a context object drops ++#[test] ++#[should_panic(expected = "MockFoo::bar(42): No matching expectation found")] ++fn ctx_hygiene() { ++ let _m = BAR_MTX.lock(); ++ ++ { ++ let ctx0 = MockFoo::bar_context(); ++ ctx0.expect() ++ .returning(|x| u64::from(x + 1)); ++ } ++ MockFoo::bar(42); ++} ++ ++#[test] ++fn return_const() { ++ let _m = BAR_MTX.lock(); ++ ++ let ctx = MockFoo::bar_context(); ++ ctx.expect() ++ .return_const(42u64); ++ assert_eq!(42, MockFoo::bar(41)); ++} ++ ++#[cfg_attr(not(feature = "nightly"), ignore)] ++#[cfg_attr(not(feature = "nightly"), allow(unused_must_use))] ++#[test] ++fn return_default() { ++ let _m = BAR_MTX.lock(); ++ ++ let ctx = MockFoo::bar_context(); ++ ctx.expect(); ++ let r = MockFoo::bar(5); ++ assert_eq!(u64::default(), r); ++} ++ ++#[test] ++fn returning() { ++ let _m = BAR_MTX.lock(); ++ ++ let ctx = MockFoo::bar_context(); ++ ctx.expect() ++ .returning(|x| u64::from(x + 1)); ++ assert_eq!(42, MockFoo::bar(41)); ++} ++ ++#[test] ++fn two_matches() { ++ let _m = BAR_MTX.lock(); ++ ++ let ctx = MockFoo::bar_context(); ++ ctx.expect() ++ .with(predicate::eq(42)) ++ .return_const(99u64); ++ ctx.expect() ++ .with(predicate::eq(69)) ++ .return_const(101u64); ++ assert_eq!(101, MockFoo::bar(69)); ++ assert_eq!(99, MockFoo::bar(42)); ++} +diff --git a/tests/mock_struct_with_trait.rs b/tests/mock_struct_with_trait.rs +new file mode 100644 +index 0000000..bdf13d4 +--- /dev/null ++++ b/tests/mock_struct_with_trait.rs +@@ -0,0 +1,24 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Foo { ++ fn foo(&self, x: u32) -> i64; ++} ++ ++mock!{ ++ pub Bar {} ++ impl Foo for Bar { ++ fn foo(&self, x: u32) -> i64; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockBar::new(); ++ mock.expect_foo() ++ .return_const(6); ++ assert_eq!(6, mock.foo(5)); ++} ++ +diff --git a/tests/mock_struct_with_trait_with_associated_types.rs b/tests/mock_struct_with_trait_with_associated_types.rs +new file mode 100644 +index 0000000..03a26e5 +--- /dev/null ++++ b/tests/mock_struct_with_trait_with_associated_types.rs +@@ -0,0 +1,21 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ pub MyIter {} ++ impl Iterator for MyIter { ++ type Item=u32; ++ ++ fn next(&mut self) -> Option; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockMyIter::new(); ++ mock.expect_next() ++ .return_const(None); ++ assert!(mock.next().is_none()); ++} +diff --git a/tests/mock_trait_returning_reference.rs b/tests/mock_trait_returning_reference.rs +new file mode 100644 +index 0000000..746acbd +--- /dev/null ++++ b/tests/mock_trait_returning_reference.rs +@@ -0,0 +1,24 @@ ++// vim: tw=80 ++//! A trait with a method that returns an immutable reference ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Foo { ++ fn foo(&self) -> &u32; ++} ++ ++mock! { ++ pub Bar {} ++ impl Foo for Bar { ++ fn foo(&self) -> &u32; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockBar::new(); ++ mock.expect_foo() ++ .return_const(5u32); ++ assert_eq!(5, *mock.foo()); ++} +diff --git a/tests/mock_trait_returning_static_reference.rs b/tests/mock_trait_returning_static_reference.rs +new file mode 100644 +index 0000000..75900d9 +--- /dev/null ++++ b/tests/mock_trait_returning_static_reference.rs +@@ -0,0 +1,20 @@ ++// vim: tw=80 ++//! A struct with a method that returns an immutable static reference ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ Foo { ++ fn foo(&self) -> &'static u32; ++ } ++} ++ ++#[test] ++fn return_const() { ++ const X: u32 = 5; ++ let mut mock = MockFoo::new(); ++ mock.expect_foo() ++ .return_const(&X); ++ assert_eq!(5, *mock.foo()); ++} +diff --git a/tests/mock_trait_with_static_method.rs b/tests/mock_trait_with_static_method.rs +new file mode 100644 +index 0000000..e0d5b1c +--- /dev/null ++++ b/tests/mock_trait_with_static_method.rs +@@ -0,0 +1,23 @@ ++// vim: tw=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Bar { ++ fn baz(x: u32) -> u64; ++} ++ ++mock!{ ++ pub Foo {} ++ impl Bar for Foo { ++ fn baz(x: u32) -> u64; ++ } ++} ++ ++#[test] ++fn returning() { ++ let ctx = MockFoo::baz_context(); ++ ctx.expect() ++ .returning(|x| u64::from(x + 1)); ++ assert_eq!(42, MockFoo::baz(41)); ++} +diff --git a/tests/mock_unsafe_trait.rs b/tests/mock_unsafe_trait.rs +new file mode 100644 +index 0000000..8368338 +--- /dev/null ++++ b/tests/mock_unsafe_trait.rs +@@ -0,0 +1,25 @@ ++// vim: ts=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++#[allow(clippy::missing_safety_doc)] ++pub unsafe trait Bar { ++ fn bar(&self) -> i32; ++} ++ ++mock! { ++ pub Foo{} ++ unsafe impl Bar for Foo { ++ fn bar(&self) -> i32; ++ } ++} ++ ++#[test] ++fn return_const() { ++ let mut mock = MockFoo::new(); ++ mock.expect_bar() ++ .return_const(42); ++ ++ assert_eq!(42, mock.bar()); ++} +diff --git a/tests/mock_unsized.rs b/tests/mock_unsized.rs +new file mode 100644 +index 0000000..5753510 +--- /dev/null ++++ b/tests/mock_unsized.rs +@@ -0,0 +1,52 @@ ++// vim: tw=80 ++//! All types of predicate should work for methods with unsized arguments ++#![deny(warnings)] ++ ++use mockall::*; ++ ++mock! { ++ Foo { ++ fn foo(&self, arg: &str); ++ } ++} ++ ++#[test] ++fn with_always() { ++ let mut foo = MockFoo::new(); ++ foo.expect_foo() ++ .with(predicate::always()) ++ .return_const(()); ++ ++ foo.foo("xxx"); ++} ++ ++#[test] ++fn with_eq() { ++ let mut foo = MockFoo::new(); ++ foo.expect_foo() ++ .with(predicate::eq("xxx")) ++ .return_const(()); ++ ++ foo.foo("xxx"); ++} ++ ++#[test] ++#[should_panic(expected = "MockFoo::foo(\"xxx\"): No matching expectation found")] ++fn with_never() { ++ let mut foo = MockFoo::new(); ++ foo.expect_foo() ++ .with(predicate::never()) ++ .return_const(()); ++ ++ foo.foo("xxx"); ++} ++ ++#[test] ++fn withf() { ++ let mut foo = MockFoo::new(); ++ foo.expect_foo() ++ .withf(|a| a == "xxx") ++ .return_const(()); ++ ++ foo.foo("xxx"); ++} +diff --git a/tests/raw_identifier.rs b/tests/raw_identifier.rs +new file mode 100644 +index 0000000..2d56e37 +--- /dev/null ++++ b/tests/raw_identifier.rs +@@ -0,0 +1,72 @@ ++// vim: tw=80 ++//! It should be possible to mock things that use raw identifiers ++#![deny(warnings)] ++#![allow(non_camel_case_types)] ++ ++use mockall::*; ++ ++#[automock] ++trait r#while { ++ fn r#match(&self); ++ fn r#loop(); ++} ++ ++#[automock] ++pub mod r#break { ++ pub fn r#if() {unimplemented!() } ++} ++ ++mock! { ++ r#do {} ++ impl r#while for r#do { ++ fn r#match(&self); ++ fn r#loop(); ++ } ++} ++ ++struct r#else {} ++#[automock] ++impl r#while for r#else { ++ fn r#match(&self) {unimplemented!()} ++ fn r#loop() {unimplemented!()} ++} ++ ++#[test] ++fn by_ref() { ++ let mut foo = Mockwhile::new(); ++ foo.expect_match() ++ .return_const(()); ++ foo.r#match(); ++} ++ ++#[test] ++fn static_method() { ++ let ctx = Mockwhile::loop_context(); ++ ctx.expect() ++ .returning(|| ()); ++ Mockwhile::r#loop(); ++} ++ ++#[test] ++fn manual_mock() { ++ let mut foo = Mockdo::new(); ++ foo.expect_match() ++ .return_const(()); ++ foo.r#match(); ++} ++ ++#[test] ++fn module() { ++ let ctx = mock_break::if_context(); ++ ctx.expect() ++ .returning(|| ()); ++ mock_break::r#if(); ++} ++ ++#[test] ++fn trait_impl() { ++ let mut mock = Mockelse::new(); ++ mock.expect_match() ++ .returning(|| ()); ++ mock.r#match(); ++} +diff --git a/tests/specific_impl.rs b/tests/specific_impl.rs +new file mode 100644 +index 0000000..e16a48e +--- /dev/null ++++ b/tests/specific_impl.rs +@@ -0,0 +1,74 @@ ++// vim: ts=80 ++#![deny(warnings)] ++ ++use mockall::*; ++ ++trait Bar { ++ fn bar(&self); ++} ++//trait Baz { ++ //fn baz(&self, y: Y); ++//} ++ ++mock! { ++ pub Foo { ++ } ++ impl Bar for Foo { ++ fn bar(&self); ++ } ++ impl Bar for Foo { ++ fn bar(&self); ++ } ++ // TODO: support specific impls with generic methods, like this ++ //impl Baz for Foo { ++ //fn baz(&self, y: Y); ++ //} ++} ++ ++#[test] ++fn specific_impl() { ++ let mut mocku = MockFoo::::new(); ++ mocku.expect_bar() ++ .return_const(()); ++ let mut mocki = MockFoo::::new(); ++ mocki.expect_bar() ++ .return_const(()); ++ ++ mocku.bar(); ++ mocki.bar(); ++} ++ ++///// Make sure generic methods work with specific impls, too ++//#[test] ++//fn withf() { ++ //let mut mocku = MockFoo::::new(); ++ //mocku.expect_baz::() ++ //.withf(|y| y == 3.14159) ++ //.return_const(()); ++ //mocku.baz::(3.14159); ++//} ++ ++// Here's a partially specific impl: Bar is implemented for Bean where one of ++// the generic types is concrete, but the other isn't. ++mock! { ++ pub Bean {} ++ impl Bar for Bean { ++ fn bar(&self); ++ } ++ impl Bar for Bean { ++ fn bar(&self); ++ } ++} ++ ++#[test] ++fn partially_specific_impl() { ++ let mut mocku = MockBean::::new(); ++ mocku.expect_bar() ++ .return_const(()); ++ let mut mocki = MockBean::::new(); ++ mocki.expect_bar() ++ .return_const(()); ++ ++ mocku.bar(); ++ mocki.bar(); ++}