adding test

This commit is contained in:
Mariotaku Lee 2016-12-02 12:36:50 +08:00
parent a9fff789f8
commit 756a6dbb4d
9 changed files with 277 additions and 96 deletions

View File

@ -37,6 +37,8 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
String TWIDERE_PROJECT_EMAIL = "twidere.project@gmail.com";
String TWIDERE_PACKAGE_NAME = "org.mariotaku.twidere";
String ACCOUNT_TYPE = "org.mariotaku.twidere.account";
String LOGTAG = TWIDERE_APP_NAME;
String USER_NICKNAME_PREFERENCES_NAME = "user_nicknames";

View File

@ -175,6 +175,7 @@ dependencies {
compile 'nl.komponents.kovenant:kovenant:3.3.0'
compile 'nl.komponents.kovenant:kovenant-android:3.3.0'
compile 'nl.komponents.kovenant:kovenant-functional:3.3.0'
compile 'nl.komponents.kovenant:kovenant-combine:3.3.0'
}
task svgToDrawable(type: SvgDrawableTask) {

View File

@ -1,38 +0,0 @@
package org.mariotaku.twidere.activity
import android.net.Uri
import org.junit.Assert.assertEquals
import org.junit.Test
import org.mariotaku.twidere.fragment.ImagePageFragment
/**
* Created by mariotaku on 16/3/3.
*/
class ImagePageFragmentTest {
@Test
@Throws(Exception::class)
fun testReplaceTwitterMediaUri() {
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:large",
ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://pbs.twimg.com/media/DEADBEEF.png:large")).toString())
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:orig",
ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://pbs.twimg.com/media/DEADBEEF.png:orig")).toString())
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:large",
ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://pbs.twimg.com/media/DEADBEEF.jpg:large")).toString())
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:large",
ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://pbs.twimg.com/media/DEADBEEF.jpg:orig")).toString())
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png",
ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://pbs.twimg.com/media/DEADBEEF.jpg")).toString())
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:",
ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://pbs.twimg.com/media/DEADBEEF.jpg:")).toString())
assertEquals("https://example.com/media/DEADBEEF.jpg",
ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://example.com/media/DEADBEEF.jpg")).toString())
}
}

View File

@ -0,0 +1,41 @@
package org.mariotaku.twidere.test.account
import android.accounts.Account
import android.accounts.AccountManager
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.mariotaku.ktextension.Bundle
import org.mariotaku.twidere.TwidereConstants.ACCOUNT_TYPE
import org.mariotaku.twidere.extension.model.account_name
import org.mariotaku.twidere.model.util.ParcelableAccountUtils
import org.mariotaku.twidere.provider.TwidereDataStore
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts
import org.mariotaku.twidere.util.support.AccountManagerSupport
/**
* Created by mariotaku on 2016/12/2.
*/
@RunWith(AndroidJUnit4::class)
class MigrationTest {
@Test
fun testMigration() {
val context = InstrumentationRegistry.getTargetContext()
val am = AccountManager.get(context)
am.getAccountsByType(ACCOUNT_TYPE).map { account ->
AccountManagerSupport.removeAccount(am, account, null, null, null)
}
ParcelableAccountUtils.getAccounts(context).forEach { pAccount ->
val account = Account(pAccount.account_name, ACCOUNT_TYPE)
val userdata = Bundle {
this[Accounts.ACCOUNT_KEY]
}
am.addAccountExplicitly(account, null, userdata)
}
}
}

View File

@ -0,0 +1,87 @@
package org.mariotaku.twidere.util.support;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.RequiresApi;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* Created by mariotaku on 2016/12/2.
*/
public class AccountManagerSupport {
public static AccountManagerFuture<Bundle> removeAccount(AccountManager am, Account account,
Activity activity,
final AccountManagerCallback<Bundle> callback,
Handler handler) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
return AccountManagerSupportL.removeAccount(am, account, activity, callback, handler);
}
//noinspection deprecation
final AccountManagerFuture<Boolean> future = am.removeAccount(account, new AccountManagerCallback<Boolean>() {
@Override
public void run(AccountManagerFuture<Boolean> future) {
callback.run(new BooleanToBundleAccountManagerFuture(future));
}
}, handler);
return new BooleanToBundleAccountManagerFuture(future);
}
private static class AccountManagerSupportL {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
static AccountManagerFuture<Bundle> removeAccount(AccountManager am, Account account,
Activity activity,
AccountManagerCallback<Bundle> callback,
Handler handler) {
return am.removeAccount(account, activity, callback, handler);
}
}
private static class BooleanToBundleAccountManagerFuture implements AccountManagerFuture<Bundle> {
private final AccountManagerFuture<Boolean> future;
BooleanToBundleAccountManagerFuture(AccountManagerFuture<Boolean> future) {
this.future = future;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return future.cancel(mayInterruptIfRunning);
}
@Override
public boolean isCancelled() {
return future.isCancelled();
}
@Override
public boolean isDone() {
return future.isDone();
}
@Override
public Bundle getResult() throws OperationCanceledException, IOException, AuthenticatorException {
Bundle result = new Bundle();
result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, future.getResult());
return result;
}
@Override
public Bundle getResult(long timeout, TimeUnit unit) throws OperationCanceledException, IOException, AuthenticatorException {
Bundle result = new Bundle();
result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, future.getResult(timeout, unit));
return result;
}
}
}

