diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index b805dc4..717fd7b 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -19,8 +19,8 @@ FunctionParameterNaming:UpdateDeeplinks.kt$UpdateDeeplinks$brand_guid: String FunctionParameterNaming:UpdateDeeplinks.kt$UpdateDeeplinks$install_type: InstallType FunctionParameterNaming:UpdateDeeplinks.kt$UpdateDeeplinks$install_url: String - LongParameterList:Bitlinks.kt$Bitlinks$( bitlink: String, title: String = Constants.EMPTY, archived: Boolean = false, tags: Array<String> = emptyArray(), deeplinks: UpdateDeeplinks = UpdateDeeplinks(), toJson: Boolean = false ) - LongParameterList:Bitlinks.kt$Bitlinks$( long_url: String, domain: String = Constants.EMPTY, group_guid: String = Constants.EMPTY, title: String = Constants.EMPTY, tags: Array<String> = emptyArray(), deeplinks: CreateDeeplinks = CreateDeeplinks(), toJson: Boolean = false ) + LongParameterList:Bitlinks.kt$Bitlinks$( bitlink: String, title: String = Constants.EMPTY, archived: Boolean = false, tags: List<String> = emptyList(), deeplinks: UpdateDeeplinks = UpdateDeeplinks(), toJson: Boolean = false ) + LongParameterList:Bitlinks.kt$Bitlinks$( long_url: String, domain: String = Constants.EMPTY, group_guid: String = Constants.EMPTY, title: String = Constants.EMPTY, tags: List<String> = emptyList(), deeplinks: CreateDeeplinks = CreateDeeplinks(), toJson: Boolean = false ) MagicNumber:CallResponse.kt$CallResponse$200 MagicNumber:CallResponse.kt$CallResponse$201 MagicNumber:CallResponse.kt$CallResponse$299 diff --git a/src/main/kotlin/net/thauvin/erik/bitly/Bitlinks.kt b/src/main/kotlin/net/thauvin/erik/bitly/Bitlinks.kt index 78ec984..f7cb3a4 100644 --- a/src/main/kotlin/net/thauvin/erik/bitly/Bitlinks.kt +++ b/src/main/kotlin/net/thauvin/erik/bitly/Bitlinks.kt @@ -136,7 +136,7 @@ open class Bitlinks(private val accessToken: String) { domain: String = Constants.EMPTY, group_guid: String = Constants.EMPTY, title: String = Constants.EMPTY, - tags: Array = emptyArray(), + tags: List = emptyList(), deeplinks: CreateDeeplinks = CreateDeeplinks(), toJson: Boolean = false ): String { @@ -282,7 +282,7 @@ open class Bitlinks(private val accessToken: String) { bitlink: String, title: String = Constants.EMPTY, archived: Boolean = false, - tags: Array = emptyArray(), + tags: List = emptyList(), deeplinks: UpdateDeeplinks = UpdateDeeplinks(), toJson: Boolean = false ): String { diff --git a/src/main/kotlin/net/thauvin/erik/bitly/Utils.kt b/src/main/kotlin/net/thauvin/erik/bitly/Utils.kt index dca27c2..956a640 100644 --- a/src/main/kotlin/net/thauvin/erik/bitly/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/bitly/Utils.kt @@ -124,7 +124,7 @@ object Utils { var message = response.message var description = "" var json = Constants.EMPTY_JSON - response.body?.string()?.let { body -> + response.body.string().let { body -> json = body if (!response.isSuccessful && body.isNotEmpty()) { try { diff --git a/src/main/kotlin/net/thauvin/erik/bitly/config/CreateConfig.kt b/src/main/kotlin/net/thauvin/erik/bitly/config/CreateConfig.kt index 25503b7..928cee1 100644 --- a/src/main/kotlin/net/thauvin/erik/bitly/config/CreateConfig.kt +++ b/src/main/kotlin/net/thauvin/erik/bitly/config/CreateConfig.kt @@ -60,7 +60,7 @@ class CreateConfig private constructor(builder: Builder) { var domain: String = Constants.EMPTY var group_guid: String = Constants.EMPTY var title: String = Constants.EMPTY - var tags: Array = emptyArray() + var tags: List = emptyList() var deeplinks: CreateDeeplinks = CreateDeeplinks() var toJson: Boolean = false @@ -76,7 +76,7 @@ class CreateConfig private constructor(builder: Builder) { fun title(title: String): Builder = apply { this.title = title } - fun tags(tags: Array): Builder = apply { this.tags = tags } + fun tags(tags: List): Builder = apply { this.tags = tags } fun deeplinks(deeplinks: CreateDeeplinks): Builder = apply { this.deeplinks = deeplinks } diff --git a/src/main/kotlin/net/thauvin/erik/bitly/config/UpdateConfig.kt b/src/main/kotlin/net/thauvin/erik/bitly/config/UpdateConfig.kt index d531d1b..52ba5ab 100644 --- a/src/main/kotlin/net/thauvin/erik/bitly/config/UpdateConfig.kt +++ b/src/main/kotlin/net/thauvin/erik/bitly/config/UpdateConfig.kt @@ -57,7 +57,7 @@ class UpdateConfig private constructor(builder: Builder) { data class Builder(var bitlink: String) { var title: String = Constants.EMPTY var archived: Boolean = false - var tags: Array = emptyArray() + var tags: List = emptyList() var deeplinks: UpdateDeeplinks = UpdateDeeplinks() var toJson: Boolean = false @@ -68,7 +68,7 @@ class UpdateConfig private constructor(builder: Builder) { fun title(title: String): Builder = apply { this.title = title } fun archived(archived: Boolean): Builder = apply { this.archived = archived } - fun tags(tags: Array): Builder = apply { this.tags = tags } + fun tags(tags: List): Builder = apply { this.tags = tags } fun deeplinks(deeplinks: UpdateDeeplinks): Builder = apply { this.deeplinks = deeplinks } /** diff --git a/src/test/kotlin/net/thauvin/erik/bitly/BitlinksTests.kt b/src/test/kotlin/net/thauvin/erik/bitly/BitlinksTests.kt index ac33bd3..9c0bec0 100644 --- a/src/test/kotlin/net/thauvin/erik/bitly/BitlinksTests.kt +++ b/src/test/kotlin/net/thauvin/erik/bitly/BitlinksTests.kt @@ -47,10 +47,12 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable import org.junit.jupiter.api.extension.ExtendWith import java.io.File +import java.util.* import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertTrue + @ExtendWith(BeforeAllTests::class) class BitlinksTests { private val bitly = with(File("local.properties")) { @@ -91,9 +93,113 @@ class BitlinksTests { } } + @Nested + @DisplayName("Constructor Tests") + inner class ConstructorTests { + @Test + fun `Constructor with access token string should set the token correctly`() { + // Arrange + val expectedToken = "my-secret-token" + + // Act + val bitly = Bitly(expectedToken) + + // Assert + assertThat(bitly.accessToken).isEqualTo(expectedToken) + } + + @Test + fun `Constructor with Path should not change token if file does not exist`() { + // Arrange + val nonExistentPath = File("non/existent/path/file.properties").toPath() + val bitlyWithDefaultToken = Bitly() + val initialToken = bitlyWithDefaultToken.accessToken + + // Act + val bitly = Bitly(nonExistentPath) + + // Assert + assertThat(bitly.accessToken).isEqualTo(initialToken) + } + + @Test + fun `Constructor with Properties and custom key should set token correctly`() { + // Arrange + val customKey = "MY_CUSTOM_BITLY_KEY" + val expectedToken = "token-from-custom-key" + val properties = Properties().apply { + setProperty(customKey, expectedToken) + } + + // Act + val bitly = Bitly(properties, customKey) + + // Assert + assertThat(bitly.accessToken).isEqualTo(expectedToken) + } + + @Test + fun `Constructor with Properties should keep default token if key not found`() { + // Arrange + val properties = Properties() // Empty properties + val bitlyWithDefaultToken = Bitly() // Has "" as token by default + val initialToken = bitlyWithDefaultToken.accessToken + + // Act + val bitly = Bitly(properties, "non-existent-key") + + // Assert + // The token should remain the default empty string + assertThat(bitly.accessToken).isEqualTo(initialToken) + } + + @Test + fun `Constructor with Properties should set token using default key`() { + // Arrange + val expectedToken = "token-from-props" + val properties = Properties().apply { + setProperty(Constants.ENV_ACCESS_TOKEN, expectedToken) + } + + // Act + val bitly = Bitly(properties) + + // Assert + assertThat(bitly.accessToken).isEqualTo(expectedToken) + } + + @Test + fun `Default constructor should default to empty string if no token is provided`() { + // Arrange: Ensure no env var or system property is set + System.clearProperty(Constants.ENV_ACCESS_TOKEN) + // Note: Testing environment variables directly is often avoided in unit tests. + // This test verifies the fallback mechanism. + + // Act + val bitly = Bitly() + + // Assert + assertThat(bitly.accessToken).isEmpty() + } + + @Test + fun `Default constructor should use system property if env var is not set`() { + // Arrange + val expectedToken = "token-from-property" + System.setProperty(Constants.ENV_ACCESS_TOKEN, expectedToken) + + // Act + val bitly = Bitly() + + // Assert + assertThat(bitly.accessToken).isEqualTo(expectedToken) + } + } + @Nested @DisplayName("Create Bitlink Tests") inner class CreateBitlinkTests { + @Test fun `Create bitlink`() { assertThat(bitly.bitlinks().create(long_url = longUrl), "create(longUrl)") @@ -103,7 +209,7 @@ class BitlinksTests { bitly.bitlinks().create( domain = "bit.ly", title = "Erik's Blog", - tags = arrayOf("erik", "thauvin", "blog", "weblog"), + tags = listOf("erik", "thauvin", "blog", "weblog"), long_url = longUrl ) ) @@ -118,7 +224,7 @@ class BitlinksTests { config = CreateConfig.Builder(longUrl) .domain("bit.ly") .title("Erik's Blog") - .tags(arrayOf("erik", "thauvin", "blog", "weblog")) + .tags(listOf("erik", "thauvin", "blog", "weblog")) .build() assertEquals( shortUrl, @@ -148,6 +254,7 @@ class BitlinksTests { @Nested @DisplayName("Expand Test") inner class ExpandTests { + @Test fun `Expand as json`() { assertTrue( @@ -165,6 +272,7 @@ class BitlinksTests { @Nested @DisplayName("Shorten Tests") inner class ShortenTests { + @Test fun `Shorten as json`() { assertTrue( @@ -218,17 +326,18 @@ class BitlinksTests { @Nested @DisplayName("Update Bitlink Tests") inner class UpdateBitlinkTests { + @Test fun `Update bitlink`() { val bl = bitly.bitlinks() assertEquals( Constants.TRUE, bl.update( - shortUrl, title = "Erik's Weblog", tags = arrayOf("blog", "weblog"), archived = true + shortUrl, title = "Erik's Weblog", tags = listOf("blog", "weblog"), archived = true ) ) - assertThat(bl.update(shortUrl, tags = emptyArray(), toJson = true), "update(tags)") + assertThat(bl.update(shortUrl, tags = emptyList(), toJson = true), "update(tags)") .contains("\"tags\":[]") } @@ -237,7 +346,7 @@ class BitlinksTests { val bl = bitly.bitlinks() var config = UpdateConfig.Builder(shortUrl) .archived(true) - .tags(arrayOf("blog", "weblog")) + .tags(listOf("blog", "weblog")) .title("Erik's Weblog") .build() @@ -279,6 +388,7 @@ class BitlinksTests { @Nested @DisplayName("Validation Tests") inner class ValidationTests { + @Test fun `Empty URL should not shorten`() { assertEquals(Constants.EMPTY, bitly.bitlinks().shorten(Constants.EMPTY)) @@ -289,13 +399,6 @@ class BitlinksTests { assertEquals(shortUrl, bitly.bitlinks().shorten(shortUrl)) } - @Test - fun `Token not specified with API call`() { - assertFailsWith(IllegalArgumentException::class, "Utils.call()") { - Utils.call("", "foo") - } - } - @Test @DisableOnCi fun `Token not specified`() { @@ -316,6 +419,13 @@ class BitlinksTests { } } + @Test + fun `Token not specified with API call`() { + assertFailsWith(IllegalArgumentException::class, "Utils.call()") { + Utils.call("", "foo") + } + } + @Test fun `Token should be valid`() { val test = Bitly().apply { accessToken = "12345679" } diff --git a/src/test/kotlin/net/thauvin/erik/bitly/UtilsTests.kt b/src/test/kotlin/net/thauvin/erik/bitly/UtilsTests.kt index a9a878b..66f31e5 100644 --- a/src/test/kotlin/net/thauvin/erik/bitly/UtilsTests.kt +++ b/src/test/kotlin/net/thauvin/erik/bitly/UtilsTests.kt @@ -51,6 +51,11 @@ class UtilsTests { assertThat("".toEndPoint()).isEqualTo("") } + @Test + fun `Convert endpoint with blank string`() { + assertThat(" ".toEndPoint()).isEqualTo(" ") + } + @Test fun `Convert endpoint with full URL`() { assertThat("https://example.com/path".toEndPoint()).isEqualTo("https://example.com/path") @@ -102,13 +107,17 @@ class UtilsTests { } } - @Test - fun `Validate invalid URL`() { - assertFalse("this is a test".isValidUrl(), "invalid url") - } + @Nested + @DisplayName("URL Validation Tests") + inner class URLValidationTests { + @Test + fun `Validate invalid URL`() { + assertFalse("this is a test".isValidUrl(), "invalid url") + } - @Test - fun `Validate URL`() { - assertTrue("https://www.example.com".isValidUrl(), "valid url") + @Test + fun `Validate URL`() { + assertTrue("https://www.example.com".isValidUrl(), "valid url") + } } } diff --git a/src/test/kotlin/net/thauvin/erik/bitly/config/ConfigTests.kt b/src/test/kotlin/net/thauvin/erik/bitly/config/ConfigTests.kt index 09c45ed..42f9b13 100644 --- a/src/test/kotlin/net/thauvin/erik/bitly/config/ConfigTests.kt +++ b/src/test/kotlin/net/thauvin/erik/bitly/config/ConfigTests.kt @@ -61,7 +61,7 @@ class ConfigTests { .deeplinks(deeplinks) .domain("domain") .groupGuid("group_guid") - .tags(arrayOf("tag", "tag2")) + .tags(listOf("tag", "tag2")) .title("title") .build() @@ -70,13 +70,13 @@ class ConfigTests { prop(CreateConfig::domain).isEqualTo("domain") prop(CreateConfig::group_guid).isEqualTo("group_guid") prop(CreateConfig::long_url).isEqualTo("long_url") - prop(CreateConfig::tags).isEqualTo(arrayOf("tag", "tag2")) + prop(CreateConfig::tags).isEqualTo(listOf("tag", "tag2")) prop(CreateConfig::title).isEqualTo("title") prop(CreateConfig::toJson).isEqualTo(false) } val map = mapOf( - "deeplinks" to arrayOf(deeplinks.links()), + "deeplinks" to listOf(deeplinks.links()), "domain" to config.domain, "group_guid" to config.group_guid, "long_url" to config.long_url, @@ -103,7 +103,7 @@ class ConfigTests { val config = UpdateConfig.Builder("blink") .archived(true) .deeplinks(deeplinks) - .tags(arrayOf("tag", "tag2")) + .tags(listOf("tag", "tag2")) .title("title") .build() @@ -111,7 +111,7 @@ class ConfigTests { prop(UpdateConfig::archived).isTrue() prop(UpdateConfig::bitlink).isEqualTo("blink") prop(UpdateConfig::deeplinks).isEqualTo(deeplinks) - prop(UpdateConfig::tags).isEqualTo(arrayOf("tag", "tag2")) + prop(UpdateConfig::tags).isEqualTo(listOf("tag", "tag2")) prop(UpdateConfig::title).isEqualTo("title") prop(UpdateConfig::toJson).isEqualTo(false) } @@ -119,7 +119,7 @@ class ConfigTests { val map = mapOf( "archived" to config.archived, "bitlink" to config.bitlink, - "deeplinks" to arrayOf(deeplinks.links()), + "deeplinks" to listOf(deeplinks.links()), "tags" to config.tags, "title" to config.title ) @@ -145,7 +145,7 @@ class ConfigTests { .deeplinks(deeplinks) .domain("domain") .groupGuid("group_guid") - .tags(arrayOf("tag", "tag2")) + .tags(listOf("tag", "tag2")) .title("title") .toJson(true) @@ -154,7 +154,7 @@ class ConfigTests { prop(CreateConfig.Builder::domain).isEqualTo("domain") prop(CreateConfig.Builder::group_guid).isEqualTo("group_guid") prop(CreateConfig.Builder::long_url).isEqualTo("long_url") - prop(CreateConfig.Builder::tags).isEqualTo(arrayOf("tag", "tag2")) + prop(CreateConfig.Builder::tags).isEqualTo(listOf("tag", "tag2")) prop(CreateConfig.Builder::title).isEqualTo("title") prop(CreateConfig.Builder::toJson).isTrue() } @@ -172,7 +172,7 @@ class ConfigTests { prop(CreateConfig.Builder::domain).isEqualTo(Constants.EMPTY) prop(CreateConfig.Builder::group_guid).isEqualTo(Constants.EMPTY) prop(CreateConfig.Builder::title).isEqualTo(Constants.EMPTY) - prop(CreateConfig.Builder::tags).isEqualTo(emptyArray()) + prop(CreateConfig.Builder::tags).isEqualTo(emptyList()) prop(CreateConfig.Builder::deeplinks).prop(CreateDeeplinks::links).isEqualTo(CreateDeeplinks().links()) prop(CreateConfig.Builder::toJson).isEqualTo(false) } @@ -189,7 +189,7 @@ class ConfigTests { val config = UpdateConfig.Builder("bitlink") .title("title") .archived(true) - .tags(arrayOf("tag", "tag2")) + .tags(listOf("tag", "tag2")) .deeplinks(deeplinks) .toJson(true) @@ -197,7 +197,7 @@ class ConfigTests { prop(UpdateConfig.Builder::bitlink).isEqualTo("bitlink") prop(UpdateConfig.Builder::title).isEqualTo("title") prop(UpdateConfig.Builder::archived).isTrue() - prop(UpdateConfig.Builder::tags).isEqualTo(arrayOf("tag", "tag2")) + prop(UpdateConfig.Builder::tags).isEqualTo(listOf("tag", "tag2")) prop(UpdateConfig.Builder::deeplinks).isEqualTo(deeplinks) prop(UpdateConfig.Builder::toJson).isTrue() } @@ -214,7 +214,7 @@ class ConfigTests { prop(UpdateConfig.Builder::bitlink).isEqualTo("bitlink") prop(UpdateConfig.Builder::title).isEqualTo(Constants.EMPTY) prop(UpdateConfig.Builder::archived).isEqualTo(false) - prop(UpdateConfig.Builder::tags).isEqualTo(emptyArray()) + prop(UpdateConfig.Builder::tags).isEqualTo(emptyList()) prop(UpdateConfig.Builder::deeplinks).prop(UpdateDeeplinks::links).isEqualTo(UpdateDeeplinks().links()) prop(UpdateConfig.Builder::toJson).isEqualTo(false) }