diff --git a/MANUAL.txt b/MANUAL.txt
--- a/MANUAL.txt
+++ b/MANUAL.txt
@@ -1,7 +1,7 @@
 ---
 title: Pandoc User's Guide
 author: John MacFarlane
-date: October 30, 2021
+date: November 02, 2021
 ---
 
 # Synopsis
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,42 @@
 # Revision history for pandoc
 
+## pandoc 2.16.1 (2021-11-02)
+
+
+  * Docx reader:  don't let first line indents trigger block quotes (#7655).
+    This fixes a regression introduced in pandoc 2.15.
+
+  * Docx writer: use `getTimestamp` for modification times in
+    reference.docx (#7654).  This ensures that when `SOURCE_DATE_EPOCH` is
+    set, the modification times of files taken from the reference.docx will
+    be set deterministically, allowing for reproducible builds.
+
+  * Lua subsystem (Albert Krewinkel):
+
+    + Load module `pandoc.path` on startup (#7524).  Previously the module
+      always had to be loaded via `require 'pandoc.path'`.
+    + Fix typo in SoftBreak constructor.
+    + Re-add `content` property to Strikeout elements.
+      Fixes a regression introduced in 2.15.
+    + Be more forgiving when retrieving the Image `caption` property.
+      Fixes a regression introduced in 2.15.
+    + Display Attr values using their native Haskell representation.
+    + Allow omitting the 2nd parameter in pandoc.Code constructor.
+      Fixes a regression introduced in 2.15 which required users to always
+      specify an Attr value when constructing a Code element.
+    + Allow to compare, show Citation values.  Comparisons of Citation
+      values are performed in Haskell; values are equal if they represent
+      the same Haskell value. Converting a Citation value to a string
+      now yields its native Haskell string representation.
+    + Restore List behavior of MetaList (#7650).  Fixes a regression
+      introduced in 2.16 which had MetaList elements lose
+      the `pandoc.List` properties.
+    + Restore `content` property on Header elements.
+    + Ensure Block elements have all expected properties.
+    + Ensure Inline elements have all expected properties.
+
+  * Allow tasty-bench 0.3.x.
+
 ## pandoc 2.16 (2021-10-31)
 
   * Switch back from HsYAML to yaml for parsing YAML metadata (#6084).
diff --git a/data/pandoc.lua b/data/pandoc.lua
--- a/data/pandoc.lua
+++ b/data/pandoc.lua
@@ -27,6 +27,7 @@
 -- Re-export bundled modules
 M.List = require 'pandoc.List'
 M.mediabag = require 'pandoc.mediabag'
+M.path = require 'pandoc.path'
 M.system = require 'pandoc.system'
 M.types = require 'pandoc.types'
 M.utils = require 'pandoc.utils'
@@ -55,6 +56,7 @@
     if k == "t" then
       return getmetatable(t)["tag"]
     end
+    return getmetatable(t)[k]
   end
   behavior.__pairs = function (t)
     return next, t
diff --git a/man/pandoc.1 b/man/pandoc.1
--- a/man/pandoc.1
+++ b/man/pandoc.1
@@ -1,7 +1,7 @@
 '\" t
 .\" Automatically generated by Pandoc 2.16
 .\"
-.TH "Pandoc User\[cq]s Guide" "" "October 30, 2021" "pandoc 2.16" ""
+.TH "Pandoc User\[cq]s Guide" "" "November 02, 2021" "pandoc 2.16.1" ""
 .hy
 .SH NAME
 pandoc - general markup converter
diff --git a/pandoc.cabal b/pandoc.cabal
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -1,6 +1,6 @@
 cabal-version:   2.2
 name:            pandoc
-version:         2.16
+version:         2.16.1
 build-type:      Simple
 license:         GPL-2.0-or-later
 license-file:    COPYING.md
@@ -926,7 +926,7 @@
   build-depends:   bytestring,
                    containers,
                    -- gauge       >= 0.2     && < 0.3,
-                   tasty-bench >= 0.2     && <= 0.3,
+                   tasty-bench >= 0.2     && <= 0.4,
                    mtl         >= 2.2     && < 2.3,
                    text        >= 1.1.1.0 && < 1.3,
                    time,
diff --git a/src/Text/Pandoc/Class/PandocMonad.hs b/src/Text/Pandoc/Class/PandocMonad.hs
--- a/src/Text/Pandoc/Class/PandocMonad.hs
+++ b/src/Text/Pandoc/Class/PandocMonad.hs
@@ -454,7 +454,7 @@
                "word/theme/theme1.xml"]
   let toLazy = BL.fromChunks . (:[])
   let pathToEntry path = do
-        epochtime <- floor . utcTimeToPOSIXSeconds <$> getCurrentTime
+        epochtime <- floor . utcTimeToPOSIXSeconds <$> getTimestamp
         contents <- toLazy <$> readDataFile ("docx/" ++ path)
         return $ toEntry path epochtime contents
   datadir <- getUserDataDir
diff --git a/src/Text/Pandoc/Lua/Marshaling/AST.hs b/src/Text/Pandoc/Lua/Marshaling/AST.hs
--- a/src/Text/Pandoc/Lua/Marshaling/AST.hs
+++ b/src/Text/Pandoc/Lua/Marshaling/AST.hs
@@ -111,7 +111,18 @@
   push = pushBlock
 
 typeCitation :: LuaError e => DocumentedType e Citation
-typeCitation = deftype "Citation" []
+typeCitation = deftype "Citation"
+  [ operation Eq $ lambda
+    ### liftPure2 (==)
+    <#> parameter (optional . peekCitation) "Citation" "a" ""
+    <#> parameter (optional . peekCitation) "Citation" "b" ""
+    =#> functionResult pushBool "boolean" "true iff the citations are equal"
+
+  , operation Tostring $ lambda
+    ### liftPure show
+    <#> parameter peekCitation "Citation" "citation" ""
+    =#> functionResult pushString "string" "native Haskell representation"
+  ]
   [ property "id" "citation ID / key"
       (pushText, citationId)
       (peekText, \citation cid -> citation{ citationId = cid })
@@ -340,6 +351,7 @@
   -- inline content
   Para inlns          -> Actual $ ContentInlines inlns
   Plain inlns         -> Actual $ ContentInlines inlns
+  Header _ _ inlns    -> Actual $ ContentInlines inlns
   -- inline content
   BlockQuote blks     -> Actual $ ContentBlocks blks
   Div _ blks          -> Actual $ ContentBlocks blks
@@ -357,6 +369,7 @@
   -- inline content
   Para _           -> Actual . Para . inlineContent
   Plain _          -> Actual . Plain . inlineContent
+  Header attr lvl _ -> Actual . Header attr lvl . inlineContent
   -- block content
   BlockQuote _     -> Actual . BlockQuote . blockContent
   Div attr _       -> Actual . Div attr . blockContent
@@ -612,6 +625,7 @@
   Quoted qt _   -> Actual . Quoted qt . inlineContent
   SmallCaps _   -> Actual . SmallCaps . inlineContent
   Span attr _   -> Actual . Span attr . inlineContent
+  Strikeout _   -> Actual . Strikeout . inlineContent
   Strong _      -> Actual . Strong . inlineContent
   Subscript _   -> Actual . Subscript . inlineContent
   Superscript _ -> Actual . Superscript . inlineContent
@@ -638,6 +652,7 @@
   Quoted _ inlns    -> Actual $ ContentInlines inlns
   SmallCaps inlns   -> Actual $ ContentInlines inlns
   Span _ inlns      -> Actual $ ContentInlines inlns
+  Strikeout inlns   -> Actual $ ContentInlines inlns
   Strong inlns      -> Actual $ ContentInlines inlns
   Subscript inlns   -> Actual $ ContentInlines inlns
   Superscript inlns -> Actual $ ContentInlines inlns
@@ -697,7 +712,7 @@
       (pushPandocList pushInline, \case
           Image _ capt _ -> Actual capt
           _              -> Absent)
-      (peekInlines, \case
+      (peekInlinesFuzzy, \case
           Image attr _ target -> Actual . (\capt -> Image attr capt target)
           _                   -> const Absent)
   , possibleProperty "citations" "list of citations"
diff --git a/src/Text/Pandoc/Lua/Marshaling/Attr.hs b/src/Text/Pandoc/Lua/Marshaling/Attr.hs
--- a/src/Text/Pandoc/Lua/Marshaling/Attr.hs
+++ b/src/Text/Pandoc/Lua/Marshaling/Attr.hs
@@ -42,6 +42,10 @@
     <#> parameter peekAttr "a1" "Attr" ""
     <#> parameter peekAttr "a2" "Attr" ""
     =#> functionResult pushBool "boolean" "whether the two are equal"
+  , operation Tostring $ lambda
+    ### liftPure show
+    <#> parameter peekAttr "Attr" "attr" ""
+    =#> functionResult pushString "string" "native Haskell representation"
   ]
   [ property "identifier" "element identifier"
       (pushText, \(ident,_,_) -> ident)
diff --git a/src/Text/Pandoc/Lua/Module/Pandoc.hs b/src/Text/Pandoc/Lua/Module/Pandoc.hs
--- a/src/Text/Pandoc/Lua/Module/Pandoc.hs
+++ b/src/Text/Pandoc/Lua/Module/Pandoc.hs
@@ -138,9 +138,9 @@
     <#> parameter peekInlinesFuzzy "content" "Inline" "placeholder content"
     =#> functionResult pushInline "Inline" "cite element"
   , defun "Code"
-    ### liftPure2 (flip Code)
+    ### liftPure2 (\text mattr -> Code (fromMaybe nullAttr mattr) text)
     <#> parameter peekText "code" "string" "code string"
-    <#> parameter peekAttr "attr" "Attr" "additional attributes"
+    <#> optionalParameter peekAttr "attr" "Attr" "additional attributes"
     =#> functionResult pushInline "Inline" "code element"
   , mkInlinesConstr "Emph" Emph
   , defun "Image"
@@ -186,7 +186,7 @@
     <#> parameter peekText "text" "string" "string content"
     =#> functionResult pushInline "Inline" "raw inline element"
   , mkInlinesConstr "SmallCaps" SmallCaps
-  , defun "SoftSpace"
+  , defun "SoftBreak"
     ### return SoftBreak
     =#> functionResult pushInline "Inline" "soft break"
   , defun "Space"
diff --git a/src/Text/Pandoc/Readers/Docx/Parse/Styles.hs b/src/Text/Pandoc/Readers/Docx/Parse/Styles.hs
--- a/src/Text/Pandoc/Readers/Docx/Parse/Styles.hs
+++ b/src/Text/Pandoc/Readers/Docx/Parse/Styles.hs
@@ -310,9 +310,8 @@
     , rightParIndent = findAttrByName ns "w" "right" indElement <|>
                        findAttrByName ns "w" "end" indElement >>=
                        stringToInteger
-    , hangingParIndent = (findAttrByName ns "w" "hanging" indElement >>= stringToInteger) <|>
-                         fmap negate
-                           (findAttrByName ns "w" "firstLine" indElement >>= stringToInteger)
+    , hangingParIndent = findAttrByName ns "w" "hanging" indElement >>=
+                         stringToInteger
     }
 
 getElementStyleName :: Coercible T.Text a => NameSpaces -> Element -> Maybe a
diff --git a/test/docx/relative_indentation_blockquotes.docx b/test/docx/relative_indentation_blockquotes.docx
Binary files a/test/docx/relative_indentation_blockquotes.docx and b/test/docx/relative_indentation_blockquotes.docx differ
diff --git a/test/docx/relative_indentation_blockquotes.native b/test/docx/relative_indentation_blockquotes.native
--- a/test/docx/relative_indentation_blockquotes.native
+++ b/test/docx/relative_indentation_blockquotes.native
@@ -1,4 +1,6 @@
 [Header 1 ("indentation-blockquotes",[],[]) [Str "Indentation",Space,Str "blockquotes"]
+,Para [Str "Foobar"]
+,Para [Str "First",Space,Str "line",Space,Str "indented."]
 ,Para [Str "Normal",Space,Str "list",Space,Str "paragraph"]
 ,Para [Str "List",Space,Str "paragraph",Space,Str "with",Space,Str "less",Space,Str "indent"]
 ,BlockQuote [Para [Str "List",Space,Str "paragraph",Space,Str "with",Space,Str "more",Space,Str "indent"]]]
diff --git a/test/lua/module/pandoc.lua b/test/lua/module/pandoc.lua
--- a/test/lua/module/pandoc.lua
+++ b/test/lua/module/pandoc.lua
@@ -149,17 +149,290 @@
     }
   },
   group "Inline elements" {
-    test('Link has property `content`', function ()
-      local link = pandoc.Link('example', 'https://example.org')
-      assert.are_same(link.content, {pandoc.Str 'example'})
+    group 'Cite' {
+      test('has property `content`', function ()
+        local cite = pandoc.Cite({}, {pandoc.Emph 'important'})
+        assert.are_same(cite.content, {pandoc.Emph {pandoc.Str 'important'}})
 
-      link.content = 'commercial'
-      link.target = 'https://example.com'
-      assert.are_equal(link, pandoc.Link('commercial', 'https://example.com'))
-    end)
+        cite.content = 'boring'
+        assert.are_equal(cite, pandoc.Cite({}, {pandoc.Str 'boring'}))
+      end),
+      test('has list of citations in property `cite`', function ()
+        local citations = {
+          pandoc.Citation('einstein1905', 'NormalCitation')
+        }
+        local cite = pandoc.Cite(citations, 'relativity')
+        assert.are_same(cite.citations, citations)
+
+        local new_citations = {
+          citations[1],
+          pandoc.Citation('Poincaré1905', 'NormalCitation')
+        }
+        cite.citations = new_citations
+        assert.are_equal(cite, pandoc.Cite(new_citations, {'relativity'}))
+      end),
+    },
+    group 'Code' {
+      test('has property `attr`', function ()
+        local code = pandoc.Code('true', {id='true', foo='bar'})
+        assert.are_equal(code.attr, pandoc.Attr('true', {}, {{'foo', 'bar'}}))
+
+        code.attr = {id='t', fubar='quux'}
+        assert.are_equal(
+          pandoc.Code('true', pandoc.Attr('t', {}, {{'fubar', 'quux'}})),
+          code
+        )
+      end),
+      test('has property `text`', function ()
+        local code = pandoc.Code('true')
+        assert.are_equal(code.text, 'true')
+
+        code.text = '1 + 1'
+        assert.are_equal(pandoc.Code('1 + 1'), code)
+      end),
+    },
+    group 'Emph' {
+      test('has property `content`', function ()
+        local elem = pandoc.Emph{'two', pandoc.Space(), 'words'}
+        assert.are_same(
+          elem.content,
+          {pandoc.Str 'two', pandoc.Space(), pandoc.Str 'words'}
+        )
+        elem.content = {'word'}
+        assert.are_equal(elem, pandoc.Emph{'word'})
+      end)
+    },
+    group 'Image' {
+      test('has property `caption`', function ()
+        local img = pandoc.Image('example', 'a.png')
+        assert.are_same(img.caption, {pandoc.Str 'example'})
+
+        img.caption = 'A'
+        assert.are_equal(img, pandoc.Image({'A'}, 'a.png'))
+      end),
+      test('has property `src`', function ()
+        local img = pandoc.Image('example', 'sample.png')
+        assert.are_same(img.src, 'sample.png')
+
+        img.src = 'example.svg'
+        assert.are_equal(img, pandoc.Image('example', 'example.svg'))
+      end),
+      test('has property `title`', function ()
+        local img = pandoc.Image('here', 'img.gif', 'example')
+        assert.are_same(img.title, 'example')
+
+        img.title = 'a'
+        assert.are_equal(img, pandoc.Image('here', 'img.gif', 'a'))
+      end),
+      test('has property `attr`', function ()
+        local img = pandoc.Image('up', 'upwards.png', '', {'up', {'point'}})
+        assert.are_same(img.attr, pandoc.Attr {'up', {'point'}})
+
+        img.attr = pandoc.Attr {'up', {'point', 'button'}}
+        assert.are_equal(
+          pandoc.Image('up', 'upwards.png', nil, {'up', {'point', 'button'}}),
+          img
+        )
+      end)
+    },
+    group 'Link' {
+      test('has property `content`', function ()
+        local link = pandoc.Link('example', 'https://example.org')
+        assert.are_same(link.content, {pandoc.Str 'example'})
+
+        link.content = 'commercial'
+        link.target = 'https://example.com'
+        assert.are_equal(link, pandoc.Link('commercial', 'https://example.com'))
+      end),
+      test('has property `target`', function ()
+        local link = pandoc.Link('example', 'https://example.org')
+        assert.are_same(link.content, {pandoc.Str 'example'})
+
+        link.target = 'https://example.com'
+        assert.are_equal(link, pandoc.Link('example', 'https://example.com'))
+      end),
+      test('has property `title`', function ()
+        local link = pandoc.Link('here', 'https://example.org', 'example')
+        assert.are_same(link.title, 'example')
+
+        link.title = 'a'
+        assert.are_equal(link, pandoc.Link('here', 'https://example.org', 'a'))
+      end),
+      test('has property `attr`', function ()
+        local link = pandoc.Link('up', '../index.html', '', {'up', {'nav'}})
+        assert.are_same(link.attr, pandoc.Attr {'up', {'nav'}})
+
+        link.attr = pandoc.Attr {'up', {'nav', 'button'}}
+        assert.are_equal(
+          pandoc.Link('up', '../index.html', nil, {'up', {'nav', 'button'}}),
+          link
+        )
+      end)
+    },
+    group 'Math' {
+      test('has property `text`', function ()
+        local elem = pandoc.Math(pandoc.InlineMath, 'x^2')
+        assert.are_same(elem.text, 'x^2')
+        elem.text = 'a + b'
+        assert.are_equal(elem, pandoc.Math(pandoc.InlineMath, 'a + b'))
+      end),
+      test('has property `mathtype`', function ()
+        local elem = pandoc.Math(pandoc.InlineMath, 'x^2')
+        assert.are_same(elem.mathtype, 'InlineMath')
+        elem.mathtype = pandoc.DisplayMath
+        assert.are_equal(elem, pandoc.Math(pandoc.DisplayMath, 'x^2'))
+      end),
+    },
+    group 'Note' {
+      test('has property `content`', function ()
+        local elem = pandoc.Note{pandoc.Para {'two', pandoc.Space(), 'words'}}
+        assert.are_same(
+          elem.content,
+          {pandoc.Para {pandoc.Str 'two', pandoc.Space(), pandoc.Str 'words'}}
+        )
+        elem.content = pandoc.Plain 'word'
+        assert.are_equal(elem, pandoc.Note{'word'})
+      end)
+    },
+    group 'Quoted' {
+      test('has property `content`', function ()
+        local elem = pandoc.Quoted('SingleQuote', pandoc.Emph{'emph'})
+        assert.are_same(
+          elem.content,
+          {pandoc.Emph{pandoc.Str 'emph'}}
+        )
+        elem.content = {'word'}
+        assert.are_equal(elem, pandoc.Quoted(pandoc.SingleQuote, {'word'}))
+      end),
+      test('has property `quotetype`', function ()
+        local elem = pandoc.Quoted('SingleQuote', 'a')
+        assert.are_same(elem.quotetype, pandoc.SingleQuote)
+        elem.quotetype = 'DoubleQuote'
+        assert.are_equal(elem, pandoc.Quoted(pandoc.DoubleQuote, {'a'}))
+      end)
+    },
+    group 'SmallCaps' {
+      test('has property `content`', function ()
+        local elem = pandoc.SmallCaps{'two', pandoc.Space(), 'words'}
+        assert.are_same(
+          elem.content,
+          {pandoc.Str 'two', pandoc.Space(), pandoc.Str 'words'}
+        )
+        elem.content = {'word'}
+        assert.are_equal(elem, pandoc.SmallCaps{'word'})
+      end)
+    },
+    group 'SoftBreak' {
+      test('can be constructed', function ()
+        local sb = pandoc.SoftBreak()
+        assert.are_equal(sb.t, 'SoftBreak')
+      end)
+    },
+    group 'Span' {
+      test('has property `attr`', function ()
+        local elem = pandoc.Span('one', {'', {'number'}})
+        assert.are_same(
+          elem.attr,
+          pandoc.Attr('', {'number'})
+        )
+        elem.attr = {'', {}, {{'a', 'b'}}}
+        assert.are_equal(elem, pandoc.Span({'one'}, {a='b'}))
+      end),
+      test('has property `content`', function ()
+        local elem = pandoc.Span{'two', pandoc.Space(), 'words'}
+        assert.are_same(
+          elem.content,
+          {pandoc.Str 'two', pandoc.Space(), pandoc.Str 'words'}
+        )
+        elem.content = {'word'}
+        assert.are_equal(elem, pandoc.Span{'word'})
+      end)
+    },
+    group 'Str' {
+      test('has property `text`', function ()
+        local elem = pandoc.Str 'nein'
+        assert.are_same(elem.text, 'nein')
+        elem.text = 'doch'
+        assert.are_equal(elem, pandoc.Str 'doch')
+      end)
+    },
+    group 'Strikeout' {
+      test('has property `content`', function ()
+        local elem = pandoc.Strikeout{'two', pandoc.Space(), 'words'}
+        assert.are_same(
+          elem.content,
+          {pandoc.Str 'two', pandoc.Space(), pandoc.Str 'words'}
+        )
+        elem.content = {'word'}
+        assert.are_equal(elem, pandoc.Strikeout{'word'})
+      end)
+    },
+    group 'Strong' {
+      test('has property `content`', function ()
+        local elem = pandoc.Strong{'two', pandoc.Space(), 'words'}
+        assert.are_same(
+          elem.content,
+          {pandoc.Str 'two', pandoc.Space(), pandoc.Str 'words'}
+        )
+        elem.content = {'word'}
+        assert.are_equal(elem, pandoc.Strong{'word'})
+      end)
+    },
+    group 'Subscript' {
+      test('has property `content`', function ()
+        local elem = pandoc.Subscript{'two', pandoc.Space(), 'words'}
+        assert.are_same(
+          elem.content,
+          {pandoc.Str 'two', pandoc.Space(), pandoc.Str 'words'}
+        )
+        elem.content = {'word'}
+        assert.are_equal(elem, pandoc.Subscript{'word'})
+      end)
+    },
+    group 'Superscript' {
+      test('has property `content`', function ()
+        local elem = pandoc.Superscript{'two', pandoc.Space(), 'words'}
+        assert.are_same(
+          elem.content,
+          {pandoc.Str 'two', pandoc.Space(), pandoc.Str 'words'}
+        )
+        elem.content = {'word'}
+        assert.are_equal(elem, pandoc.Superscript{'word'})
+      end)
+    },
+    group 'Underline' {
+      test('has property `content`', function ()
+        local elem = pandoc.Underline{'two', pandoc.Space(), 'words'}
+        assert.are_same(
+          elem.content,
+          {pandoc.Str 'two', pandoc.Space(), pandoc.Str 'words'}
+        )
+        elem.content = {'word'}
+        assert.are_equal(elem, pandoc.Underline{'word'})
+      end)
+    },
   },
   group "Block elements" {
-    group "BulletList" {
+    group 'BlockQuote' {
+      test('access content via property `content`', function ()
+        local elem = pandoc.BlockQuote{'word'}
+        assert.are_same(elem.content, {pandoc.Plain 'word'})
+        assert.are_equal(type(elem.content), 'table')
+
+        elem.content = {
+          pandoc.Para{pandoc.Str 'one'},
+          pandoc.Para{pandoc.Str 'two'}
+        }
+        assert.are_equal(
+          pandoc.BlockQuote{
+            pandoc.Para 'one',
+            pandoc.Para 'two'
+          },
+          elem
+        )
+      end),
+    },
+    group 'BulletList' {
       test('access items via property `content`', function ()
         local para = pandoc.Para 'one'
         local blist = pandoc.BulletList{{para}}
@@ -175,23 +448,25 @@
         assert.are_same({{new}}, blist:clone().content)
       end),
     },
-    group "OrderedList" {
-      test('access items via property `content`', function ()
-        local para = pandoc.Plain 'one'
-        local olist = pandoc.OrderedList{{para}}
-        assert.are_same({{para}}, olist.content)
-      end),
-      test('forgiving constructor', function ()
-        local plain = pandoc.Plain 'old'
-        local olist = pandoc.OrderedList({plain}, {3, 'Example', 'Period'})
-        local listAttribs = pandoc.ListAttributes(3, 'Example', 'Period')
-        assert.are_same(olist.listAttributes, listAttribs)
+    group 'CodeBlock' {
+      test('access code via property `text`', function ()
+        local cb = pandoc.CodeBlock('return true')
+        assert.are_equal(cb.text, 'return true')
+        assert.are_equal(type(cb.text), 'string')
+
+        cb.text = 'return nil'
+        assert.are_equal(cb, pandoc.CodeBlock('return nil'))
       end),
-      test('has list attribute aliases', function ()
-        local olist = pandoc.OrderedList({}, {4, 'Decimal', 'OneParen'})
-        assert.are_equal(olist.start, 4)
-        assert.are_equal(olist.style, 'Decimal')
-        assert.are_equal(olist.delimiter, 'OneParen')
+      test('access Attr via property `attr`', function ()
+        local cb = pandoc.CodeBlock('true', {'my-code', {'lua'}})
+        assert.are_equal(cb.attr, pandoc.Attr{'my-code', {'lua'}})
+        assert.are_equal(type(cb.attr), 'userdata')
+
+        cb.attr = pandoc.Attr{'my-other-code', {'java'}}
+        assert.are_equal(
+          pandoc.CodeBlock('true', {'my-other-code', {'java'}}),
+          cb
+        )
       end)
     },
     group 'DefinitionList' {
@@ -221,29 +496,58 @@
         assert.are_equal(deflist, newlist)
       end),
     },
-    group 'Para' {
-      test('access inline via property `content`', function ()
-        local para = pandoc.Para{'Moin, ', pandoc.Space(), 'Sylt!'}
-        assert.are_same(
-          para.content,
-          {pandoc.Str 'Moin, ', pandoc.Space(), pandoc.Str 'Sylt!'}
+    group 'Div' {
+      test('access content via property `content`', function ()
+        local elem = pandoc.Div{pandoc.BlockQuote{pandoc.Plain 'word'}}
+        assert.are_same(elem.content, {pandoc.BlockQuote{'word'}})
+        assert.are_equal(type(elem.content), 'table')
+
+        elem.content = {
+          pandoc.Para{pandoc.Str 'one'},
+          pandoc.Para{pandoc.Str 'two'}
+        }
+        assert.are_equal(
+          pandoc.Div{
+            pandoc.Para 'one',
+            pandoc.Para 'two'
+          },
+          elem
         )
       end),
-      test('modifying `content` changes the element', function ()
-        local para = pandoc.Para{'Moin, ', pandoc.Space(), pandoc.Str 'Sylt!'}
+      test('access Attr via property `attr`', function ()
+        local div = pandoc.Div('word', {'my-div', {'sample'}})
+        assert.are_equal(div.attr, pandoc.Attr{'my-div', {'sample'}})
+        assert.are_equal(type(div.attr), 'userdata')
 
-        para.content[3] = 'Hamburg!'
-        assert.are_same(
-          para:clone().content,
-          {pandoc.Str 'Moin, ', pandoc.Space(), pandoc.Str 'Hamburg!'}
+        div.attr = pandoc.Attr{'my-other-div', {'example'}}
+        assert.are_equal(
+          pandoc.Div('word', {'my-other-div', {'example'}}),
+          div
         )
+      end)
+    },
+    group 'Header' {
+      test('access inlines via property `content`', function ()
+        local header = pandoc.Header(1, 'test')
+        assert.are_same(header.content, {pandoc.Str 'test'})
 
-        para.content = 'Huh'
-        assert.are_same(
-          para:clone().content,
-          {pandoc.Str 'Huh'}
-        )
-        end),
+        header.content = {'new text'}
+        assert.are_equal(header, pandoc.Header(1, 'new text'))
+      end),
+      test('access Attr via property `attr`', function ()
+        local header = pandoc.Header(1, 'test', {'my-test'})
+        assert.are_same(header.attr, pandoc.Attr{'my-test'})
+
+        header.attr = 'second-test'
+        assert.are_equal(header, pandoc.Header(1, 'test', 'second-test'))
+      end),
+      test('access level via property `level`', function ()
+        local header = pandoc.Header(3, 'test')
+        assert.are_same(header.level, 3)
+
+        header.level = 2
+        assert.are_equal(header, pandoc.Header(2, 'test'))
+      end),
     },
     group 'LineBlock' {
       test('access lines via property `content`', function ()
@@ -277,8 +581,176 @@
         )
       end)
     },
+    group 'OrderedList' {
+      test('access items via property `content`', function ()
+        local para = pandoc.Plain 'one'
+        local olist = pandoc.OrderedList{{para}}
+        assert.are_same({{para}}, olist.content)
+      end),
+      test('forgiving constructor', function ()
+        local plain = pandoc.Plain 'old'
+        local olist = pandoc.OrderedList({plain}, {3, 'Example', 'Period'})
+        local listAttribs = pandoc.ListAttributes(3, 'Example', 'Period')
+        assert.are_same(olist.listAttributes, listAttribs)
+      end),
+      test('has list attribute aliases', function ()
+        local olist = pandoc.OrderedList({}, {4, 'Decimal', 'OneParen'})
+        assert.are_equal(olist.start, 4)
+        assert.are_equal(olist.style, 'Decimal')
+        assert.are_equal(olist.delimiter, 'OneParen')
+      end)
+                        },
+    group 'Para' {
+      test('access inline via property `content`', function ()
+        local para = pandoc.Para{'Moin, ', pandoc.Space(), 'Sylt!'}
+        assert.are_same(
+          para.content,
+          {pandoc.Str 'Moin, ', pandoc.Space(), pandoc.Str 'Sylt!'}
+        )
+      end),
+      test('modifying `content` changes the element', function ()
+        local para = pandoc.Para{'Moin, ', pandoc.Space(), pandoc.Str 'Sylt!'}
+
+        para.content[3] = 'Hamburg!'
+        assert.are_same(
+          para:clone().content,
+          {pandoc.Str 'Moin, ', pandoc.Space(), pandoc.Str 'Hamburg!'}
+        )
+
+        para.content = 'Huh'
+        assert.are_same(
+          para:clone().content,
+          {pandoc.Str 'Huh'}
+        )
+      end),
+    },
+    group 'RawBlock' {
+      test('access raw content via property `text`', function ()
+        local raw = pandoc.RawBlock('markdown', '- one')
+        assert.are_equal(type(raw.text), 'string')
+        assert.are_equal(raw.text, '- one')
+
+        raw.text = '+ one'
+        assert.are_equal(raw, pandoc.RawBlock('markdown', '+ one'))
+      end),
+      test('access Format via property `format`', function ()
+        local raw = pandoc.RawBlock('markdown', '* hi')
+        assert.are_equal(type(raw.format), 'string')
+        assert.are_equal(raw.format, 'markdown')
+
+        raw.format = 'org'
+        assert.are_equal(pandoc.RawBlock('org', '* hi'), raw)
+      end)
+    },
+    group 'Table' {
+      test('access Attr via property `attr`', function ()
+        local caption = {long = {pandoc.Plain 'cap'}}
+        local tbl = pandoc.Table(caption, {}, {{}, {}}, {}, {{}, {}},
+                                 {'my-tbl', {'a'}})
+        assert.are_equal(tbl.attr, pandoc.Attr{'my-tbl', {'a'}})
+
+        tbl.attr = pandoc.Attr{'my-other-tbl', {'b'}}
+        assert.are_equal(
+          pandoc.Table(caption, {}, {{}, {}}, {}, {{}, {}},
+                       {'my-other-tbl', {'b'}}),
+          tbl
+        )
+      end),
+      test('access caption via property `caption`', function ()
+        local caption = {long = {pandoc.Plain 'cap'}}
+        local tbl = pandoc.Table(caption, {}, {{}, {}}, {}, {{}, {}})
+        assert.are_same(tbl.caption, {long = {pandoc.Plain 'cap'}})
+
+        tbl.caption.short = 'brief'
+        tbl.caption.long  = {pandoc.Plain 'extended'}
+
+        local new_caption = {
+          short = 'brief',
+          long = {pandoc.Plain 'extended'}
+        }
+        assert.are_equal(
+          pandoc.Table(new_caption, {}, {{}, {}}, {}, {{}, {}}),
+          tbl
+        )
+      end),
+      test('access column specifiers via property `colspecs`', function ()
+        local colspecs = {{pandoc.AlignCenter, 1}}
+        local tbl = pandoc.Table({long = {}}, colspecs, {{}, {}}, {}, {{}, {}})
+        assert.are_same(tbl.colspecs, colspecs)
+
+        tbl.colspecs[1][1] = pandoc.AlignRight
+        tbl.colspecs[1][2] = nil
+
+        local new_colspecs = {{pandoc.AlignRight}}
+        assert.are_equal(
+          pandoc.Table({long = {}}, new_colspecs, {{}, {}}, {}, {{}, {}}),
+          tbl
+        )
+      end),
+      test('access table head via property `head`', function ()
+        local head = {pandoc.Attr{'tbl-head'}, {}}
+        local tbl = pandoc.Table({long = {}}, {}, head, {}, {{}, {}})
+        assert.are_same(tbl.head, head)
+
+        tbl.head[1] = pandoc.Attr{'table-head'}
+
+        local new_head = {'table-head', {}}
+        assert.are_equal(
+          pandoc.Table({long = {}}, {}, new_head, {}, {{}, {}}),
+          tbl
+        )
+      end),
+      test('access table head via property `head`', function ()
+        local foot = {{id = 'tbl-foot'}, {}}
+        local tbl = pandoc.Table({long = {}}, {}, {{}, {}}, {}, foot)
+        assert.are_same(tbl.foot, {pandoc.Attr('tbl-foot'), {}})
+
+        tbl.foot[1] = pandoc.Attr{'table-foot'}
+
+        local new_foot = {'table-foot', {}}
+        assert.are_equal(
+          pandoc.Table({long = {}}, {}, {{}, {}}, {}, new_foot),
+          tbl
+        )
+      end)
+    },
   },
+  group 'MetaValue elements' {
+    test('MetaList elements behave like lists', function ()
+      local metalist = pandoc.MetaList{}
+      assert.are_equal(type(metalist.insert), 'function')
+      assert.are_equal(type(metalist.remove), 'function')
+    end),
+    test('MetaList, MetaMap, MetaInlines, MetaBlocks have `t` tag', function ()
+      assert.are_equal((pandoc.MetaList{}).t, 'MetaList')
+      assert.are_equal((pandoc.MetaMap{}).t, 'MetaMap')
+      assert.are_equal((pandoc.MetaInlines{}).t, 'MetaInlines')
+      assert.are_equal((pandoc.MetaBlocks{}).t, 'MetaBlocks')
+    end),
+    test('`tag` is an alias for `t``', function ()
+      assert.are_equal((pandoc.MetaList{}).tag, (pandoc.MetaList{}).t)
+      assert.are_equal((pandoc.MetaMap{}).tag, (pandoc.MetaMap{}).t)
+      assert.are_equal((pandoc.MetaInlines{}).tag, (pandoc.MetaInlines{}).t)
+      assert.are_equal((pandoc.MetaBlocks{}).tag, (pandoc.MetaBlocks{}).t)
+    end)
+  },
   group 'Other types' {
+    group 'Citation' {
+      test('checks equality by comparing Haskell values', function()
+        assert.are_equal(
+          pandoc.Citation('a', pandoc.NormalCitation),
+          pandoc.Citation('a', pandoc.NormalCitation)
+        )
+        assert.is_falsy(
+          pandoc.Citation('a', pandoc.NormalCitation) ==
+          pandoc.Citation('a', pandoc.AuthorInText)
+        )
+        assert.is_falsy(
+          pandoc.Citation('a', pandoc.NormalCitation) ==
+          pandoc.Citation('b', pandoc.NormalCitation)
+        )
+      end),
+    },
     group 'SimpleTable' {
       test('can access properties', function ()
         local spc = pandoc.Space()
