Compare commits
28 commits
Author | SHA1 | Date | |
---|---|---|---|
1b07597252 | |||
82b45b0bc1 | |||
9f2c399b6e | |||
c7c70f1b90 | |||
f46f958de0 | |||
6283fc8aef | |||
58fbc4ec2c | |||
8c03669240 | |||
3fe4c9cfc5 | |||
3eeae9c19b | |||
4b4b273461 | |||
820ec736bb | |||
fc3e641793 | |||
cce4ddbcb9 | |||
a72af5cac6 | |||
f57295637f | |||
54b6a09572 | |||
4dd96b7cdb | |||
d79f225325 | |||
a8ce2a04b8 | |||
ed5dd2110a | |||
6d8525c30c | |||
f6a1e7bc3d | |||
7357756667 | |||
2f974c46da | |||
854ea4e434 | |||
8d5ac54078 | |||
8ff8044982 |
27 changed files with 1043 additions and 563 deletions
43
.github/workflows/bld.yml
vendored
43
.github/workflows/bld.yml
vendored
|
@ -5,17 +5,16 @@ on: [push, pull_request, workflow_dispatch]
|
|||
env:
|
||||
BITLY_ACCESS_TOKEN: ${{ secrets.BITLY_ACCESS_TOKEN }}
|
||||
COVERAGE_JDK: "21"
|
||||
COVERAGE_KOTLIN: "2.0.0"
|
||||
KOTLIN_HOME: /usr/share/kotlinc
|
||||
KOTLIN_VERSION: "2.2.0"
|
||||
|
||||
jobs:
|
||||
build-bld-project:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
java-version: [17, 21, 23]
|
||||
kotlin-version: [1.9.25, 2.1.10]
|
||||
java-version: [ 17, 21, 24 ]
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout source repository
|
||||
|
@ -23,12 +22,36 @@ jobs:
|
|||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK ${{ matrix.java-version }} with Kotlin ${{ matrix.kotlin-version }}
|
||||
- name: Set up JDK ${{ matrix.java-version }}
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: ${{ matrix.java-version }}
|
||||
|
||||
- name: Setup Kotlin ${{ env.KOTLIN_VERSION }}
|
||||
uses: fwilhe2/setup-kotlin@main
|
||||
with:
|
||||
version: ${{ env.KOTLIN_VERSION }}
|
||||
|
||||
- name: Download dependencies [bld example]
|
||||
working-directory: examples/bld
|
||||
run: ./bld download
|
||||
|
||||
- name: Compile and run examples [bld example]
|
||||
working-directory: examples/bld
|
||||
run: |
|
||||
./bld compile
|
||||
./bld run --args='https://erik.thauvin.net/ https://bit.ly/2PsNMAA'
|
||||
./bld run-retrieve
|
||||
./bld run-java --args='https://erik.thauvin.net/ https://bit.ly/2PsNMAA'
|
||||
|
||||
- name: Run examples [gradle example]
|
||||
working-directory: examples/gradle
|
||||
run: |
|
||||
./gradlew run --args='https://erik.thauvin.net/ https://bit.ly/2PsNMAA'
|
||||
./gradlew runRetrieve
|
||||
./gradlew runJava --args='https://erik.thauvin.net/ https://bit.ly/2PsNMAA'
|
||||
|
||||
- name: Download dependencies
|
||||
run: ./bld download
|
||||
|
||||
|
@ -39,12 +62,12 @@ jobs:
|
|||
run: ./bld jacoco
|
||||
|
||||
- name: Remove pom.xml
|
||||
if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN
|
||||
if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.os == 'ubuntu-latest'
|
||||
run: rm -rf pom.xml
|
||||
|
||||
- name: SonarCloud Scan
|
||||
uses: sonarsource/sonarcloud-github-action@master
|
||||
if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN
|
||||
uses: SonarSource/sonarqube-scan-action@v5.2.0
|
||||
if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.os == 'ubuntu-latest'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
|
|
1
.idea/inspectionProfiles/Project_Default.xml
generated
1
.idea/inspectionProfiles/Project_Default.xml
generated
|
@ -4,5 +4,6 @@
|
|||
<inspection_tool class="JavadocDeclaration" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ADDITIONAL_TAGS" value="created" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UsePropertyAccessSyntax" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
16
.idea/kotlinc.xml
generated
Normal file
16
.idea/kotlinc.xml
generated
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Kotlin2JsCompilerArguments">
|
||||
<option name="moduleKind" value="plain" />
|
||||
</component>
|
||||
<component name="Kotlin2JvmCompilerArguments">
|
||||
<option name="jvmTarget" value="11" />
|
||||
</component>
|
||||
<component name="KotlinCommonCompilerArguments">
|
||||
<option name="apiVersion" value="1.9" />
|
||||
<option name="languageVersion" value="1.9" />
|
||||
</component>
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="2.2.0" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,5 +1,5 @@
|
|||
[](https://opensource.org/licenses/BSD-3-Clause)
|
||||
[](https://kotlinlang.org/)
|
||||
[](https://kotlinlang.org/)
|
||||
[](https://rife2.com/bld)
|
||||
[](https://github.com/ethauvin/bitly-shorten/releases/latest)
|
||||
[](https://central.sonatype.com/artifact/net.thauvin.erik/bitly-shorten)
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
image: ubuntu:latest
|
||||
|
||||
pipelines:
|
||||
default:
|
||||
- step:
|
||||
name: Test with bld
|
||||
script:
|
||||
# Install latest Java & Kotlin via SDKMAN!
|
||||
- apt-get update -qq && apt-get install -y curl zip
|
||||
- curl -s "https://get.sdkman.io" | bash
|
||||
- echo sdkman_auto_answer=true > $HOME/.sdkman/etc/config
|
||||
- echo sdkman_auto_selfupdate=true >> $HOME/.sdkman/etc/config
|
||||
- source "$HOME/.sdkman/bin/sdkman-init.sh"
|
||||
- sdk install java
|
||||
- sdk install kotlin
|
||||
- source "$HOME/.sdkman/bin/sdkman-init.sh"
|
||||
# Download, compile and test with bld
|
||||
- ./bld download
|
||||
- ./bld compile
|
||||
- ./bld test
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" ?>
|
||||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues></ManuallySuppressedIssues>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>ConstructorParameterNaming:CreateConfig.kt$CreateConfig.Builder$var long_url: String</ID>
|
||||
<ID>FunctionParameterNaming:Bitlinks.kt$Bitlinks$bitlink_id: String</ID>
|
||||
|
@ -42,7 +42,6 @@
|
|||
<ID>VariableNaming:CreateConfig.kt$CreateConfig$val group_guid = builder.group_guid</ID>
|
||||
<ID>VariableNaming:CreateConfig.kt$CreateConfig$val long_url = builder.long_url</ID>
|
||||
<ID>VariableNaming:CreateConfig.kt$CreateConfig.Builder$var group_guid: String = Constants.EMPTY</ID>
|
||||
<ID>WildcardImport:BitlyTest.kt$import assertk.assertions.*</ID>
|
||||
<ID>WildcardImport:BitlyTest.kt$import kotlin.test.*</ID>
|
||||
<ID>WildcardImport:BitlinksTests.kt$import assertk.assertions.*</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
||||
|
|
6
examples/bld/.idea/bld.xml
generated
Normal file
6
examples/bld/.idea/bld.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="BldConfiguration">
|
||||
<events />
|
||||
</component>
|
||||
</project>
|
|
@ -1,7 +1,7 @@
|
|||
bld.downloadExtensionJavadoc=false
|
||||
bld.downloadExtensionSources=true
|
||||
bld.downloadLocation=
|
||||
bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.4
|
||||
bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.1.0
|
||||
bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES
|
||||
bld.sourceDirectories=
|
||||
bld.version=2.2.1
|
||||
|
|
|
@ -25,7 +25,7 @@ public class ExampleBuild extends BaseProject {
|
|||
|
||||
scope(compile)
|
||||
.include(dependency("net.thauvin.erik:bitly-shorten:2.0.0"))
|
||||
.include(dependency("org.json:json:20250107"));
|
||||
.include(dependency("org.json:json:20250517"));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
|
2
examples/gradle/.idea/kotlinc.xml
generated
2
examples/gradle/.idea/kotlinc.xml
generated
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="2.0.0" />
|
||||
<option name="version" value="2.2.0" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,7 +1,7 @@
|
|||
plugins {
|
||||
id("application")
|
||||
id("com.github.ben-manes.versions") version "0.51.0"
|
||||
kotlin("jvm") version "2.1.10"
|
||||
kotlin("jvm") version "2.2.0"
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
|
BIN
examples/gradle/gradle/wrapper/gradle-wrapper.jar
vendored
BIN
examples/gradle/gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
4
examples/gradle/gradlew
vendored
4
examples/gradle/gradlew
vendored
|
@ -114,7 +114,7 @@ case "$( uname )" in #(
|
|||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
|
@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
|
4
examples/gradle/gradlew.bat
vendored
4
examples/gradle/gradlew.bat
vendored
|
@ -70,11 +70,11 @@ goto fail
|
|||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
bld.downloadExtensionJavadoc=false
|
||||
bld.downloadExtensionSources=true
|
||||
bld.downloadLocation=
|
||||
bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.9
|
||||
bld.extension-dokka=com.uwyn.rife2:bld-dokka:1.0.3
|
||||
bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.9
|
||||
bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.4
|
||||
bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.10-SNAPSHOT
|
||||
bld.extension-dokka=com.uwyn.rife2:bld-dokka:1.0.4-SNAPSHOT
|
||||
bld.extension-exec=com.uwyn.rife2:bld-exec:1.0.5
|
||||
bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.11-SNAPSHOT
|
||||
bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.1.0
|
||||
bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES
|
||||
bld.sourceDirectories=
|
||||
bld.version=2.2.1
|
||||
|
|
10
pom.xml
10
pom.xml
|
@ -4,7 +4,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>net.thauvin.erik</groupId>
|
||||
<artifactId>bitly-shorten</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.0.1-SNAPSHOT</version>
|
||||
<name>bitly-shorten</name>
|
||||
<description>A simple implementation of the Bitly link shortening API v4</description>
|
||||
<url>https://github.com/ethauvin/bitly-shorten</url>
|
||||
|
@ -18,19 +18,19 @@
|
|||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>2.1.10</version>
|
||||
<version>2.2.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-common</artifactId>
|
||||
<version>2.1.10</version>
|
||||
<version>2.2.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||
<version>2.1.10</version>
|
||||
<version>2.2.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -48,7 +48,7 @@
|
|||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20250107</version>
|
||||
<version>20250517</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
@ -33,10 +33,7 @@ package net.thauvin.erik.bitly;
|
|||
|
||||
import rife.bld.BuildCommand;
|
||||
import rife.bld.Project;
|
||||
import rife.bld.extension.CompileKotlinOperation;
|
||||
import rife.bld.extension.DetektOperation;
|
||||
import rife.bld.extension.DokkaOperation;
|
||||
import rife.bld.extension.JacocoReportOperation;
|
||||
import rife.bld.extension.*;
|
||||
import rife.bld.extension.dokka.LoggingLevel;
|
||||
import rife.bld.extension.dokka.OutputFormat;
|
||||
import rife.bld.extension.dokka.SourceSet;
|
||||
|
@ -49,27 +46,35 @@ import rife.tools.exceptions.FileUtilsErrorException;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.logging.ConsoleHandler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static rife.bld.dependencies.Repository.*;
|
||||
import static rife.bld.dependencies.Scope.compile;
|
||||
import static rife.bld.dependencies.Scope.test;
|
||||
|
||||
public class BitlyShortenBuild extends Project {
|
||||
static final String TEST_RESULTS_DIR = "build/test-results/test/";
|
||||
final File srcMainKotlin = new File(srcMainDirectory(), "kotlin");
|
||||
|
||||
public BitlyShortenBuild() {
|
||||
pkg = "net.thauvin.erik";
|
||||
name = "bitly-shorten";
|
||||
version = version(2, 0, 0);
|
||||
version = version(2, 0, 1, "SNAPSHOT");
|
||||
|
||||
javaRelease = 11;
|
||||
|
||||
downloadSources = true;
|
||||
autoDownloadPurge = true;
|
||||
|
||||
repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL);
|
||||
|
||||
var okHttp = version(4, 12, 0);
|
||||
final var kotlin = version(2, 1, 10);
|
||||
final var kotlin = version(2, 2, 0);
|
||||
scope(compile)
|
||||
// Kotlin
|
||||
.include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin))
|
||||
|
@ -79,11 +84,12 @@ public class BitlyShortenBuild extends Project {
|
|||
.include(dependency("com.squareup.okhttp3", "okhttp", okHttp))
|
||||
.include(dependency("com.squareup.okhttp3", "logging-interceptor", okHttp))
|
||||
// JSON
|
||||
.include(dependency("org.json", "json", "20250107"));
|
||||
.include(dependency("org.json", "json", "20250517"));
|
||||
scope(test)
|
||||
.include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin))
|
||||
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 1)))
|
||||
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 1)))
|
||||
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 13, 2)))
|
||||
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 13, 2)))
|
||||
.include(dependency("org.junit.platform", "junit-platform-launcher", version(1, 13, 2)))
|
||||
.include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1)));
|
||||
|
||||
publishOperation()
|
||||
|
@ -119,15 +125,25 @@ public class BitlyShortenBuild extends Project {
|
|||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Enable detailed logging for the extensions
|
||||
var level = Level.ALL;
|
||||
var logger = Logger.getLogger("rife.bld.extension");
|
||||
var consoleHandler = new ConsoleHandler();
|
||||
|
||||
consoleHandler.setLevel(level);
|
||||
logger.addHandler(consoleHandler);
|
||||
logger.setLevel(level);
|
||||
logger.setUseParentHandlers(false);
|
||||
|
||||
new BitlyShortenBuild().start(args);
|
||||
}
|
||||
|
||||
@BuildCommand(summary = "Compiles the Kotlin project")
|
||||
@Override
|
||||
public void compile() throws Exception {
|
||||
new CompileKotlinOperation()
|
||||
.fromProject(this)
|
||||
.execute();
|
||||
var op = new CompileKotlinOperation().fromProject(this);
|
||||
op.compileOptions().languageVersion("1.9").verbose(true);
|
||||
op.execute();
|
||||
}
|
||||
|
||||
@BuildCommand(summary = "Checks source with Detekt")
|
||||
|
@ -169,11 +185,61 @@ public class BitlyShortenBuild extends Project {
|
|||
|
||||
@BuildCommand(summary = "Generates JaCoCo Reports")
|
||||
public void jacoco() throws Exception {
|
||||
new JacocoReportOperation()
|
||||
var op = new JacocoReportOperation().fromProject(this);
|
||||
op.testToolOptions("--reports-dir=" + TEST_RESULTS_DIR);
|
||||
|
||||
Exception ex = null;
|
||||
try {
|
||||
op.execute();
|
||||
} catch (Exception e) {
|
||||
ex = e;
|
||||
}
|
||||
|
||||
renderWithXunitViewer();
|
||||
|
||||
if (ex != null) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@BuildCommand(value = "pom-root", summary = "Generates the POM file in the root directory")
|
||||
public void pomRoot() throws FileUtilsErrorException {
|
||||
PomBuilder.generateInto(publishOperation().fromProject(this).info(), dependencies(),
|
||||
new File(workDirectory, "pom.xml"));
|
||||
}
|
||||
|
||||
private void renderWithXunitViewer() throws Exception {
|
||||
var xunitViewer = new File("/usr/bin/xunit-viewer");
|
||||
if (xunitViewer.exists() && xunitViewer.canExecute()) {
|
||||
var reportsDir = "build/reports/tests/test/";
|
||||
|
||||
Files.createDirectories(Path.of(reportsDir));
|
||||
|
||||
new ExecOperation()
|
||||
.fromProject(this)
|
||||
.sourceFiles(srcMainKotlin)
|
||||
.command(xunitViewer.getPath(), "-r", TEST_RESULTS_DIR, "-o", reportsDir + "index.html")
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
var op = testOperation().fromProject(this);
|
||||
op.testToolOptions().reportsDir(new File(TEST_RESULTS_DIR));
|
||||
|
||||
Exception ex = null;
|
||||
try {
|
||||
op.execute();
|
||||
} catch (Exception e) {
|
||||
ex = e;
|
||||
}
|
||||
|
||||
renderWithXunitViewer();
|
||||
|
||||
if (ex != null) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void javadoc() throws ExitStatusException, IOException, InterruptedException {
|
||||
|
@ -198,10 +264,4 @@ public class BitlyShortenBuild extends Project {
|
|||
super.publishLocal();
|
||||
pomRoot();
|
||||
}
|
||||
|
||||
@BuildCommand(value = "pom-root", summary = "Generates the POM file in the root directory")
|
||||
public void pomRoot() throws FileUtilsErrorException {
|
||||
PomBuilder.generateInto(publishOperation().fromProject(this).info(), dependencies(),
|
||||
new File(workDirectory, "pom.xml"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -174,8 +174,9 @@ object Utils {
|
|||
return false
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes http(s) scheme from string.
|
||||
* Removes the `http` or `https` schemes from a string.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun String.removeHttp(): String {
|
||||
|
@ -183,7 +184,7 @@ object Utils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Builds the full API endpoint URL using the [Constants.API_BASE_URL].
|
||||
* Converts a path to an API endpoint URL using the [Constants.API_BASE_URL], unless a URL is already specified.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun String.toEndPoint(): String {
|
||||
|
|
52
src/test/kotlin/net/thauvin/erik/bitly/BeforeAllTests.kt
Normal file
52
src/test/kotlin/net/thauvin/erik/bitly/BeforeAllTests.kt
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* BeforeAllTests.kt
|
||||
*
|
||||
* Copyright 2020-2025 Erik C. Thauvin (erik@thauvin.net)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of this project nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.bitly
|
||||
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.logging.ConsoleHandler
|
||||
import java.util.logging.Level
|
||||
|
||||
class BeforeAllTests : BeforeAllCallback {
|
||||
private val isFirstTime: AtomicBoolean = AtomicBoolean(true)
|
||||
|
||||
override fun beforeAll(context: ExtensionContext?) {
|
||||
if (isFirstTime.getAndSet(false)) {
|
||||
with(Utils.logger) {
|
||||
addHandler(ConsoleHandler().apply { level = Level.FINE })
|
||||
level = Level.FINE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
328
src/test/kotlin/net/thauvin/erik/bitly/BitlinksTests.kt
Normal file
328
src/test/kotlin/net/thauvin/erik/bitly/BitlinksTests.kt
Normal file
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* BitlinksTests.kt
|
||||
*
|
||||
* Copyright 2020-2025 Erik C. Thauvin (erik@thauvin.net)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of this project nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.bitly
|
||||
|
||||
import DisableOnCi
|
||||
import assertk.all
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.*
|
||||
import net.thauvin.erik.bitly.config.CreateConfig
|
||||
import net.thauvin.erik.bitly.config.UpdateConfig
|
||||
import net.thauvin.erik.bitly.config.deeplinks.CreateDeeplinks
|
||||
import net.thauvin.erik.bitly.config.deeplinks.UpdateDeeplinks
|
||||
import net.thauvin.erik.bitly.config.deeplinks.enums.InstallType
|
||||
import net.thauvin.erik.bitly.config.deeplinks.enums.Os
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Nested
|
||||
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 kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@ExtendWith(BeforeAllTests::class)
|
||||
class BitlinksTests {
|
||||
private val bitly = with(File("local.properties")) {
|
||||
if (exists()) {
|
||||
Bitly(toPath())
|
||||
} else {
|
||||
Bitly()
|
||||
}
|
||||
}
|
||||
private val longUrl = "https://erik.thauvin.net/blog"
|
||||
private val shortUrl = "https://bit.ly/380ojFd"
|
||||
|
||||
@Nested
|
||||
@DisplayName("Bitlinks Tests")
|
||||
inner class BitlinksTests {
|
||||
@Test
|
||||
fun `Clicks summary`() {
|
||||
val bl = bitly.bitlinks()
|
||||
val clicks = bl.clicks(shortUrl, unit = Units.MONTH, units = 1)
|
||||
assertThat(bl.lastCallResponse).all {
|
||||
prop(CallResponse::description).isEmpty()
|
||||
prop(CallResponse::isSuccessful).isTrue()
|
||||
prop(CallResponse::statusCode).isEqualTo(200)
|
||||
}
|
||||
assertThat(clicks.toInt()).isGreaterThanOrEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Clicks summary as json`() {
|
||||
val bl = bitly.bitlinks()
|
||||
val clicks = bl.clicks(shortUrl, toJson = true)
|
||||
assertThat(bl.lastCallResponse).all {
|
||||
prop(CallResponse::description).isEmpty()
|
||||
prop(CallResponse::isSuccessful).isTrue()
|
||||
prop(CallResponse::statusCode).isEqualTo(200)
|
||||
}
|
||||
assertThat(clicks).startsWith("{\"unit_reference\":")
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("Create Bitlink Tests")
|
||||
inner class CreateBitlinkTests {
|
||||
@Test
|
||||
fun `Create bitlink`() {
|
||||
assertThat(bitly.bitlinks().create(long_url = longUrl), "create(longUrl)")
|
||||
.matches("https://\\w+.\\w{2}/\\w{7}".toRegex())
|
||||
assertEquals(
|
||||
shortUrl,
|
||||
bitly.bitlinks().create(
|
||||
domain = "bit.ly",
|
||||
title = "Erik's Blog",
|
||||
tags = arrayOf("erik", "thauvin", "blog", "weblog"),
|
||||
long_url = longUrl
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Create bitlink with config`() {
|
||||
var config = CreateConfig.Builder(longUrl).build()
|
||||
assertThat(bitly.bitlinks().create(config), "create(config)")
|
||||
.matches("https://\\w+.\\w{2}/\\w{7}".toRegex())
|
||||
|
||||
config = CreateConfig.Builder(longUrl)
|
||||
.domain("bit.ly")
|
||||
.title("Erik's Blog")
|
||||
.tags(arrayOf("erik", "thauvin", "blog", "weblog"))
|
||||
.build()
|
||||
assertEquals(
|
||||
shortUrl,
|
||||
bitly.bitlinks().create(config)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Create bitlink with deep links`() {
|
||||
val bl = bitly.bitlinks()
|
||||
val dl = CreateDeeplinks().apply {
|
||||
app_uri_path("/store?id=123456")
|
||||
install_type(InstallType.NO_INSTALL)
|
||||
install_url("https://play.google.com/store/apps/details?id=com.bitly.app&hl=en_US")
|
||||
}
|
||||
|
||||
val config = CreateConfig.Builder(longUrl)
|
||||
.deeplinks(dl)
|
||||
.domain("bit.ly")
|
||||
.build()
|
||||
|
||||
assertThat(bl.create(config)).isEqualTo(Constants.EMPTY)
|
||||
assertThat(bl.lastCallResponse.isUpgradeRequired).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("Expand Test")
|
||||
inner class ExpandTests {
|
||||
@Test
|
||||
fun `Expand as json`() {
|
||||
assertTrue(
|
||||
bitly.bitlinks().expand(shortUrl, toJson = true)
|
||||
.startsWith("{\"created_at\":")
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Expand link`() {
|
||||
assertEquals(longUrl, Bitlinks(bitly.accessToken).expand(shortUrl))
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("Shorten Tests")
|
||||
inner class ShortenTests {
|
||||
@Test
|
||||
fun `Shorten as json`() {
|
||||
assertTrue(
|
||||
bitly.bitlinks().shorten(longUrl, toJson = true)
|
||||
.startsWith("{\"created_at\":")
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Shorten last call response`() {
|
||||
val bl = Bitlinks(bitly.accessToken)
|
||||
bl.shorten(longUrl, domain = "bit.ly")
|
||||
assertThat(bl.lastCallResponse, "shorten(longUrl)").all {
|
||||
prop(CallResponse::body).contains("\"link\":\"$shortUrl\"")
|
||||
prop(CallResponse::isSuccessful).isTrue()
|
||||
prop(CallResponse::message).isEmpty()
|
||||
prop(CallResponse::statusCode).isEqualTo(200)
|
||||
}
|
||||
|
||||
bl.shorten(shortUrl)
|
||||
assertThat(bl.lastCallResponse, "shorten(shortUrl)").all {
|
||||
prop(CallResponse::description).isEqualTo("The value provided is invalid.")
|
||||
prop(CallResponse::isBadRequest).isTrue()
|
||||
prop(CallResponse::isSuccessful).isFalse()
|
||||
prop(CallResponse::message).isEqualTo("ALREADY_A_BITLY_LINK")
|
||||
prop(CallResponse::statusCode).isEqualTo(400)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Shorten link`() {
|
||||
assertEquals(
|
||||
shortUrl, Bitlinks(bitly.accessToken)
|
||||
.shorten(longUrl, domain = "bit.ly")
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Shorten with invalid domain`() {
|
||||
val bl = bitly.bitlinks()
|
||||
bl.shorten("https://www.examples.com", domain = "foo.com")
|
||||
assertThat(bl.lastCallResponse).all {
|
||||
prop(CallResponse::description).contains("invalid")
|
||||
prop(CallResponse::isBadRequest).isTrue()
|
||||
prop(CallResponse::isSuccessful).isFalse()
|
||||
prop(CallResponse::message).isEqualTo("INVALID_ARG_DOMAIN")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
)
|
||||
)
|
||||
|
||||
assertThat(bl.update(shortUrl, tags = emptyArray(), toJson = true), "update(tags)")
|
||||
.contains("\"tags\":[]")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Update bitlink with config`() {
|
||||
val bl = bitly.bitlinks()
|
||||
var config = UpdateConfig.Builder(shortUrl)
|
||||
.archived(true)
|
||||
.tags(arrayOf("blog", "weblog"))
|
||||
.title("Erik's Weblog")
|
||||
.build()
|
||||
|
||||
assertEquals(Constants.TRUE, bl.update(config))
|
||||
|
||||
config = UpdateConfig.Builder(shortUrl)
|
||||
.toJson(true)
|
||||
.build()
|
||||
|
||||
assertThat(bl.update(config), "update(tags)").contains("\"tags\":[]")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Update bitlink with deep links`() {
|
||||
val bl = bitly.bitlinks()
|
||||
val dl = UpdateDeeplinks().apply {
|
||||
os(Os.ANDROID)
|
||||
brand_guid("Ba1bc23dE4F")
|
||||
}
|
||||
val config = UpdateConfig.Builder(shortUrl)
|
||||
.deeplinks(dl)
|
||||
.build()
|
||||
|
||||
assertThat(bl.update(config)).isEqualTo(Constants.FALSE)
|
||||
assertThat(bl.lastCallResponse.isUpgradeRequired).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableOnCi
|
||||
fun `Update custom bitlink`() {
|
||||
val bl = bitly.bitlinks()
|
||||
assertEquals(
|
||||
Constants.TRUE,
|
||||
bl.updateCustom("https://thauv.in/2NwtljT", "thauv.in/2NwtljT")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("Validation Tests")
|
||||
inner class ValidationTests {
|
||||
@Test
|
||||
fun `Empty URL should not shorten`() {
|
||||
assertEquals(Constants.EMPTY, bitly.bitlinks().shorten(Constants.EMPTY))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Short URL should not shorten`() {
|
||||
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`() {
|
||||
val test = Bitly()
|
||||
|
||||
assertFailsWith(IllegalArgumentException::class) {
|
||||
test.bitlinks().shorten(longUrl)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledIfEnvironmentVariable(named = "CI", matches = "true")
|
||||
fun `Token not specified on CI`() {
|
||||
val test = Bitly(Constants.EMPTY) // to avoid picking up the environment variable
|
||||
|
||||
assertFailsWith(IllegalArgumentException::class) {
|
||||
test.bitlinks().shorten(longUrl)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Token should be valid`() {
|
||||
val test = Bitly().apply { accessToken = "12345679" }
|
||||
assertEquals(
|
||||
"{\"message\":\"FORBIDDEN\"}",
|
||||
test.bitlinks().shorten("https://erik.thauvin.net/blog", toJson = true)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,324 +0,0 @@
|
|||
/*
|
||||
* BitlyTest.kt
|
||||
*
|
||||
* Copyright 2020-2025 Erik C. Thauvin (erik@thauvin.net)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of this project nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.bitly
|
||||
|
||||
import DisableOnCi
|
||||
import assertk.all
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.*
|
||||
import net.thauvin.erik.bitly.Utils.isValidUrl
|
||||
import net.thauvin.erik.bitly.Utils.removeHttp
|
||||
import net.thauvin.erik.bitly.Utils.toEndPoint
|
||||
import net.thauvin.erik.bitly.config.CreateConfig
|
||||
import net.thauvin.erik.bitly.config.UpdateConfig
|
||||
import net.thauvin.erik.bitly.config.deeplinks.CreateDeeplinks
|
||||
import net.thauvin.erik.bitly.config.deeplinks.UpdateDeeplinks
|
||||
import net.thauvin.erik.bitly.config.deeplinks.enums.InstallType
|
||||
import net.thauvin.erik.bitly.config.deeplinks.enums.Os
|
||||
import org.json.JSONObject
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
import java.io.File
|
||||
import java.util.logging.Level
|
||||
import kotlin.test.*
|
||||
|
||||
class BitlyTest {
|
||||
private val bitly = with(File("local.properties")) {
|
||||
if (exists()) {
|
||||
Bitly(toPath())
|
||||
} else {
|
||||
Bitly()
|
||||
}
|
||||
}
|
||||
private val longUrl = "https://erik.thauvin.net/blog"
|
||||
private val shortUrl = "https://bit.ly/380ojFd"
|
||||
|
||||
@Test
|
||||
fun `token should be specified`() {
|
||||
val test = Bitly()
|
||||
if (System.getenv("CI") == "true") {
|
||||
test.accessToken = Constants.EMPTY
|
||||
}
|
||||
assertFailsWith(IllegalArgumentException::class) {
|
||||
test.bitlinks().shorten(longUrl)
|
||||
}
|
||||
assertFailsWith(IllegalArgumentException::class, "Utils.call()") {
|
||||
Utils.call("", "foo")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `token should be valid`() {
|
||||
val test = Bitly().apply { accessToken = "12345679" }
|
||||
assertEquals(
|
||||
"{\"message\":\"FORBIDDEN\"}",
|
||||
test.bitlinks().shorten("https://erik.thauvin.net/blog", toJson = true)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `long url should be valid`() {
|
||||
assertEquals(Constants.EMPTY, bitly.bitlinks().shorten(Constants.EMPTY))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `long url should not be short`() {
|
||||
assertEquals(shortUrl, bitly.bitlinks().shorten(shortUrl))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `endPoint should be specified`() {
|
||||
assertFailsWith(IllegalArgumentException::class, "bitly.call()") {
|
||||
bitly.call("")
|
||||
}
|
||||
assertFailsWith(IllegalArgumentException::class, "Utils.call()") {
|
||||
Utils.call("1234568", "")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `endPoint conversion`() {
|
||||
assertThat(Constants.API_BASE_URL.toEndPoint()).isEqualTo(Constants.API_BASE_URL)
|
||||
assertThat("path".toEndPoint()).isEqualTo("${Constants.API_BASE_URL}/path")
|
||||
assertThat("/path".toEndPoint()).isEqualTo("${Constants.API_BASE_URL}/path")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `shorten = expand`() {
|
||||
val shortUrl = bitly.bitlinks().shorten(longUrl, domain = "bit.ly")
|
||||
assertEquals(longUrl, bitly.bitlinks().expand(shortUrl))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `shorten as json`() {
|
||||
assertTrue(bitly.bitlinks().shorten(longUrl, toJson = true).startsWith("{\"created_at\":"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get user`() {
|
||||
assertThat(bitly.call("user", method = Methods.GET), "call(user)")
|
||||
.prop(CallResponse::isSuccessful).isTrue()
|
||||
assertThat(Utils.call(bitly.accessToken, "user".toEndPoint(), method = Methods.GET), "call(/user)").all {
|
||||
prop(CallResponse::isSuccessful).isTrue()
|
||||
prop(CallResponse::body).contains("login")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `created by`() {
|
||||
assertEquals(
|
||||
"ethauvin",
|
||||
JSONObject(
|
||||
bitly.call(
|
||||
"/bitlinks/${shortUrl.removeHttp()}",
|
||||
method = Methods.GET
|
||||
).body
|
||||
).getString("created_by")
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `bitlinks shorten`() {
|
||||
assertEquals(shortUrl, Bitlinks(bitly.accessToken).shorten(longUrl, domain = "bit.ly"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `bitlinks expand`() {
|
||||
assertEquals(longUrl, Bitlinks(bitly.accessToken).expand(shortUrl))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `bitlinks lastCallResponse`() {
|
||||
val bl = Bitlinks(bitly.accessToken)
|
||||
bl.shorten(longUrl, domain = "bit.ly")
|
||||
assertThat(bl.lastCallResponse, "shorten(longUrl)").all {
|
||||
prop(CallResponse::isSuccessful).isTrue()
|
||||
prop(CallResponse::statusCode).isEqualTo(200)
|
||||
prop(CallResponse::body).contains("\"link\":\"$shortUrl\"")
|
||||
prop(CallResponse::message).isEmpty()
|
||||
}
|
||||
|
||||
bl.shorten(shortUrl)
|
||||
assertThat(bl.lastCallResponse, "shorten(shortUrl)").all {
|
||||
prop(CallResponse::isSuccessful).isFalse()
|
||||
prop(CallResponse::statusCode).isEqualTo(400)
|
||||
prop(CallResponse::isBadRequest).isTrue()
|
||||
prop(CallResponse::message).isEqualTo("ALREADY_A_BITLY_LINK")
|
||||
prop(CallResponse::description).isEqualTo("The value provided is invalid.")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicks summary`() {
|
||||
val bl = bitly.bitlinks()
|
||||
assertThat(bl.clicks(shortUrl)).isNotEqualTo(Constants.EMPTY)
|
||||
val clicks = bl.clicks(shortUrl, unit = Units.MONTH, units = 1)
|
||||
assertThat(bl.lastCallResponse).all {
|
||||
prop(CallResponse::isSuccessful).isTrue()
|
||||
prop(CallResponse::statusCode).isEqualTo(200)
|
||||
prop(CallResponse::description).isEmpty()
|
||||
}
|
||||
assertThat(clicks.toInt()).isGreaterThanOrEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `create bitlink`() {
|
||||
assertThat(bitly.bitlinks().create(long_url = longUrl), "create(longUrl)")
|
||||
.matches("https://\\w+.\\w{2}/\\w{7}".toRegex())
|
||||
assertEquals(
|
||||
shortUrl,
|
||||
bitly.bitlinks().create(
|
||||
domain = "bit.ly",
|
||||
title = "Erik's Blog",
|
||||
tags = arrayOf("erik", "thauvin", "blog", "weblog"),
|
||||
long_url = longUrl
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `create bitlink with config`() {
|
||||
var config = CreateConfig.Builder(longUrl).build()
|
||||
assertThat(bitly.bitlinks().create(config), "create(config)")
|
||||
.matches("https://\\w+.\\w{2}/\\w{7}".toRegex())
|
||||
|
||||
config = CreateConfig.Builder(longUrl)
|
||||
.domain("bit.ly")
|
||||
.title("Erik's Blog")
|
||||
.tags(arrayOf("erik", "thauvin", "blog", "weblog"))
|
||||
.build()
|
||||
assertEquals(
|
||||
shortUrl,
|
||||
bitly.bitlinks().create(config)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `create bitlink with deeplinks`() {
|
||||
val bl = bitly.bitlinks()
|
||||
val dl = CreateDeeplinks().apply {
|
||||
install_type(InstallType.NO_INSTALL)
|
||||
app_uri_path("/store?id=123456")
|
||||
install_url("https://play.google.com/store/apps/details?id=com.bitly.app&hl=en_US")
|
||||
}
|
||||
|
||||
val config = CreateConfig.Builder(longUrl)
|
||||
.domain("bit.ly")
|
||||
.deeplinks(dl)
|
||||
.build()
|
||||
|
||||
assertThat(bl.create(config)).isEqualTo(Constants.EMPTY)
|
||||
assertThat(bl.lastCallResponse.isUpgradeRequired).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `shorten with invalid domain`() {
|
||||
val bl = bitly.bitlinks()
|
||||
bl.shorten("https://www.examples.com", domain = "foo.com")
|
||||
assertThat(bl.lastCallResponse).all {
|
||||
prop(CallResponse::isSuccessful).isFalse()
|
||||
prop(CallResponse::isBadRequest).isTrue()
|
||||
prop(CallResponse::message).isEqualTo("INVALID_ARG_DOMAIN")
|
||||
prop(CallResponse::description).contains("invalid")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableOnCi
|
||||
fun `update custom bitlink`() {
|
||||
val bl = bitly.bitlinks()
|
||||
assertEquals(
|
||||
Constants.TRUE,
|
||||
bl.updateCustom("https://thauv.in/2NwtljT", "thauv.in/2NwtljT")
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `update bitlink`() {
|
||||
val bl = bitly.bitlinks()
|
||||
assertEquals(
|
||||
Constants.TRUE,
|
||||
bl.update(shortUrl, title = "Erik's Weblog", tags = arrayOf("blog", "weblog"), archived = true)
|
||||
)
|
||||
|
||||
assertThat(bl.update(shortUrl, tags = emptyArray(), toJson = true), "update(tags)")
|
||||
.contains("\"tags\":[]")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `update bitlink with config`() {
|
||||
val bl = bitly.bitlinks()
|
||||
var config = UpdateConfig.Builder(shortUrl)
|
||||
.title("Erik's Weblog")
|
||||
.tags(arrayOf("blog", "weblog"))
|
||||
.archived(true)
|
||||
.build()
|
||||
|
||||
assertEquals(Constants.TRUE, bl.update(config))
|
||||
|
||||
config = UpdateConfig.Builder(shortUrl)
|
||||
.toJson(true)
|
||||
.build()
|
||||
|
||||
assertThat(bl.update(config), "update(tags)").contains("\"tags\":[]")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `update bitlink with deeplinks`() {
|
||||
val bl = bitly.bitlinks()
|
||||
val dl = UpdateDeeplinks().apply {
|
||||
os(Os.ANDROID)
|
||||
brand_guid("Ba1bc23dE4F")
|
||||
}
|
||||
val config = UpdateConfig.Builder(shortUrl)
|
||||
.deeplinks(dl)
|
||||
.build()
|
||||
|
||||
assertThat(bl.update(config)).isEqualTo(Constants.FALSE)
|
||||
assertThat(bl.lastCallResponse.isUpgradeRequired).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validate URL`() {
|
||||
assertTrue("https://www.example.com".isValidUrl(), "valid url")
|
||||
assertFalse("this is a test".isValidUrl(), "invalid url")
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@BeforeAll
|
||||
fun before() {
|
||||
with(Utils.logger) {
|
||||
level = Level.FINE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
101
src/test/kotlin/net/thauvin/erik/bitly/BitlyTests.kt
Normal file
101
src/test/kotlin/net/thauvin/erik/bitly/BitlyTests.kt
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* BitlyTests.kt
|
||||
*
|
||||
* Copyright 2020-2025 Erik C. Thauvin (erik@thauvin.net)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of this project nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.bitly
|
||||
|
||||
import assertk.all
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.contains
|
||||
import assertk.assertions.isTrue
|
||||
import assertk.assertions.prop
|
||||
import net.thauvin.erik.bitly.Utils.removeHttp
|
||||
import net.thauvin.erik.bitly.Utils.toEndPoint
|
||||
import org.json.JSONObject
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import java.io.File
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
@ExtendWith(BeforeAllTests::class)
|
||||
class BitlyTests {
|
||||
private val bitly = with(File("local.properties")) {
|
||||
if (exists()) {
|
||||
Bitly(toPath())
|
||||
} else {
|
||||
Bitly()
|
||||
}
|
||||
}
|
||||
private val shortUrl = "https://bit.ly/380ojFd"
|
||||
|
||||
@Nested
|
||||
@DisplayName("API Call Tests")
|
||||
inner class ApiCallTests {
|
||||
@Test
|
||||
fun `Created by`() {
|
||||
assertEquals(
|
||||
"ethauvin",
|
||||
JSONObject(
|
||||
bitly.call(
|
||||
"/bitlinks/${shortUrl.removeHttp()}",
|
||||
method = Methods.GET
|
||||
).body
|
||||
).getString("created_by")
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `EndPoint should be specified`() {
|
||||
assertFailsWith(IllegalArgumentException::class, "bitly.call()") {
|
||||
bitly.call("")
|
||||
}
|
||||
assertFailsWith(IllegalArgumentException::class, "Utils.call()") {
|
||||
Utils.call("1234568", "")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get user`() {
|
||||
assertThat(bitly.call("user", method = Methods.GET), "call(user)")
|
||||
.prop(CallResponse::isSuccessful).isTrue()
|
||||
assertThat(
|
||||
Utils.call(
|
||||
bitly.accessToken, "user".toEndPoint(), method = Methods.GET
|
||||
), "call(/user)"
|
||||
).all {
|
||||
prop(CallResponse::isSuccessful).isTrue()
|
||||
prop(CallResponse::body).contains("login")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
114
src/test/kotlin/net/thauvin/erik/bitly/UtilsTests.kt
Normal file
114
src/test/kotlin/net/thauvin/erik/bitly/UtilsTests.kt
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* UtilsTests.kt
|
||||
*
|
||||
* Copyright 2020-2025 Erik C. Thauvin (erik@thauvin.net)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of this project nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.bitly
|
||||
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import net.thauvin.erik.bitly.Utils.isValidUrl
|
||||
import net.thauvin.erik.bitly.Utils.removeHttp
|
||||
import net.thauvin.erik.bitly.Utils.toEndPoint
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class UtilsTests {
|
||||
@Nested
|
||||
@DisplayName("Endpoint Conversion Tests")
|
||||
inner class EndpointConversionTests {
|
||||
@Test
|
||||
fun `Convert endpoint with empty string`() {
|
||||
assertThat("".toEndPoint()).isEqualTo("")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Convert endpoint with full URL`() {
|
||||
assertThat("https://example.com/path".toEndPoint()).isEqualTo("https://example.com/path")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Convert endpoint with leading slash`() {
|
||||
assertThat("/path".toEndPoint()).isEqualTo("${Constants.API_BASE_URL}/path")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Convert endpoint with multiple path segments`() {
|
||||
assertThat("/existing/path".toEndPoint()).isEqualTo("${Constants.API_BASE_URL}/existing/path")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Convert endpoint with no leading slash`() {
|
||||
assertThat("path".toEndPoint()).isEqualTo("${Constants.API_BASE_URL}/path")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Convert endpoint with trailing slash`() {
|
||||
assertThat("path/".toEndPoint()).isEqualTo("${Constants.API_BASE_URL}/path/")
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("Remote HTTP Tests")
|
||||
inner class RemoteHTTPTests {
|
||||
@Test
|
||||
@Suppress("HttpUrlsUsage")
|
||||
fun `Remove HTTP`() {
|
||||
assertThat("http://example.com".removeHttp()).isEqualTo("example.com")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Remove HTTPS`() {
|
||||
assertThat("https://example.com".removeHttp()).isEqualTo("example.com")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Remove mixed case`() {
|
||||
assertThat("HtTPs://EXAMPLE.Com".removeHttp()).isEqualTo("EXAMPLE.Com")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Remove no scheme`() {
|
||||
assertThat("example.com".removeHttp()).isEqualTo("example.com")
|
||||
}
|
||||
}
|
||||
|
||||
@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")
|
||||
}
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* ConfigTest.kt
|
||||
*
|
||||
* Copyright 2020-2025 Erik C. Thauvin (erik@thauvin.net)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of this project nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.bitly.config
|
||||
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import net.thauvin.erik.bitly.config.deeplinks.CreateDeeplinks
|
||||
import net.thauvin.erik.bitly.config.deeplinks.UpdateDeeplinks
|
||||
import net.thauvin.erik.bitly.config.deeplinks.enums.InstallType
|
||||
import net.thauvin.erik.bitly.config.deeplinks.enums.Os
|
||||
import org.json.JSONObject
|
||||
import kotlin.test.Test
|
||||
|
||||
class ConfigTest {
|
||||
@Test
|
||||
fun `create config test`() {
|
||||
val deeplinks = CreateDeeplinks().apply {
|
||||
app_id("app_id")
|
||||
install_type(InstallType.AUTO_INSTALL)
|
||||
}
|
||||
|
||||
val config = CreateConfig.Builder("long_url")
|
||||
.domain("domain")
|
||||
.groupGuid("group_guid")
|
||||
.title("title")
|
||||
.tags(arrayOf("tag", "tag2"))
|
||||
.deeplinks(deeplinks)
|
||||
.build()
|
||||
|
||||
val map = mapOf(
|
||||
"long_url" to config.long_url,
|
||||
"domain" to config.domain,
|
||||
"group_guid" to config.group_guid,
|
||||
"title" to config.title,
|
||||
"tags" to config.tags,
|
||||
"deeplinks" to arrayOf(deeplinks.links())
|
||||
)
|
||||
|
||||
assertThat(JSONObject(map).toString()).isEqualTo(
|
||||
"""
|
||||
{"group_guid":"group_guid","long_url":"long_url","title":"title","deeplinks":[{"app_id":"app_id","install_type":"auto_install"}],"domain":"domain","tags":["tag","tag2"]}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `update config test`() {
|
||||
val deeplinks = UpdateDeeplinks().apply {
|
||||
os(Os.IOS)
|
||||
install_type(InstallType.PROMOTE_INSTALL)
|
||||
app_guid("app_guid")
|
||||
}
|
||||
|
||||
val config = UpdateConfig.Builder("blink")
|
||||
.title("title")
|
||||
.archived(true)
|
||||
.tags(arrayOf("tag", "tag2"))
|
||||
.deeplinks(deeplinks)
|
||||
.build()
|
||||
|
||||
val map = mapOf(
|
||||
"bitlink" to config.bitlink,
|
||||
"title" to config.title,
|
||||
"archived" to config.archived,
|
||||
"tags" to config.tags,
|
||||
"deeplinks" to arrayOf(deeplinks.links())
|
||||
)
|
||||
|
||||
assertThat(JSONObject(map).toString()).isEqualTo(
|
||||
"""
|
||||
{"archived":true,"bitlink":"blink","title":"title","deeplinks":[{"os":"ios","app_guid":"app_guid","install_type":"promote_install"}],"tags":["tag","tag2"]}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
}
|
||||
}
|
223
src/test/kotlin/net/thauvin/erik/bitly/config/ConfigTests.kt
Normal file
223
src/test/kotlin/net/thauvin/erik/bitly/config/ConfigTests.kt
Normal file
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* ConfigTests.kt
|
||||
*
|
||||
* Copyright 2020-2025 Erik C. Thauvin (erik@thauvin.net)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of this project nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.bitly.config
|
||||
|
||||
import assertk.all
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import assertk.assertions.isTrue
|
||||
import assertk.assertions.prop
|
||||
import net.thauvin.erik.bitly.Constants
|
||||
import net.thauvin.erik.bitly.config.deeplinks.CreateDeeplinks
|
||||
import net.thauvin.erik.bitly.config.deeplinks.UpdateDeeplinks
|
||||
import net.thauvin.erik.bitly.config.deeplinks.enums.InstallType
|
||||
import net.thauvin.erik.bitly.config.deeplinks.enums.Os
|
||||
import org.json.JSONObject
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Nested
|
||||
import kotlin.test.Test
|
||||
|
||||
class ConfigTests {
|
||||
@Nested
|
||||
@DisplayName("Build Configuration Tests")
|
||||
inner class BuildConfigurationTests {
|
||||
@Test
|
||||
fun `Build create configuration`() {
|
||||
val deeplinks = CreateDeeplinks().apply {
|
||||
app_id("app_id")
|
||||
install_type(InstallType.AUTO_INSTALL)
|
||||
}
|
||||
|
||||
val config = CreateConfig.Builder("long_url")
|
||||
.deeplinks(deeplinks)
|
||||
.domain("domain")
|
||||
.groupGuid("group_guid")
|
||||
.tags(arrayOf("tag", "tag2"))
|
||||
.title("title")
|
||||
.build()
|
||||
|
||||
assertThat(config).all {
|
||||
prop(CreateConfig::deeplinks).isEqualTo(deeplinks)
|
||||
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::title).isEqualTo("title")
|
||||
prop(CreateConfig::toJson).isEqualTo(false)
|
||||
}
|
||||
|
||||
val map = mapOf(
|
||||
"deeplinks" to arrayOf(deeplinks.links()),
|
||||
"domain" to config.domain,
|
||||
"group_guid" to config.group_guid,
|
||||
"long_url" to config.long_url,
|
||||
"tags" to config.tags,
|
||||
"title" to config.title
|
||||
)
|
||||
|
||||
assertThat(JSONObject(map).toString()).isEqualTo(
|
||||
"""
|
||||
{"group_guid":"group_guid","deeplinks":[{"app_id":"app_id","install_type":"auto_install"}],"long_url":"long_url","title":"title","domain":"domain","tags":["tag","tag2"]}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Build update configuration`() {
|
||||
val deeplinks = UpdateDeeplinks().apply {
|
||||
os(Os.IOS)
|
||||
install_type(InstallType.PROMOTE_INSTALL)
|
||||
app_guid("app_guid")
|
||||
}
|
||||
|
||||
val config = UpdateConfig.Builder("blink")
|
||||
.archived(true)
|
||||
.deeplinks(deeplinks)
|
||||
.tags(arrayOf("tag", "tag2"))
|
||||
.title("title")
|
||||
.build()
|
||||
|
||||
assertThat(config).all {
|
||||
prop(UpdateConfig::archived).isTrue()
|
||||
prop(UpdateConfig::bitlink).isEqualTo("blink")
|
||||
prop(UpdateConfig::deeplinks).isEqualTo(deeplinks)
|
||||
prop(UpdateConfig::tags).isEqualTo(arrayOf("tag", "tag2"))
|
||||
prop(UpdateConfig::title).isEqualTo("title")
|
||||
prop(UpdateConfig::toJson).isEqualTo(false)
|
||||
}
|
||||
|
||||
val map = mapOf(
|
||||
"archived" to config.archived,
|
||||
"bitlink" to config.bitlink,
|
||||
"deeplinks" to arrayOf(deeplinks.links()),
|
||||
"tags" to config.tags,
|
||||
"title" to config.title
|
||||
)
|
||||
|
||||
assertThat(JSONObject(map).toString()).isEqualTo(
|
||||
"""
|
||||
{"archived":true,"bitlink":"blink","deeplinks":[{"os":"ios","app_guid":"app_guid","install_type":"promote_install"}],"title":"title","tags":["tag","tag2"]}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("Validate Configuration Tests")
|
||||
inner class ValidateConfigurationTests {
|
||||
@Test
|
||||
fun `Validate create configuration`() {
|
||||
val deeplinks = CreateDeeplinks().apply {
|
||||
app_id("app_id")
|
||||
install_type(InstallType.AUTO_INSTALL)
|
||||
}
|
||||
|
||||
val config = CreateConfig.Builder("long_url")
|
||||
.deeplinks(deeplinks)
|
||||
.domain("domain")
|
||||
.groupGuid("group_guid")
|
||||
.tags(arrayOf("tag", "tag2"))
|
||||
.title("title")
|
||||
.toJson(true)
|
||||
|
||||
assertThat(config).all {
|
||||
prop(CreateConfig.Builder::deeplinks).prop(CreateDeeplinks::links).isEqualTo(deeplinks.links())
|
||||
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::title).isEqualTo("title")
|
||||
prop(CreateConfig.Builder::toJson).isTrue()
|
||||
}
|
||||
|
||||
config.longUrl("longer_url")
|
||||
assertThat(config).prop(CreateConfig.Builder::long_url).isEqualTo("longer_url")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Validate create default configuration`() {
|
||||
val config = CreateConfig.Builder("long_url")
|
||||
|
||||
assertThat(config).all {
|
||||
prop(CreateConfig.Builder::long_url).isEqualTo("long_url")
|
||||
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::deeplinks).prop(CreateDeeplinks::links).isEqualTo(CreateDeeplinks().links())
|
||||
prop(CreateConfig.Builder::toJson).isEqualTo(false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Validate update configuration`() {
|
||||
val deeplinks = UpdateDeeplinks().apply {
|
||||
os(Os.IOS)
|
||||
install_type(InstallType.PROMOTE_INSTALL)
|
||||
app_guid("app_guid")
|
||||
}
|
||||
|
||||
val config = UpdateConfig.Builder("bitlink")
|
||||
.title("title")
|
||||
.archived(true)
|
||||
.tags(arrayOf("tag", "tag2"))
|
||||
.deeplinks(deeplinks)
|
||||
.toJson(true)
|
||||
|
||||
assertThat(config).all {
|
||||
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::deeplinks).isEqualTo(deeplinks)
|
||||
prop(UpdateConfig.Builder::toJson).isTrue()
|
||||
}
|
||||
|
||||
config.bitlink("blink")
|
||||
assertThat(config).prop(UpdateConfig.Builder::bitlink).isEqualTo("blink")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Validate update default configuration`() {
|
||||
val config = UpdateConfig.Builder("bitlink")
|
||||
|
||||
assertThat(config).all {
|
||||
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::deeplinks).prop(UpdateDeeplinks::links).isEqualTo(UpdateDeeplinks().links())
|
||||
prop(UpdateConfig.Builder::toJson).isEqualTo(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* DeeplinksTest.kt
|
||||
* DeeplinksTests.kt
|
||||
*
|
||||
* Copyright 2020-2025 Erik C. Thauvin (erik@thauvin.net)
|
||||
*
|
||||
|
@ -31,11 +31,11 @@
|
|||
|
||||
package net.thauvin.erik.bitly.config.deeplinks
|
||||
|
||||
import assertk.all
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.contains
|
||||
import assertk.assertions.doesNotContain
|
||||
import assertk.assertions.isEqualTo
|
||||
import assertk.assertions.isNull
|
||||
import assertk.assertions.prop
|
||||
import net.thauvin.erik.bitly.config.deeplinks.enums.InstallType
|
||||
import net.thauvin.erik.bitly.config.deeplinks.enums.Os
|
||||
import org.json.JSONObject
|
||||
|
@ -43,90 +43,94 @@ import org.junit.Test
|
|||
import java.time.ZoneId
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
class DeeplinksTest {
|
||||
class DeeplinksTests {
|
||||
@Test
|
||||
fun `create test`() {
|
||||
fun `Create deeplink`() {
|
||||
val deeplinks = CreateDeeplinks().apply {
|
||||
app_uri_path("app_uri_path")
|
||||
install_type(InstallType.NO_INSTALL)
|
||||
}
|
||||
|
||||
assertThat(deeplinks.install_url()).isNull()
|
||||
deeplinks.install_url("install_url")
|
||||
|
||||
assertThat(deeplinks.app_uri_path()).isEqualTo("app_uri_path")
|
||||
assertThat(deeplinks.install_type()).isEqualTo(InstallType.NO_INSTALL)
|
||||
assertThat(deeplinks).all {
|
||||
prop(CreateDeeplinks::app_id).isNull()
|
||||
prop(CreateDeeplinks::app_uri_path).isEqualTo("app_uri_path")
|
||||
prop(CreateDeeplinks::install_type).isEqualTo(InstallType.NO_INSTALL)
|
||||
prop(CreateDeeplinks::install_url).isNull()
|
||||
prop(CreateDeeplinks::links).isEqualTo(deeplinks.links())
|
||||
}
|
||||
|
||||
assertThat(JSONObject(deeplinks.links()).toString()).isEqualTo(
|
||||
"""
|
||||
{"app_uri_path":"app_uri_path","install_type":"no_install","install_url":"install_url"}
|
||||
{"app_uri_path":"app_uri_path","install_type":"no_install"}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
deeplinks.install_type(InstallType.PROMOTE_INSTALL)
|
||||
deeplinks.app_id("app_id")
|
||||
deeplinks.install_type(InstallType.PROMOTE_INSTALL)
|
||||
deeplinks.install_url("install_url")
|
||||
|
||||
assertThat(deeplinks.app_id()).isEqualTo("app_id")
|
||||
|
||||
assertThat(JSONObject(deeplinks.links()).toString()).apply {
|
||||
doesNotContain(InstallType.NO_INSTALL.type)
|
||||
contains(InstallType.PROMOTE_INSTALL.type)
|
||||
contains("\"app_id\":\"app_id\"")
|
||||
assertThat(deeplinks).all {
|
||||
prop(CreateDeeplinks::app_id).isEqualTo("app_id")
|
||||
prop(CreateDeeplinks::install_type).isEqualTo(InstallType.PROMOTE_INSTALL)
|
||||
prop(CreateDeeplinks::install_url).isEqualTo("install_url")
|
||||
}
|
||||
|
||||
assertThat(JSONObject(deeplinks.links()).toString()).isEqualTo(
|
||||
"""
|
||||
{"install_url":"install_url","app_id":"app_id","app_uri_path":"app_uri_path","install_type":"promote_install"}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `update test`() {
|
||||
fun `Update deeplink`() {
|
||||
val deeplinks = UpdateDeeplinks().apply {
|
||||
app_guid("app_guid")
|
||||
os(Os.IOS)
|
||||
install_type(InstallType.NO_INSTALL)
|
||||
guid("guid")
|
||||
install_url("install_url")
|
||||
app_uri_path("app_uri_path")
|
||||
created("created")
|
||||
guid("guid")
|
||||
install_type(InstallType.NO_INSTALL)
|
||||
install_url("install_url")
|
||||
modified("modified")
|
||||
os(Os.IOS)
|
||||
}
|
||||
|
||||
assertThat(deeplinks.brand_guid()).isNull()
|
||||
assertThat(deeplinks).all {
|
||||
prop(UpdateDeeplinks::app_guid).isEqualTo("app_guid")
|
||||
prop(UpdateDeeplinks::app_uri_path).isEqualTo("app_uri_path")
|
||||
prop(UpdateDeeplinks::bitlink).isNull()
|
||||
prop(UpdateDeeplinks::brand_guid).isNull()
|
||||
prop(UpdateDeeplinks::created).isEqualTo("created")
|
||||
prop(UpdateDeeplinks::guid).isEqualTo("guid")
|
||||
prop(UpdateDeeplinks::install_type).isEqualTo(InstallType.NO_INSTALL)
|
||||
prop(UpdateDeeplinks::install_url).isEqualTo("install_url")
|
||||
prop(UpdateDeeplinks::links).isEqualTo(deeplinks.links())
|
||||
prop(UpdateDeeplinks::modified).isEqualTo("modified")
|
||||
prop(UpdateDeeplinks::os).isEqualTo(Os.IOS)
|
||||
}
|
||||
|
||||
val zdt = ZonedDateTime.of(1997, 8, 29, 2, 14, 0, 0, ZoneId.of("US/Eastern"))
|
||||
|
||||
deeplinks.bitlink("bitlink")
|
||||
deeplinks.brand_guid("brand_guid")
|
||||
deeplinks.created(zdt)
|
||||
deeplinks.install_type(InstallType.PROMOTE_INSTALL)
|
||||
deeplinks.modified(zdt)
|
||||
deeplinks.os(Os.ANDROID)
|
||||
|
||||
assertThat(deeplinks.app_uri_path()).isEqualTo("app_uri_path")
|
||||
assertThat(deeplinks.install_url()).isEqualTo("install_url")
|
||||
|
||||
assertThat(deeplinks.os()).isEqualTo(Os.IOS)
|
||||
assertThat(deeplinks.install_type()).isEqualTo(InstallType.NO_INSTALL)
|
||||
assertThat(deeplinks.app_guid()).isEqualTo("app_guid")
|
||||
assertThat(deeplinks.modified()).isEqualTo("modified")
|
||||
assertThat(deeplinks.brand_guid()).isEqualTo("brand_guid")
|
||||
|
||||
assertThat(deeplinks).all {
|
||||
prop(UpdateDeeplinks::bitlink).isEqualTo("bitlink")
|
||||
prop(UpdateDeeplinks::brand_guid).isEqualTo("brand_guid")
|
||||
prop(UpdateDeeplinks::created).isEqualTo("1997-08-29T02:14:00-0400")
|
||||
prop(UpdateDeeplinks::install_type).isEqualTo(InstallType.PROMOTE_INSTALL)
|
||||
prop(UpdateDeeplinks::modified).isEqualTo("1997-08-29T02:14:00-0400")
|
||||
prop(UpdateDeeplinks::os).isEqualTo(Os.ANDROID)
|
||||
}
|
||||
|
||||
assertThat(JSONObject(deeplinks.links()).toString()).isEqualTo(
|
||||
"""
|
||||
{"app_guid":"app_guid","install_url":"install_url","os":"ios","app_uri_path":"app_uri_path","created":"created","brand_guid":"brand_guid","guid":"guid","modified":"modified","install_type":"no_install"}
|
||||
{"app_guid":"app_guid","install_url":"install_url","bitlink":"bitlink","os":"android","app_uri_path":"app_uri_path","created":"1997-08-29T02:14:00-0400","brand_guid":"brand_guid","guid":"guid","modified":"1997-08-29T02:14:00-0400","install_type":"promote_install"}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
deeplinks.install_type(InstallType.PROMOTE_INSTALL)
|
||||
deeplinks.os(Os.ANDROID)
|
||||
deeplinks.bitlink("bitlink")
|
||||
|
||||
val zdt = ZonedDateTime.of(1997, 8, 29, 2, 14, 0, 0, ZoneId.of("US/Eastern"))
|
||||
deeplinks.modified(zdt)
|
||||
deeplinks.created(zdt)
|
||||
|
||||
assertThat(deeplinks.bitlink()).isEqualTo("bitlink")
|
||||
assertThat(deeplinks.created()).isEqualTo("1997-08-29T02:14:00-0400")
|
||||
assertThat(deeplinks.modified()).isEqualTo("1997-08-29T02:14:00-0400")
|
||||
|
||||
assertThat(JSONObject(deeplinks.links()).toString()).apply {
|
||||
doesNotContain(InstallType.NO_INSTALL.type)
|
||||
contains(InstallType.PROMOTE_INSTALL.type)
|
||||
|
||||
doesNotContain(Os.IOS.type)
|
||||
contains("\"os\":\"android\"")
|
||||
|
||||
contains("\"bitlink\":\"bitlink\"")
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue