| ... | @@ -1173,10 +1173,14 @@ fn a_share_notebook_names_its_files_from_the_share_s_top() { | ... | @@ -1173,10 +1173,14 @@ fn a_share_notebook_names_its_files_from_the_share_s_top() { |
| 1173 | ); | 1173 | ); |
| 1174 | } | 1174 | } |
| 1175 | | 1175 | |
| 1176 | /// A notebook copy with its library, and a section of it open for editing. | 1176 | /// A notebook copy with its library, and a section of it open for editing. Working |
| 1177 | fn notebook_open(path: &str) -> (tempfile::TempDir, PathBuf, Arc<Library>, Section) { | 1177 | /// `offline` from the start, no sync step can publish the section's edits. |
| | 1178 | fn notebook_open(path: &str, offline: bool) -> (tempfile::TempDir, PathBuf, Arc<Library>, Section) { |
| 1178 | let (directory, root) = copy("m6/native-features-01/notebook"); | 1179 | let (directory, root) = copy("m6/native-features-01/notebook"); |
| 1179 | let library = Arc::new(Library::open(&root, &directory.path().join("cache"), true).unwrap()); | 1180 | let library = Arc::new(Library::open(&root, &directory.path().join("cache"), true).unwrap()); |
| | 1181 | if offline { |
| | 1182 | sb_library_set_offline(&library, true); |
| | 1183 | } |
| 1180 | let section = open(&library, path); | 1184 | let section = open(&library, path); |
| 1181 | (directory, root, library, section) | 1185 | (directory, root, library, section) |
| 1182 | } | 1186 | } |
| ... | @@ -1195,7 +1199,7 @@ fn eventually(mut ready: impl FnMut() -> bool) -> bool { | ... | @@ -1195,7 +1199,7 @@ fn eventually(mut ready: impl FnMut() -> bool) -> bool { |
| 1195 | | 1199 | |
| 1196 | #[test] | 1200 | #[test] |
| 1197 | fn sync_status_lists_every_section_and_work_offline_holds_edits_until_sync_now() { | 1201 | fn sync_status_lists_every_section_and_work_offline_holds_edits_until_sync_now() { |
| 1198 | let (_directory, root, library, section) = notebook_open("Features.one"); | 1202 | let (_directory, root, library, section) = notebook_open("Features.one", false); |
| 1199 | // Every readable section, the open one's from its session. | 1203 | // Every readable section, the open one's from its session. |
| 1200 | assert!(eventually(|| { | 1204 | assert!(eventually(|| { |
| 1201 | let status = library.sync_status(); | 1205 | let status = library.sync_status(); |
| ... | @@ -1499,8 +1503,7 @@ fn the_accent_pen_and_shapes_draw_as_the_desktop_and_a_cancelled_sweep_stores_no | ... | @@ -1499,8 +1503,7 @@ fn the_accent_pen_and_shapes_draw_as_the_desktop_and_a_cancelled_sweep_stores_no |
| 1499 | /// Queues an offline edit to Features.one and closes its session, leaving the edit to the | 1503 | /// Queues an offline edit to Features.one and closes its session, leaving the edit to the |
| 1500 | /// background; the replicas in the cache, and the text edited in. | 1504 | /// background; the replicas in the cache, and the text edited in. |
| 1501 | fn unpublished_edit() -> (tempfile::TempDir, PathBuf, Arc<Library>, ExGuid) { | 1505 | fn unpublished_edit() -> (tempfile::TempDir, PathBuf, Arc<Library>, ExGuid) { |
| 1502 | let (directory, root, library, section) = notebook_open("Features.one"); | 1506 | let (directory, root, library, section) = notebook_open("Features.one", true); |
| 1503 | sb_library_set_offline(&library, true); | | |
| 1504 | let mut canvas = canvas(&section, "Paragraph controls"); | 1507 | let mut canvas = canvas(&section, "Paragraph controls"); |
| 1505 | focus(&mut canvas, "Collapsed parent"); | 1508 | focus(&mut canvas, "Collapsed parent"); |
| 1506 | canvas.insert("Unpublished ".into()).unwrap(); | 1509 | canvas.insert("Unpublished ".into()).unwrap(); |
| ... | @@ -1699,34 +1702,38 @@ fn levels(section: &Section) -> Vec<(ExGuid, u32)> { | ... | @@ -1699,34 +1702,38 @@ fn levels(section: &Section) -> Vec<(ExGuid, u32)> { |
| 1699 | | 1702 | |
| 1700 | #[test] | 1703 | #[test] |
| 1701 | fn pages_drag_indent_and_undo_as_one_edit_each() { | 1704 | fn pages_drag_indent_and_undo_as_one_edit_each() { |
| 1702 | let (_directory, _root, _library, section) = notebook_open("Features.one"); | 1705 | let (_directory, _root, _library, section) = notebook_open("Features.one", true); |
| | 1706 | let queued = || { |
| | 1707 | section.shared.section.written().unwrap(); |
| | 1708 | section.shared.section.pending().unwrap().len() |
| | 1709 | }; |
| 1703 | let before = levels(&section); | 1710 | let before = levels(&section); |
| 1704 | assert!(before.len() > 2); | 1711 | assert!(before.len() > 2); |
| 1705 | let last = before.last().unwrap().0; | 1712 | let last = before.last().unwrap().0; |
| 1706 | let mut dragged = before.clone(); | 1713 | let mut dragged = before.clone(); |
| 1707 | let moved = dragged.pop().unwrap(); | 1714 | let moved = dragged.pop().unwrap(); |
| 1708 | dragged.insert(0, moved); | 1715 | dragged.insert(0, moved); |
| 1709 | let revisions = section.shared.section.pending().unwrap().len(); | 1716 | let mut edits = queued(); |
| 1710 | assert!(section.arrange(&dragged, &[last]).unwrap()); | 1717 | let mut arrange = |order: &[(ExGuid, u32)], moved: ExGuid| { |
| 1711 | assert_eq!(levels(&section), dragged); | 1718 | assert!(section.arrange(order, &[moved]).unwrap()); |
| 1712 | assert_eq!( | 1719 | assert_eq!(levels(&section), order); |
| 1713 | section.shared.section.pending().unwrap().len(), | 1720 | edits += 1; |
| 1714 | revisions + 1 | 1721 | assert_eq!(queued(), edits); |
| 1715 | ); | 1722 | }; |
| | 1723 | arrange(&dragged, last); |
| 1716 | let second = dragged[1].0; | 1724 | let second = dragged[1].0; |
| 1717 | let mut indented = dragged.clone(); | 1725 | let mut indented = dragged.clone(); |
| 1718 | indented[1].1 = 2; | 1726 | indented[1].1 = 2; |
| 1719 | assert!(section.arrange(&indented, &[second]).unwrap()); | 1727 | arrange(&indented, second); |
| 1720 | assert_eq!(levels(&section), indented); | 1728 | arrange(&dragged, second); |
| 1721 | assert!(section.arrange(&dragged, &[second]).unwrap()); | 1729 | arrange(&before, last); |
| 1722 | assert!(section.arrange(&before, &[last]).unwrap()); | | |
| 1723 | assert_eq!(levels(&section), before); | | |
| 1724 | assert!(!section.arrange(&before, &[ExGuid::default()]).unwrap()); | 1730 | assert!(!section.arrange(&before, &[ExGuid::default()]).unwrap()); |
| | 1731 | assert_eq!(queued(), edits); |
| 1725 | } | 1732 | } |
| 1726 | | 1733 | |
| 1727 | #[test] | 1734 | #[test] |
| 1728 | fn a_page_moves_to_another_section_and_back_where_it_was() { | 1735 | fn a_page_moves_to_another_section_and_back_where_it_was() { |
| 1729 | let (_directory, root, library, features) = notebook_open("Features.one"); | 1736 | let (_directory, root, library, features) = notebook_open("Features.one", false); |
| 1730 | let before = levels(&features); | 1737 | let before = levels(&features); |
| 1731 | let (space, level) = before[1]; | 1738 | let (space, level) = before[1]; |
| 1732 | let title = features.shared.section.page(space).unwrap().title; | 1739 | let title = features.shared.section.page(space).unwrap().title; |
| ... | @@ -1785,7 +1792,7 @@ fn a_page_moves_to_another_section_and_back_where_it_was() { | ... | @@ -1785,7 +1792,7 @@ fn a_page_moves_to_another_section_and_back_where_it_was() { |
| 1785 | fn a_page_edited_while_it_moves_stays_with_its_edit() { | 1792 | fn a_page_edited_while_it_moves_stays_with_its_edit() { |
| 1786 | library::sb_set_coordinator(coordinator); | 1793 | library::sb_set_coordinator(coordinator); |
| 1787 | for edited in [true, false] { | 1794 | for edited in [true, false] { |
| 1788 | let (_directory, root, library, features) = notebook_open("Features.one"); | 1795 | let (_directory, root, library, features) = notebook_open("Features.one", false); |
| 1789 | assert!(eventually(|| { | 1796 | assert!(eventually(|| { |
| 1790 | let status = library.sync_status(); | 1797 | let status = library.sync_status(); |
| 1791 | !status.is_empty() | 1798 | !status.is_empty() |
| ... | @@ -1861,7 +1868,7 @@ fn a_page_its_section_cannot_retire_stays_beside_its_copy() { | ... | @@ -1861,7 +1868,7 @@ fn a_page_its_section_cannot_retire_stays_beside_its_copy() { |
| 1861 | let _exclusive = vfs::EXCLUSIVE | 1868 | let _exclusive = vfs::EXCLUSIVE |
| 1862 | .lock() | 1869 | .lock() |
| 1863 | .unwrap_or_else(std::sync::PoisonError::into_inner); | 1870 | .unwrap_or_else(std::sync::PoisonError::into_inner); |
| 1864 | let (directory, root, library, empty) = notebook_open("Empty.one"); | 1871 | let (directory, root, library, empty) = notebook_open("Empty.one", false); |
| 1865 | let features = open(&library, "Features.one"); | 1872 | let features = open(&library, "Features.one"); |
| 1866 | let space = space(&features, "Task controls"); | 1873 | let space = space(&features, "Task controls"); |
| 1867 | drop(features); | 1874 | drop(features); |
| ... | @@ -1908,7 +1915,7 @@ fn a_page_its_section_cannot_retire_stays_beside_its_copy() { | ... | @@ -1908,7 +1915,7 @@ fn a_page_its_section_cannot_retire_stays_beside_its_copy() { |
| 1908 | /// A page the section it moves to refuses stays where it was, and the move fails. | 1915 | /// A page the section it moves to refuses stays where it was, and the move fails. |
| 1909 | #[test] | 1916 | #[test] |
| 1910 | fn a_page_the_other_section_refuses_stays() { | 1917 | fn a_page_the_other_section_refuses_stays() { |
| 1911 | let (_directory, _root, library, features) = notebook_open("Features.one"); | 1918 | let (_directory, _root, library, features) = notebook_open("Features.one", false); |
| 1912 | let before = levels(&features); | 1919 | let before = levels(&features); |
| 1913 | let (space, _) = before[1]; | 1920 | let (space, _) = before[1]; |
| 1914 | let page = features.shared.section.page(space).unwrap(); | 1921 | let page = features.shared.section.page(space).unwrap(); |
| ... | @@ -1938,7 +1945,7 @@ fn a_page_the_other_section_refuses_stays() { | ... | @@ -1938,7 +1945,7 @@ fn a_page_the_other_section_refuses_stays() { |
| 1938 | | 1945 | |
| 1939 | #[test] | 1946 | #[test] |
| 1940 | fn a_sections_last_page_moving_leaves_a_page_that_undo_takes_out() { | 1947 | fn a_sections_last_page_moving_leaves_a_page_that_undo_takes_out() { |
| 1941 | let (_directory, _root, library, features) = notebook_open("Features.one"); | 1948 | let (_directory, _root, library, features) = notebook_open("Features.one", false); |
| 1942 | let date = ["Thursday, October 1, 2026", "9:02 AM"]; | 1949 | let date = ["Thursday, October 1, 2026", "9:02 AM"]; |
| 1943 | let page = features.new_page(None, date[0], date[1]).unwrap(); | 1950 | let page = features.new_page(None, date[0], date[1]).unwrap(); |
| 1944 | let arrived: ExGuid = library | 1951 | let arrived: ExGuid = library |
| ... | @@ -1989,7 +1996,7 @@ fn a_sections_last_page_moving_leaves_a_page_that_undo_takes_out() { | ... | @@ -1989,7 +1996,7 @@ fn a_sections_last_page_moving_leaves_a_page_that_undo_takes_out() { |
| 1989 | | 1996 | |
| 1990 | #[test] | 1997 | #[test] |
| 1991 | fn sections_reorder_and_move_between_groups_and_back() { | 1998 | fn sections_reorder_and_move_between_groups_and_back() { |
| 1992 | let (_directory, root, library, features) = notebook_open("Features.one"); | 1999 | let (_directory, root, library, features) = notebook_open("Features.one", false); |
| 1993 | drop(features); | 2000 | drop(features); |
| 1994 | let top = |library: &Library| -> Vec<String> { | 2001 | let top = |library: &Library| -> Vec<String> { |
| 1995 | let tabs = library.tabs().unwrap(); | 2002 | let tabs = library.tabs().unwrap(); |