use muon::adapter::Json;
use muon::helper::QuasiObserver;
use muon::observe::{ObserveExt, SerializeObserverExt};
use muon::{Observe, observe};
use muon_test_utils::*;
use serde::Serialize;
use serde_json::json;
#[derive(Serialize, Debug, PartialEq, Observe)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
Point,
Origin,
}
#[test]
fn unit_variant_no_change() {
let mut s = Shape::Point;
let Json(mutation) = observe!(s => {}).unwrap();
assert_eq!(mutation, None);
}
#[test]
fn unit_variant_change_to_unit() {
let mut s = Shape::Point;
let Json(mutation) = observe!(s => {
*s = Shape::Origin;
})
.unwrap();
assert_eq!(mutation, Some(replace!(_, json!("Origin"))));
}
#[test]
fn unit_to_field_variant() {
let mut s = Shape::Point;
let Json(mutation) = observe!(s => {
*s = Shape::Circle { radius: 5.0 };
})
.unwrap();
assert_eq!(mutation, Some(replace!(_, json!({"Circle": {"radius": 5.0}}))));
}
#[test]
fn field_to_unit_variant() {
let mut s = Shape::Circle { radius: 3.0 };
let Json(mutation) = observe!(s => {
*s = Shape::Point;
})
.unwrap();
assert_eq!(mutation, Some(replace!(_, json!("Point"))));
}
#[test]
fn field_variant_inner_mutation() {
let mut s = Shape::Rectangle {
width: 10.0,
height: 20.0,
};
let mut ob = s.__observe();
if let Shape::Rectangle { width, .. } = ob.untracked_mut() {
*width = 5.0;
}
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(replace!(Rectangle.width, json!(5.0))));
}
#[test]
fn field_variant_multiple_inner_mutations() {
let mut s = Shape::Rectangle {
width: 10.0,
height: 20.0,
};
let mut ob = s.__observe();
if let Shape::Rectangle { width, height } = ob.untracked_mut() {
*width = 15.0;
*height = 25.0;
}
let Json(mutation) = ob.flush().unwrap();
assert_eq!(
mutation,
Some(replace!(_, json!({"Rectangle": {"width": 15.0, "height": 25.0}})))
);
}
#[test]
fn field_variant_no_change() {
let mut s = Shape::Circle { radius: 3.0 };
let mut ob = s.__observe();
if let Shape::Circle { radius } = ob.untracked_ref() {
let _ = *radius;
}
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, None);
}
#[test]
fn field_variant_deref_mut_replace() {
let mut s = Shape::Circle { radius: 3.0 };
let Json(mutation) = observe!(s => {
*s = Shape::Circle { radius: 10.0 };
})
.unwrap();
assert_eq!(mutation, Some(replace!(_, json!({"Circle": {"radius": 10.0}}))));
}
#[derive(Serialize, Observe)]
#[serde(rename_all = "snake_case")]
enum Action {
DoSomething { value: i32, bar: i32 },
DoNothing,
}
#[test]
fn enum_rename_all_variant() {
let mut a = Action::DoNothing;
let Json(mutation) = observe!(a => {
*a = Action::DoSomething { value: 42, bar: 0 };
})
.unwrap();
assert_eq!(
mutation,
Some(replace!(_, json!({"do_something": {"value": 42, "bar": 0}})))
);
}
#[test]
fn enum_rename_all_inner_mutation() {
let mut a = Action::DoSomething { value: 1, bar: 0 };
let mut ob = a.__observe();
if let Action::DoSomething { value, .. } = ob.untracked_mut() {
*value = 99;
}
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(replace!(do_something.value, json!(99))));
}
#[test]
fn flush_resets_state() {
let mut s = Shape::Point;
let Json(mutation1) = observe!(s => {
*s = Shape::Origin;
})
.unwrap();
assert!(mutation1.is_some());
let Json(mutation2) = observe!(s => {}).unwrap();
assert!(mutation2.is_none());
}
#[test]
fn flush_resets_field_variant() {
let mut s = Shape::Circle { radius: 3.0 };
let mut ob = s.__observe();
if let Shape::Circle { radius } = ob.untracked_mut() {
*radius = 5.0;
}
let Json(mutation1) = ob.flush().unwrap();
assert!(mutation1.is_some());
let Json(mutation2) = ob.flush().unwrap();
assert!(mutation2.is_none());
}
#[derive(Serialize, Observe)]
#[allow(dead_code)]
enum Color {
Red,
Green,
Blue,
}
#[test]
fn all_unit_enum_no_change() {
let mut c = Color::Red;
let Json(mutation) = observe!(c => {}).unwrap();
assert_eq!(mutation, None);
}
#[test]
fn all_unit_enum_change() {
let mut c = Color::Red;
let Json(mutation) = observe!(c => {
*c = Color::Blue;
})
.unwrap();
assert_eq!(mutation, Some(replace!(_, json!("Blue"))));
}
#[derive(Serialize, Observe)]
#[serde(tag = "type")]
enum Event {
Click { x: i32, y: i32 },
Scroll { delta: i32 },
}
#[test]
fn internal_tag_inner_mutation() {
let mut e = Event::Click { x: 10, y: 20 };
let mut ob = e.__observe();
if let Event::Click { x, .. } = ob.untracked_mut() {
*x = 50;
}
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(replace!(x, json!(50))));
}
#[test]
fn internal_tag_variant_change() {
let mut e = Event::Click { x: 10, y: 20 };
let Json(mutation) = observe!(e => {
*e = Event::Scroll { delta: 5 };
})
.unwrap();
assert_eq!(mutation, Some(replace!(_, json!({"type": "Scroll", "delta": 5}))));
}
#[derive(Serialize, Observe)]
#[allow(dead_code)]
enum Container {
Items { list: Vec<i32> },
Empty,
}
#[test]
fn field_variant_vec_append() {
let mut c = Container::Items { list: vec![1, 2, 3] };
let mut ob = c.__observe();
if let Container::Items { list } = ob.untracked_mut() {
list.push(4);
}
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(append!(Items.list, json!([4]))));
}
#[derive(Serialize, Observe)]
enum Wrapper {
Single(i32),
Pair(i32, String),
}
#[test]
fn tuple_variant_single_field() {
let mut w = Wrapper::Single(10);
let mut ob = w.__observe();
if let Wrapper::Single(v) = ob.untracked_mut() {
*v = 20;
}
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(replace!(Single, json!(20))));
}
#[test]
fn tuple_variant_multi_field() {
let mut w = Wrapper::Pair(1, "hello".into());
let mut ob = w.__observe();
if let Wrapper::Pair(n, s) = ob.untracked_mut() {
*n = 42;
s.push('!');
}
let Json(mutation) = ob.flush().unwrap();
assert_eq!(
mutation,
Some(batch!(Pair, replace!(0, json!(42)), append!(1, json!("!"))))
);
}