Move from AssertJ to AssertK.

Resolves #13841
This commit is contained in:
Jameson Williams 2024-12-12 20:35:57 -06:00 committed by Greyson Parrelli
parent 56d53f0b6a
commit a96c8867ae
13 changed files with 431 additions and 365 deletions

View file

@ -590,7 +590,7 @@ dependencies {
}
testImplementation(testLibs.junit.junit)
testImplementation(testLibs.assertj.core)
testImplementation(testLibs.assertk)
testImplementation(testLibs.androidx.test.core)
testImplementation(testLibs.robolectric.robolectric) {
exclude(group = "com.google.protobuf", module = "protobuf-java")

View file

@ -5,7 +5,7 @@
-dontwarn com.android.support.test.**
-dontwarn sun.reflect.**
-dontwarn sun.misc.**
-dontwarn org.assertj.**
-dontwarn assertk.**
-dontwarn org.hamcrest.**
-dontwarn com.squareup.**

View file

@ -25,7 +25,6 @@ The following dependencies are licensed under Apache License, Version 2.0:
* Android Tracing (https://developer.android.com/jetpack/androidx/releases/tracing#1.0.0)
* AndroidX Futures (https://developer.android.com/topic/libraries/architecture/index.html)
* AndroidX Test Library (https://developer.android.com/testing)
* AssertJ fluent assertions
* AutoValue Annotations (https://github.com/google/auto/tree/master/value)
* Byte Buddy (without dependencies)
* Byte Buddy agent
@ -336,6 +335,7 @@ The following dependencies are licensed under The MIT License:
* annotations (http://robolectric.org)
* framework (http://robolectric.org)
* junit (http://robolectric.org)
* assertk (https://github.com/willowtreeapps/assertk)
* ktlint (https://github.com/pinterest/ktlint)
* ktlint-cli-reporter (https://github.com/pinterest/ktlint)
* ktlint-cli-ruleset-core (https://github.com/pinterest/ktlint)

View file

@ -1,110 +0,0 @@
package org.thoughtcrime.securesms.groups.v2;
import androidx.annotation.NonNull;
import org.junit.Test;
import org.signal.core.util.Base64;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.storageservice.protos.groups.GroupInviteLink;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
import okio.ByteString;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertNull;
public final class GroupInviteLinkUrl_InvalidGroupLinkException_Test {
@Test
public void empty_string() throws GroupInviteLinkUrl.InvalidGroupLinkException, GroupInviteLinkUrl.UnknownGroupLinkVersionException {
assertNull(GroupInviteLinkUrl.fromUri(""));
}
@Test
public void not_a_url_string() throws GroupInviteLinkUrl.InvalidGroupLinkException, GroupInviteLinkUrl.UnknownGroupLinkVersionException {
assertNull(GroupInviteLinkUrl.fromUri("abc"));
}
@Test
public void wrong_host() throws GroupInviteLinkUrl.InvalidGroupLinkException, GroupInviteLinkUrl.UnknownGroupLinkVersionException {
assertNull(GroupInviteLinkUrl.fromUri("https://x.signal.org/#CjQKIAD34MKnGrBkzDztTATwjXt-9LhLLCIG9pgzvmz-NN-AEhCbwyTuxDfP2mrluK779H7o"));
}
@Test
public void wrong_scheme() throws GroupInviteLinkUrl.InvalidGroupLinkException, GroupInviteLinkUrl.UnknownGroupLinkVersionException {
assertNull(GroupInviteLinkUrl.fromUri("http://signal.group/#CjQKIAD34MKnGrBkzDztTATwjXt-9LhLLCIG9pgzvmz-NN-AEhCbwyTuxDfP2mrluK779H7o"));
}
@Test
public void has_path() {
assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri("https://signal.group/not_expected/#CjQKIAD34MKnGrBkzDztTATwjXt-9LhLLCIG9pgzvmz-NN-AEhCbwyTuxDfP2mrluK779H7o"))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
.hasMessage("No path was expected in uri");
}
@Test
public void missing_ref() {
assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri("https://signal.group/"))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
.hasMessage("No reference was in the uri");
}
@Test
public void empty_ref() {
assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri("https://signal.group/#"))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
.hasMessage("No reference was in the uri");
}
@Test
public void bad_base64() {
assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri("https://signal.group/#CAESNAogpQEzURH6BON1bCS264cmTi37Yi6HTOReXZUEHdsBIgSEPCLfiL7k4wCX;mwVi31USVY"))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
.hasCauseExactlyInstanceOf(IOException.class);
}
@Test
public void bad_protobuf() {
assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri("https://signal.group/#CAESNAogpQEzURH6BON1bCS264cmTi37Yi6HTOReXZUEHdsBIgSEPCLfiL7k4wCXmwVi31USVY"))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
.hasCauseExactlyInstanceOf(IllegalStateException.class);
}
@Test
public void version_999_url() {
String url = "https://signal.group/#uj4zCiDMSxlNUvF4bQ3z3fYzGyZTFbJ1xEqWbPE3uZSD8bjOrxIP8NxV-0GUz3jpxMLR1rN3";
assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri(url))
.isInstanceOf(GroupInviteLinkUrl.UnknownGroupLinkVersionException.class)
.hasMessage("Url contains no known group link content");
}
@Test
public void bad_master_key_length() {
byte[] masterKeyBytes = Util.getSecretBytes(33);
GroupLinkPassword password = GroupLinkPassword.createNew();
String encoding = createEncodedProtobuf(masterKeyBytes, password.serialize());
String url = "https://signal.group/#" + encoding;
assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri(url))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
.hasCauseExactlyInstanceOf(InvalidInputException.class);
}
private static String createEncodedProtobuf(@NonNull byte[] groupMasterKey,
@NonNull byte[] passwordBytes)
{
return Base64.encodeUrlSafeWithoutPadding(new GroupInviteLink.Builder()
.v1Contents(new GroupInviteLink.GroupInviteLinkContentsV1.Builder()
.groupMasterKey(ByteString.of(groupMasterKey))
.inviteLinkPassword(ByteString.of(passwordBytes))
.build())
.build()
.encode());
}
}

View file

@ -0,0 +1,130 @@
package org.thoughtcrime.securesms.groups.v2
import assertk.assertFailure
import assertk.assertThat
import assertk.assertions.hasMessage
import assertk.assertions.isInstanceOf
import assertk.assertions.isNull
import assertk.assertions.messageContains
import assertk.assertions.rootCause
import okio.ByteString
import org.junit.Test
import org.signal.core.util.Base64.encodeUrlSafeWithoutPadding
import org.signal.libsignal.zkgroup.InvalidInputException
import org.signal.storageservice.protos.groups.GroupInviteLink
import org.thoughtcrime.securesms.groups.v2.GroupInviteLinkUrl.InvalidGroupLinkException
import org.thoughtcrime.securesms.groups.v2.GroupInviteLinkUrl.UnknownGroupLinkVersionException
import org.thoughtcrime.securesms.util.Util
import java.io.IOException
@Suppress("ClassName")
class GroupInviteLinkUrl_InvalidGroupLinkException_Test {
@Test
fun empty_string() {
val uri = ""
assertThat(GroupInviteLinkUrl.fromUri(uri)).isNull()
}
@Test
fun not_a_url_string() {
val uri = "abc"
assertThat(GroupInviteLinkUrl.fromUri(uri)).isNull()
}
@Test
fun wrong_host() {
val uri = "https://x.signal.org/#CjQKIAD34MKnGrBkzDztTATwjXt-9LhLLCIG9pgzvmz-NN-AEhCbwyTuxDfP2mrluK779H7o"
assertThat(GroupInviteLinkUrl.fromUri(uri)).isNull()
}
@Test
fun wrong_scheme() {
val uri = "http://signal.group/#CjQKIAD34MKnGrBkzDztTATwjXt-9LhLLCIG9pgzvmz-NN-AEhCbwyTuxDfP2mrluK779H7o"
assertThat(GroupInviteLinkUrl.fromUri(uri)).isNull()
}
@Test
fun has_path() {
val uri = "https://signal.group/not_expected/#CjQKIAD34MKnGrBkzDztTATwjXt-9LhLLCIG9pgzvmz-NN-AEhCbwyTuxDfP2mrluK779H7o"
assertFailure { GroupInviteLinkUrl.fromUri(uri) }
.isInstanceOf<InvalidGroupLinkException>()
.hasMessage("No path was expected in uri")
}
@Test
fun missing_ref() {
val uri = "https://signal.group/"
assertFailure { GroupInviteLinkUrl.fromUri(uri) }
.isInstanceOf<InvalidGroupLinkException>()
.hasMessage("No reference was in the uri")
}
@Test
fun empty_ref() {
val uri = "https://signal.group/#"
assertFailure { GroupInviteLinkUrl.fromUri(uri) }
.isInstanceOf<InvalidGroupLinkException>()
.hasMessage("No reference was in the uri")
}
@Test
fun bad_base64() {
val uri = "https://signal.group/#CAESNAogpQEzURH6BON1bCS264cmTi37Yi6HTOReXZUEHdsBIgSEPCLfiL7k4wCX;mwVi31USVY"
assertFailure { GroupInviteLinkUrl.fromUri(uri) }
.isInstanceOf<InvalidGroupLinkException>()
.rootCause()
.isInstanceOf<IOException>()
}
@Test
fun bad_protobuf() {
val uri = "https://signal.group/#CAESNAogpQEzURH6BON1bCS264cmTi37Yi6HTOReXZUEHdsBIgSEPCLfiL7k4wCXmwVi31USVY"
assertFailure {
GroupInviteLinkUrl.fromUri(uri)
}.isInstanceOf<InvalidGroupLinkException>()
.rootCause()
.isInstanceOf<IllegalStateException>()
}
@Test
fun version_999_url() {
val url = "https://signal.group/#uj4zCiDMSxlNUvF4bQ3z3fYzGyZTFbJ1xEqWbPE3uZSD8bjOrxIP8NxV-0GUz3jpxMLR1rN3"
assertFailure { GroupInviteLinkUrl.fromUri(url) }
.isInstanceOf<UnknownGroupLinkVersionException>()
.messageContains("Url contains no known group link content")
}
@Test
fun bad_master_key_length() {
val masterKeyBytes = Util.getSecretBytes(33)
val password = GroupLinkPassword.createNew()
val encoding = createEncodedProtobuf(masterKeyBytes, password.serialize())
val url = "https://signal.group/#$encoding"
assertFailure { GroupInviteLinkUrl.fromUri(url) }
.isInstanceOf<InvalidGroupLinkException>()
.rootCause()
.isInstanceOf<InvalidInputException>()
}
companion object {
private fun createEncodedProtobuf(
groupMasterKey: ByteArray,
passwordBytes: ByteArray
): String {
return encodeUrlSafeWithoutPadding(
GroupInviteLink.Builder()
.v1Contents(
GroupInviteLink.GroupInviteLinkContentsV1.Builder()
.groupMasterKey(ByteString.of(*groupMasterKey))
.inviteLinkPassword(ByteString.of(*passwordBytes))
.build()
)
.build()
.encode()
)
}
}
}

View file

@ -1,122 +0,0 @@
package org.thoughtcrime.securesms.payments;
import org.junit.Before;
import org.junit.Test;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.internal.push.PaymentAddress;
import okio.ByteString;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertArrayEquals;
import static org.whispersystems.signalservice.test.LibSignalLibraryUtil.assumeLibSignalSupportedOnOS;
public final class MobileCoinPublicAddressProfileUtilTest {
@Before
public void ensureNativeSupported() {
assumeLibSignalSupportedOnOS();
}
@Test
public void can_verify_an_address() throws PaymentsAddressException {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] address = Util.getSecretBytes(100);
PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
byte[] paymentsAddress = MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(signedPaymentAddress, identityKeyPair.getPublicKey());
assertArrayEquals(address, paymentsAddress);
}
@Test
public void can_not_verify_an_address_with_the_wrong_key() {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
IdentityKey wrongPublicKey = IdentityKeyUtil.generateIdentityKeyPair().getPublicKey();
byte[] address = Util.getSecretBytes(100);
PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
assertThatThrownBy(() -> MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(signedPaymentAddress, wrongPublicKey))
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
}
@Test
public void can_not_verify_a_tampered_signature() {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] address = Util.getSecretBytes(100);
PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
byte[] signature = signedPaymentAddress.mobileCoinAddress.signature.toByteArray();
signature[0] = (byte) (signature[0] ^ 0x01);
PaymentAddress tamperedSignature = signedPaymentAddress.newBuilder()
.mobileCoinAddress(signedPaymentAddress.mobileCoinAddress
.newBuilder()
.signature(ByteString.of(signature))
.build())
.build();
assertThatThrownBy(() -> MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(tamperedSignature, identityKeyPair.getPublicKey()))
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
}
@Test
public void can_not_verify_a_tampered_address() {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] addressBytes = Util.getSecretBytes(100);
PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(addressBytes, identityKeyPair);
byte[] address = signedPaymentAddress.mobileCoinAddress.address.toByteArray();
address[0] = (byte) (address[0] ^ 0x01);
PaymentAddress tamperedAddress = signedPaymentAddress.newBuilder()
.mobileCoinAddress(signedPaymentAddress.mobileCoinAddress
.newBuilder()
.address(ByteString.of(address))
.build())
.build();
assertThatThrownBy(() -> MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(tamperedAddress, identityKeyPair.getPublicKey()))
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
}
@Test
public void can_not_verify_a_missing_signature() {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] address = Util.getSecretBytes(100);
PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
PaymentAddress removedSignature = signedPaymentAddress.newBuilder()
.mobileCoinAddress(signedPaymentAddress.mobileCoinAddress
.newBuilder()
.signature(null)
.build())
.build();
assertThatThrownBy(() -> MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(removedSignature, identityKeyPair.getPublicKey()))
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
}
@Test
public void can_not_verify_a_missing_address() {
IdentityKeyPair identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair();
byte[] address = Util.getSecretBytes(100);
PaymentAddress signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair);
PaymentAddress removedAddress = signedPaymentAddress.newBuilder()
.mobileCoinAddress(signedPaymentAddress.mobileCoinAddress
.newBuilder()
.address(null)
.build())
.build();
assertThatThrownBy(() -> MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(removedAddress, identityKeyPair.getPublicKey()))
.isInstanceOf(PaymentsAddressException.class)
.hasMessage("Invalid MobileCoin address signature on payments address proto");
}
}

