/ src / modules / cmdpal / Tests / Microsoft.CmdPal.Ext.Bookmarks.UnitTests / BookmarkManagerTests.cs
BookmarkManagerTests.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Linq; 7 using Microsoft.VisualStudio.TestTools.UnitTesting; 8 9 namespace Microsoft.CmdPal.Ext.Bookmarks.UnitTests; 10 11 [TestClass] 12 public class BookmarkManagerTests 13 { 14 [TestMethod] 15 public void BookmarkManager_CanBeInstantiated() 16 { 17 // Arrange & Act 18 var bookmarkManager = new BookmarksManager(new MockBookmarkDataSource()); 19 20 // Assert 21 Assert.IsNotNull(bookmarkManager); 22 } 23 24 [TestMethod] 25 public void BookmarkManager_InitialBookmarksEmpty() 26 { 27 // Arrange 28 var bookmarkManager = new BookmarksManager(new MockBookmarkDataSource()); 29 30 // Act 31 var bookmarks = bookmarkManager.Bookmarks; 32 33 // Assert 34 Assert.IsNotNull(bookmarks); 35 Assert.AreEqual(0, bookmarks.Count); 36 } 37 38 [TestMethod] 39 public void BookmarkManager_InitialBookmarksCorruptedData() 40 { 41 // Arrange 42 var json = "@*>$ß Corrupted data. Hey, this is not JSON!"; 43 var bookmarkManager = new BookmarksManager(new MockBookmarkDataSource(json)); 44 45 // Act 46 var bookmarks = bookmarkManager.Bookmarks; 47 48 // Assert 49 Assert.IsNotNull(bookmarks); 50 Assert.AreEqual(0, bookmarks.Count); 51 } 52 53 [TestMethod] 54 public void BookmarkManager_InitializeWithExistingData() 55 { 56 // Arrange 57 const string json = """ 58 { 59 "Data":[ 60 {"Id":"d290f1ee-6c54-4b01-90e6-d701748f0851","Name":"Bookmark1","Bookmark":"C:\\Path1"}, 61 {"Id":"c4a760a4-5b63-4c9e-b8b3-2c3f5f3e6f7a","Name":"Bookmark2","Bookmark":"D:\\Path2"} 62 ] 63 } 64 """; 65 var bookmarkManager = new BookmarksManager(new MockBookmarkDataSource(json)); 66 67 // Act 68 var bookmarks = bookmarkManager.Bookmarks?.ToList(); 69 70 // Assert 71 Assert.IsNotNull(bookmarks); 72 Assert.AreEqual(2, bookmarks.Count); 73 74 Assert.AreEqual("Bookmark1", bookmarks[0].Name); 75 Assert.AreEqual("C:\\Path1", bookmarks[0].Bookmark); 76 Assert.AreEqual(Guid.Parse("d290f1ee-6c54-4b01-90e6-d701748f0851"), bookmarks[0].Id); 77 78 Assert.AreEqual("Bookmark2", bookmarks[1].Name); 79 Assert.AreEqual("D:\\Path2", bookmarks[1].Bookmark); 80 Assert.AreEqual(Guid.Parse("c4a760a4-5b63-4c9e-b8b3-2c3f5f3e6f7a"), bookmarks[1].Id); 81 } 82 83 [TestMethod] 84 public void BookmarkManager_InitializeWithLegacyData_GeneratesIds() 85 { 86 // Arrange 87 const string json = """ 88 { 89 "Data": 90 [ 91 { "Name":"Bookmark1", "Bookmark":"C:\\Path1" }, 92 { "Name":"Bookmark2", "Bookmark":"D:\\Path2" } 93 ] 94 } 95 """; 96 var bookmarkManager = new BookmarksManager(new MockBookmarkDataSource(json)); 97 98 // Act 99 var bookmarks = bookmarkManager.Bookmarks?.ToList(); 100 101 // Assert 102 Assert.IsNotNull(bookmarks); 103 Assert.AreEqual(2, bookmarks.Count); 104 105 Assert.AreEqual("Bookmark1", bookmarks[0].Name); 106 Assert.AreEqual("C:\\Path1", bookmarks[0].Bookmark); 107 Assert.AreNotEqual(Guid.Empty, bookmarks[0].Id); 108 109 Assert.AreEqual("Bookmark2", bookmarks[1].Name); 110 Assert.AreEqual("D:\\Path2", bookmarks[1].Bookmark); 111 Assert.AreNotEqual(Guid.Empty, bookmarks[1].Id); 112 113 Assert.AreNotEqual(bookmarks[0].Id, bookmarks[1].Id); 114 } 115 116 [TestMethod] 117 public void BookmarkManager_AddBookmark_WorksCorrectly() 118 { 119 // Arrange 120 var bookmarkManager = new BookmarksManager(new MockBookmarkDataSource()); 121 var bookmarkAddedEventFired = false; 122 bookmarkManager.BookmarkAdded += (bookmark) => 123 { 124 bookmarkAddedEventFired = true; 125 Assert.AreEqual("TestBookmark", bookmark.Name); 126 Assert.AreEqual("C:\\TestPath", bookmark.Bookmark); 127 }; 128 129 // Act 130 var addedBookmark = bookmarkManager.Add("TestBookmark", "C:\\TestPath"); 131 132 // Assert 133 var bookmarks = bookmarkManager.Bookmarks; 134 Assert.AreEqual(1, bookmarks.Count); 135 Assert.AreEqual(addedBookmark, bookmarks.First()); 136 Assert.IsTrue(bookmarkAddedEventFired); 137 } 138 139 [TestMethod] 140 public void BookmarkManager_RemoveBookmark_WorksCorrectly() 141 { 142 // Arrange 143 var bookmarkManager = new BookmarksManager(new MockBookmarkDataSource()); 144 var addedBookmark = bookmarkManager.Add("TestBookmark", "C:\\TestPath"); 145 var bookmarkRemovedEventFired = false; 146 bookmarkManager.BookmarkRemoved += (bookmark) => 147 { 148 bookmarkRemovedEventFired = true; 149 Assert.AreEqual(addedBookmark, bookmark); 150 }; 151 152 // Act 153 var removeResult = bookmarkManager.Remove(addedBookmark.Id); 154 155 // Assert 156 var bookmarks = bookmarkManager.Bookmarks; 157 Assert.IsTrue(removeResult); 158 Assert.AreEqual(0, bookmarks.Count); 159 Assert.IsTrue(bookmarkRemovedEventFired); 160 } 161 162 [TestMethod] 163 public void BookmarkManager_UpdateBookmark_WorksCorrectly() 164 { 165 // Arrange 166 var bookmarkManager = new BookmarksManager(new MockBookmarkDataSource()); 167 var addedBookmark = bookmarkManager.Add("TestBookmark", "C:\\TestPath"); 168 var bookmarkUpdatedEventFired = false; 169 bookmarkManager.BookmarkUpdated += (data, bookmarkData) => 170 { 171 bookmarkUpdatedEventFired = true; 172 Assert.AreEqual(addedBookmark, data); 173 Assert.AreEqual("UpdatedBookmark", bookmarkData.Name); 174 Assert.AreEqual("D:\\UpdatedPath", bookmarkData.Bookmark); 175 }; 176 177 // Act 178 var updatedBookmark = bookmarkManager.Update(addedBookmark.Id, "UpdatedBookmark", "D:\\UpdatedPath"); 179 180 // Assert 181 var bookmarks = bookmarkManager.Bookmarks; 182 Assert.IsNotNull(updatedBookmark); 183 Assert.AreEqual(1, bookmarks.Count); 184 Assert.AreEqual(updatedBookmark, bookmarks.First()); 185 Assert.AreEqual("UpdatedBookmark", updatedBookmark.Name); 186 Assert.AreEqual("D:\\UpdatedPath", updatedBookmark.Bookmark); 187 Assert.IsTrue(bookmarkUpdatedEventFired); 188 } 189 190 [TestMethod] 191 public void BookmarkManager_LegacyData_IdsArePersistedAcrossLoads() 192 { 193 // Arrange 194 const string json = """ 195 { 196 "Data": 197 [ 198 { "Name": "C:\\","Bookmark": "C:\\" }, 199 { "Name": "Bing.com","Bookmark": "https://bing.com" } 200 ] 201 } 202 """; 203 204 var dataSource = new MockBookmarkDataSource(json); 205 206 // First load: IDs should be generated for legacy entries 207 var manager1 = new BookmarksManager(dataSource); 208 var firstLoad = manager1.Bookmarks.ToList(); 209 Assert.AreEqual(2, firstLoad.Count); 210 Assert.AreNotEqual(Guid.Empty, firstLoad[0].Id); 211 Assert.AreNotEqual(Guid.Empty, firstLoad[1].Id); 212 213 // Keep a name->id map to be insensitive to ordering 214 var firstIdsByName = firstLoad.ToDictionary(b => b.Name, b => b.Id); 215 216 // Wait deterministically for async persistence to complete 217 var wasSaved = dataSource.WaitForSave(1, 5000); 218 Assert.IsTrue(wasSaved, "Data was not saved within the expected time."); 219 220 // Second load: should read back the same IDs from persisted data 221 var manager2 = new BookmarksManager(dataSource); 222 var secondLoad = manager2.Bookmarks.ToList(); 223 Assert.AreEqual(2, secondLoad.Count); 224 225 var secondIdsByName = secondLoad.ToDictionary(b => b.Name, b => b.Id); 226 227 foreach (var kvp in firstIdsByName) 228 { 229 Assert.IsTrue(secondIdsByName.ContainsKey(kvp.Key), $"Missing bookmark '{kvp.Key}' after reload."); 230 Assert.AreEqual(kvp.Value, secondIdsByName[kvp.Key], $"Bookmark '{kvp.Key}' upgraded ID was not persisted across loads."); 231 } 232 } 233 }