Skip to content

Rustdoc json tests: New @ismany test command #99474

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
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
13 changes: 7 additions & 6 deletions src/test/rustdoc-json/nested.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,28 @@
// @is nested.json "$.crate_version" \"1.0.0\"
// @is - "$.index[*][?(@.name=='nested')].kind" \"module\"
// @is - "$.index[*][?(@.name=='nested')].inner.is_crate" true
// @count - "$.index[*][?(@.name=='nested')].inner.items[*]" 1

// @set l1_id = - "$.index[*][?(@.name=='l1')].id"
// @ismany - "$.index[*][?(@.name=='nested')].inner.items[*]" $l1_id

// @is nested.json "$.index[*][?(@.name=='l1')].kind" \"module\"
// @is - "$.index[*][?(@.name=='l1')].inner.is_crate" false
// @count - "$.index[*][?(@.name=='l1')].inner.items[*]" 2
pub mod l1 {

// @is nested.json "$.index[*][?(@.name=='l3')].kind" \"module\"
// @is - "$.index[*][?(@.name=='l3')].inner.is_crate" false
// @count - "$.index[*][?(@.name=='l3')].inner.items[*]" 1
// @set l3_id = - "$.index[*][?(@.name=='l3')].id"
// @has - "$.index[*][?(@.name=='l1')].inner.items[*]" $l3_id
pub mod l3 {

// @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\"
// @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\"
// @set l4_id = - "$.index[*][?(@.name=='L4')].id"
// @has - "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id
// @ismany - "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id
pub struct L4;
}
// @is nested.json "$.index[*][?(@.inner.source=='l3::L4')].kind" \"import\"
// @is - "$.index[*][?(@.inner.source=='l3::L4')].inner.glob" false
// @is - "$.index[*][?(@.inner.source=='l3::L4')].inner.id" $l4_id
// @set l4_use_id = - "$.index[*][?(@.inner.source=='l3::L4')].id"
pub use l3::L4;
}
// @ismany - "$.index[*][?(@.name=='l1')].inner.items[*]" $l3_id $l4_use_id
9 changes: 7 additions & 2 deletions src/test/rustdoc-json/reexport/glob_extern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@
#![feature(no_core)]

// @is glob_extern.json "$.index[*][?(@.name=='mod1')].kind" \"module\"
// @is glob_extern.json "$.index[*][?(@.name=='mod1')].inner.is_stripped" "true"
// @is - "$.index[*][?(@.name=='mod1')].inner.is_stripped" "true"
Copy link
Member

@Enselic Enselic Jul 19, 2022

Choose a reason for hiding this comment

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

Sorry to nit-pick, but I wonder: Is it worth to use - instead of the whole filename? That messes up the alignment and makes the code harder to read, IMHO.

