diff --git a/.ci/test-cover b/.ci/test-cover new file mode 100755 index 0000000..6f413e5 --- /dev/null +++ b/.ci/test-cover @@ -0,0 +1,31 @@ +#!/bin/bash + +set -e + +DESTDIR="${PWD}/target/cover" + +rustup component add llvm-tools +cargo install grcov + +export RUSTFLAGS="-Cinstrument-coverage" +export LLVM_PROFILE_FILE="${DESTDIR}/default_%m_%p.profraw" +cargo test + +grcov "${DESTDIR}" \ + --ignore '**/clang-sys*/**' \ + --ignore "$HOME/.cargo/**" \ + --ignore-not-existing \ + --ignore 'tests/**' \ + --excl-start '#(\[cfg\(test\)\]|\[test\])' \ + --llvm \ + --binary-path "target/debug/" \ + -s . \ + --branch \ + -o "${DESTDIR}" \ + --output-types html,cobertura + +xmllint --xpath "concat('Coverage: ', 100 * string(//coverage/@line-rate), '%')" "${DESTDIR}/cobertura.xml" + +if [ "$(uname -o)" = "Darwin" ] && [ -z "$CI" ]; then + open "${DESTDIR}/html/index.html" +fi diff --git a/.github/workflows/test-and-lint.yml b/.github/workflows/test-and-lint.yml index 6360125..3d4df37 100644 --- a/.github/workflows/test-and-lint.yml +++ b/.github/workflows/test-and-lint.yml @@ -33,3 +33,13 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: Run pre-commit uses: pre-commit/action@v3.0.1 + - name: Install dependencies + run: sudo apt-get install -y libxml2-utils + - name: Generate Coverage + run: make cover RUST_BACKTRACE=1 + - name: Publish Coverage + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: pgxn/meta + files: target/cover/cobertura.xml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 306f7b5..aa09062 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,6 +13,14 @@ repos: name: Don't permit large files exclude_types: [image] + - repo: local + hooks: + - id: cargo-doc + name: cargo doc + entry: cargo doc + language: system + pass_filenames: false + - repo: https://github.com/backplane/pre-commit-rust-hooks rev: v1.1.0 hooks: diff --git a/Cargo.lock b/Cargo.lock index 6eb6aee..80556b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,6 +68,32 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "const_format" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "fluent-uri" version = "0.1.4" @@ -107,6 +133,15 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -125,6 +160,22 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -138,13 +189,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] -name = "pgxn-meta-spec" +name = "pgxn_meta" version = "0.1.0" dependencies = [ "boon", + "relative-path", "serde", "serde_json", "spdx", + "wax", +] + +[[package]] +name = "pori" +version = "0.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a63d338dec139f56dacc692ca63ad35a6be6a797442479b55acd611d79e906" +dependencies = [ + "nom", ] [[package]] @@ -194,12 +256,27 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "serde" version = "1.0.203" @@ -257,6 +334,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tinyvec" version = "1.6.1" @@ -293,6 +390,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "url" version = "2.5.2" @@ -310,12 +413,119 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wax" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d12a78aa0bab22d2f26ed1a96df7ab58e8a93506a3e20adb47c51a93b4e1357" +dependencies = [ + "const_format", + "itertools", + "nom", + "pori", + "regex", + "thiserror", + "walkdir", +] + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "zerocopy" version = "0.7.34" diff --git a/Cargo.toml b/Cargo.toml index 6f33a3e..bdee343 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "pgxn-meta-spec" +name = "pgxn_meta" version = "0.1.0" description = "The PGXN distribution metadata specification" repository = "https://github.com/pgxn/pgxn-meta-spec" @@ -12,10 +12,12 @@ exclude = [ ".github", ".gitattributes", "target", ".vscode", ".gitignore" ] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dev-dependencies] -boon = "0.6" -serde_json = "1.0" - [dependencies] +boon = "0.6" +relative-path = "1.9.3" serde = { version = "1", features = ["derive"] } +serde_json = "1.0" spdx = "0.10.6" +wax = "0.6.0" + +[dev-dependencies] diff --git a/Makefile b/Makefile index b1e3080..b71b752 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: test # Validate the JSON schema. +.PHONY: test # Run the full test suite. test: @cargo test @@ -9,3 +9,14 @@ test: .PHONY: lint # Lint the project lint: .pre-commit-config.yaml @pre-commit run --show-diff-on-failure --color=always --all-files + +.PHONY: cover # Run cover tests and generate & open a report. +cover: + @./.ci/test-cover + +.PHONY: docs # Generate and open cargo docs. +docs: target/doc/pgxn_meta/index.html + open $< + +target/doc/pgxn_meta/index.html: $(shell find . -name \*.rs) + cargo doc diff --git a/README.md b/README.md index 1d8b4e2..b77fac2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ PGXN Meta Spec ============== +[![PostgreSQL License](https://img.shields.io/badge/License-PostgreSQL-blue.svg)](https://opensource.org/licenses/PostgreSQL "⚖️ PostgreSQL License") +[![Build Status](https://github.com/pgxn/meta/actions/workflows/test-and-lint/badge.svg)](https://github.com/pgxn/meta/actions +workflows/test-and-lint "🧪 Test and Lint") +[![Code Coverage](https://codecov.io/gh/pgxn/meta/graph/badge.svg?token=5DOLLPIHEO)](https://codecov.io/gh/pgxn/meta "📊 Code Coverage") + The PGXN Meta Spec defines the requirements for the metadata file (`META.json`) file for [PGXN] source distribution packages. diff --git a/schema/v2/path.schema.json b/schema/v2/path.schema.json index f39b10a..9864fce 100644 --- a/schema/v2/path.schema.json +++ b/schema/v2/path.schema.json @@ -6,7 +6,6 @@ "type": "string", "minLength": 2, "format": "path", - "pattern": "^(?:[^/\\\\]|\\\\\\\\)(?:[^\\\\]|\\\\\\\\)+$", "$comment": "https://regex101.com/r/d49AVj", "examples": [".git", "src/pair.c", "doc/pair.md"] } diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs new file mode 100644 index 0000000..70ec653 --- /dev/null +++ b/src/compiler/mod.rs @@ -0,0 +1,152 @@ +use relative_path::{Component, RelativePath}; +/// Public but undocumented and un-exported module that creates a +/// boon::Compiler for use in validation and Tests. +use std::error::Error; +use std::fs::File; +use std::path::Path; + +use boon::Compiler; +use serde_json::Value; +use wax::Glob; + +/// new returns a new boon::compiler with the schema files loaded from `dir` +/// and configured to validate `path` and `license` formats. +pub fn new>(dir: P) -> Result> { + let mut compiler = spec_compiler(); + + let glob = Glob::new("**/*.schema.json")?; + for path in glob.walk(dir) { + let schema: Value = serde_json::from_reader(File::open(path?.into_path())?)?; + let s = &schema["$id"] + .as_str() + .ok_or(super::valid::ValidationError::UnknownID)?; + compiler.add_resource(s, schema.to_owned())?; + } + + Ok(compiler) +} + +/// Creates a new boon::compiler with format assertions enabled and validation +/// for the custom `path` and `license` formats. +fn spec_compiler() -> Compiler { + let mut compiler = Compiler::new(); + compiler.enable_format_assertions(); + compiler.register_format(boon::Format { + name: "path", + func: is_path, + }); + compiler.register_format(boon::Format { + name: "license", + func: is_license, + }); + compiler +} + +/// Returns an error if v is not a valid path. +fn is_path(v: &Value) -> Result<(), Box> { + let Value::String(s) = v else { + Err("not a string")? + }; + + let path = RelativePath::new(s); + for c in path.components() { + if c == Component::ParentDir { + Err("parent dir")? + }; + } + + Ok(()) +} + +/// Returns an error if vi is not a valid SPDX license expression. +fn is_license(v: &Value) -> Result<(), Box> { + let Value::String(s) = v else { + Err("not a string")? + }; + _ = spdx::Expression::parse(s)?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn test_path() { + // Test valid paths. + for valid in [ + json!("\\foo.md"), + json!("this\\and\\that.txt"), + json!("/absolute/path"), + json!(""), + json!("C:\\foo"), + json!("README.txt"), + json!(".git"), + json!("src/pair.c"), + json!(".github/workflows/"), + json!("this\\\\and\\\\that.txt"), + ] { + if let Err(e) = is_path(&valid) { + panic!("{} failed: {e}", valid); + } + } + + // Test invalid paths. + for invalid in [ + json!("../outside/path"), + json!("thing/../other"), + json!({}), + json!([]), + json!(true), + json!(null), + json!(42), + ] { + if is_path(&invalid).is_ok() { + panic!("{} unexpectedly passed!", invalid) + } + } + } + + #[test] + fn test_license() { + // Test valid relative licenses. + for valid_license in [ + json!("MIT"), + json!("PostgreSQL"), + json!("Apache-2.0 OR MIT"), + json!("Apache-2.0 OR MIT OR PostgreSQL"), + json!("Apache-2.0 AND MIT"), + json!("MIT OR Apache-2.0 AND BSD-2-Clause"), + json!("(MIT AND (LGPL-2.1-or-later OR BSD-3-Clause))"), + json!("((Apache-2.0 WITH LLVM-exception) OR Apache-2.0) AND OpenSSL OR MIT"), + json!("Apache-2.0 WITH LLVM-exception OR Apache-2.0 AND (OpenSSL OR MIT)"), + json!("Apache-2.0 WITH LLVM-exception OR (Apache-2.0 AND OpenSSL) OR MIT"), + json!("((((Apache-2.0 WITH LLVM-exception) OR (Apache-2.0)) AND (OpenSSL)) OR (MIT))"), + json!("CDDL-1.0+"), + json!("LicenseRef-23"), + json!("LicenseRef-MIT-Style-1"), + json!("DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2"), + ] { + if let Err(e) = is_license(&valid_license) { + panic!("{} failed: {e}", valid_license); + } + } + + // Test invalid licenses. + for invalid_license in [ + json!(""), + json!(null), + json!("0"), + json!(0), + json!("\n\t"), + json!("()"), + json!("AND"), + json!("OR"), + ] { + if is_license(&invalid_license).is_ok() { + panic!("{} unexpectedly passed!", invalid_license) + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..93cf3f1 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,49 @@ +#![deny(missing_docs)] +#![deny(rustdoc::missing_crate_level_docs)] +/*! +PGXN Metadata validation. + +This crate uses JSON Schema to validate PGXN Meta Spec `META.json` files. +It supports both the [v1] and [v2] specs. + +# Example + +``` rust +use std::{path::PathBuf, error::Error}; +use serde_json::json; +use pgxn_meta::*; + +let schemas_dir: PathBuf = [env!("CARGO_MANIFEST_DIR"), "schema"].iter().collect(); +let mut validator = Validator::new(schemas_dir)?; + +let meta = json!({ + "name": "pair", + "abstract": "A key/value pair data type", + "version": "0.1.8", + "maintainers": [{ "name": "theory", "email": "theory@pgxn.org" }], + "license": "PostgreSQL", + "contents": { + "extensions": { + "pair": { + "sql": "sql/pair.sql", + "control": "pair.control" + } + } + }, + "meta-spec": { "version": "2.0.0" } +}); + +assert!(validator.validate(&meta).is_ok()); +# Ok::<(), Box>(()) +``` + +[v1]: https://rfcs.pgxn.org/0001-meta-spec-v1.html +[v2]: https://rfcs.pgxn.org/0003-meta-spec-v2.html + +*/ + +mod valid; +pub use valid::{ValidationError, Validator}; + +#[doc(hidden)] +pub mod compiler; diff --git a/src/valid/mod.rs b/src/valid/mod.rs new file mode 100644 index 0000000..813455c --- /dev/null +++ b/src/valid/mod.rs @@ -0,0 +1,142 @@ +//! The valid module provides pgxn_meta validation. +use std::path::Path; +use std::{error::Error, fmt}; + +use boon::{Compiler, Schemas}; +use serde_json::Value; + +/// PGXN Meta validator. +pub struct Validator { + compiler: Compiler, + schemas: Schemas, +} + +/// Errors returned by Validator are ValidationError objects. +#[derive(Debug)] +pub enum ValidationError { + /// UnknownSpec errors are returned when the validator cannot determine + /// the version of the meta spec. + UnknownSpec, + /// UnknownID errors are returned by new() when a schema file has no `$id` + /// property. + UnknownID, +} + +impl Error for ValidationError {} + +impl fmt::Display for ValidationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ValidationError::UnknownSpec => write!(f, "Cannot determine meta-spec version"), + ValidationError::UnknownID => write!(f, "No $id found in schema"), + } + } +} +const SCHEMA_BASE: &str = "https://pgxn.org/meta/v"; + +impl Validator { + /// Validator constructor. + /// + /// new creates and returns a new Validator with the schemas loaded from + /// `dir`. + pub fn new>(dir: P) -> Result> { + let compiler = super::compiler::new(dir)?; + let schemas = Schemas::new(); + Ok(Validator { compiler, schemas }) + } + + /// Validates a PGXN Meta document. + /// + /// Load a `META.json` file into a serde_json::value::Value and pass it + /// for validation. Returns true on success and a validation error on + /// failure. + pub fn validate<'a>(&'a mut self, meta: &'a Value) -> Result> { + let map = meta.as_object().ok_or(ValidationError::UnknownSpec)?; + let version = map + .get("meta-spec") + .ok_or(ValidationError::UnknownSpec)? + .as_object() + .ok_or(ValidationError::UnknownSpec)? + .get("version") + .ok_or(ValidationError::UnknownSpec)? + .as_str() + .ok_or(ValidationError::UnknownSpec)?; + + let v = match &version[0..2] { + "1." => 1, + "2." => 2, + _ => return Err(Box::new(ValidationError::UnknownSpec)), + }; + let id = format!("{SCHEMA_BASE}{v}/distribution.schema.json"); + + let compiler = &mut self.compiler; + let schemas = &mut self.schemas; + let idx = compiler.compile(&id, schemas)?; + schemas.validate(meta, idx)?; + Ok(true) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::{json, Value}; + use std::error::Error; + use std::fs::File; + use std::path::PathBuf; + use wax::Glob; + + #[test] + fn test_corpus() -> Result<(), Box> { + let schemas_dir: PathBuf = [env!("CARGO_MANIFEST_DIR"), "schema"].iter().collect(); + let mut validator = Validator::new(schemas_dir)?; + + for v_dir in ["v1", "v2"] { + let dir: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests", "corpus", v_dir] + .iter() + .collect(); + let glob = Glob::new("*.json")?; + + for path in glob.walk(dir) { + let path = path?.into_path(); + let meta: Value = serde_json::from_reader(File::open(&path)?)?; + if let Err(e) = validator.validate(&meta) { + panic!("{v_dir}/{:?} failed: {e}", path.file_name().unwrap()); + } + println!("Example {v_dir}/{:?} ok", path.file_name().unwrap()); + } + } + Ok(()) + } + + #[test] + fn test_errors() { + assert_eq!( + format!("{}", ValidationError::UnknownSpec), + "Cannot determine meta-spec version", + ); + assert_eq!( + format!("{}", ValidationError::UnknownID), + "No $id found in schema", + ); + } + + #[test] + fn test_invalid_schemas() -> Result<(), Box> { + let schemas_dir: PathBuf = [env!("CARGO_MANIFEST_DIR"), "schema"].iter().collect(); + let mut validator = Validator::new(schemas_dir)?; + + for tc in [ + ("no meta spec", json!({})), + ("meta spec array", json!({"meta-spec": []})), + ("no meta version", json!({"meta-spec": {}})), + ("meta version bool", json!({"meta-spec": true})), + ("bad meta version", json!({"meta-spec": {"version": "0.0"}})), + ] { + let res = validator.validate(&tc.1); + assert!(res.is_err()); + } + + Ok(()) + } +} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 3b868ca..5fdd14f 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,5 +1,4 @@ use std::fs::{self, File}; -use std::path::{Component, Path}; use std::{collections::HashMap, error::Error}; use boon::{Compiler, Schemas}; @@ -88,69 +87,6 @@ pub fn id_for(version: u8, schema: &str) -> String { format!("{SCHEMA_BASE}{version}/{schema}.schema.json") } -fn spec_compiler() -> Compiler { - let mut compiler = Compiler::new(); - compiler.enable_format_assertions(); - compiler.register_format(boon::Format { - name: "path", - func: is_path, - }); - compiler.register_format(boon::Format { - name: "license", - func: is_license, - }); - compiler -} - -pub fn new_compiler(dir: &str) -> Result> { - let mut compiler = spec_compiler(); - - let paths = fs::read_dir(dir)?; - for path in paths { - let path = path?.path(); - let bn = path.file_name().unwrap().to_str().unwrap(); - if bn.ends_with(".schema.json") { - let schema: Value = serde_json::from_reader(File::open(path.clone())?)?; - if let Value::String(s) = &schema["$id"] { - // Add the schema to the compiler. - compiler.add_resource(s, schema.to_owned())?; - } else { - panic!("Unable to find ID in {}", path.display()); - } - } else { - println!("Skipping {}", path.display()); - } - } - - Ok(compiler) -} - -fn is_path(v: &Value) -> Result<(), Box> { - let Value::String(s) = v else { - return Ok(()); // applicable only on strings - }; - - let path = Path::new(s); - for c in path.components() { - match c { - Component::ParentDir => Err("parent dir")?, - Component::Prefix(_) => Err("windows path")?, - Component::RootDir => Err("absolute path")?, - _ => (), - }; - } - - Ok(()) -} - -fn is_license(v: &Value) -> Result<(), Box> { - let Value::String(s) = v else { - return Ok(()); // applicable only on strings - }; - _ = spdx::Expression::parse(s)?; - Ok(()) -} - pub fn test_term_schema(mut compiler: Compiler, version: u8) -> Result<(), Box> { let mut schemas = Schemas::new(); let id = id_for(version, "term"); @@ -250,7 +186,8 @@ pub fn test_tags_schema(mut compiler: Compiler, version: u8) -> Result<(), Box Result<(), Box> { - let mut compiler = spec_compiler(); + let mut compiler = Compiler::new(); + compiler.enable_format_assertions(); let mut loaded: HashMap> = HashMap::new(); let paths = fs::read_dir(format!("./schema/v{version}"))?; diff --git a/tests/corpus/v1/howto.json b/tests/corpus/v1/howto.json new file mode 100644 index 0000000..538f12b --- /dev/null +++ b/tests/corpus/v1/howto.json @@ -0,0 +1,19 @@ +{ + "name": "pair", + "abstract": "A key/value pair data type", + "version": "0.1.0", + "maintainer": "David E. Wheeler ", + "license": "postgresql", + "provides": { + "pair": { + "abstract": "A key/value pair data type", + "file": "sql/pair.sql", + "docfile": "doc/pair.md", + "version": "0.1.0" + } + }, + "meta-spec": { + "version": "1.0.0", + "url": "https://pgxn.org/meta/spec.txt" + } +} diff --git a/tests/corpus/v1/howto2.json b/tests/corpus/v1/howto2.json new file mode 100644 index 0000000..2da2b22 --- /dev/null +++ b/tests/corpus/v1/howto2.json @@ -0,0 +1,39 @@ +{ + "name": "pair", + "abstract": "A key/value pair data type", + "description": "This library contains a single PostgreSQL extension, a key/value pair data type called “pair”, along with a convenience function for constructing key/value pairs.", + "version": "0.1.4", + "maintainer": ["David E. Wheeler "], + "license": "postgresql", + "provides": { + "pair": { + "abstract": "A key/value pair data type", + "file": "sql/pair.sql", + "docfile": "doc/pair.md", + "version": "0.1.0" + } + }, + "resources": { + "bugtracker": { + "web": "https://github.com/theory/kv-pair/issues/" + }, + "repository": { + "url": "git://github.com/theory/kv-pair.git", + "web": "https://github.com/theory/kv-pair/", + "type": "git" + } + }, + "generated_by": "David E. Wheeler", + "meta-spec": { + "version": "1.0.0", + "url": "https://pgxn.org/meta/spec.txt" + }, + "tags": [ + "variadic function", + "ordered pair", + "pair", + "key value", + "key value pair", + "data type" + ] +} diff --git a/tests/corpus/v1/invalid.txt b/tests/corpus/v1/invalid.txt deleted file mode 100644 index 0cccc65..0000000 --- a/tests/corpus/v1/invalid.txt +++ /dev/null @@ -1 +0,0 @@ -{"test":"no_version","error":"missing properties 'version'","meta":{"name":"pair","abstract":"A key/value pair data type","maintainer":"David E. Wheeler ","license":"postgresql","provides":{"pair":{"abstract":"A key/value pair data type","file":"sql/pair.sql","docfile":"doc/pair.md","version":"0.1.0"}},"meta-spec":{"version":"1.0.0","url":"https://pgxn.org/meta/spec.txt"}}} diff --git a/tests/corpus/v1/valid.txt b/tests/corpus/v1/valid.txt deleted file mode 100644 index ae9d804..0000000 --- a/tests/corpus/v1/valid.txt +++ /dev/null @@ -1,3 +0,0 @@ -{"test":"howto1","meta":{"name":"pair","abstract":"A key/value pair data type","version":"0.1.0","maintainer":"David E. Wheeler ","license":"postgresql","provides":{"pair":{"abstract":"A key/value pair data type","file":"sql/pair.sql","docfile":"doc/pair.md","version":"0.1.0"}},"meta-spec":{"version":"1.0.0","url":"https://pgxn.org/meta/spec.txt"}}} -{"test":"howto2","meta":{"name":"pair","abstract":"A key/value pair data type","description":"This library contains a single PostgreSQL extension, a key/value pair data type called “pair”, along with a convenience function for constructing key/value pairs.","version":"0.1.4","maintainer":["David E. Wheeler "],"license":"postgresql","provides":{"pair":{"abstract":"A key/value pair data type","file":"sql/pair.sql","docfile":"doc/pair.md","version":"0.1.0"}},"resources":{"bugtracker":{"web":"https://github.com/theory/kv-pair/issues/"},"repository":{"url":"git://github.com/theory/kv-pair.git","web":"https://github.com/theory/kv-pair/","type":"git"}},"generated_by":"David E. Wheeler","meta-spec":{"version":"1.0.0","url":"https://pgxn.org/meta/spec.txt"},"tags":["variadic function","ordered pair","pair","key value","key value pair","data type"]}} -{"test":"widget","meta":{"name":"widget","abstract":"Widget for PostgreSQL","description":"¿A widget is just thing thing, yoŭ know?","version":"0.2.5","maintainer":["David E. Wheeler "],"license":{"PostgreSQL":"https://www.postgresql.org/about/licence"},"prereqs":{"runtime":{"requires":{"plpgsql":0,"PostgreSQL":"8.0.0"},"recommends":{"PostgreSQL":"8.4.0"}}},"provides":{"widget":{"file":"sql/widget.sql.in","version":"0.2.5"}},"resources":{"homepage":"http://widget.example.org/"},"generated_by":"theory","meta-spec":{"version":"1.0.0","url":"https://pgxn.org/meta/spec.txt"},"tags":["widget","gadget","full text search"]}} diff --git a/tests/corpus/v1/widget.json b/tests/corpus/v1/widget.json new file mode 100644 index 0000000..0e39d92 --- /dev/null +++ b/tests/corpus/v1/widget.json @@ -0,0 +1,36 @@ +{ + "name": "widget", + "abstract": "Widget for PostgreSQL", + "description": "¿A widget is just thing thing, yoŭ know?", + "version": "0.2.5", + "maintainer": ["David E. Wheeler "], + "license": { + "PostgreSQL": "https://www.postgresql.org/about/licence" + }, + "prereqs": { + "runtime": { + "requires": { + "plpgsql": 0, + "PostgreSQL": "8.0.0" + }, + "recommends": { + "PostgreSQL": "8.4.0" + } + } + }, + "provides": { + "widget": { + "file": "sql/widget.sql.in", + "version": "0.2.5" + } + }, + "resources": { + "homepage": "http://widget.example.org/" + }, + "generated_by": "theory", + "meta-spec": { + "version": "1.0.0", + "url": "https://pgxn.org/meta/spec.txt" + }, + "tags": ["widget", "gadget", "full text search"] +} diff --git a/tests/corpus/v2/minimal.json b/tests/corpus/v2/minimal.json new file mode 100644 index 0000000..44f11ef --- /dev/null +++ b/tests/corpus/v2/minimal.json @@ -0,0 +1,21 @@ +{ + "name": "pair", + "abstract": "A key/value pair data type", + "version": "0.1.8", + "maintainers": [ + { + "name": "David E. Wheeler", + "email": "david@justatheory.com" + } + ], + "license": "PostgreSQL", + "contents": { + "extensions": { + "pair": { + "sql": "sql/pair.sql", + "control": "pair.control" + } + } + }, + "meta-spec": { "version": "2.0.0" } +} diff --git a/tests/corpus/v2/pg_partman.json b/tests/corpus/v2/pg_partman.json new file mode 100644 index 0000000..3541a85 --- /dev/null +++ b/tests/corpus/v2/pg_partman.json @@ -0,0 +1,91 @@ +{ + "name": "pg_partman", + "abstract": "Extension to manage partitioned tables by time or ID", + "version": "5.1.0", + "maintainers": [ + { + "name": "Keith Fiske", + "email": "keith@keithf4.com" + } + ], + "license": "PostgreSQL", + "contents": { + "extensions": { + "pg_partman": { + "control": "pg_partman.control", + "sql": "sql/types/types.sql", + "doc": "doc/pg_partman.md", + "abstract": "Extension to manage partitioned tables by time or ID" + } + }, + "modules": { + "pg_partman_bgw": { + "type": "bgw", + "lib": "src/pg_partman_bgw", + "preload": "server" + } + }, + "apps": { + "check_unique_constraint": { + "lang": "python", + "bin": "bin/common/check_unique_constraint.py", + "abstract": "Check that all rows in a partition set are unique for the given columns" + }, + "dump_partition": { + "lang": "python", + "bin": "bin/common/dump_partition.py", + "abstract": "Dump out and then drop all tables contained in a schema." + }, + "vacuum_maintenance": { + "lang": "python", + "bin": "bin/common/vacuum_maintenance.py", + "abstract": "Performing vacuum maintenance on to avoid excess vacuuming and transaction id wraparound issues" + } + } + }, + "dependencies": { + "postgres": { + "version": "14.0" + }, + "packages": { + "run": { + "requires": { + "pkg:generic/python": "2.0", + "pkg:pypi/psycopg2": 0 + }, + "recommends": { + "pkg:pgxn/pg_jobmon": "1.4.1" + } + } + } + }, + "resources": { + "issues": "https://github.com/theory/pg-envvar/issues/", + "repository": "https://github.com/theory/pg-envvar/", + "badges": [ + { + "alt": "CI Status", + "src": "https://github.com/theory/pg-envvar/actions/workflows/ci.yml/badge.svg", + "url": "https://github.com/theory/pg-envvar/actions/workflows/ci.yml" + } + ] + }, + "producer": "David E. Wheeler", + "meta-spec": { + "version": "2.0.0", + "url": "https://rfcs.pgxn.org/0003-meta-spec-v2.html" + }, + "classifications": { + "categories": ["Orchestration"], + "tags": [ + "partition", + "partitions", + "partitioning", + "table", + "tables", + "bgw", + "background worker", + "custom background worker" + ] + } +} diff --git a/tests/corpus/v2/postgresml.json b/tests/corpus/v2/postgresml.json new file mode 100644 index 0000000..1f4bf3b --- /dev/null +++ b/tests/corpus/v2/postgresml.json @@ -0,0 +1,147 @@ +{ + "name": "pgml", + "version": "2.8.2", + "abstract": "pgml: Created by the PostgresML team", + "maintainers": [ + { + "name": "the PostgresML team", + "url": "https://github.com/postgresml/postgresml/" + } + ], + "license": "MIT", + "contents": { + "extensions": { + "pgml": { + "sql": "target/release/**/pgml--2.7.13.sql", + "control": "target/release/**/pgml.control" + } + }, + "modules": { + "pgml": { + "type": "extension", + "lib": "target/release/pgml", + "preload": "server" + } + } + }, + "dependencies": { + "postgres": { + "version": "9.1.0" + }, + "pipeline": "pgrx", + "packages": { + "configure": { + "requires": { + "pkg:generic/cmake": 0, + "pkg:cargo/cargo-pgrx": "0.11.2" + } + }, + "build": { + "requires": { + "pkg:generic/cargo": 0, + "pkg:generic/bison": 0, + "pkg:generic/flex": 0, + "pkg:generic/clang": 0, + "pkg:generic/openblas": 0, + "pkg:generic/python3": "3.7", + "pkg:generic/readline": 0, + "pkg:generic/openssl": 0, + "pkg:generic/pkg-config": 0 + } + }, + "run": { + "requires": { + "pkg:generic/openblas": 0, + "pkg:generic/python3": "3.7", + "pkg:generic/readline": 0, + "pkg:generic/openssl": 0 + }, + "recommends": { + "pkg:pypi/pyarrow": "11.0.0", + "pkg:pypi/catboost": 0, + "pkg:pypi/lightgbm": 0, + "pkg:pypi/torch": 0, + "pkg:pypi/torchaudio": 0, + "pkg:pypi/torchvision": 0, + "pkg:pypi/xgboost": 0, + "pkg:pypi/accelerate": 0, + "pkg:pypi/bitsandbytes": 0, + "pkg:pypi/ctransformers": 0, + "pkg:pypi/huggingface-hub": 0, + "pkg:pypi/deepspeed": 0, + "pkg:pypi/einops": 0, + "pkg:pypi/optimum": 0, + "pkg:pypi/peft": 0, + "pkg:pypi/tokenizers": 0, + "pkg:pypi/transformers": 0, + "pkg:pypi/transformers-stream-generator": 0, + "pkg:pypi/InstructorEmbedding": 0, + "pkg:pypi/sentence-transformers": 0, + "pkg:pypi/rouge": 0, + "pkg:pypi/sacrebleu": 0, + "pkg:pypi/sacremoses": 0, + "pkg:pypi/datasets": 0, + "pkg:pypi/orjson": 0, + "pkg:pypi/langchain": 0 + } + } + }, + "variations": [ + { + "where": { + "platforms": ["linux"] + }, + "dependencies": { + "packages": { + "run": { + "recommends": { + "pkg:pypi/auto-gptq": 0, + "pkg:pypi/xformers": 0 + } + } + } + } + } + ] + }, + "resources": { + "homepage": "https://postgresml.org/", + "issues": "https://github.com/postgresml/postgresml/issues", + "docs": "https://postgresml.org/docs/", + "support": "https://discord.com/invite/DmyJP3qJ7U", + "repository": "https://github.com/postgresml/postgresml", + "badges": [ + { + "alt": "Tests Passing", + "src": "https://github.com/postgresml/postgresml/actions/workflows/ci.yml/badge.svg", + "url": "https://github.com/postgresml/postgresml/actions/workflows/ci.yml" + }, + { + "alt": "Chat Activity", + "src": "https://img.shields.io/discord/1013868243036930099", + "url": "https://discord.gg/DmyJP3qJ7U" + } + ] + }, + "producer": "David E. Wheeler", + "meta-spec": { + "version": "2.0.0", + "url": "https://rfcs.pgxn.org/0003-meta-spec-v2.html" + }, + "classifications": { + "tags": ["machine learning", "ml", "transformers"], + "categories": ["Machine Learning"] + }, + "artifacts": [ + { + "type": "source", + "url": "https://github.com/postgresml/postgresml/archive/refs/tags/v2.8.2.zip", + "sha256": "2b9d2416096d2930be51e5332b70bcd97846947777a93e4a3d65fe1b5fd7b004" + }, + { + "type": "source", + "url": "https://github.com/postgresml/postgresml/archive/refs/tags/v2.8.2.tar.gz", + "sha256": "845f28339c6159ac32daccea1cd17b386ea083c3e60bb8d58fb737725afe7eb5" + } + ] +} diff --git a/tests/corpus/v2/typical-c.json b/tests/corpus/v2/typical-c.json new file mode 100644 index 0000000..c4a8801 --- /dev/null +++ b/tests/corpus/v2/typical-c.json @@ -0,0 +1,61 @@ +{ + "name": "envvar", + "abstract": "Get the value of a server environment variable", + "description": "Provides a function that returns the value of an environment variable set on the Postgres server.", + "version": "1.0.0", + "maintainers": [ + { + "name": "David E. Wheeler", + "email": "david@justatheory.com" + } + ], + "license": "PostgreSQL", + "contents": { + "extensions": { + "envvar": { + "abstract": "Get the value of a server environment variable", + "control": "envvar.control", + "sql": "sql/envvar.sql", + "doc": "doc/envvar.md" + } + }, + "modules": { + "envvar": { + "type": "extension", + "lib": "src/envvar" + } + } + }, + "dependencies": { + "postgres": { + "version": "9.1.0" + } + }, + "resources": { + "issues": "https://github.com/theory/pg-envvar/issues/", + "repository": "https://github.com/theory/pg-envvar/", + "badges": [ + { + "alt": "CI Status", + "src": "https://github.com/theory/pg-envvar/actions/workflows/ci.yml/badge.svg", + "url": "https://github.com/theory/pg-envvar/actions/workflows/ci.yml" + } + ] + }, + "producer": "David E. Wheeler", + "meta-spec": { + "version": "2.0.0", + "url": "https://rfcs.pgxn.org/0003-meta-spec-v2.html" + }, + "classifications": { + "categories": ["Data and Transformations"], + "tags": ["environment variable", "environment", "server"] + }, + "artifacts": [ + { + "type": "source", + "url": "https://github.com/theory/pg-envvar/releases/download/v1.0.0/envvar-1.0.0.zip", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + ] +} diff --git a/tests/corpus/v2/typical-pgrx.json b/tests/corpus/v2/typical-pgrx.json new file mode 100644 index 0000000..a7bec8d --- /dev/null +++ b/tests/corpus/v2/typical-pgrx.json @@ -0,0 +1,85 @@ +{ + "name": "jsonschema", + "abstract": "JSON Schema validation functions for PostgreSQL", + "description": "The jsonschema extension provides JSON Schema validation functions supporting drafts 2020-12, 2019-09, 7, 6, and 4", + "version": "0.1.1", + "maintainers": [ + { + "name": "David E. Wheeler", + "email": "david@justatheory.com" + }, + { + "name": "Tembo", + "email": "admin+pgxn@tembo.io" + } + ], + "license": "MIT", + "contents": { + "extensions": { + "jsonschema": { + "abstract": "JSON Schema validation functions for PostgreSQL", + "doc": "doc/jsonschema.md", + "x_comment": "Paths non-deterministic until pgrx ", + "sql": "target/release/**/jsonschema--0.1.1.sql", + "control": "target/release/**/jsonschema.control" + } + }, + "modules": { + "libjsonschema": { + "type": "extension", + "lib": "target/release/libjsonschema" + } + } + }, + "dependencies": { + "pipeline": "pgrx", + "postgres": { + "version": "12.0" + } + }, + "resources": { + "issues": "https://github.com/tembo-io/pg-jsonschema-boon/issues/", + "repository": "https://github.com/tembo-io/pg-jsonschema-boon/", + "badges": [ + { + "alt": "⚖️ MIT License", + "src": "https://img.shields.io/badge/License-MIT-blue.svg", + "url": "https://github.com/tembo-io/pg-jsonschema-boon/blob/main/LICENSE.md" + }, + { + "alt": "🧪 Lint and Test", + "src": "https://github.com/tembo-io/pg-jsonschema-boon/actions/workflows/lint-and-test.yml/badge.svg", + "url": "https://github.com/tembo-io/pg-jsonschema-boon/actions/workflows/lint-and-test.yml" + }, + { + "alt": "📊 Code Coverage", + "src": "https://codecov.io/gh/tembo-io/pg-jsonschema-boon/graph/badge.svg", + "url": "https://codecov.io/gh/tembo-io/pg-jsonschema-boon" + } + ] + }, + "producer": "David E. Wheeler", + "meta-spec": { + "version": "2.0.0", + "url": "https://rfcs.pgxn.org/0003-meta-spec-v2.html" + }, + "classifications": { + "categories": ["Data and Transformations"], + "tags": [ + "jsonschema", + "validation", + "json", + "schema", + "constraint", + "pgrx", + "rust" + ] + }, + "artifacts": [ + { + "type": "source", + "url": "https://github.com/tembo-io/pg-jsonschema-boon/releases/download/v0.1.1/jsonschema-0.1.1.zip", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + ] +} diff --git a/tests/corpus/v2/typical-sql.json b/tests/corpus/v2/typical-sql.json new file mode 100644 index 0000000..2ceb778 --- /dev/null +++ b/tests/corpus/v2/typical-sql.json @@ -0,0 +1,62 @@ +{ + "name": "pair", + "abstract": "A key/value pair data type", + "description": "This library contains a single PostgreSQL extension, a key/value pair data type called “pair”, along with a convenience function for constructing key/value pairs.", + "version": "0.1.8", + "maintainers": [ + { + "name": "David E. Wheeler", + "email": "david@justatheory.com" + } + ], + "license": "PostgreSQL", + "contents": { + "extensions": { + "pair": { + "abstract": "A key/value pair data type", + "sql": "sql/pair.sql", + "doc": "doc/pair.md", + "control": "pair.control", + "tle": true + } + } + }, + "dependencies": { + "postgres": { + "version": "9.1.0" + } + }, + "resources": { + "issues": "https://github.com/theory/kv-pair/issues/", + "repository": "https://github.com/theory/kv-pair/", + "badges": [ + { + "alt": "Test Status", + "src": "https://github.com/theory/kv-pair/workflows/CI/badge.svg", + "url": "https://github.com/theory/kv-pair/actions" + } + ] + }, + "producer": "David E. Wheeler", + "meta-spec": { + "version": "2.0.0", + "url": "https://rfcs.pgxn.org/0003-meta-spec-v2.html" + }, + "classifications": { + "categories": ["Data and Transformations"], + "tags": [ + "variadic function", + "ordered pair", + "pair", + "key value", + "key value pair" + ] + }, + "artifacts": [ + { + "type": "source", + "url": "https://github.com/theory/kv-pair/releases/download/v0.1.7/pair-0.1.7.zip", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + ] +} diff --git a/tests/v1_schema_test.rs b/tests/v1_schema_test.rs index 4ce8ec4..a01a3fa 100644 --- a/tests/v1_schema_test.rs +++ b/tests/v1_schema_test.rs @@ -1,14 +1,12 @@ use std::error::Error; -use std::fs::File; -use std::io::{prelude::*, BufReader}; use boon::Schemas; -use serde::{Deserialize, Serialize}; use serde_json::{json, Map, Value}; // importing common module. mod common; use common::*; +use pgxn_meta::compiler; const SCHEMA_VERSION: u8 = 1; @@ -17,80 +15,24 @@ fn test_schema_v1() -> Result<(), Box> { test_schema_version(SCHEMA_VERSION) } -#[derive(Deserialize, Serialize)] -struct CorpusCase { - test: String, - error: Option, - meta: Value, -} - -#[test] -fn test_corpus_v1_valid() -> Result<(), Box> { - // Load the schemas and compile the root schema. - let mut compiler = new_compiler("schema/v1")?; - let mut schemas = Schemas::new(); - let id = id_for(SCHEMA_VERSION, "distribution"); - let index = compiler.compile(&id, &mut schemas)?; - - // Test each meta JSON in the corpus. - let file = File::open("tests/corpus/v1/valid.txt")?; - let reader = BufReader::new(file); - for line in reader.lines() { - let tc: CorpusCase = serde_json::from_str(&line?)?; - - if let Err(e) = schemas.validate(&tc.meta, index) { - panic!("{} failed: {e}", &tc.test); - } - println!("Example {} ok", &tc.test); - } - - Ok(()) -} - -#[test] -fn test_corpus_v1_invalid() -> Result<(), Box> { - // Load the schemas and compile the root schema. - let mut compiler = new_compiler("schema/v1")?; - let mut schemas = Schemas::new(); - let id = id_for(SCHEMA_VERSION, "distribution"); - let index = compiler.compile(&id, &mut schemas)?; - - // Test each meta JSON in the corpus. - let file = File::open("tests/corpus/v1/invalid.txt")?; - let reader = BufReader::new(file); - for line in reader.lines() { - let tc: CorpusCase = serde_json::from_str(&line?)?; - match schemas.validate(&tc.meta, index) { - Ok(_) => panic!("{} unexpectedly passed!", &tc.test), - Err(e) => assert!( - e.to_string().contains(&tc.error.unwrap()), - "{} error: {e}", - &tc.test, - ), - } - } - - Ok(()) -} - #[test] fn test_v1_term() -> Result<(), Box> { // Load the schemas and compile the term schema. - let compiler = new_compiler("schema/v1")?; + let compiler = compiler::new("schema/v1")?; test_term_schema(compiler, SCHEMA_VERSION) } #[test] fn test_v1_tags() -> Result<(), Box> { // Load the schemas and compile the tags schema. - let compiler = new_compiler("schema/v1")?; + let compiler = compiler::new("schema/v1")?; test_tags_schema(compiler, SCHEMA_VERSION) } #[test] fn test_v1_version() -> Result<(), Box> { // Load the schemas and compile the version schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "version"); let idx = compiler.compile(&id, &mut schemas)?; @@ -115,7 +57,7 @@ fn test_v1_version() -> Result<(), Box> { #[test] fn test_v1_version_range() -> Result<(), Box> { // Load the schemas and compile the version_range schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "version_range"); let idx = compiler.compile(&id, &mut schemas)?; @@ -186,7 +128,7 @@ fn test_v1_version_range() -> Result<(), Box> { #[test] fn test_v1_license() -> Result<(), Box> { // Load the schemas and compile the license schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "license"); let idx = compiler.compile(&id, &mut schemas)?; @@ -255,7 +197,7 @@ fn test_v1_license() -> Result<(), Box> { #[test] fn test_v1_provides() -> Result<(), Box> { // Load the schemas and compile the provides schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "provides"); let idx = compiler.compile(&id, &mut schemas)?; @@ -354,7 +296,7 @@ fn test_v1_provides() -> Result<(), Box> { #[test] fn test_v1_extension() -> Result<(), Box> { // Load the schemas and compile the extension schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "extension"); let idx = compiler.compile(&id, &mut schemas)?; @@ -530,7 +472,7 @@ fn test_v1_extension() -> Result<(), Box> { #[test] fn test_v1_maintainer() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "maintainer"); let idx = compiler.compile(&id, &mut schemas)?; @@ -580,7 +522,7 @@ fn test_v1_maintainer() -> Result<(), Box> { #[test] fn test_v1_meta_spec() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "meta-spec"); let idx = compiler.compile(&id, &mut schemas)?; @@ -634,7 +576,7 @@ fn test_v1_meta_spec() -> Result<(), Box> { #[test] fn test_v1_bugtracker() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "bugtracker"); let idx = compiler.compile(&id, &mut schemas)?; @@ -688,7 +630,7 @@ fn test_v1_bugtracker() -> Result<(), Box> { #[test] fn test_v1_no_index() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "no_index"); let idx = compiler.compile(&id, &mut schemas)?; @@ -755,7 +697,7 @@ fn test_v1_no_index() -> Result<(), Box> { #[test] fn test_v1_prereq_relationship() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "prereq_relationship"); let idx = compiler.compile(&id, &mut schemas)?; @@ -808,7 +750,7 @@ fn test_v1_prereq_relationship() -> Result<(), Box> { #[test] fn test_v1_prereq_phase() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "prereq_phase"); let idx = compiler.compile(&id, &mut schemas)?; @@ -920,7 +862,7 @@ fn test_v1_prereq_phase() -> Result<(), Box> { #[test] fn test_v1_prereqs() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "prereqs"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1068,7 +1010,7 @@ fn test_v1_prereqs() -> Result<(), Box> { #[test] fn test_v1_repository() -> Result<(), Box> { // Load the schemas and compile the repository schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "repository"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1145,7 +1087,7 @@ fn test_v1_repository() -> Result<(), Box> { #[test] fn test_v1_resources() -> Result<(), Box> { // Load the schemas and compile the resources schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "resources"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1282,7 +1224,7 @@ fn valid_distribution() -> Value { #[test] fn test_v1_distribution() -> Result<(), Box> { // Load the schemas and compile the distribution schema. - let mut compiler = new_compiler("schema/v1")?; + let mut compiler = compiler::new("schema/v1")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "distribution"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1337,7 +1279,7 @@ fn test_v1_distribution() -> Result<(), Box> { spec.insert("x_foo".to_string(), json!(1)); }), ("multibyte name", |m: &mut Obj| { - m.insert("name".to_string(), json!("yoŭknow")); + m.insert("name".to_string(), json!("yoŭ_know")); }), ("emoji name", |m: &mut Obj| { m.insert("name".to_string(), json!("📀📟🎱")); diff --git a/tests/v2_schema_test.rs b/tests/v2_schema_test.rs index 45c21b3..8a71161 100644 --- a/tests/v2_schema_test.rs +++ b/tests/v2_schema_test.rs @@ -6,6 +6,7 @@ use serde_json::{json, Map, Value}; // importing common module. mod common; use common::*; +use pgxn_meta::compiler; const SCHEMA_VERSION: u8 = 2; @@ -17,21 +18,21 @@ fn test_schema_v2() -> Result<(), Box> { #[test] fn test_v2_term() -> Result<(), Box> { // Load the schemas and compile the term schema. - let compiler = new_compiler("schema/v2")?; + let compiler = compiler::new("schema/v2")?; test_term_schema(compiler, SCHEMA_VERSION) } #[test] fn test_v2_tags() -> Result<(), Box> { // Load the schemas and compile the tags schema. - let compiler = new_compiler("schema/v2")?; + let compiler = compiler::new("schema/v2")?; test_tags_schema(compiler, SCHEMA_VERSION) } #[test] fn test_v2_semver() -> Result<(), Box> { // Load the schemas and compile the semver schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "semver"); let idx = compiler.compile(&id, &mut schemas)?; @@ -61,13 +62,17 @@ fn test_v2_semver() -> Result<(), Box> { #[test] fn test_v2_path() -> Result<(), Box> { // Load the schemas and compile the semver schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "path"); let idx = compiler.compile(&id, &mut schemas)?; // Test valid paths. for valid in [ + json!("\\foo.md"), + json!("this\\and\\that.txt"), + json!("/absolute/path"), + json!("C:\\foo"), json!("README.txt"), json!(".git"), json!("src/pair.c"), @@ -81,16 +86,15 @@ fn test_v2_path() -> Result<(), Box> { // Test invalid paths. for invalid in [ - json!("\\foo.md"), - json!("this\\and\\that.txt"), - json!("/absolute/path"), - // Enforced only by custom format for now. - // https://github.com/santhosh-tekuri/boon/issues/19 json!("../outside/path"), json!("thing/../other"), json!(null), json!(""), - json!("C:\\foo"), + json!({}), + json!([]), + json!(true), + json!(null), + json!(42), ] { if schemas.validate(&invalid, idx).is_ok() { panic!("{} unexpectedly passed!", invalid) @@ -102,7 +106,7 @@ fn test_v2_path() -> Result<(), Box> { #[test] fn test_v2_glob() -> Result<(), Box> { // Load the schemas and compile the semver schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "glob"); let idx = compiler.compile(&id, &mut schemas)?; @@ -143,7 +147,7 @@ fn test_v2_glob() -> Result<(), Box> { #[test] fn test_v2_version_range() -> Result<(), Box> { // Load the schemas and compile the version_range schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "version_range"); let idx = compiler.compile(&id, &mut schemas)?; @@ -213,7 +217,7 @@ fn test_v2_version_range() -> Result<(), Box> { #[test] fn test_v2_license() -> Result<(), Box> { // Load the schemas and compile the semver schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "license"); let idx = compiler.compile(&id, &mut schemas)?; @@ -256,13 +260,14 @@ fn test_v2_license() -> Result<(), Box> { panic!("{} unexpectedly passed!", invalid_license) } } + Ok(()) } #[test] fn test_v2_purl() -> Result<(), Box> { // Load the schemas and compile the semver schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "purl"); let idx = compiler.compile(&id, &mut schemas)?; @@ -306,7 +311,7 @@ fn test_v2_purl() -> Result<(), Box> { #[test] fn test_v2_platform() -> Result<(), Box> { // Load the schemas and compile the semver schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "platform"); let idx = compiler.compile(&id, &mut schemas)?; @@ -392,7 +397,7 @@ fn test_v2_platform() -> Result<(), Box> { #[test] fn test_v2_platforms() -> Result<(), Box> { // Load the schemas and compile the semver schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "platforms"); let idx = compiler.compile(&id, &mut schemas)?; @@ -440,7 +445,7 @@ fn test_v2_platforms() -> Result<(), Box> { #[test] fn test_v2_maintainers() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "maintainers"); let idx = compiler.compile(&id, &mut schemas)?; @@ -578,7 +583,7 @@ fn test_v2_maintainers() -> Result<(), Box> { #[test] fn test_v2_extension() -> Result<(), Box> { // Load the schemas and compile the extension schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "extension"); let idx = compiler.compile(&id, &mut schemas)?; @@ -755,7 +760,7 @@ fn test_v2_extension() -> Result<(), Box> { #[test] fn test_v2_module() -> Result<(), Box> { // Load the schemas and compile the extension schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "module"); let idx = compiler.compile(&id, &mut schemas)?; @@ -924,7 +929,7 @@ fn test_v2_module() -> Result<(), Box> { #[test] fn test_v2_app() -> Result<(), Box> { // Load the schemas and compile the extension schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "app"); let idx = compiler.compile(&id, &mut schemas)?; @@ -983,7 +988,7 @@ fn test_v2_app() -> Result<(), Box> { // doc ("empty doc", json!({"bin": "bog", "doc": ""})), ("null doc", json!({"bin": "bog", "doc": null})), - ("windows doc", json!({"bin": "bog", "doc": "c:\\foo"})), + ("up-dir doc", json!({"bin": "bog", "doc": "../foo"})), ("number doc", json!({"bin": "bog", "doc": 42})), ("bool doc", json!({"bin": "bog", "doc": true})), ("array doc", json!({"bin": "bog", "doc": ["hi"]})), @@ -1005,7 +1010,7 @@ fn test_v2_app() -> Result<(), Box> { // lib ("empty lib", json!({"bin": "bog", "lib": ""})), ("null lib", json!({"bin": "bog", "lib": null})), - ("windows lib", json!({"bin": "bog", "lib": "c:\\foo"})), + ("up-dir lib", json!({"bin": "bog", "lib": "../foo"})), ("number lib", json!({"bin": "bog", "lib": 42})), ("bool lib", json!({"bin": "bog", "lib": true})), ("array lib", json!({"bin": "bog", "lib": ["hi"]})), @@ -1013,7 +1018,7 @@ fn test_v2_app() -> Result<(), Box> { // man ("empty man", json!({"bin": "bog", "man": ""})), ("null man", json!({"bin": "bog", "man": null})), - ("windows man", json!({"bin": "bog", "man": "c:\\foo"})), + ("up-dir man", json!({"bin": "bog", "man": "../foo"})), ("number man", json!({"bin": "bog", "man": 42})), ("bool man", json!({"bin": "bog", "man": true})), ("array man", json!({"bin": "bog", "man": ["hi"]})), @@ -1021,7 +1026,7 @@ fn test_v2_app() -> Result<(), Box> { // html ("empty html", json!({"bin": "bog", "html": ""})), ("null html", json!({"bin": "bog", "html": null})), - ("windows html", json!({"bin": "bog", "html": "c:\\foo"})), + ("up-dir html", json!({"bin": "bog", "html": "../foo"})), ("number html", json!({"bin": "bog", "html": 42})), ("bool html", json!({"bin": "bog", "html": true})), ("array html", json!({"bin": "bog", "html": ["hi"]})), @@ -1038,7 +1043,7 @@ fn test_v2_app() -> Result<(), Box> { #[test] fn test_v2_contents() -> Result<(), Box> { // Load the schemas and compile the extension schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "contents"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1177,7 +1182,7 @@ fn test_v2_contents() -> Result<(), Box> { #[test] fn test_v2_meta_spec() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "meta-spec"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1231,7 +1236,7 @@ fn test_v2_meta_spec() -> Result<(), Box> { #[test] fn test_v2_categories() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "categories"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1300,7 +1305,7 @@ fn test_v2_categories() -> Result<(), Box> { #[test] fn test_v2_classifications() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "classifications"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1371,7 +1376,7 @@ fn test_v2_classifications() -> Result<(), Box> { #[test] fn test_v2_ignore() -> Result<(), Box> { // Load the schemas and compile the semver schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "ignore"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1429,7 +1434,7 @@ fn test_v2_ignore() -> Result<(), Box> { #[test] fn test_v2_phase() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "phase"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1556,7 +1561,7 @@ fn test_v2_phase() -> Result<(), Box> { #[test] fn test_v2_packages() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "packages"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1710,7 +1715,7 @@ fn test_v2_packages() -> Result<(), Box> { #[test] fn test_v2_postgres() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "postgres"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1770,7 +1775,7 @@ fn test_v2_postgres() -> Result<(), Box> { #[test] fn test_v2_pipeline() -> Result<(), Box> { // Load the schemas and compile the semver schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "pipeline"); let idx = compiler.compile(&id, &mut schemas)?; @@ -1814,7 +1819,7 @@ fn test_v2_pipeline() -> Result<(), Box> { #[test] fn test_v2_dependencies() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "dependencies"); let idx = compiler.compile(&id, &mut schemas)?; @@ -2069,7 +2074,7 @@ fn test_v2_dependencies() -> Result<(), Box> { #[test] fn test_v2_variations() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "variations"); let idx = compiler.compile(&id, &mut schemas)?; @@ -2199,7 +2204,7 @@ fn test_v2_variations() -> Result<(), Box> { #[test] fn test_v2_badges() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "badges"); let idx = compiler.compile(&id, &mut schemas)?; @@ -2312,7 +2317,7 @@ fn test_v2_badges() -> Result<(), Box> { #[test] fn test_v2_resources() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "resources"); let idx = compiler.compile(&id, &mut schemas)?; @@ -2438,7 +2443,7 @@ fn test_v2_resources() -> Result<(), Box> { #[test] fn test_v2_artifacts() -> Result<(), Box> { // Load the schemas and compile the maintainer schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "artifacts"); let idx = compiler.compile(&id, &mut schemas)?; @@ -2884,7 +2889,7 @@ fn valid_v2_distribution() -> Value { #[test] fn test_v2_distribution() -> Result<(), Box> { // Load the schemas and compile the distribution schema. - let mut compiler = new_compiler("schema/v2")?; + let mut compiler = compiler::new("schema/v2")?; let mut schemas = Schemas::new(); let id = id_for(SCHEMA_VERSION, "distribution"); let idx = compiler.compile(&id, &mut schemas)?; @@ -2957,7 +2962,7 @@ fn test_v2_distribution() -> Result<(), Box> { spec.remove("url"); }), ("multibyte name", |m: &mut Obj| { - m.insert("name".to_string(), json!("yoŭknow")); + m.insert("name".to_string(), json!("_know")); }), ("emoji name", |m: &mut Obj| { m.insert("name".to_string(), json!("📀📟🎱")); @@ -2966,7 +2971,7 @@ fn test_v2_distribution() -> Result<(), Box> { m.insert("name".to_string(), json!("foo-bar")); }), ("multibyte abstract", |m: &mut Obj| { - m.insert("abstract".to_string(), json!("yoŭknow")); + m.insert("abstract".to_string(), json!("yoŭ_know")); }), ("emoji abstract", |m: &mut Obj| { m.insert("abstract".to_string(), json!("📀📟🎱")); @@ -2999,13 +3004,13 @@ fn test_v2_distribution() -> Result<(), Box> { m.insert("version".to_string(), json!("1.2.1-beta1")); }), ("multibyte description", |m: &mut Obj| { - m.insert("description".to_string(), json!("yoŭknow")); + m.insert("description".to_string(), json!("yoŭ_know")); }), ("emoji description", |m: &mut Obj| { m.insert("description".to_string(), json!("📀📟🎱")); }), ("multibyte producer", |m: &mut Obj| { - m.insert("producer".to_string(), json!("yoŭknow")); + m.insert("producer".to_string(), json!("yoŭ_know")); }), ("emoji producer", |m: &mut Obj| { m.insert("producer".to_string(), json!("📀📟🎱"));