1#![cfg_attr(not(any(test, feature = "box", feature = "option")), no_std)]
77
78#[doc(hidden)]
79pub use struct_patch_derive::Filler;
80#[doc(hidden)]
81pub use struct_patch_derive::Patch;
82#[cfg(any(feature = "box", feature = "option"))]
83pub mod std;
84pub mod traits;
85pub use traits::*;
86
87#[cfg(test)]
88mod tests {
89 use serde::Deserialize;
90 #[cfg(feature = "merge")]
91 use struct_patch::Merge;
92 use struct_patch::Patch;
93 #[cfg(feature = "status")]
94 use struct_patch::Status;
95
96 use crate as struct_patch;
97
98 #[test]
99 fn test_basic() {
100 #[derive(Patch, Debug, PartialEq)]
101 struct Item {
102 field: u32,
103 other: String,
104 }
105
106 let mut item = Item {
107 field: 1,
108 other: String::from("hello"),
109 };
110 let patch = ItemPatch {
111 field: None,
112 other: Some(String::from("bye")),
113 };
114
115 item.apply(patch);
116 assert_eq!(
117 item,
118 Item {
119 field: 1,
120 other: String::from("bye")
121 }
122 );
123 }
124
125 #[test]
126 #[cfg(feature = "status")]
127 fn test_empty() {
128 #[derive(Patch)]
129 #[patch(attribute(derive(Debug, PartialEq)))]
130 struct Item {
131 data: u32,
132 }
133
134 let patch = ItemPatch { data: None };
135 let other_patch = Item::new_empty_patch();
136 assert!(patch.is_empty());
137 assert_eq!(patch, other_patch);
138 let patch = ItemPatch { data: Some(0) };
139 assert!(!patch.is_empty());
140 }
141
142 #[test]
143 fn test_derive() {
144 #[allow(dead_code)]
145 #[derive(Patch)]
146 #[patch(attribute(derive(Copy, Clone, PartialEq, Debug)))]
147 struct Item;
148
149 let patch = ItemPatch {};
150 let other_patch = patch;
151 assert_eq!(patch, other_patch);
152 }
153
154 #[test]
155 fn test_name() {
156 #[derive(Patch)]
157 #[patch(name = "PatchItem")]
158 struct Item;
159
160 let patch = PatchItem {};
161 let mut item = Item;
162 item.apply(patch);
163 }
164
165 #[test]
166 fn test_nullable() {
167 #[derive(Patch, Debug, PartialEq)]
168 struct Item {
169 field: Option<u32>,
170 other: Option<String>,
171 }
172
173 let mut item = Item {
174 field: Some(1),
175 other: Some(String::from("hello")),
176 };
177 let patch = ItemPatch {
178 field: None,
179 other: Some(None),
180 };
181
182 item.apply(patch);
183 assert_eq!(
184 item,
185 Item {
186 field: Some(1),
187 other: None
188 }
189 );
190 }
191
192 #[test]
193 fn test_skip() {
194 #[derive(Patch, PartialEq, Debug)]
195 #[patch(attribute(derive(PartialEq, Debug, Deserialize)))]
196 struct Item {
197 #[patch(skip)]
198 id: u32,
199 data: u32,
200 }
201
202 let mut item = Item { id: 1, data: 2 };
203 let data = r#"{ "id": 10, "data": 15 }"#; let patch: ItemPatch = serde_json::from_str(data).unwrap();
205 assert_eq!(patch, ItemPatch { data: Some(15) });
206
207 item.apply(patch);
208 assert_eq!(item, Item { id: 1, data: 15 });
209 }
210
211 #[test]
212 fn test_nested() {
213 #[derive(PartialEq, Debug, Patch, Deserialize)]
214 #[patch(attribute(derive(PartialEq, Debug, Deserialize)))]
215 struct B {
216 c: u32,
217 d: u32,
218 }
219
220 #[derive(PartialEq, Debug, Patch, Deserialize)]
221 #[patch(attribute(derive(PartialEq, Debug, Deserialize)))]
222 struct A {
223 #[patch(name = "BPatch")]
224 b: B,
225 }
226
227 let mut a = A {
228 b: B { c: 0, d: 0 },
229 };
230 let data = r#"{ "b": { "c": 1 } }"#;
231 let patch: APatch = serde_json::from_str(data).unwrap();
232 a.apply(patch);
239 assert_eq!(
240 a,
241 A {
242 b: B { c: 1, d: 0 }
243 }
244 );
245 }
246
247 #[test]
248 fn test_generic() {
249 #[derive(Patch)]
250 struct Item<T>
251 where
252 T: PartialEq,
253 {
254 pub field: T,
255 }
256
257 let patch = ItemPatch {
258 field: Some(String::from("hello")),
259 };
260 let mut item = Item {
261 field: String::new(),
262 };
263 item.apply(patch);
264 assert_eq!(item.field, "hello");
265 }
266
267 #[test]
268 fn test_named_generic() {
269 #[derive(Patch)]
270 #[patch(name = "PatchItem")]
271 struct Item<T>
272 where
273 T: PartialEq,
274 {
275 pub field: T,
276 }
277
278 let patch = PatchItem {
279 field: Some(String::from("hello")),
280 };
281 let mut item = Item {
282 field: String::new(),
283 };
284 item.apply(patch);
285 }
286
287 #[test]
288 fn test_nested_generic() {
289 #[derive(PartialEq, Debug, Patch, Deserialize)]
290 #[patch(attribute(derive(PartialEq, Debug, Deserialize)))]
291 struct B<T>
292 where
293 T: PartialEq,
294 {
295 c: T,
296 d: T,
297 }
298
299 #[derive(PartialEq, Debug, Patch, Deserialize)]
300 #[patch(attribute(derive(PartialEq, Debug, Deserialize)))]
301 struct A {
302 #[patch(name = "BPatch<u32>")]
303 b: B<u32>,
304 }
305
306 let mut a = A {
307 b: B { c: 0, d: 0 },
308 };
309 let data = r#"{ "b": { "c": 1 } }"#;
310 let patch: APatch = serde_json::from_str(data).unwrap();
311
312 a.apply(patch);
313 assert_eq!(
314 a,
315 A {
316 b: B { c: 1, d: 0 }
317 }
318 );
319 }
320
321 #[cfg(feature = "op")]
322 #[test]
323 fn test_shl() {
324 #[derive(Patch, Debug, PartialEq)]
325 struct Item {
326 field: u32,
327 other: String,
328 }
329
330 let item = Item {
331 field: 1,
332 other: String::from("hello"),
333 };
334 let patch = ItemPatch {
335 field: None,
336 other: Some(String::from("bye")),
337 };
338
339 assert_eq!(
340 item << patch,
341 Item {
342 field: 1,
343 other: String::from("bye")
344 }
345 );
346 }
347
348 #[cfg(all(feature = "op", feature = "merge"))]
349 #[test]
350 fn test_shl_on_patch() {
351 #[derive(Patch, Debug, PartialEq)]
352 struct Item {
353 field: u32,
354 other: String,
355 }
356
357 let mut item = Item {
358 field: 1,
359 other: String::from("hello"),
360 };
361 let patch = ItemPatch {
362 field: None,
363 other: Some(String::from("bye")),
364 };
365 let patch2 = ItemPatch {
366 field: Some(2),
367 other: None,
368 };
369
370 let new_patch = patch << patch2;
371
372 item.apply(new_patch);
373 assert_eq!(
374 item,
375 Item {
376 field: 2,
377 other: String::from("bye")
378 }
379 );
380 }
381
382 #[cfg(feature = "op")]
383 #[test]
384 fn test_add_patches() {
385 #[derive(Patch)]
386 #[patch(attribute(derive(Debug, PartialEq)))]
387 struct Item {
388 field: u32,
389 other: String,
390 }
391
392 let patch = ItemPatch {
393 field: Some(1),
394 other: None,
395 };
396 let patch2 = ItemPatch {
397 field: None,
398 other: Some(String::from("hello")),
399 };
400 let overall_patch = patch + patch2;
401 assert_eq!(
402 overall_patch,
403 ItemPatch {
404 field: Some(1),
405 other: Some(String::from("hello")),
406 }
407 );
408 }
409
410 #[cfg(feature = "op")]
411 #[test]
412 #[should_panic]
413 fn test_add_conflict_patches_panic() {
414 #[derive(Patch, Debug, PartialEq)]
415 struct Item {
416 field: u32,
417 }
418
419 let patch = ItemPatch { field: Some(1) };
420 let patch2 = ItemPatch { field: Some(2) };
421 let _overall_patch = patch + patch2;
422 }
423
424 #[cfg(feature = "merge")]
425 #[test]
426 fn test_merge() {
427 #[derive(Patch)]
428 #[patch(attribute(derive(PartialEq, Debug)))]
429 struct Item {
430 a: u32,
431 b: u32,
432 c: u32,
433 d: u32,
434 }
435
436 let patch = ItemPatch {
437 a: None,
438 b: Some(2),
439 c: Some(0),
440 d: None,
441 };
442 let patch2 = ItemPatch {
443 a: Some(1),
444 b: None,
445 c: Some(3),
446 d: None,
447 };
448
449 let merged_patch = patch.merge(patch2);
450 assert_eq!(
451 merged_patch,
452 ItemPatch {
453 a: Some(1),
454 b: Some(2),
455 c: Some(3),
456 d: None,
457 }
458 );
459 }
460
461 #[cfg(feature = "merge")]
462 #[test]
463 fn test_merge_nested() {
464 #[derive(Patch, PartialEq, Debug)]
465 #[patch(attribute(derive(PartialEq, Debug, Clone)))]
466 struct B {
467 c: u32,
468 d: u32,
469 e: u32,
470 f: u32,
471 }
472
473 #[derive(Patch)]
474 #[patch(attribute(derive(PartialEq, Debug)))]
475 struct A {
476 a: u32,
477 #[patch(name = "BPatch")]
478 b: B,
479 }
480
481 let patches = vec![
482 APatch {
483 a: Some(1),
484 b: Some(BPatch {
485 c: None,
486 d: Some(2),
487 e: Some(0),
488 f: None,
489 }),
490 },
491 APatch {
492 a: Some(0),
493 b: Some(BPatch {
494 c: Some(1),
495 d: None,
496 e: Some(3),
497 f: None,
498 }),
499 },
500 ];
501
502 let merged_patch = patches.into_iter().reduce(Merge::merge).unwrap();
503
504 assert_eq!(
505 merged_patch,
506 APatch {
507 a: Some(0),
508 b: Some(BPatch {
509 c: Some(1),
510 d: Some(2),
511 e: Some(3),
512 f: None,
513 }),
514 }
515 );
516 }
517}