Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions helperlib/src/test/java/android/util/Log.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
package android.util;

public class Log {
public static final int VERBOSE = 2;
public static final int DEBUG = 3;
public static final int INFO = 4;
public static final int WARN = 5;
public static final int ERROR = 6;

public static int d(String tag, String msg) {
System.out.println("DEBUG: " + tag + ": " + msg);
return 0;
}

public static int d(String tag, String msg, Throwable tr) {
System.out.println("DEBUG: " + tag + ": " + msg + " - " + tr);
return 0;
}

public static int i(String tag, String msg) {
System.out.println("INFO: " + tag + ": " + msg);
return 0;
Expand All @@ -16,11 +27,31 @@ public static int w(String tag, String msg) {
return 0;
}

public static int w(String tag, Throwable tr) {
System.out.println("WARN: " + tag + ": " + tr);
return 0;
}

public static int w(String tag, String msg, Throwable tr) {
System.out.println("WARN: " + tag + ": " + msg + " - " + tr);
return 0;
}

public static int e(String tag, String msg) {
System.out.println("ERROR: " + tag + ": " + msg);
return 0;
}

public static int e(String tag, String msg, Throwable tr) {
System.out.println("ERROR: " + tag + ": " + msg + " - " + tr);
return 0;
}

public static int wtf(String tag, String msg) {
System.out.println("WTF: " + tag + ": " + msg);
return 0;
}

public static int println(int priority, String tag, String msg) {
System.out.println(priority + ": " + tag + ": " + msg);
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.spy
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
Expand Down Expand Up @@ -128,9 +127,51 @@ class CoroutineAsyncTaskTest {
assertEquals(50, task.progress)
}

@Test
fun cancelWithMayInterruptFalseCancelsCompletedTask() = runBlocking {
task.execute("param1")
task.preJob?.join()
task.bgJob?.await()

task.cancel(false)
delay(100)
Comment thread
itachi1706 marked this conversation as resolved.

assertEquals(true, task.isCancelled)
assertEquals(Status.FINISHED, task.status)
}

@Test
fun publishProgressAfterCancellationDoesNotInvokeProgressCallback() = runBlocking {
task.execute("param1")
task.preJob?.join()
task.cancel(true)

task.publishProgress(99)
delay(100)

assertEquals(null, task.progress)
assertEquals(0, task.progressUpdateCount)
}

@Test
fun cancelAfterBackgroundCompletionInvokesOnCancelledWithResult() = runBlocking {
task.execute("param1")
task.preJob?.join()
task.bgJob?.await()

task.cancel(true)
delay(100)

assertEquals(1, task.cancelledInvocationCount)
assertEquals("Result", task.cancelledResult)
}
Comment thread
itachi1706 marked this conversation as resolved.

private class TestCoroutineAsyncTask : CoroutineAsyncTask<String, Int, String>("TestTask") {
var result: String? = null
var progress: Int? = null
var progressUpdateCount: Int = 0
var cancelledResult: String? = null
var cancelledInvocationCount: Int = 0

override fun doInBackground(vararg params: String?): String {
return "Result"
Expand All @@ -142,6 +183,13 @@ class CoroutineAsyncTaskTest {

override fun onProgressUpdate(vararg params: Int?) {
this.progress = params[0]
this.progressUpdateCount++
}

override fun onCancelled(result: String?) {
this.cancelledResult = result
this.cancelledInvocationCount++
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.itachi1706.helperlib.exceptions

import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull

class ApiExceptionTest {

@Test
fun apiExceptionPreservesMessage() {
val exception = ApiException("Callback is not set")

assertEquals("Callback is not set", exception.message)
}

@Test
fun apiExceptionExtendsExceptionType() {
val exception = ApiException("Any message")
val asException: Exception = exception

assertEquals("Any message", asException.message)
}

@Test
fun apiExceptionHasNullCauseByDefault() {
val exception = ApiException("Any message")

assertNull(exception.cause)
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.itachi1706.helperlib.helpers

import com.itachi1706.helperlib.interfaces.LogHandler
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import kotlin.test.Test
import kotlin.test.assertEquals

class LogHelperTest {

@Test
fun getLogLevelCharReturnsErrorForError() {
assertEquals('E', LogHelper.getLogLevelChar(6))
}

@Test
fun getLogLevelCharReturnsWarnForWarn() {
assertEquals('W', LogHelper.getLogLevelChar(5))
}

@Test
fun getLogLevelCharReturnsDebugForDebug() {
assertEquals('D', LogHelper.getLogLevelChar(3))
}

@Test
fun getLogLevelCharReturnsInfoForInfo() {
assertEquals('I', LogHelper.getLogLevelChar(4))
}

@Test
fun getLogLevelCharReturnsVerboseForUnknownLevel() {
assertEquals('V', LogHelper.getLogLevelChar(Int.MAX_VALUE))
}

@Test
fun getGenericLogStringFormatsLevelTagAndMessage() {
val log = LogHelper.getGenericLogString(5, "Network", "Timeout")

assertEquals("W/Network: Timeout", log)
}

@Test
fun addExternalLogForwardsDebugMessagesToExternalLogger() {
val logger = mock<LogHandler>()
LogHelper.addExternalLog(logger)

LogHelper.d("UnitTest", "hello")

verify(logger).handleExtraLogging(3, "UnitTest", "hello")
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.itachi1706.helperlib.helpers

import kotlin.test.Test
import kotlin.test.assertEquals

class ValidationHelperTest {

@Test
fun bytesToHexFormatsSingleByteAsUppercaseHex() {
val value = byteArrayOf(0x0A)

assertEquals("0A", ValidationHelper.bytesToHex(value))
}

@Test
fun bytesToHexFormatsMultipleBytesWithColonSeparator() {
val value = byteArrayOf(0x12, 0x34, 0x56)

assertEquals("12:34:56", ValidationHelper.bytesToHex(value))
}

@Test
fun bytesToHexHandlesNegativeByteValuesCorrectly() {
val value = byteArrayOf(0xFF.toByte(), 0x80.toByte(), 0x00)

assertEquals("FF:80:00", ValidationHelper.bytesToHex(value))
}

@Test
fun bytesToHexReturnsEmptyStringForEmptyArray() {
assertEquals("", ValidationHelper.bytesToHex(byteArrayOf()))
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package com.itachi1706.helperlib.objects

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertNotNull
import kotlin.test.assertNull

class ApiResponseTest {

@Test
fun getTypedDataReturnsDecodedObjectWhenDataMatchesType() {
val response = ApiResponse(
date = "2025-10-01T10:29:38.201645045Z",
status = 200,
message = "OK",
success = true,
data = buildJsonObject {
put("id", 7)
put("name", "Kenneth")
}
)

val typedData = response.getTypedData<TestPayload>()

assertEquals(TestPayload(id = 7, name = "Kenneth"), typedData)
}

@Test
fun getTypedDataReturnsNullWhenDataIsMissing() {
val response = ApiResponse(
date = "2025-10-01T10:29:38.201645045Z",
status = 204,
message = "No Content",
success = true,
data = null
)

assertNull(response.getTypedData<TestPayload>())
}

@Test
fun getTypedDataUsesProvidedJsonConfigurationForUnknownKeys() {
val response = ApiResponse(
date = "2025-10-01T10:29:38.201645045Z",
status = 200,
message = "OK",
success = true,
data = buildJsonObject {
put("id", 7)
put("name", "Kenneth")
put("ignored", "value")
}
)

val typedData = response.getTypedData<TestPayload>(
Json {
ignoreUnknownKeys = true
}
)

assertEquals(TestPayload(id = 7, name = "Kenneth"), typedData)
}

@Test
fun getTypedDataUsesProvidedJsonConfigurationForLenientPayloads() {
val json = Json {
isLenient = true
ignoreUnknownKeys = true
}

val response = json.decodeFromString<ApiResponse>(
"{\"date\":\"2025-10-01T10:29:38.201645045Z\",\"status\":200,\"message\":\"OK\",\"success\":true,\"data\":{\"id\":7,\"name\":\"Kenneth\"},\"ignored\":\"value\"}"
)

val typedData = response.getTypedData<TestPayload>(json)

assertEquals(TestPayload(id = 7, name = "Kenneth"), typedData)
}

@Test
fun getTypedDataThrowsWhenPayloadDoesNotMatchRequestedType() {
val response = ApiResponse(
date = "2025-10-01T10:29:38.201645045Z",
status = 200,
message = "OK",
success = true,
data = JsonPrimitive("not a number")
)

assertFailsWith<IllegalArgumentException> {
response.getTypedData<Int>()
}
Comment thread
itachi1706 marked this conversation as resolved.
}

@Test
fun getDateObjectParsesIsoDateWithNanosecondsByTruncatingToMilliseconds() {
val response = ApiResponse(
date = "2025-10-01T10:29:38.201645045Z",
status = 200,
message = "OK",
success = true
)

val parsedDate = response.getDateObject()

assertNotNull(parsedDate)
assertEquals(1759314578201L, parsedDate.time)
}

@Test
fun getDateObjectReturnsNullForInvalidDateString() {
val response = ApiResponse(
date = "not-a-date",
status = 500,
message = "Error",
success = false
)

assertNull(response.getDateObject())
}

@Serializable
private data class TestPayload(
val id: Int,
val name: String
)
}



Loading