packages feed

cobot-io-0.1.4.2: test/SequenceSpec.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}

module SequenceSpec where

import qualified Data.List.NonEmpty as NE (fromList)
import           Data.Text          (Text)
import           Prelude            hiding (drop, reverse, tail, take)
import           Test.Hspec

import Bio.Sequence               (BareSequence, IsMarking, IsWeight (..), MarkedSequence,
                                   Range (..), Sequence, WeightedSequence, addMarkings,
                                   bareSequence, createSequence, drop, getMarking, getRange,
                                   getWeight, markedSequence, mean, meanInRange, preciseSpan,
                                   reverse, tail, take, toMarked, toWeighted, unsafeCreateSequence,
                                   unsafeMarkedSequence, unsafeWeightedSequence, weightedSequence)

instance IsWeight Int where
  toDouble = fromIntegral

type TestWeightedSequence = WeightedSequence Int Char

weightedSequenceSpec :: Spec
weightedSequenceSpec =
  describe "Weighted sequence" $ do
    it "successful creation of weighted sequence" $ do
      let seqE = weightedSequence ['a', 'b', 'c', 'd'] [1, 2, 3, 4] :: Either Text TestWeightedSequence
      seqE `shouldBe` Right (unsafeWeightedSequence ['a', 'b', 'c', 'd'] [1, 2, 3, 4])

    it "unsuccessful creation of weighted sequence" $ do
      let seqErr  = Left "Bio.Sequence.Class: sequence and weights have different lengths."
      let seqErr1 = Left "Bio.Sequence.Class: weights are null for sequence."

      let seqE = weightedSequence ['a', 'b', 'c', 'd'] [1, 2, 4] :: Either Text TestWeightedSequence
      seqE `shouldBe` seqErr

      let seqE = weightedSequence ['a', 'b', 'c', 'd'] [] :: Either Text TestWeightedSequence
      seqE `shouldBe` seqErr1

      let seqE = weightedSequence [] [1] :: Either Text TestWeightedSequence
      seqE `shouldBe` seqErr

      let seqE = weightedSequence [] [] :: Either Text TestWeightedSequence
      seqE `shouldBe` seqErr1

newtype TestMarking
  = TestMarking Text
  deriving (Eq, Show, Ord)

instance IsMarking TestMarking

type TestMarkedSequence = MarkedSequence TestMarking Char

