Check and Windows preview / check (patina) (push) Successful in 2m20s
Check and Windows preview / check (rivet) (push) Successful in 1m38s
Check and Windows preview / previews (push) Successful in 1m6s
Check and Windows preview / windows (push) Successful in 1m50s
Independent plugin release / publish (push) Successful in 8s
Independent plugin release / plan (push) Successful in 7s
Independent plugin release / build (push) Successful in 2m21s
139 lines
4.8 KiB
Rust
139 lines
4.8 KiB
Rust
use rivet_core::*;
|
|
|
|
fn session() -> Session {
|
|
let mut s = Session {
|
|
source: Some(demo_motif()),
|
|
..Default::default()
|
|
};
|
|
s.regenerate().unwrap();
|
|
s
|
|
}
|
|
#[test]
|
|
fn moves_fork_and_restore_context_without_losing_siblings() {
|
|
let mut s = session();
|
|
s.pin_selected(0).unwrap();
|
|
let root = s.save_branch("Original").unwrap();
|
|
let original = s.composed_phrase().unwrap();
|
|
s.apply_move(CreativeMove::Thin, Some(1)).unwrap();
|
|
let thin = s.active_branch.unwrap();
|
|
let thinned = s.composed_phrase().unwrap();
|
|
assert_ne!(thinned, original);
|
|
assert_eq!(
|
|
&thinned.notes[..demo_motif().notes.len()],
|
|
demo_motif().notes.as_slice()
|
|
);
|
|
s.restore_branch(root).unwrap();
|
|
assert_eq!(s.composed_phrase().unwrap(), original);
|
|
assert_eq!(s.pins.len(), 1);
|
|
s.apply_move(CreativeMove::Lengthen, Some(2)).unwrap();
|
|
let long = s.active_branch.unwrap();
|
|
assert_ne!(thin, long);
|
|
assert_eq!(s.branches.len(), 3);
|
|
assert_eq!(
|
|
s.branches.iter().find(|b| b.id == thin).unwrap().parent,
|
|
Some(root)
|
|
);
|
|
assert_eq!(
|
|
s.branches.iter().find(|b| b.id == long).unwrap().parent,
|
|
Some(root)
|
|
);
|
|
s.restore_branch(thin).unwrap();
|
|
assert_eq!(s.composed_phrase().unwrap(), thinned);
|
|
assert!(s.remove_branch(root).is_err());
|
|
assert_eq!(Session::from_json(&s.to_json().unwrap()).unwrap(), s);
|
|
}
|
|
#[test]
|
|
fn gesture_recall_and_cross_project_library_preserve_performance() {
|
|
let mut s = session();
|
|
s.performance.mode = RoleMode::CallResponse;
|
|
s.performance.voices[1].controller.enabled = true;
|
|
s.performance.voices[1].controller.cc = 20;
|
|
s.performance.voices[1].controller.shape(2);
|
|
let id = s.save_gesture("Floating answer", Some(1)).unwrap();
|
|
let saved = s.gestures[0].clone();
|
|
let bytes = s.export_gesture_library().unwrap();
|
|
let mut other = Session {
|
|
source: Some(demo_motif()),
|
|
harmony: Harmony::progression(2, Scale::Major),
|
|
..Default::default()
|
|
};
|
|
other.save_gesture("Existing", None).unwrap();
|
|
let context = other.harmony.clone();
|
|
other
|
|
.import_gesture_library(read_gesture_library(&bytes).unwrap())
|
|
.unwrap();
|
|
assert_eq!(other.gestures.len(), 2);
|
|
assert_ne!(other.gestures[0].id, other.gestures[1].id);
|
|
let imported = other.gestures[1].id;
|
|
other.recall_gesture(imported).unwrap();
|
|
assert_eq!(other.source, Some(saved.phrase));
|
|
assert_eq!(other.performance, saved.performance);
|
|
assert_eq!(other.harmony, context);
|
|
assert!(other.candidates.is_empty());
|
|
assert!(other.pins.is_empty());
|
|
assert!(s.gestures.iter().any(|g| g.id == id));
|
|
}
|
|
#[test]
|
|
fn blocked_moves_and_full_histories_are_atomic() {
|
|
let mut s = session();
|
|
s.settings.preserve_rhythm = true;
|
|
let before = s.clone();
|
|
assert!(s.apply_move(CreativeMove::Thin, None).is_err());
|
|
assert_eq!(s, before);
|
|
s.settings.preserve_rhythm = false;
|
|
for i in 0..MAX_BRANCHES {
|
|
s.save_branch(&format!("Idea {i}")).unwrap();
|
|
}
|
|
let before = s.clone();
|
|
assert!(s.apply_move(CreativeMove::Thin, Some(1)).is_err());
|
|
assert_eq!(s, before);
|
|
let leaf = s.active_branch.unwrap();
|
|
s.remove_branch(leaf).unwrap();
|
|
assert_eq!(s.branches.len(), MAX_BRANCHES - 1);
|
|
}
|
|
#[test]
|
|
fn malformed_ancestry_libraries_and_version_two_state_are_handled() {
|
|
let mut s = session();
|
|
let id = s.save_branch("Root").unwrap();
|
|
s.branches[0].parent = Some(id);
|
|
assert!(s.validate().is_err());
|
|
assert!(read_gesture_library(br#"{"version":99,"gestures":[]}"#).is_err());
|
|
let old = session();
|
|
let mut value = serde_json::to_value(&old).unwrap();
|
|
value["version"] = 2.into();
|
|
for key in [
|
|
"performance",
|
|
"gestures",
|
|
"branches",
|
|
"active_branch",
|
|
"next_id",
|
|
] {
|
|
value.as_object_mut().unwrap().remove(key);
|
|
}
|
|
let restored = Session::from_json(&serde_json::to_vec(&value).unwrap()).unwrap();
|
|
assert_eq!(restored.version, 3);
|
|
assert_eq!(restored.source, old.source);
|
|
assert_eq!(restored.performance, PerformanceSettings::default());
|
|
}
|
|
|
|
#[test]
|
|
fn delay_moves_adjacent_notes_together_and_rejects_protected_collisions() {
|
|
let mut s = session();
|
|
let make_note = |start| Note {
|
|
start,
|
|
duration: PPQ,
|
|
pitch: 60,
|
|
velocity: 90,
|
|
..Default::default()
|
|
};
|
|
s.candidates[s.selected].phrase.notes = vec![make_note(SECTION), make_note(SECTION + PPQ)];
|
|
s.apply_move(CreativeMove::Delay, Some(1)).unwrap();
|
|
let moved = s.composed_phrase().unwrap();
|
|
assert_eq!(moved.notes[0].start, SECTION + PPQ / 4);
|
|
assert_eq!(moved.notes[1].start, SECTION + PPQ + PPQ / 4);
|
|
s.candidates[0].phrase.notes[1].rhythm_locked = true;
|
|
let before = s.clone();
|
|
assert!(s.apply_move(CreativeMove::Delay, Some(1)).is_err());
|
|
assert_eq!(s, before);
|
|
}
|