| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stddef.h> | 5 #include <stddef.h> |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include <set> | 9 #include <set> |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 content::TestBrowserThreadBundle thread_bundle_; | 88 content::TestBrowserThreadBundle thread_bundle_; |
| 89 }; | 89 }; |
| 90 | 90 |
| 91 #if !defined(OS_CHROMEOS) | 91 #if !defined(OS_CHROMEOS) |
| 92 // Test that GetStatusLabelsForSyncGlobalError returns an error if a | 92 // Test that GetStatusLabelsForSyncGlobalError returns an error if a |
| 93 // passphrase is required. | 93 // passphrase is required. |
| 94 TEST_F(SyncUIUtilTest, PassphraseGlobalError) { | 94 TEST_F(SyncUIUtilTest, PassphraseGlobalError) { |
| 95 std::unique_ptr<Profile> profile = MakeSignedInTestingProfile(); | 95 std::unique_ptr<Profile> profile = MakeSignedInTestingProfile(); |
| 96 ProfileSyncServiceMock service( | 96 ProfileSyncServiceMock service( |
| 97 CreateProfileSyncServiceParamsForTest(profile.get())); | 97 CreateProfileSyncServiceParamsForTest(profile.get())); |
| 98 syncer::SyncBackendHost::Status status; | 98 syncer::SyncEngine::Status status; |
| 99 EXPECT_CALL(service, QueryDetailedSyncStatus(_)) | 99 EXPECT_CALL(service, QueryDetailedSyncStatus(_)) |
| 100 .WillRepeatedly(Return(false)); | 100 .WillRepeatedly(Return(false)); |
| 101 EXPECT_CALL(service, IsPassphraseRequired()) | 101 EXPECT_CALL(service, IsPassphraseRequired()) |
| 102 .WillRepeatedly(Return(true)); | 102 .WillRepeatedly(Return(true)); |
| 103 EXPECT_CALL(service, IsPassphraseRequiredForDecryption()) | 103 EXPECT_CALL(service, IsPassphraseRequiredForDecryption()) |
| 104 .WillRepeatedly(Return(true)); | 104 .WillRepeatedly(Return(true)); |
| 105 | 105 |
| 106 VerifySyncGlobalErrorResult(&service, | 106 VerifySyncGlobalErrorResult(&service, |
| 107 GoogleServiceAuthError::NONE, | 107 GoogleServiceAuthError::NONE, |
| 108 true /* signed in */, | 108 true /* signed in */, |
| 109 true /* error */); | 109 true /* error */); |
| 110 } | 110 } |
| 111 | 111 |
| 112 // Test that GetStatusLabelsForSyncGlobalError returns an error if a | 112 // Test that GetStatusLabelsForSyncGlobalError returns an error if a |
| 113 // passphrase is required and not for auth errors. | 113 // passphrase is required and not for auth errors. |
| 114 TEST_F(SyncUIUtilTest, AuthAndPassphraseGlobalError) { | 114 TEST_F(SyncUIUtilTest, AuthAndPassphraseGlobalError) { |
| 115 std::unique_ptr<Profile> profile(MakeSignedInTestingProfile()); | 115 std::unique_ptr<Profile> profile(MakeSignedInTestingProfile()); |
| 116 ProfileSyncServiceMock service( | 116 ProfileSyncServiceMock service( |
| 117 CreateProfileSyncServiceParamsForTest(profile.get())); | 117 CreateProfileSyncServiceParamsForTest(profile.get())); |
| 118 syncer::SyncBackendHost::Status status; | 118 syncer::SyncEngine::Status status; |
| 119 EXPECT_CALL(service, QueryDetailedSyncStatus(_)) | 119 EXPECT_CALL(service, QueryDetailedSyncStatus(_)) |
| 120 .WillRepeatedly(Return(false)); | 120 .WillRepeatedly(Return(false)); |
| 121 | 121 |
| 122 EXPECT_CALL(service, IsPassphraseRequired()) | 122 EXPECT_CALL(service, IsPassphraseRequired()) |
| 123 .WillRepeatedly(Return(true)); | 123 .WillRepeatedly(Return(true)); |
| 124 EXPECT_CALL(service, IsPassphraseRequiredForDecryption()) | 124 EXPECT_CALL(service, IsPassphraseRequiredForDecryption()) |
| 125 .WillRepeatedly(Return(true)); | 125 .WillRepeatedly(Return(true)); |
| 126 EXPECT_CALL(service, IsFirstSetupComplete()).WillRepeatedly(Return(true)); | 126 EXPECT_CALL(service, IsFirstSetupComplete()).WillRepeatedly(Return(true)); |
| 127 | 127 |
| 128 GoogleServiceAuthError auth_error( | 128 GoogleServiceAuthError auth_error( |
| 129 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); | 129 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); |
| 130 EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error)); | 130 EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error)); |
| 131 base::string16 menu_label, label2, label3; | 131 base::string16 menu_label, label2, label3; |
| 132 sync_ui_util::GetStatusLabelsForSyncGlobalError( | 132 sync_ui_util::GetStatusLabelsForSyncGlobalError( |
| 133 &service, &menu_label, &label2, &label3); | 133 &service, &menu_label, &label2, &label3); |
| 134 // Make sure we are still displaying the passphrase error badge (don't show | 134 // Make sure we are still displaying the passphrase error badge (don't show |
| 135 // auth errors through SyncUIUtil). | 135 // auth errors through SyncUIUtil). |
| 136 EXPECT_EQ(menu_label, l10n_util::GetStringUTF16( | 136 EXPECT_EQ(menu_label, l10n_util::GetStringUTF16( |
| 137 IDS_SYNC_PASSPHRASE_ERROR_WRENCH_MENU_ITEM)); | 137 IDS_SYNC_PASSPHRASE_ERROR_WRENCH_MENU_ITEM)); |
| 138 } | 138 } |
| 139 | 139 |
| 140 // Test that GetStatusLabelsForSyncGlobalError does not indicate errors for | 140 // Test that GetStatusLabelsForSyncGlobalError does not indicate errors for |
| 141 // auth errors (these are reported through SigninGlobalError). | 141 // auth errors (these are reported through SigninGlobalError). |
| 142 TEST_F(SyncUIUtilTest, AuthStateGlobalError) { | 142 TEST_F(SyncUIUtilTest, AuthStateGlobalError) { |
| 143 std::unique_ptr<Profile> profile(MakeSignedInTestingProfile()); | 143 std::unique_ptr<Profile> profile(MakeSignedInTestingProfile()); |
| 144 ProfileSyncService::InitParams init_params = | 144 ProfileSyncService::InitParams init_params = |
| 145 CreateProfileSyncServiceParamsForTest(profile.get()); | 145 CreateProfileSyncServiceParamsForTest(profile.get()); |
| 146 NiceMock<ProfileSyncServiceMock> service(&init_params); | 146 NiceMock<ProfileSyncServiceMock> service(&init_params); |
| 147 | 147 |
| 148 syncer::SyncBackendHost::Status status; | 148 syncer::SyncEngine::Status status; |
| 149 EXPECT_CALL(service, QueryDetailedSyncStatus(_)) | 149 EXPECT_CALL(service, QueryDetailedSyncStatus(_)) |
| 150 .WillRepeatedly(Return(false)); | 150 .WillRepeatedly(Return(false)); |
| 151 | 151 |
| 152 GoogleServiceAuthError::State table[] = { | 152 GoogleServiceAuthError::State table[] = { |
| 153 GoogleServiceAuthError::NONE, | 153 GoogleServiceAuthError::NONE, |
| 154 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, | 154 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, |
| 155 GoogleServiceAuthError::USER_NOT_SIGNED_UP, | 155 GoogleServiceAuthError::USER_NOT_SIGNED_UP, |
| 156 GoogleServiceAuthError::CONNECTION_FAILED, | 156 GoogleServiceAuthError::CONNECTION_FAILED, |
| 157 GoogleServiceAuthError::CAPTCHA_REQUIRED, | 157 GoogleServiceAuthError::CAPTCHA_REQUIRED, |
| 158 GoogleServiceAuthError::ACCOUNT_DELETED, | 158 GoogleServiceAuthError::ACCOUNT_DELETED, |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 int caseNumber) { | 213 int caseNumber) { |
| 214 // Auth Error object is returned by reference in mock and needs to stay in | 214 // Auth Error object is returned by reference in mock and needs to stay in |
| 215 // scope throughout test, so it is owned by calling method. However it is | 215 // scope throughout test, so it is owned by calling method. However it is |
| 216 // immutable so can only be allocated in this method. | 216 // immutable so can only be allocated in this method. |
| 217 switch (caseNumber) { | 217 switch (caseNumber) { |
| 218 case STATUS_CASE_SETUP_IN_PROGRESS: { | 218 case STATUS_CASE_SETUP_IN_PROGRESS: { |
| 219 EXPECT_CALL(*service, IsFirstSetupComplete()) | 219 EXPECT_CALL(*service, IsFirstSetupComplete()) |
| 220 .WillRepeatedly(Return(false)); | 220 .WillRepeatedly(Return(false)); |
| 221 EXPECT_CALL(*service, IsFirstSetupInProgress()) | 221 EXPECT_CALL(*service, IsFirstSetupInProgress()) |
| 222 .WillRepeatedly(Return(true)); | 222 .WillRepeatedly(Return(true)); |
| 223 syncer::SyncBackendHost::Status status; | 223 syncer::SyncEngine::Status status; |
| 224 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) | 224 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) |
| 225 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); | 225 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); |
| 226 return; | 226 return; |
| 227 } | 227 } |
| 228 case STATUS_CASE_SETUP_ERROR: { | 228 case STATUS_CASE_SETUP_ERROR: { |
| 229 EXPECT_CALL(*service, IsFirstSetupComplete()) | 229 EXPECT_CALL(*service, IsFirstSetupComplete()) |
| 230 .WillRepeatedly(Return(false)); | 230 .WillRepeatedly(Return(false)); |
| 231 EXPECT_CALL(*service, IsFirstSetupInProgress()) | 231 EXPECT_CALL(*service, IsFirstSetupInProgress()) |
| 232 .WillRepeatedly(Return(false)); | 232 .WillRepeatedly(Return(false)); |
| 233 EXPECT_CALL(*service, HasUnrecoverableError()) | 233 EXPECT_CALL(*service, HasUnrecoverableError()) |
| 234 .WillRepeatedly(Return(true)); | 234 .WillRepeatedly(Return(true)); |
| 235 syncer::SyncBackendHost::Status status; | 235 syncer::SyncEngine::Status status; |
| 236 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) | 236 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) |
| 237 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); | 237 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); |
| 238 return; | 238 return; |
| 239 } | 239 } |
| 240 case STATUS_CASE_AUTHENTICATING: { | 240 case STATUS_CASE_AUTHENTICATING: { |
| 241 EXPECT_CALL(*service, IsFirstSetupComplete()) | 241 EXPECT_CALL(*service, IsFirstSetupComplete()) |
| 242 .WillRepeatedly(Return(true)); | 242 .WillRepeatedly(Return(true)); |
| 243 EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); | 243 EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); |
| 244 EXPECT_CALL(*service, IsPassphraseRequired()) | 244 EXPECT_CALL(*service, IsPassphraseRequired()) |
| 245 .WillRepeatedly(Return(false)); | 245 .WillRepeatedly(Return(false)); |
| 246 syncer::SyncBackendHost::Status status; | 246 syncer::SyncEngine::Status status; |
| 247 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) | 247 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) |
| 248 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); | 248 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); |
| 249 EXPECT_CALL(*service, HasUnrecoverableError()) | 249 EXPECT_CALL(*service, HasUnrecoverableError()) |
| 250 .WillRepeatedly(Return(false)); | 250 .WillRepeatedly(Return(false)); |
| 251 signin->set_auth_in_progress(); | 251 signin->set_auth_in_progress(); |
| 252 return; | 252 return; |
| 253 } | 253 } |
| 254 case STATUS_CASE_AUTH_ERROR: { | 254 case STATUS_CASE_AUTH_ERROR: { |
| 255 EXPECT_CALL(*service, IsFirstSetupComplete()) | 255 EXPECT_CALL(*service, IsFirstSetupComplete()) |
| 256 .WillRepeatedly(Return(true)); | 256 .WillRepeatedly(Return(true)); |
| 257 EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); | 257 EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); |
| 258 EXPECT_CALL(*service, IsPassphraseRequired()) | 258 EXPECT_CALL(*service, IsPassphraseRequired()) |
| 259 .WillRepeatedly(Return(false)); | 259 .WillRepeatedly(Return(false)); |
| 260 syncer::SyncBackendHost::Status status; | 260 syncer::SyncEngine::Status status; |
| 261 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) | 261 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) |
| 262 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); | 262 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); |
| 263 provider->SetAuthError( | 263 provider->SetAuthError( |
| 264 signin->GetAuthenticatedAccountId(), | 264 signin->GetAuthenticatedAccountId(), |
| 265 GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); | 265 GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); |
| 266 EXPECT_CALL(*service, HasUnrecoverableError()) | 266 EXPECT_CALL(*service, HasUnrecoverableError()) |
| 267 .WillRepeatedly(Return(false)); | 267 .WillRepeatedly(Return(false)); |
| 268 return; | 268 return; |
| 269 } | 269 } |
| 270 case STATUS_CASE_PROTOCOL_ERROR: { | 270 case STATUS_CASE_PROTOCOL_ERROR: { |
| 271 EXPECT_CALL(*service, IsFirstSetupComplete()) | 271 EXPECT_CALL(*service, IsFirstSetupComplete()) |
| 272 .WillRepeatedly(Return(true)); | 272 .WillRepeatedly(Return(true)); |
| 273 EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); | 273 EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); |
| 274 EXPECT_CALL(*service, IsPassphraseRequired()) | 274 EXPECT_CALL(*service, IsPassphraseRequired()) |
| 275 .WillRepeatedly(Return(false)); | 275 .WillRepeatedly(Return(false)); |
| 276 syncer::SyncProtocolError protocolError; | 276 syncer::SyncProtocolError protocolError; |
| 277 protocolError.action = syncer::UPGRADE_CLIENT; | 277 protocolError.action = syncer::UPGRADE_CLIENT; |
| 278 syncer::SyncBackendHost::Status status; | 278 syncer::SyncEngine::Status status; |
| 279 status.sync_protocol_error = protocolError; | 279 status.sync_protocol_error = protocolError; |
| 280 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) | 280 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) |
| 281 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); | 281 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); |
| 282 EXPECT_CALL(*service, HasUnrecoverableError()) | 282 EXPECT_CALL(*service, HasUnrecoverableError()) |
| 283 .WillRepeatedly(Return(false)); | 283 .WillRepeatedly(Return(false)); |
| 284 return; | 284 return; |
| 285 } | 285 } |
| 286 case STATUS_CASE_PASSPHRASE_ERROR: { | 286 case STATUS_CASE_PASSPHRASE_ERROR: { |
| 287 EXPECT_CALL(*service, IsFirstSetupComplete()) | 287 EXPECT_CALL(*service, IsFirstSetupComplete()) |
| 288 .WillRepeatedly(Return(true)); | 288 .WillRepeatedly(Return(true)); |
| 289 EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); | 289 EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); |
| 290 syncer::SyncBackendHost::Status status; | 290 syncer::SyncEngine::Status status; |
| 291 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) | 291 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) |
| 292 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); | 292 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); |
| 293 EXPECT_CALL(*service, HasUnrecoverableError()) | 293 EXPECT_CALL(*service, HasUnrecoverableError()) |
| 294 .WillRepeatedly(Return(false)); | 294 .WillRepeatedly(Return(false)); |
| 295 EXPECT_CALL(*service, IsPassphraseRequired()) | 295 EXPECT_CALL(*service, IsPassphraseRequired()) |
| 296 .WillRepeatedly(Return(true)); | 296 .WillRepeatedly(Return(true)); |
| 297 EXPECT_CALL(*service, IsPassphraseRequiredForDecryption()) | 297 EXPECT_CALL(*service, IsPassphraseRequiredForDecryption()) |
| 298 .WillRepeatedly(Return(true)); | 298 .WillRepeatedly(Return(true)); |
| 299 return; | 299 return; |
| 300 } | 300 } |
| 301 case STATUS_CASE_SYNCED: { | 301 case STATUS_CASE_SYNCED: { |
| 302 EXPECT_CALL(*service, IsFirstSetupComplete()) | 302 EXPECT_CALL(*service, IsFirstSetupComplete()) |
| 303 .WillRepeatedly(Return(true)); | 303 .WillRepeatedly(Return(true)); |
| 304 EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); | 304 EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); |
| 305 EXPECT_CALL(*service, IsPassphraseRequired()) | 305 EXPECT_CALL(*service, IsPassphraseRequired()) |
| 306 .WillRepeatedly(Return(false)); | 306 .WillRepeatedly(Return(false)); |
| 307 syncer::SyncBackendHost::Status status; | 307 syncer::SyncEngine::Status status; |
| 308 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) | 308 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) |
| 309 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); | 309 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); |
| 310 EXPECT_CALL(*service, HasUnrecoverableError()) | 310 EXPECT_CALL(*service, HasUnrecoverableError()) |
| 311 .WillRepeatedly(Return(false)); | 311 .WillRepeatedly(Return(false)); |
| 312 EXPECT_CALL(*service, IsPassphraseRequired()) | 312 EXPECT_CALL(*service, IsPassphraseRequired()) |
| 313 .WillRepeatedly(Return(false)); | 313 .WillRepeatedly(Return(false)); |
| 314 return; | 314 return; |
| 315 } | 315 } |
| 316 case STATUS_CASE_SYNC_DISABLED_BY_POLICY: { | 316 case STATUS_CASE_SYNC_DISABLED_BY_POLICY: { |
| 317 EXPECT_CALL(*service, IsManaged()).WillRepeatedly(Return(true)); | 317 EXPECT_CALL(*service, IsManaged()).WillRepeatedly(Return(true)); |
| 318 EXPECT_CALL(*service, IsFirstSetupComplete()) | 318 EXPECT_CALL(*service, IsFirstSetupComplete()) |
| 319 .WillRepeatedly(Return(false)); | 319 .WillRepeatedly(Return(false)); |
| 320 EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(false)); | 320 EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(false)); |
| 321 EXPECT_CALL(*service, IsPassphraseRequired()) | 321 EXPECT_CALL(*service, IsPassphraseRequired()) |
| 322 .WillRepeatedly(Return(false)); | 322 .WillRepeatedly(Return(false)); |
| 323 syncer::SyncBackendHost::Status status; | 323 syncer::SyncEngine::Status status; |
| 324 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) | 324 EXPECT_CALL(*service, QueryDetailedSyncStatus(_)) |
| 325 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); | 325 .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false))); |
| 326 EXPECT_CALL(*service, HasUnrecoverableError()) | 326 EXPECT_CALL(*service, HasUnrecoverableError()) |
| 327 .WillRepeatedly(Return(false)); | 327 .WillRepeatedly(Return(false)); |
| 328 return; | 328 return; |
| 329 } | 329 } |
| 330 default: | 330 default: |
| 331 NOTREACHED(); | 331 NOTREACHED(); |
| 332 } | 332 } |
| 333 } | 333 } |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 sync_ui_util::GetStatusLabels(profile.get(), &service, *signin, | 516 sync_ui_util::GetStatusLabels(profile.get(), &service, *signin, |
| 517 sync_ui_util::PLAIN_TEXT, | 517 sync_ui_util::PLAIN_TEXT, |
| 518 &second_actionable_error_status_label, | 518 &second_actionable_error_status_label, |
| 519 &link_label, &action_type); | 519 &link_label, &action_type); |
| 520 // Expect a passive message instead of a call to action. | 520 // Expect a passive message instead of a call to action. |
| 521 EXPECT_EQ(sync_ui_util::NO_ACTION, action_type); | 521 EXPECT_EQ(sync_ui_util::NO_ACTION, action_type); |
| 522 | 522 |
| 523 EXPECT_NE(first_actionable_error_status_label, | 523 EXPECT_NE(first_actionable_error_status_label, |
| 524 second_actionable_error_status_label); | 524 second_actionable_error_status_label); |
| 525 } | 525 } |
| OLD | NEW |