content: -- 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 WriterTest (writerTests) where
  
  import Control.Monad.IO.Class (MonadIO, liftIO)
  import Data.ByteString.Char8 as BS8
  import OpenDAL
  import Test.Tasty
  import Test.Tasty.HUnit
  
  writerTests :: TestTree
  writerTests =
    testGroup
      "Writer Tests"
      [ testCase "testWriterSequentialWrites" testWriterSequentialWrites,
        testCase "testWriterLargeData" testWriterLargeData,
        testCase "testWriterEmptyData" testWriterEmptyData,
        testCase "testWriterBinaryData" testWriterBinaryData,
        testCase "testAppendToNonExistent" testAppendToNonExistent,
        testCase "testAppendMultipleTimes" testAppendMultipleTimes,
        testCase "testWriterErrorHandling" testWriterErrorHandling
      ]
  
  testWriterSequentialWrites :: Assertion
  testWriterSequentialWrites = do
    Right op <- newOperator "memory"
    Right writer <- writerOpRaw op "sequential-test" defaultWriterOption
    
    -- Write in multiple chunks
    writerWrite writer "Line 1\n" ?= Right ()
    writerWrite writer "Line 2\n" ?= Right ()
    writerWrite writer "Line 3\n" ?= Right ()
    
    Right meta <- writerClose writer
    mContentLength meta @?= 21
    
    -- Verify content
    readOpRaw op "sequential-test" ?= Right "Line 1\nLine 2\nLine 3\n"
  
  testWriterLargeData :: Assertion
  testWriterLargeData = do
    Right op <- newOperator "memory"
    Right writer <- writerOpRaw op "large-data-test" defaultWriterOption
    
    -- Write 1KB of data in chunks
    let chunk = BS8.replicate 100 'A'
    mapM_ (\_ -> writerWrite writer chunk ?= Right ()) [1..10 :: Int]
    
    Right meta <- writerClose writer
    mContentLength meta @?= 1000
    
    -- Verify first few bytes
    Right content <- readOpRaw op "large-data-test"
    BS8.take 10 content @?= "AAAAAAAAAA"
    BS8.length content @?= 1000
  
  testWriterEmptyData :: Assertion
  testWriterEmptyData = do
    Right op <- newOperator "memory"
    Right writer <- writerOpRaw op "empty-test" defaultWriterOption
    
    -- Write empty data
    writerWrite writer "" ?= Right ()
    
    Right meta <- writerClose writer
    mContentLength meta @?= 0
    
    -- Verify content
    readOpRaw op "empty-test" ?= Right ""
  
  testWriterBinaryData :: Assertion
  testWriterBinaryData = do
    Right op <- newOperator "memory"
    Right writer <- writerOpRaw op "binary-test" defaultWriterOption
    
    -- Write binary data (all bytes 0-255)
    let binaryData = BS8.pack ['\0'..'\255']
    writerWrite writer binaryData ?= Right ()
    
    Right meta <- writerClose writer
    mContentLength meta @?= 256
    
    -- Verify content
    Right content <- readOpRaw op "binary-test"
    content @?= binaryData
  
  testAppendToNonExistent :: Assertion
  testAppendToNonExistent = do
    Right op <- newOperator "memory"
    
    -- Verify file doesn't exist
    isExistOpRaw op "new-append-file" ?= Right False
    
    -- Write to non-existent file using writer API (should create it)
    Right writer <- writerOpRaw op "new-append-file" defaultWriterOption
    writerWrite writer "First content" ?= Right ()
    writerClose writer >>= \case
      Right _ -> return ()
      Left err -> assertFailure $ "Failed to close writer: " ++ show err
    
    -- Verify file was created
    isExistOpRaw op "new-append-file" ?= Right True
    readOpRaw op "new-append-file" ?= Right "First content"
  
  testAppendMultipleTimes :: Assertion
  testAppendMultipleTimes = do
    Right op <- newOperator "memory"
    
    -- Multiple write operations using writer API
    Right writer <- writerOpRaw op "multi-append" defaultWriterOption
    writerWrite writer "Hello" ?= Right ()
    writerWrite writer " " ?= Right ()
    writerWrite writer "World" ?= Right ()
    writerWrite writer "!" ?= Right ()
    writerClose writer >>= \case
      Right _ -> return ()
      Left err -> assertFailure $ "Failed to close writer: " ++ show err
    
    -- Verify final content
    readOpRaw op "multi-append" ?= Right "Hello World!"
  
  testWriterErrorHandling :: Assertion
  testWriterErrorHandling = do
    Right op <- newOperator "memory"
    
    -- Test writing to invalid path (should work with memory backend)
    -- Memory backend is permissive, so let's test a more complex scenario
    Right writer <- writerOpRaw op "test-file" defaultWriterOption
    writerWrite writer "some data" ?= Right ()
    
    -- Close writer successfully
    Right meta <- writerClose writer
    mContentLength meta @?= 9
  
  -- helper function
  
  (?=) :: (MonadIO m, Eq a, Show a) => m a -> a -> m ()
  result ?= except = result >>= liftIO . (@?= except) 