View file

@ -0,0 +1,129 @@
package org.thoughtcrime.securesms.payments
import assertk.assertFailure
import assertk.assertThat
import assertk.assertions.hasMessage
import assertk.assertions.isEqualTo
import assertk.assertions.isInstanceOf
import okio.ByteString
import org.junit.Before
import org.junit.Test
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.util.Util
import org.whispersystems.signalservice.test.LibSignalLibraryUtil
class MobileCoinPublicAddressProfileUtilTest {
@Before
fun ensureNativeSupported() {
LibSignalLibraryUtil.assumeLibSignalSupportedOnOS()
}
@Test
fun can_verify_an_address() {
val identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair()
val address = Util.getSecretBytes(100)
val signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair)
val paymentsAddress = MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(signedPaymentAddress, identityKeyPair.publicKey)
assertThat(paymentsAddress).isEqualTo(address)
}
@Test
fun can_not_verify_an_address_with_the_wrong_key() {
val identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair()
val wrongPublicKey = IdentityKeyUtil.generateIdentityKeyPair().publicKey
val address = Util.getSecretBytes(100)
val signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair)
assertFailure { MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(signedPaymentAddress, wrongPublicKey) }
.isInstanceOf<PaymentsAddressException>()
.hasMessage("Invalid MobileCoin address signature on payments address proto")
}
@Test
fun can_not_verify_a_tampered_signature() {
val identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair()
val address = Util.getSecretBytes(100)
val signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair)
val mobileCoinAddress = signedPaymentAddress.mobileCoinAddress!!
val signature = mobileCoinAddress.signature!!.toByteArray()
signature[0] = (signature[0].toInt() xor 0x01).toByte()
val tamperedSignature = signedPaymentAddress.newBuilder()
.mobileCoinAddress(
mobileCoinAddress
.newBuilder()
.signature(ByteString.of(*signature))
.build()
)
.build()
assertFailure { MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(tamperedSignature, identityKeyPair.publicKey) }
.isInstanceOf<PaymentsAddressException>()
.hasMessage("Invalid MobileCoin address signature on payments address proto")
}
@Test
fun can_not_verify_a_tampered_address() {
val identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair()
val addressBytes = Util.getSecretBytes(100)
val signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(addressBytes, identityKeyPair)
val mobileCoinAddress = signedPaymentAddress.mobileCoinAddress!!
val address = mobileCoinAddress.address!!.toByteArray()
address[0] = (address[0].toInt() xor 0x01).toByte()
val tamperedAddress = signedPaymentAddress.newBuilder()
.mobileCoinAddress(
mobileCoinAddress
.newBuilder()
.address(ByteString.of(*address))
.build()
)
.build()
assertFailure { MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(tamperedAddress, identityKeyPair.publicKey) }
.isInstanceOf<PaymentsAddressException>()
.hasMessage("Invalid MobileCoin address signature on payments address proto")
}
@Test
fun can_not_verify_a_missing_signature() {
val identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair()
val address = Util.getSecretBytes(100)
val signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair)
val removedSignature = signedPaymentAddress.newBuilder()
.mobileCoinAddress(
signedPaymentAddress.mobileCoinAddress!!
.newBuilder()
.signature(null)
.build()
)
.build()
assertFailure { MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(removedSignature, identityKeyPair.publicKey) }
.isInstanceOf<PaymentsAddressException>()
.hasMessage("Invalid MobileCoin address signature on payments address proto")
}
@Test
fun can_not_verify_a_missing_address() {
val identityKeyPair = IdentityKeyUtil.generateIdentityKeyPair()
val address = Util.getSecretBytes(100)
val signedPaymentAddress = MobileCoinPublicAddressProfileUtil.signPaymentsAddress(address, identityKeyPair)
val removedAddress = signedPaymentAddress.newBuilder()
.mobileCoinAddress(
signedPaymentAddress.mobileCoinAddress!!
.newBuilder()
.address(null)
.build()
)
.build()
assertFailure { MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(removedAddress, identityKeyPair.publicKey) }
.isInstanceOf<PaymentsAddressException>()
.hasMessage("Invalid MobileCoin address signature on payments address proto")
}
}

