| -- Licensed to the Apache Software Foundation (ASF) under one |
| -- or more contributor license agreements. See the NOTICE file |
| -- distributed with this work for additional information |
| -- regarding copyright ownership. The ASF licenses this file |
| -- to you under the Apache License, Version 2.0 (the |
| -- "License"); you may not use this file except in compliance |
| -- with the License. You may obtain a copy of the License at |
| -- |
| -- http://www.apache.org/licenses/LICENSE-2.0 |
| -- |
| -- Unless required by applicable law or agreed to in writing, |
| -- software distributed under the License is distributed on an |
| -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| -- KIND, either express or implied. See the License for the |
| -- specific language governing permissions and limitations |
| -- under the License. |
| |
| module BasicTest (basicTests) where |
| |
| import Control.Monad.IO.Class (MonadIO, liftIO) |
| import OpenDAL |
| import Test.Tasty |
| import Test.Tasty.HUnit |
| |
| basicTests :: TestTree |
| basicTests = |
| testGroup |
| "Basic Tests" |
| [ testCase "testBasicOperation" testRawOperation, |
| testCase "testMonad" testMonad, |
| testCase "testError" testError, |
| testCase "testWriter" testWriter, |
| testCase "testWriterAppend" testWriterAppend, |
| testCase "testAppendOperation" testAppendOperation, |
| testCase "testLister" testLister, |
| testCase "testCopyRename" testCopyRename, |
| testCase "testRemoveAll" testRemoveAll, |
| testCase "testOperatorInfo" testOperatorInfo |
| ] |
| |
| testRawOperation :: Assertion |
| testRawOperation = do |
| Right op <- newOperator "memory" |
| writeOpRaw op "key1" "value1" ?= Right () |
| writeOpRaw op "key2" "value2" ?= Right () |
| readOpRaw op "key1" ?= Right "value1" |
| readOpRaw op "key2" ?= Right "value2" |
| isExistOpRaw op "key1" ?= Right True |
| isExistOpRaw op "key2" ?= Right True |
| createDirOpRaw op "dir1/" ?= Right () |
| isExistOpRaw op "dir1/" ?= Right True |
| statOpRaw op "key1" >>= \case |
| Right meta -> meta @?= except_meta |
| Left _ -> assertFailure "should not reach here" |
| deleteOpRaw op "key1" ?= Right () |
| isExistOpRaw op "key1" ?= Right False |
| where |
| except_meta = |
| Metadata |
| { mMode = File, |
| mCacheControl = Nothing, |
| mContentDisposition = Nothing, |
| mContentLength = 6, |
| mContentMD5 = Nothing, |
| mContentType = Nothing, |
| mETag = Nothing, |
| mLastModified = Nothing |
| } |
| |
| testMonad :: Assertion |
| testMonad = do |
| Right op <- newOperator "memory" |
| runOp op operation ?= Right () |
| where |
| operation = do |
| writeOp "key1" "value1" |
| writeOp "key2" "value2" |
| readOp "key1" ?= "value1" |
| readOp "key2" ?= "value2" |
| isExistOp "key1" ?= True |
| isExistOp "key2" ?= True |
| createDirOp "dir1/" |
| isExistOp "dir1/" ?= True |
| statOp "key1" ?= except_meta |
| deleteOp "key1" |
| isExistOp "key1" ?= False |
| except_meta = |
| Metadata |
| { mMode = File, |
| mCacheControl = Nothing, |
| mContentDisposition = Nothing, |
| mContentLength = 6, |
| mContentMD5 = Nothing, |
| mContentType = Nothing, |
| mETag = Nothing, |
| mLastModified = Nothing |
| } |
| |
| testError :: Assertion |
| testError = do |
| Right op <- newOperator "memory" |
| runOp op operation >>= \case |
| Left err -> errorCode err @?= NotFound |
| Right _ -> assertFailure "should not reach here" |
| where |
| operation = readOp "non-exist-path" |
| |
| testWriter :: Assertion |
| testWriter = do |
| Right op <- newOperator "memory" |
| Right writer <- writerOpRaw op "test-writer-file" defaultWriterOption |
| writerWrite writer "Hello" ?= Right () |
| writerWrite writer " " ?= Right () |
| writerWrite writer "World!" ?= Right () |
| writerClose writer >>= \case |
| Right meta -> mContentLength meta @?= 12 |
| Left err -> assertFailure $ "Failed to close writer: " ++ show err |
| readOpRaw op "test-writer-file" ?= Right "Hello World!" |
| |
| testWriterAppend :: Assertion |
| testWriterAppend = do |
| Right op <- newOperator "memory" |
| -- First write some initial content |
| writeOpRaw op "append-file" "Initial content" ?= Right () |
| -- Create append writer and add more content |
| result <- writerOpRaw op "append-file" appendWriterOption |
| case result of |
| Right writer -> do |
| writerWrite writer " appended" ?= Right () |
| writerClose writer >>= \case |
| Right meta -> mContentLength meta @?= 24 |
| Left err -> assertFailure $ "Failed to close append writer: " ++ show err |
| readOpRaw op "append-file" ?= Right "Initial content appended" |
| Left err -> case errorCode err of |
| Unsupported -> putStrLn "Append writer not supported by memory backend - skipping" |
| _ -> assertFailure $ "Failed to create append writer: " ++ show err |
| |
| testAppendOperation :: Assertion |
| testAppendOperation = do |
| Right op <- newOperator "memory" |
| -- Write initial content |
| writeOpRaw op "append-test" "Hello" ?= Right () |
| -- Demonstrate append using writer API |
| result <- writerOpRaw op "append-test" appendWriterOption |
| case result of |
| Right writer -> do |
| writerWrite writer " World" ?= Right () |
| writerClose writer >>= \case |
| Right _ -> readOpRaw op "append-test" ?= Right "Hello World" |
| Left err -> assertFailure $ "Failed to close append writer: " ++ show err |
| Left err -> case errorCode err of |
| Unsupported -> do |
| putStrLn "Append writer not supported by memory backend - demonstrating manual append" |
| -- Manual append: read existing content, append new content, write back |
| Right existingContent <- readOpRaw op "append-test" |
| let newContent = existingContent <> " World" |
| writeOpRaw op "append-test" newContent ?= Right () |
| readOpRaw op "append-test" ?= Right "Hello World" |
| _ -> assertFailure $ "Failed to create append writer: " ++ show err |
| |
| testLister :: Assertion |
| testLister = do |
| Right op <- newOperator "memory" |
| -- Create some test files and directories |
| writeOpRaw op "dir1/file1.txt" "content1" ?= Right () |
| writeOpRaw op "dir1/file2.txt" "content2" ?= Right () |
| writeOpRaw op "dir1/subdir/file3.txt" "content3" ?= Right () |
| createDirOpRaw op "dir1/empty-dir/" ?= Right () |
| |
| -- Test listing |
| Right lister <- listOpRaw op "dir1/" |
| files <- collectListerItems lister |
| length files @?= 4 -- file1.txt, file2.txt, subdir/, empty-dir/ |
| |
| -- Test scanning (recursive) |
| Right scanner <- scanOpRaw op "dir1/" |
| allFiles <- collectListerItems scanner |
| length allFiles @?= 4 -- All files including nested ones |
| |
| testCopyRename :: Assertion |
| testCopyRename = do |
| Right op <- newOperator "memory" |
| -- Create source file |
| writeOpRaw op "source.txt" "test content" ?= Right () |
| -- Test copy - handle case where operation is not supported |
| copyResult <- copyOpRaw op "source.txt" "copy.txt" |
| case copyResult of |
| Right () -> do |
| readOpRaw op "copy.txt" ?= Right "test content" |
| isExistOpRaw op "source.txt" ?= Right True |
| Left err -> case errorCode err of |
| Unsupported -> putStrLn "Copy operation not supported by memory backend - skipping" |
| _ -> assertFailure $ "Unexpected error in copy: " ++ show err |
| |
| -- Test rename - handle case where operation is not supported |
| renameResult <- renameOpRaw op "source.txt" "renamed.txt" |
| case renameResult of |
| Right () -> do |
| readOpRaw op "renamed.txt" ?= Right "test content" |
| isExistOpRaw op "source.txt" ?= Right False |
| Left err -> case errorCode err of |
| Unsupported -> putStrLn "Rename operation not supported by memory backend - skipping" |
| _ -> assertFailure $ "Unexpected error in rename: " ++ show err |
| |
| testRemoveAll :: Assertion |
| testRemoveAll = do |
| Right op <- newOperator "memory" |
| -- Create directory structure |
| writeOpRaw op "remove-test/file1.txt" "content1" ?= Right () |
| writeOpRaw op "remove-test/subdir/file2.txt" "content2" ?= Right () |
| createDirOpRaw op "remove-test/empty/" ?= Right () |
| |
| -- Verify structure exists |
| isExistOpRaw op "remove-test/file1.txt" ?= Right True |
| isExistOpRaw op "remove-test/subdir/file2.txt" ?= Right True |
| |
| -- Remove all |
| removeAllOpRaw op "remove-test/" ?= Right () |
| |
| -- Verify everything is gone |
| isExistOpRaw op "remove-test/file1.txt" ?= Right False |
| isExistOpRaw op "remove-test/subdir/file2.txt" ?= Right False |
| isExistOpRaw op "remove-test/" ?= Right False |
| |
| testOperatorInfo :: Assertion |
| testOperatorInfo = do |
| Right op <- newOperator "memory" |
| operatorInfoRaw op ?= Right "memory" |
| |
| -- Helper function to collect all items from a lister |
| collectListerItems :: Lister -> IO [String] |
| collectListerItems lister = go [] |
| where |
| go acc = do |
| result <- nextLister lister |
| case result of |
| Right (Just item) -> go (item : acc) |
| Right Nothing -> return $ reverse acc |
| Left err -> assertFailure $ "Lister error: " ++ show err |
| |
| -- helper function |
| |
| (?=) :: (MonadIO m, Eq a, Show a) => m a -> a -> m () |
| result ?= except = result >>= liftIO . (@?= except) |