chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1 @@
{"files":{".cargo_vcs_info.json":"3a8a129ae736dcc2435be4021ab24a2cd09126d04bb30033c0e500b7004ec8bd",".github/workflows/rust-ci.yml":"45f556e22e33afe1d00cb9402052ffe07f2c747a0b925285c1e2de5f9ac1ca57","CHANGELOG.md":"8f6d1844310ce9251238925c0f8c0d632228c078ac326b5ad8427ff79f260de6","Cargo.toml":"e27c2305c5522dde841d5dda9b23fd340fbeb590bfddd85f1ae2f2d5189fe74a","Cargo.toml.orig":"f89f10f7a852a30999f6f5c841ecfd5b92c770584a3a0f314582bb1006275e30","LICENSE":"65eac389b5c3fda1149b4f0a89fd2d866b07628f789d4e4dc1c3cbb885680f58","README.md":"f9c300e3c413f69e70b5b561531ab267c1a37969e4ce4a0718b39fb59baae518","bin/release":"78948e28edc72e807c5cf8b7e369c28a79a1f362f77dacc08d69d81e71211343","src/core_ext.rs":"ff23dbd2d7c4fb74883efbaab7c3604fee83523608d5281230d5b303306926bd","src/diff.rs":"170dfb49e44bded85865146a346481cd3d378df37c3530eca56d385a19751e9a","src/lib.rs":"f42e095a89a441367ef2a50663ed7c64a34ef80f357514050cbb3fa610c3db63","tests/integration_test.rs":"29f3cdc3646c06bad70e2171c1e28658471df676776765f242deecb23704fb35","tests/version-numbers.rs":"0d75532e72e9054cb8c8c12b8851e55fad7319ed14482b562f6806872f18dd0f"},"package":"47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12"}

View File

@@ -0,0 +1,6 @@
{
"git": {
"sha1": "bca0d2c590808274298d939e0533da79cd09076d"
},
"path_in_vcs": ""
}

View File

@@ -0,0 +1,104 @@
on:
push:
branches:
- main
tags:
- "*"
pull_request:
name: CI
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
# make sure all code has been formatted with rustfmt
- run: rustup component add rustfmt
- name: check rustfmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: -- --check --color always
# run clippy to verify we have no warnings
- run: rustup component add clippy
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: cargo clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --lib --tests -- -D warnings
test:
name: Test
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: cargo test
uses: actions-rs/cargo@v1
with:
command: test
args: --release
publish-check:
name: Publish Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: cargo publish check
uses: actions-rs/cargo@v1
with:
command: publish
args: --dry-run
# Remove this job if you don't publish the crate(s) from this repo
# You must add a crates.io API token to your GH secrets called CRATES_IO_TOKEN
publish:
name: Publish
needs: [test, publish-check]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: cargo publish
uses: actions-rs/cargo@v1
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
with:
command: publish

77
vendor/assert-json-diff/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,77 @@
# Change Log
All user visible changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/), as described
for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/text/1105-api-evolution.md)
## Unreleased
- None.
### Breaking changes
None.
## 2.0.2 - 2022-06-29
- Don't move the `Value`s being compared in `assert_json_matches`
## 2.0.1 - 2021-02-14
- Add maintenance status to readme and `Cargo.toml`.
## 2.0.0 - 2021-01-23
## Unreleased
- A less strict numeric mode for comparisons is now supported. The `AssumeFloat` mode will make `1 == 1.0`. This mode can be set via `Config::numeric_mode`.
- A panicking `assert_json_matches` macro has been added which takes a `Config`.
- Remove dependency on "extend".
### Breaking changes
- Some breaking changes have been made to support customizing how the JSON values are compared:
- `assert_json_eq_no_panic` and `assert_json_include_no_panic` have been replaced by `assert_json_matches_no_panic` which takes a `Config` that describes how the comparison should work.
- This setup will support adding further customizations without more breaking changes.
## 1.1.0 - 2020-07-12
- All methods now accept any `T: Serialize` rather than just `serde_json::Value`.
## 1.0.3 - 2020-02-21
- Introduce non-panicking functions with `assert_json_include_no_panic` and `assert_json_eq_no_panic`.
## 1.0.2 - 2020-02-19
- Internal diffing algorithm simplified. There should be no external changes. Some error messages might have changed, but everything that passed/failed before should still do the same.
## 1.0.1 - 2019-10-24
- Update to 2018 edition
## 1.0.0 - 2019-02-15
### Fixed
- Make macros work with trailing comma
## 0.2.1 - 2018-11-15
### Fixed
- Fix wrong error message when a JSON atom was missing from actual.
## 0.2.0 - 2018-11-16
### Added
- Add `assert_json_include`. It does partial matching the same way the old `assert_json_eq` did.
### Changed
- Change `assert_json_eq` do exact matching. If the two values are not exactly the same, it'll panic.
## 0.1.0 - 2018-10-17
Initial release.

44
vendor/assert-json-diff/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,44 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "assert-json-diff"
version = "2.0.2"
authors = ["David Pedersen <david.pdrsn@gmail.com>"]
description = "Easily compare two JSON values and get great output"
homepage = "https://github.com/davidpdrsn/assert-json-diff"
documentation = "https://docs.rs/assert-json-diff"
readme = "README.md"
keywords = [
"serde_json",
"json",
"testing",
]
categories = ["development-tools"]
license = "MIT"
repository = "https://github.com/davidpdrsn/assert-json-diff.git"
[dependencies.serde]
version = "1"
[dependencies.serde_json]
version = "1"
[dev-dependencies.serde]
version = "1"
features = ["derive"]
[dev-dependencies.version-sync]
version = "0.8"
[badges.maintenance]
status = "passively-maintained"

7
vendor/assert-json-diff/LICENSE vendored Normal file
View File

