1
use serde_json::Value;
2

            
3
/// Compare two JSON values.
4
/// If the values are String, Number, or Bool, they are compared directly.
5
/// If the values are arrays, they are compared element-wise.
6
/// Otherwise, they are compared as strings.
7
64788
fn json_value_cmp(a: &Value, b: &Value) -> std::cmp::Ordering {
8
64788
    match (a, b) {
9
        (Value::Null, Value::Null) => std::cmp::Ordering::Equal,
10
        (Value::Bool(a), Value::Bool(b)) => a.cmp(b),
11
        (Value::String(a), Value::String(b)) => a.cmp(b),
12
        (Value::Number(a), Value::Number(b)) => {
13
            let af = a.as_f64().unwrap_or_default();
14
            let bf = b.as_f64().unwrap_or_default();
15
            af.total_cmp(&bf)
16
        }
17
1392
        (Value::Array(a), Value::Array(b)) => {
18
1392
            for (a, b) in a.iter().zip(b.iter()) {
19
1392
                let cmp = json_value_cmp(a, b);
20
1392
                if cmp != std::cmp::Ordering::Equal {
21
1392
                    return cmp;
22
                }
23
            }
24
            std::cmp::Ordering::Equal
25
        }
26
63396
        _ => a.to_string().cmp(&b.to_string()),
27
    }
28
64788
}
29

            
30
/// Sort the "variables" field by name.
31
/// We have to do this separately because that field is not a JSON object, instead it's an array of tuples.
32
600
pub fn sort_json_variables(value: &Value) -> Value {
33
600
    match value {
34
600
        Value::Array(vars) => {
35
600
            let mut vars_sorted = vars.clone();
36
600
            vars_sorted.sort_by(json_value_cmp);
37
600
            Value::Array(vars_sorted)
38
        }
39
        _ => value.clone(),
40
    }
41
600
}
42

            
43
/// Recursively sorts the keys of all JSON objects within the provided JSON value.
44
///
45
/// serde_json will output JSON objects in an arbitrary key order.
46
/// this is normally fine, except in our use case we wouldn't want to update the expected output again and again.
47
/// so a consistent (sorted) ordering of the keys is desirable.
48
145998
pub fn sort_json_object(value: &Value, sort_arrays: bool) -> Value {
49
145998
    match value {
50
37224
        Value::Object(obj) => {
51
37224
            let mut ordered: Vec<(String, Value)> = obj
52
37224
                .iter()
53
112572
                .map(|(k, v)| {
54
112572
                    if k == "variables" {
55
600
                        (k.clone(), sort_json_variables(v))
56
                    } else {
57
111972
                        (k.clone(), sort_json_object(v, sort_arrays))
58
                    }
59
112572
                })
60
37224
                .collect();
61
37224

            
62
75348
            ordered.sort_by(|a, b| a.0.cmp(&b.0));
63
37224
            Value::Object(ordered.into_iter().collect())
64
        }
65
7140
        Value::Array(arr) => {
66
7140
            let mut arr: Vec<Value> = arr
67
7140
                .iter()
68
32478
                .map(|val| sort_json_object(val, sort_arrays))
69
7140
                .collect();
70
7140

            
71
7140
            if sort_arrays {
72
600
                arr.sort_by(json_value_cmp);
73
6540
            }
74

            
75
7140
            Value::Array(arr)
76
        }
77
101634
        _ => value.clone(),
78
    }
79
145998
}