1mod apply_patch;
2mod apply_patch_mut;
3mod diff_patch;
4
5pub use apply_patch::apply;
6pub use apply_patch_mut::apply_mut;
7pub use diff_patch::diff;
8pub use diff_patch::diff_including;
9
10#[cfg(test)]
11mod tests {
12 use serde::{Deserialize, Serialize};
13 use serde_json::json;
14
15 #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
16 struct Profile {
17 bio: String,
18 avatar_url: Option<String>,
19 }
20
21 #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
22 struct User {
23 id: u32,
24 username: String,
25 age: u8,
26 active: bool,
27 profile: Option<Profile>,
28 }
29
30 #[test]
31 fn test_diff() {
32 let old = User {
33 id: 1001,
34 username: "alice".to_string(),
35 age: 30,
36 active: true,
37 profile: Some(Profile {
38 bio: "Software engineer".to_string(),
39 avatar_url: Some("https://example.com/alice-old.jpg".to_string()),
40 }),
41 };
42
43 let new = User {
44 id: 1001,
45 username: "alice".to_string(),
46 age: 31,
47 active: false,
48 profile: Some(Profile {
49 bio: "Senior software engineer".to_string(),
50 avatar_url: None,
51 }),
52 };
53
54 let patch = serde_json::to_string(&crate::diff(&old, &new).unwrap()).unwrap();
55
56 assert_eq!(
57 patch,
58 r#"{"active":false,"age":31,"profile":{"avatar_url":null,"bio":"Senior software engineer"}}"#
59 );
60 }
61
62 #[test]
63 fn test_diff_forced_nested() {
64 let old = User {
65 id: 1001,
66 username: "alice".to_string(),
67 age: 30,
68 active: true,
69 profile: Some(Profile {
70 bio: "Software engineer".to_string(), avatar_url: Some("https://example.com/alice-old.jpg".to_string()),
72 }),
73 };
74 let new = User {
75 id: 1001,
76 username: "alice".to_string(),
77 age: 31,
78 active: false,
79 profile: Some(Profile {
80 bio: "Software engineer".to_string(),
81 avatar_url: None,
82 }),
83 };
84
85 let patch_value = crate::diff_including(&old, &new, &["profile.bio"]).unwrap();
86
87 let expected = json!({
88 "age": 31,
89 "active": false,
90 "profile": {
91 "bio": "Software engineer",
92 "avatar_url": null
93 }
94 });
95
96 assert_eq!(patch_value, expected);
97 }
98
99 #[test]
100 fn test_apply_patch_immutable() {
101 let current = User {
102 id: 1001,
103 username: "alice".to_string(),
104 age: 30,
105 active: true,
106 profile: Some(Profile {
107 bio: "Software engineer".to_string(),
108 avatar_url: Some("https://example.com/alice-old.jpg".to_string()),
109 }),
110 };
111
112 let patch = r#"
113 {
114 "age": 31,
115 "active": false,
116 "profile": {
117 "bio": "Senior software engineer",
118 "avatar_url": null
119 }
120 }
121 "#;
122
123 let updated: User = crate::apply(current, patch).unwrap();
124
125 assert_eq!(
126 updated,
127 User {
128 id: 1001,
129 username: "alice".to_string(),
130 age: 31,
131 active: false,
132 profile: Some(Profile {
133 bio: "Senior software engineer".to_string(),
134 avatar_url: None,
135 }),
136 }
137 );
138 }
139
140 #[test]
141 fn test_apply_patch_mutable() {
142 let mut current = User {
143 id: 1001,
144 username: "alice".to_string(),
145 age: 30,
146 active: true,
147 profile: Some(Profile {
148 bio: "Software engineer".to_string(),
149 avatar_url: Some("https://example.com/alice-old.jpg".to_string()),
150 }),
151 };
152
153 let patch = r#"
154 {
155 "age": 31,
156 "active": false,
157 "profile": {
158 "bio": "Senior software engineer",
159 "avatar_url": null
160 }
161 }
162 "#;
163
164 crate::apply_mut(&mut current, patch).unwrap();
165
166 assert_eq!(
167 current,
168 User {
169 id: 1001,
170 username: "alice".to_string(),
171 age: 31,
172 active: false,
173 profile: Some(Profile {
174 bio: "Senior software engineer".to_string(),
175 avatar_url: None,
176 }),
177 }
178 );
179 }
180}