markedSequenceSpec :: Spec
markedSequenceSpec =
  describe "Marked sequence" $ do
    it "successful creation of marked sequence" $ do
      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] :: Either Text TestMarkedSequence
      seqE `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))])

      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", preciseSpan (1, 4)), (TestMarking "a", preciseSpan (3, 4))] :: Either Text TestMarkedSequence
      seqE `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", preciseSpan (1, 4)), (TestMarking "a", preciseSpan (3, 4))])

      let seqE = markedSequence [] [] :: Either Text TestMarkedSequence
      seqE `shouldBe` Right (unsafeMarkedSequence [] [])

      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [] :: Either Text TestMarkedSequence
      seqE `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [])
    it "unsuccessful creation of marked sequence" $ do

      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", preciseSpan (-1, 0))] :: Either Text TestMarkedSequence
      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = -1}, _upper = RangeBorder {_borderType = Precise, _borderLocation = 0}}\n"

      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", preciseSpan (0, 5)), (TestMarking "a", preciseSpan (3, 4))] :: Either Text TestMarkedSequence
      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = 0}, _upper = RangeBorder {_borderType = Precise, _borderLocation = 5}}\n"

      let seqE = markedSequence ['a'] [(TestMarking "a", preciseSpan (0, -1))] :: Either Text TestMarkedSequence
      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = 0}, _upper = RangeBorder {_borderType = Precise, _borderLocation = -1}}\n" 

      let seqE = markedSequence [] [(TestMarking "k", Point 0)] :: Either Text TestMarkedSequence
      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nPoint {_location = 0}\n" 

type TestMarkedAndWeightedSequence = Sequence TestMarking Int Char

markedAndWeightedSequenceSpec :: Spec
markedAndWeightedSequenceSpec =
  describe "Marked and weighted sequence" $ do
    it "successful creation of marked and weighted sequence" $ do
      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence
      seqE `shouldBe` Right (unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 5])

    it "unsuccessful creation of marked and weighted sequence" $ do

      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", preciseSpan (-1, 0))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence
      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = -1}, _upper = RangeBorder {_borderType = Precise, _borderLocation = 0}}\n" 

      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", preciseSpan (0, 5)), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence
      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = 0}, _upper = RangeBorder {_borderType = Precise, _borderLocation = 5}}\n" 

      let seqE = createSequence ['a'] [(TestMarking "a", preciseSpan (0, -1))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence
      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = 0}, _upper = RangeBorder {_borderType = Precise, _borderLocation = -1}}\n" 

      let seqE = createSequence [] [(TestMarking "k", Point 0)] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence
      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nPoint {_location = 0}\n" 

      let seqE = createSequence ['a', 'b', 'c', 'd'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2, 4] :: Either Text TestMarkedAndWeightedSequence
      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = 3}, _upper = RangeBorder {_borderType = Precise, _borderLocation = 4}}\n" 

      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence
      seqE `shouldBe` Right (unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [] [1, 2.. 5])

      let seqErr1 = Left "Bio.Sequence.Class: sequence and weights have different lengths."

      let seqE = createSequence ['a', 'b', 'c', 'd'] [(TestMarking "a", Point 0), (TestMarking "a", Point 3)] [1, 2] :: Either Text TestMarkedAndWeightedSequence
      seqE `shouldBe` seqErr1

      let seqErr2 = Left "Bio.Sequence.Class: weights are null for sequence."

      let seqE = createSequence ['a', 'b', 'c', 'd'] [(TestMarking "a", Point 0), (TestMarking "a", Point 3)] [] :: Either Text TestMarkedAndWeightedSequence
      seqE `shouldBe` seqErr2

functionsSpec :: Spec
functionsSpec =
  describe "Sequence functions" $ do
    -- common 'IsSequence' functions
    getRangeSpec
    reverseSpec
    dropSpec
    takeSpec
    tailSpec

    -- 'Marking functions
    getMarkingSpec
    toMarkedSpec
    addMarkingsSpec

    -- 'Weight' functions
    meanAndMeanInRangeSpec
    getWeightSpec
    toWeightedSpec

getRangeSpec :: Spec
getRangeSpec =
  describe "getRange" $ do
    let getRangeError = Left "Bio.Sequence.Functions.Sequence: invalid range in getRange."
    let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 5] :: TestMarkedAndWeightedSequence

    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: 0" $ do
      getRange s (Point 0) `shouldBe` Right ['a']
    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (2, 4)" $ do
      getRange s (preciseSpan (2, 4)) `shouldBe` Right ['c', 'a', 'a']
    it "sequence: ['a', 'b', 'c', 'a', 'a', 'd', 'e']; range: (5, 6)" $ do
      let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a', 'd', 'e'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 7] :: TestMarkedAndWeightedSequence
      getRange s (preciseSpan (5, 6)) `shouldBe` Right ['d', 'e']
    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (0, -1)" $ do
      getRange s (preciseSpan (0, -1)) `shouldBe` getRangeError
    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (3, 7)" $ do
      getRange s (preciseSpan (3, 7)) `shouldBe` getRangeError

reverseSpec :: Spec
reverseSpec =
  describe "reverse" $ do
    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; weights: [1, 2.. 5]" $ do
      let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 5] :: TestMarkedAndWeightedSequence
      reverse s `shouldBe` unsafeCreateSequence ['a', 'a', 'c', 'b', 'a'] [(TestMarking "a", Point 4), (TestMarking "a", preciseSpan (0, 1))] [5, 4.. 1]
    it "sequence: ['a', 'b']; markings: []; weights: [1, 2]" $ do
      let s = unsafeWeightedSequence ['a', 'b'] [1, 2] :: TestWeightedSequence
      reverse s `shouldBe` unsafeWeightedSequence ['b', 'a'] [2, 1]
    it "sequence: ['a', 'b', 'c', 'd', 'e']; markings: [(abc, (0, 3)), (abcd, (0, 4)), (de, (3, 5)), (abcde, (0, 5))]; weights: []" $ do
      let s = unsafeMarkedSequence ['a', 'b', 'c', 'd', 'e'] [(TestMarking "abc", preciseSpan (0, 2)), (TestMarking "abcd", preciseSpan (0, 3)), (TestMarking "de", preciseSpan (3, 4)), (TestMarking "abcde", preciseSpan (0, 4))] :: TestMarkedSequence
      reverse s `shouldBe` unsafeMarkedSequence ['e', 'd', 'c', 'b', 'a'] [(TestMarking "abc", preciseSpan (2, 4)), (TestMarking "abcd", preciseSpan (1, 4)), (TestMarking "de", preciseSpan (0, 1)), (TestMarking "abcde", preciseSpan (0, 4))]

dropSpec :: Spec
dropSpec =
  describe "drop" $ do
    let s  = unsafeWeightedSequence ['a', 'b', 'c', 'a', 'a'] [1.. 5] :: TestWeightedSequence
    let sB = bareSequence ['a', 'b', 'c', 'a', 'a'] :: TestBareSequence

    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; drop: 2" $ do
      drop 2 s `shouldBe` unsafeWeightedSequence ['c', 'a', 'a'] [3.. 5]
    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; drop: 4" $ do
      drop 4 s `shouldBe` unsafeWeightedSequence ['a'] [5]
    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; drop: 4" $ do
      drop 0 s `shouldBe` s
    it "sequence: ['a', 'b', 'c', 'a', 'a']; drop: 2" $ do
      drop 2 sB `shouldBe` bareSequence ['c', 'a', 'a']

takeSpec :: Spec
takeSpec =
  describe "take" $ do
    let s = unsafeWeightedSequence ['a', 'b', 'c', 'a', 'a'] [1.. 5] :: TestWeightedSequence

    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; take: 2" $ do
      take 2 s `shouldBe` unsafeWeightedSequence ['a', 'b'] [1.. 2]
    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; take: 8" $ do
      take 8 s `shouldBe` s

tailSpec :: Spec
tailSpec =
  describe "tail" $ do
    let s = unsafeWeightedSequence ['a', 'b', 'c', 'a', 'a'] [1.. 5] :: TestWeightedSequence

    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]" $ do
      tail s `shouldBe` unsafeWeightedSequence ['b', 'c', 'a', 'a'] [2.. 5]
    it "sequence: ['b', 'c', 'a', 'a']; weights: [2.. 5]" $ do
      tail (tail s) `shouldBe` unsafeWeightedSequence ['c', 'a', 'a'] [3.. 5]
    it "sequence: [c', 'a', 'a']; weights: [3.. 5]" $ do
      tail (tail (tail s)) `shouldBe` unsafeWeightedSequence ['a', 'a'] [4.. 5]
    it "sequence: [a', 'a']; weights: [4.. 5]" $ do
      tail (tail (tail (tail s))) `shouldBe` unsafeWeightedSequence ['a'] [5]

getMarkingSpec :: Spec
getMarkingSpec =
  describe "getMarking" $ do
    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, 0), (a, (3, 4))]; get: a" $ do
      let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 5] :: TestMarkedAndWeightedSequence
      getMarking s (TestMarking "a") `shouldBe` Right (NE.fromList [['a'], ['a', 'a']])
    it "sequence: ['a', 'b', 'c', 'd', 'e']; markings: [(abc, (0, 3)), (abcd, (0, 4)), (de, (3, 5)), (abcde, (0, 5))]; get: abcde" $ do
      let s = unsafeMarkedSequence ['a', 'b', 'c', 'd', 'e'] [(TestMarking "abc", preciseSpan (0, 2)), (TestMarking "abcd", preciseSpan (0, 3)), (TestMarking "de", preciseSpan (3, 4)), (TestMarking "abcde", preciseSpan (0, 4))] :: TestMarkedSequence
      getMarking s (TestMarking "abcde") `shouldBe` Right (NE.fromList [['a', 'b', 'c', 'd', 'e']])

type TestBareSequence = BareSequence Char

toMarkedSpec :: Spec
toMarkedSpec =
  describe "toMarked" $ do
    let s = bareSequence ['a', 'b', 'c', 'a', 'a'] :: TestBareSequence

    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]" $ do
      (toMarked s [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] :: Either Text TestMarkedSequence) `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))])
    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 6)), (a, (3, 5))]" $ do
      let rangesError = Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = 0}, _upper = RangeBorder {_borderType = Precise, _borderLocation = 5}}\n" 
      (toMarked s [(TestMarking "a", preciseSpan (0, 5)), (TestMarking "a", preciseSpan (3, 4))] :: Either Text TestMarkedSequence) `shouldBe` rangesError

