Skip to content

Commit 19f3a4a

Browse files
committed
Merge branch 'main-ose' into 1245-push-support-unifiedpush-connector-3x
2 parents f961096 + 0012dec commit 19f3a4a

33 files changed

+876
-591
lines changed

.github/ISSUE_TEMPLATE/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
blank_issues_enabled: false
1+
blank_issues_enabled: true
22
contact_links:
33
- name: DAVx⁵ Community Support
44
url: https://github.com/bitfireAT/davx5-ose/discussions

.github/ISSUE_TEMPLATE/qualified-bug.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
name: Qualified Bug Report
2-
description: "[Developers only] For qualified bug reports. (Use Discussions if unsure.)"
2+
description: "For qualified bug reports. (Use Discussions if unsure.)"
3+
type: bug
34
labels: ["bug"]
45
body:
56
- type: checkboxes

.github/ISSUE_TEMPLATE/qualified-feature.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
name: Qualified Feature Request
2-
description: "[Developers only] For qualified feature requests. (Use Discussions if unsure.)"
2+
description: "For qualified feature requests. (Use Discussions if unsure.)"
3+
type: feature
34
labels: ["enhancement"]
45
body:
56
- type: checkboxes

app/src/androidTest/kotlin/at/bitfire/davdroid/resource/LocalAddressBookStoreTest.kt