View file

@ -1,120 +0,0 @@
package org.thoughtcrime.securesms.util.livedata;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import org.assertj.core.api.Assertions;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import static org.junit.Assert.assertEquals;
import static org.thoughtcrime.securesms.util.livedata.LiveDataTestUtil.assertNoValue;
import static org.thoughtcrime.securesms.util.livedata.LiveDataTestUtil.observeAndGetOneValue;
public final class LiveDataUtilTest_skip {
@Rule
public TestRule rule = new LiveDataRule();
@Test
public void skip_no_value() {
MutableLiveData<String> liveData = new MutableLiveData<>();
LiveData<String> skipped = LiveDataUtil.skip(liveData, 0);
assertNoValue(skipped);
}
@Test
public void skip_same_value_with_zero_skip() {
MutableLiveData<String> liveData = new MutableLiveData<>();
LiveData<String> skipped = LiveDataUtil.skip(liveData, 0);
liveData.setValue("A");
assertEquals("A", observeAndGetOneValue(skipped));
}
@Test
public void skip_second_value_with_skip_one() {
MutableLiveData<String> liveData = new MutableLiveData<>();
TestObserver<String> testObserver = new TestObserver<>();
LiveData<String> skipped = LiveDataUtil.skip(liveData, 1);
skipped.observeForever(testObserver);
liveData.setValue("A");
liveData.setValue("B");
skipped.removeObserver(testObserver);
Assertions.assertThat(testObserver.getValues())
.containsExactly("B");
}
@Test
public void skip_no_value_with_skip() {
MutableLiveData<String> liveData = new MutableLiveData<>();
LiveData<String> skipped = LiveDataUtil.skip(liveData, 1);
liveData.setValue("A");
assertNoValue(skipped);
}
@Test
public void skip_third_and_fourth_value_with_skip_two() {
MutableLiveData<String> liveData = new MutableLiveData<>();
TestObserver<String> testObserver = new TestObserver<>();
LiveData<String> skipped = LiveDataUtil.skip(liveData, 2);
skipped.observeForever(testObserver);
liveData.setValue("A");
liveData.setValue("B");
liveData.setValue("C");
liveData.setValue("D");
skipped.removeObserver(testObserver);
Assertions.assertThat(testObserver.getValues())
.containsExactly("C", "D");
}
@Test
public void skip_set_one_before_then_skip() {
MutableLiveData<String> liveData = new MutableLiveData<>();
TestObserver<String> testObserver = new TestObserver<>();
liveData.setValue("A");
LiveData<String> skipped = LiveDataUtil.skip(liveData, 2);
skipped.observeForever(testObserver);
liveData.setValue("B");
liveData.setValue("C");
liveData.setValue("D");
skipped.removeObserver(testObserver);
Assertions.assertThat(testObserver.getValues())
.containsExactly("C", "D");
}
@Test
public void skip_set_two_before_then_skip() {
MutableLiveData<String> liveData = new MutableLiveData<>();
TestObserver<String> testObserver = new TestObserver<>();
liveData.setValue("A");
liveData.setValue("B");
LiveData<String> skipped = LiveDataUtil.skip(liveData, 2);
skipped.observeForever(testObserver);
liveData.setValue("C");
liveData.setValue("D");
skipped.removeObserver(testObserver);
Assertions.assertThat(testObserver.getValues())
.containsExactly("D");
}
}

