diff --git a/gradle.properties b/gradle.properties index b89d1cc..da5ec13 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,3 +20,5 @@ org.gradle.jvmargs=-Xmx1024m # The Android Gradle Plugin uses deprecated APIs, they have until Gradle 6.0 to fix their crap. # https://android.googlesource.com/platform/tools/base/+/studio-master-dev/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/scope/BuildArtifactsHolder.kt org.gradle.warning.mode=none +android.enableJetifier=true +android.useAndroidX=true diff --git a/tanker-bindings/gradle.properties b/tanker-bindings/gradle.properties deleted file mode 100644 index 5465fec..0000000 --- a/tanker-bindings/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -android.enableJetifier=true -android.useAndroidX=true \ No newline at end of file diff --git a/tanker-bindings/gradle/wrapper/gradle-wrapper.jar b/tanker-bindings/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index f6b961f..0000000 Binary files a/tanker-bindings/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/tanker-bindings/gradle/wrapper/gradle-wrapper.properties b/tanker-bindings/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 3fcc99b..0000000 --- a/tanker-bindings/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Thu Jul 11 11:06:10 CEST 2019 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/tanker-bindings/gradlew b/tanker-bindings/gradlew deleted file mode 100644 index cccdd3d..0000000 --- a/tanker-bindings/gradlew +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env sh - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/tanker-bindings/gradlew.bat b/tanker-bindings/gradlew.bat deleted file mode 100644 index e95643d..0000000 --- a/tanker-bindings/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/tanker-bindings/proguard-rules.pro b/tanker-bindings/proguard-rules.pro deleted file mode 100644 index 3787093..0000000 --- a/tanker-bindings/proguard-rules.pro +++ /dev/null @@ -1,3 +0,0 @@ --keepclassmembers class * { - @io.tanker.api.ProguardKeep ; -} diff --git a/tanker-bindings/src/main/kotlin/io/tanker/api/AsynchronousByteChannelWrapper.kt b/tanker-bindings/src/main/kotlin/io/tanker/api/AsynchronousByteChannelWrapper.kt index f75166f..07e36d3 100644 --- a/tanker-bindings/src/main/kotlin/io/tanker/api/AsynchronousByteChannelWrapper.kt +++ b/tanker-bindings/src/main/kotlin/io/tanker/api/AsynchronousByteChannelWrapper.kt @@ -6,7 +6,7 @@ import java.nio.channels.AsynchronousByteChannel import java.nio.channels.CompletionHandler @RequiresApi(26) -class AsynchronousByteChannelWrapper(private val channel: AsynchronousByteChannel) : TankerAsynchronousByteChannel { +internal class AsynchronousByteChannelWrapper(private val channel: AsynchronousByteChannel) : TankerAsynchronousByteChannel { override fun close() { channel.close() } @@ -15,15 +15,16 @@ class AsynchronousByteChannelWrapper(private val channel: AsynchronousByteChanne return channel.isOpen } - override fun read(dst: ByteBuffer?, attachment: A, handler: TankerCompletionHandler?) { + override fun read(dst: ByteBuffer, attachment: A, handler: TankerCompletionHandler) { + // CompletionHandler is API 26 only, hence the boilerplate channel.read(dst, attachment, object : CompletionHandler { override fun completed(result: Int, attachment: A) { - handler!!.completed(result, attachment) + handler.completed(result, attachment) } override fun failed(exc: Throwable, attachment: A) { - handler!!.failed(exc, attachment) + handler.failed(exc, attachment) } }) } -} \ No newline at end of file +} diff --git a/tanker-bindings/src/main/kotlin/io/tanker/api/InputStreamWrapper.kt b/tanker-bindings/src/main/kotlin/io/tanker/api/InputStreamWrapper.kt index 67c5218..a8c9e56 100644 --- a/tanker-bindings/src/main/kotlin/io/tanker/api/InputStreamWrapper.kt +++ b/tanker-bindings/src/main/kotlin/io/tanker/api/InputStreamWrapper.kt @@ -1,34 +1,37 @@ package io.tanker.api +import java.io.IOException import java.io.InputStream import java.nio.ByteBuffer -import java.util.concurrent.Future -class InputStreamWrapper(private val inputStream: InputStream) : TankerAsynchronousByteChannel { - companion object { - private var isClosed = false - } - - override fun read(dst: ByteBuffer?, attachment: A, handler: TankerCompletionHandler?) { +class InputStreamWrapper(private var inputStream: InputStream?) : TankerAsynchronousByteChannel { + override fun read(dst: ByteBuffer, attachment: A, handler: TankerCompletionHandler) { TankerFuture.threadPool.execute { - try { - val b = ByteArray(dst!!.remaining()) - val nbRead = inputStream.read(b) - if (nbRead != -1) { - dst.put(b, 0, nbRead) + if (!isOpen) + handler.failed(IOException("Stream is closed"), attachment) + else { + try { + val b = ByteArray(dst.remaining()) + val nbRead = inputStream!!.read(b) + if (nbRead != -1) { + dst.put(b, 0, nbRead) + } + handler.completed(nbRead, attachment) + } catch (e: Throwable) { + handler.failed(e, attachment) } - handler!!.completed(nbRead, attachment) - } catch (e: Throwable) { - handler!!.failed(e, attachment) } } } + override fun isOpen(): Boolean { - return !isClosed + return inputStream != null } override fun close() { - inputStream.close() - isClosed = true + if (inputStream != null) { + inputStream!!.close() + inputStream = null + } } } diff --git a/tanker-bindings/src/main/kotlin/io/tanker/api/Tanker.kt b/tanker-bindings/src/main/kotlin/io/tanker/api/Tanker.kt index ede7050..df1f85b 100644 --- a/tanker-bindings/src/main/kotlin/io/tanker/api/Tanker.kt +++ b/tanker-bindings/src/main/kotlin/io/tanker/api/Tanker.kt @@ -7,8 +7,6 @@ import com.sun.jna.Pointer import com.sun.jna.StringArray import io.tanker.bindings.* import io.tanker.jni.KVMx86Bug -import java.io.InputStream -import java.nio.channels.AsynchronousByteChannel /** * Main entry point for the Tanker SDK. Can open a TankerSession. @@ -278,62 +276,26 @@ class Tanker(tankerOptions: TankerOptions) { }) } - @RequiresApi(26) - fun encrypt(channel: AsynchronousByteChannel): TankerFuture { - return encrypt(channel, null) - } - - @RequiresApi(26) - fun encrypt(channel: AsynchronousByteChannel, options: EncryptOptions?): TankerFuture { - return encrypt(AsynchronousByteChannelWrapper(channel), options).andThen(TankerCallback { - TankerStreamChannelWrapper(it) - }) - } - - @RequiresApi(26) - fun decrypt(channel: AsynchronousByteChannel): TankerFuture { - return decrypt(AsynchronousByteChannelWrapper(channel)).andThen(TankerCallback { - TankerStreamChannelWrapper(it) - }) - } - - fun encrypt(stream: InputStream): TankerFuture { - return encrypt(stream, null) - } - - fun encrypt(stream: InputStream, options: EncryptOptions?): TankerFuture { - return encrypt(InputStreamWrapper(stream), options).andThen(TankerCallback { - TankerInputStream(it) - }) - } - - fun encrypt(channel: TankerAsynchronousByteChannel): TankerFuture { - return encrypt(channel, null) - } - - fun encrypt(channel: TankerAsynchronousByteChannel, options: EncryptOptions?): TankerFuture { + fun encrypt(channel: TankerAsynchronousByteChannel, options: EncryptOptions?): TankerFuture { val cb = TankerStreamInputSourceCallback(channel) val futurePtr = lib.tanker_stream_encrypt(tanker, cb, null, options) return TankerFuture(futurePtr, Pointer::class.java).andThen(TankerCallback { - TankerStreamChannel(it, cb) + TankerResourceChannel(it, cb) }) } - fun decrypt(channel: TankerAsynchronousByteChannel): TankerFuture { + fun encrypt(channel: TankerAsynchronousByteChannel): TankerFuture { + return encrypt(channel, null) + } + + fun decrypt(channel: TankerAsynchronousByteChannel): TankerFuture { val cb = TankerStreamInputSourceCallback(channel) val futurePtr = lib.tanker_stream_decrypt(tanker, cb, null) return TankerFuture(futurePtr, Pointer::class.java).andThen(TankerCallback { - TankerStreamChannel(it, cb) + TankerResourceChannel(it, cb) }) } - fun decrypt(stream: InputStream): TankerFuture { - return decrypt(InputStreamWrapper(stream)).andThen(TankerCallback { - TankerInputStream(it) - }) - } - - /** * Decrypts {@code data} with options, assuming the data was encrypted and shared beforehand. * @return A future that resolves when the data has been decrypted. @@ -377,22 +339,8 @@ class Tanker(tankerOptions: TankerOptions) { * @param channel Tanker channel returned either by {@code encrypt} or {@code decrypt}. * @return The resource ID of the encrypted data (base64 encoded). */ - fun getResourceID(channel: TankerStreamChannel): String { - return channel.resourceID - } - - @RequiresApi(26) - fun getResourceID(channel: TankerStreamChannelWrapper): String { - return channel.streamChannel.resourceID - } - - /** - * Get the resource ID used for sharing encrypted data. - * @param stream Tanker input stream returned either by {@code encrypt} or {@code decrypt}. - * @return The resource ID of the encrypted data (base64 encoded). - */ - fun getResourceID(stream: TankerInputStream): String { - return stream.resourceID + fun getResourceID(channel: TankerAsynchronousByteChannel): String { + return (channel as TankerResourceChannel).resourceID } /** diff --git a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerAsynchronousByteChannel.kt b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerAsynchronousByteChannel.kt index 3df3586..3b6420d 100644 --- a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerAsynchronousByteChannel.kt +++ b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerAsynchronousByteChannel.kt @@ -1,13 +1,11 @@ package io.tanker.api -import java.io.InputStream import java.nio.ByteBuffer import java.nio.channels.Channel -import java.util.concurrent.Future // nio.channels.AsynchronousByteChannel requires API 26 // provide our own interface as a replacement interface TankerAsynchronousByteChannel : Channel { - public abstract fun read(dst: ByteBuffer?, attachment: A, handler: TankerCompletionHandler?) + fun read(dst: ByteBuffer, attachment: A, handler: TankerCompletionHandler) } \ No newline at end of file diff --git a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerStreamChannelWrapper.kt b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerAsynchronousByteChannelWrapper.kt similarity index 50% rename from tanker-bindings/src/main/kotlin/io/tanker/api/TankerStreamChannelWrapper.kt rename to tanker-bindings/src/main/kotlin/io/tanker/api/TankerAsynchronousByteChannelWrapper.kt index d80dc93..07b919d 100644 --- a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerStreamChannelWrapper.kt +++ b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerAsynchronousByteChannelWrapper.kt @@ -8,24 +8,27 @@ import java.nio.channels.ReadPendingException import java.util.concurrent.Future @RequiresApi(26) -class TankerStreamChannelWrapper(internal val streamChannel: TankerStreamChannel) : AsynchronousByteChannel { +internal class TankerAsynchronousByteChannelWrapper(internal val streamChannel: TankerAsynchronousByteChannel) : AsynchronousByteChannel { override fun read(dst: ByteBuffer?): Future { throw UnsupportedOperationException() } - override fun read(dst: ByteBuffer?, attachment: A, handler: CompletionHandler?) { - return streamChannel.read(dst, attachment, object : TankerCompletionHandler { - override fun completed(result: Int, attachment: A) { - handler!!.completed(result, attachment) - } - - override fun failed(exc: Throwable, attachment: A) { - if (exc is TankerReadPendingException) - handler!!.failed(ReadPendingException(), attachment) - else - handler!!.failed(exc, attachment) - } - }) + override fun read(dst: ByteBuffer, attachment: A, handler: CompletionHandler) { + try { + return streamChannel.read(dst, attachment, object : TankerCompletionHandler { + override fun completed(result: Int, attachment: A) { + handler.completed(result, attachment) + } + + override fun failed(exc: Throwable, attachment: A) { + handler.failed(exc, attachment) + } + }) + } catch (exc: Throwable) { + if (exc is TankerPendingReadException) + throw ReadPendingException() + throw exc + } } override fun close() { diff --git a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerChannels.kt b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerChannels.kt index 3fd5b9e..e90694e 100644 --- a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerChannels.kt +++ b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerChannels.kt @@ -1,13 +1,32 @@ package io.tanker.api +import androidx.annotation.RequiresApi import java.io.InputStream +import java.nio.channels.AsynchronousByteChannel class TankerChannels { companion object { @JvmStatic - public fun newInputStream(channel: TankerStreamChannel): InputStream { + fun toInputStream(channel: TankerAsynchronousByteChannel): InputStream { return TankerInputStream(channel) } + + @JvmStatic + fun fromInputStream(stream: InputStream): TankerAsynchronousByteChannel { + return InputStreamWrapper(stream) + } + + @RequiresApi(26) + @JvmStatic + fun toAsynchronousByteChannel(channel: TankerAsynchronousByteChannel): AsynchronousByteChannel { + return TankerAsynchronousByteChannelWrapper(channel) + } + + @RequiresApi(26) + @JvmStatic + fun fromAsynchronousByteChannel(channel: AsynchronousByteChannel): TankerAsynchronousByteChannel { + return AsynchronousByteChannelWrapper(channel) + } } } \ No newline at end of file diff --git a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerCompletionHandler.kt b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerCompletionHandler.kt index 0e292c0..cad597e 100644 --- a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerCompletionHandler.kt +++ b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerCompletionHandler.kt @@ -4,6 +4,6 @@ package io.tanker.api // provide our own interface as a replacement interface TankerCompletionHandler { - public abstract fun completed(result: V, attachment: A): Unit - public abstract fun failed(exc: Throwable, attachment: A): Unit + fun completed(result: V, attachment: A) + fun failed(exc: Throwable, attachment: A) } \ No newline at end of file diff --git a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerInputStream.kt b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerInputStream.kt index 12712c0..663324e 100644 --- a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerInputStream.kt +++ b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerInputStream.kt @@ -11,58 +11,56 @@ import java.util.concurrent.FutureTask import java.util.concurrent.ThreadPoolExecutor -class TankerInputStream internal constructor(private val channel: TankerStreamChannel) : InputStream() { - val resourceID = channel.resourceID +internal class TankerInputStream constructor(private val channel: TankerAsynchronousByteChannel) : InputStream() { - override fun read(): Int { - val buffer = ByteArray(1) - if (read(buffer, 0, 1) == -1) - return -1 - return buffer[0].toInt() - } - - override fun read(b: ByteArray): Int { - return read(b, 0, b.size) + override fun read(): Int { + val buffer = ByteArray(1) + if (read(buffer, 0, 1) == -1) + return -1 + return buffer[0].toInt() + } - } + override fun read(b: ByteArray): Int { + return read(b, 0, b.size) + } - override fun read(b: ByteArray, off: Int, len: Int): Int { - val fut = FutureTask {} - var nbRead = 0 - var err : Throwable? = null + override fun read(b: ByteArray, off: Int, len: Int): Int { + val fut = FutureTask {} + var nbRead = 0 + var err: Throwable? = null - val buffer = ByteBuffer.wrap(b, off, len) - channel.read(buffer, Unit, object : TankerCompletionHandler { - override fun completed(result: Int, attachment: Unit) { - nbRead = result - fut.run() - } + val buffer = ByteBuffer.wrap(b, off, len) + channel.read(buffer, Unit, object : TankerCompletionHandler { + override fun completed(result: Int, attachment: Unit) { + nbRead = result + fut.run() + } - override fun failed(exc: Throwable, attachment: Unit) { - err = exc - fut.run() - } - }) - fut.get() - if (err != null) { - if (err is ClosedChannelException) { - throw IOException("Stream is closed", err) - } - throw err!! - } - return nbRead + override fun failed(exc: Throwable, attachment: Unit) { + err = exc + fut.run() + } + }) + fut.get() + if (err != null) { + if (err is ClosedChannelException) { + throw IOException("Stream is closed", err) + } + throw err!! } + return nbRead + } - override fun markSupported(): Boolean { - return false - } + override fun markSupported(): Boolean { + return false + } - override fun available(): Int { - return 0 - } + override fun available(): Int { + return 0 + } - override fun close() { - channel.close() - } + override fun close() { + channel.close() + } } \ No newline at end of file diff --git a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerReadPendingException.kt b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerPendingReadException.kt similarity index 50% rename from tanker-bindings/src/main/kotlin/io/tanker/api/TankerReadPendingException.kt rename to tanker-bindings/src/main/kotlin/io/tanker/api/TankerPendingReadException.kt index bb34158..ec8c37e 100644 --- a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerReadPendingException.kt +++ b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerPendingReadException.kt @@ -2,5 +2,5 @@ package io.tanker.api import java.lang.IllegalStateException -open class TankerReadPendingException : IllegalStateException() { +open class TankerPendingReadException : IllegalStateException() { } \ No newline at end of file diff --git a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerStreamChannel.kt b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerResourceChannel.kt similarity index 64% rename from tanker-bindings/src/main/kotlin/io/tanker/api/TankerStreamChannel.kt rename to tanker-bindings/src/main/kotlin/io/tanker/api/TankerResourceChannel.kt index 1492062..224432a 100644 --- a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerStreamChannel.kt +++ b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerResourceChannel.kt @@ -3,19 +3,14 @@ package io.tanker.api import com.sun.jna.Memory import com.sun.jna.Pointer import io.tanker.bindings.StreamPointer -import io.tanker.bindings.TankerError import java.io.IOException import java.nio.ByteBuffer import java.nio.channels.ClosedChannelException -import java.nio.channels.ReadPendingException -import java.util.concurrent.Future -// FIXME wrap it in an API 26 class - -class TankerStreamChannel internal constructor(private var cStream: StreamPointer?, private val cb: TankerStreamInputSourceCallback) : TankerAsynchronousByteChannel { +internal class TankerResourceChannel constructor(private var cStream: StreamPointer?, private val cb: TankerStreamInputSourceCallback) : TankerAsynchronousByteChannel { val resourceID = initResourceID() - var pendingReadOperation = false + private var pendingReadOperation = false private fun initResourceID(): String { if (cStream == null) @@ -40,22 +35,22 @@ class TankerStreamChannel internal constructor(private var cStream: StreamPointe cStream = null } - override fun read(dst: ByteBuffer?, attachment: A, handler: TankerCompletionHandler?) { + override fun read(dst: ByteBuffer, attachment: A, handler: TankerCompletionHandler) { if (pendingReadOperation) - handler!!.failed(TankerReadPendingException(), attachment) - else - readTankerInput(dst!!, attachment, handler!!) + throw TankerPendingReadException() + readTankerInput(dst, attachment, handler) } private fun readTankerInput(buffer: ByteBuffer, attachment: A, handler: TankerCompletionHandler) { val offset = buffer.position() val size = buffer.remaining() - if (size == 0) - handler.completed(0, attachment) - else if (cStream == null) + if (cStream == null) handler.failed(ClosedChannelException(), attachment) else { - val inBuf = Memory(size.toLong()) + var inBuf: Pointer? = null + // handle special 0 case, which will trigger a buffering operation + if (size != 0) + inBuf = Memory(size.toLong()) pendingReadOperation = true TankerFuture(Tanker.lib.tanker_stream_read(cStream!!, inBuf, size.toLong()), Int::class.java).then(TankerVoidCallback { @@ -73,16 +68,20 @@ class TankerStreamChannel internal constructor(private var cStream: StreamPointe } } else { var nbRead = it.get() - if (buffer.hasArray()) { - inBuf.read(0, buffer.array(), offset, nbRead) + if (inBuf == null) { + handler.completed(nbRead, attachment) } else { - val b = inBuf.getByteBuffer(0, nbRead.toLong()) - buffer.put(b) - } - if (nbRead == 0) { - nbRead = -1 + if (buffer.hasArray()) { + inBuf.read(0, buffer.array(), offset, nbRead) + } else { + val b = inBuf.getByteBuffer(0, nbRead.toLong()) + buffer.put(b) + } + if (nbRead == 0) { + nbRead = -1 + } + handler.completed(nbRead, attachment) } - handler.completed(nbRead, attachment) } }) } diff --git a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerStreamInputSourceCallback.kt b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerStreamInputSourceCallback.kt index f37a095..d0efc5e 100644 --- a/tanker-bindings/src/main/kotlin/io/tanker/api/TankerStreamInputSourceCallback.kt +++ b/tanker-bindings/src/main/kotlin/io/tanker/api/TankerStreamInputSourceCallback.kt @@ -5,25 +5,25 @@ import io.tanker.bindings.StreamInputSourceReadOperationPointer import io.tanker.bindings.TankerLib import java.nio.ByteBuffer -class TankerStreamInputSourceCallback(val channel: TankerAsynchronousByteChannel) : TankerLib.StreamInputSourceCallback { - var streamError: Throwable? = null +internal class TankerStreamInputSourceCallback(val channel: TankerAsynchronousByteChannel) : TankerLib.StreamInputSourceCallback { + var streamError: Throwable? = null - override fun callback(buffer: Pointer, buffer_size: Long, op: StreamInputSourceReadOperationPointer, userArg: Pointer?) { - val b = ByteBuffer.allocate(buffer_size.toInt()) - channel.read(b, Unit, object : TankerCompletionHandler { - override fun completed(result: Int, attachment: Unit) { - var nbRead = result - if (result == -1) { - nbRead = 0 - } - buffer.write(0, b.array(), 0, nbRead) - Tanker.lib.tanker_stream_read_operation_finish(op, nbRead.toLong()) - } - - override fun failed(exc: Throwable, attachment: Unit) { - Tanker.lib.tanker_stream_read_operation_finish(op, -1) - streamError = exc - } - }) + override fun callback(buffer: Pointer, buffer_size: Long, op: StreamInputSourceReadOperationPointer, userArg: Pointer?) { + val b = ByteBuffer.allocate(buffer_size.toInt()) + channel.read(b, Unit, object : TankerCompletionHandler { + override fun completed(result: Int, attachment: Unit) { + var nbRead = result + if (result == -1) { + nbRead = 0 } - } \ No newline at end of file + buffer.write(0, b.array(), 0, nbRead) + Tanker.lib.tanker_stream_read_operation_finish(op, nbRead.toLong()) + } + + override fun failed(exc: Throwable, attachment: Unit) { + Tanker.lib.tanker_stream_read_operation_finish(op, -1) + streamError = exc + } + }) + } +} diff --git a/tanker-bindings/src/main/kotlin/io/tanker/bindings/TankerLib.kt b/tanker-bindings/src/main/kotlin/io/tanker/bindings/TankerLib.kt index 43d833a..e1551d4 100644 --- a/tanker-bindings/src/main/kotlin/io/tanker/bindings/TankerLib.kt +++ b/tanker-bindings/src/main/kotlin/io/tanker/bindings/TankerLib.kt @@ -94,7 +94,7 @@ interface TankerLib : Library { fun tanker_stream_encrypt(session: SessionPointer, cb: StreamInputSourceCallback, user_data: Pointer?, options: EncryptOptions?): FuturePointer fun tanker_stream_decrypt(session: SessionPointer, cb: StreamInputSourceCallback, user_data: Pointer?): FuturePointer - fun tanker_stream_read(stream: StreamPointer, buffer: Pointer, buffer_size: Long): FuturePointer + fun tanker_stream_read(stream: StreamPointer, buffer: Pointer?, buffer_size: Long): FuturePointer fun tanker_stream_read_operation_finish(op: StreamInputSourceReadOperationPointer, nb_read: Long) fun tanker_stream_get_resource_id(stream: StreamPointer): ExpectedPointer fun tanker_stream_close(stream: StreamPointer): FuturePointer diff --git a/tanker-bindings/src/test/kotlin/io/tanker/api/Tanker.kt b/tanker-bindings/src/test/kotlin/io/tanker/api/Tanker.kt index 2fdcde9..c2fa8cc 100644 --- a/tanker-bindings/src/test/kotlin/io/tanker/api/Tanker.kt +++ b/tanker-bindings/src/test/kotlin/io/tanker/api/Tanker.kt @@ -73,12 +73,12 @@ class TankerTests : TankerSpec() { tanker.registerIdentity(PassphraseVerification("pass")).get() val plaintext = ByteArray(3 * 1024 * 1024) - val clear = plaintext.inputStream() + val clear = InputStreamWrapper(plaintext.inputStream()) val encryptor = tanker.encrypt(clear).get() val decryptor = tanker.decrypt(encryptor).get() - val decrypted = decryptor.readBytes() + val decrypted = TankerInputStream(decryptor).readBytes() decrypted shouldBe plaintext tanker.stop().get() } @@ -111,7 +111,7 @@ class TankerTests : TankerSpec() { tanker.start(identity).get() tanker.registerIdentity(PassphraseVerification("pass")).get() - val clear = ByteArray(0).inputStream() + val clear = InputStreamWrapper(ByteArray(0).inputStream()) val encryptor = tanker.encrypt(clear).get() val decryptor = tanker.decrypt(encryptor).get() @@ -133,10 +133,12 @@ class TankerTests : TankerSpec() { tankerBob.registerIdentity(PassphraseVerification("pass")).get() val plaintext = "plain text" - val encryptor = tankerAlice.encrypt(plaintext.toByteArray().inputStream()).get() + val channel = InputStreamWrapper(plaintext.toByteArray().inputStream()) + val encryptor = tankerAlice.encrypt(channel).get() val shareOptions = ShareOptions().shareWithUsers(Identity.getPublicIdentity(bobId)) tankerAlice.share(arrayOf(tankerAlice.getResourceID(encryptor)), shareOptions).get() - String(tankerBob.decrypt(encryptor).get().readBytes()) shouldBe plaintext + val decryptionStream = TankerInputStream(tankerBob.decrypt(encryptor).get()) + String(decryptionStream.readBytes()) shouldBe plaintext tankerAlice.stop().get() tankerBob.stop().get() @@ -156,8 +158,10 @@ class TankerTests : TankerSpec() { val plaintext = "There are no mistakes, just happy accidents" val encryptOptions = EncryptOptions().shareWithUsers(Identity.getPublicIdentity(bobId)) - val encryptor = tankerAlice.encrypt(plaintext.toByteArray().inputStream(), encryptOptions).get() - String(tankerBob.decrypt(encryptor).get().readBytes()) shouldBe plaintext + val channel = InputStreamWrapper(plaintext.toByteArray().inputStream()) + val encryptor = tankerAlice.encrypt(channel, encryptOptions).get() + val decryptionStream = TankerInputStream(tankerBob.decrypt(encryptor).get()) + String(decryptionStream.readBytes()) shouldBe plaintext tankerAlice.stop().get() tankerBob.stop().get() diff --git a/tanker-bindings/src/test/kotlin/io/tanker/api/TankerInputStream.kt b/tanker-bindings/src/test/kotlin/io/tanker/api/TankerInputStream.kt index 0952582..03c7b36 100644 --- a/tanker-bindings/src/test/kotlin/io/tanker/api/TankerInputStream.kt +++ b/tanker-bindings/src/test/kotlin/io/tanker/api/TankerInputStream.kt @@ -4,87 +4,98 @@ import io.kotlintest.Description import io.kotlintest.shouldBe import io.kotlintest.shouldThrow import java.io.IOException -import java.io.InputStream +import java.nio.ByteBuffer class InputStreamTests : TankerSpec() { lateinit var tanker: Tanker - lateinit var buffer: ByteArray + lateinit var array: ByteArray + lateinit var buffer: ByteBuffer override fun beforeTest(description: Description) { tanker = Tanker(options.setWritablePath(createTmpDir().toString())) val st = tanker.start(tc.createIdentity()).get() st shouldBe Status.IDENTITY_REGISTRATION_NEEDED tanker.registerIdentity(PassphraseVerification("")).get() - buffer = ByteArray(10) + array = ByteArray(10) + buffer = ByteBuffer.allocate(10) } init { "Attempting to decrypt a non encrypted stream throws" { val clear = "clear" - shouldThrow { tanker.decrypt(clear.byteInputStream()).get() } + val clearChannel = TankerChannels.fromInputStream(clear.byteInputStream()) + shouldThrow { tanker.decrypt(clearChannel).get() } } "Attempting to encrypt a closed stream throws" { val file = createTempFile() - val stream = file.inputStream() - val encryptor = tanker.encrypt(stream).get() - stream.close() - shouldThrow { encryptor.read() } + val channel = TankerChannels.fromInputStream(file.inputStream()) + val encryptionStream = TankerChannels.toInputStream(tanker.encrypt(channel).get()) + channel.close() + shouldThrow { encryptionStream.read() } } - "Attempting to decrypt a closed stream throws" { - val encryptor = tanker.encrypt(buffer.inputStream()).get() - encryptor.close() - shouldThrow { tanker.decrypt(encryptor).get() } + "Attempting to decrypt a closed throws" { + val channel = InputStreamWrapper(array.inputStream()) + val encryptionStream = TankerChannels.toInputStream(tanker.encrypt(channel).get()) + encryptionStream.close() + shouldThrow { tanker.decrypt(TankerChannels.fromInputStream(encryptionStream)).get() } } - "Reading 0 bytes from a closed stream does nothing" { - val encryptor = tanker.encrypt(buffer.inputStream()).get() - encryptor.close() - encryptor.read(buffer, 0 , 0) shouldBe 0 + "Reading 0 bytes from a closed stream throws" { + val channel = TankerChannels.fromInputStream(array.inputStream()) + val encryptionStream = TankerChannels.toInputStream(tanker.encrypt(channel).get()) + encryptionStream.close() + shouldThrow { encryptionStream.read(array, 0, 0) shouldBe 0 } } "Reading a byte" { - val decryptor = tanker.decrypt(tanker.encrypt(buffer.inputStream()).get()).get() - decryptor.read() shouldBe 0 + val channel = TankerChannels.fromInputStream(array.inputStream()) + val decryptionStream = TankerChannels.toInputStream(tanker.decrypt(tanker.encrypt(channel).get()).get()) + decryptionStream.read() shouldBe 0 } "Reading into a whole ByteArray" { - val decryptor = tanker.decrypt(tanker.encrypt(buffer.inputStream()).get()).get() + val channel = TankerChannels.fromInputStream(array.inputStream()) + val decryptionStream = TankerChannels.toInputStream(tanker.decrypt(tanker.encrypt(channel).get()).get()) val b = ByteArray(10) { 1 } - decryptor.read(b) shouldBe 10 - b shouldBe buffer - decryptor.read() shouldBe -1 + decryptionStream.read(b) shouldBe 10 + b shouldBe array + decryptionStream.read() shouldBe -1 } "Reading 0 bytes should do nothing" { - val encryptor = tanker.encrypt(buffer.inputStream()).get() + val channel = TankerChannels.fromInputStream(array.inputStream()) + val encryptionStream = TankerChannels.toInputStream(tanker.encrypt(channel).get()) val b = ByteArray(10) { 1 } - encryptor.read(b, 0, 0) shouldBe 0 + encryptionStream.read(b, 0, 0) shouldBe 0 b.all { it == 1.toByte() } shouldBe true val empty = ByteArray(0) - encryptor.read(empty) shouldBe 0 + encryptionStream.read(empty) shouldBe 0 empty.size shouldBe 0 } "Giving negative values to read throws" { - val encryptor = tanker.encrypt(buffer.inputStream()).get() - shouldThrow { encryptor.read(buffer, -1, 1) } - shouldThrow { encryptor.read(buffer, 0, -1)} + val channel = TankerChannels.fromInputStream(array.inputStream()) + val encryptionStream = TankerChannels.toInputStream(tanker.encrypt(channel).get()) + shouldThrow { encryptionStream.read(array, -1, 1) } + shouldThrow { encryptionStream.read(array, 0, -1) } } "Giving a length larger than buffer size - offset throws" { - val encryptor = tanker.encrypt(buffer.inputStream()).get() - shouldThrow { encryptor.read(buffer, 9, 10) } + val channel = TankerChannels.fromInputStream(array.inputStream()) + val encryptionStream = TankerChannels.toInputStream(tanker.encrypt(channel).get()) + shouldThrow { encryptionStream.read(array, 9, 10) } } "Reading into a ByteArray twice" { - val decryptor = tanker.decrypt(tanker.encrypt(buffer.inputStream()).get()).get() + val channel = TankerChannels.fromInputStream(array.inputStream()) + val decryptionStream = TankerChannels.toInputStream(tanker.decrypt(tanker.encrypt(channel).get()).get()) val b = ByteArray(10) { 1 } - decryptor.read(b, off = 0, len = 5) shouldBe 5 - decryptor.read(b, off = 5, len = 5) shouldBe 5 - b shouldBe buffer + decryptionStream.read(b, 0, 5) shouldBe 5 + decryptionStream.read(b, 5, 5) shouldBe 5 + b shouldBe array } } } diff --git a/tanker-bindings/src/test/kotlin/io/tanker/api/TankerStreamChannel.kt b/tanker-bindings/src/test/kotlin/io/tanker/api/TankerResourceChannel.kt similarity index 67% rename from tanker-bindings/src/test/kotlin/io/tanker/api/TankerStreamChannel.kt rename to tanker-bindings/src/test/kotlin/io/tanker/api/TankerResourceChannel.kt index 4d6261c..7d4ec9a 100644 --- a/tanker-bindings/src/test/kotlin/io/tanker/api/TankerStreamChannel.kt +++ b/tanker-bindings/src/test/kotlin/io/tanker/api/TankerResourceChannel.kt @@ -4,7 +4,7 @@ import androidx.annotation.RequiresApi import io.kotlintest.Description import io.kotlintest.shouldBe import io.kotlintest.shouldNotBe -import org.eclipse.jgit.merge.ThreeWayMergeStrategy +import io.kotlintest.shouldThrow import java.nio.ByteBuffer import java.nio.channels.AsynchronousByteChannel import java.nio.channels.ClosedChannelException @@ -17,67 +17,22 @@ class DummyChannel : TankerAsynchronousByteChannel { val clearBuffer = ByteBuffer.allocate(1024 * 1024 * 2)!! private var isClosed = false - override fun read(dst: ByteBuffer?, attachment: A, handler: TankerCompletionHandler?) { + override fun read(dst: ByteBuffer, attachment: A, handler: TankerCompletionHandler) { try { - if (dst!!.remaining() == 0) { - handler!!.completed(0, attachment) + if (dst.remaining() == 0) { + handler.completed(0, attachment) } else if (clearBuffer.remaining() == 0) { - handler!!.completed(-1, attachment) + handler.completed(-1, attachment) } else { val clearArray = clearBuffer.array() val currentPos = clearBuffer.arrayOffset() val finalLength = minOf(dst.remaining(), clearBuffer.remaining()) dst.put(clearArray, currentPos, finalLength) clearBuffer.position(clearBuffer.position() + finalLength) - handler!!.completed(finalLength, attachment) + handler.completed(finalLength, attachment) } } catch (e: Throwable) { - handler!!.failed(e, attachment) - } - } - - override fun isOpen(): Boolean { - return !isClosed - } - - override fun close() { - isClosed = true - } -} - -@RequiresApi(26) -class API26DummyChannel : AsynchronousByteChannel { - override fun write(src: ByteBuffer?): Future { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun write(src: ByteBuffer?, attachment: A, handler: CompletionHandler?) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun read(dst: ByteBuffer?): Future { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - val clearBuffer = ByteBuffer.allocate(1024 * 1024 * 2)!! - private var isClosed = false - - override fun read(dst: ByteBuffer?, attachment: A, handler: CompletionHandler?) { - try { - if (dst!!.remaining() == 0) { - handler!!.completed(0, attachment) - } else if (clearBuffer.remaining() == 0) { - handler!!.completed(-1, attachment) - } else { - val clearArray = clearBuffer.array() - val currentPos = clearBuffer.arrayOffset() - val finalLength = minOf(dst.remaining(), clearBuffer.remaining()) - dst.put(clearArray, currentPos, finalLength) - clearBuffer.position(clearBuffer.position() + finalLength) - handler!!.completed(finalLength, attachment) - } - } catch (e: Throwable) { - handler!!.failed(e, attachment) + handler.failed(e, attachment) } } @@ -92,7 +47,8 @@ class API26DummyChannel : AsynchronousByteChannel { @RequiresApi(26) class API26StreamChannelTestHelper(tanker: Tanker) { - val clearChannel = API26DummyChannel() + val dummyChannel = DummyChannel() + val clearChannel = TankerChannels.toAsynchronousByteChannel(dummyChannel) var err: Throwable? = null var nbRead = 0 var decryptor: AsynchronousByteChannel @@ -118,7 +74,8 @@ class API26StreamChannelTestHelper(tanker: Tanker) { } init { - decryptor = tanker.decrypt(tanker.encrypt(clearChannel).get()).get() + val encryptionChannel = tanker.encrypt(TankerChannels.fromAsynchronousByteChannel(clearChannel)).get() + decryptor = TankerChannels.toAsynchronousByteChannel(tanker.decrypt(encryptionChannel).get()) } } @@ -126,7 +83,7 @@ class StreamChannelTestHelper(tanker: Tanker) { val clearChannel = DummyChannel() var err: Throwable? = null var nbRead = 0 - var decryptor: TankerStreamChannel + var decryptor: TankerAsynchronousByteChannel val decryptedBuffer = ByteBuffer.allocate(1024 * 1024 * 2) val fut = FutureTask {} @@ -187,15 +144,12 @@ class StreamChannelTests : TankerSpec() { "Attempting two read operations simultaneously throws" { val secondBuffer = ByteBuffer.allocate(helper.decryptedBuffer.capacity()) helper.decryptor.read(helper.decryptedBuffer, Unit, helper.callback()) - helper.decryptor.read(secondBuffer, Unit, helper.callback()) - helper.fut.get() - helper.err shouldNotBe null - (helper.err is TankerReadPendingException) shouldBe true + shouldThrow { helper.decryptor.read(secondBuffer, Unit, helper.callback()) } } } } -@RequiresApi (26) +@RequiresApi(26) class API26StreamChannelTests : TankerSpec() { lateinit var tanker: Tanker lateinit var helper: API26StreamChannelTestHelper @@ -214,8 +168,8 @@ class API26StreamChannelTests : TankerSpec() { helper.fut.get() helper.err shouldBe null helper.nbRead shouldBe helper.decryptedBuffer.capacity() - helper.clearChannel.clearBuffer.position(0) - helper.decryptedBuffer shouldBe helper.clearChannel.clearBuffer + helper.dummyChannel.clearBuffer.position(0) + helper.decryptedBuffer shouldBe helper.dummyChannel.clearBuffer } "Reading a closed channel throws" { @@ -229,10 +183,7 @@ class API26StreamChannelTests : TankerSpec() { "Attempting two read operations simultaneously throws" { val secondBuffer = ByteBuffer.allocate(helper.decryptedBuffer.capacity()) helper.decryptor.read(helper.decryptedBuffer, Unit, helper.callback()) - helper.decryptor.read(secondBuffer, Unit, helper.callback()) - helper.fut.get() - helper.err shouldNotBe null - (helper.err is ReadPendingException) shouldBe true + shouldThrow { helper.decryptor.read(secondBuffer, Unit, helper.callback()) } } } }