View File

@ -0,0 +1,52 @@
package org.mariotaku.ktextension
import nl.komponents.kovenant.Deferred
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.deferred
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicReferenceArray
/**
* Created by mariotaku on 2016/12/2.
*/
fun <V, E> combine(promises: List<Promise<V, E>>): Promise<List<V>, E> {
return concreteCombine(promises)
}
fun <V, E> concreteCombine(promises: List<Promise<V, E>>): Promise<List<V>, E> {
val deferred = deferred<List<V>, E>()
val results = AtomicReferenceArray<V>(promises.size)
val successCount = AtomicInteger(promises.size)
fun createArray(): List<V> {
return (0 until results.length()).map { results[it] }
}
fun Promise<V, *>.registerSuccess(idx: Int) {
success { v ->
results.set(idx, v)
if (successCount.decrementAndGet() == 0) {
deferred.resolve(createArray())
}
}
}
fun <V, E> Deferred<V, E>.registerFail(promises: List<Promise<*, E>>) {
val failCount = AtomicInteger(0)
promises.forEach { promise ->
promise.fail { e ->
if (failCount.incrementAndGet() == 1) {
this.reject(e)
}
}
}
}
promises.forEachIndexed { idx, promise ->
promise.registerSuccess(idx)
}
deferred.registerFail(promises)
return deferred.promise
}

View File

