-
-
Notifications
You must be signed in to change notification settings - Fork 6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
372f939
commit 777a91a
Showing
11 changed files
with
757 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 114 additions & 0 deletions
114
sms-exporter/lib/src/test/java/org/signal/smsexporter/InMemoryContentProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package org.signal.smsexporter | ||
|
||
import android.content.ContentProvider | ||
import android.content.ContentValues | ||
import android.database.Cursor | ||
import android.database.sqlite.SQLiteDatabase | ||
import android.database.sqlite.SQLiteOpenHelper | ||
import android.net.Uri | ||
import android.provider.Telephony | ||
import androidx.test.core.app.ApplicationProvider | ||
|
||
/** | ||
* Provides a content provider which reads and writes to an in-memory database. | ||
*/ | ||
class InMemoryContentProvider : ContentProvider() { | ||
|
||
private val database: InMemoryDatabase = InMemoryDatabase() | ||
|
||
override fun onCreate(): Boolean { | ||
return false | ||
} | ||
|
||
override fun query(p0: Uri, p1: Array<out String>?, p2: String?, p3: Array<out String>?, p4: String?): Cursor? { | ||
val tableName = if (p0.pathSegments.isNotEmpty()) p0.lastPathSegment else p0.authority | ||
return database.readableDatabase.query(tableName, p1, p2, p3, p4, null, null) | ||
} | ||
|
||
override fun getType(p0: Uri): String? { | ||
return null | ||
} | ||
|
||
override fun insert(p0: Uri, p1: ContentValues?): Uri? { | ||
val tableName = if (p0.pathSegments.isNotEmpty()) p0.lastPathSegment else p0.authority | ||
val id = database.writableDatabase.insert(tableName, null, p1) | ||
return if (id == -1L) { | ||
null | ||
} else { | ||
p0.buildUpon().appendPath("$id").build() | ||
} | ||
} | ||
|
||
override fun delete(p0: Uri, p1: String?, p2: Array<out String>?): Int { | ||
return -1 | ||
} | ||
|
||
override fun update(p0: Uri, p1: ContentValues?, p2: String?, p3: Array<out String>?): Int { | ||
return -1 | ||
} | ||
|
||
private class InMemoryDatabase : SQLiteOpenHelper(ApplicationProvider.getApplicationContext(), null, null, 1) { | ||
override fun onCreate(db: SQLiteDatabase) { | ||
db.execSQL( | ||
""" | ||
CREATE TABLE sms ( | ||
${Telephony.Sms._ID} INTEGER PRIMARY KEY AUTOINCREMENT, | ||
${Telephony.Sms.ADDRESS} TEXT, | ||
${Telephony.Sms.DATE_SENT} INTEGER, | ||
${Telephony.Sms.DATE} INTEGER, | ||
${Telephony.Sms.BODY} TEXT, | ||
${Telephony.Sms.READ} INTEGER, | ||
${Telephony.Sms.TYPE} INTEGER | ||
); | ||
""".trimIndent() | ||
) | ||
|
||
db.execSQL( | ||
""" | ||
CREATE TABLE mms ( | ||
${Telephony.Mms._ID} INTEGER PRIMARY KEY AUTOINCREMENT, | ||
${Telephony.Mms.THREAD_ID} INTEGER, | ||
${Telephony.Mms.DATE} INTEGER, | ||
${Telephony.Mms.DATE_SENT} INTEGER, | ||
${Telephony.Mms.MESSAGE_BOX} INTEGER, | ||
${Telephony.Mms.READ} INTEGER, | ||
${Telephony.Mms.CONTENT_TYPE} TEXT, | ||
${Telephony.Mms.MESSAGE_TYPE} INTEGER, | ||
${Telephony.Mms.MMS_VERSION} INTEGER, | ||
${Telephony.Mms.MESSAGE_CLASS} TEXT, | ||
${Telephony.Mms.PRIORITY} INTEGER, | ||
${Telephony.Mms.TRANSACTION_ID} TEXT, | ||
${Telephony.Mms.RESPONSE_STATUS} INTEGER, | ||
${Telephony.Mms.SEEN} INTEGER | ||
); | ||
""".trimIndent() | ||
) | ||
|
||
db.execSQL( | ||
""" | ||
CREATE TABLE part ( | ||
${Telephony.Mms.Part._ID} INTEGER PRIMARY KEY AUTOINCREMENT, | ||
${Telephony.Mms.Part.MSG_ID} INTEGER, | ||
${Telephony.Mms.Part.CONTENT_TYPE} TEXT, | ||
${Telephony.Mms.Part.CONTENT_ID} INTEGER, | ||
${Telephony.Mms.Part.TEXT} TEXT | ||
) | ||
""".trimIndent() | ||
) | ||
|
||
db.execSQL( | ||
""" | ||
CREATE TABLE addr ( | ||
${Telephony.Mms.Addr._ID} INTEGER PRIMARY KEY AUTOINCREMENT, | ||
${Telephony.Mms.Addr.ADDRESS} TEXT, | ||
${Telephony.Mms.Addr.CHARSET} INTEGER, | ||
${Telephony.Mms.Addr.TYPE} INTEGER | ||
) | ||
""".trimIndent() | ||
) | ||
} | ||
|
||
override fun onUpgrade(db: SQLiteDatabase, p1: Int, p2: Int) = Unit | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
sms-exporter/lib/src/test/java/org/signal/smsexporter/TestUtils.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package org.signal.smsexporter | ||
|
||
import android.provider.Telephony | ||
import org.robolectric.shadows.ShadowContentResolver | ||
import java.util.UUID | ||
|
||
object TestUtils { | ||
fun generateSmsMessage( | ||
id: String = UUID.randomUUID().toString(), | ||
address: String = "+15555060177", | ||
dateReceived: Long = 2, | ||
dateSent: Long = 1, | ||
isRead: Boolean = false, | ||
isOutgoing: Boolean = false, | ||
body: String = "Hello, $id" | ||
): ExportableMessage.Sms { | ||
return ExportableMessage.Sms(id, address, dateReceived, dateSent, isRead, isOutgoing, body) | ||
} | ||
|
||
fun generateMmsMessage( | ||
id: String = UUID.randomUUID().toString(), | ||
addresses: Set<String> = setOf("+15555060177"), | ||
dateReceived: Long = 2, | ||
dateSent: Long = 1, | ||
isRead: Boolean = false, | ||
isOutgoing: Boolean = false, | ||
parts: List<ExportableMessage.Mms.Part> = listOf(ExportableMessage.Mms.Part.Text("Hello, $id")), | ||
sender: CharSequence = "+15555060177" | ||
): ExportableMessage.Mms { | ||
return ExportableMessage.Mms(id, addresses, dateReceived, dateSent, isRead, isOutgoing, parts, sender) | ||
} | ||
|
||
fun setUpSmsContentProviderAndResolver() { | ||
ShadowContentResolver.registerProviderInternal( | ||
Telephony.Sms.CONTENT_URI.authority, | ||
InMemoryContentProvider() | ||
) | ||
} | ||
|
||
fun setUpMmsContentProviderAndResolver() { | ||
ShadowContentResolver.registerProviderInternal( | ||
Telephony.Mms.CONTENT_URI.authority, | ||
InMemoryContentProvider() | ||
) | ||
} | ||
} |
133 changes: 133 additions & 0 deletions
133
...ter/lib/src/test/java/org/signal/smsexporter/internal/mms/ExportMmsMessagesUseCaseTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package org.signal.smsexporter.internal.mms | ||
|
||
import android.content.Context | ||
import android.net.Uri | ||
import android.provider.Telephony | ||
import androidx.test.core.app.ApplicationProvider | ||
import org.junit.Assert.assertEquals | ||
import org.junit.Before | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
import org.robolectric.RobolectricTestRunner | ||
import org.signal.core.util.CursorUtil | ||
import org.signal.smsexporter.ExportableMessage | ||
import org.signal.smsexporter.TestUtils | ||
|
||
@RunWith(RobolectricTestRunner::class) | ||
class ExportMmsMessagesUseCaseTest { | ||
|
||
@Before | ||
fun setUp() { | ||
TestUtils.setUpMmsContentProviderAndResolver() | ||
} | ||
|
||
@Test | ||
fun `Given an MMS message, when I execute, then I expect an MMS record to be created`() { | ||
// GIVEN | ||
val mmsMessage = TestUtils.generateMmsMessage() | ||
val threadUseCaseOutput = GetOrCreateMmsThreadIdsUseCase.Output(mmsMessage, 1) | ||
|
||
// WHEN | ||
val result = ExportMmsMessagesUseCase.execute( | ||
ApplicationProvider.getApplicationContext(), | ||
threadUseCaseOutput, | ||
false | ||
) | ||
|
||
// THEN | ||
result.either( | ||
onSuccess = { | ||
validateExportedMessage(mmsMessage) | ||
}, | ||
onFailure = { | ||
throw it | ||
} | ||
) | ||
} | ||
|
||
@Test | ||
fun `Given an MMS message that already exists, when I execute and check for existence, then I expect no new MMS record to be created`() { | ||
// GIVEN | ||
val mmsMessage = TestUtils.generateMmsMessage() | ||
val threadUseCaseOutput = GetOrCreateMmsThreadIdsUseCase.Output(mmsMessage, 1) | ||
ExportMmsMessagesUseCase.execute( | ||
ApplicationProvider.getApplicationContext(), | ||
threadUseCaseOutput, | ||
false | ||
) | ||
|
||
// WHEN | ||
val result = ExportMmsMessagesUseCase.execute( | ||
ApplicationProvider.getApplicationContext(), | ||
threadUseCaseOutput, | ||
true | ||
) | ||
|
||
// THEN | ||
result.either( | ||
onSuccess = { | ||
validateExportedMessage(mmsMessage) | ||
}, | ||
onFailure = { | ||
throw it | ||
} | ||
) | ||
} | ||
|
||
@Test | ||
fun `Given an MMS message that already exists, when I execute and do not check for existence, then I expect a duplicate MMS record to be created`() { | ||
// GIVEN | ||
val mmsMessage = TestUtils.generateMmsMessage() | ||
val threadUseCaseOutput = GetOrCreateMmsThreadIdsUseCase.Output(mmsMessage, 1) | ||
ExportMmsMessagesUseCase.execute( | ||
ApplicationProvider.getApplicationContext(), | ||
threadUseCaseOutput, | ||
false | ||
) | ||
|
||
// WHEN | ||
val result = ExportMmsMessagesUseCase.execute( | ||
ApplicationProvider.getApplicationContext(), | ||
threadUseCaseOutput, | ||
false | ||
) | ||
|
||
// THEN | ||
result.either( | ||
onSuccess = { | ||
validateExportedMessage(mmsMessage, expectedRowCount = 2) | ||
}, | ||
onFailure = { | ||
throw it | ||
} | ||
) | ||
} | ||
|
||
private fun validateExportedMessage( | ||
mms: ExportableMessage.Mms, | ||
expectedRowCount: Int = 1, | ||
threadId: Long = 1L | ||
) { | ||
val context: Context = ApplicationProvider.getApplicationContext() | ||
val baseUri: Uri = Telephony.Mms.CONTENT_URI | ||
val transactionId = ExportMmsMessagesUseCase.getTransactionId(mms) | ||
|
||
context.contentResolver.query( | ||
baseUri, | ||
null, | ||
"${Telephony.Mms.TRANSACTION_ID} = ?", | ||
arrayOf(transactionId), | ||
null, | ||
null | ||
)?.use { | ||
it.moveToFirst() | ||
assertEquals(expectedRowCount, it.count) | ||
assertEquals(threadId, CursorUtil.requireLong(it, Telephony.Mms.THREAD_ID)) | ||
assertEquals(mms.dateReceived, CursorUtil.requireLong(it, Telephony.Mms.DATE)) | ||
assertEquals(mms.dateSent, CursorUtil.requireLong(it, Telephony.Mms.DATE_SENT)) | ||
assertEquals(if (mms.isOutgoing) Telephony.Mms.MESSAGE_BOX_SENT else Telephony.Mms.MESSAGE_BOX_INBOX, CursorUtil.requireInt(it, Telephony.Mms.MESSAGE_BOX)) | ||
assertEquals(mms.isRead, CursorUtil.requireBoolean(it, Telephony.Mms.READ)) | ||
assertEquals(transactionId, CursorUtil.requireString(it, Telephony.Mms.TRANSACTION_ID)) | ||
} ?: org.junit.Assert.fail("Content Resolver returned a null cursor") | ||
} | ||
} |
Oops, something went wrong.