2014-01-31 11:14:13 +01:00
|
|
|
/**
|
2018-01-04 17:26:29 +00:00
|
|
|
* Copyright (C) 2009-2018 Lightbend Inc. <https://www.lightbend.com>
|
2014-01-31 11:14:13 +01:00
|
|
|
*/
|
|
|
|
|
|
2011-06-19 16:32:21 -06:00
|
|
|
package akka.util
|
|
|
|
|
|
2015-04-21 14:33:48 +08:00
|
|
|
import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream }
|
|
|
|
|
import java.lang.Double.doubleToRawLongBits
|
|
|
|
|
import java.lang.Float.floatToRawIntBits
|
|
|
|
|
import java.nio.{ ByteBuffer, ByteOrder }
|
|
|
|
|
import java.nio.ByteOrder.{ BIG_ENDIAN, LITTLE_ENDIAN }
|
2015-04-07 07:37:26 -05:00
|
|
|
|
2016-07-20 14:01:51 +02:00
|
|
|
import akka.util.ByteString.{ ByteString1, ByteString1C, ByteStrings }
|
2015-04-21 14:33:48 +08:00
|
|
|
import org.apache.commons.codec.binary.Hex.encodeHex
|
2014-01-31 11:14:13 +01:00
|
|
|
import org.scalacheck.Arbitrary.arbitrary
|
2015-04-21 14:33:48 +08:00
|
|
|
import org.scalacheck.{ Arbitrary, Gen }
|
|
|
|
|
import org.scalatest.{ Matchers, WordSpec }
|
|
|
|
|
import org.scalatest.prop.Checkers
|
2015-04-07 07:37:26 -05:00
|
|
|
|
2012-06-12 14:13:17 +09:00
|
|
|
import scala.collection.mutable.Builder
|
|
|
|
|
|
2013-12-17 14:25:56 +01:00
|
|
|
class ByteStringSpec extends WordSpec with Matchers with Checkers {
|
2011-06-19 16:32:21 -06:00
|
|
|
|
2016-08-29 09:38:09 +01:00
|
|
|
implicit val betterGeneratorDrivenConfig = PropertyCheckConfig().copy(minSuccessful = 1000)
|
2016-07-20 14:01:51 +02:00
|
|
|
|
2011-06-19 16:32:21 -06:00
|
|
|
def genSimpleByteString(min: Int, max: Int) = for {
|
2014-01-31 11:14:13 +01:00
|
|
|
n ← Gen.choose(min, max)
|
2011-06-19 16:32:21 -06:00
|
|
|
b ← Gen.containerOfN[Array, Byte](n, arbitrary[Byte])
|
2014-01-31 11:14:13 +01:00
|
|
|
from ← Gen.choose(0, b.length)
|
2017-02-24 10:26:42 +01:00
|
|
|
until ← Gen.choose(from, from max b.length)
|
2012-05-01 18:41:04 +02:00
|
|
|
} yield ByteString(b).slice(from, until)
|
2011-06-19 16:32:21 -06:00
|
|
|
|
|
|
|
|
implicit val arbitraryByteString: Arbitrary[ByteString] = Arbitrary {
|
|
|
|
|
Gen.sized { s ⇒
|
|
|
|
|
for {
|
2014-01-31 11:14:13 +01:00
|
|
|
chunks ← Gen.choose(0, s)
|
2017-02-24 10:26:42 +01:00
|
|
|
bytes ← Gen.listOfN(chunks, genSimpleByteString(1, 1 max (s / (chunks max 1))))
|
2011-06-19 16:32:21 -06:00
|
|
|
} yield (ByteString.empty /: bytes)(_ ++ _)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-01 18:41:04 +02:00
|
|
|
type ByteStringSlice = (ByteString, Int, Int)
|
|
|
|
|
|
|
|
|
|
implicit val arbitraryByteStringSlice: Arbitrary[ByteStringSlice] = Arbitrary {
|
|
|
|
|
for {
|
|
|
|
|
xs ← arbitraryByteString.arbitrary
|
2017-02-24 10:26:42 +01:00
|
|
|
from ← Gen.choose(0, 0 max (xs.length - 1))
|
|
|
|
|
until ← {
|
|
|
|
|
require(from <= xs.length)
|
|
|
|
|
Gen.choose(from, xs.length)
|
|
|
|
|
}
|
2012-05-01 18:41:04 +02:00
|
|
|
} yield (xs, from, until)
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-27 16:26:22 +02:00
|
|
|
type ArraySlice[A] = (Array[A], Int, Int)
|
|
|
|
|
|
|
|
|
|
def arbSlice[A](arbArray: Arbitrary[Array[A]]): Arbitrary[ArraySlice[A]] = Arbitrary {
|
|
|
|
|
for {
|
|
|
|
|
xs ← arbArray.arbitrary
|
2014-01-31 11:14:13 +01:00
|
|
|
from ← Gen.choose(0, xs.length)
|
|
|
|
|
until ← Gen.choose(from, xs.length)
|
2012-05-27 16:26:22 +02:00
|
|
|
} yield (xs, from, until)
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-03 16:20:59 +02:00
|
|
|
def serialize(obj: AnyRef): Array[Byte] = {
|
2015-04-07 07:37:26 -05:00
|
|
|
val os = new ByteArrayOutputStream
|
|
|
|
|
val bos = new ObjectOutputStream(os)
|
|
|
|
|
bos.writeObject(obj)
|
2016-08-03 16:20:59 +02:00
|
|
|
os.toByteArray
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def deserialize(bytes: Array[Byte]): AnyRef = {
|
|
|
|
|
val is = new ObjectInputStream(new ByteArrayInputStream(bytes))
|
2015-04-07 07:37:26 -05:00
|
|
|
|
2016-08-03 16:20:59 +02:00
|
|
|
is.readObject
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def testSer(obj: AnyRef) = {
|
|
|
|
|
deserialize(serialize(obj)) == obj
|
2015-04-07 07:37:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def hexFromSer(obj: AnyRef) = {
|
|
|
|
|
val os = new ByteArrayOutputStream
|
|
|
|
|
val bos = new ObjectOutputStream(os)
|
|
|
|
|
bos.writeObject(obj)
|
|
|
|
|
String valueOf encodeHex(os.toByteArray)
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-27 16:26:22 +02:00
|
|
|
val arbitraryByteArray: Arbitrary[Array[Byte]] = Arbitrary { Gen.sized { n ⇒ Gen.containerOfN[Array, Byte](n, arbitrary[Byte]) } }
|
|
|
|
|
implicit val arbitraryByteArraySlice: Arbitrary[ArraySlice[Byte]] = arbSlice(arbitraryByteArray)
|
|
|
|
|
val arbitraryShortArray: Arbitrary[Array[Short]] = Arbitrary { Gen.sized { n ⇒ Gen.containerOfN[Array, Short](n, arbitrary[Short]) } }
|
|
|
|
|
implicit val arbitraryShortArraySlice: Arbitrary[ArraySlice[Short]] = arbSlice(arbitraryShortArray)
|
|
|
|
|
val arbitraryIntArray: Arbitrary[Array[Int]] = Arbitrary { Gen.sized { n ⇒ Gen.containerOfN[Array, Int](n, arbitrary[Int]) } }
|
|
|
|
|
implicit val arbitraryIntArraySlice: Arbitrary[ArraySlice[Int]] = arbSlice(arbitraryIntArray)
|
|
|
|
|
val arbitraryLongArray: Arbitrary[Array[Long]] = Arbitrary { Gen.sized { n ⇒ Gen.containerOfN[Array, Long](n, arbitrary[Long]) } }
|
|
|
|
|
implicit val arbitraryLongArraySlice: Arbitrary[ArraySlice[Long]] = arbSlice(arbitraryLongArray)
|
|
|
|
|
val arbitraryFloatArray: Arbitrary[Array[Float]] = Arbitrary { Gen.sized { n ⇒ Gen.containerOfN[Array, Float](n, arbitrary[Float]) } }
|
|
|
|
|
implicit val arbitraryFloatArraySlice: Arbitrary[ArraySlice[Float]] = arbSlice(arbitraryFloatArray)
|
|
|
|
|
val arbitraryDoubleArray: Arbitrary[Array[Double]] = Arbitrary { Gen.sized { n ⇒ Gen.containerOfN[Array, Double](n, arbitrary[Double]) } }
|
|
|
|
|
implicit val arbitraryDoubleArraySlice: Arbitrary[ArraySlice[Double]] = arbSlice(arbitraryDoubleArray)
|
|
|
|
|
|
2013-07-23 11:59:36 +02:00
|
|
|
type ArrayNumBytes[A] = (Array[A], Int)
|
|
|
|
|
|
|
|
|
|
implicit val arbitraryLongArrayNumBytes: Arbitrary[ArrayNumBytes[Long]] = Arbitrary {
|
|
|
|
|
for {
|
|
|
|
|
xs ← arbitraryLongArray.arbitrary
|
2014-01-31 11:14:13 +01:00
|
|
|
from ← Gen.choose(0, xs.length)
|
|
|
|
|
until ← Gen.choose(from, xs.length)
|
|
|
|
|
bytes ← Gen.choose(0, 8)
|
2013-07-23 11:59:36 +02:00
|
|
|
} yield (xs.slice(from, until), bytes)
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-28 13:34:47 +08:00
|
|
|
implicit val arbitraryByteStringBuilder: Arbitrary[ByteStringBuilder] = Arbitrary(ByteString.newBuilder)
|
|
|
|
|
|
2012-06-12 15:03:07 +09:00
|
|
|
def likeVector(bs: ByteString)(body: IndexedSeq[Byte] ⇒ Any): Boolean = {
|
|
|
|
|
val vec = Vector(bs: _*)
|
|
|
|
|
body(bs) == body(vec)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def likeVectors(bsA: ByteString, bsB: ByteString)(body: (IndexedSeq[Byte], IndexedSeq[Byte]) ⇒ Any): Boolean = {
|
|
|
|
|
val vecA = Vector(bsA: _*)
|
|
|
|
|
val vecB = Vector(bsB: _*)
|
|
|
|
|
body(bsA, bsB) == body(vecA, vecB)
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-01 18:41:04 +02:00
|
|
|
def likeVecIt(bs: ByteString)(body: BufferedIterator[Byte] ⇒ Any, strict: Boolean = true): Boolean = {
|
|
|
|
|
val bsIterator = bs.iterator
|
|
|
|
|
val vecIterator = Vector(bs: _*).iterator.buffered
|
|
|
|
|
(body(bsIterator) == body(vecIterator)) &&
|
|
|
|
|
(!strict || (bsIterator.toSeq == vecIterator.toSeq))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def likeVecIts(a: ByteString, b: ByteString)(body: (BufferedIterator[Byte], BufferedIterator[Byte]) ⇒ Any, strict: Boolean = true): Boolean = {
|
|
|
|
|
val (bsAIt, bsBIt) = (a.iterator, b.iterator)
|
|
|
|
|
val (vecAIt, vecBIt) = (Vector(a: _*).iterator.buffered, Vector(b: _*).iterator.buffered)
|
|
|
|
|
(body(bsAIt, bsBIt) == body(vecAIt, vecBIt)) &&
|
2016-06-02 14:06:57 +02:00
|
|
|
(!strict || (bsAIt.toSeq → bsBIt.toSeq) == (vecAIt.toSeq → vecBIt.toSeq))
|
2012-05-01 18:41:04 +02:00
|
|
|
}
|
|
|
|
|
|
2012-06-12 14:13:17 +09:00
|
|
|
def likeVecBld(body: Builder[Byte, _] ⇒ Unit): Boolean = {
|
|
|
|
|
val bsBuilder = ByteString.newBuilder
|
|
|
|
|
val vecBuilder = Vector.newBuilder[Byte]
|
|
|
|
|
|
|
|
|
|
body(bsBuilder)
|
|
|
|
|
body(vecBuilder)
|
|
|
|
|
|
|
|
|
|
bsBuilder.result == vecBuilder.result
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-27 16:26:22 +02:00
|
|
|
def testShortDecoding(slice: ByteStringSlice, byteOrder: ByteOrder): Boolean = {
|
|
|
|
|
val elemSize = 2
|
|
|
|
|
val (bytes, from, until) = slice
|
|
|
|
|
val (n, a, b) = (bytes.length / elemSize, from / elemSize, until / elemSize)
|
2017-03-13 17:49:45 +01:00
|
|
|
val reference = new Array[Short](n)
|
2012-05-27 16:26:22 +02:00
|
|
|
bytes.asByteBuffer.order(byteOrder).asShortBuffer.get(reference, 0, n)
|
|
|
|
|
val input = bytes.iterator
|
2017-03-13 17:49:45 +01:00
|
|
|
val decoded = new Array[Short](n)
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until a) decoded(i) = input.getShort(byteOrder)
|
2012-05-27 16:26:22 +02:00
|
|
|
input.getShorts(decoded, a, b - a)(byteOrder)
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← b until n) decoded(i) = input.getShort(byteOrder)
|
2012-05-27 16:26:22 +02:00
|
|
|
(decoded.toSeq == reference.toSeq) && (input.toSeq == bytes.drop(n * elemSize))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def testIntDecoding(slice: ByteStringSlice, byteOrder: ByteOrder): Boolean = {
|
|
|
|
|
val elemSize = 4
|
|
|
|
|
val (bytes, from, until) = slice
|
|
|
|
|
val (n, a, b) = (bytes.length / elemSize, from / elemSize, until / elemSize)
|
2017-03-13 17:49:45 +01:00
|
|
|
val reference = new Array[Int](n)
|
2012-05-27 16:26:22 +02:00
|
|
|
bytes.asByteBuffer.order(byteOrder).asIntBuffer.get(reference, 0, n)
|
|
|
|
|
val input = bytes.iterator
|
2017-03-13 17:49:45 +01:00
|
|
|
val decoded = new Array[Int](n)
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until a) decoded(i) = input.getInt(byteOrder)
|
2012-05-27 16:26:22 +02:00
|
|
|
input.getInts(decoded, a, b - a)(byteOrder)
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← b until n) decoded(i) = input.getInt(byteOrder)
|
2012-05-27 16:26:22 +02:00
|
|
|
(decoded.toSeq == reference.toSeq) && (input.toSeq == bytes.drop(n * elemSize))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def testLongDecoding(slice: ByteStringSlice, byteOrder: ByteOrder): Boolean = {
|
|
|
|
|
val elemSize = 8
|
|
|
|
|
val (bytes, from, until) = slice
|
|
|
|
|
val (n, a, b) = (bytes.length / elemSize, from / elemSize, until / elemSize)
|
2017-03-13 17:49:45 +01:00
|
|
|
val reference = new Array[Long](n)
|
2012-05-27 16:26:22 +02:00
|
|
|
bytes.asByteBuffer.order(byteOrder).asLongBuffer.get(reference, 0, n)
|
|
|
|
|
val input = bytes.iterator
|
2017-03-13 17:49:45 +01:00
|
|
|
val decoded = new Array[Long](n)
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until a) decoded(i) = input.getLong(byteOrder)
|
2012-05-27 16:26:22 +02:00
|
|
|
input.getLongs(decoded, a, b - a)(byteOrder)
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← b until n) decoded(i) = input.getLong(byteOrder)
|
2012-05-27 16:26:22 +02:00
|
|
|
(decoded.toSeq == reference.toSeq) && (input.toSeq == bytes.drop(n * elemSize))
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-08 17:57:41 +09:00
|
|
|
def testFloatDecoding(slice: ByteStringSlice, byteOrder: ByteOrder): Boolean = {
|
|
|
|
|
val elemSize = 4
|
|
|
|
|
val (bytes, from, until) = slice
|
|
|
|
|
val (n, a, b) = (bytes.length / elemSize, from / elemSize, until / elemSize)
|
2017-03-13 17:49:45 +01:00
|
|
|
val reference = new Array[Float](n)
|
2012-06-08 17:57:41 +09:00
|
|
|
bytes.asByteBuffer.order(byteOrder).asFloatBuffer.get(reference, 0, n)
|
|
|
|
|
val input = bytes.iterator
|
2017-03-13 17:49:45 +01:00
|
|
|
val decoded = new Array[Float](n)
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until a) decoded(i) = input.getFloat(byteOrder)
|
2012-06-08 17:57:41 +09:00
|
|
|
input.getFloats(decoded, a, b - a)(byteOrder)
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← b until n) decoded(i) = input.getFloat(byteOrder)
|
2012-06-08 17:57:41 +09:00
|
|
|
((decoded.toSeq map floatToRawIntBits) == (reference.toSeq map floatToRawIntBits)) &&
|
|
|
|
|
(input.toSeq == bytes.drop(n * elemSize))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def testDoubleDecoding(slice: ByteStringSlice, byteOrder: ByteOrder): Boolean = {
|
|
|
|
|
val elemSize = 8
|
|
|
|
|
val (bytes, from, until) = slice
|
|
|
|
|
val (n, a, b) = (bytes.length / elemSize, from / elemSize, until / elemSize)
|
2017-03-13 17:49:45 +01:00
|
|
|
val reference = new Array[Double](n)
|
2012-06-08 17:57:41 +09:00
|
|
|
bytes.asByteBuffer.order(byteOrder).asDoubleBuffer.get(reference, 0, n)
|
|
|
|
|
val input = bytes.iterator
|
2017-03-13 17:49:45 +01:00
|
|
|
val decoded = new Array[Double](n)
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until a) decoded(i) = input.getDouble(byteOrder)
|
2012-06-08 17:57:41 +09:00
|
|
|
input.getDoubles(decoded, a, b - a)(byteOrder)
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← b until n) decoded(i) = input.getDouble(byteOrder)
|
2012-06-08 17:57:41 +09:00
|
|
|
((decoded.toSeq map doubleToRawLongBits) == (reference.toSeq map doubleToRawLongBits)) &&
|
|
|
|
|
(input.toSeq == bytes.drop(n * elemSize))
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-27 16:26:22 +02:00
|
|
|
def testShortEncoding(slice: ArraySlice[Short], byteOrder: ByteOrder): Boolean = {
|
|
|
|
|
val elemSize = 2
|
2013-07-23 11:59:36 +02:00
|
|
|
val (data, from, to) = slice
|
2017-03-13 17:49:45 +01:00
|
|
|
val reference = new Array[Byte](data.length * elemSize)
|
2012-05-27 16:26:22 +02:00
|
|
|
ByteBuffer.wrap(reference).order(byteOrder).asShortBuffer.put(data)
|
|
|
|
|
val builder = ByteString.newBuilder
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until from) builder.putShort(data(i))(byteOrder)
|
|
|
|
|
builder.putShorts(data, from, to - from)(byteOrder)
|
|
|
|
|
for (i ← to until data.length) builder.putShort(data(i))(byteOrder)
|
2012-05-27 16:26:22 +02:00
|
|
|
reference.toSeq == builder.result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def testIntEncoding(slice: ArraySlice[Int], byteOrder: ByteOrder): Boolean = {
|
|
|
|
|
val elemSize = 4
|
2013-07-23 11:59:36 +02:00
|
|
|
val (data, from, to) = slice
|
2017-03-13 17:49:45 +01:00
|
|
|
val reference = new Array[Byte](data.length * elemSize)
|
2012-05-27 16:26:22 +02:00
|
|
|
ByteBuffer.wrap(reference).order(byteOrder).asIntBuffer.put(data)
|
|
|
|
|
val builder = ByteString.newBuilder
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until from) builder.putInt(data(i))(byteOrder)
|
|
|
|
|
builder.putInts(data, from, to - from)(byteOrder)
|
|
|
|
|
for (i ← to until data.length) builder.putInt(data(i))(byteOrder)
|
2012-05-27 16:26:22 +02:00
|
|
|
reference.toSeq == builder.result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def testLongEncoding(slice: ArraySlice[Long], byteOrder: ByteOrder): Boolean = {
|
|
|
|
|
val elemSize = 8
|
2013-07-23 11:59:36 +02:00
|
|
|
val (data, from, to) = slice
|
2017-03-13 17:49:45 +01:00
|
|
|
val reference = new Array[Byte](data.length * elemSize)
|
2012-05-27 16:26:22 +02:00
|
|
|
ByteBuffer.wrap(reference).order(byteOrder).asLongBuffer.put(data)
|
|
|
|
|
val builder = ByteString.newBuilder
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until from) builder.putLong(data(i))(byteOrder)
|
|
|
|
|
builder.putLongs(data, from, to - from)(byteOrder)
|
|
|
|
|
for (i ← to until data.length) builder.putLong(data(i))(byteOrder)
|
2012-05-27 16:26:22 +02:00
|
|
|
reference.toSeq == builder.result
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-23 11:59:36 +02:00
|
|
|
def testLongPartEncoding(anb: ArrayNumBytes[Long], byteOrder: ByteOrder): Boolean = {
|
|
|
|
|
val elemSize = 8
|
|
|
|
|
val (data, nBytes) = anb
|
|
|
|
|
|
2017-03-13 17:49:45 +01:00
|
|
|
val reference = new Array[Byte](data.length * elemSize)
|
2013-07-23 11:59:36 +02:00
|
|
|
ByteBuffer.wrap(reference).order(byteOrder).asLongBuffer.put(data)
|
|
|
|
|
val builder = ByteString.newBuilder
|
|
|
|
|
for (i ← 0 until data.length) builder.putLongPart(data(i), nBytes)(byteOrder)
|
|
|
|
|
|
|
|
|
|
reference.zipWithIndex.collect({ // Since there is no partial put on LongBuffer, we need to collect only the interesting bytes
|
2013-08-16 12:04:36 +02:00
|
|
|
case (r, i) if byteOrder == ByteOrder.LITTLE_ENDIAN && i % elemSize < nBytes ⇒ r
|
2013-07-23 11:59:36 +02:00
|
|
|
case (r, i) if byteOrder == ByteOrder.BIG_ENDIAN && i % elemSize >= (elemSize - nBytes) ⇒ r
|
|
|
|
|
}).toSeq == builder.result
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-08 17:57:41 +09:00
|
|
|
def testFloatEncoding(slice: ArraySlice[Float], byteOrder: ByteOrder): Boolean = {
|
|
|
|
|
val elemSize = 4
|
2013-07-23 11:59:36 +02:00
|
|
|
val (data, from, to) = slice
|
2017-03-13 17:49:45 +01:00
|
|
|
val reference = new Array[Byte](data.length * elemSize)
|
2012-06-08 17:57:41 +09:00
|
|
|
ByteBuffer.wrap(reference).order(byteOrder).asFloatBuffer.put(data)
|
|
|
|
|
val builder = ByteString.newBuilder
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until from) builder.putFloat(data(i))(byteOrder)
|
|
|
|
|
builder.putFloats(data, from, to - from)(byteOrder)
|
|
|
|
|
for (i ← to until data.length) builder.putFloat(data(i))(byteOrder)
|
2012-06-08 17:57:41 +09:00
|
|
|
reference.toSeq == builder.result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def testDoubleEncoding(slice: ArraySlice[Double], byteOrder: ByteOrder): Boolean = {
|
|
|
|
|
val elemSize = 8
|
2013-07-23 11:59:36 +02:00
|
|
|
val (data, from, to) = slice
|
2017-03-13 17:49:45 +01:00
|
|
|
val reference = new Array[Byte](data.length * elemSize)
|
2012-06-08 17:57:41 +09:00
|
|
|
ByteBuffer.wrap(reference).order(byteOrder).asDoubleBuffer.put(data)
|
|
|
|
|
val builder = ByteString.newBuilder
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until from) builder.putDouble(data(i))(byteOrder)
|
|
|
|
|
builder.putDoubles(data, from, to - from)(byteOrder)
|
|
|
|
|
for (i ← to until data.length) builder.putDouble(data(i))(byteOrder)
|
2012-06-08 17:57:41 +09:00
|
|
|
reference.toSeq == builder.result
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-20 14:01:51 +02:00
|
|
|
"ByteString1" must {
|
2016-10-05 23:25:34 +09:00
|
|
|
"drop" in {
|
|
|
|
|
ByteString1.empty.drop(-1) should ===(ByteString(""))
|
|
|
|
|
ByteString1.empty.drop(0) should ===(ByteString(""))
|
|
|
|
|
ByteString1.empty.drop(1) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("a").drop(-1) should ===(ByteString("a"))
|
2016-07-20 14:01:51 +02:00
|
|
|
ByteString1.fromString("a").drop(0) should ===(ByteString("a"))
|
|
|
|
|
ByteString1.fromString("a").drop(1) should ===(ByteString(""))
|
2016-10-05 23:25:34 +09:00
|
|
|
ByteString1.fromString("a").drop(2) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("abc").drop(-1) should ===(ByteString("abc"))
|
|
|
|
|
ByteString1.fromString("abc").drop(0) should ===(ByteString("abc"))
|
|
|
|
|
ByteString1.fromString("abc").drop(1) should ===(ByteString("bc"))
|
|
|
|
|
ByteString1.fromString("abc").drop(2) should ===(ByteString("c"))
|
|
|
|
|
ByteString1.fromString("abc").drop(3) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("abc").drop(4) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("0123456789").drop(1).take(2) should ===(ByteString("12"))
|
2016-07-20 14:01:51 +02:00
|
|
|
ByteString1.fromString("0123456789").drop(5).take(4).drop(1).take(2) should ===(ByteString("67"))
|
|
|
|
|
}
|
2016-12-06 23:51:11 +09:00
|
|
|
"dropRight" in {
|
|
|
|
|
ByteString1.empty.dropRight(-1) should ===(ByteString(""))
|
|
|
|
|
ByteString1.empty.dropRight(0) should ===(ByteString(""))
|
|
|
|
|
ByteString1.empty.dropRight(1) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("a").dropRight(-1) should ===(ByteString("a"))
|
|
|
|
|
ByteString1.fromString("a").dropRight(0) should ===(ByteString("a"))
|
|
|
|
|
ByteString1.fromString("a").dropRight(1) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("a").dropRight(2) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("abc").dropRight(-1) should ===(ByteString("abc"))
|
|
|
|
|
ByteString1.fromString("abc").dropRight(0) should ===(ByteString("abc"))
|
|
|
|
|
ByteString1.fromString("abc").dropRight(1) should ===(ByteString("ab"))
|
|
|
|
|
ByteString1.fromString("abc").dropRight(2) should ===(ByteString("a"))
|
|
|
|
|
ByteString1.fromString("abc").dropRight(3) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("abc").dropRight(4) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("0123456789").dropRight(1).take(2) should ===(ByteString("01"))
|
|
|
|
|
ByteString1.fromString("0123456789").dropRight(5).take(4).drop(1).take(2) should ===(ByteString("12"))
|
|
|
|
|
}
|
2016-09-22 12:40:54 +09:00
|
|
|
"take" in {
|
|
|
|
|
ByteString1.empty.take(-1) should ===(ByteString(""))
|
|
|
|
|
ByteString1.empty.take(0) should ===(ByteString(""))
|
|
|
|
|
ByteString1.empty.take(1) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("a").take(1) should ===(ByteString("a"))
|
|
|
|
|
ByteString1.fromString("ab").take(-1) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("ab").take(0) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("ab").take(1) should ===(ByteString("a"))
|
|
|
|
|
ByteString1.fromString("ab").take(2) should ===(ByteString("ab"))
|
|
|
|
|
ByteString1.fromString("ab").take(3) should ===(ByteString("ab"))
|
|
|
|
|
ByteString1.fromString("0123456789").take(3).drop(1) should ===(ByteString("12"))
|
|
|
|
|
ByteString1.fromString("0123456789").take(10).take(8).drop(3).take(5) should ===(ByteString("34567"))
|
|
|
|
|
}
|
2016-07-20 14:01:51 +02:00
|
|
|
}
|
|
|
|
|
"ByteString1C" must {
|
2016-10-05 23:25:34 +09:00
|
|
|
"drop" in {
|
|
|
|
|
ByteString1C.fromString("").drop(-1) should ===(ByteString(""))
|
|
|
|
|
ByteString1C.fromString("").drop(0) should ===(ByteString(""))
|
2016-07-20 14:01:51 +02:00
|
|
|
ByteString1C.fromString("").drop(1) should ===(ByteString(""))
|
2016-10-05 23:25:34 +09:00
|
|
|
ByteString1C.fromString("a").drop(-1) should ===(ByteString("a"))
|
|
|
|
|
ByteString1C.fromString("a").drop(0) should ===(ByteString("a"))
|
2016-07-20 14:01:51 +02:00
|
|
|
ByteString1C.fromString("a").drop(1) should ===(ByteString(""))
|
2016-10-05 23:25:34 +09:00
|
|
|
ByteString1C.fromString("a").drop(2) should ===(ByteString(""))
|
|
|
|
|
ByteString1C.fromString("abc").drop(-1) should ===(ByteString("abc"))
|
|
|
|
|
ByteString1C.fromString("abc").drop(0) should ===(ByteString("abc"))
|
|
|
|
|
ByteString1C.fromString("abc").drop(1) should ===(ByteString("bc"))
|
|
|
|
|
ByteString1C.fromString("abc").drop(2) should ===(ByteString("c"))
|
|
|
|
|
ByteString1C.fromString("abc").drop(3) should ===(ByteString(""))
|
|
|
|
|
ByteString1C.fromString("abc").drop(4) should ===(ByteString(""))
|
|
|
|
|
ByteString1C.fromString("0123456789").drop(1).take(2) should ===(ByteString("12"))
|
|
|
|
|
ByteString1C.fromString("0123456789").drop(5).take(4).drop(1).take(2) should ===(ByteString("67"))
|
2016-07-20 14:01:51 +02:00
|
|
|
}
|
2016-12-06 23:51:11 +09:00
|
|
|
"dropRight" in {
|
|
|
|
|
ByteString1C.fromString("").dropRight(-1) should ===(ByteString(""))
|
|
|
|
|
ByteString1C.fromString("").dropRight(0) should ===(ByteString(""))
|
|
|
|
|
ByteString1C.fromString("").dropRight(1) should ===(ByteString(""))
|
|
|
|
|
ByteString1C.fromString("a").dropRight(-1) should ===(ByteString("a"))
|
|
|
|
|
ByteString1C.fromString("a").dropRight(0) should ===(ByteString("a"))
|
|
|
|
|
ByteString1C.fromString("a").dropRight(1) should ===(ByteString(""))
|
|
|
|
|
ByteString1C.fromString("a").dropRight(2) should ===(ByteString(""))
|
|
|
|
|
ByteString1C.fromString("abc").dropRight(-1) should ===(ByteString("abc"))
|
|
|
|
|
ByteString1C.fromString("abc").dropRight(0) should ===(ByteString("abc"))
|
|
|
|
|
ByteString1C.fromString("abc").dropRight(1) should ===(ByteString("ab"))
|
|
|
|
|
ByteString1C.fromString("abc").dropRight(2) should ===(ByteString("a"))
|
|
|
|
|
ByteString1C.fromString("abc").dropRight(3) should ===(ByteString(""))
|
|
|
|
|
ByteString1C.fromString("abc").dropRight(4) should ===(ByteString(""))
|
|
|
|
|
ByteString1C.fromString("0123456789").dropRight(1).take(2) should ===(ByteString("01"))
|
|
|
|
|
ByteString1C.fromString("0123456789").dropRight(5).take(4).drop(1).take(2) should ===(ByteString("12"))
|
|
|
|
|
}
|
2016-07-20 14:01:51 +02:00
|
|
|
"take" in {
|
|
|
|
|
ByteString1.fromString("abcdefg").drop(1).take(0) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("abcdefg").drop(1).take(-1) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("abcdefg").drop(1).take(-2) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("abcdefg").drop(2) should ===(ByteString("cdefg"))
|
|
|
|
|
ByteString1.fromString("abcdefg").drop(2).take(1) should ===(ByteString("c"))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"ByteStrings" must {
|
2016-10-05 23:25:34 +09:00
|
|
|
"drop" in {
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).drop(Int.MinValue) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).drop(-1) should ===(ByteString(""))
|
2016-07-20 14:01:51 +02:00
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).drop(0) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).drop(1) should ===(ByteString(""))
|
2016-10-05 23:25:34 +09:00
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).drop(Int.MaxValue) should ===(ByteString(""))
|
|
|
|
|
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).drop(Int.MinValue) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).drop(-1) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).drop(0) should ===(ByteString("a"))
|
2016-07-20 14:01:51 +02:00
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).drop(1) should ===(ByteString(""))
|
2016-10-05 23:25:34 +09:00
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).drop(2) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).drop(Int.MaxValue) should ===(ByteString(""))
|
|
|
|
|
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).drop(Int.MinValue) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).drop(-1) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).drop(0) should ===(ByteString("a"))
|
2016-07-20 14:01:51 +02:00
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).drop(1) should ===(ByteString(""))
|
2016-10-05 23:25:34 +09:00
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).drop(2) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).drop(Int.MaxValue) should ===(ByteString(""))
|
|
|
|
|
|
|
|
|
|
val bss = ByteStrings(Vector(
|
|
|
|
|
ByteString1.fromString("a"),
|
|
|
|
|
ByteString1.fromString("bc"),
|
|
|
|
|
ByteString1.fromString("def")))
|
|
|
|
|
|
|
|
|
|
bss.drop(Int.MinValue) should ===(ByteString("abcdef"))
|
|
|
|
|
bss.drop(-1) should ===(ByteString("abcdef"))
|
|
|
|
|
bss.drop(0) should ===(ByteString("abcdef"))
|
|
|
|
|
bss.drop(1) should ===(ByteString("bcdef"))
|
|
|
|
|
bss.drop(2) should ===(ByteString("cdef"))
|
|
|
|
|
bss.drop(3) should ===(ByteString("def"))
|
|
|
|
|
bss.drop(4) should ===(ByteString("ef"))
|
|
|
|
|
bss.drop(5) should ===(ByteString("f"))
|
|
|
|
|
bss.drop(6) should ===(ByteString(""))
|
|
|
|
|
bss.drop(7) should ===(ByteString(""))
|
|
|
|
|
bss.drop(Int.MaxValue) should ===(ByteString(""))
|
|
|
|
|
|
|
|
|
|
ByteString("0123456789").drop(5).take(2) should ===(ByteString("56"))
|
|
|
|
|
ByteString("0123456789").drop(5).drop(3).take(1) should ===(ByteString("8"))
|
|
|
|
|
(ByteString1C.fromString("a") ++ ByteString1.fromString("bc")).drop(2) should ===(ByteString("c"))
|
2016-07-20 14:01:51 +02:00
|
|
|
}
|
2016-12-06 23:51:11 +09:00
|
|
|
"dropRight" in {
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).dropRight(Int.MinValue) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).dropRight(-1) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).dropRight(0) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).dropRight(1) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).dropRight(Int.MaxValue) should ===(ByteString(""))
|
|
|
|
|
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(Int.MinValue) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(-1) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(0) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(1) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(2) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(Int.MaxValue) should ===(ByteString(""))
|
|
|
|
|
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).dropRight(Int.MinValue) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).dropRight(-1) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).dropRight(0) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).dropRight(1) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).dropRight(2) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).dropRight(Int.MaxValue) should ===(ByteString(""))
|
|
|
|
|
|
|
|
|
|
val bss = ByteStrings(Vector(
|
|
|
|
|
ByteString1.fromString("a"),
|
|
|
|
|
ByteString1.fromString("bc"),
|
|
|
|
|
ByteString1.fromString("def")))
|
|
|
|
|
|
|
|
|
|
bss.dropRight(Int.MinValue) should ===(ByteString("abcdef"))
|
|
|
|
|
bss.dropRight(-1) should ===(ByteString("abcdef"))
|
|
|
|
|
bss.dropRight(0) should ===(ByteString("abcdef"))
|
|
|
|
|
bss.dropRight(1) should ===(ByteString("abcde"))
|
|
|
|
|
bss.dropRight(2) should ===(ByteString("abcd"))
|
|
|
|
|
bss.dropRight(3) should ===(ByteString("abc"))
|
|
|
|
|
bss.dropRight(4) should ===(ByteString("ab"))
|
|
|
|
|
bss.dropRight(5) should ===(ByteString("a"))
|
|
|
|
|
bss.dropRight(6) should ===(ByteString(""))
|
|
|
|
|
bss.dropRight(7) should ===(ByteString(""))
|
|
|
|
|
bss.dropRight(Int.MaxValue) should ===(ByteString(""))
|
|
|
|
|
|
|
|
|
|
ByteString("0123456789").dropRight(5).take(2) should ===(ByteString("01"))
|
|
|
|
|
ByteString("0123456789").dropRight(5).drop(3).take(1) should ===(ByteString("3"))
|
|
|
|
|
(ByteString1C.fromString("a") ++ ByteString1.fromString("bc")).dropRight(2) should ===(ByteString("a"))
|
|
|
|
|
}
|
2016-07-20 14:01:51 +02:00
|
|
|
"slice" in {
|
|
|
|
|
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).slice(1, 1) should ===(ByteString(""))
|
2016-08-29 09:38:09 +01:00
|
|
|
// We explicitly test all edge cases to always test them, refs bug #21237
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(-10, 10) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(-10, 0) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(-10, 1) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(0, 1) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(0, 10) should ===(ByteString("a"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(1, 10) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(1, -2) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(-10, -100) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(-100, -10) should ===(ByteString(""))
|
|
|
|
|
// Get an empty if `from` is greater then `until`
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(1, 0) should ===(ByteString(""))
|
|
|
|
|
|
2016-07-20 14:01:51 +02:00
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(2, 2) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(2, 3) should ===(ByteString("c"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(2, 4) should ===(ByteString("cd"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(3, 4) should ===(ByteString("d"))
|
2016-08-29 09:38:09 +01:00
|
|
|
// Can obtain expected results from 6 basic patterns
|
|
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(-10, 10) should ===(ByteString("abcd"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(-10, 0) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(-10, 4) should ===(ByteString("abcd"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(0, 4) should ===(ByteString("abcd"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(1, -2) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(0, 10) should ===(ByteString("abcd"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(-10, -100) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(-100, -10) should ===(ByteString(""))
|
|
|
|
|
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(1, -2) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(-10, -100) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).slice(-100, -10) should ===(ByteString(""))
|
|
|
|
|
|
|
|
|
|
// various edge cases using raw ByteString1
|
|
|
|
|
ByteString1.fromString("cd").slice(100, 10) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("cd").slice(100, 1000) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("cd").slice(-10, -5) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("cd").slice(-2, -5) should ===(ByteString(""))
|
|
|
|
|
ByteString1.fromString("cd").slice(-2, 1) should ===(ByteString("c"))
|
|
|
|
|
ByteString1.fromString("abcd").slice(1, -1) should ===(ByteString(""))
|
|
|
|
|
|
|
|
|
|
// Get an empty if `from` is greater than `until`
|
|
|
|
|
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(4, 0) should ===(ByteString(""))
|
2016-07-20 14:01:51 +02:00
|
|
|
}
|
|
|
|
|
"take" in {
|
2016-09-22 12:40:54 +09:00
|
|
|
ByteString.empty.take(-1) should ===(ByteString(""))
|
|
|
|
|
ByteString.empty.take(0) should ===(ByteString(""))
|
|
|
|
|
ByteString.empty.take(1) should ===(ByteString(""))
|
2016-07-20 14:01:51 +02:00
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("bc")).drop(1).take(0) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("bc")).drop(1).take(-1) should ===(ByteString(""))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("bc")).drop(1).take(-2) should ===(ByteString(""))
|
|
|
|
|
(ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("bc")) ++ ByteString1.fromString("defg")).drop(2) should ===(ByteString("cdefg"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("bc")).drop(2).take(1) should ===(ByteString("c"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("bc")).take(100) should ===(ByteString("abc"))
|
|
|
|
|
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("bc")).drop(1).take(100) should ===(ByteString("bc"))
|
|
|
|
|
}
|
2016-10-19 11:26:50 +02:00
|
|
|
"indexOf" in {
|
|
|
|
|
ByteString.empty.indexOf(5) should ===(-1)
|
|
|
|
|
val byteString1 = ByteString1.fromString("abc")
|
|
|
|
|
byteString1.indexOf('a') should ===(0)
|
|
|
|
|
byteString1.indexOf('b') should ===(1)
|
|
|
|
|
byteString1.indexOf('c') should ===(2)
|
|
|
|
|
byteString1.indexOf('d') should ===(-1)
|
|
|
|
|
|
|
|
|
|
val byteStrings = ByteStrings(ByteString1.fromString("abc"), ByteString1.fromString("efg"))
|
|
|
|
|
byteStrings.indexOf('a') should ===(0)
|
|
|
|
|
byteStrings.indexOf('c') should ===(2)
|
|
|
|
|
byteStrings.indexOf('d') should ===(-1)
|
|
|
|
|
byteStrings.indexOf('e') should ===(3)
|
|
|
|
|
byteStrings.indexOf('f') should ===(4)
|
|
|
|
|
byteStrings.indexOf('g') should ===(5)
|
|
|
|
|
|
|
|
|
|
val compact = byteStrings.compact
|
|
|
|
|
compact.indexOf('a') should ===(0)
|
|
|
|
|
compact.indexOf('c') should ===(2)
|
|
|
|
|
compact.indexOf('d') should ===(-1)
|
|
|
|
|
compact.indexOf('e') should ===(3)
|
|
|
|
|
compact.indexOf('f') should ===(4)
|
|
|
|
|
compact.indexOf('g') should ===(5)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
"indexOf from offset" in {
|
|
|
|
|
ByteString.empty.indexOf(5, -1) should ===(-1)
|
|
|
|
|
ByteString.empty.indexOf(5, 0) should ===(-1)
|
|
|
|
|
ByteString.empty.indexOf(5, 1) should ===(-1)
|
|
|
|
|
val byteString1 = ByteString1.fromString("abc")
|
|
|
|
|
byteString1.indexOf('d', -1) should ===(-1)
|
|
|
|
|
byteString1.indexOf('d', 0) should ===(-1)
|
|
|
|
|
byteString1.indexOf('d', 1) should ===(-1)
|
|
|
|
|
byteString1.indexOf('d', 4) should ===(-1)
|
|
|
|
|
byteString1.indexOf('a', -1) should ===(0)
|
|
|
|
|
byteString1.indexOf('a', 0) should ===(0)
|
|
|
|
|
byteString1.indexOf('a', 1) should ===(-1)
|
|
|
|
|
|
|
|
|
|
val byteStrings = ByteStrings(ByteString1.fromString("abc"), ByteString1.fromString("efg"))
|
|
|
|
|
byteStrings.indexOf('c', -1) should ===(2)
|
|
|
|
|
byteStrings.indexOf('c', 0) should ===(2)
|
|
|
|
|
byteStrings.indexOf('c', 2) should ===(2)
|
|
|
|
|
byteStrings.indexOf('c', 3) should ===(-1)
|
|
|
|
|
|
|
|
|
|
byteStrings.indexOf('e', -1) should ===(3)
|
|
|
|
|
byteStrings.indexOf('e', 0) should ===(3)
|
|
|
|
|
byteStrings.indexOf('e', 1) should ===(3)
|
|
|
|
|
byteStrings.indexOf('e', 4) should ===(-1)
|
|
|
|
|
byteStrings.indexOf('e', 6) should ===(-1)
|
|
|
|
|
|
|
|
|
|
byteStrings.indexOf('g', -1) should ===(5)
|
|
|
|
|
byteStrings.indexOf('g', 0) should ===(5)
|
|
|
|
|
byteStrings.indexOf('g', 1) should ===(5)
|
|
|
|
|
byteStrings.indexOf('g', 4) should ===(5)
|
|
|
|
|
byteStrings.indexOf('g', 5) should ===(5)
|
|
|
|
|
byteStrings.indexOf('g', 6) should ===(-1)
|
|
|
|
|
|
|
|
|
|
val compact = byteStrings.compact
|
|
|
|
|
compact.indexOf('c', -1) should ===(2)
|
|
|
|
|
compact.indexOf('c', 0) should ===(2)
|
|
|
|
|
compact.indexOf('c', 2) should ===(2)
|
|
|
|
|
compact.indexOf('c', 3) should ===(-1)
|
|
|
|
|
|
|
|
|
|
compact.indexOf('e', -1) should ===(3)
|
|
|
|
|
compact.indexOf('e', 0) should ===(3)
|
|
|
|
|
compact.indexOf('e', 1) should ===(3)
|
|
|
|
|
compact.indexOf('e', 4) should ===(-1)
|
|
|
|
|
compact.indexOf('e', 6) should ===(-1)
|
|
|
|
|
|
|
|
|
|
compact.indexOf('g', -1) should ===(5)
|
|
|
|
|
compact.indexOf('g', 0) should ===(5)
|
|
|
|
|
compact.indexOf('g', 1) should ===(5)
|
|
|
|
|
compact.indexOf('g', 4) should ===(5)
|
|
|
|
|
compact.indexOf('g', 5) should ===(5)
|
|
|
|
|
compact.indexOf('g', 6) should ===(-1)
|
|
|
|
|
}
|
2016-07-20 14:01:51 +02:00
|
|
|
}
|
|
|
|
|
|
2011-06-19 16:32:21 -06:00
|
|
|
"A ByteString" must {
|
|
|
|
|
"have correct size" when {
|
|
|
|
|
"concatenating" in { check((a: ByteString, b: ByteString) ⇒ (a ++ b).size == a.size + b.size) }
|
|
|
|
|
"dropping" in { check((a: ByteString, b: ByteString) ⇒ (a ++ b).drop(b.size).size == a.size) }
|
2016-07-20 14:01:51 +02:00
|
|
|
"taking" in { check((a: ByteString, b: ByteString) ⇒ (a ++ b).take(a.size) == a) }
|
|
|
|
|
"takingRight" in { check((a: ByteString, b: ByteString) ⇒ (a ++ b).takeRight(b.size) == b) }
|
|
|
|
|
"droppnig then taking" in { check((a: ByteString, b: ByteString) ⇒ (b ++ a ++ b).drop(b.size).take(a.size) == a) }
|
|
|
|
|
"droppingRight" in { check((a: ByteString, b: ByteString) ⇒ (b ++ a ++ b).drop(b.size).dropRight(b.size) == a) }
|
2011-06-19 16:32:21 -06:00
|
|
|
}
|
2012-06-12 15:03:07 +09:00
|
|
|
|
2011-06-19 16:32:21 -06:00
|
|
|
"be sequential" when {
|
|
|
|
|
"taking" in { check((a: ByteString, b: ByteString) ⇒ (a ++ b).take(a.size) == a) }
|
|
|
|
|
"dropping" in { check((a: ByteString, b: ByteString) ⇒ (a ++ b).drop(a.size) == b) }
|
2012-05-31 00:48:56 +02:00
|
|
|
}
|
2012-06-12 15:03:07 +09:00
|
|
|
|
2012-05-31 00:48:56 +02:00
|
|
|
"be equal to the original" when {
|
|
|
|
|
"compacting" in { check { xs: ByteString ⇒ val ys = xs.compact; (xs == ys) && ys.isCompact } }
|
2012-05-27 16:26:22 +02:00
|
|
|
"recombining" in {
|
|
|
|
|
check { (xs: ByteString, from: Int, until: Int) ⇒
|
|
|
|
|
val (tmp, c) = xs.splitAt(until)
|
|
|
|
|
val (a, b) = tmp.splitAt(from)
|
|
|
|
|
(a ++ b ++ c) == xs
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-20 14:01:51 +02:00
|
|
|
def excerciseRecombining(xs: ByteString, from: Int, until: Int) = {
|
|
|
|
|
val (tmp, c) = xs.splitAt(until)
|
|
|
|
|
val (a, b) = tmp.splitAt(from)
|
2016-07-22 14:07:41 +02:00
|
|
|
(a ++ b ++ c) should ===(xs)
|
2016-07-20 14:01:51 +02:00
|
|
|
}
|
|
|
|
|
"recombining - edge cases" in {
|
|
|
|
|
excerciseRecombining(ByteStrings(Vector(ByteString1(Array[Byte](1)), ByteString1(Array[Byte](2)))), -2147483648, 112121212)
|
|
|
|
|
excerciseRecombining(ByteStrings(Vector(ByteString1(Array[Byte](100)))), 0, 2)
|
|
|
|
|
excerciseRecombining(ByteStrings(Vector(ByteString1(Array[Byte](100)))), -2147483648, 2)
|
|
|
|
|
excerciseRecombining(ByteStrings(Vector(ByteString1.fromString("ab"), ByteString1.fromString("cd"))), 0, 1)
|
|
|
|
|
excerciseRecombining(ByteString1.fromString("abc").drop(1).take(1), -324234, 234232)
|
|
|
|
|
excerciseRecombining(ByteString("a"), 0, 2147483647)
|
|
|
|
|
excerciseRecombining(ByteStrings(Vector(ByteString1.fromString("ab"), ByteString1.fromString("cd"))).drop(2), 2147483647, 1)
|
|
|
|
|
excerciseRecombining(ByteString1.fromString("ab").drop1(1), Int.MaxValue, Int.MaxValue)
|
|
|
|
|
}
|
2011-06-19 16:32:21 -06:00
|
|
|
}
|
2012-06-12 15:03:07 +09:00
|
|
|
|
|
|
|
|
"behave as expected" when {
|
|
|
|
|
"created from and decoding to String" in { check { s: String ⇒ ByteString(s, "UTF-8").decodeString("UTF-8") == s } }
|
|
|
|
|
|
|
|
|
|
"compacting" in {
|
|
|
|
|
check { a: ByteString ⇒
|
|
|
|
|
val wasCompact = a.isCompact
|
|
|
|
|
val b = a.compact
|
|
|
|
|
((!wasCompact) || (b eq a)) &&
|
|
|
|
|
(b == a) &&
|
|
|
|
|
b.isCompact &&
|
|
|
|
|
(b.compact eq b)
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-01-27 23:46:03 +01:00
|
|
|
|
|
|
|
|
"asByteBuffers" in {
|
|
|
|
|
check { (a: ByteString) ⇒ if (a.isCompact) a.asByteBuffers.size == 1 && a.asByteBuffers.head == a.asByteBuffer else a.asByteBuffers.size > 0 }
|
|
|
|
|
check { (a: ByteString) ⇒ a.asByteBuffers.foldLeft(ByteString.empty) { (bs, bb) ⇒ bs ++ ByteString(bb) } == a }
|
|
|
|
|
check { (a: ByteString) ⇒ a.asByteBuffers.forall(_.isReadOnly) }
|
|
|
|
|
check { (a: ByteString) ⇒
|
2016-07-20 12:18:52 +02:00
|
|
|
import scala.collection.JavaConverters.iterableAsScalaIterableConverter
|
2013-01-28 17:56:29 +01:00
|
|
|
a.asByteBuffers.zip(a.getByteBuffers().asScala).forall(x ⇒ x._1 == x._2)
|
2013-01-27 23:46:03 +01:00
|
|
|
}
|
|
|
|
|
}
|
2016-11-17 15:51:36 +01:00
|
|
|
|
|
|
|
|
"toString should start with ByteString(" in {
|
|
|
|
|
check { (bs: ByteString) ⇒
|
|
|
|
|
bs.toString.startsWith("ByteString(")
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-06-12 15:03:07 +09:00
|
|
|
}
|
|
|
|
|
"behave like a Vector" when {
|
2013-01-27 23:46:03 +01:00
|
|
|
"concatenating" in { check { (a: ByteString, b: ByteString) ⇒ likeVectors(a, b) { _ ++ _ } } }
|
2012-06-12 15:03:07 +09:00
|
|
|
|
|
|
|
|
"calling apply" in {
|
|
|
|
|
check { slice: ByteStringSlice ⇒
|
|
|
|
|
slice match {
|
|
|
|
|
case (xs, i1, i2) ⇒ likeVector(xs) { seq ⇒
|
|
|
|
|
(if ((i1 >= 0) && (i1 < seq.length)) seq(i1) else 0,
|
|
|
|
|
if ((i2 >= 0) && (i2 < seq.length)) seq(i2) else 0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"calling head" in { check { a: ByteString ⇒ a.isEmpty || likeVector(a) { _.head } } }
|
2012-06-17 22:18:51 +02:00
|
|
|
"calling tail" in { check { a: ByteString ⇒ a.isEmpty || likeVector(a) { _.tail } } }
|
2012-06-12 15:03:07 +09:00
|
|
|
"calling last" in { check { a: ByteString ⇒ a.isEmpty || likeVector(a) { _.last } } }
|
2012-06-17 22:18:51 +02:00
|
|
|
"calling init" in { check { a: ByteString ⇒ a.isEmpty || likeVector(a) { _.init } } }
|
2012-06-12 15:03:07 +09:00
|
|
|
"calling length" in { check { a: ByteString ⇒ likeVector(a) { _.length } } }
|
|
|
|
|
|
|
|
|
|
"calling span" in { check { (a: ByteString, b: Byte) ⇒ likeVector(a)({ _.span(_ != b) match { case (a, b) ⇒ (a, b) } }) } }
|
|
|
|
|
|
|
|
|
|
"calling takeWhile" in { check { (a: ByteString, b: Byte) ⇒ likeVector(a)({ _.takeWhile(_ != b) }) } }
|
|
|
|
|
"calling dropWhile" in { check { (a: ByteString, b: Byte) ⇒ likeVector(a) { _.dropWhile(_ != b) } } }
|
|
|
|
|
"calling indexWhere" in { check { (a: ByteString, b: Byte) ⇒ likeVector(a) { _.indexWhere(_ == b) } } }
|
|
|
|
|
"calling indexOf" in { check { (a: ByteString, b: Byte) ⇒ likeVector(a) { _.indexOf(b) } } }
|
2016-10-19 11:26:50 +02:00
|
|
|
// this actually behave weird for Vector and negative indexes - SI9936, fixed in Scala 2.12
|
|
|
|
|
// so let's just skip negative indexes (doesn't make much sense anyway)
|
|
|
|
|
"calling indexOf(elem, idx)" in { check { (a: ByteString, b: Byte, idx: Int) ⇒ likeVector(a) { _.indexOf(b, math.max(0, idx)) } } }
|
|
|
|
|
|
2012-06-12 15:03:07 +09:00
|
|
|
"calling foreach" in { check { a: ByteString ⇒ likeVector(a) { it ⇒ var acc = 0; it foreach { acc += _ }; acc } } }
|
|
|
|
|
"calling foldLeft" in { check { a: ByteString ⇒ likeVector(a) { _.foldLeft(0) { _ + _ } } } }
|
|
|
|
|
"calling toArray" in { check { a: ByteString ⇒ likeVector(a) { _.toArray.toSeq } } }
|
|
|
|
|
|
|
|
|
|
"calling slice" in {
|
|
|
|
|
check { slice: ByteStringSlice ⇒
|
|
|
|
|
slice match {
|
|
|
|
|
case (xs, from, until) ⇒ likeVector(xs)({
|
|
|
|
|
_.slice(from, until)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"calling take and drop" in {
|
|
|
|
|
check { slice: ByteStringSlice ⇒
|
|
|
|
|
slice match {
|
|
|
|
|
case (xs, from, until) ⇒ likeVector(xs)({
|
|
|
|
|
_.drop(from).take(until - from)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"calling copyToArray" in {
|
|
|
|
|
check { slice: ByteStringSlice ⇒
|
|
|
|
|
slice match {
|
|
|
|
|
case (xs, from, until) ⇒ likeVector(xs)({ it ⇒
|
2017-03-13 17:49:45 +01:00
|
|
|
val array = new Array[Byte](xs.length)
|
2012-06-12 15:03:07 +09:00
|
|
|
it.slice(from, until).copyToArray(array, from, until)
|
|
|
|
|
array.toSeq
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-04-07 07:37:26 -05:00
|
|
|
|
|
|
|
|
"serialize correctly" when {
|
|
|
|
|
"parsing regular ByteString1C as compat" in {
|
|
|
|
|
val oldSerd = "aced000573720021616b6b612e7574696c2e42797465537472696e672442797465537472696e67314336e9eed0afcfe4a40200015b000562797465737400025b427872001b616b6b612e7574696c2e436f6d7061637442797465537472696e67fa2925150f93468f0200007870757200025b42acf317f8060854e002000078700000000a74657374737472696e67"
|
|
|
|
|
val bs = ByteString("teststring", "UTF8")
|
|
|
|
|
val str = hexFromSer(bs)
|
|
|
|
|
|
|
|
|
|
require(oldSerd == str)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"given all types of ByteString" in {
|
|
|
|
|
check { bs: ByteString ⇒
|
|
|
|
|
testSer(bs)
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-08-03 16:20:59 +02:00
|
|
|
|
|
|
|
|
"with a large concatenated bytestring" in {
|
|
|
|
|
// coverage for #20901
|
|
|
|
|
val original = ByteString(Array.fill[Byte](1000)(1)) ++ ByteString(Array.fill[Byte](1000)(2))
|
|
|
|
|
|
|
|
|
|
deserialize(serialize(original)) shouldEqual original
|
|
|
|
|
}
|
2015-04-07 07:37:26 -05:00
|
|
|
}
|
2011-06-19 16:32:21 -06:00
|
|
|
}
|
2012-05-01 18:41:04 +02:00
|
|
|
|
|
|
|
|
"A ByteStringIterator" must {
|
|
|
|
|
"behave like a buffered Vector Iterator" when {
|
|
|
|
|
"concatenating" in { check { (a: ByteString, b: ByteString) ⇒ likeVecIts(a, b) { (a, b) ⇒ (a ++ b).toSeq } } }
|
|
|
|
|
|
|
|
|
|
"calling head" in { check { a: ByteString ⇒ a.isEmpty || likeVecIt(a) { _.head } } }
|
|
|
|
|
"calling next" in { check { a: ByteString ⇒ a.isEmpty || likeVecIt(a) { _.next() } } }
|
|
|
|
|
"calling hasNext" in { check { a: ByteString ⇒ likeVecIt(a) { _.hasNext } } }
|
|
|
|
|
"calling length" in { check { a: ByteString ⇒ likeVecIt(a) { _.length } } }
|
|
|
|
|
"calling duplicate" in { check { a: ByteString ⇒ likeVecIt(a)({ _.duplicate match { case (a, b) ⇒ (a.toSeq, b.toSeq) } }, strict = false) } }
|
2012-05-27 01:12:45 +02:00
|
|
|
|
|
|
|
|
// Have to used toList instead of toSeq here, iterator.span (new in
|
|
|
|
|
// Scala-2.9) seems to be broken in combination with toSeq for the
|
|
|
|
|
// scala.collection default Iterator (see Scala issue SI-5838).
|
2012-05-27 01:13:45 +02:00
|
|
|
"calling span" in { check { (a: ByteString, b: Byte) ⇒ likeVecIt(a)({ _.span(_ != b) match { case (a, b) ⇒ (a.toList, b.toList) } }, strict = false) } }
|
2012-05-27 01:12:45 +02:00
|
|
|
|
2012-05-27 01:13:45 +02:00
|
|
|
"calling takeWhile" in { check { (a: ByteString, b: Byte) ⇒ likeVecIt(a)({ _.takeWhile(_ != b).toSeq }, strict = false) } }
|
|
|
|
|
"calling dropWhile" in { check { (a: ByteString, b: Byte) ⇒ likeVecIt(a) { _.dropWhile(_ != b).toSeq } } }
|
2012-05-01 18:41:04 +02:00
|
|
|
"calling indexWhere" in { check { (a: ByteString, b: Byte) ⇒ likeVecIt(a) { _.indexWhere(_ == b) } } }
|
|
|
|
|
"calling indexOf" in { check { (a: ByteString, b: Byte) ⇒ likeVecIt(a) { _.indexOf(b) } } }
|
|
|
|
|
"calling toSeq" in { check { a: ByteString ⇒ likeVecIt(a) { _.toSeq } } }
|
|
|
|
|
"calling foreach" in { check { a: ByteString ⇒ likeVecIt(a) { it ⇒ var acc = 0; it foreach { acc += _ }; acc } } }
|
|
|
|
|
"calling foldLeft" in { check { a: ByteString ⇒ likeVecIt(a) { _.foldLeft(0) { _ + _ } } } }
|
|
|
|
|
"calling toArray" in { check { a: ByteString ⇒ likeVecIt(a) { _.toArray.toSeq } } }
|
|
|
|
|
|
|
|
|
|
"calling slice" in {
|
|
|
|
|
check { slice: ByteStringSlice ⇒
|
|
|
|
|
slice match {
|
|
|
|
|
case (xs, from, until) ⇒ likeVecIt(xs)({
|
|
|
|
|
_.slice(from, until).toSeq
|
|
|
|
|
}, strict = false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-31 10:15:44 +02:00
|
|
|
"calling take and drop" in {
|
|
|
|
|
check { slice: ByteStringSlice ⇒
|
|
|
|
|
slice match {
|
|
|
|
|
case (xs, from, until) ⇒ likeVecIt(xs)({
|
|
|
|
|
_.drop(from).take(until - from).toSeq
|
|
|
|
|
}, strict = false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-01 18:41:04 +02:00
|
|
|
"calling copyToArray" in {
|
|
|
|
|
check { slice: ByteStringSlice ⇒
|
|
|
|
|
slice match {
|
|
|
|
|
case (xs, from, until) ⇒ likeVecIt(xs)({ it ⇒
|
2017-03-13 17:49:45 +01:00
|
|
|
val array = new Array[Byte](xs.length)
|
2012-05-01 18:41:04 +02:00
|
|
|
it.slice(from, until).copyToArray(array, from, until)
|
|
|
|
|
array.toSeq
|
|
|
|
|
}, strict = false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-27 16:26:22 +02:00
|
|
|
|
|
|
|
|
"function as expected" when {
|
|
|
|
|
"getting Bytes, using getByte and getBytes" in {
|
|
|
|
|
// mixing getByte and getBytes here for more rigorous testing
|
|
|
|
|
check { slice: ByteStringSlice ⇒
|
2013-07-23 11:59:36 +02:00
|
|
|
val (bytes, from, to) = slice
|
2012-05-27 16:26:22 +02:00
|
|
|
val input = bytes.iterator
|
2017-03-13 17:49:45 +01:00
|
|
|
val output = new Array[Byte](bytes.length)
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until from) output(i) = input.getByte
|
|
|
|
|
input.getBytes(output, from, to - from)
|
|
|
|
|
for (i ← to until bytes.length) output(i) = input.getByte
|
2012-05-27 16:26:22 +02:00
|
|
|
(output.toSeq == bytes) && (input.isEmpty)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-21 14:33:48 +08:00
|
|
|
"getting Bytes with a given length" in {
|
|
|
|
|
check {
|
|
|
|
|
slice: ByteStringSlice ⇒
|
|
|
|
|
val (bytes, _, _) = slice
|
|
|
|
|
val input = bytes.iterator
|
|
|
|
|
(input.getBytes(bytes.length).toSeq == bytes) && input.isEmpty
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"getting ByteString with a given length" in {
|
|
|
|
|
check {
|
|
|
|
|
slice: ByteStringSlice ⇒
|
|
|
|
|
val (bytes, _, _) = slice
|
|
|
|
|
val input = bytes.iterator
|
|
|
|
|
(input.getByteString(bytes.length) == bytes) && input.isEmpty
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-27 16:26:22 +02:00
|
|
|
"getting Bytes, using the InputStream wrapper" in {
|
|
|
|
|
// combining skip and both read methods here for more rigorous testing
|
|
|
|
|
check { slice: ByteStringSlice ⇒
|
2013-07-23 11:59:36 +02:00
|
|
|
val (bytes, from, to) = slice
|
2012-05-27 16:26:22 +02:00
|
|
|
val a = (0 max from) min bytes.length
|
2013-07-23 11:59:36 +02:00
|
|
|
val b = (a max to) min bytes.length
|
2012-05-27 16:26:22 +02:00
|
|
|
val input = bytes.iterator
|
2017-03-13 17:49:45 +01:00
|
|
|
val output = new Array[Byte](bytes.length)
|
2012-05-27 16:26:22 +02:00
|
|
|
|
|
|
|
|
input.asInputStream.skip(a)
|
|
|
|
|
|
|
|
|
|
val toRead = b - a
|
|
|
|
|
var (nRead, eof) = (0, false)
|
|
|
|
|
while ((nRead < toRead) && !eof) {
|
|
|
|
|
val n = input.asInputStream.read(output, a + nRead, toRead - nRead)
|
|
|
|
|
if (n == -1) eof = true
|
|
|
|
|
else nRead += n
|
|
|
|
|
}
|
|
|
|
|
if (eof) throw new RuntimeException("Unexpected EOF")
|
|
|
|
|
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← b until bytes.length) output(i) = input.asInputStream.read().toByte
|
2012-05-27 16:26:22 +02:00
|
|
|
|
|
|
|
|
(output.toSeq.drop(a) == bytes.drop(a)) &&
|
|
|
|
|
(input.asInputStream.read() == -1) &&
|
|
|
|
|
((output.length < 1) || (input.asInputStream.read(output, 0, 1) == -1))
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-31 10:15:44 +02:00
|
|
|
|
|
|
|
|
"calling copyToBuffer" in {
|
|
|
|
|
check { bytes: ByteString ⇒
|
|
|
|
|
import java.nio.ByteBuffer
|
|
|
|
|
val buffer = ByteBuffer.allocate(bytes.size)
|
|
|
|
|
bytes.copyToBuffer(buffer)
|
|
|
|
|
buffer.flip()
|
2017-03-13 17:49:45 +01:00
|
|
|
val array = new Array[Byte](bytes.size)
|
2012-05-31 10:15:44 +02:00
|
|
|
buffer.get(array)
|
|
|
|
|
bytes == array.toSeq
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-27 16:26:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"decode data correctly" when {
|
|
|
|
|
"decoding Short in big-endian" in { check { slice: ByteStringSlice ⇒ testShortDecoding(slice, BIG_ENDIAN) } }
|
|
|
|
|
"decoding Short in little-endian" in { check { slice: ByteStringSlice ⇒ testShortDecoding(slice, LITTLE_ENDIAN) } }
|
|
|
|
|
"decoding Int in big-endian" in { check { slice: ByteStringSlice ⇒ testIntDecoding(slice, BIG_ENDIAN) } }
|
|
|
|
|
"decoding Int in little-endian" in { check { slice: ByteStringSlice ⇒ testIntDecoding(slice, LITTLE_ENDIAN) } }
|
|
|
|
|
"decoding Long in big-endian" in { check { slice: ByteStringSlice ⇒ testLongDecoding(slice, BIG_ENDIAN) } }
|
|
|
|
|
"decoding Long in little-endian" in { check { slice: ByteStringSlice ⇒ testLongDecoding(slice, LITTLE_ENDIAN) } }
|
2012-06-08 17:57:41 +09:00
|
|
|
"decoding Float in big-endian" in { check { slice: ByteStringSlice ⇒ testFloatDecoding(slice, BIG_ENDIAN) } }
|
|
|
|
|
"decoding Float in little-endian" in { check { slice: ByteStringSlice ⇒ testFloatDecoding(slice, LITTLE_ENDIAN) } }
|
|
|
|
|
"decoding Double in big-endian" in { check { slice: ByteStringSlice ⇒ testDoubleDecoding(slice, BIG_ENDIAN) } }
|
|
|
|
|
"decoding Double in little-endian" in { check { slice: ByteStringSlice ⇒ testDoubleDecoding(slice, LITTLE_ENDIAN) } }
|
2012-05-27 16:26:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"A ByteStringBuilder" must {
|
2012-06-12 14:13:17 +09:00
|
|
|
"function like a VectorBuilder" when {
|
|
|
|
|
"adding various contents using ++= and +=" in {
|
|
|
|
|
check { (array1: Array[Byte], array2: Array[Byte], bs1: ByteString, bs2: ByteString, bs3: ByteString) ⇒
|
|
|
|
|
likeVecBld { builder ⇒
|
|
|
|
|
builder ++= array1
|
|
|
|
|
bs1 foreach { b ⇒ builder += b }
|
|
|
|
|
builder ++= bs2
|
|
|
|
|
bs3 foreach { b ⇒ builder += b }
|
|
|
|
|
builder ++= Vector(array2: _*)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-27 16:26:22 +02:00
|
|
|
"function as expected" when {
|
|
|
|
|
"putting Bytes, using putByte and putBytes" in {
|
|
|
|
|
// mixing putByte and putBytes here for more rigorous testing
|
|
|
|
|
check { slice: ArraySlice[Byte] ⇒
|
2013-07-23 11:59:36 +02:00
|
|
|
val (data, from, to) = slice
|
2012-05-27 16:26:22 +02:00
|
|
|
val builder = ByteString.newBuilder
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until from) builder.putByte(data(i))
|
|
|
|
|
builder.putBytes(data, from, to - from)
|
|
|
|
|
for (i ← to until data.length) builder.putByte(data(i))
|
2012-05-27 16:26:22 +02:00
|
|
|
data.toSeq == builder.result
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"putting Bytes, using the OutputStream wrapper" in {
|
|
|
|
|
// mixing the write methods here for more rigorous testing
|
|
|
|
|
check { slice: ArraySlice[Byte] ⇒
|
2013-07-23 11:59:36 +02:00
|
|
|
val (data, from, to) = slice
|
2012-05-27 16:26:22 +02:00
|
|
|
val builder = ByteString.newBuilder
|
2013-07-23 11:59:36 +02:00
|
|
|
for (i ← 0 until from) builder.asOutputStream.write(data(i).toInt)
|
|
|
|
|
builder.asOutputStream.write(data, from, to - from)
|
|
|
|
|
for (i ← to until data.length) builder.asOutputStream.write(data(i).toInt)
|
2012-05-27 16:26:22 +02:00
|
|
|
data.toSeq == builder.result
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"encode data correctly" when {
|
|
|
|
|
"encoding Short in big-endian" in { check { slice: ArraySlice[Short] ⇒ testShortEncoding(slice, BIG_ENDIAN) } }
|
|
|
|
|
"encoding Short in little-endian" in { check { slice: ArraySlice[Short] ⇒ testShortEncoding(slice, LITTLE_ENDIAN) } }
|
|
|
|
|
"encoding Int in big-endian" in { check { slice: ArraySlice[Int] ⇒ testIntEncoding(slice, BIG_ENDIAN) } }
|
|
|
|
|
"encoding Int in little-endian" in { check { slice: ArraySlice[Int] ⇒ testIntEncoding(slice, LITTLE_ENDIAN) } }
|
|
|
|
|
"encoding Long in big-endian" in { check { slice: ArraySlice[Long] ⇒ testLongEncoding(slice, BIG_ENDIAN) } }
|
|
|
|
|
"encoding Long in little-endian" in { check { slice: ArraySlice[Long] ⇒ testLongEncoding(slice, LITTLE_ENDIAN) } }
|
2013-07-23 11:59:36 +02:00
|
|
|
"encoding LongPart in big-endian" in { check { slice: ArrayNumBytes[Long] ⇒ testLongPartEncoding(slice, BIG_ENDIAN) } }
|
|
|
|
|
"encoding LongPart in little-endian" in { check { slice: ArrayNumBytes[Long] ⇒ testLongPartEncoding(slice, LITTLE_ENDIAN) } }
|
2012-06-08 17:57:41 +09:00
|
|
|
"encoding Float in big-endian" in { check { slice: ArraySlice[Float] ⇒ testFloatEncoding(slice, BIG_ENDIAN) } }
|
|
|
|
|
"encoding Float in little-endian" in { check { slice: ArraySlice[Float] ⇒ testFloatEncoding(slice, LITTLE_ENDIAN) } }
|
|
|
|
|
"encoding Double in big-endian" in { check { slice: ArraySlice[Double] ⇒ testDoubleEncoding(slice, BIG_ENDIAN) } }
|
|
|
|
|
"encoding Double in little-endian" in { check { slice: ArraySlice[Double] ⇒ testDoubleEncoding(slice, LITTLE_ENDIAN) } }
|
2012-05-27 16:26:22 +02:00
|
|
|
}
|
2015-03-28 13:34:47 +08:00
|
|
|
|
|
|
|
|
"have correct empty info" when {
|
|
|
|
|
"is empty" in {
|
|
|
|
|
check { a: ByteStringBuilder ⇒ a.isEmpty }
|
|
|
|
|
}
|
|
|
|
|
"is nonEmpty" in {
|
|
|
|
|
check { a: ByteStringBuilder ⇒
|
|
|
|
|
a.putByte(1.toByte)
|
|
|
|
|
a.nonEmpty
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-01 18:41:04 +02:00
|
|
|
}
|
2011-06-19 16:32:21 -06:00
|
|
|
}
|