@ -19,6 +19,8 @@
package org.mariotaku.twidere.activity
import android.accounts.AccountAuthenticatorResponse
import android.accounts.AccountManager
import android.app.Activity
import android.app.Dialog
import android.content.ContentValues
@ -79,6 +81,7 @@ import org.mariotaku.twidere.util.OAuthPasswordAuthenticator.*
import org.mariotaku.twidere.util.view.ConsumerKeySecretValidator
import java.lang.ref.WeakReference
class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
private var apiUrlFormat: String? = null
private var authType: Int = 0
@ -89,15 +92,66 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
private var noVersionSuffix: Boolean = false
private var signInTask: AbstractSignInTask? = null
override fun afterTextChanged(s: Editable) {
private var accountAuthenticatorResponse: AccountAuthenticatorResponse? = null
private var accountAuthenticatorResult: Bundle? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
accountAuthenticatorResponse = intent.getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE)
accountAuthenticatorResponse?.onRequestContinued()
setContentView(R.layout.activity_sign_in)
if (savedInstanceState != null) {
apiUrlFormat = savedInstanceState.getString(Accounts.API_URL_FORMAT)
authType = savedInstanceState.getInt(Accounts.AUTH_TYPE)
sameOAuthSigningUrl = savedInstanceState.getBoolean(Accounts.SAME_OAUTH_SIGNING_URL)
consumerKey = savedInstanceState.getString(Accounts.CONSUMER_KEY)?.trim()
consumerSecret = savedInstanceState.getString(Accounts.CONSUMER_SECRET)?.trim()
apiChangeTimestamp = savedInstanceState.getLong(EXTRA_API_LAST_CHANGE)
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
val isTwipOMode = authType == AuthType.TWIP_O_MODE
usernamePasswordContainer.visibility = if (isTwipOMode) View.GONE else View.VISIBLE
signInSignUpContainer.orientation = if (isTwipOMode) LinearLayout.VERTICAL else LinearLayout.HORIZONTAL
editUsername.addTextChangedListener(this)
editPassword.addTextChangedListener(this)
signIn.setOnClickListener(this)
signUp.setOnClickListener(this)
passwordSignIn.setOnClickListener(this)
val color = ColorStateList.valueOf(ContextCompat.getColor(this,
R.color.material_light_green))
ViewCompat.setBackgroundTintList(signIn, color)
val consumerKey = preferences.getString(KEY_CONSUMER_KEY, null)
val consumerSecret = preferences.getString(KEY_CONSUMER_SECRET, null)
if (BuildConfig.SHOW_CUSTOM_TOKEN_DIALOG && savedInstanceState == null &&
!preferences.getBoolean(KEY_CONSUMER_KEY_SECRET_SET, false) &&
!Utils.isCustomConsumerKeySecret(consumerKey, consumerSecret)) {
val df = SetConsumerKeySecretDialogFragment()
df.isCancelable = false
df.show(supportFragmentManager, "set_consumer_key_secret")
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
updateSignInType()
setSignInButton()
}
override fun onDestroy() {
loaderManager.destroyLoader(0)
super.onDestroy()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_sign_in, menu)
return true
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_EDIT_API -> {
if (resultCode == Activity.RESULT_OK) {
@ -121,6 +175,27 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
super.onActivityResult(requestCode, resultCode, data)
}
override fun finish() {
accountAuthenticatorResponse?.let { response ->
// send the result bundle back if set, otherwise send an error.
if (accountAuthenticatorResult != null) {
response.onResult(accountAuthenticatorResult)
} else {
response.onError(AccountManager.ERROR_CODE_CANCELED, "canceled")
}
accountAuthenticatorResponse = null
}
super.finish()
}
override fun afterTextChanged(s: Editable) {
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
internal fun updateSignInType() {
when (authType) {
AuthType.XAUTH, AuthType.BASIC -> {
@ -162,16 +237,6 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_sign_in, menu)
return true
}
public override fun onDestroy() {
loaderManager.destroyLoader(0)
super.onDestroy()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
@ -237,54 +302,11 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
super.onSaveInstanceState(outState)
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
setSignInButton()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sign_in)
if (savedInstanceState != null) {
apiUrlFormat = savedInstanceState.getString(Accounts.API_URL_FORMAT)
authType = savedInstanceState.getInt(Accounts.AUTH_TYPE)
sameOAuthSigningUrl = savedInstanceState.getBoolean(Accounts.SAME_OAUTH_SIGNING_URL)
consumerKey = savedInstanceState.getString(Accounts.CONSUMER_KEY)?.trim()
consumerSecret = savedInstanceState.getString(Accounts.CONSUMER_SECRET)?.trim()
apiChangeTimestamp = savedInstanceState.getLong(EXTRA_API_LAST_CHANGE)
}
val isTwipOMode = authType == AuthType.TWIP_O_MODE
usernamePasswordContainer.visibility = if (isTwipOMode) View.GONE else View.VISIBLE
signInSignUpContainer.orientation = if (isTwipOMode) LinearLayout.VERTICAL else LinearLayout.HORIZONTAL
editUsername.addTextChangedListener(this)
editPassword.addTextChangedListener(this)
signIn.setOnClickListener(this)
signUp.setOnClickListener(this)
passwordSignIn.setOnClickListener(this)
val color = ColorStateList.valueOf(ContextCompat.getColor(this,
R.color.material_light_green))
ViewCompat.setBackgroundTintList(signIn, color)
val consumerKey = preferences.getString(KEY_CONSUMER_KEY, null)
val consumerSecret = preferences.getString(KEY_CONSUMER_SECRET, null)
if (BuildConfig.SHOW_CUSTOM_TOKEN_DIALOG && savedInstanceState == null &&
!preferences.getBoolean(KEY_CONSUMER_KEY_SECRET_SET, false) &&
!Utils.isCustomConsumerKeySecret(consumerKey, consumerSecret)) {
val df = SetConsumerKeySecretDialogFragment()
df.isCancelable = false
df.show(supportFragmentManager, "set_consumer_key_secret")
}
updateSignInType()
setSignInButton()
}
internal fun doLogin() {
if (signInTask != null && signInTask!!.status == AsyncTask.Status.RUNNING) {
signInTask!!.cancel(true)

View File

@ -0,0 +1,12 @@
package org.mariotaku.twidere.extension.model
import org.mariotaku.twidere.model.ParcelableAccount
import org.mariotaku.twidere.model.UserKey
/**
* Created by mariotaku on 2016/12/2.
*/
val ParcelableAccount.account_name: String
get() = UserKey(screen_name, account_key.host).toString()

View File

@ -10,7 +10,9 @@ import android.content.Intent
import android.os.Bundle
import android.os.IBinder
import org.mariotaku.ktextension.set
import org.mariotaku.twidere.TwidereConstants
import org.mariotaku.twidere.activity.SignInActivity
import org.mariotaku.twidere.util.support.AccountManagerSupport
/**