Skip to content

Commit 619e47b

Browse files
authored
Rollup merge of #82311 - aDotInTheVoid:jsondocck-improvements, r=jyn514
Jsondocck improvements Adds 2 new commands, ```@is``` and ```@set`.`` ```@is``` works like ```@has`,`` except instead of checking if any value matches, it checks that there is exactly one value, and it matches. This allows more precise testing. ```@set``` gets a value, and saves it to be used later. This makes it possible to check that an item appears in the correct module. Once this lands, the rest of the test suite can be upgraded to use these. cc ``@CraftSpider`` ``@rustbot`` modify labels: +T-rustdoc +A-rustdoc-json +A-testsuite
2 parents 269f399 + 4c949a4 commit 619e47b

File tree

3 files changed

+70
-27
lines changed

3 files changed

+70
-27
lines changed

src/test/rustdoc-json/nested.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
// edition:2018
22

3-
// @has nested.json "$.index[*][?(@.name=='nested')].kind" \"module\"
4-
// @has - "$.index[*][?(@.name=='nested')].inner.is_crate" true
3+
// @is nested.json "$.index[*][?(@.name=='nested')].kind" \"module\"
4+
// @is - "$.index[*][?(@.name=='nested')].inner.is_crate" true
55
// @count - "$.index[*][?(@.name=='nested')].inner.items[*]" 1
66

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

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

17-
// @has nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\"
18-
// @has - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\"
19+
// @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\"
20+
// @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\"
21+
// @set l4_id = - "$.index[*][?(@.name=='L4')].id"
22+
// @has - "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id
1923
pub struct L4;
2024
}
21-
// @has nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\"
22-
// @has - "$.index[*][?(@.inner.span=='l3::L4')].inner.glob" false
25+
// @is nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\"
26+
// @is - "$.index[*][?(@.inner.span=='l3::L4')].inner.glob" false
2327
pub use l3::L4;
2428
}

src/tools/jsondocck/src/cache.rs

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub struct Cache {
99
root: PathBuf,
1010
files: HashMap<PathBuf, String>,
1111
values: HashMap<PathBuf, Value>,
12+
pub variables: HashMap<String, Value>,
1213
last_path: Option<PathBuf>,
1314
}
1415

@@ -19,6 +20,7 @@ impl Cache {
1920
root: Path::new(doc_dir).to_owned(),
2021
files: HashMap::new(),
2122
values: HashMap::new(),
23+
variables: HashMap::new(),
2224
last_path: None,
2325
}
2426
}

src/tools/jsondocck/src/main.rs

+54-17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use jsonpath_lib::select;
22
use lazy_static::lazy_static;
33
use regex::{Regex, RegexBuilder};
44
use serde_json::Value;
5+
use std::borrow::Cow;
56
use std::{env, fmt, fs};
67

78
mod cache;
@@ -48,13 +49,16 @@ pub struct Command {
4849
pub enum CommandKind {
4950
Has,
5051
Count,
52+
Is,
53+
Set,
5154
}
5255

5356
impl CommandKind {
5457
fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool {
5558
let count = match self {
5659
CommandKind::Has => (1..=3).contains(&args.len()),
57-
CommandKind::Count => 3 == args.len(),
60+
CommandKind::Count | CommandKind::Is => 3 == args.len(),
61+
CommandKind::Set => 4 == args.len(),
5862
};
5963

6064
if !count {
@@ -83,6 +87,8 @@ impl fmt::Display for CommandKind {
8387
let text = match self {
8488
CommandKind::Has => "has",
8589
CommandKind::Count => "count",
90+
CommandKind::Is => "is",
91+
CommandKind::Set => "set",
8692
};
8793
write!(f, "{}", text)
8894
}
@@ -127,6 +133,8 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
127133
let cmd = match cmd {
128134
"has" => CommandKind::Has,
129135
"count" => CommandKind::Count,
136+
"is" => CommandKind::Is,
137+
"set" => CommandKind::Set,
130138
_ => {
131139
print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
132140
errors = true;
@@ -180,6 +188,7 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
180188
/// Performs the actual work of ensuring a command passes. Generally assumes the command
181189
/// is syntactically valid.
182190
fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
191+
// FIXME: Be more granular about why, (e.g. syntax error, count not equal)
183192
let result = match command.kind {
184193
CommandKind::Has => {
185194
match command.args.len() {
@@ -188,23 +197,15 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
188197
// @has <path> <jsonpath> = check path exists
189198
2 => {
190199
let val = cache.get_value(&command.args[0])?;
191-
192-
match select(&val, &command.args[1]) {
193-
Ok(results) => !results.is_empty(),
194-
Err(_) => false,
195-
}
200+
let results = select(&val, &command.args[1]).unwrap();
201+
!results.is_empty()
196202
}
197203
// @has <path> <jsonpath> <value> = check *any* item matched by path equals value
198204
3 => {
199205
let val = cache.get_value(&command.args[0])?;
200-
match select(&val, &command.args[1]) {
201-
Ok(results) => {
202-
let pat: Value = serde_json::from_str(&command.args[2]).unwrap();
203-
204-
!results.is_empty() && results.into_iter().any(|val| *val == pat)
205-
}
206-
Err(_) => false,
207-
}
206+
let results = select(&val, &command.args[1]).unwrap();
207+
let pat = string_to_value(&command.args[2], cache);
208+
results.contains(&pat.as_ref())
208209
}
209210
_ => unreachable!(),
210211
}
@@ -215,9 +216,37 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
215216
let expected: usize = command.args[2].parse().unwrap();
216217

217218
let val = cache.get_value(&command.args[0])?;
218-
match select(&val, &command.args[1]) {
219-
Ok(results) => results.len() == expected,
220-
Err(_) => false,
219+
let results = select(&val, &command.args[1]).unwrap();
220+
results.len() == expected
221+
}
222+
CommandKind::Is => {
223+
// @has <path> <jsonpath> <value> = check *exactly one* item matched by path, and it equals value
224+
assert_eq!(command.args.len(), 3);
225+
let val = cache.get_value(&command.args[0])?;
226+
let results = select(&val, &command.args[1]).unwrap();
227+
let pat = string_to_value(&command.args[2], cache);
228+
results.len() == 1 && results[0] == pat.as_ref()
229+
}
230+
CommandKind::Set => {
231+
// @set <name> = <path> <jsonpath>
232+
assert_eq!(command.args.len(), 4);
233+
assert_eq!(command.args[1], "=", "Expected an `=`");
234+
let val = cache.get_value(&command.args[2])?;
235+
let results = select(&val, &command.args[3]).unwrap();
236+
assert_eq!(results.len(), 1);
237+
match results.len() {
238+
0 => false,
239+
1 => {
240+
let r = cache.variables.insert(command.args[0].clone(), results[0].clone());
241+
assert!(r.is_none(), "Name collision: {} is duplicated", command.args[0]);
242+
true
243+
}
244+
_ => {
245+
panic!(
246+
"Got multiple results in `@set` for `{}`: {:?}",
247+
&command.args[3], results
248+
);
249+
}
221250
}
222251
}
223252
};
@@ -247,3 +276,11 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
247276
Ok(())
248277
}
249278
}
279+
280+
fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> {
281+
if s.starts_with("$") {
282+
Cow::Borrowed(&cache.variables[&s[1..]])
283+
} else {
284+
Cow::Owned(serde_json::from_str(s).unwrap())
285+
}
286+
}

0 commit comments

Comments
 (0)