mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-10-06 22:04:06 +00:00
fixes
This commit is contained in:
@@ -68,7 +68,12 @@ mod tests {
|
|||||||
fn test_metadata_applies_to_selected_track() {
|
fn test_metadata_applies_to_selected_track() {
|
||||||
let mut fx = Fixture::default();
|
let mut fx = Fixture::default();
|
||||||
let data = std::fs::read("data/with_tracks.gpx").unwrap();
|
let data = std::fs::read("data/with_tracks.gpx").unwrap();
|
||||||
crate::Load { data: &data }.apply(&mut fx.state()).unwrap();
|
crate::Load {
|
||||||
|
data: &data,
|
||||||
|
name: "file",
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
let file = fx.files.values().next().unwrap().clone();
|
let file = fx.files.values().next().unwrap().clone();
|
||||||
fx.selection = Selection::Track {
|
fx.selection = Selection::Track {
|
||||||
file_id: file.id,
|
file_id: file.id,
|
||||||
|
|||||||
@@ -41,7 +41,12 @@ mod tests {
|
|||||||
fn test_style_applies_to_all_tracks_of_selected_file_and_keeps_unset_fields() {
|
fn test_style_applies_to_all_tracks_of_selected_file_and_keeps_unset_fields() {
|
||||||
let mut fx = Fixture::default();
|
let mut fx = Fixture::default();
|
||||||
let data = std::fs::read("data/with_style.gpx").unwrap();
|
let data = std::fs::read("data/with_style.gpx").unwrap();
|
||||||
crate::Load { data: &data }.apply(&mut fx.state()).unwrap();
|
crate::Load {
|
||||||
|
data: &data,
|
||||||
|
name: "file",
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
let id = *fx.files.keys().next().unwrap();
|
let id = *fx.files.keys().next().unwrap();
|
||||||
let before = fx.files[&id].clone();
|
let before = fx.files[&id].clone();
|
||||||
assert!(!before.trk.is_empty());
|
assert!(!before.trk.is_empty());
|
||||||
|
|||||||
@@ -98,7 +98,12 @@ mod tests {
|
|||||||
fn loaded() -> (Fixture, FileId) {
|
fn loaded() -> (Fixture, FileId) {
|
||||||
let mut fx = Fixture::default();
|
let mut fx = Fixture::default();
|
||||||
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
||||||
Load { data: &data }.apply(&mut fx.state()).unwrap();
|
Load {
|
||||||
|
data: &data,
|
||||||
|
name: "file",
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
let id = fx.order.0[0];
|
let id = fx.order.0[0];
|
||||||
(fx, id)
|
(fx, id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,7 +211,12 @@ mod tests {
|
|||||||
fn loaded() -> (Fixture, FileId) {
|
fn loaded() -> (Fixture, FileId) {
|
||||||
let mut fx = Fixture::default();
|
let mut fx = Fixture::default();
|
||||||
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
||||||
Load { data: &data }.apply(&mut fx.state()).unwrap();
|
Load {
|
||||||
|
data: &data,
|
||||||
|
name: "file",
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
let id = fx.order.0[0];
|
let id = fx.order.0[0];
|
||||||
(fx, id)
|
(fx, id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,18 @@ use crate::{Apply, CommandError, State, parse, produce};
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Load<'a> {
|
pub struct Load<'a> {
|
||||||
pub data: &'a [u8],
|
pub data: &'a [u8],
|
||||||
|
/// Name of the file when the data has none (typically the name of the file on disk, without
|
||||||
|
/// its extension).
|
||||||
|
pub name: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Apply for Load<'_> {
|
impl Apply for Load<'_> {
|
||||||
fn apply(self, state: &mut State) -> Result<(), CommandError> {
|
fn apply(self, state: &mut State) -> Result<(), CommandError> {
|
||||||
let file = parse(self.data).map_err(|err| CommandError::InvalidData(err.to_string()))?;
|
let mut file =
|
||||||
|
parse(self.data).map_err(|err| CommandError::InvalidData(err.to_string()))?;
|
||||||
|
if file.info.name.trim().is_empty() {
|
||||||
|
file.info.name = self.name.to_owned();
|
||||||
|
}
|
||||||
produce(state, |_| vec![file]);
|
produce(state, |_| vec![file]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -23,7 +30,14 @@ mod tests {
|
|||||||
fn test_load() {
|
fn test_load() {
|
||||||
let mut fx = Fixture::default();
|
let mut fx = Fixture::default();
|
||||||
let data = std::fs::read("data/with_tracks.gpx").unwrap();
|
let data = std::fs::read("data/with_tracks.gpx").unwrap();
|
||||||
assert!(Load { data: &data }.apply(&mut fx.state()).is_ok());
|
assert!(
|
||||||
|
Load {
|
||||||
|
data: &data,
|
||||||
|
name: "file",
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.is_ok()
|
||||||
|
);
|
||||||
assert_eq!(fx.files.len(), 1);
|
assert_eq!(fx.files.len(), 1);
|
||||||
let file = fx.files.values().next().unwrap();
|
let file = fx.files.values().next().unwrap();
|
||||||
assert!(!file.trk.is_empty());
|
assert!(!file.trk.is_empty());
|
||||||
@@ -38,6 +52,7 @@ mod tests {
|
|||||||
|
|
||||||
let result = Load {
|
let result = Load {
|
||||||
data: b"<gpx><trk></gpx>",
|
data: b"<gpx><trk></gpx>",
|
||||||
|
name: "file",
|
||||||
}
|
}
|
||||||
.apply(&mut fx.state());
|
.apply(&mut fx.state());
|
||||||
assert!(matches!(result, Err(CommandError::InvalidData(_))));
|
assert!(matches!(result, Err(CommandError::InvalidData(_))));
|
||||||
@@ -45,4 +60,29 @@ mod tests {
|
|||||||
assert_eq!(fx.order.0.len(), 1);
|
assert_eq!(fx.order.0.len(), 1);
|
||||||
assert_eq!(fx.selected_files(), selected);
|
assert_eq!(fx.selected_files(), selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_with_name(data: &[u8]) -> String {
|
||||||
|
let mut fx = Fixture::default();
|
||||||
|
Load {
|
||||||
|
data,
|
||||||
|
name: "from disk",
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
|
fx.files.values().next().unwrap().info.name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_keeps_the_name_of_the_file() {
|
||||||
|
let data = br#"<gpx version="1.1"><metadata><name>in the file</name></metadata></gpx>"#;
|
||||||
|
assert_eq!(load_with_name(data), "in the file");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_without_name_uses_the_given_name() {
|
||||||
|
let without = br#"<gpx version="1.1"><trk><trkseg></trkseg></trk></gpx>"#;
|
||||||
|
assert_eq!(load_with_name(without), "from disk");
|
||||||
|
let empty = br#"<gpx version="1.1"><metadata><name> </name></metadata></gpx>"#;
|
||||||
|
assert_eq!(load_with_name(empty), "from disk");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,12 @@ mod tests {
|
|||||||
fn loaded() -> (Fixture, FileId) {
|
fn loaded() -> (Fixture, FileId) {
|
||||||
let mut fx = Fixture::default();
|
let mut fx = Fixture::default();
|
||||||
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
||||||
Load { data: &data }.apply(&mut fx.state()).unwrap();
|
Load {
|
||||||
|
data: &data,
|
||||||
|
name: "file",
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
let id = fx.order.0[0];
|
let id = fx.order.0[0];
|
||||||
let trk = &fx.files[&id].trk[0];
|
let trk = &fx.files[&id].trk[0];
|
||||||
fx.selection = Selection::TrackSegment {
|
fx.selection = Selection::TrackSegment {
|
||||||
@@ -282,7 +287,12 @@ mod tests {
|
|||||||
fn test_splice_on_multiple_files_uses_last_in_file_order() {
|
fn test_splice_on_multiple_files_uses_last_in_file_order() {
|
||||||
let (mut fx, first) = loaded();
|
let (mut fx, first) = loaded();
|
||||||
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
||||||
Load { data: &data }.apply(&mut fx.state()).unwrap();
|
Load {
|
||||||
|
data: &data,
|
||||||
|
name: "file",
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
let second = fx.order.0[1];
|
let second = fx.order.0[1];
|
||||||
fx.selection = Selection::File {
|
fx.selection = Selection::File {
|
||||||
file_ids: HashSet::from([second, first]),
|
file_ids: HashSet::from([second, first]),
|
||||||
|
|||||||
@@ -73,7 +73,12 @@ mod tests {
|
|||||||
fn loaded() -> (Fixture, FileId) {
|
fn loaded() -> (Fixture, FileId) {
|
||||||
let mut fx = Fixture::default();
|
let mut fx = Fixture::default();
|
||||||
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
||||||
Load { data: &data }.apply(&mut fx.state()).unwrap();
|
Load {
|
||||||
|
data: &data,
|
||||||
|
name: "file",
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
let id = fx.order.0[0];
|
let id = fx.order.0[0];
|
||||||
(fx, id)
|
(fx, id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,12 @@ mod tests {
|
|||||||
fn test_structure_of_a_file() {
|
fn test_structure_of_a_file() {
|
||||||
let mut fx = Fixture::default();
|
let mut fx = Fixture::default();
|
||||||
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
||||||
Load { data: &data }.apply(&mut fx.state()).unwrap();
|
Load {
|
||||||
|
data: &data,
|
||||||
|
name: "file",
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
let file = &fx.files[&fx.order.0[0]];
|
let file = &fx.files[&fx.order.0[0]];
|
||||||
let node = FileStructure::new(file);
|
let node = FileStructure::new(file);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -41,8 +41,18 @@ mod tests {
|
|||||||
fn test_only_files_of_the_diff_are_recomputed() {
|
fn test_only_files_of_the_diff_are_recomputed() {
|
||||||
let mut fx = Fixture::default();
|
let mut fx = Fixture::default();
|
||||||
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
||||||
Load { data: &data }.apply(&mut fx.state()).unwrap();
|
Load {
|
||||||
Load { data: &data }.apply(&mut fx.state()).unwrap();
|
data: &data,
|
||||||
|
name: "file",
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
|
Load {
|
||||||
|
data: &data,
|
||||||
|
name: "file",
|
||||||
|
}
|
||||||
|
.apply(&mut fx.state())
|
||||||
|
.unwrap();
|
||||||
let (a, b) = (fx.order.0[0], fx.order.0[1]);
|
let (a, b) = (fx.order.0[0], fx.order.0[1]);
|
||||||
|
|
||||||
let mut cache = FileStructureCache::default();
|
let mut cache = FileStructureCache::default();
|
||||||
|
|||||||
@@ -164,7 +164,13 @@ mod tests {
|
|||||||
|
|
||||||
fn load(engine: &mut Engine, path: &str) -> bool {
|
fn load(engine: &mut Engine, path: &str) -> bool {
|
||||||
let data = std::fs::read(path).unwrap();
|
let data = std::fs::read(path).unwrap();
|
||||||
edit(engine, Command::Load(Load { data: &data }))
|
edit(
|
||||||
|
engine,
|
||||||
|
Command::Load(Load {
|
||||||
|
data: &data,
|
||||||
|
name: "file",
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn selected(engine: &Engine) -> Vec<FileId> {
|
fn selected(engine: &Engine) -> Vec<FileId> {
|
||||||
@@ -213,7 +219,8 @@ mod tests {
|
|||||||
assert!(!edit(
|
assert!(!edit(
|
||||||
&mut engine,
|
&mut engine,
|
||||||
Command::Load(Load {
|
Command::Load(Load {
|
||||||
data: b"<gpx><trk></gpx>"
|
data: b"<gpx><trk></gpx>",
|
||||||
|
name: "file",
|
||||||
})
|
})
|
||||||
));
|
));
|
||||||
assert!(engine.stack.current().is_none());
|
assert!(engine.stack.current().is_none());
|
||||||
|
|||||||
@@ -149,9 +149,10 @@ pub fn new_file(name: &str) -> bool {
|
|||||||
edit(Command::New(engine::New { name }))
|
edit(Command::New(engine::New { name }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `name`: the name of the file when the data has none (the name on disk, without extension).
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn load_file(data: &[u8]) -> bool {
|
pub fn load_file(data: &[u8], name: &str) -> bool {
|
||||||
edit(Command::Load(engine::Load { data }))
|
edit(Command::Load(engine::Load { data, name }))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
|||||||
@@ -85,7 +85,11 @@ export class SortableFileList {
|
|||||||
this._unsubscribes.push(
|
this._unsubscribes.push(
|
||||||
engine.selection.subscribe(() => tick().then(() => this.updateFromSelection()))
|
engine.selection.subscribe(() => tick().then(() => this.updateFromSelection()))
|
||||||
);
|
);
|
||||||
this._unsubscribes.push(engine.order.subscribe(() => this.updateFromFileOrder()));
|
// after the elements are rendered: sorting a list that does not have the new files yet
|
||||||
|
// would put them at the beginning
|
||||||
|
this._unsubscribes.push(
|
||||||
|
engine.order.subscribe(() => tick().then(() => this.updateFromFileOrder()))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The node of a child of the list. */
|
/** The node of a child of the list. */
|
||||||
|
|||||||
@@ -147,8 +147,9 @@ class Engine {
|
|||||||
return this.run((w) => w.new_file(name));
|
return this.run((w) => w.new_file(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
loadFile(data: Uint8Array) {
|
/** `name` is the name of the file when the data has none (the name on disk, without extension). */
|
||||||
return this.run((w) => w.load_file(data));
|
loadFile(data: Uint8Array, name: string) {
|
||||||
|
return this.run((w) => w.load_file(data, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
duplicate() {
|
duplicate() {
|
||||||
|
|||||||
Reference in New Issue
Block a user