Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/cargo/core/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ struct SerializedTarget<'a> {
doctest: bool,
/// Whether tests should be run for the target (`test` field in `Cargo.toml`)
test: bool,
/// Whether the target uses the libtest harness (`harness` field in `Cargo.toml`).
#[serde(skip_serializing_if = "bool::clone")] // skip if true
harness: bool,

@epage epage Jun 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since we wrote cargo metadata, we adopted a policy to omit defaults, see https://doc.crates.io/contrib/implementation/schemas.html#schema-design

However, the question becomes how do we deal with the lack of the field vs the default?

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Sorry for missing that detail from the guidelines. I'll add skip_serializing_ifhere.

However, the question becomes how do we deal with the lack of the field vs the default?

I'm not sure exactly what you mean here. In RustRover we can easily assume that no value means true. Or do you mean something else?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unresolved this because of the open question.

If we always provide harness, then we have three states: true, false, and "unknown". The last one is relevant when using an old version of Cargo. If we skip on default (would it be a true? false?) then a caller can't differentiate it from "unknown".

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks, I understand now :). Dealing with "unknown" is unavoidable, at least for a while, because older versions of cargo won't have this field. The problem is that now there is some ambiguity: a value not present might be either true or unknown depending on the version of cargo.

For us it would be slightly better if the default was not skipped. In that way, our logic will be something like: if harness is not there, fallback to try to get it from Cargo.toml. If we skip the default value, our logic will be: if harness is not there an cargo version > x it's true otherwise fallback.

So we can manage both ways. I understand the spirit of the guidelines and the fact that extra data means extra parsing time and this can affect certain tools. But from my perspective the ambiguity introduced is worse. So I would prefer if we don't skip.

}

impl ser::Serialize for Target {
Expand All @@ -418,6 +421,7 @@ impl ser::Serialize for Target {
doc: self.documented(),
doctest: self.doctested() && self.doctestable(),
test: self.tested(),
harness: self.harness(),
}
.serialize(s)
}
Expand Down
8 changes: 7 additions & 1 deletion src/doc/man/cargo-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,13 @@ The JSON output has the following format:
"doctest": false,
/* Whether or not this target should be built and run with `--test`
*/
"test": true
"test": true,
/* Whether or not the target uses the libtest harness.
Corresponds to the `harness` field in `Cargo.toml`.
This property is not included if `harness` is true
(the default).
*/
"harness": false
}
],
/* Set of features defined for the package.
Expand Down
8 changes: 7 additions & 1 deletion src/doc/man/generated_txt/cargo-metadata.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,13 @@ OUTPUT FORMAT
"doctest": false,
/* Whether or not this target should be built and run with `--test`
*/
"test": true
"test": true,
/* Whether or not the target uses the libtest harness.
Corresponds to the `harness` field in `Cargo.toml`.
This property is not included if `harness` is true
(the default).
*/
"harness": false
}
],
/* Set of features defined for the package.
Expand Down
8 changes: 7 additions & 1 deletion src/doc/src/commands/cargo-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,13 @@ The JSON output has the following format:
"doctest": false,
/* Whether or not this target should be built and run with `--test`
*/
"test": true
"test": true,
/* Whether or not the target uses the libtest harness.
Corresponds to the `harness` field in `Cargo.toml`.
This property is not included if `harness` is true
(the default).
*/
"harness": false
}
],
/* Set of features defined for the package.
Expand Down
10 changes: 8 additions & 2 deletions src/doc/src/reference/external-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,12 @@ structure:
"doctest": true
/* Whether or not this target should be built and run with `--test`
*/
"test": true
"test": true,
/* Whether or not the target uses the libtest harness.
Corresponds to the `harness` field in `Cargo.toml`.

@epage epage Jun 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Raised a higher level concern at #11846 (comment)

View changes since the review

This property is not included if `harness` is true (the default).
*/
"harness": false
},
/* The message emitted by the compiler.

Expand Down Expand Up @@ -167,7 +172,8 @@ following structure:
"edition": "2018",
"doc": true,
"doctest": true,
"test": true
"test": true,
"harness": false
},
/* The profile indicates which compiler settings were used. */
"profile": {
Expand Down
3 changes: 2 additions & 1 deletion src/doc/src/reference/unstable.md
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,8 @@ The following is a description of the JSON structure:
"src_path": "/path/to/my-package/src/lib.rs",
"edition": "2018",
"test": true,
"doctest": true
"doctest": true,
"harness": false
},
/* The profile settings for this unit.
These values may not match the profile defined in the manifest.
Expand Down
8 changes: 7 additions & 1 deletion src/etc/man/cargo-metadata.1
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,13 @@ The JSON output has the following format:
"doctest": false,
/* Whether or not this target should be built and run with `\-\-test`
*/
"test": true
"test": true,
/* Whether or not the target uses the libtest harness.
Corresponds to the `harness` field in `Cargo.toml`.
This property is not included if `harness` is true
(the default).
*/
"harness": false
}
],
/* Set of features defined for the package.
Expand Down
123 changes: 123 additions & 0 deletions tests/testsuite/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,129 @@ fn cargo_metadata_warns_on_implicit_version() {
.run();
}

#[cargo_test]
fn cargo_metadata_no_harness() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"

[[test]]
name = "no_harness_test"
path = "tests/no_harness_test.rs"
harness = false

[[bench]]
name = "no_harness_bench"
path = "benches/no_harness_bench.rs"
harness = false
"#,
)
.file("src/lib.rs", "")
.file("tests/no_harness_test.rs", "fn main() {}")
.file("benches/no_harness_bench.rs", "fn main() {}")
.build();

p.cargo("metadata --no-deps --format-version 1")
.with_stdout_data(
str![[r#"
{
"metadata": null,
"packages": [
{
"authors": [],
"categories": [],
"default_run": null,
"dependencies": [],
"description": null,
"documentation": null,
"edition": "2015",
"features": {},
"homepage": null,
"id": "path+[ROOTURL]/foo#0.1.0",
"keywords": [],
"license": null,
"license_file": null,
"links": null,
"manifest_path": "[ROOT]/foo/Cargo.toml",
"metadata": null,
"name": "foo",
"publish": null,
"readme": null,
"repository": null,
"rust_version": null,
"source": null,
"targets": [
{
"crate_types": [
"lib"
],
"doc": true,
"doctest": true,
"edition": "2015",
"kind": [
"lib"
],
"name": "foo",
"src_path": "[ROOT]/foo/src/lib.rs",
"test": true
},
{
"crate_types": [
"bin"
],
"doc": false,
"doctest": false,
"edition": "2015",
"harness": false,
"kind": [
"test"
],
"name": "no_harness_test",
"src_path": "[ROOT]/foo/tests/no_harness_test.rs",
"test": true
},
{
"crate_types": [
"bin"
],
"doc": false,
"doctest": false,
"edition": "2015",
"harness": false,
"kind": [
"bench"
],
"name": "no_harness_bench",
"src_path": "[ROOT]/foo/benches/no_harness_bench.rs",
"test": false
}
],
"version": "0.1.0"
}
],
"resolve": null,
"target_directory": "[ROOT]/foo/target",
"build_directory": "[ROOT]/foo/target",
"version": 1,
"workspace_default_members": [
"path+[ROOTURL]/foo#0.1.0"
],
"workspace_members": [
"path+[ROOTURL]/foo#0.1.0"
],
"workspace_root": "[ROOT]/foo"
}
"#]]
.is_json(),
)
.run();
}

#[cargo_test]
fn library_with_several_crate_types() {
let p = project()
Expand Down
Loading