@@ -0,0 +1,7 @@
Copyright (c) 2019 David Pedersen
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

149
vendor/assert-json-diff/README.md vendored Normal file
View File

@@ -0,0 +1,149 @@
[![Crates.io](https://img.shields.io/crates/v/assert-json-diff.svg)](https://crates.io/crates/assert-json-diff)
[![Docs](https://docs.rs/assert-json-diff/badge.svg)](https://docs.rs/assert-json-diff)
[![dependency status](https://deps.rs/repo/github/davidpdrsn/assert-json-diff/status.svg)](https://deps.rs/repo/github/davidpdrsn/assert-json-diff)
[![Build status](https://github.com/davidpdrsn/assert-json-diff/workflows/CI/badge.svg)](https://github.com/davidpdrsn/assert-json-diff/actions)
![maintenance-status](https://img.shields.io/badge/maintenance-passively--maintained-yellowgreen.svg)
# assert-json-diff
This crate includes macros for comparing two serializable values by diffing their JSON
representations. It is designed to give much more helpful error messages than the standard
[`assert_eq!`]. It basically does a diff of the two objects and tells you the exact
differences. This is useful when asserting that two large JSON objects are the same.
It uses the [serde] and [serde_json] to perform the serialization.
[serde]: https://crates.io/crates/serde
[serde_json]: https://crates.io/crates/serde_json
[`assert_eq!`]: https://doc.rust-lang.org/std/macro.assert_eq.html
### Partial matching
If you want to assert that one JSON value is "included" in another use
[`assert_json_include`](macro.assert_json_include.html):
```rust
use assert_json_diff::assert_json_include;
use serde_json::json;
let a = json!({
"data": {
"users": [
{
"id": 1,
"country": {
"name": "Denmark"
}
},
{
"id": 24,
"country": {
"name": "Denmark"
}
}
]
}
});
let b = json!({
"data": {
"users": [
{
"id": 1,
"country": {
"name": "Sweden"
}
},
{
"id": 2,
"country": {
"name": "Denmark"
}
}
]
}
});
assert_json_include!(actual: a, expected: b)
```
This will panic with the error message:
```
json atoms at path ".data.users[0].country.name" are not equal:
expected:
"Sweden"
actual:
"Denmark"
json atoms at path ".data.users[1].id" are not equal:
expected:
2
actual:
24
```
[`assert_json_include`](macro.assert_json_include.html) allows extra data in `actual` but not in `expected`. That is so you can verify just a part
of the JSON without having to specify the whole thing. For example this test passes:
```rust
use assert_json_diff::assert_json_include;
use serde_json::json;
assert_json_include!(
actual: json!({
"a": { "b": 1 },
}),
expected: json!({
"a": {},
})
)
```
However `expected` cannot contain additional data so this test fails:
```rust
use assert_json_diff::assert_json_include;
use serde_json::json;
assert_json_include!(
actual: json!({
"a": {},
}),
expected: json!({
"a": { "b": 1 },
})
)
```
That will print
```
json atom at path ".a.b" is missing from actual
```
### Exact matching
If you want to ensure two JSON values are *exactly* the same, use [`assert_json_eq`](macro.assert_json_eq.html).
```rust
use assert_json_diff::assert_json_eq;
use serde_json::json;
assert_json_eq!(
json!({ "a": { "b": 1 } }),
json!({ "a": {} })
)
```
This will panic with the error message:
```
json atom at path ".a.b" is missing from lhs
```
### Further customization
You can use [`assert_json_matches`] to further customize the comparison.
License: MIT

54
vendor/assert-json-diff/bin/release vendored Executable file
View File

@@ -0,0 +1,54 @@
#!/bin/bash
set -e
confirm() {
while true; do
read -p "$1? Please double check. y/n? " yn
case $yn in
[Yy]* ) break;;
[Nn]* ) exit 1;;
* ) echo "Please answer yes or no.";;
esac
done
}
cargo fmt --all -- --check
echo "✔ code formatting looks good!"
cargo check
echo "✔ types look good"
cargo readme > README.md
echo "✔ README.md compiled"
cargo test > /dev/null
echo "✔ tests are passing"
confirm "Updated Cargo.toml"
confirm "Updated CHANGELOG.md"
version="$1"
version_without_v="`sed \"s/v//g\" <(echo $version)`"
if (echo $version | egrep "v\d+\.\d+\.\d+" > /dev/null)
then
confirm "Ready to release $version (as $version_without_v)?"
else
echo "Invalid version number: $1"
exit 1
fi
version_in_toml=$(cat Cargo.toml | egrep "^version = \"$version_without_v\"")
if [[ "$version_in_toml" == "version = \"$version_without_v\"" ]]
then
true
else
echo "Cargo.toml isn't set to version $version_without_v"
fi
GIT_COMMITTER_DATE=$(git log -n1 --pretty=%aD) git tag -a -m "Release $version" $version
git push --tags
cargo publish --dry-run
cargo publish || true

55
vendor/assert-json-diff/src/core_ext.rs vendored Normal file
View File

@@ -0,0 +1,55 @@
pub trait Indent {
fn indent(&self, level: u32) -> String;
}
impl<T> Indent for T
where
T: ToString,
{
fn indent(&self, level: u32) -> String {
let mut indent = String::new();
for _ in 0..level {
indent.push(' ');
}
self.to_string()
.lines()
.map(|line| format!("{}{}", indent, line))
.collect::<Vec<_>>()
.join("\n")
}
}
pub trait Indexes {
fn indexes(&self) -> Vec<usize>;
}
impl<T> Indexes for Vec<T> {
fn indexes(&self) -> Vec<usize> {
if self.is_empty() {
vec![]
} else {
(0..=self.len() - 1).collect()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_indent() {
assert_eq!(" foo", "foo".indent(2));
assert_eq!(" foo\n bar", "foo\nbar".indent(2));
}
#[test]
fn test_indexes() {
let empty: Vec<i32> = vec![];
let empty_indexes: Vec<usize> = vec![];
assert_eq!(empty.indexes(), empty_indexes);
assert_eq!(vec!['a', 'b'].indexes(), vec![0, 1]);
}
}

532
vendor/assert-json-diff/src/diff.rs vendored Normal file
View File

@@ -0,0 +1,532 @@
use crate::core_ext::{Indent, Indexes};
use crate::{CompareMode, Config, NumericMode};
use serde_json::Value;
use std::{collections::HashSet, fmt};
pub(crate) fn diff<'a>(lhs: &'a Value, rhs: &'a Value, config: Config) -> Vec<Difference<'a>> {
let mut acc = vec![];
diff_with(lhs, rhs, config, Path::Root, &mut acc);
acc
}
fn diff_with<'a>(
lhs: &'a Value,
rhs: &'a Value,
config: Config,
path: Path<'a>,
acc: &mut Vec<Difference<'a>>,
) {
let mut folder = DiffFolder {
rhs,
path,
acc,
config,
};
fold_json(lhs, &mut folder);
}
#[derive(Debug)]
struct DiffFolder<'a, 'b> {
rhs: &'a Value,
path: Path<'a>,
acc: &'b mut Vec<Difference<'a>>,
config: Config,
}
macro_rules! direct_compare {
($name:ident) => {
fn $name(&mut self, lhs: &'a Value) {
if self.rhs != lhs {
self.acc.push(Difference {
lhs: Some(lhs),
rhs: Some(&self.rhs),
path: self.path.clone(),
config: self.config.clone(),
});
}
}
};
}
impl<'a, 'b> DiffFolder<'a, 'b> {
direct_compare!(on_null);
direct_compare!(on_bool);
direct_compare!(on_string);
fn on_number(&mut self, lhs: &'a Value) {
let is_equal = match self.config.numeric_mode {
NumericMode::Strict => self.rhs == lhs,
NumericMode::AssumeFloat => self.rhs.as_f64() == lhs.as_f64(),
};
if !is_equal {
self.acc.push(Difference {
lhs: Some(lhs),
rhs: Some(&self.rhs),
path: self.path.clone(),
config: self.config.clone(),
});
}
}
fn on_array(&mut self, lhs: &'a Value) {
if let Some(rhs) = self.rhs.as_array() {
let lhs = lhs.as_array().unwrap();
match self.config.compare_mode {
CompareMode::Inclusive => {
for (idx, rhs) in rhs.iter().enumerate() {
let path = self.path.append(Key::Idx(idx));
if let Some(lhs) = lhs.get(idx) {
diff_with(lhs, rhs, self.config.clone(), path, self.acc)
} else {
self.acc.push(Difference {
lhs: None,
rhs: Some(&self.rhs),
path,
config: self.config.clone(),
});
}
}
}
CompareMode::Strict => {
let all_keys = rhs
.indexes()
.into_iter()
.chain(lhs.indexes())
.collect::<HashSet<_>>();
for key in all_keys {
let path = self.path.append(Key::Idx(key));
match (lhs.get(key), rhs.get(key)) {
(Some(lhs), Some(rhs)) => {
diff_with(lhs, rhs, self.config.clone(), path, self.acc);
}
(None, Some(rhs)) => {
self.acc.push(Difference {
lhs: None,
rhs: Some(rhs),
path,
config: self.config.clone(),
});
}
(Some(lhs), None) => {
self.acc.push(Difference {
lhs: Some(lhs),
rhs: None,
path,
config: self.config.clone(),
});
}
(None, None) => {
unreachable!("at least one of the maps should have the key")
}
}
}
}
}
} else {
self.acc.push(Difference {
lhs: Some(lhs),
rhs: Some(&self.rhs),
path: self.path.clone(),
config: self.config.clone(),
});
}
}
fn on_object(&mut self, lhs: &'a Value) {
if let Some(rhs) = self.rhs.as_object() {
let lhs = lhs.as_object().unwrap();
match self.config.compare_mode {
CompareMode::Inclusive => {
for (key, rhs) in rhs.iter() {
let path = self.path.append(Key::Field(key));
if let Some(lhs) = lhs.get(key) {
diff_with(lhs, rhs, self.config.clone(), path, self.acc)
} else {
self.acc.push(Difference {
lhs: None,
rhs: Some(&self.rhs),
path,
config: self.config.clone(),
});
}
}
}
CompareMode::Strict => {
let all_keys = rhs.keys().chain(lhs.keys()).collect::<HashSet<_>>();
for key in all_keys {
let path = self.path.append(Key::Field(key));
match (lhs.get(key), rhs.get(key)) {
(Some(lhs), Some(rhs)) => {
diff_with(lhs, rhs, self.config.clone(), path, self.acc);
}
(None, Some(rhs)) => {
self.acc.push(Difference {
lhs: None,
rhs: Some(rhs),
path,
config: self.config.clone(),
});
}
(Some(lhs), None) => {
self.acc.push(Difference {
lhs: Some(lhs),
rhs: None,
path,
config: self.config.clone(),
});
}
(None, None) => {
unreachable!("at least one of the maps should have the key")
}
}
}
}
}
} else {
self.acc.push(Difference {
lhs: Some(lhs),
rhs: Some(&self.rhs),
path: self.path.clone(),
config: self.config.clone(),
});
}
}
}
#[derive(Debug, PartialEq)]
pub(crate) struct Difference<'a> {
path: Path<'a>,
lhs: Option<&'a Value>,
rhs: Option<&'a Value>,
config: Config,
}
impl<'a> fmt::Display for Difference<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let json_to_string = |json: &Value| serde_json::to_string_pretty(json).unwrap();
match (&self.config.compare_mode, &self.lhs, &self.rhs) {
(CompareMode::Inclusive, Some(actual), Some(expected)) => {
writeln!(f, "json atoms at path \"{}\" are not equal:", self.path)?;
writeln!(f, " expected:")?;
writeln!(f, "{}", json_to_string(expected).indent(8))?;
writeln!(f, " actual:")?;
write!(f, "{}", json_to_string(actual).indent(8))?;
}
(CompareMode::Inclusive, None, Some(_expected)) => {
write!(
f,
"json atom at path \"{}\" is missing from actual",
self.path
)?;
}
(CompareMode::Inclusive, Some(_actual), None) => {
unreachable!("stuff missing actual wont produce an error")
}
(CompareMode::Inclusive, None, None) => unreachable!("can't both be missing"),
(CompareMode::Strict, Some(lhs), Some(rhs)) => {
writeln!(f, "json atoms at path \"{}\" are not equal:", self.path)?;
writeln!(f, " lhs:")?;
writeln!(f, "{}", json_to_string(lhs).indent(8))?;
writeln!(f, " rhs:")?;
write!(f, "{}", json_to_string(rhs).indent(8))?;
}
(CompareMode::Strict, None, Some(_)) => {
write!(f, "json atom at path \"{}\" is missing from lhs", self.path)?;
}
(CompareMode::Strict, Some(_), None) => {
write!(f, "json atom at path \"{}\" is missing from rhs", self.path)?;
}
(CompareMode::Strict, None, None) => unreachable!("can't both be missing"),
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
enum Path<'a> {
Root,
Keys(Vec<Key<'a>>),
}
impl<'a> Path<'a> {
fn append(&self, next: Key<'a>) -> Path<'a> {
match self {
Path::Root => Path::Keys(vec![next]),
Path::Keys(list) => {
let mut copy = list.clone();
copy.push(next);
Path::Keys(copy)
}
}
}
}
impl<'a> fmt::Display for Path<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Path::Root => write!(f, "(root)"),
Path::Keys(keys) => {
for key in keys {
write!(f, "{}", key)?;
}
Ok(())
}
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
enum Key<'a> {
Idx(usize),
Field(&'a str),
}
impl<'a> fmt::Display for Key<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Key::Idx(idx) => write!(f, "[{}]", idx),
Key::Field(key) => write!(f, ".{}", key),
}
}
}
fn fold_json<'a>(json: &'a Value, folder: &mut DiffFolder<'a, '_>) {
match json {
Value::Null => folder.on_null(json),
Value::Bool(_) => folder.on_bool(json),
Value::Number(_) => folder.on_number(json),
Value::String(_) => folder.on_string(json),
Value::Array(_) => folder.on_array(json),
Value::Object(_) => folder.on_object(json),
}
}
#[cfg(test)]
mod test {
#[allow(unused_imports)]
use super::*;
use serde_json::json;
#[test]
fn test_diffing_leaf_json() {
let diffs = diff(
&json!(null),
&json!(null),
Config::new(CompareMode::Inclusive),
);
assert_eq!(diffs, vec![]);
let diffs = diff(
&json!(false),
&json!(false),
Config::new(CompareMode::Inclusive),
);
assert_eq!(diffs, vec![]);
let diffs = diff(
&json!(true),
&json!(true),
Config::new(CompareMode::Inclusive),
);
assert_eq!(diffs, vec![]);
let diffs = diff(
&json!(false),
&json!(true),
Config::new(CompareMode::Inclusive),
);
assert_eq!(diffs.len(), 1);
let diffs = diff(
&json!(true),
&json!(false),
Config::new(CompareMode::Inclusive),
);
assert_eq!(diffs.len(), 1);
let actual = json!(1);
let expected = json!(1);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs, vec![]);
let actual = json!(2);
let expected = json!(1);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs.len(), 1);
let actual = json!(1);
let expected = json!(2);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs.len(), 1);
let actual = json!(1.0);
let expected = json!(1.0);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs, vec![]);
let actual = json!(1);
let expected = json!(1.0);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs.len(), 1);
let actual = json!(1.0);
let expected = json!(1);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs.len(), 1);
let actual = json!(1);
let expected = json!(1.0);
let diffs = diff(
&actual,
&expected,
Config::new(CompareMode::Inclusive).numeric_mode(NumericMode::AssumeFloat),
);
assert_eq!(diffs, vec![]);
let actual = json!(1.0);
let expected = json!(1);
let diffs = diff(
&actual,
&expected,
Config::new(CompareMode::Inclusive).numeric_mode(NumericMode::AssumeFloat),
);
assert_eq!(diffs, vec![]);
}
#[test]
fn test_diffing_array() {
// empty
let actual = json!([]);
let expected = json!([]);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs, vec![]);
let actual = json!([1]);
let expected = json!([]);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs.len(), 0);
let actual = json!([]);
let expected = json!([1]);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs.len(), 1);
// eq
let actual = json!([1]);
let expected = json!([1]);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs, vec![]);
// actual longer
let actual = json!([1, 2]);
let expected = json!([1]);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs, vec![]);
// expected longer
let actual = json!([1]);
let expected = json!([1, 2]);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs.len(), 1);
// eq length but different
let actual = json!([1, 3]);
let expected = json!([1, 2]);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs.len(), 1);
// different types
let actual = json!(1);
let expected = json!([1]);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs.len(), 1);
let actual = json!([1]);
let expected = json!(1);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs.len(), 1);
}
#[test]
fn test_array_strict() {
let actual = json!([]);
let expected = json!([]);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Strict));
assert_eq!(diffs.len(), 0);
let actual = json!([1, 2]);
let expected = json!([1, 2]);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Strict));
assert_eq!(diffs.len(), 0);
let actual = json!([1]);
let expected = json!([1, 2]);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Strict));
assert_eq!(diffs.len(), 1);
let actual = json!([1, 2]);
let expected = json!([1]);
let diffs = diff(&actual, &expected, Config::new(CompareMode::Strict));
assert_eq!(diffs.len(), 1);
}
#[test]
fn test_object() {
let actual = json!({});
let expected = json!({});
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs, vec![]);
let actual = json!({ "a": 1 });
let expected = json!({ "a": 1 });
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs, vec![]);
let actual = json!({ "a": 1, "b": 123 });
let expected = json!({ "a": 1 });
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs, vec![]);
let actual = json!({ "a": 1 });
let expected = json!({ "b": 1 });
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs.len(), 1);
let actual = json!({ "a": 1 });
let expected = json!({ "a": 2 });
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs.len(), 1);
let actual = json!({ "a": { "b": true } });
let expected = json!({ "a": {} });
let diffs = diff(&actual, &expected, Config::new(CompareMode::Inclusive));
assert_eq!(diffs, vec![]);
}
#[test]
fn test_object_strict() {
let lhs = json!({});
let rhs = json!({ "a": 1 });
let diffs = diff(&lhs, &rhs, Config::new(CompareMode::Strict));
assert_eq!(diffs.len(), 1);
let lhs = json!({ "a": 1 });
let rhs = json!({});
let diffs = diff(&lhs, &rhs, Config::new(CompareMode::Strict));
assert_eq!(diffs.len(), 1);
let json = json!({ "a": 1 });
let diffs = diff(&json, &json, Config::new(CompareMode::Strict));
assert_eq!(diffs, vec![]);
}
}