Edit: Well, if all other lines use - then the alignment becomes good for them at least...

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, most of the tests use - for all but the first item. (Side note, I should add a feature to set the - to the obvious value initialy, because I don't think this is ever used, but just a hold over from the HTML side)

mod mod1 {
extern "C" {
// @has - "$.index[*][?(@.name=='public_fn')].id"
// @set public_fn_id = - "$.index[*][?(@.name=='public_fn')].id"
pub fn public_fn();
// @!has - "$.index[*][?(@.name=='private_fn')]"
fn private_fn();
}
// @ismany - "$.index[*][?(@.name=='mod1')].inner.items[*]" $public_fn_id
// @set mod1_id = - "$.index[*][?(@.name=='mod1')].id"
}

// @is - "$.index[*][?(@.kind=='import')].inner.glob" true
// @is - "$.index[*][?(@.kind=='import')].inner.id" $mod1_id
// @set use_id = - "$.index[*][?(@.kind=='import')].id"
// @ismany - "$.index[*][?(@.name=='glob_extern')].inner.items[*]" $use_id
pub use mod1::*;
9 changes: 5 additions & 4 deletions src/test/rustdoc-json/reexport/glob_private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mod mod1 {
struct Mod2Private;
}

// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='mod2')]"
// @set mod2_use_id = - "$.index[*][?(@.kind=='import' && @.inner.name=='mod2')].id"
pub use self::mod2::*;

// @set m1pub_id = - "$.index[*][?(@.name=='Mod1Public')].id"
Expand All @@ -25,8 +25,9 @@ mod mod1 {
struct Mod1Private;
}

// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='mod1')]"
// @set mod1_use_id = - "$.index[*][?(@.kind=='import' && @.inner.name=='mod1')].id"
pub use mod1::*;

// @has - "$.index[*][?(@.name=='mod2')].inner.items[*]" $m2pub_id
// @has - "$.index[*][?(@.name=='mod1')].inner.items[*]" $m1pub_id
// @ismany - "$.index[*][?(@.name=='mod2')].inner.items[*]" $m2pub_id
// @ismany - "$.index[*][?(@.name=='mod1')].inner.items[*]" $m1pub_id $mod2_use_id
// @ismany - "$.index[*][?(@.name=='glob_private')].inner.items[*]" $mod1_use_id
4 changes: 2 additions & 2 deletions src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

pub mod foo {
// @set bar_id = in_root_and_mod_pub.json "$.index[*][?(@.name=='Bar')].id"
// @has - "$.index[*][?(@.name=='foo')].inner.items[*]" $bar_id
// @ismany - "$.index[*][?(@.name=='foo')].inner.items[*]" $bar_id
pub struct Bar;
}

Expand All @@ -15,6 +15,6 @@ pub use foo::Bar;
pub mod baz {
// @set baz_import_id = - "$.index[*][?(@.inner.source=='crate::foo::Bar')].id"
// @is - "$.index[*][?(@.inner.source=='crate::foo::Bar')].inner.id" $bar_id
// @has - "$.index[*][?(@.name=='baz')].inner.items[*]" $baz_import_id
// @ismany - "$.index[*][?(@.name=='baz')].inner.items[*]" $baz_import_id
pub use crate::foo::Bar;
}
6 changes: 2 additions & 4 deletions src/test/rustdoc-json/reexport/macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@
#![no_core]
#![feature(no_core)]

// @count macro.json "$.index[*][?(@.name=='macro')].inner.items[*]" 2

// @set repro_id = macro.json "$.index[*][?(@.name=='repro')].id"
// @has - "$.index[*][?(@.name=='macro')].inner.items[*]" $repro_id
#[macro_export]
macro_rules! repro {
() => {};
}

// @set repro2_id = macro.json "$.index[*][?(@.inner.name=='repro2')].id"
// @has - "$.index[*][?(@.name=='macro')].inner.items[*]" $repro2_id
pub use crate::repro as repro2;

// @ismany macro.json "$.index[*][?(@.name=='macro')].inner.items[*]" $repro_id $repro2_id
18 changes: 14 additions & 4 deletions src/test/rustdoc-json/reexport/private_twice_one_inline.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
// aux-build:pub-struct.rs
// ignore-tidy-linelength

// Test for the ICE in rust/83057
// Am external type re-exported with different attributes shouldn't cause an error
// Test for the ICE in https://github.com/rust-lang/rust/issues/83057
// An external type re-exported with different attributes shouldn't cause an error

#![no_core]
#![feature(no_core)]

extern crate pub_struct as foo;

#[doc(inline)]

// @set crate_use_id = private_twice_one_inline.json "$.index[*][?(@.docs=='Hack A')].id"
// @set foo_id = - "$.index[*][?(@.docs=='Hack A')].inner.id"
/// Hack A
pub use foo::Foo;

// @set bar_id = - "$.index[*][?(@.name=='bar')].id"
pub mod bar {
// @is - "$.index[*][?(@.docs=='Hack B')].inner.id" $foo_id
// @set bar_use_id = - "$.index[*][?(@.docs=='Hack B')].id"
// @ismany - "$.index[*][?(@.name=='bar')].inner.items[*]" $bar_use_id
/// Hack B
pub use foo::Foo;
}

// @count private_twice_one_inline.json "$.index[*][?(@.kind=='import')]" 2
// @ismany - "$.index[*][?(@.kind=='import')].id" $crate_use_id $bar_use_id
// @ismany - "$.index[*][?(@.name=='private_twice_one_inline')].inner.items[*]" $bar_id $crate_use_id
14 changes: 10 additions & 4 deletions src/test/rustdoc-json/reexport/private_two_names.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// Test for the ICE in rust/83720
// ignore-tidy-linelength

// Test for the ICE in https://github.com/rust-lang/rust/issues/83720
// A pub-in-private type re-exported under two different names shouldn't cause an error

#![no_core]
Expand All @@ -7,11 +9,15 @@
// @is private_two_names.json "$.index[*][?(@.name=='style')].kind" \"module\"
// @is private_two_names.json "$.index[*][?(@.name=='style')].inner.is_stripped" "true"
mod style {
// @has - "$.index[*](?(@.name=='Color'))"
// @set color_struct_id = - "$.index[*][?(@.kind=='struct' && @.name=='Color')].id"
pub struct Color;
}

// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='Color')]"
// @is - "$.index[*][?(@.kind=='import' && @.inner.name=='Color')].inner.id" $color_struct_id
// @set color_export_id = - "$.index[*][?(@.kind=='import' && @.inner.name=='Color')].id"
pub use style::Color;
// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='Colour')]"
// @is - "$.index[*][?(@.kind=='import' && @.inner.name=='Colour')].inner.id" $color_struct_id
// @set colour_export_id = - "$.index[*][?(@.kind=='import' && @.inner.name=='Colour')].id"
pub use style::Color as Colour;

// @ismany - "$.index[*][?(@.name=='private_two_names')].inner.items[*]" $color_export_id $colour_export_id
6 changes: 3 additions & 3 deletions src/test/rustdoc-json/reexport/rename_public.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
#![feature(no_core)]

// @set inner_id = rename_public.json "$.index[*][?(@.name=='inner')].id"
// @has - "$.index[*][?(@.name=='rename_public')].inner.items[*]" $inner_id
pub mod inner {
// @set public_id = - "$.index[*][?(@.name=='Public')].id"
// @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id
// @ismany - "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id
pub struct Public;
}
// @set import_id = - "$.index[*][?(@.inner.name=='NewName')].id"
// @!has - "$.index[*][?(@.inner.name=='Public')]"
// @has - "$.index[*][?(@.name=='rename_public')].inner.items[*]" $import_id
// @is - "$.index[*][?(@.inner.name=='NewName')].inner.source" \"inner::Public\"
pub use inner::Public as NewName;

// @ismany - "$.index[*][?(@.name=='rename_public')].inner.items[*]" $inner_id $import_id
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
// ignore-tidy-linelength

// Regression test for <https://github.com/rust-lang/rust/issues/97432>.

#![feature(no_core)]
#![no_std]
#![no_core]

// @has same_type_reexported_more_than_once.json
// @has - "$.index[*][?(@.name=='Trait')]"
pub use inner::Trait;
// @has - "$.index[*].inner[?(@.name=='Reexport')].id"
pub use inner::Trait as Reexport;

mod inner {
// @set trait_id = - "$.index[*][?(@.name=='Trait')].id"
pub trait Trait {}
}

// @set export_id = - "$.index[*][?(@.inner.name=='Trait')].id"
// @is - "$.index[*][?(@.inner.name=='Trait')].inner.id" $trait_id
pub use inner::Trait;
// @set reexport_id = - "$.index[*][?(@.inner.name=='Reexport')].id"
// @is - "$.index[*][?(@.inner.name=='Reexport')].inner.id" $trait_id
pub use inner::Trait as Reexport;

// @ismany - "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.items[*]" $reexport_id $export_id
4 changes: 3 additions & 1 deletion src/test/rustdoc-json/reexport/simple_private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ mod inner {
}

// @is - "$.index[*][?(@.kind=='import')].inner.name" \"Public\"
// @set use_id = - "$.index[*][?(@.kind=='import')].id"
pub use inner::Public;

// @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $pub_id
// @ismany - "$.index[*][?(@.name=='inner')].inner.items[*]" $pub_id
// @ismany - "$.index[*][?(@.name=='simple_private')].inner.items[*]" $use_id
6 changes: 3 additions & 3 deletions src/test/rustdoc-json/reexport/simple_public.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
#![feature(no_core)]

// @set inner_id = simple_public.json "$.index[*][?(@.name=='inner')].id"
// @has - "$.index[*][?(@.name=='simple_public')].inner.items[*]" $inner_id
pub mod inner {

// @set public_id = - "$.index[*][?(@.name=='Public')].id"
// @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id
// @ismany - "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id
pub struct Public;
}

// @set import_id = - "$.index[*][?(@.inner.name=='Public')].id"
// @has - "$.index[*][?(@.name=='simple_public')].inner.items[*]" $import_id
// @is - "$.index[*][?(@.inner.name=='Public')].inner.source" \"inner::Public\"
pub use inner::Public;

// @ismany - "$.index[*][?(@.name=='simple_public')].inner.items[*]" $import_id $inner_id
3 changes: 1 addition & 2 deletions src/test/rustdoc-json/type/fn_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

// @is fn_lifetime.json "$.index[*][?(@.name=='GenericFn')].kind" \"typedef\"

// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*]" 1
// @is - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].name" \"\'a\"
// @ismany - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].name" \"\'a\"
// @has - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime"
// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime.outlives[*]" 0
// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.where_predicates[*]" 0
Expand Down
42 changes: 42 additions & 0 deletions src/tools/jsondocck/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@ pub enum CommandKind {
Has,
Count,
Is,
IsMany,
Set,
}

impl CommandKind {
fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool {
let count = match self {
CommandKind::Has => (1..=3).contains(&args.len()),
CommandKind::IsMany => args.len() >= 3,
CommandKind::Count | CommandKind::Is => 3 == args.len(),
CommandKind::Set => 4 == args.len(),
};
Expand Down Expand Up @@ -89,6 +91,7 @@ impl fmt::Display for CommandKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let text = match self {
CommandKind::Has => "has",
CommandKind::IsMany => "ismany",
CommandKind::Count => "count",
CommandKind::Is => "is",
CommandKind::Set => "set",
Expand Down Expand Up @@ -137,6 +140,7 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
"has" => CommandKind::Has,
"count" => CommandKind::Count,
"is" => CommandKind::Is,
"ismany" => CommandKind::IsMany,
"set" => CommandKind::Set,
_ => {
print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
Expand Down Expand Up @@ -227,6 +231,44 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
_ => unreachable!(),
}
}
CommandKind::IsMany => {
// @ismany <path> <jsonpath> <value>...
let (path, query, values) = if let [path, query, values @ ..] = &command.args[..] {
(path, query, values)
} else {
unreachable!("Checked in CommandKind::validate")
};
let val = cache.get_value(path)?;
let got_values = select(&val, &query).unwrap();
assert!(!command.negated, "`@!ismany` is not supported");

// Serde json doesn't implement Ord or Hash for Value, so we must
// use a Vec here. While in theory that makes setwize equality
// O(n^2), in practice n will never be large enought to matter.
Copy link
Member

Choose a reason for hiding this comment

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

I feel like a 'hasexact' would make me expect that it would check the order too, not just presence -- and that would avoid any question of n^2 comparison time. I agree that n^2 comparison time isn't itself an issue, though, so maybe this is fine as-is.

Copy link
Member Author

Choose a reason for hiding this comment

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

It needs to not check order, as that's not a property that's stable, so the intension is to a setwise comparison.

HasExact should definatly be renamed, as it's been confusing twice now.

let expected_values =
values.iter().map(|v| string_to_value(v, cache)).collect::<Vec<_>>();
if expected_values.len() != got_values.len() {
return Err(CkError::FailedCheck(
format!(
"Expected {} values, but `{}` matched to {} values ({:?})",
expected_values.len(),
query,
got_values.len(),
got_values
),
command,
));
};
for got_value in got_values {
if !expected_values.iter().any(|exp| &**exp == got_value) {
return Err(CkError::FailedCheck(
format!("`{}` has match {:?}, which was not expected", query, got_value),
command,
));
}
}
true
}
CommandKind::Count => {
// @count <path> <jsonpath> <count> = Check that the jsonpath matches exactly [count] times
assert_eq!(command.args.len(), 3);
Expand Down