Skip to content

Feature/0.6.0 better error handling #8

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: coverage instrument based

on: [ push, pull_request ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Install latest nightly
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
override: true
components: rustfmt, clippy, llvm-tools-preview

- name: Install lcov
run: sudo apt-get install lcov

- name: install grcov
run: cargo install grcov

- uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Run grcov
env:
PROJECT_NAME: "json-diff"
RUSTDOCFLAGS: "-Cinstrument-coverage -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
RUSTFLAGS: "-Cinstrument-coverage -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
CARGO_INCREMENTAL: 0
run: |
cargo +nightly build --verbose
cargo +nightly test --verbose
grcov . -s . --binary-path ./target/debug/ -t lcov --llvm --branch --ignore-not-existing --ignore="/*" --ignore="target/*" --ignore="tests/*" -o lcov.info

- name: Push grcov results to Coveralls via GitHub Action
uses: coverallsapp/github-action@v1.0.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: "lcov.info"
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
[![Crates.io](https://img.shields.io/crates/d/json_diff_ng?style=flat)](https://crates.io/crates/json_diff_ng)
[![Documentation](https://docs.rs/json_diff_ng/badge.svg)](https://docs.rs/json_diff_ng)
![CI](https://github.com/ChrisRega/json-diff/actions/workflows/rust.yml/badge.svg?branch=master "CI")
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat)](LICENSE)
[![Coverage Status](https://coveralls.io/repos/github/ChrisRega/json-diff/badge.svg?branch=master)](https://coveralls.io/github/ChrisRega/json-diff?branch=master)
[![License](https://img.shields.io/github/license/ChrisRega/json-diff)](LICENSE)

## Contributors:

Expand All @@ -12,31 +13,34 @@
</a>

## Library

json_diff_ng can be used to get diffs of json-serializable structures in rust.

### Usage example

```rust
use json_diff::compare_strs;
let data1 = r#"["a",{"c": ["d","f"] },"b"]"#;
let data2 = r#"["b",{"c": ["e","d"] },"a"]"#;
let diffs = compare_strs(data1, data2, true, &[]).unwrap();
let diffs = compare_strs(data1, data2, true, & []).unwrap();
assert!(!diffs.is_empty());
let diffs = diffs.unequal_values.get_diffs();
assert_eq!(diffs.len(), 1);
assert_eq!(
diffs.first().unwrap().to_string(),
r#".[0].c.[1].("f" != "e")"#
diffs.first().unwrap().to_string(),
r#".[0].c.[1].("f" != "e")"#
);
```

See [docs.rs](https://docs.rs/json_diff_ng) for more details.


## CLI
json-diff is a command line utility to compare two jsons.

json-diff is a command line utility to compare two jsons.

Input can be fed as inline strings or through files.
For readability, output is neatly differentiated into three categories: keys with different values, and keys not present in either of the objects.
For readability, output is neatly differentiated into three categories: keys with different values, and keys not present
in either of the objects.
Only missing or unequal keys are printed in output to reduce the verbosity.

Usage Example:
Expand All @@ -50,5 +54,6 @@ file : read input from json files
direct : read input from command line

### Installation

`$ cargo install json_diff_ng`

44 changes: 39 additions & 5 deletions src/enums.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::collections::HashMap;
use std::fmt::{Display, Formatter};

use serde_json::Value;
use thiserror::Error;
use vg_errortools::FatIOError;

Expand All @@ -19,10 +21,6 @@ impl From<String> for Error {
}
}

use std::collections::HashMap;

use serde_json::Value;

#[derive(Debug, PartialEq)]
pub enum DiffTreeNode {
Null,
Expand Down Expand Up @@ -123,13 +121,23 @@ impl<'a> PathElement<'a> {
}
}

/// A view on a single end-node of the [`DiffKeyNode`] tree.
/// A view on a single end-node of the [`DiffTreeNode`] tree.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct DiffEntry<'a> {
pub path: Vec<PathElement<'a>>,
pub values: Option<(&'a serde_json::Value, &'a serde_json::Value)>,
}

impl<'a> DiffEntry<'a> {
pub fn resolve<'b>(&'a self, value: &'b serde_json::Value) -> Option<&'b serde_json::Value> {
let mut return_value = value;
for a in &self.path {
return_value = a.resolve(return_value)?;
}
Some(return_value)
}
}

impl Display for DiffEntry<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
for element in &self.path {
Expand Down Expand Up @@ -158,3 +166,29 @@ impl Display for PathElement<'_> {
}
}
}

#[cfg(test)]
mod test {
use serde_json::json;

use crate::compare_serde_values;
use crate::sort::sort_value;

#[test]
fn test_resolve() {
let data1 = json! {["a",{"c": ["d","f"] },"b"]};
let data2 = json! {["b",{"c": ["e","d"] },"a"]};
let diffs = compare_serde_values(&data1, &data2, true, &[]).unwrap();
assert!(!diffs.is_empty());
let data1_sorted = sort_value(&data1, &[]);
let data2_sorted = sort_value(&data2, &[]);

let all_diffs = diffs.all_diffs();
assert_eq!(all_diffs.len(), 1);
let (_type, diff) = all_diffs.first().unwrap();
let val = diff.resolve(&data1_sorted);
assert_eq!(val.unwrap().as_str().unwrap(), "f");
let val = diff.resolve(&data2_sorted);
assert_eq!(val.unwrap().as_str().unwrap(), "e");
}
}
45 changes: 41 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,54 @@
//! a flat list of [`DiffEntry`] which is more easily usable. The path in the json is collapsed into a vector of [`PathElement`] which can be used to follow the diff.
//! Similarly, all diffs after an operation can be collected using [`Mismatch::all_diffs`].
//!
//! ### Just print everything
//!
//! ```rust
//! use serde_json::json;
//! use json_diff_ng::compare_serde_values;
//! use json_diff_ng::sort::sort_value;
//! let data1 = json! {["a",{"c": ["d","f"] },"b"]};
//! let data2 = json! {["b",{"c": ["e","d"] },"a"]};
//! let diffs = compare_serde_values(&data1, &data2, true, &[]).unwrap();
//! for (d_type, d_path) in diffs.all_diffs() {
//! let _message = format!("{d_type}: {d_path}");
//! }
//! ```
//!
//! ### Traversing the diff result JSONs
//! ```rust
//! use serde_json::json;
//! use json_diff_ng::compare_serde_values;
//! use json_diff_ng::sort::sort_value;
//! let data1 = json! {["a",{"c": ["d","f"] },"b"]};
//! let data2 = json! {["b",{"c": ["e","d"] },"a"]};
//! let diffs = compare_serde_values(&data1, &data2, true, &[]).unwrap();
//! assert!(!diffs.is_empty());
//! // since we sorted for comparison, if we want to resolve the path, we need a sorted result as well.
//! let data1_sorted = sort_value(&data1, &[]);
//! let data2_sorted = sort_value(&data2, &[]);
//! let all_diffs = diffs.all_diffs();
//! assert_eq!(all_diffs.len(), 1);
//! let (_type, diff) = all_diffs.first().unwrap();
//! let val = diff.resolve(&data1_sorted);
//! assert_eq!(val.unwrap().as_str().unwrap(), "f");
//! let val = diff.resolve(&data2_sorted);
//! assert_eq!(val.unwrap().as_str().unwrap(), "e");
//! ```
//!

pub mod enums;
pub mod mismatch;
pub mod process;
pub mod sort;
pub use enums::DiffEntry;
pub use enums::DiffTreeNode;
pub use enums::DiffType;
pub use enums::Error;
pub use enums::PathElement;
pub use mismatch::Mismatch;
pub use process::compare_serde_values;
pub use process::compare_strs;

pub mod enums;
pub mod mismatch;
pub mod process;
pub mod sort;

pub type Result<T> = std::result::Result<T, Error>;
Loading
Loading