| ... | @@ -73,6 +73,119 @@ fn renaming_an_unlisted_section_creates_its_toc_entry_and_preserves_its_neighbor | ... | @@ -73,6 +73,119 @@ fn renaming_an_unlisted_section_creates_its_toc_entry_and_preserves_its_neighbor |
| 73 | } | 73 | } |
| 74 | } | 74 | } |
| 75 | | 75 | |
| | 76 | #[test] |
| | 77 | fn moving_discovered_entries_preserves_unregistered_source_tocs() { |
| | 78 | for group in [false, true] { |
| | 79 | for source_toc in ["missing", "empty", "unlisted", "registered"] { |
| | 80 | let temporary = tempfile::tempdir().unwrap(); |
| | 81 | let folder = temporary.path().join("notebook"); |
| | 82 | let cache = temporary.path().join("cache"); |
| | 83 | let page = PageCreation::new(None, Some("Garden plan"), "Fixture").unwrap(); |
| | 84 | let mut notebook = |
| | 85 | Notebook::create(&folder, &cache, Notebook::NEW_COLOR, &page).unwrap(); |
| | 86 | let first = notebook.catalog().sections[0].path.clone(); |
| | 87 | let neighbor = notebook.create_section("", "Neighbor", &page).unwrap(); |
| | 88 | let target = notebook.create_group("", "Target").unwrap(); |
| | 89 | let existing = notebook.create_section(&target, "Existing", &page).unwrap(); |
| | 90 | let (entry, section, identity) = if group { |
| | 91 | let entry = notebook.create_group("", "Source").unwrap(); |
| | 92 | let section = notebook.create_section(&entry, "Inside", &page).unwrap(); |
| | 93 | let identity = notebook |
| | 94 | .folder(&entry) |
| | 95 | .unwrap() |
| | 96 | .toc |
| | 97 | .as_ref() |
| | 98 | .unwrap() |
| | 99 | .file_id; |
| | 100 | (entry, section, identity) |
| | 101 | } else { |
| | 102 | let identity = notebook.section_path(&first).unwrap().file_id; |
| | 103 | (first.clone(), first, identity) |
| | 104 | }; |
| | 105 | let section_id = notebook.section_path(&section).unwrap().file_id; |
| | 106 | let neighbor_bytes = fs::read(folder.join(&neighbor)).unwrap(); |
| | 107 | let existing_bytes = fs::read(folder.join(&existing)).unwrap(); |
| | 108 | if source_toc == "unlisted" { |
| | 109 | notebook |
| | 110 | .edit_toc("", &[onestore::TocEdit::Remove { identity }]) |
| | 111 | .unwrap(); |
| | 112 | } |
| | 113 | drop(notebook); |
| | 114 | if source_toc == "missing" { |
| | 115 | fs::remove_file(folder.join(TOC)).unwrap(); |
| | 116 | } else if source_toc == "empty" { |
| | 117 | fs::write( |
| | 118 | folder.join(TOC), |
| | 119 | onestore::create_table_of_contents(TOC, &[]).unwrap(), |
| | 120 | ) |
| | 121 | .unwrap(); |
| | 122 | } |
| | 123 | let before = fs::read(folder.join(TOC)).ok(); |
| | 124 | let mut notebook = Notebook::open(&folder, &cache).unwrap(); |
| | 125 | let order: Vec<_> = notebook |
| | 126 | .catalog() |
| | 127 | .order |
| | 128 | .iter() |
| | 129 | .filter(|path| **path != entry) |
| | 130 | .cloned() |
| | 131 | .collect(); |
| | 132 | let moved = catalog_path(&target, &entry); |
| | 133 | assert_eq!(notebook.move_entry(&entry, &target).unwrap(), moved); |
| | 134 | assert!(!folder.join(&entry).exists()); |
| | 135 | let moved_section = catalog_path(&target, &section); |
| | 136 | let check = |notebook: &Notebook| { |
| | 137 | assert_eq!(notebook.catalog().order, order); |
| | 138 | assert_eq!( |
| | 139 | notebook.section_path(&moved_section).unwrap().file_id, |
| | 140 | section_id |
| | 141 | ); |
| | 142 | assert!(lists(&notebook.read_toc(&target).unwrap(), identity).unwrap()); |
| | 143 | assert_eq!( |
| | 144 | stored_pages(&notebook.read_section(&moved_section).unwrap()).unwrap()[0] |
| | 145 | .page |
| | 146 | .title, |
| | 147 | "Garden plan" |
| | 148 | ); |
| | 149 | if source_toc == "registered" { |
| | 150 | let toc = notebook.read_toc("").unwrap(); |
| | 151 | assert!(!lists(&toc, identity).unwrap()); |
| | 152 | assert_eq!( |
| | 153 | notebook.catalog().toc.as_ref().unwrap().color, |
| | 154 | Some(Notebook::NEW_COLOR) |
| | 155 | ); |
| | 156 | } else { |
| | 157 | assert_eq!(fs::read(folder.join(TOC)).ok(), before); |
| | 158 | } |
| | 159 | assert_eq!(fs::read(folder.join(&neighbor)).unwrap(), neighbor_bytes); |
| | 160 | assert_eq!(fs::read(folder.join(&existing)).unwrap(), existing_bytes); |
| | 161 | }; |
| | 162 | check(&notebook); |
| | 163 | drop(notebook); |
| | 164 | check(&Notebook::open(&folder, temporary.path().join("cold-cache")).unwrap()); |
| | 165 | } |
| | 166 | } |
| | 167 | } |
| | 168 | |
| | 169 | #[test] |
| | 170 | fn moving_an_entry_reads_its_registered_source_toc_before_renaming() { |
| | 171 | let temporary = tempfile::tempdir().unwrap(); |
| | 172 | let folder = temporary.path().join("notebook"); |
| | 173 | let page = PageCreation::new(None, Some("Garden plan"), "Fixture").unwrap(); |
| | 174 | let mut notebook = Notebook::create( |
| | 175 | &folder, |
| | 176 | temporary.path().join("cache"), |
| | 177 | Notebook::NEW_COLOR, |
| | 178 | &page, |
| | 179 | ) |
| | 180 | .unwrap(); |
| | 181 | let section = notebook.catalog().sections[0].path.clone(); |
| | 182 | notebook.create_group("", "Target").unwrap(); |
| | 183 | fs::write(folder.join(TOC), b"unreadable source TOC").unwrap(); |
| | 184 | assert!(notebook.move_entry(&section, "Target").is_err()); |
| | 185 | assert!(folder.join(&section).exists()); |
| | 186 | assert!(!folder.join("Target").join(&section).exists()); |
| | 187 | } |
| | 188 | |
| 76 | struct FaultStorage { | 189 | struct FaultStorage { |
| 77 | inner: Directory, | 190 | inner: Directory, |
| 78 | revision: Mutex<Option<(String, Transaction)>>, | 191 | revision: Mutex<Option<(String, Transaction)>>, |