Files
bass-foundry/plugins/rivet/core/tests/creative.rs
T
nvrl 15853e61ac
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
restructure
2026-11-05 23:58:00 +01:00

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);
}