Skip to content

Commit

Permalink
Merge pull request #2393 from dathere/validate-schema
Browse files Browse the repository at this point in the history
feat: `validate` add `--validate-schema` option to check if the JSON Schema itself is valid
  • Loading branch information
jqnatividad authored Dec 31, 2024
2 parents aaee3e9 + 3575a16 commit 2e6ec06
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 15 deletions.
4 changes: 2 additions & 2 deletions resources/test/public-toilets-schema.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://json-schema.org/draft-07/schema",
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://example.com/public_toilets_schema.json",
"title": "Public Toilets",
"description": "Manually converted from JSON Table Schema at https://github.com/esd-org-uk/schemas/blob/master/PublicToilets/PublicToilets.json",
Expand Down Expand Up @@ -170,4 +170,4 @@
}
},
"required": [ "ExtractDate", "OrganisationLabel", "ServiceTypeLabel", "LocationText", "GeoX", "GeoY" ]
}
}
39 changes: 35 additions & 4 deletions src/cmd/validate.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
static USAGE: &str = r#"
Validates CSV data using two modes:
Validates CSV data using two main modes:
JSON SCHEMA VALIDATION MODE:
===========================
Expand Down Expand Up @@ -98,12 +98,15 @@ If we validate another CSV file, "mydata2.csv", which we know is valid, there ar
and the exit code is 0.
If piped from stdin, the filenames will use `stdin.csv` as the base filename. For example:
`cat mydata.csv | qsv validate reference.schema.json`
`cat mydata.csv | qsv validate reference.schema.json`
* stdin.csv.valid
* stdin.csv.invalid
* stdin.csv.validation-errors.tsv
`validate` also has a `schema` subcommand to validate JSON Schema files. For example:
`qsv validate schema myjsonschema.json`
RFC 4180 VALIDATION MODE:
========================
Expand All @@ -119,6 +122,7 @@ For examples, see the tests included in this file (denoted by '#[test]') or see
https://github.com/dathere/qsv/blob/master/tests/test_validate.rs.
Usage:
qsv validate schema [<json-schema>]
qsv validate [options] [<input>] [<json-schema>]
qsv validate --help
Expand Down Expand Up @@ -256,6 +260,7 @@ macro_rules! fail_validation_error {
#[derive(Deserialize)]
#[allow(dead_code)]
struct Args {
cmd_schema: bool,
flag_trim: bool,
flag_fail_fast: bool,
flag_valid: Option<String>,
Expand Down Expand Up @@ -570,6 +575,30 @@ fn dyn_enum_validator_factory<'a>(
pub fn run(argv: &[&str]) -> CliResult<()> {
let args: Args = util::get_args(USAGE, argv)?;

// validate the JSON Schema file
if args.cmd_schema {
if let Some(ref schema) = args.arg_json_schema {
let schema_json = load_json(&schema)?;
match jsonschema::meta::try_is_valid(&serde_json::from_str(&schema_json)?) {
Ok(is_valid) => {
if is_valid {
if !args.flag_quiet {
winfo!("Valid JSON Schema.");
return Ok(());
}
} else {
return fail_clierror!("Invalid JSON Schema.");
}
},
Err(e) => {
return fail_clierror!("Invalid JSON Schema: {e}");
},
}
} else {
return fail_clierror!("No JSON Schema file supplied.");
}
}

TIMEOUT_SECS.store(
util::timeout_secs(args.flag_timeout)? as u16,
Ordering::Relaxed,
Expand Down Expand Up @@ -860,12 +889,14 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
{
Ok(schema) => (json, schema),
Err(e) => {
return fail_clierror!("Cannot compile JSONschema. error: {e}");
return fail_clierror!(r#"Cannot compile JSONschema. error: {e}
Try running `qsv validate --validate-schema` to check the JSON Schema file."#);
},
}
},
Err(e) => {
return fail_clierror!("Unable to parse JSONschema. error: {e}");
return fail_clierror!(r#"Unable to parse JSONschema. error: {e}
Try running `qsv validate --validate-schema` to check the JSON Schema file."#);
},
}
},
Expand Down
10 changes: 5 additions & 5 deletions tests/test_partition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ macro_rules! part_eq {

fn data(headers: bool) -> Vec<Vec<String>> {
let mut rows = vec![
svec!["NY", "Manhatten"],
svec!["NY", "Manhattan"],
svec!["CA", "San Francisco"],
svec!["TX", "Dallas"],
svec!["NY", "Buffalo"],
Expand Down Expand Up @@ -47,7 +47,7 @@ CA,San Francisco
"NY.csv",
"\
state,city
NY,Manhatten
NY,Manhattan
NY,Buffalo
"
);
Expand Down Expand Up @@ -87,7 +87,7 @@ San Francisco
"NY.csv",
"\
city
Manhatten
Manhattan
Buffalo
"
);
Expand Down Expand Up @@ -125,7 +125,7 @@ CA,San Francisco
wrk,
"NY.csv",
"\
NY,Manhatten
NY,Manhattan
NY,Buffalo
"
);
Expand Down Expand Up @@ -163,7 +163,7 @@ San Francisco
wrk,
"NY.csv",
"\
Manhatten
Manhattan
Buffalo
"
);
Expand Down
8 changes: 4 additions & 4 deletions tests/test_validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,10 @@ fn validate_adur_public_toilets_dataset_with_json_schema_valid_output() {
.arg("schema.json")
.args(["--valid-output", "-"]);

let out = wrk.output_stderr(&mut cmd);
let expected = "13\n";
assert_eq!(out, expected);

let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
let expected = vec![
svec!["ExtractDate", "OrganisationURI", "OrganisationLabel", "ServiceTypeURI", "ServiceTypeLabel", "LocationText", "CoordinateReferenceSystem", "GeoX", "GeoY", "GeoPointLicensingURL", "Category", "AccessibleCategory", "RADARKeyNeeded", "BabyChange", "FamilyToilet", "ChangingPlace", "AutomaticPublicConvenience", "FullTimeStaffing", "PartOfCommunityScheme", "CommunitySchemeName", "ChargeAmount", "InfoURL", "OpeningHours", "ManagedBy", "ReportEmail", "ReportTel", "Notes", "UPRN", "Postcode", "StreetAddress", "GeoAreaURI", "GeoAreaLabel"],
Expand All @@ -319,10 +323,6 @@ fn validate_adur_public_toilets_dataset_with_json_schema_valid_output() {
];
assert_eq!(got, expected);

let num_recs = wrk.output_stderr(&mut cmd);
let num_recs_expected = "13".to_string();
assert_eq!(num_recs.trim_end(), num_recs_expected);

wrk.assert_err(&mut cmd);
}

Expand Down

0 comments on commit 2e6ec06

Please sign in to comment.