diff --git a/pandoc-plantuml-diagrams.cabal b/pandoc-plantuml-diagrams.cabal
--- a/pandoc-plantuml-diagrams.cabal
+++ b/pandoc-plantuml-diagrams.cabal
@@ -1,5 +1,5 @@
 name:                pandoc-plantuml-diagrams
-version:             0.1.0.3
+version:             0.1.0.4
 synopsis:            Render and insert PlantUML diagrams with Pandoc
 description:         PlantUML renders different types of UML diagrams.
                      This filter invokes plantuml.jar (which must be present
@@ -47,6 +47,17 @@
   Main-Is:             Spec.hs
   hs-source-dirs:      test, src
   default-language:    Haskell2010
+  other-modules:       Text.Pandoc.PlantUML.Filter
+                     , Text.Pandoc.PlantUML.Filter.IORender
+                     , Text.Pandoc.PlantUML.Filter.Types
+                     , Text.Pandoc.PlantUML.Filter.FileNameGenerator
+                     , Text.Pandoc.PlantUML.Filter.Formats
+                     , Text.Pandoc.PlantUML.Filter.OutputBlock
+                     , Text.Pandoc.PlantUML.Filter.FileNameGeneratorSpec
+                     , Text.Pandoc.PlantUML.Filter.FormatsSpec
+                     , Text.Pandoc.PlantUML.Filter.OutputBlockSpec
+                     , Text.Pandoc.PlantUML.Filter.TypesSpec
+                     , Text.Pandoc.PlantUML.FilterSpec
   Build-depends:       hspec
                      , hspec-discover
                      , base >= 4 && < 5
@@ -54,6 +65,9 @@
                      , pandoc-types
                      , SHA
                      , utf8-string
+                     , bytestring
+                     , process
+                     , directory
 
 source-repository head
   type:                git
diff --git a/src/Text/Pandoc/PlantUML/Filter/IORender.hs b/src/Text/Pandoc/PlantUML/Filter/IORender.hs
--- a/src/Text/Pandoc/PlantUML/Filter/IORender.hs
+++ b/src/Text/Pandoc/PlantUML/Filter/IORender.hs
@@ -1,4 +1,4 @@
-
+{-# LANGUAGE BangPatterns #-}
 -- | Module: Text.Pandoc.PlantUML.Filter.Render
 -- Defines the actual rendering done with PlantUML
 module Text.Pandoc.PlantUML.Filter.IORender() where
@@ -26,6 +26,6 @@
 
 pipe :: Handle -> Handle -> IO ()
 pipe hIn hOut = do
-  input <- hGetContents hIn
+  !input <- hGetContents hIn
   hPut hOut input
 
diff --git a/src/Text/Pandoc/PlantUML/Filter/OutputBlock.hs b/src/Text/Pandoc/PlantUML/Filter/OutputBlock.hs
--- a/src/Text/Pandoc/PlantUML/Filter/OutputBlock.hs
+++ b/src/Text/Pandoc/PlantUML/Filter/OutputBlock.hs
@@ -19,7 +19,7 @@
 resultBlock imageFileName attr = Para $ map (\p -> p imageFileName attr) [imageTag, idTag]
 
 imageTag :: ImageFileName -> Attr -> Inline
-imageTag imageFileName attr    = Image (altTagInline attr) ((show imageFileName), "fig:")
+imageTag imageFileName attr    = Image nullAttr (altTagInline attr) (show imageFileName, "fig:")
 
 idTag :: ImageFileName -> Attr -> Inline
 idTag _ (id, _, _)             = Str ("{#" ++ id ++ "}")
diff --git a/test/Text/Pandoc/PlantUML/Filter/FileNameGeneratorSpec.hs b/test/Text/Pandoc/PlantUML/Filter/FileNameGeneratorSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Text/Pandoc/PlantUML/Filter/FileNameGeneratorSpec.hs
@@ -0,0 +1,18 @@
+
+
+module Text.Pandoc.PlantUML.Filter.FileNameGeneratorSpec where
+
+import Test.Hspec
+import Text.Pandoc.PlantUML.Filter.FileNameGenerator
+import Text.Pandoc.PlantUML.Filter.Types
+
+spec :: Spec
+spec = do
+  describe "Text.Pandoc.PlantUML.Filter.FileNameGenerator" $ do
+    it "generates the correct name for an empty source" $ do
+      (fileNameForSource (DiagramSource "")) `shouldBe` ".rendered.da39a3ee5e6b4b0d3255bfef95601890afd80709"
+    it "generates the correct name for 'hello'" $ do
+      (fileNameForSource (DiagramSource "hello")) `shouldBe` ".rendered.aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"
+
+main :: IO ()
+main = hspec spec
diff --git a/test/Text/Pandoc/PlantUML/Filter/FormatsSpec.hs b/test/Text/Pandoc/PlantUML/Filter/FormatsSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Text/Pandoc/PlantUML/Filter/FormatsSpec.hs
@@ -0,0 +1,25 @@
+
+
+module Text.Pandoc.PlantUML.Filter.FormatsSpec where
+
+import Test.Hspec
+import Text.Pandoc.Definition
+import Text.Pandoc.PlantUML.Filter.Formats
+
+formatFor :: String -> String
+formatFor = imageFormatTypeFor . Format
+
+shouldBeFormattedAs :: String -> String -> Expectation
+shouldBeFormattedAs docFormat imageFormat = (imageFormatTypeFor (Format docFormat)) `shouldBe` imageFormat
+
+spec :: Spec
+spec = do
+  describe "Text.Pandoc.PlantUML.Filter.Formats" $ do
+    it "gives EPS for latex" $ do
+      "latex" `shouldBeFormattedAs` "eps"
+    it "gives PNG for html5" $ do
+      "html5" `shouldBeFormattedAs` "png"
+
+
+main :: IO ()
+main = hspec spec
diff --git a/test/Text/Pandoc/PlantUML/Filter/OutputBlockSpec.hs b/test/Text/Pandoc/PlantUML/Filter/OutputBlockSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Text/Pandoc/PlantUML/Filter/OutputBlockSpec.hs
@@ -0,0 +1,29 @@
+
+module Text.Pandoc.PlantUML.Filter.OutputBlockSpec where
+
+import Test.Hspec
+import Text.Pandoc.PlantUML.Filter.OutputBlock
+import Text.Pandoc.PlantUML.Filter.Types
+import Text.Pandoc.Definition
+
+-- resultBlock :: ImageFileName -> Attr -> Block
+
+spec :: Spec
+spec = do
+  describe "Text.Pandoc.PlantUML.Filter.OutputBlock" $ do
+    it "renders into a Paragraph containing an Image" $ do
+      let b = resultBlock (ImageFileName "asd" "png") ("id", [], [])
+      case b of
+        Para [(Image nullAttr _ (src, _)), _ ]   -> do
+          src `shouldBe` "asd.png"
+        otherwise                -> expectationFailure "should be an image in a paragraph"
+    it "renders into a Paragraph containing an ID tag" $ do
+      let b = resultBlock (ImageFileName "asd" "png") ("fig:id", [], [])
+      case b of
+        Para [_, (Str id) ]       -> do
+          id `shouldBe` "{#fig:id}"
+        otherwise                -> expectationFailure "should be an image in a paragraph"
+
+
+main :: IO()
+main = hspec spec
diff --git a/test/Text/Pandoc/PlantUML/Filter/TypesSpec.hs b/test/Text/Pandoc/PlantUML/Filter/TypesSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Text/Pandoc/PlantUML/Filter/TypesSpec.hs
@@ -0,0 +1,15 @@
+
+module Text.Pandoc.PlantUML.Filter.TypesSpec where
+
+import Test.Hspec
+import Text.Pandoc.PlantUML.Filter.Types
+
+spec :: Spec
+spec = do
+  describe "Text.Pandoc.PlantUML.Filter.Types" $ do
+    it "can show an image filename correctly" $ do
+      (show (ImageFileName "base" "eps")) `shouldBe` "base.eps"
+
+
+main :: IO ()
+main = hspec spec
diff --git a/test/Text/Pandoc/PlantUML/FilterSpec.hs b/test/Text/Pandoc/PlantUML/FilterSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Text/Pandoc/PlantUML/FilterSpec.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE FlexibleInstances #-}
+
+module Text.Pandoc.PlantUML.FilterSpec where
+
+import Test.Hspec
+import Text.Pandoc.Definition
+
+import Text.Pandoc.PlantUML.Filter.Types
+import Text.Pandoc.PlantUML.Filter.FileNameGenerator
+import Text.Pandoc.PlantUML.Filter
+import Control.Monad.State.Lazy as S
+
+type FakeImageIO = S.State WorldInfo
+
+data WorldInfo = WorldInfo {
+    renderedImages :: [(String, DiagramSource)]
+  , existingImages :: [String]
+}
+
+baseNameForDiagramAsd = fileNameForSource (DiagramSource "asd")
+baseNameForDiagramDsa = fileNameForSource (DiagramSource "dsa")
+
+def = WorldInfo [] []
+
+instance ImageIO (S.State WorldInfo) where
+  doesImageExist fileName     = do
+    st <- S.get
+    return $ (show fileName) `elem` (existingImages st)
+  renderImage fileName source = do
+    st <- S.get
+    let oldImages = renderedImages st
+    S.put st { renderedImages = ((show fileName), source) : oldImages}
+
+
+runProcessingIn :: WorldInfo -> String -> Block -> (Block, WorldInfo)
+runProcessingIn wi format block = S.runState (processBlocks (Just (Format format)) block) wi
+
+
+main :: IO ()
+main = hspec spec
+
+spec :: Spec
+spec = do
+  describe "Text.Pandoc.PlantUML.Filter" $ do
+    it "renders a diagram with some content" $ do
+      let (_, endState) = runProcessingIn def "manpage" (CodeBlock ("id", ["uml"], []) "dsa")
+      (renderedImages endState) `shouldBe` [(baseNameForDiagramDsa ++ ".png", (DiagramSource "dsa"))]
+    it "skips other blocks" $ do
+      let (_, endState) = runProcessingIn def "manpage" $ Para [Str "@startuml asd @enduml"]
+      (renderedImages endState) `shouldBe` []
+    it "doesn't re-render an already rendered diagram" $ do
+      let world = def { existingImages = [baseNameForDiagramAsd ++ ".eps"]}
+      let (_, endState) = runProcessingIn world "latex" $ (CodeBlock ("id", ["uml"], []) "asd")
+      (renderedImages endState) `shouldBe` []
+    it "rerenders a diagram for a different format" $ do
+      let world = def { existingImages = [baseNameForDiagramAsd ++ ".eps"]}
+      let (_, endState) = runProcessingIn world "html" $ (CodeBlock ("id", ["uml"], []) "asd")
+      (renderedImages endState) `shouldBe` [(baseNameForDiagramAsd ++ ".png", (DiagramSource "asd"))]