660
vendor/assert-json-diff/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,660 @@
//! This crate includes macros for comparing two serializable values by diffing their JSON
//! representations. It is designed to give much more helpful error messages than the standard
//! [`assert_eq!`]. It basically does a diff of the two objects and tells you the exact
//! differences. This is useful when asserting that two large JSON objects are the same.
//!
//! It uses the [serde] and [serde_json] to perform the serialization.
//!
//! [serde]: https://crates.io/crates/serde
//! [serde_json]: https://crates.io/crates/serde_json
//! [`assert_eq!`]: https://doc.rust-lang.org/std/macro.assert_eq.html
//!
//! ## Partial matching
//!
//! If you want to assert that one JSON value is "included" in another use
//! [`assert_json_include`](macro.assert_json_include.html):
//!
//! ```should_panic
//! use assert_json_diff::assert_json_include;
//! use serde_json::json;
//!
//! let a = json!({
//! "data": {
//! "users": [
//! {
//! "id": 1,
//! "country": {
//! "name": "Denmark"
//! }
//! },
//! {
//! "id": 24,
//! "country": {
//! "name": "Denmark"
//! }
//! }
//! ]
//! }
//! });
//!
//! let b = json!({
//! "data": {
//! "users": [
//! {
//! "id": 1,
//! "country": {
//! "name": "Sweden"
//! }
//! },
//! {
//! "id": 2,
//! "country": {
//! "name": "Denmark"
//! }
//! }
//! ]
//! }
//! });
//!
//! assert_json_include!(actual: a, expected: b)
//! ```
//!
//! This will panic with the error message:
//!
//! ```text
//! json atoms at path ".data.users[0].country.name" are not equal:
//! expected:
//! "Sweden"
//! actual:
//! "Denmark"
//!
//! json atoms at path ".data.users[1].id" are not equal:
//! expected:
//! 2
//! actual:
//! 24
//! ```
//!
//! [`assert_json_include`](macro.assert_json_include.html) allows extra data in `actual` but not in `expected`. That is so you can verify just a part
//! of the JSON without having to specify the whole thing. For example this test passes:
//!
//! ```
//! use assert_json_diff::assert_json_include;
//! use serde_json::json;
//!
//! assert_json_include!(
//! actual: json!({
//! "a": { "b": 1 },
//! }),
//! expected: json!({
//! "a": {},
//! })
//! )
//! ```
//!
//! However `expected` cannot contain additional data so this test fails:
//!
//! ```should_panic
//! use assert_json_diff::assert_json_include;
//! use serde_json::json;
//!
//! assert_json_include!(
//! actual: json!({
//! "a": {},
//! }),
//! expected: json!({
//! "a": { "b": 1 },
//! })
//! )
//! ```
//!
//! That will print
//!
//! ```text
//! json atom at path ".a.b" is missing from actual
//! ```
//!
//! ## Exact matching
//!
//! If you want to ensure two JSON values are *exactly* the same, use [`assert_json_eq`](macro.assert_json_eq.html).
//!
//! ```rust,should_panic
//! use assert_json_diff::assert_json_eq;
//! use serde_json::json;
//!
//! assert_json_eq!(
//! json!({ "a": { "b": 1 } }),
//! json!({ "a": {} })
//! )
//! ```
//!
//! This will panic with the error message:
//!
//! ```text
//! json atom at path ".a.b" is missing from lhs
//! ```
//!
//! ## Further customization
//!
//! You can use [`assert_json_matches`] to further customize the comparison.
#![deny(
missing_docs,
unused_imports,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications,
unknown_lints
)]
use diff::diff;
use serde::Serialize;
mod core_ext;
mod diff;
/// Compare two JSON values for an inclusive match.
///
/// It allows `actual` to contain additional data. If you want an exact match use
/// [`assert_json_eq`](macro.assert_json_eq.html) instead.
///
/// See [crate documentation](index.html) for examples.
#[macro_export]
macro_rules! assert_json_include {
(actual: $actual:expr, expected: $expected:expr $(,)?) => {{
$crate::assert_json_matches!(
$actual,
$expected,
$crate::Config::new($crate::CompareMode::Inclusive)
)
}};
(expected: $expected:expr, actual: $actual:expr $(,)?) => {{
$crate::assert_json_include!(actual: $actual, expected: $expected)
}};
}
/// Compare two JSON values for an exact match.
///
/// If you want an inclusive match use [`assert_json_include`](macro.assert_json_include.html) instead.
///
/// See [crate documentation](index.html) for examples.
#[macro_export]
macro_rules! assert_json_eq {
($lhs:expr, $rhs:expr $(,)?) => {{
$crate::assert_json_matches!($lhs, $rhs, $crate::Config::new($crate::CompareMode::Strict))
}};
}
/// Compare two JSON values according to a configuration.
///
/// ```
/// use assert_json_diff::{
/// CompareMode,
/// Config,
/// NumericMode,
/// assert_json_matches,
/// };
/// use serde_json::json;
///
/// let config = Config::new(CompareMode::Strict).numeric_mode(NumericMode::AssumeFloat);
///
/// assert_json_matches!(
/// json!({
/// "a": { "b": [1, 2, 3.0] },
/// }),
/// json!({
/// "a": { "b": [1, 2.0, 3] },
/// }),
/// config,
/// )
/// ```
///
/// When using `CompareMode::Inclusive` the first argument is `actual` and the second argument is
/// `expected`. Example:
///
/// ```
/// # use assert_json_diff::{
/// # CompareMode,
/// # Config,
/// # NumericMode,
/// # assert_json_matches,
/// # assert_json_include,
/// # };
/// # use serde_json::json;
/// #
/// // This
/// assert_json_matches!(
/// json!({
/// "a": { "b": 1 },
/// }),
/// json!({
/// "a": {},
/// }),
/// Config::new(CompareMode::Inclusive),
/// );
///
/// // Is the same as this
/// assert_json_include!(
/// actual: json!({
/// "a": { "b": 1 },
/// }),
/// expected: json!({
/// "a": {},
/// }),
/// );
/// ```
#[macro_export]
macro_rules! assert_json_matches {
($lhs:expr, $rhs:expr, $config:expr $(,)?) => {{
if let Err(error) = $crate::assert_json_matches_no_panic(&$lhs, &$rhs, $config) {
panic!("\n\n{}\n\n", error);
}
}};
}
/// Compares two JSON values without panicking.
///
/// Instead it returns a `Result` where the error is the message that would be passed to `panic!`.
/// This is might be useful if you want to control how failures are reported and don't want to deal
/// with panics.
pub fn assert_json_matches_no_panic<Lhs, Rhs>(
lhs: &Lhs,
rhs: &Rhs,
config: Config,
) -> Result<(), String>
where
Lhs: Serialize,
Rhs: Serialize,
{
let lhs = serde_json::to_value(lhs).unwrap_or_else(|err| {
panic!(
"Couldn't convert left hand side value to JSON. Serde error: {}",
err
)
});
let rhs = serde_json::to_value(rhs).unwrap_or_else(|err| {
panic!(
"Couldn't convert right hand side value to JSON. Serde error: {}",
err
)
});
let diffs = diff(&lhs, &rhs, config);
if diffs.is_empty() {
Ok(())
} else {
let msg = diffs
.into_iter()
.map(|d| d.to_string())
.collect::<Vec<_>>()
.join("\n\n");
Err(msg)
}
}
/// Configuration for how JSON values should be compared.
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(missing_copy_implementations)]
pub struct Config {
pub(crate) compare_mode: CompareMode,
pub(crate) numeric_mode: NumericMode,
}
impl Config {
/// Create a new [`Config`] using the given [`CompareMode`].
///
/// The default `numeric_mode` is be [`NumericMode::Strict`].
pub fn new(compare_mode: CompareMode) -> Self {
Self {
compare_mode,
numeric_mode: NumericMode::Strict,
}
}
/// Change the config's numeric mode.
///
/// The default `numeric_mode` is be [`NumericMode::Strict`].
pub fn numeric_mode(mut self, numeric_mode: NumericMode) -> Self {
self.numeric_mode = numeric_mode;
self
}
/// Change the config's compare mode.
pub fn compare_mode(mut self, compare_mode: CompareMode) -> Self {
self.compare_mode = compare_mode;
self
}
}
/// Mode for how JSON values should be compared.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CompareMode {
/// The two JSON values don't have to be exactly equal. The "actual" value is only required to
/// be "contained" inside "expected". See [crate documentation](index.html) for examples.
///
/// The mode used with [`assert_json_include`].
Inclusive,
/// The two JSON values must be exactly equal.
///
/// The mode used with [`assert_json_eq`].
Strict,
}
/// How should numbers be compared.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum NumericMode {
/// Different numeric types aren't considered equal.
Strict,
/// All numeric types are converted to float before comparison.
AssumeFloat,
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::{json, Value};
use std::fmt::Write;
#[test]
fn boolean_root() {
let result = test_partial_match(json!(true), json!(true));
assert_output_eq(result, Ok(()));
let result = test_partial_match(json!(false), json!(false));
assert_output_eq(result, Ok(()));
let result = test_partial_match(json!(false), json!(true));
assert_output_eq(
result,
Err(r#"json atoms at path "(root)" are not equal:
expected:
true
actual:
false"#),
);
let result = test_partial_match(json!(true), json!(false));
assert_output_eq(
result,
Err(r#"json atoms at path "(root)" are not equal:
expected:
false
actual:
true"#),
);
}
#[test]
fn string_root() {
let result = test_partial_match(json!("true"), json!("true"));
assert_output_eq(result, Ok(()));
let result = test_partial_match(json!("false"), json!("false"));
assert_output_eq(result, Ok(()));
let result = test_partial_match(json!("false"), json!("true"));
assert_output_eq(
result,
Err(r#"json atoms at path "(root)" are not equal:
expected:
"true"
actual:
"false""#),
);
let result = test_partial_match(json!("true"), json!("false"));
assert_output_eq(
result,
Err(r#"json atoms at path "(root)" are not equal:
expected:
"false"
actual:
"true""#),
);
}
#[test]
fn number_root() {
let result = test_partial_match(json!(1), json!(1));
assert_output_eq(result, Ok(()));
let result = test_partial_match(json!(0), json!(0));
assert_output_eq(result, Ok(()));
let result = test_partial_match(json!(0), json!(1));
assert_output_eq(
result,
Err(r#"json atoms at path "(root)" are not equal:
expected:
1
actual:
0"#),
);
let result = test_partial_match(json!(1), json!(0));
assert_output_eq(
result,
Err(r#"json atoms at path "(root)" are not equal:
expected:
0
actual:
1"#),
);
}
#[test]
fn null_root() {
let result = test_partial_match(json!(null), json!(null));
assert_output_eq(result, Ok(()));
let result = test_partial_match(json!(null), json!(1));
assert_output_eq(
result,
Err(r#"json atoms at path "(root)" are not equal:
expected:
1
actual:
null"#),
);
let result = test_partial_match(json!(1), json!(null));
assert_output_eq(
result,
Err(r#"json atoms at path "(root)" are not equal:
expected:
null
actual:
1"#),
);
}
#[test]
fn into_object() {
let result = test_partial_match(json!({ "a": true }), json!({ "a": true }));
assert_output_eq(result, Ok(()));
let result = test_partial_match(json!({ "a": false }), json!({ "a": true }));
assert_output_eq(
result,
Err(r#"json atoms at path ".a" are not equal:
expected:
true
actual:
false"#),
);
let result =
test_partial_match(json!({ "a": { "b": true } }), json!({ "a": { "b": true } }));
assert_output_eq(result, Ok(()));
let result = test_partial_match(json!({ "a": true }), json!({ "a": { "b": true } }));
assert_output_eq(
result,
Err(r#"json atoms at path ".a" are not equal:
expected:
{
"b": true
}
actual:
true"#),
);
let result = test_partial_match(json!({}), json!({ "a": true }));
assert_output_eq(
result,
Err(r#"json atom at path ".a" is missing from actual"#),
);
let result = test_partial_match(json!({ "a": { "b": true } }), json!({ "a": true }));
assert_output_eq(
result,
Err(r#"json atoms at path ".a" are not equal:
expected:
true
actual:
{
"b": true
}"#),
);
}
#[test]
fn into_array() {
let result = test_partial_match(json!([1]), json!([1]));
assert_output_eq(result, Ok(()));
let result = test_partial_match(json!([2]), json!([1]));
assert_output_eq(
result,
Err(r#"json atoms at path "[0]" are not equal:
expected:
1
actual:
2"#),
);
let result = test_partial_match(json!([1, 2, 4]), json!([1, 2, 3]));
assert_output_eq(
result,
Err(r#"json atoms at path "[2]" are not equal:
expected:
3
actual:
4"#),
);
let result = test_partial_match(json!({ "a": [1, 2, 3]}), json!({ "a": [1, 2, 4]}));
assert_output_eq(
result,
Err(r#"json atoms at path ".a[2]" are not equal:
expected:
4
actual:
3"#),
);
let result = test_partial_match(json!({ "a": [1, 2, 3]}), json!({ "a": [1, 2]}));
assert_output_eq(result, Ok(()));
let result = test_partial_match(json!({ "a": [1, 2]}), json!({ "a": [1, 2, 3]}));
assert_output_eq(
result,
Err(r#"json atom at path ".a[2]" is missing from actual"#),
);
}
#[test]
fn exact_matching() {
let result = test_exact_match(json!(true), json!(true));
assert_output_eq(result, Ok(()));
let result = test_exact_match(json!("s"), json!("s"));
assert_output_eq(result, Ok(()));
let result = test_exact_match(json!("a"), json!("b"));
assert_output_eq(
result,
Err(r#"json atoms at path "(root)" are not equal:
lhs:
"a"
rhs:
"b""#),
);
let result = test_exact_match(
json!({ "a": [1, { "b": 2 }] }),
json!({ "a": [1, { "b": 3 }] }),
);
assert_output_eq(
result,
Err(r#"json atoms at path ".a[1].b" are not equal:
lhs:
2
rhs:
3"#),
);
}
#[test]
fn exact_match_output_message() {
let result = test_exact_match(json!({ "a": { "b": 1 } }), json!({ "a": {} }));
assert_output_eq(
result,
Err(r#"json atom at path ".a.b" is missing from rhs"#),
);
let result = test_exact_match(json!({ "a": {} }), json!({ "a": { "b": 1 } }));
assert_output_eq(
result,
Err(r#"json atom at path ".a.b" is missing from lhs"#),
);
}
fn assert_output_eq(actual: Result<(), String>, expected: Result<(), &str>) {
match (actual, expected) {
(Ok(()), Ok(())) => {}
(Err(actual_error), Ok(())) => {
let mut f = String::new();
writeln!(f, "Did not expect error, but got").unwrap();
writeln!(f, "{}", actual_error).unwrap();
panic!("{}", f);
}
(Ok(()), Err(expected_error)) => {
let expected_error = expected_error.to_string();
let mut f = String::new();
writeln!(f, "Expected error, but did not get one. Expected error:").unwrap();
writeln!(f, "{}", expected_error).unwrap();
panic!("{}", f);
}
(Err(actual_error), Err(expected_error)) => {
let expected_error = expected_error.to_string();
if actual_error != expected_error {
let mut f = String::new();
writeln!(f, "Errors didn't match").unwrap();
writeln!(f, "Expected:").unwrap();
writeln!(f, "{}", expected_error).unwrap();
writeln!(f, "Got:").unwrap();
writeln!(f, "{}", actual_error).unwrap();
panic!("{}", f);
}
}
}
}
fn test_partial_match(lhs: Value, rhs: Value) -> Result<(), String> {
assert_json_matches_no_panic(&lhs, &rhs, Config::new(CompareMode::Inclusive))
}
fn test_exact_match(lhs: Value, rhs: Value) -> Result<(), String> {
assert_json_matches_no_panic(&lhs, &rhs, Config::new(CompareMode::Strict))
}
}

Binary file not shown.

View File

@@ -0,0 +1 @@
{"name":"assert-json-diff","vers":"2.0.2","deps":[{"name":"serde","req":"^1","features":[],"optional":false,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"serde_json","req":"^1","features":[],"optional":false,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"serde","req":"^1","features":["derive"],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"version-sync","req":"^0.8","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false}],"features":{},"features2":null,"cksum":"ded9c6ba91dc4a5e434e416bbb4c2f49d4b5c8d0f49955bdf6df6aa2c2191685","yanked":null,"links":null,"rust_version":null,"v":2}

View File

@@ -0,0 +1,184 @@
use assert_json_diff::{
assert_json_eq, assert_json_include, assert_json_matches, assert_json_matches_no_panic,
CompareMode, Config, NumericMode,
};
use serde::Serialize;
use serde_json::json;
#[test]
fn can_pass() {
assert_json_include!(
actual: json!({ "a": { "b": true }, "c": [true, null, 1] }),
expected: json!({ "a": { "b": true }, "c": [true, null, 1] })
);
assert_json_include!(
actual: json!({ "a": { "b": true } }),
expected: json!({ "a": {} })
);
assert_json_include!(
actual: json!({ "a": { "b": true } }),
expected: json!({ "a": {} }),
);
assert_json_include!(
expected: json!({ "a": {} }),
actual: json!({ "a": { "b": true } }),
);
}
#[test]
#[should_panic]
fn can_fail() {
assert_json_include!(
actual: json!({ "a": { "b": true }, "c": [true, null, 1] }),
expected: json!({ "a": { "b": false }, "c": [false, null, {}] })
);
}
#[test]
#[should_panic]
fn different_numeric_types_include_should_fail() {
assert_json_include!(
actual: json!({ "a": { "b": true }, "c": 1 }),
expected: json!({ "a": { "b": true }, "c": 1.0 })
);
}
#[test]
#[should_panic]
fn different_numeric_types_eq_should_fail() {
assert_json_eq!(
json!({ "a": { "b": true }, "c": 1 }),
json!({ "a": { "b": true }, "c": 1.0 })
);
}
#[test]
fn different_numeric_types_assume_float() {
let actual = json!({ "a": { "b": true }, "c": [true, null, 1] });
let expected = json!({ "a": { "b": true }, "c": [true, null, 1.0] });
let config = Config::new(CompareMode::Inclusive).numeric_mode(NumericMode::AssumeFloat);
assert_json_matches!(actual, expected, config.clone());
assert_json_matches!(actual, expected, config.compare_mode(CompareMode::Strict))
}
#[test]
fn can_pass_with_exact_match() {
assert_json_eq!(json!({ "a": { "b": true } }), json!({ "a": { "b": true } }));
assert_json_eq!(json!({ "a": { "b": true } }), json!({ "a": { "b": true } }),);
}
#[test]
#[should_panic]
fn can_fail_with_exact_match() {
assert_json_eq!(json!({ "a": { "b": true } }), json!({ "a": {} }));
}
#[test]
fn inclusive_match_without_panicking() {
assert!(assert_json_matches_no_panic(
&json!({ "a": 1, "b": 2 }),
&json!({ "b": 2}),
Config::new(CompareMode::Inclusive,).numeric_mode(NumericMode::Strict),
)
.is_ok());
assert!(assert_json_matches_no_panic(
&json!({ "a": 1, "b": 2 }),
&json!("foo"),
Config::new(CompareMode::Inclusive,).numeric_mode(NumericMode::Strict),
)
.is_err());
}
#[test]
fn exact_match_without_panicking() {
assert!(assert_json_matches_no_panic(
&json!([1, 2, 3]),
&json!([1, 2, 3]),
Config::new(CompareMode::Strict).numeric_mode(NumericMode::Strict)
)
.is_ok());
assert!(assert_json_matches_no_panic(
&json!([1, 2, 3]),
&json!("foo"),
Config::new(CompareMode::Strict).numeric_mode(NumericMode::Strict)
)
.is_err());
}
#[derive(Serialize)]
struct User {
id: i32,
username: String,
}
#[test]
fn include_with_serializable() {
let user = User {
id: 1,
username: "bob".to_string(),
};
assert_json_include!(
actual: json!({
"id": 1,
"username": "bob",
"email": "bob@example.com"
}),
expected: user,
);
}
#[test]
fn include_with_serializable_ref() {
let user = User {
id: 1,
username: "bob".to_string(),
};
assert_json_include!(
actual: &json!({
"id": 1,
"username": "bob",
"email": "bob@example.com"
}),
expected: &user,
);
}
#[test]
fn eq_with_serializable() {
let user = User {
id: 1,
username: "bob".to_string(),
};
assert_json_eq!(
json!({
"id": 1,
"username": "bob"
}),
user,
);
}
#[test]
fn eq_with_serializable_ref() {
let user = User {
id: 1,
username: "bob".to_string(),
};
assert_json_eq!(
&json!({
"id": 1,
"username": "bob"
}),
&user,
);
}

View File

@@ -0,0 +1,12 @@
#[macro_use]
extern crate version_sync;
#[test]
fn test_readme_deps() {
assert_markdown_deps_updated!("README.md");
}
#[test]
fn test_html_root_url() {
assert_html_root_url_updated!("src/lib.rs");
}