1 // Copyright 2020 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.bookmarks; 6 7 import android.app.Activity; 8 import android.content.Context; 9 import android.content.Intent; 10 import android.support.test.InstrumentationRegistry; 11 import android.view.MenuItem; 12 13 import androidx.test.filters.MediumTest; 14 15 import org.junit.After; 16 import org.junit.Assert; 17 import org.junit.Before; 18 import org.junit.Rule; 19 import org.junit.Test; 20 import org.junit.runner.RunWith; 21 import org.mockito.Mockito; 22 23 import org.chromium.base.ActivityState; 24 import org.chromium.base.ApplicationStatus; 25 import org.chromium.base.ApplicationStatus.ActivityStateListener; 26 import org.chromium.base.test.BaseJUnit4ClassRunner; 27 import org.chromium.base.test.util.Batch; 28 import org.chromium.base.test.util.CallbackHelper; 29 import org.chromium.base.test.util.CriteriaHelper; 30 import org.chromium.base.test.util.Feature; 31 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem; 32 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkModelObserver; 33 import org.chromium.chrome.browser.profiles.Profile; 34 import org.chromium.chrome.test.ChromeBrowserTestRule; 35 import org.chromium.chrome.test.util.BookmarkTestUtil; 36 import org.chromium.components.bookmarks.BookmarkId; 37 import org.chromium.content_public.browser.test.util.TestThreadUtils; 38 39 import java.util.concurrent.ExecutionException; 40 import java.util.concurrent.TimeoutException; 41 42 /** 43 * Tests functionality in BookmarkEditActivity. 44 */ 45 @RunWith(BaseJUnit4ClassRunner.class) 46 @Batch(Batch.PER_CLASS) 47 public class BookmarkEditTest { 48 private static final String TITLE_A = "a"; 49 private static final String TITLE_B = "b"; 50 private static final String URL_A = "http://a.com/"; 51 private static final String URL_B = "http://b.com/"; 52 private static final String FOLDER_A = "FolderA"; 53 54 @Rule 55 public final ChromeBrowserTestRule mChromeBrowserTestRule = new ChromeBrowserTestRule(); 56 57 private BookmarkModel mBookmarkModel; 58 private BookmarkModel.BookmarkModelObserver mModelObserver; 59 private CallbackHelper mModelChangedCallback = new CallbackHelper(); 60 private BookmarkId mBookmarkId; 61 private BookmarkId mMobileNode; 62 private BookmarkId mOtherNode; 63 private BookmarkEditActivity mBookmarkEditActivity; 64 65 private CallbackHelper mDestroyedCallback = new CallbackHelper(); 66 private ActivityStateListener mActivityStateListener = new ActivityStateListener() { 67 @Override 68 public void onActivityStateChange(Activity activity, int newState) { 69 if (newState == ActivityState.DESTROYED) mDestroyedCallback.notifyCalled(); 70 } 71 }; 72 73 @Before setUp()74 public void setUp() throws TimeoutException { 75 TestThreadUtils.runOnUiThreadBlocking(() -> { 76 Profile profile = Profile.getLastUsedRegularProfile(); 77 mBookmarkModel = new BookmarkModel(profile); 78 mBookmarkModel.loadEmptyPartnerBookmarkShimForTesting(); 79 }); 80 81 BookmarkTestUtil.waitForBookmarkModelLoaded(); 82 TestThreadUtils.runOnUiThreadBlocking(() -> { 83 mMobileNode = mBookmarkModel.getMobileFolderId(); 84 mOtherNode = mBookmarkModel.getOtherFolderId(); 85 }); 86 mBookmarkId = BookmarkModelTest.addBookmark(mBookmarkModel, mMobileNode, 0, TITLE_A, URL_A); 87 88 mModelObserver = new BookmarkModelObserver() { 89 @Override 90 public void bookmarkModelChanged() { 91 mModelChangedCallback.notifyCalled(); 92 } 93 }; 94 mBookmarkModel.addObserver(mModelObserver); 95 96 startEditActivity(mBookmarkId); 97 ApplicationStatus.registerStateListenerForActivity( 98 mActivityStateListener, mBookmarkEditActivity); 99 } 100 101 @After tearDown()102 public void tearDown() { 103 mBookmarkModel.removeObserver(mModelObserver); 104 TestThreadUtils.runOnUiThreadBlocking(() -> mBookmarkModel.removeAllUserBookmarks()); 105 ApplicationStatus.unregisterActivityStateListener(mActivityStateListener); 106 } 107 108 @Test 109 @MediumTest 110 @Feature({"Bookmark"}) testEditTitleAndUrl()111 public void testEditTitleAndUrl() throws ExecutionException, TimeoutException { 112 Assert.assertEquals("Incorrect title.", TITLE_A, 113 mBookmarkEditActivity.getTitleEditText().getEditText().getText().toString()); 114 Assert.assertEquals("Incorrect url.", URL_A, 115 mBookmarkEditActivity.getUrlEditText().getEditText().getText().toString()); 116 117 int currentModelChangedCount = mModelChangedCallback.getCallCount(); 118 TestThreadUtils.runOnUiThreadBlocking(() -> { 119 mBookmarkEditActivity.getTitleEditText().getEditText().setText(TITLE_B); 120 mBookmarkEditActivity.getUrlEditText().getEditText().setText(URL_B); 121 mBookmarkEditActivity.finish(); 122 }); 123 mDestroyedCallback.waitForCallback(0); 124 125 BookmarkItem bookmarkItem = getBookmarkItem(mBookmarkId); 126 Assert.assertEquals("Incorrect title after edit.", TITLE_B, bookmarkItem.getTitle()); 127 Assert.assertEquals("Incorrect url after edit.", URL_B, bookmarkItem.getUrl()); 128 } 129 130 @Test 131 @MediumTest 132 @Feature({"Bookmark"}) testEditEmptyInputRejected()133 public void testEditEmptyInputRejected() throws ExecutionException, TimeoutException { 134 Assert.assertEquals("Incorrect title.", TITLE_A, 135 mBookmarkEditActivity.getTitleEditText().getEditText().getText().toString()); 136 Assert.assertEquals("Incorrect url.", URL_A, 137 mBookmarkEditActivity.getUrlEditText().getEditText().getText().toString()); 138 139 TestThreadUtils.runOnUiThreadBlocking(() -> { 140 mBookmarkEditActivity.getTitleEditText().getEditText().setText(""); 141 mBookmarkEditActivity.getUrlEditText().getEditText().setText(""); 142 mBookmarkEditActivity.finish(); 143 }); 144 mDestroyedCallback.waitForCallback(0); 145 146 BookmarkItem bookmarkItem = getBookmarkItem(mBookmarkId); 147 Assert.assertEquals("Incorrect title after edit.", TITLE_A, bookmarkItem.getTitle()); 148 Assert.assertEquals("Incorrect url after edit.", URL_A, bookmarkItem.getUrl()); 149 } 150 151 @Test 152 @MediumTest 153 @Feature({"Bookmark"}) testInvalidUrlRejected()154 public void testInvalidUrlRejected() throws ExecutionException, TimeoutException { 155 Assert.assertEquals("Incorrect url.", URL_A, 156 mBookmarkEditActivity.getUrlEditText().getEditText().getText().toString()); 157 158 TestThreadUtils.runOnUiThreadBlocking(() -> { 159 mBookmarkEditActivity.getUrlEditText().getEditText().setText("http:://?foo=bar"); 160 mBookmarkEditActivity.finish(); 161 }); 162 mDestroyedCallback.waitForCallback(0); 163 164 BookmarkItem bookmarkItem = getBookmarkItem(mBookmarkId); 165 Assert.assertEquals("Incorrect url after edit.", URL_A, bookmarkItem.getUrl()); 166 } 167 168 @Test 169 @MediumTest 170 @Feature({"Bookmark"}) testEditActivityDeleteButton()171 public void testEditActivityDeleteButton() throws ExecutionException, TimeoutException { 172 TestThreadUtils.runOnUiThreadBlocking(() -> { 173 mBookmarkEditActivity.onOptionsItemSelected(mBookmarkEditActivity.getDeleteButton()); 174 }); 175 mDestroyedCallback.waitForCallback(0); 176 177 BookmarkItem bookmarkItem = getBookmarkItem(mBookmarkId); 178 Assert.assertNull("Bookmark item should have been deleted.", bookmarkItem); 179 } 180 181 @Test 182 @MediumTest 183 @Feature({"Bookmark"}) testEditActivityHomeButton()184 public void testEditActivityHomeButton() throws ExecutionException { 185 MenuItem item = Mockito.mock(MenuItem.class); 186 Mockito.when(item.getItemId()).thenReturn(android.R.id.home); 187 TestThreadUtils.runOnUiThreadBlocking( 188 () -> mBookmarkEditActivity.onOptionsItemSelected(item)); 189 190 Assert.assertTrue("BookmarkActivity should be finishing or destroyed.", 191 mBookmarkEditActivity.isFinishing() || mBookmarkEditActivity.isDestroyed()); 192 } 193 194 @Test 195 @MediumTest 196 @Feature({"Bookmark"}) testEditActivityReflectsModelChanges()197 public void testEditActivityReflectsModelChanges() throws TimeoutException, ExecutionException { 198 Assert.assertEquals("Incorrect title.", TITLE_A, 199 mBookmarkEditActivity.getTitleEditText().getEditText().getText().toString()); 200 Assert.assertEquals("Incorrect folder.", getBookmarkItem(mMobileNode).getTitle(), 201 mBookmarkEditActivity.getFolderTextView().getText()); 202 203 int currentModelChangedCount = mModelChangedCallback.getCallCount(); 204 TestThreadUtils.runOnUiThreadBlocking(() -> { 205 mBookmarkModel.setBookmarkTitle(mBookmarkId, TITLE_B); 206 mBookmarkModel.moveBookmark(mBookmarkId, mOtherNode, 0); 207 }); 208 mModelChangedCallback.waitForCallback(currentModelChangedCount); 209 210 Assert.assertEquals("Title shouldn't change after model update.", TITLE_A, 211 mBookmarkEditActivity.getTitleEditText().getEditText().getText().toString()); 212 Assert.assertEquals("Folder should change after model update.", 213 getBookmarkItem(mOtherNode).getTitle(), 214 mBookmarkEditActivity.getFolderTextView().getText()); 215 } 216 217 @Test 218 @MediumTest 219 @Feature({"Bookmark"}) testEditActivityFinishesWhenBookmarkDeleted()220 public void testEditActivityFinishesWhenBookmarkDeleted() throws TimeoutException { 221 int currentModelChangedCount = mModelChangedCallback.getCallCount(); 222 TestThreadUtils.runOnUiThreadBlocking(() -> mBookmarkModel.deleteBookmark(mBookmarkId)); 223 mModelChangedCallback.waitForCallback(currentModelChangedCount); 224 225 Assert.assertTrue("BookmarkActivity should be finishing or destroyed.", 226 mBookmarkEditActivity.isFinishing() || mBookmarkEditActivity.isDestroyed()); 227 } 228 229 @Test 230 @MediumTest 231 @Feature({"Bookmark"}) testEditFolderLocation()232 public void testEditFolderLocation() throws ExecutionException, TimeoutException { 233 BookmarkId testFolder = addFolder(mMobileNode, 0, FOLDER_A); 234 TestThreadUtils.runOnUiThreadBlocking( 235 () -> mBookmarkEditActivity.getFolderTextView().performClick()); 236 waitForMoveFolderActivity(); 237 238 TestThreadUtils.runOnUiThreadBlocking(() -> { 239 BookmarkFolderSelectActivity folderSelectActivity = 240 (BookmarkFolderSelectActivity) 241 ApplicationStatus.getLastTrackedFocusedActivity(); 242 int pos = folderSelectActivity.getFolderPositionForTesting(testFolder); 243 Assert.assertNotEquals("Didn't find position for test folder.", -1, pos); 244 folderSelectActivity.performClickForTesting(pos); 245 }); 246 247 waitForEditActivity(); 248 Assert.assertEquals("Folder should change after folder activity finishes.", FOLDER_A, 249 mBookmarkEditActivity.getFolderTextView().getText()); 250 } 251 getBookmarkItem(BookmarkId bookmarkId)252 private BookmarkItem getBookmarkItem(BookmarkId bookmarkId) throws ExecutionException { 253 return TestThreadUtils.runOnUiThreadBlocking( 254 () -> mBookmarkModel.getBookmarkById(bookmarkId)); 255 } 256 startEditActivity(BookmarkId bookmarkId)257 private void startEditActivity(BookmarkId bookmarkId) { 258 Context context = InstrumentationRegistry.getTargetContext(); 259 Intent intent = new Intent(context, BookmarkEditActivity.class); 260 intent.putExtra(BookmarkEditActivity.INTENT_BOOKMARK_ID, bookmarkId.toString()); 261 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 262 mBookmarkEditActivity = (BookmarkEditActivity) InstrumentationRegistry.getInstrumentation() 263 .startActivitySync(intent); 264 } 265 addFolder(BookmarkId parent, int index, String title)266 private BookmarkId addFolder(BookmarkId parent, int index, String title) 267 throws ExecutionException { 268 return TestThreadUtils.runOnUiThreadBlocking( 269 () -> mBookmarkModel.addFolder(parent, index, title)); 270 } 271 waitForMoveFolderActivity()272 private void waitForMoveFolderActivity() { 273 // clang-format off 274 CriteriaHelper.pollUiThread(()-> 275 ApplicationStatus.getLastTrackedFocusedActivity() 276 instanceof BookmarkFolderSelectActivity, 277 "Timed out waiting for BookmarkFolderSelectActivity"); 278 // clang-format on 279 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 280 } 281 waitForEditActivity()282 private void waitForEditActivity() { 283 // clang-format off 284 CriteriaHelper.pollUiThread(()-> 285 ApplicationStatus.getLastTrackedFocusedActivity() instanceof BookmarkEditActivity, 286 "Timed out waiting for BookmarkEditActivity"); 287 // clang-format on 288 mBookmarkEditActivity = 289 (BookmarkEditActivity) ApplicationStatus.getLastTrackedFocusedActivity(); 290 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 291 } 292 } 293