diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,7 @@
+# 0.4.0.0, 2018-11-24
+- ported to multilinear-0.4.0.0
+- added more robust tests
+
 # 0.3.0.0, 2018-11-14
 - ported to multilinear-0.3.0.0
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,9 +1,4 @@
-# README
-
-## Build status
-- Travis (Linux, macOS): [![Build Status](https://travis-ci.org/ArturB/multilinear-io.svg?branch=master)](https://travis-ci.org/ArturB/multilinear-io)
-- AppVeyor (Windows): [![Tests status](https://ci.appveyor.com/api/projects/status/github/ArturB/multilinear-io
-)](https://ci.appveyor.com/api/projects/status/github/ArturB/multilinear-io)
+# multilinear-io [![Hackage](https://img.shields.io/hackage/v/multilinear-io.svg)](https://hackage.haskell.org/package/multilinear-io) [![Build Status](https://travis-ci.org/ArturB/multilinear-io.svg?branch=master)](https://travis-ci.org/ArturB/multilinear-io) 
 
 ## Summary
 This package provides conduit-based input/output capability for [Multilinear](https://github.com/ArturB/multilinear) package, in various formats:
diff --git a/multilinear-io.cabal b/multilinear-io.cabal
--- a/multilinear-io.cabal
+++ b/multilinear-io.cabal
@@ -2,12 +2,12 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 86b14a55f0044713d22b5d0d065b6241e7d37686463ad116dde83c012791e38b
+-- hash: e8f399289e551ae39e7efffa83e1b8f92a5cb52d1d5f332879287e1a14387be1
 
 name:           multilinear-io
-version:        0.3.0.0
-synopsis:       Input/output capability for multilinear package.
-description:    Input & output capability for multilinear package <https://hackage.haskell.org/package/multilinear>. Supports various file formats: binary, CSV, JSON. More information available on GitHub: <https://github.com/ArturB/multilinear-io#readme>
+version:        0.4.0.0
+synopsis:       Conduit-vased input/output capability for multilinear package.
+description:    Conduit-based input & output capability for multilinear package <https://hackage.haskell.org/package/multilinear>. Supports various file formats: binary, CSV, JSON. More information available on GitHub: <https://github.com/ArturB/multilinear-io#readme>
 category:       Machine learning
 homepage:       https://github.com/ArturB/multilinear-io#readme
 bug-reports:    https://github.com/ArturB/multilinear-io/issues
@@ -30,7 +30,6 @@
   exposed-modules:
       Multilinear.Generic.Serialize
       Multilinear.Index.Finite.Serialize
-      Multilinear.Index.Infinite.Serialize
   other-modules:
       Paths_multilinear_io
   hs-source-dirs:
diff --git a/src/Multilinear/Generic/Serialize.hs b/src/Multilinear/Generic/Serialize.hs
--- a/src/Multilinear/Generic/Serialize.hs
+++ b/src/Multilinear/Generic/Serialize.hs
@@ -37,7 +37,6 @@
 import           Multilinear.Generic
 import qualified Multilinear.Index.Finite   as Finite
 import           Multilinear.Index.Finite.Serialize ()
-import           Multilinear.Index.Infinite.Serialize ()
 
 -- Binary serialization instance
 instance (Serialize a, Unboxed.Unbox a) => Serialize (Tensor a)
diff --git a/src/Multilinear/Index/Infinite/Serialize.hs b/src/Multilinear/Index/Infinite/Serialize.hs
deleted file mode 100644
--- a/src/Multilinear/Index/Infinite/Serialize.hs
+++ /dev/null
@@ -1,27 +0,0 @@
-{-|
-Module      : Multilinear.Index.Infinite.Serialize
-Description : Infinite-dimensional tensor index serialization: binary, JSON. 
-Copyright   : (c) Artur M. Brodzki, 2018
-License     : BSD3
-Maintainer  : artur@brodzki.org
-Stability   : experimental
-Portability : Windows/POSIX
-
-Infinite-dimensional tensor index.
-
--}
-
-module Multilinear.Index.Infinite.Serialize (
-    Index(..)
-) where
-
-import           Data.Aeson
-import           Data.Serialize
-import           Multilinear.Index.Infinite
-
-{-| Binary serialization and deserialization |-}
-instance Serialize Index
-
-{-| Serialization to and from JSON |-}
-instance FromJSON Index
-instance   ToJSON Index
diff --git a/test/csv/Spec.hs b/test/csv/Spec.hs
--- a/test/csv/Spec.hs
+++ b/test/csv/Spec.hs
@@ -10,17 +10,71 @@
 import           Multilinear.Generic.Serialize
 import           Multilinear.Index
 import qualified Multilinear.Matrix         as Matrix
+import qualified Multilinear.Vector         as Vector
 import           System.Directory
 
-fileName1 :: String
-fileName1  = "test/m1"
+matrix :: Tensor Double
+matrix = Matrix.fromIndices "ij" 50 50 $ \i j -> cos (fromIntegral i) + sin (fromIntegral j)
 
-m1 :: Tensor Double
-m1 = Matrix.fromIndices "ij" 50 50 $ \i j -> cos (fromIntegral i) + sin (fromIntegral j)
+vector :: Tensor Double
+vector = Vector.fromIndices "i" 50 $ \i -> cos (fromIntegral i)
 
+form :: Tensor Double
+form = Vector.fromIndices "i" 50 $ \i -> cos (fromIntegral i)
+
+scalar :: Tensor Double
+scalar = Scalar 5.0
+
+writeScalarCSV :: Tensor Double -> String -> IO ()
+writeScalarCSV m fileName = do
+  putStrLn $ "Writing scalar to " ++ fileName ++ ".csv..."
+  m `toCSVFile` (fileName ++ ".csv")
+  putStrLn "Scalar successfully written!"
+
+readScalarCSV :: Tensor Double -> String -> ExceptT String IO ()
+readScalarCSV m fileName = do
+  lift $ putStrLn $ "Reading scalar s1 from " ++ fileName ++ ".csv..."
+  (m1' :: Tensor Double) <- fromCSVFile (fileName ++ ".csv") ',' "ij"
+  if m1' == m then
+    lift $ putStrLn "Scalar successfully read!"
+  else
+    ExceptT $ return $ Left "Scalar deserialization error"
+
+writeVectorCSV :: Tensor Double -> String -> IO ()
+writeVectorCSV m fileName = do
+  let size = fromJust . indexSize <$> head $ indices m
+  putStrLn $ "Writing " ++ show size ++ " elements vector to " ++ fileName ++ ".csv..."
+  m `toCSVFile` (fileName ++ ".csv")
+  putStrLn "Vector successfully written!"
+
+readVectorCSV :: Tensor Double -> String -> ExceptT String IO ()
+readVectorCSV m fileName = do
+  lift $ putStrLn $ "Reading vector v1 from " ++ fileName ++ ".csv..."
+  (m1' :: Tensor Double) <- fromCSVFile (fileName ++ ".csv") ',' "ij"
+  if m1' == m then
+    lift $ putStrLn "Vector successfully read!"
+  else
+    ExceptT $ return $ Left "Vector deserialization error"
+
+writeFormCSV :: Tensor Double -> String -> IO ()
+writeFormCSV m fileName = do
+  let size = fromJust . indexSize <$> head $ indices m
+  putStrLn $ "Writing " ++ show size ++ " elements form to " ++ fileName ++ ".csv..."
+  m `toCSVFile` (fileName ++ ".csv")
+  putStrLn "Form successfully written!"
+
+readFormCSV :: Tensor Double -> String -> ExceptT String IO ()
+readFormCSV m fileName = do
+  lift $ putStrLn $ "Reading form f1 from " ++ fileName ++ ".csv..."
+  (m1' :: Tensor Double) <- fromCSVFile (fileName ++ ".csv") ',' "ij"
+  if m1' == m then
+    lift $ putStrLn "Form successfully read!"
+  else
+    ExceptT $ return $ Left "Form deserialization error"
+
 writeMatrixCSV :: Tensor Double -> String -> IO ()
 writeMatrixCSV m fileName = do
-  let [xsize,ysize] = indexSize <$> indices m1
+  let [xsize,ysize] = indexSize <$> indices m
   putStrLn $ "Writing " ++ show (fromJust xsize) ++ "x" ++ show (fromJust ysize) ++ " matrix to " ++ fileName ++ ".csv..."
   m `toCSVFile` (fileName ++ ".csv")
   putStrLn "Matrix successfully written!"
@@ -34,10 +88,25 @@
   else
     ExceptT $ return $ Left "Matrix deserialization error"
 
+  
 -- ENTRY POINT
 main :: IO ()
 main = do
-  writeMatrixCSV m1 fileName1
-  runExceptT $ readMatrixCSV m1 fileName1
-  removeFile $ fileName1 ++ ".csv"
+  -- Scalar CSV read/write
+  writeScalarCSV scalar "test/s1"
+  runExceptT $ readScalarCSV scalar "test/s1"
+  -- Vector CSV read/write
+  writeVectorCSV vector "test/v1"
+  runExceptT $ readVectorCSV vector "test/v1"
+  -- Form CSV read/write
+  writeFormCSV form "test/f1"
+  runExceptT $ readFormCSV form "test/f1"
+  -- Matrix CSV read/write
+  writeMatrixCSV matrix "test/m1"
+  runExceptT $ readMatrixCSV matrix "test/m1"
+  -- Remove test file
+  removeFile "test/s1.csv"
+  removeFile "test/v1.csv"
+  removeFile "test/f1.csv"
+  removeFile "test/m1.csv"
   return ()
