blob: f2d3202e890ac6cc474be254b338df7b99145c04 [file] [log] [blame]
//! Tests for `[lints]`
use crate::prelude::*;
use cargo_test_support::project;
use cargo_test_support::registry::Package;
use cargo_test_support::str;
#[cargo_test]
fn dependency_warning_ignored() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[dependencies]
bar.path = "../bar"
"#,
)
.file("src/lib.rs", "")
.build();
let _bar = project()
.at("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
edition = "2015"
authors = []
[lints.rust]
unsafe_code = "forbid"
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check")
.with_stderr_data(str![[r#"
[LOCKING] 1 package to latest compatible version
[CHECKING] bar v0.0.1 ([ROOT]/bar)
[CHECKING] foo v0.0.1 ([ROOT]/foo)
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
"#]])
.run();
}
#[cargo_test]
fn malformed_on_stable() {
let foo = project()
.file(
"Cargo.toml",
r#"
lints = 20
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] invalid type: integer `20`, expected a lints table
--> Cargo.toml:2:25
|
2 | lints = 20
| ^^
"#]])
.run();
}
#[cargo_test]
fn fail_on_invalid_tool() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[workspace.lints.super-awesome-linter]
unsafe_code = "forbid"
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check").with_stderr_data(str![[r#"
[WARNING] [ROOT]/foo/Cargo.toml: unrecognized lint tool `lints.super-awesome-linter`, specifying unrecognized tools may break in the future.
supported tools: cargo, clippy, rust, rustdoc
[CHECKING] foo v0.0.1 ([ROOT]/foo)
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
"#]]).run();
}
#[cargo_test]
fn invalid_type_in_lint_value() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
[workspace.lints.rust]
rust-2018-idioms = -1
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] invalid type: integer `-1`, expected a string or map
--> Cargo.toml:8:36
|
8 | rust-2018-idioms = -1
| ^^
"#]])
.run();
}
#[cargo_test]
fn warn_on_unused_key() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
[workspace.lints.rust]
rust-2018-idioms = { level = "allow", unused = true }
[lints.rust]
rust-2018-idioms = { level = "allow", unused = true }
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check")
.with_stderr_data(str![[r#"
[WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: `lints.rust.rust-2018-idioms.unused`
[WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: `lints.rust.rust-2018-idioms.unused`
[CHECKING] foo v0.0.1 ([ROOT]/foo)
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
"#]])
.run();
}
#[cargo_test]
fn fail_on_tool_injection() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[workspace.lints.rust]
"clippy::cyclomatic_complexity" = "warn"
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml`
Caused by:
`lints.rust.clippy::cyclomatic_complexity` is not valid lint name; try `lints.clippy.cyclomatic_complexity`
"#]])
.run();
}
#[cargo_test]
fn fail_on_redundant_tool() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[workspace.lints.rust]
"rust::unsafe_code" = "forbid"
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml`
Caused by:
`lints.rust.rust::unsafe_code` is not valid lint name; try `lints.rust.unsafe_code`
"#]])
.run();
}
#[cargo_test]
fn fail_on_conflicting_tool() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[workspace.lints.rust]
"super-awesome-tool::unsafe_code" = "forbid"
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml`
Caused by:
`lints.rust.super-awesome-tool::unsafe_code` is not a valid lint name
"#]])
.run();
}
#[cargo_test]
fn package_lint_deny() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[lints.rust]
"unsafe_code" = "deny"
"#,
)
.file(
"src/lib.rs",
"
pub fn foo(num: i32) -> u32 {
unsafe { std::mem::transmute(num) }
}
",
)
.build();
foo.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
[CHECKING] foo v0.0.1 ([ROOT]/foo)
[ERROR] usage of an `unsafe` block
...
"#]])
.run();
}
#[cargo_test]
fn workspace_cant_be_false() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[lints]
workspace = false
[workspace.lints.rust]
"unsafe_code" = "deny"
"#,
)
.file(
"src/lib.rs",
"
pub fn foo(num: i32) -> u32 {
unsafe { std::mem::transmute(num) }
}
",
)
.build();
foo.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] `workspace` cannot be false
--> Cargo.toml:9:29
|
9 | workspace = false
| ^^^^^
"#]])
.run();
}
#[cargo_test]
fn workspace_lint_deny() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[lints]
workspace = true
[workspace.lints.rust]
"unsafe_code" = "deny"
"#,
)
.file(
"src/lib.rs",
"
pub fn foo(num: i32) -> u32 {
unsafe { std::mem::transmute(num) }
}
",
)
.build();
foo.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
[CHECKING] foo v0.0.1 ([ROOT]/foo)
[ERROR] usage of an `unsafe` block
...
"#]])
.run();
}
#[cargo_test]
fn workspace_and_package_lints() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[lints]
workspace = true
[lints.rust]
"unsafe_code" = "allow"
[workspace.lints.rust]
"unsafe_code" = "deny"
"#,
)
.file(
"src/lib.rs",
"
pub fn foo(num: i32) -> u32 {
unsafe { std::mem::transmute(num) }
}
",
)
.build();
foo.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml`
Caused by:
cannot override `workspace.lints` in `lints`, either remove the overrides or `lints.workspace = true` and manually specify the lints
"#]])
.run();
}
#[cargo_test]
fn attribute_has_precedence() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[lints.rust]
"unsafe_code" = "deny"
"#,
)
.file(
"src/lib.rs",
"
#![allow(unsafe_code)]
pub fn foo(num: i32) -> u32 {
unsafe { std::mem::transmute(num) }
}
",
)
.build();
foo.cargo("check")
.arg("-v") // Show order of rustflags on failure
.run();
}
#[cargo_test]
fn rustflags_has_precedence() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[lints.rust]
"unsafe_code" = "deny"
"#,
)
.file(
"src/lib.rs",
"
pub fn foo(num: i32) -> u32 {
unsafe { std::mem::transmute(num) }
}
",
)
.build();
foo.cargo("check")
.arg("-v") // Show order of rustflags on failure
.env("RUSTFLAGS", "-Aunsafe_code")
.run();
}
#[cargo_test]
fn profile_rustflags_has_precedence() {
let foo = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["profile-rustflags"]
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
[lints.rust]
"unsafe_code" = "deny"
[profile.dev]
rustflags = ["-A", "unsafe_code"]
"#,
)
.file(
"src/lib.rs",
"
pub fn foo(num: i32) -> u32 {
unsafe { std::mem::transmute(num) }
}
",
)
.build();
foo.cargo("check")
.arg("-v") // Show order of rustflags on failure
.masquerade_as_nightly_cargo(&["profile-rustflags"])
.run();
}
#[cargo_test]
fn build_rustflags_has_precedence() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
[lints.rust]
"unsafe_code" = "deny"
"#,
)
.file(
".cargo/config.toml",
r#"
[build]
rustflags = ["-A", "unsafe_code"]
"#,
)
.file(
"src/lib.rs",
"
pub fn foo(num: i32) -> u32 {
unsafe { std::mem::transmute(num) }
}
",
)
.build();
foo.cargo("check")
.arg("-v") // Show order of rustflags on failure
.run();
}
#[cargo_test]
fn without_priority() {
Package::new("reg-dep", "1.0.0").publish();
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2018"
authors = []
[dependencies]
reg-dep = "1.0.0"
[lints.rust]
"rust-2018-idioms" = "deny"
"unused-extern-crates" = "allow"
"#,
)
.file(
"src/lib.rs",
"
extern crate reg_dep;
pub fn foo() -> u32 {
2
}
",
)
.build();
foo.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
...
[ERROR] unused extern crate
...
"#]])
.run();
}
#[cargo_test]
fn with_priority() {
Package::new("reg-dep", "1.0.0").publish();
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2018"
authors = []
[dependencies]
reg-dep = "1.0.0"
[lints.rust]
"rust-2018-idioms" = { level = "deny", priority = -1 }
"unused-extern-crates" = "allow"
"#,
)
.file(
"src/lib.rs",
"
extern crate reg_dep;
pub fn foo() -> u32 {
2
}
",
)
.build();
foo.cargo("check").run();
}
#[cargo_test]
fn rustdoc_lint() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[lints.rustdoc]
broken_intra_doc_links = "deny"
"#,
)
.file(
"src/lib.rs",
"
/// [`bar`] doesn't exist
pub fn foo() -> u32 {
}
",
)
.build();
foo.cargo("doc")
.with_status(101)
.with_stderr_data(str![[r#"
[DOCUMENTING] foo v0.0.1 ([ROOT]/foo)
[ERROR] unresolved link to `bar`
...
"#]])
.run();
}
#[cargo_test]
fn doctest_respects_lints() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[lints.rust]
confusable-idents = 'allow'
"#,
)
.file(
"src/lib.rs",
r#"
/// Test
///
/// [`Foo`]
///
/// ```
/// let s = "rust";
/// let s_s = "rust2";
/// ```
pub fn f() {}
pub const Ě: i32 = 1;
pub const Ĕ: i32 = 2;
"#,
)
.build();
foo.cargo("check")
.with_stderr_data(str![[r#"
[CHECKING] foo v0.0.1 ([ROOT]/foo)
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
"#]])
.run();
foo.cargo("test --doc")
.with_stderr_data(str![[r#"
[COMPILING] foo v0.0.1 ([ROOT]/foo)
[FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[DOCTEST] foo
"#]])
.run();
}
#[cargo_test]
fn cargo_lints_nightly_required() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[lints.cargo]
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check")
.with_stderr_data(str![[r#"
[WARNING] unused manifest key `lints.cargo` (may be supported in a future version)
this Cargo does not support nightly features, but if you
switch to nightly channel you can pass
`-Zcargo-lints` to enable this feature.
[CHECKING] foo v0.0.1 ([ROOT]/foo)
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
"#]])
.run();
}
#[cargo_test]
fn cargo_lints_no_z_flag() {
let foo = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["test-dummy-unstable"]
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
im-a-teapot = true
[lints.cargo]
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check")
.masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"])
.with_stderr_data(str![[r#"
[WARNING] unused manifest key `lints.cargo` (may be supported in a future version)
consider passing `-Zcargo-lints` to enable this feature.
[CHECKING] foo v0.0.1 ([ROOT]/foo)
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
"#]])
.run();
}
#[cargo_test]
fn cargo_lints_success() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["test-dummy-unstable"]
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
im-a-teapot = true
[lints.cargo]
im_a_teapot = "warn"
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("check -Zcargo-lints")
.masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"])
.with_stderr_data(str![[r#"
[WARNING] `im_a_teapot` is specified
--> Cargo.toml:9:1
|
9 | im-a-teapot = true
| ^^^^^^^^^^^^^^^^^^
|
= [NOTE] `cargo::im_a_teapot` is set to `warn` in `[lints]`
[CHECKING] foo v0.0.1 ([ROOT]/foo)
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
"#]])
.run();
}