+13-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ class LocalAddressBookStoreTest {
6363
hiltRule.inject()
6464

6565
addressBookAccountType = context.getString(R.string.account_type_address_book)
66-
removeAddressBooks()
6766

6867
account = TestAccount.create()
6968
service = Service(
@@ -82,9 +81,22 @@ class LocalAddressBookStoreTest {
8281
@After
8382
fun tearDown() {
8483
TestAccount.remove(account)
84+
removeAddressBooks()
8585
}
8686

8787

88+
@Test
89+
fun test_accountName_removesSpecialChars() {
90+
// Should remove iso control characters and `, ", ',
91+
val collection = mockk<Collection> {
92+
every { id } returns 1
93+
every { url } returns "https://example.com/addressbook/funnyfriends".toHttpUrl()
94+
every { displayName } returns "手 M's_\"F-e\"\\(´д`)/;æøå% äöü #42"
95+
every { serviceId } returns service.id
96+
}
97+
assertEquals("手 Ms_F-e\\(´д)/;æøå% äöü #42 (Test Account) #1", localAddressBookStore.accountName(collection))
98+
}
99+
88100
@Test
89101
fun test_accountName_missingService() {
90102
val collection = mockk<Collection> {

app/src/androidTest/kotlin/at/bitfire/davdroid/resource/LocalAddressBookTest.kt

+89-57
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import dagger.hilt.android.qualifiers.ApplicationContext
1818
import dagger.hilt.android.testing.HiltAndroidRule
1919
import dagger.hilt.android.testing.HiltAndroidTest
2020
import ezvcard.property.Telephone
21-
import org.junit.After
2221
import org.junit.AfterClass
2322
import org.junit.Assert.assertEquals
2423
import org.junit.Assert.assertFalse
@@ -28,6 +27,7 @@ import org.junit.BeforeClass
2827
import org.junit.ClassRule
2928
import org.junit.Rule
3029
import org.junit.Test
30+
import java.io.FileNotFoundException
3131
import java.util.LinkedList
3232
import javax.inject.Inject
3333

@@ -37,24 +37,17 @@ class LocalAddressBookTest {
3737
@Inject @ApplicationContext
3838
lateinit var context: Context
3939

40+
@Inject
41+
lateinit var localTestAddressBookProvider: LocalTestAddressBookProvider
42+
4043
@get:Rule
4144
val hiltRule = HiltAndroidRule(this)
4245

4346
val account = Account("Test Account", "Test Account Type")
44-
lateinit var addressBook: LocalTestAddressBook
45-
4647

4748
@Before
4849
fun setUp() {
4950
hiltRule.inject()
50-
51-
addressBook = LocalTestAddressBook.create(context, account, provider)
52-
}
53-
54-
@After
55-
fun tearDown() {
56-
// remove address book
57-
addressBook.remove()
5851
}
5952

6053

@@ -63,59 +56,98 @@ class LocalAddressBookTest {
6356
*/
6457
@Test
6558
fun test_renameAccount_retainsContacts() {
66-
// insert contact with data row
67-
val uid = "12345"
68-
val contact = Contact(
69-
uid = uid,
70-
displayName = "Test Contact",
71-
phoneNumbers = LinkedList(listOf(LabeledProperty(Telephone("1234567890"))))
72-
)
73-
val uri = LocalContact(addressBook, contact, null, null, 0).add()
74-
val id = ContentUris.parseId(uri)
75-
val localContact = addressBook.findContactById(id)
76-
localContact.resetDirty()
77-
assertFalse("Contact is dirty before moving", addressBook.isContactDirty(id))
78-
79-
// rename address book
80-
val newName = "New Name"
81-
addressBook.renameAccount(newName)
82-
assertEquals(newName, addressBook.addressBookAccount.name)
83-
84-
// check whether contact is still here (including data rows) and not dirty
85-
val result = addressBook.findContactById(id)
86-
assertFalse("Contact is dirty after moving", addressBook.isContactDirty(id))
87-
88-
val contact2 = result.getContact()
89-
assertEquals(uid, contact2.uid)
90-
assertEquals("Test Contact", contact2.displayName)
91-
assertEquals("1234567890", contact2.phoneNumbers.first().component1().text)
59+
localTestAddressBookProvider.provide(account, provider) { addressBook ->
60+
// insert contact with data row
61+
val uid = "12345"
62+
val contact = Contact(
63+
uid = uid,
64+
displayName = "Test Contact",
65+
phoneNumbers = LinkedList(listOf(LabeledProperty(Telephone("1234567890"))))
66+
)
67+
val uri = LocalContact(addressBook, contact, null, null, 0).add()
68+
val id = ContentUris.parseId(uri)
69+
val localContact = addressBook.findContactById(id)
70+
localContact.resetDirty()
71+
assertFalse("Contact is dirty before moving", isContactDirty(addressBook, id))
72+
73+
// rename address book
74+
val newName = "New Name"
75+
addressBook.renameAccount(newName)
76+
assertEquals(newName, addressBook.addressBookAccount.name)
77+
78+
// check whether contact is still here (including data rows) and not dirty
79+
val result = addressBook.findContactById(id)
80+
assertFalse("Contact is dirty after moving", isContactDirty(addressBook, id))
81+
82+
val contact2 = result.getContact()
83+
assertEquals(uid, contact2.uid)
84+
assertEquals("Test Contact", contact2.displayName)
85+
assertEquals("1234567890", contact2.phoneNumbers.first().component1().text)
86+
}
9287
}
9388

9489
/**
9590
* Tests whether groups are moved (and not lost) when an address book is renamed.
9691
*/
9792
@Test
9893
fun test_renameAccount_retainsGroups() {
99-
// insert group
100-
val localGroup = LocalGroup(addressBook, Contact(displayName = "Test Group"), null, null, 0)
101-
val uri = localGroup.add()
102-
val id = ContentUris.parseId(uri)
103-
104-
// make sure it's not dirty
105-
localGroup.clearDirty(null, null, null)
106-
assertFalse("Group is dirty before moving", addressBook.isGroupDirty(id))
107-
108-
// rename address book
109-
val newName = "New Name"
110-
assertTrue(addressBook.renameAccount(newName))
111-
assertEquals(newName, addressBook.addressBookAccount.name)
112-
113-
// check whether group is still here and not dirty
114-
val result = addressBook.findGroupById(id)
115-
assertFalse("Group is dirty after moving", addressBook.isGroupDirty(id))
116-
117-
val group = result.getContact()
118-
assertEquals("Test Group", group.displayName)
94+
localTestAddressBookProvider.provide(account, provider) { addressBook ->
95+
// insert group
96+
val localGroup = LocalGroup(addressBook, Contact(displayName = "Test Group"), null, null, 0)
97+
val uri = localGroup.add()
98+
val id = ContentUris.parseId(uri)
99+
100+
// make sure it's not dirty
101+
localGroup.clearDirty(null, null, null)
102+
assertFalse("Group is dirty before moving", isGroupDirty(addressBook, id))
103+
104+
// rename address book
105+
val newName = "New Name"
106+
assertTrue(addressBook.renameAccount(newName))
107+
assertEquals(newName, addressBook.addressBookAccount.name)
108+
109+
// check whether group is still here and not dirty
110+
val result = addressBook.findGroupById(id)
111+
assertFalse("Group is dirty after moving", isGroupDirty(addressBook, id))
112+
113+
val group = result.getContact()
114+
assertEquals("Test Group", group.displayName)
115+
}
116+
}
117+
118+
119+
// helpers
120+
121+
/**
122+
* Returns the dirty flag of the given contact.
123+
*
124+
* @return true if the contact is dirty, false otherwise
125+
*
126+
* @throws FileNotFoundException if the contact can't be found
127+
*/
128+
fun isContactDirty(adddressBook: LocalAddressBook, id: Long): Boolean {
129+
val uri = ContentUris.withAppendedId(adddressBook.rawContactsSyncUri(), id)
130+
provider!!.query(uri, arrayOf(ContactsContract.RawContacts.DIRTY), null, null, null)?.use { cursor ->
131+
if (cursor.moveToFirst())
132+
return cursor.getInt(0) != 0
133+
}
134+
throw FileNotFoundException()
135+
}
136+
137+
/**
138+
* Returns the dirty flag of the given contact group.
139+
*
140+
* @return true if the group is dirty, false otherwise
141+
*
142+
* @throws FileNotFoundException if the group can't be found
143+
*/
144+
fun isGroupDirty(adddressBook: LocalAddressBook, id: Long): Boolean {
145+
val uri = ContentUris.withAppendedId(adddressBook.groupsSyncUri(), id)
146+
provider!!.query(uri, arrayOf(ContactsContract.Groups.DIRTY), null, null, null)?.use { cursor ->
147+
if (cursor.moveToFirst())
148+
return cursor.getInt(0) != 0
149+
}
150+
throw FileNotFoundException()
119151
}
120152

121153

0 commit comments

Comments
 (0)