177 lines
5.9 KiB
Kotlin
177 lines
5.9 KiB
Kotlin
|
|
/*
|
||
|
|
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
|
||
|
|
*/
|
||
|
|
|
||
|
|
package at.bitfire.davdroid.resource
|
||
|
|
|
||
|
|
import android.Manifest
|
||
|
|
import android.accounts.Account
|
||
|
|
import android.content.ContentProviderClient
|
||
|
|
import android.content.ContentUris
|
||
|
|
import android.content.Context
|
||
|
|
import android.provider.ContactsContract
|
||
|
|
import androidx.test.platform.app.InstrumentationRegistry
|
||
|
|
import androidx.test.rule.GrantPermissionRule
|
||
|
|
import at.bitfire.vcard4android.Contact
|
||
|
|
import at.bitfire.vcard4android.LabeledProperty
|
||
|
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||
|
|
import dagger.hilt.android.testing.HiltAndroidRule
|
||
|
|
import dagger.hilt.android.testing.HiltAndroidTest
|
||
|
|
import ezvcard.property.Telephone
|
||
|
|
import org.junit.AfterClass
|
||
|
|
import org.junit.Assert.assertEquals
|
||
|
|
import org.junit.Assert.assertFalse
|
||
|
|
import org.junit.Assert.assertTrue
|
||
|
|
import org.junit.Before
|
||
|
|
import org.junit.BeforeClass
|
||
|
|
import org.junit.ClassRule
|
||
|
|
import org.junit.Rule
|
||
|
|
import org.junit.Test
|
||
|
|
import java.io.FileNotFoundException
|
||
|
|
import java.util.LinkedList
|
||
|
|
import java.util.Optional
|
||
|
|
import javax.inject.Inject
|
||
|
|
|
||
|
|
@HiltAndroidTest
|
||
|
|
class LocalAddressBookTest {
|
||
|
|
|
||
|
|
@Inject @ApplicationContext
|
||
|
|
lateinit var context: Context
|
||
|
|
|
||
|
|
@Inject
|
||
|
|
lateinit var localTestAddressBookProvider: LocalTestAddressBookProvider
|
||
|
|
|
||
|
|
@get:Rule
|
||
|
|
val hiltRule = HiltAndroidRule(this)
|
||
|
|
|
||
|
|
val account = Account("Test Account", "Test Account Type")
|
||
|
|
|
||
|
|
@Before
|
||
|
|
fun setUp() {
|
||
|
|
hiltRule.inject()
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Tests whether contacts are moved (and not lost) when an address book is renamed.
|
||
|
|
*/
|
||
|
|
@Test
|
||
|
|
fun test_renameAccount_retainsContacts() {
|
||
|
|
localTestAddressBookProvider.provide(account, provider) { addressBook ->
|
||
|
|
// insert contact with data row
|
||
|
|
val uid = "12345"
|
||
|
|
val contact = Contact(
|
||
|
|
uid = uid,
|
||
|
|
displayName = "Test Contact",
|
||
|
|
phoneNumbers = LinkedList(listOf(LabeledProperty(Telephone("1234567890"))))
|
||
|
|
)
|
||
|
|
val uri = LocalContact(addressBook, contact, null, null, 0).add()
|
||
|
|
val id = ContentUris.parseId(uri)
|
||
|
|
val localContact = addressBook.findContactById(id)
|
||
|
|
localContact.resetDirty()
|
||
|
|
assertFalse("Contact is dirty before moving", isContactDirty(addressBook, id))
|
||
|
|
|
||
|
|
// rename address book
|
||
|
|
val newName = "New Name"
|
||
|
|
addressBook.renameAccount(newName)
|
||
|
|
assertEquals(newName, addressBook.addressBookAccount.name)
|
||
|
|
|
||
|
|
// check whether contact is still here (including data rows) and not dirty
|
||
|
|
val result = addressBook.findContactById(id)
|
||
|
|
assertFalse("Contact is dirty after moving", isContactDirty(addressBook, id))
|
||
|
|
|
||
|
|
val contact2 = result.getContact()
|
||
|
|
assertEquals(uid, contact2.uid)
|
||
|
|
assertEquals("Test Contact", contact2.displayName)
|
||
|
|
assertEquals("1234567890", contact2.phoneNumbers.first().component1().text)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Tests whether groups are moved (and not lost) when an address book is renamed.
|
||
|
|
*/
|
||
|
|
@Test
|
||
|
|
fun test_renameAccount_retainsGroups() {
|
||
|
|
localTestAddressBookProvider.provide(account, provider) { addressBook ->
|
||
|
|
// insert group
|
||
|
|
val localGroup = LocalGroup(addressBook, Contact(displayName = "Test Group"), null, null, 0)
|
||
|
|
val uri = localGroup.add()
|
||
|
|
val id = ContentUris.parseId(uri)
|
||
|
|
|
||
|
|
// make sure it's not dirty
|
||
|
|
localGroup.clearDirty(Optional.empty(), null, null)
|
||
|
|
assertFalse("Group is dirty before moving", isGroupDirty(addressBook, id))
|
||
|
|
|
||
|
|
// rename address book
|
||
|
|
val newName = "New Name"
|
||
|
|
assertTrue(addressBook.renameAccount(newName))
|
||
|
|
assertEquals(newName, addressBook.addressBookAccount.name)
|
||
|
|
|
||
|
|
// check whether group is still here and not dirty
|
||
|
|
val result = addressBook.findGroupById(id)
|
||
|
|
assertFalse("Group is dirty after moving", isGroupDirty(addressBook, id))
|
||
|
|
|
||
|
|
val group = result.getContact()
|
||
|
|
assertEquals("Test Group", group.displayName)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// helpers
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns the dirty flag of the given contact.
|
||
|
|
*
|
||
|
|
* @return true if the contact is dirty, false otherwise
|
||
|
|
*
|
||
|
|
* @throws FileNotFoundException if the contact can't be found
|
||
|
|
*/
|
||
|
|
fun isContactDirty(adddressBook: LocalAddressBook, id: Long): Boolean {
|
||
|
|
val uri = ContentUris.withAppendedId(adddressBook.rawContactsSyncUri(), id)
|
||
|
|
provider.query(uri, arrayOf(ContactsContract.RawContacts.DIRTY), null, null, null)?.use { cursor ->
|
||
|
|
if (cursor.moveToFirst())
|
||
|
|
return cursor.getInt(0) != 0
|
||
|
|
}
|
||
|
|
throw FileNotFoundException()
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns the dirty flag of the given contact group.
|
||
|
|
*
|
||
|
|
* @return true if the group is dirty, false otherwise
|
||
|
|
*
|
||
|
|
* @throws FileNotFoundException if the group can't be found
|
||
|
|
*/
|
||
|
|
fun isGroupDirty(adddressBook: LocalAddressBook, id: Long): Boolean {
|
||
|
|
val uri = ContentUris.withAppendedId(adddressBook.groupsSyncUri(), id)
|
||
|
|
provider.query(uri, arrayOf(ContactsContract.Groups.DIRTY), null, null, null)?.use { cursor ->
|
||
|
|
if (cursor.moveToFirst())
|
||
|
|
return cursor.getInt(0) != 0
|
||
|
|
}
|
||
|
|
throw FileNotFoundException()
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
companion object {
|
||
|
|
|
||
|
|
@JvmField
|
||
|
|
@ClassRule
|
||
|
|
val permissionRule = GrantPermissionRule.grant(Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS)!!
|
||
|
|
|
||
|
|
private lateinit var provider: ContentProviderClient
|
||
|
|
|
||
|
|
@BeforeClass
|
||
|
|
@JvmStatic
|
||
|
|
fun connect() {
|
||
|
|
val context = InstrumentationRegistry.getInstrumentation().context
|
||
|
|
provider = context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY)!!
|
||
|
|
}
|
||
|
|
|
||
|
|
@AfterClass
|
||
|
|
@JvmStatic
|
||
|
|
fun disconnect() {
|
||
|
|
provider.close()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|