packages feed

nbparts-0.1.0.0: tests/Tests/Integration/UnpackPackSpec.hs

{-# LANGUAGE DataKinds #-}

module Tests.Integration.UnpackPackSpec where

import Control.Monad.Except (runExceptT)
import Data.ByteString.Lazy qualified as LazyByteString
import Data.Either qualified as Either
import Data.Text (Text)
import Nbparts.Pack
  ( PackOptions
      ( PackOptions,
        force,
        outputPath,
        partsDirectory
      ),
  )
import Nbparts.Unpack
  ( UnpackOptions
      ( UnpackOptions,
        force,
        metadataFormat,
        notebookPath,
        outputPath,
        outputsFormat,
        sourcesFormat
      ),
  )
import Network.HTTP.Req
  ( GET (GET),
    NoReqBody (NoReqBody),
    Scheme (Https),
    Url,
    defaultHttpConfig,
    https,
    lbsResponse,
    req,
    responseBody,
    runReq,
    (/:),
  )
import System.FilePath ((</>))
import System.IO.Temp (withSystemTempDirectory)
import Test.Hspec
  ( Arg,
    Expectation,
    Spec,
    SpecWith,
    around,
    context,
    describe,
    it,
    shouldBe,
    shouldSatisfy,
  )
import Tests.Integration.Util
  ( UnpackFormats
      ( UnpackFormats,
        metadataFormat,
        outputsFormat,
        sourcesFormat
      ),
    fixtureDir,
    readIpynb,
    runPack,
    runSpecWithUnpackFormatsCA,
    runUnpack,
  )

testIdentityWith' :: UnpackFormats -> FilePath -> FilePath -> Expectation
testIdentityWith' (UnpackFormats {sourcesFormat, metadataFormat, outputsFormat}) nbPath tmpdir = do
  let unpackPath = tmpdir </> "unpacked"
  let repackPath = tmpdir </> "repacked.ipynb"

  unpackResult <-
    runExceptT $
      runUnpack $
        UnpackOptions
          { notebookPath = nbPath,
            sourcesFormat,
            metadataFormat,
            outputsFormat,
            outputPath = Just unpackPath,
            force = False
          }
  unpackResult `shouldSatisfy` Either.isRight

  packResult <-
    runExceptT $
      runPack $
        PackOptions
          { partsDirectory = unpackPath,
            outputPath = Just repackPath,
            force = False
          }
  packResult `shouldSatisfy` Either.isRight

  nb <- runExceptT $ readIpynb nbPath
  repackedNb <- runExceptT $ readIpynb repackPath
  repackedNb `shouldBe` nb

testNetIdentityWith' :: UnpackFormats -> Url scheme -> FilePath -> Expectation
testNetIdentityWith' unpackFormats url tmpdir = do
  lbs <- runReq defaultHttpConfig $ req GET url NoReqBody lbsResponse mempty
  let nbBytes = responseBody lbs

  let nbPath = tmpdir </> "nb.ipynb"
  LazyByteString.writeFile nbPath nbBytes

  testIdentityWith' unpackFormats nbPath tmpdir

testNetIdentityWith :: UnpackFormats -> Url scheme -> SpecWith (Arg (FilePath -> Expectation))
testNetIdentityWith unpackFormats url = it "is identity" $ testNetIdentityWith' unpackFormats url

testIdentityWith :: UnpackFormats -> FilePath -> SpecWith (Arg (FilePath -> Expectation))
testIdentityWith unpackFormats nbpath = it "is identity" $ testIdentityWith' unpackFormats nbpath

testFixtureIdentityWith :: UnpackFormats -> FilePath -> SpecWith (Arg (FilePath -> Expectation))
testFixtureIdentityWith unpackFormats fixture = testIdentityWith unpackFormats $ fixtureDir </> fixture

data GitHubReleaseFile = GitHubReleaseFile
  { owner :: Text,
    repo :: Text,
    tag :: Text,
    file :: Text
  }

mkGitHubReleaseFileUrl :: GitHubReleaseFile -> Url 'Https
mkGitHubReleaseFileUrl GitHubReleaseFile {owner, repo, tag, file} =
  https "github.com"
    /: owner
    /: repo
    /: "releases"
    /: "download"
    /: tag
    /: file

runTests :: UnpackFormats -> SpecWith FilePath
runTests unpackFormats = do
  let testFixtureIdentity = testFixtureIdentityWith unpackFormats
  let testNetIdentity = testNetIdentityWith unpackFormats

  context "when given an empty notebook (no sources, outputs or metadata)" $
    testFixtureIdentity "empty.ipynb"

  context "when given a notebook with erroneous outputs" $ do
    testFixtureIdentity "error-outputs.ipynb"

  context "when given a notebook with empty cells" $ do
    testFixtureIdentity "empty-cells.ipynb"

  context "when given a notebook containing the markdown spec" $
    testFixtureIdentity ("commonmark-spec" </> "commonmark-spec.ipynb")

  context "when given a notebook containing stream outputs" $
    testFixtureIdentity "stream-outputs.ipynb"

  context "when given a notebook containing image outputs" $
    testFixtureIdentity "image-outputs.ipynb"

  context "when given a notebook containing an interactive figure" $
    testFixtureIdentity "interactive-figure-outputs.ipynb"

  context "when given a notebook with raw cells" $ do
    testFixtureIdentity "raw-cells.ipynb"

  context "when given a notebook with latex" $ do
    testFixtureIdentity "latex.ipynb"

  context "when given a notebook containing markdown comments" $ do
    testFixtureIdentity "escape-markdown-comments.ipynb"

  context "when given a notebook with attachments" $
    testFixtureIdentity "attachments.ipynb"

  context "when given a notebook with duplicate attachments" $
    testFixtureIdentity "duplicate-attachments.ipynb"

  context "when given a notebook with a missing attachment" $
    testFixtureIdentity "missing-attachment.ipynb"

  context "when given a notebook containing attachments with unusual formatting" $
    testFixtureIdentity "attachments-unusual-formatting.ipynb"

  context "when given a notebook with an attachment that has multiple mime bundle entries" $
    testFixtureIdentity "attachments-multiple-mime-bundle-entries.ipynb"

  context "when given a notebook containing reference-link attachments" $
    testFixtureIdentity "attachments-reference.ipynb"

  context "when given a notebook containing reference-link attachments with unusual formatting" $
    testFixtureIdentity "attachments-reference-unusual-formatting.ipynb"

  context "when given a real-world notebook (mlp-vgg16-fashion.ipynb)" $
    testNetIdentity $
      mkGitHubReleaseFileUrl
        GitHubReleaseFile
          { owner = "dixslyf",
            repo = "mlp-vgg16-fashion",
            tag = "v1.0.0",
            file = "mlp-vgg16-fashion.ipynb"
          }

  context "when given a real-world notebook (unet-nuclei-instance-segmentation.ipynb)" $
    testNetIdentity $
      mkGitHubReleaseFileUrl
        GitHubReleaseFile
          { owner = "dixslyf",
            repo = "unet-nuclei-instance-segmentation",
            tag = "v1.0.0",
            file = "unet-nuclei-instance-segmentation.ipynb"
          }

spec :: Spec
spec = around (withSystemTempDirectory "test-nbparts") $ do
  describe "Unpack then pack" $ do
    runSpecWithUnpackFormatsCA runTests