addMarkingsSpec :: Spec
addMarkingsSpec =
  describe "addMarkings" $ do
    let s = unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] :: TestMarkedSequence
    let rangesError = Left "Bio.Sequence.Functions.Marking: can't add markings to Sequence, because some of them are out of range."

    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; add: [(b, (1, 2))]" $ do
      addMarkings s [(TestMarking "b", Point 1)] `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4)), (TestMarking "b", Point 1)])
    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; add: []" $ do
      addMarkings s [] `shouldBe` Right s
    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; add: [(b, (1, 2)), (c, (2, 3)), (abcaa, (0, 5))]" $ do
      addMarkings s [(TestMarking "b", Point 1), (TestMarking "c", Point 2), (TestMarking "abcaa", preciseSpan (0, 4))] `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4)), (TestMarking "b", Point 1), (TestMarking "c", Point 2), (TestMarking "abcaa", preciseSpan (0, 4))])
    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; add: [(b, (1, 2)), (c, (2, 3)), (abcaa, (0, 6))]" $ do
      addMarkings s [(TestMarking "b", Point 1), (TestMarking "c", Point 2), (TestMarking "abcaa",preciseSpan  (0, 5))] `shouldBe` rangesError

meanAndMeanInRangeSpec :: Spec
meanAndMeanInRangeSpec =
  describe "mean and meanInRange" $ do
    let s = unsafeWeightedSequence ['a', 'b', 'c', 'a', 'a'] [1.. 5] :: TestWeightedSequence

    it "mean for sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]" $ do
      mean s `shouldBe` 3
    it "meanInRange for sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; range: (2, 4)" $ do
      meanInRange s (2, 4) `shouldBe` 4
    it "meanInRange for sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; range: (0, 5)" $ do
      meanInRange s (0, 5) `shouldBe` 3
    it "meanInRange for sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; range: (0, 0)" $ do
      meanInRange s (0, 0) `shouldBe` 1

getWeightSpec :: Spec
getWeightSpec =
  describe "getWeight" $ do
    let s = unsafeWeightedSequence ['a', 'b', 'c', 'a', 'a'] [1.. 5] :: TestWeightedSequence

    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; ind: 2" $ do
      getWeight s 2 `shouldBe` Right 3
    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; ind: 4" $ do
      getWeight s 4 `shouldBe` Right 5
    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; ind: 7" $ do
      getWeight s 7 `shouldBe` Left "Bio.Sequence.Functions.Weight: index out of range."

toWeightedSpec :: Spec
toWeightedSpec =
  describe "toWeighted" $ do
    let s = bareSequence ['a', 'b', 'c', 'a', 'a'] :: TestBareSequence

    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]" $ do
      (toWeighted s [1.. 5] :: Either Text TestWeightedSequence) `shouldBe` Right (unsafeWeightedSequence ['a', 'b', 'c', 'a', 'a'] [1.. 5])
    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 3]" $ do
      let rangesError = Left "Bio.Sequence.Class: sequence and weights have different lengths."
      (toWeighted s [1.. 3] :: Either Text TestWeightedSequence) `shouldBe` rangesError