View file

@ -0,0 +1,112 @@
package org.thoughtcrime.securesms.util.livedata
import androidx.lifecycle.MutableLiveData
import assertk.assertThat
import assertk.assertions.containsExactlyInAnyOrder
import assertk.assertions.isEqualTo
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestRule
@Suppress("ClassName")
class LiveDataUtilTest_skip {
@get:Rule
val rule: TestRule = LiveDataRule()
@Test
fun skip_no_value() {
val liveData = MutableLiveData<String>()
val skipped = LiveDataUtil.skip(liveData, 0)
LiveDataTestUtil.assertNoValue(skipped)
}
@Test
fun skip_same_value_with_zero_skip() {
val liveData = MutableLiveData<String>()
val skipped = LiveDataUtil.skip(liveData, 0)
liveData.value = "A"
assertThat(LiveDataTestUtil.observeAndGetOneValue(skipped)).isEqualTo("A")
}
@Test
fun skip_second_value_with_skip_one() {
val liveData = MutableLiveData<String>()
val testObserver = TestObserver<String>()
val skipped = LiveDataUtil.skip(liveData, 1)
skipped.observeForever(testObserver)
liveData.value = "A"
liveData.value = "B"
skipped.removeObserver(testObserver)
assertThat(testObserver.values).containsExactlyInAnyOrder("B")
}
@Test
fun skip_no_value_with_skip() {
val liveData = MutableLiveData<String>()
val skipped = LiveDataUtil.skip(liveData, 1)
liveData.value = "A"
LiveDataTestUtil.assertNoValue(skipped)
}
@Test
fun skip_third_and_fourth_value_with_skip_two() {
val liveData = MutableLiveData<String>()
val testObserver = TestObserver<String>()
val skipped = LiveDataUtil.skip(liveData, 2)
skipped.observeForever(testObserver)
liveData.value = "A"
liveData.value = "B"
liveData.value = "C"
liveData.value = "D"
skipped.removeObserver(testObserver)
assertThat(testObserver.values).containsExactlyInAnyOrder("C", "D")
}
@Test
fun skip_set_one_before_then_skip() {
val liveData = MutableLiveData<String>()
val testObserver = TestObserver<String>()
liveData.value = "A"
val skipped = LiveDataUtil.skip(liveData, 2)
skipped.observeForever(testObserver)
liveData.value = "B"
liveData.value = "C"
liveData.value = "D"
skipped.removeObserver(testObserver)
assertThat(testObserver.values).containsExactlyInAnyOrder("C", "D")
}
@Test
fun skip_set_two_before_then_skip() {
val liveData = MutableLiveData<String>()
val testObserver = TestObserver<String>()
liveData.value = "A"
liveData.value = "B"
val skipped = LiveDataUtil.skip(liveData, 2)
skipped.observeForever(testObserver)
liveData.value = "C"
liveData.value = "D"
skipped.removeObserver(testObserver)
assertThat(testObserver.values).containsExactlyInAnyOrder("D")
}
}

