Skip to content

Commit

Permalink
Add tests for ByteArray. Apply suggestions from code review.
Browse files Browse the repository at this point in the history
  • Loading branch information
klntsky committed Jan 26, 2022
1 parent d7b35b9 commit 6b093a6
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 57 deletions.
2 changes: 2 additions & 0 deletions spago.dhall
Expand Up @@ -27,6 +27,8 @@ You can edit this file as you like.
, "ordered-collections"
, "prelude"
, "psci-support"
, "quickcheck"
, "quickcheck-laws"
, "refs"
, "spec"
, "strings"
Expand Down
76 changes: 38 additions & 38 deletions src/Types/ByteArray.js
@@ -1,49 +1,41 @@
// From instance for Array in prelude
exports.ordImpl = function (f) {
return function (xs) {
return function (ys) {
var i = 0;
var xlen = xs.length;
var ylen = ys.length;
while (i < xlen && i < ylen) {
var x = xs[i];
var y = ys[i];
var o = f(x)(y);
if (o !== 0) {
return o;
}
i++;
}
if (xlen === ylen) {
return 0;
} else if (xlen > ylen) {
return -1;
} else {
return 1;
}
};
};
exports.ord_ = f => xs => ys => {
let i = 0;
const xlen = xs.length;
const ylen = ys.length;
while (i < xlen && i < ylen) {
var o = f(xs[i])(ys[i]);
if (o !== 0) {
return o;
}
i++;
}
if (xlen === ylen) {
return 0;
} else if (xlen > ylen) {
return -1;
} else {
return 1;
}
};

exports.concatImpl = function (xs) {
return function (ys) {
const res = new Uint8Array(xs.length + ys.length);
for (let i = 0; i < xs.length; i++) {
res[i] = xs[i];
}
for (let i = 0; i < ys.length; i++) {
res[i + xs.length] = ys[i];
}
return res;
};
exports.concat_ = xs => ys => {
const res = new Uint8Array(xs.length + ys.length);
for (let i = 0; i < xs.length; i++) {
res[i] = xs[i];
}
for (let i = 0; i < ys.length; i++) {
res[i + xs.length] = ys[i];
}
return res;
};

exports.byteArrayToHex = arr =>
Buffer.from(arr).toString('hex');

exports.hexToByteArrayImpl = nothing => just => hex => {
exports.hexToByteArray_ = nothing => just => hex => {
for (var bytes = [], c = 0; c < hex.length; c += 2) {
let chunk = hex.substr(c, 2);
const chunk = hex.substr(c, 2);
if (/[0-9a-f]{2}/i.test(chunk)) {
bytes.push(parseInt(chunk, 16));
} else {
Expand All @@ -59,6 +51,14 @@ exports.hexToByteArrayUnsafe = hex => {
return new Uint8Array(bytes);
};

exports.byteArrayFromIntArray = ints => new Uint8Array(ints);
exports.byteArrayFromIntArrayUnsafe = ints => new Uint8Array(ints);

exports.byteArrayFromIntArray_ = nothing => just => ints => {
if (ints.every(i => i < 256 && i >= 0)) {
return just(new Uint8Array(ints));
} else {
return nothing;
}
};

exports.byteArrayToIntArray = bytes => Array.from(bytes);
38 changes: 24 additions & 14 deletions src/Types/ByteArray.purs
@@ -1,29 +1,30 @@
-- | Our domain type for byte arrays, a wrapper over Uint8Array.
module Types.ByteArray
( ByteArray (..)
, hexToByteArray
, byteArrayToHex
, hexToByteArrayUnsafe
, byteArrayFromIntArray
, byteArrayFromIntArrayUnsafe
, byteArrayToIntArray
, byteArrayToHex
, hexToByteArray
, hexToByteArrayUnsafe
)
where

import Data.ArrayBuffer.Types (Uint8Array)
import Data.Maybe (Maybe(..))
import Data.Ordering (Ordering(..))
import Prelude
import Data.ArrayBuffer.Types (Uint8Array)
import Test.QuickCheck.Arbitrary (class Arbitrary, arbitrary)

newtype ByteArray = ByteArray Uint8Array

instance showByteArray :: Show ByteArray where
show arr = "(byteArrayFromIntArray " <> show (byteArrayToIntArray arr) <> ")"
show arr = "(byteArrayFromIntArrayUnsafe " <> show (byteArrayToIntArray arr) <> ")"

instance eqByteArray :: Eq ByteArray where
eq a b = compare a b == EQ

instance ordByteArray :: Ord ByteArray where
compare = \xs ys -> compare 0 (ordImpl toDelta xs ys)
compare = \xs ys -> compare 0 (ord_ toDelta xs ys)
where
toDelta x y =
case compare x y of
Expand All @@ -32,28 +33,37 @@ instance ordByteArray :: Ord ByteArray where
GT -> -1

instance semigroupByteArray :: Semigroup ByteArray where
append = concatImpl
append = concat_

instance monoidByteArray :: Monoid ByteArray where
mempty = byteArrayFromIntArray []
mempty = byteArrayFromIntArrayUnsafe []

foreign import ordImpl :: forall a. (Int -> Int -> Int) -> ByteArray -> ByteArray -> Int
foreign import ord_ :: forall a. (Int -> Int -> Int) -> ByteArray -> ByteArray -> Int

foreign import concatImpl :: ByteArray -> ByteArray -> ByteArray
foreign import concat_ :: ByteArray -> ByteArray -> ByteArray

foreign import byteArrayToHex :: ByteArray -> String

foreign import hexToByteArrayImpl :: (forall a. Maybe a) -> (forall a. a -> Maybe a) -> String -> Maybe ByteArray
foreign import hexToByteArray_ :: (forall a. Maybe a) -> (forall a. a -> Maybe a) -> String -> Maybe ByteArray

-- | Input string must consist of hexademical numbers.
-- | Length of the input string must be even (2 characters per byte).
hexToByteArray :: String -> Maybe ByteArray
hexToByteArray = hexToByteArrayImpl Nothing Just
hexToByteArray = hexToByteArray_ Nothing Just

-- | Characters not in range will be converted to zero.
foreign import hexToByteArrayUnsafe :: String -> ByteArray

-- | Overflowing integers will be silently accepted modulo 256.
foreign import byteArrayFromIntArray :: Array Int -> ByteArray
foreign import byteArrayFromIntArrayUnsafe :: Array Int -> ByteArray

foreign import byteArrayFromIntArray_ :: (forall a. Maybe a) -> (forall a. a -> Maybe a) -> Array Int -> Maybe ByteArray

-- | A safer version of `byteArrayFromIntArrayUnsafe` that checks that elements are in range 0-255.
byteArrayFromIntArray :: Array Int -> Maybe ByteArray
byteArrayFromIntArray = byteArrayFromIntArray_ Nothing Just

foreign import byteArrayToIntArray :: ByteArray -> Array Int

instance arbitraryByteArray :: Arbitrary ByteArray where
arbitrary = byteArrayFromIntArrayUnsafe <$> arbitrary
9 changes: 4 additions & 5 deletions src/Types/Transaction.purs
@@ -1,14 +1,13 @@
module Types.Transaction where

import Prelude
import Data.ArrayBuffer.Types
import Data.BigInt as BigInt
import Data.Maybe (Maybe(..))
import Data.Tuple.Nested ((/\), type (/\))
import Data.Map (Map(..))
import Data.Maybe (Maybe)
import Data.Tuple.Nested (type (/\))
import Data.Map (Map)
import Data.Generic.Rep (class Generic)
import Data.Show.Generic (genericShow)
import Types.ByteArray
import Types.ByteArray (ByteArray)

newtype Transaction = Transaction {
body :: TxBody,
Expand Down
35 changes: 35 additions & 0 deletions test/ByteArray.purs
@@ -0,0 +1,35 @@
module Test.ByteArray where

import Prelude
import Data.Maybe (Maybe(Just))
import Effect.Class (liftEffect)
import Mote (group, test)
import Test.QuickCheck (quickCheck, (===))
import Test.QuickCheck.Laws.Data.Eq (checkEq)
import Test.QuickCheck.Laws.Data.Monoid (checkMonoid)
import Test.QuickCheck.Laws.Data.Ord (checkOrd)
import Test.QuickCheck.Laws.Data.Semigroup (checkSemigroup)
import TestM (TestPlanM)
import Type.Proxy (Proxy(..))
import Types.ByteArray (ByteArray, byteArrayFromIntArray, byteArrayFromIntArrayUnsafe, byteArrayToHex, byteArrayToIntArray, hexToByteArray)

suite :: TestPlanM Unit
suite = do
group "ByteArray" do
test "Eq instance" $ liftEffect do
checkEq (Proxy :: Proxy ByteArray)
test "Ord instance" $ liftEffect do
checkOrd (Proxy :: Proxy ByteArray)
test "Semigroup instance" $ liftEffect do
checkSemigroup (Proxy :: Proxy ByteArray)
test "Monoid instance" $ liftEffect do
checkMonoid (Proxy :: Proxy ByteArray)
test "hexToByteArray <<< byteArrayToHex = Just" $ liftEffect do
quickCheck \bytes ->
hexToByteArray (byteArrayToHex bytes) === Just bytes
test "byteArrayFromIntArrayUnsafe <<< byteArrayToIntArray = id" $ liftEffect do
quickCheck \bytes ->
byteArrayFromIntArrayUnsafe (byteArrayToIntArray bytes) === bytes
test "byteArrayFromIntArray <<< byteArrayToIntArray = Just" $ liftEffect do
quickCheck \bytes ->
byteArrayFromIntArray (byteArrayToIntArray bytes) === Just bytes
2 changes: 2 additions & 0 deletions test/Main.purs
Expand Up @@ -10,6 +10,7 @@ import Test.Spec (Spec, describe, it)
import Test.Spec.Runner (runSpec)
import Test.Spec.Reporter (consoleReporter)
import Test.AffInterface as AffInterface
import Test.ByteArray as ByteArrayTest
import Test.Parser as ParseTest
import TestM (TestPlanM)
import Mote (Plan, foldPlan, planT)
Expand Down Expand Up @@ -41,3 +42,4 @@ testPlan :: TestPlanM Unit
testPlan = do
ParseTest.suite
AffInterface.suite
ByteArrayTest.suite

0 comments on commit 6b093a6

Please sign in to comment.