View file

@ -55,7 +55,6 @@ dependencies {
implementation(libs.kotlinx.coroutines.core.jvm)
testImplementation(testLibs.junit.junit)
testImplementation(testLibs.assertj.core)
testImplementation(testLibs.junit.junit)
testImplementation(testLibs.assertk)
testImplementation(testLibs.kotlinx.coroutines.test)
}

View file

@ -21,7 +21,7 @@ robolectric-robolectric = { module = "org.robolectric:robolectric", version.ref
bouncycastle-bcprov-jdk15on = "org.bouncycastle:bcprov-jdk15on:1.70"
bouncycastle-bcpkix-jdk15on = "org.bouncycastle:bcpkix-jdk15on:1.70"
hamcrest-hamcrest = "org.hamcrest:hamcrest:2.2"
assertj-core = "org.assertj:assertj-core:3.11.1"
assertk = "com.willowtreeapps.assertk:assertk:0.28.1"
square-okhttp-mockserver = "com.squareup.okhttp3:mockwebserver:4.12.0"
mockk = "io.mockk:mockk:1.13.2"
mockk-android = "io.mockk:mockk-android:1.13.2"

View file

@ -4526,6 +4526,38 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="0e09c60f88d446ff209c17a0a36503b49fdec475225d4381ae4fe9ed83fb912d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.willowtreeapps.assertk" name="assertk" version="0.28.1">
<artifact name="assertk-0.28.1.module">
<sha256 value="0326ac846e66a6f79a786c4fa0a120f15b9d10256610cd7d2bd5d0842b307bcd" origin="Generated by Gradle"/>
</artifact>
<artifact name="assertk-metadata-0.28.1.jar">
<sha256 value="1a624bd88c992dd9c0b628b41c7e1b2f2c22ca17439cd162b915d13549e70b56" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.willowtreeapps.assertk" name="assertk-jvm" version="0.28.1">
<artifact name="assertk-jvm-0.28.1.jar">
<sha256 value="0f8ec47cd657d47e36675d2e7f1e3a6ffc242399c1c6f2a6cd03fafb22fef3e3" origin="Generated by Gradle"/>
</artifact>
<artifact name="assertk-jvm-0.28.1.module">
<sha256 value="eeb033a1bfebd90d706c07d3847d75568095c94eb8509455965a191b763f0791" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.willowtreeapps.opentest4k" name="opentest4k" version="1.3.0">
<artifact name="opentest4k-1.3.0.module">
<sha256 value="80a43a89a61f9cfadffc531d02c495d862634c68be10db3bc0627ffbdafaffbf" origin="Generated by Gradle"/>
</artifact>
<artifact name="opentest4k-metadata-1.3.0.jar">
<sha256 value="8a5aa481a492c53fcab52144844a94740583235edf1d29defb2f2a063b0689fe" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.willowtreeapps.opentest4k" name="opentest4k-jvm" version="1.3.0">
<artifact name="opentest4k-jvm-1.3.0.jar">
<sha256 value="67bebae94b0cfcd01d97093ea100b68551afc3a4024be19f7341252556fea32f" origin="Generated by Gradle"/>
</artifact>
<artifact name="opentest4k-jvm-1.3.0.module">
<sha256 value="bd09ab5d717ead0c16e4cfe8f162ae4abc76126f1ee22605aad64edb4e33d975" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="commons-codec" name="commons-codec" version="1.10">
<artifact name="commons-codec-1.10.jar">
<sha256 value="4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569" origin="Generated by Gradle"/>
@ -5000,11 +5032,6 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="0b2b1102c18d3c7e05a77214b9b7501a6f6056174ae5604e0e256776eda7553e" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.assertj" name="assertj-core" version="3.11.1">
<artifact name="assertj-core-3.11.1.jar">
<sha256 value="2ee2bd3e81fc818d423d442b658f28acf938d9078d6ba016a64b362fdd7779e8" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bitbucket.b_c" name="jose4j" version="0.7.0">
<artifact name="jose4j-0.7.0.jar">
<sha256 value="eb14f69c0395d4a106c6c46fe6dff080c4608ccabc99b1f03933d374383d9bbe" origin="Generated by Gradle"/>
@ -5439,6 +5466,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="dccaa5d315470fab3920502886bbb85f2da6c86102c65d9c04410544eedb2019" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="kotlin-stdlib" version="1.9.21">
<artifact name="kotlin-stdlib-1.9.21-all.jar">
<sha256 value="cec38bc3302e72a8aaf9cde436b5a9071ee0331e2ad05e84d8bb897334d7e9d4" origin="Generated by Gradle"/>
</artifact>
<artifact name="kotlin-stdlib-1.9.21.module">
<sha256 value="d3019f7f0d71924ce47298c9cc46af0245f75219719b35c5915fbcc7e7a69395" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="kotlin-stdlib" version="1.9.22">
<artifact name="kotlin-stdlib-1.9.22-all.jar">
<sha256 value="cec38bc3302e72a8aaf9cde436b5a9071ee0331e2ad05e84d8bb897334d7e9d4" origin="Generated by Gradle"/>
@ -5496,6 +5531,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="858828bc5191b9e602affa14e01d66489dafb08c4c18d2faee3cbed7ba7d9992" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-common" version="1.9.21">
<artifact name="kotlin-stdlib-common-1.9.21.module">
<sha256 value="68dc8e84aa05f5278c16505247d71346d3512b9edadd41f613d657c94c59993b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-common" version="1.9.22">
<artifact name="kotlin-stdlib-common-1.9.22.module">
<sha256 value="f93c9e9abf8d52d8e8fd8e851aa802ecec55132161c4aeee7d3cd924bf794246" origin="Generated by Gradle"/>
@ -6045,6 +6085,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="58812de60898d976fb81ef3b62da05c6604c18fd4a249f5044282479fc286af2" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.opentest4j" name="opentest4j" version="1.3.0">
<artifact name="opentest4j-1.3.0.jar">
<sha256 value="48e2df636cab6563ced64dcdff8abb2355627cb236ef0bf37598682ddf742f1b" origin="Generated by Gradle"/>
</artifact>
<artifact name="opentest4j-1.3.0.module">
<sha256 value="48bf1d6c8b5dc94f74652bd17900f654deb714350248cf5e8fca27b9090c8e0d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.ow2.asm" name="asm" version="9.5">
<artifact name="asm-9.5.jar">
<sha256 value="b62e84b5980729751b0458c534cf1366f727542bb8d158621335682a460f0353" origin="Generated by Gradle"/>

View file

@ -101,7 +101,7 @@ dependencies {
implementation(project(":core-util-jvm"))
testImplementation(testLibs.junit.junit)
testImplementation(testLibs.assertj.core)
testImplementation(testLibs.assertk)
testImplementation(testLibs.conscrypt.openjdk.uber)
testImplementation(testLibs.mockk)
testImplementation(testLibs.hamcrest.hamcrest)