You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/12/13 06:13:41 UTC

[isis] branch master updated: ISIS-2473: cleanup adoc writer tests

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 7ef67b6  ISIS-2473: cleanup adoc writer tests
7ef67b6 is described below

commit 7ef67b6bc7110d5606a363bf777f51921a805ce6
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sun Dec 13 07:13:28 2020 +0100

    ISIS-2473: cleanup adoc writer tests
---
 .../isis/applib/annotation/OrderPrecedence.java    |   2 +-
 .../apache/isis/commons/internal/base/_Refs.java   | 126 +++++++
 .../isis/tooling/model4adoc/AsciiDocFactory.java   |   8 +-
 .../isis/tooling/model4adoc/AsciiDocWriter.java    |   2 +-
 .../isis/tooling/model4adoc/BlockVisitor.java      |  50 +--
 .../apache/isis/tooling/model4adoc/NodeWriter.java |  73 ++--
 .../model4adoc/StructuralNodeTraversor.java        |  26 +-
 .../tooling/model4adoc/StructuralNodeVisitor.java  |  37 +-
 ...onTest.java => AbstractAsciiDocWriterTest.java} |  69 ++--
 .../tooling/adocmodel/test/AdmonitionTest.java     |  34 +-
 .../tooling/adocmodel/test/AsciiDocWriterTest.java | 378 ---------------------
 .../adocmodel/test/AttributedTableTest.java        |  63 ++++
 .../tooling/adocmodel/test/DocumentHeaderTest.java |  59 ++++
 .../isis/tooling/adocmodel/test/FootnoteTest.java  |  36 +-
 .../tooling/adocmodel/test/NestedListTest.java     |  67 ++++
 .../isis/tooling/adocmodel/test/OpenBlockTest.java |  89 +++++
 .../tooling/adocmodel/test/SimpleListTest.java     |  57 ++++
 .../tooling/adocmodel/test/SimpleTableTest.java    |  67 ++++
 .../adocmodel/test/{Debug.java => _Debug.java}     |  53 ++-
 19 files changed, 707 insertions(+), 589 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/annotation/OrderPrecedence.java b/api/applib/src/main/java/org/apache/isis/applib/annotation/OrderPrecedence.java
index 8c2a72e..79d7a5c 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/annotation/OrderPrecedence.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/annotation/OrderPrecedence.java
@@ -25,7 +25,7 @@ import lombok.experimental.UtilityClass;
 
 /**
  * 
- * @since 1.x {@index}
+ * @since 2.0 {@index}
  */
 @UtilityClass
 public class OrderPrecedence {
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/base/_Refs.java b/commons/src/main/java/org/apache/isis/commons/internal/base/_Refs.java
new file mode 100644
index 0000000..65012ef
--- /dev/null
+++ b/commons/src/main/java/org/apache/isis/commons/internal/base/_Refs.java
@@ -0,0 +1,126 @@
+/*
+ *  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.
+ */
+package org.apache.isis.commons.internal.base;
+
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongUnaryOperator;
+import java.util.function.UnaryOperator;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NonNull;
+
+/**
+ * <h1>- internal use only -</h1>
+ * <p>
+ * Not thread-safe, primitive and object references.
+ * </p>
+ * <p>
+ * <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/>
+ * These may be changed or removed without notice!
+ * </p>
+ *
+ * @since 2.0
+ */
+public final class _Refs {
+
+    // -- FACTORIES
+    
+    public static BooleanReference booleanRef(final boolean value) {
+        return new BooleanReference(value);
+    }
+    
+    public static IntReference intRef(final int value) {
+        return new IntReference(value);
+    }
+    
+    public static LongReference longRef(final int value) {
+        return new LongReference(value);
+    }
+    
+    public static <T> ObjectReference<T> objectRef(final T value) {
+        return new ObjectReference<>(value);
+    }
+    
+    // -- IMPLEMENTATIONS
+    
+    @FunctionalInterface
+    public static interface BooleanUnaryOperator {
+        boolean applyAsBoolean(boolean value);
+    }
+    
+    
+    @Data @AllArgsConstructor
+    public static final class BooleanReference {
+        private boolean value;
+        
+        public boolean update(final @NonNull BooleanUnaryOperator operator) {
+            return value=operator.applyAsBoolean(value);
+        }
+        
+        public boolean isTrue() {
+            return value;
+        }
+        
+        public boolean isFalse() {
+            return !value;
+        }
+    }
+    
+    @Data @AllArgsConstructor
+    public static final class IntReference {
+        private int value;
+        
+        public int update(final @NonNull IntUnaryOperator operator) {
+            return value = operator.applyAsInt(value);
+        }
+        
+        public boolean isSet(int other) {
+            return value==other;
+        }
+        
+    }
+    
+    @Data @AllArgsConstructor
+    public static final class LongReference {
+        private long value;
+        
+        public long update(final @NonNull LongUnaryOperator operator) {
+            return value = operator.applyAsLong(value);
+        }
+        
+        public boolean isSet(long other) {
+            return value==other;
+        }
+    }
+    
+    @Data @AllArgsConstructor
+    public static final class ObjectReference<T> {
+        private T value;
+        
+        public T update(final @NonNull UnaryOperator<T> operator) {
+            return value = operator.apply(value);
+        }
+        
+        public boolean isSet(T other) {
+            return value==other;
+        }
+    }
+    
+}
diff --git a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/AsciiDocFactory.java b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/AsciiDocFactory.java
index 0d110d9..9e25ca1 100644
--- a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/AsciiDocFactory.java
+++ b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/AsciiDocFactory.java
@@ -68,7 +68,7 @@ public class AsciiDocFactory {
     // -- ATTRIBUTES
     
     public static void attrNotice(Document node, String value) {
-        node.setAttribute("Notice", value, true);
+        node.setAttribute("notice", value, true);
     }
     
     // -- ADMONITIONS
@@ -140,6 +140,12 @@ public class AsciiDocFactory {
         return openBlock;
     }
     
+    public static Block listingBlock(StructuralNode parent, @NonNull String source) {
+        val listingBlock = block(parent, source);
+        listingBlock.setStyle("listing");
+        return listingBlock;
+    }
+    
     // -- FOOTNOTES
     
     public static org.asciidoctor.ast.List footnotes(StructuralNode parent) {
diff --git a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/AsciiDocWriter.java b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/AsciiDocWriter.java
index 4c92a85..456c428 100644
--- a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/AsciiDocWriter.java
+++ b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/AsciiDocWriter.java
@@ -117,7 +117,7 @@ public class AsciiDocWriter {
         }
         
         val nodeWriter = new NodeWriter(writer);
-        StructuralNodeTraversor.traverse(nodeWriter, doc);
+        StructuralNodeTraversor.depthFirst(nodeWriter, doc);
         writer.flush();
     }
     
diff --git a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/BlockVisitor.java b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/BlockVisitor.java
index f35af1a..97bf6d8 100644
--- a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/BlockVisitor.java
+++ b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/BlockVisitor.java
@@ -21,10 +21,6 @@ package org.apache.isis.tooling.model4adoc;
 import java.util.function.Predicate;
 
 import org.asciidoctor.ast.Block;
-import org.asciidoctor.ast.Document;
-import org.asciidoctor.ast.List;
-import org.asciidoctor.ast.ListItem;
-import org.asciidoctor.ast.Table;
 
 import lombok.RequiredArgsConstructor;
 
@@ -33,50 +29,10 @@ final class BlockVisitor
 implements StructuralNodeVisitor {
 
     private final Predicate<Block> blockConsumer;
-    private boolean continueVisit = true;
-    
+   
     @Override
-    public void documentHead(Document doc, int depth) {
-    }
-
-    @Override
-    public void blockHead(Block block, int depth) {
-        if(!continueVisit) {
-            return;
-        }
-        continueVisit = blockConsumer.test(block);
-    }
-
-    @Override
-    public void listHead(List list, int depth) {
-    }
-
-    @Override
-    public void listItemHead(ListItem listItem, int depth) {
-    }
-
-    @Override
-    public void tableHead(Table table, int depth) {
-    }
-
-    @Override
-    public void documentTail(Document doc, int depth) {
-    }
-
-    @Override
-    public void blockTail(Block block, int depth) {
-    }
-
-    @Override
-    public void listTail(List list, int depth) {
-    }
-
-    @Override
-    public void listItemTail(ListItem listItem, int depth) {
-    }
-
-    @Override
-    public void tableTail(Table table, int depth) {
+    public boolean blockHead(Block block, int depth) {
+        return blockConsumer.test(block);
     }
 
 }
diff --git a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/NodeWriter.java b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/NodeWriter.java
index 52b7b64..347af8b 100644
--- a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/NodeWriter.java
+++ b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/NodeWriter.java
@@ -36,6 +36,7 @@ import org.asciidoctor.ast.StructuralNode;
 import org.asciidoctor.ast.Table;
 
 import org.apache.isis.commons.internal.base._NullSafe;
+import org.apache.isis.commons.internal.base._Refs;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.base._Text;
 import org.apache.isis.commons.internal.collections._Arrays;
@@ -51,24 +52,13 @@ final class NodeWriter implements StructuralNodeVisitor {
 
     private final Writer writer;
 
-    @Override
-    public void head(StructuralNode node, int depth) {
-        StructuralNodeVisitor.super.head(node, depth);
-    }
-
-    @Override
-    public void tail(StructuralNode node, int depth) {
-        StructuralNodeVisitor.super.tail(node, depth);
-
-    }
-
     // -- DOCUMENT
 
     private static final List<String> knownDocAttributes = _Lists.of(
             "Notice");
 
     @Override
-    public void documentHead(Document doc, int depth) {
+    public boolean documentHead(Document doc, int depth) {
 
         _Strings.nonEmpty(doc.getTitle())
         .ifPresent(title->printChapterTitle(title, depth+1));
@@ -76,21 +66,24 @@ final class NodeWriter implements StructuralNodeVisitor {
         val attr = doc.getAttributes();
         if(!attr.isEmpty()) {
             for(val knownAttrKey : knownDocAttributes) {
-                Optional.ofNullable(attr.get(knownAttrKey))
+                Optional.ofNullable(attr.get(knownAttrKey.toLowerCase()))
                 .ifPresent(attrValue->printfln(":%s: %s", knownAttrKey, attrValue));
             }
         }
+        
+        return true; // continue visit
     }
 
-    @Override
-    public void documentTail(Document doc, int depth) {
-    }
+//    @Override
+//    public void documentTail(Document doc, int depth) {
+//    }
 
     // -- BLOCK
 
     @RequiredArgsConstructor
     private static enum Style {
         OPEN_BLOCK("open"::equals),
+        LISTING_BLOCK("listing"::equals),
         FOOTNOTE_LIST("arabic"::equals),
         ADMONITION_NOTE("NOTE"::equals),
         ADMONITION_TIP("TIP"::equals),
@@ -110,6 +103,9 @@ final class NodeWriter implements StructuralNodeVisitor {
         public boolean isOpenBlock() {
             return this==Style.OPEN_BLOCK;
         }
+        public boolean isListingBlock() {
+            return this==Style.LISTING_BLOCK;
+        }
         public boolean isFootnoteList() {
             return this==Style.FOOTNOTE_LIST;
         }
@@ -119,11 +115,11 @@ final class NodeWriter implements StructuralNodeVisitor {
     }
 
     @Override
-    public void blockHead(Block block, int depth) {
+    public boolean blockHead(Block block, int depth) {
 
         val style = Style.parse(block);        
 
-        if(style.isOpenBlock()){
+        if(style.isOpenBlock()) {
             pushNewWriter(); // write the open block to a StringWriter, such that can handle empty blocks
             println("+");
             println("--");
@@ -136,7 +132,7 @@ final class NodeWriter implements StructuralNodeVisitor {
             }    
         }
 
-        if(style.isAdmonition()){
+        if(style.isAdmonition()) {
             if(block.getBlocks().size()>0) {
                 printfln("[%s]", block.getStyle());
                 println("====");    
@@ -144,12 +140,15 @@ final class NodeWriter implements StructuralNodeVisitor {
             } else {
                 printf("%s: ", block.getStyle());
             }
-        } 
+        } else if(style.isListingBlock()) {
+            println("----");
+        }
 
         for(val line : block.getLines()) {
             println(line);
         }
 
+        return true; // continue visit
     }
 
     @Override
@@ -165,13 +164,15 @@ final class NodeWriter implements StructuralNodeVisitor {
             if(block.getBlocks().size()>0) {
                 println("====");    
             }
+        } else if(style.isListingBlock()) {
+            println("----");
         }
     }
 
     // -_ LIST 
 
     @Override
-    public void listHead(org.asciidoctor.ast.List list, int depth) {
+    public boolean listHead(org.asciidoctor.ast.List list, int depth) {
         if(bulletCount==0) {
             if(newLineCount<=1) {
                 printNewLine();
@@ -181,6 +182,8 @@ final class NodeWriter implements StructuralNodeVisitor {
 
         _Strings.nonEmpty(list.getTitle())
         .ifPresent(this::printBlockTitle);
+        
+        return true; // continue visit
     }
 
     @Override
@@ -189,7 +192,7 @@ final class NodeWriter implements StructuralNodeVisitor {
     }
 
     @Override
-    public void listItemHead(ListItem listItem, int depth) {
+    public boolean listItemHead(ListItem listItem, int depth) {
 
         val isFootnoteStyle = Style.parse((org.asciidoctor.ast.List)(listItem.getParent()))
                 .isFootnoteList(); 
@@ -201,12 +204,12 @@ final class NodeWriter implements StructuralNodeVisitor {
         val listItemSource = _Strings.nullToEmpty(listItem.getSource()).trim();
         if(!listItemSource.isEmpty()) {
             printfln("%s %s", bullets, listItemSource);
-            return;
+            return true; // continue visit
         }
         
         if(_NullSafe.isEmpty(listItem.getBlocks())) {
             printfln("%s _missing listitem text_", bullets);
-            return; 
+            return true; // continue visit
         }
         
         //there is a special case, if source is blank
@@ -214,24 +217,24 @@ final class NodeWriter implements StructuralNodeVisitor {
         
         //find the first block that has a source, use it and blank it out, so is not written twice
         
-        boolean isFixed[] = {false};
+        val isFixed = _Refs.booleanRef(false); 
         
-        StructuralNodeTraversor.traverse(new BlockVisitor(block->{
+        StructuralNodeTraversor.depthFirst(new BlockVisitor(block->{
             val blockSource = _Strings.nullToEmpty(block.getSource()).trim();
             if(!blockSource.isEmpty()) {
                 block.setSource(null);
                 printfln("%s %s", bullets, blockSource);
-                isFixed[0] = true;
+                isFixed.setValue(true);
                 return false; // terminate the visit
             }
             return true; // continue the visit
         }), listItem);
         
-        if(!isFixed[0]) {
+        if(isFixed.isFalse()) {
             printfln("%s _missing listitem text_", bullets);
         }
 
-
+        return true; // continue visit
     }
 
     @Override
@@ -253,7 +256,7 @@ final class NodeWriter implements StructuralNodeVisitor {
     //  |Cell in column 3, row 2
     //  |===
     @Override
-    public void tableHead(Table table, int depth) {
+    public boolean tableHead(Table table, int depth) {
 
         _Strings.nonEmpty(table.getTitle())
         .ifPresent(this::printBlockTitle);
@@ -280,12 +283,14 @@ final class NodeWriter implements StructuralNodeVisitor {
         }
 
         println("|===");
+        
+        return true; // continue visit
     }
 
-    @Override
-    public void tableTail(Table table, int depth) {
-
-    }
+//    @Override
+//    public void tableTail(Table table, int depth) {
+//
+//    }
 
     // -- HELPER
 
diff --git a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/StructuralNodeTraversor.java b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/StructuralNodeTraversor.java
index 01f110e..6f6f79a 100644
--- a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/StructuralNodeTraversor.java
+++ b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/StructuralNodeTraversor.java
@@ -21,20 +21,23 @@ package org.apache.isis.tooling.model4adoc;
 import org.asciidoctor.ast.StructuralNode;
 
 import org.apache.isis.commons.internal.base._NullSafe;
+import org.apache.isis.commons.internal.base._Refs;
+import org.apache.isis.commons.internal.base._Refs.BooleanReference;
 
 import lombok.val;
 
 /**
- * Depth-first node traversor. Use to iterate through all nodes under and including the specified root node.
+ * Depth-first node traversing. Use to iterate through all nodes under and including the specified root node.
  */
 final class StructuralNodeTraversor {
+    
     /**
      * Start a depth-first traverse of the root and all of its descendants.
      * @param visitor Node visitor.
      * @param root the root node point to traverse.
      */
-    public static void traverse(StructuralNodeVisitor visitor, StructuralNode root) {
-        traverse(visitor, root, 0);
+    public static void depthFirst(StructuralNodeVisitor visitor, StructuralNode root) {
+        traverse(visitor, root, 0, _Refs.booleanRef(true));
     }
     
     // -- HELPER
@@ -42,15 +45,26 @@ final class StructuralNodeTraversor {
     private static void traverse(
             final StructuralNodeVisitor visitor, 
             final StructuralNode node, 
-            final int depth) {
+            final int depth,
+            final BooleanReference continueTraverse) {
+        
+        if(continueTraverse.isFalse()) {
+            return;
+        }
         
-        visitor.head(node, depth);
+        val continueVisit = visitor.head(node, depth);
+        if(!continueVisit) {
+            continueTraverse.update(__->false);
+        }
         
         val blocks = node.getBlocks();
         
         if(!_NullSafe.isEmpty(blocks)) {
             for(val subNode : blocks) {
-                traverse(visitor, subNode, depth+1);
+                traverse(visitor, subNode, depth+1, continueTraverse);
+                if(continueTraverse.isFalse()) {
+                    break;
+                }
             }
         }
         
diff --git a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/StructuralNodeVisitor.java b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/StructuralNodeVisitor.java
index e409acd..9d50f56 100644
--- a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/StructuralNodeVisitor.java
+++ b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/StructuralNodeVisitor.java
@@ -45,41 +45,36 @@ interface StructuralNodeVisitor {
      * @param depth the depth of the node, relative to the root node. E.g., the root node has depth 0, and a child node
      * of that will have depth 1.
      */
-    default void head(StructuralNode node, int depth) {
+    default boolean head(StructuralNode node, int depth) {
         if(node instanceof Document) {
-            documentHead((Document)node, depth);
-            return;
+            return documentHead((Document)node, depth);
         }
         if(node instanceof Table) {
-            tableHead((Table)node, depth);
-            return;
+            return tableHead((Table)node, depth);
         }
         if(node instanceof org.asciidoctor.ast.List) {
-            listHead((org.asciidoctor.ast.List)node, depth);
-            return;
+            return listHead((org.asciidoctor.ast.List)node, depth);
         }
         if(node instanceof ListItem) {
-            listItemHead((ListItem)node, depth);
-            return;
+            return listItemHead((ListItem)node, depth);
         }
         if(node instanceof Block) {
-            blockHead((Block)node, depth);
-            return;
+            return blockHead((Block)node, depth);
         }    
         throw _Exceptions.unsupportedOperation("node type not supported %s", node.getClass());
     }
 
     // -- HEAD SPECIALISATIONS
     
-    void documentHead(Document doc, int depth);
+    default boolean documentHead(Document doc, int depth) { return true; }
 
-    void blockHead(Block block, int depth);
+    default boolean blockHead(Block block, int depth) { return true; }
 
-    void listHead(org.asciidoctor.ast.List list, int depth);
+    default boolean listHead(org.asciidoctor.ast.List list, int depth) { return true; }
     
-    void listItemHead(ListItem listItem, int depth);
+    default boolean listItemHead(ListItem listItem, int depth) { return true; }
 
-    void tableHead(Table table, int depth);
+    default boolean tableHead(Table table, int depth) { return true; }
     
    // -- TAIL
 
@@ -116,15 +111,15 @@ interface StructuralNodeVisitor {
     
     // -- TAIL SPECIALISATIONS
     
-    void documentTail(Document doc, int depth);
+    default void documentTail(Document doc, int depth) {}
 
-    void blockTail(Block block, int depth);
+    default void blockTail(Block block, int depth) {}
 
-    void listTail(org.asciidoctor.ast.List list, int depth);
+    default void listTail(org.asciidoctor.ast.List list, int depth) {}
     
-    void listItemTail(ListItem listItem, int depth);
+    default void listItemTail(ListItem listItem, int depth) {}
 
-    void tableTail(Table table, int depth);
+    default void tableTail(Table table, int depth) {}
     
     
 }
\ No newline at end of file
diff --git a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AdmonitionTest.java b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AbstractAsciiDocWriterTest.java
similarity index 57%
copy from tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AdmonitionTest.java
copy to tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AbstractAsciiDocWriterTest.java
index a70761b..d2187e0 100644
--- a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AdmonitionTest.java
+++ b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AbstractAsciiDocWriterTest.java
@@ -24,68 +24,57 @@ import java.util.HashMap;
 
 import org.asciidoctor.Asciidoctor;
 import org.asciidoctor.ast.Document;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.base._Text;
-import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
 import org.apache.isis.tooling.model4adoc.AsciiDocWriter;
 
-import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.doc;
-
 import lombok.val;
 
-class AdmonitionTest {
-
-    private Document doc;
-
-    @BeforeEach
-    void setUp() throws Exception {
-        doc = doc();
-    }
-
-    //[NOTE]
-    //====
-    //the note is multiple paragraphs, and can have all the usual styling
-    //
-    //also note
-    //====
-    //
-    //TIP: Here's something worth knowing...
-    @Test
-    void testAdmonition() throws IOException {
-        
-        val note = AsciiDocFactory.note(doc);
-        AsciiDocFactory.block(note, "the note is multiple paragraphs, and can have all the usual styling");
-        AsciiDocFactory.block(note, "also note");
+abstract class AbstractAsciiDocWriterTest {
+    
+    protected String adocSourceResourceLocation;
+    protected boolean debugEnabled;
+    
+    protected void assertDocumentIsCorrectlyWritten(final Document documentUnderTest) {
         
-        AsciiDocFactory.tip(doc, "Here's something worth knowing...");
+        final String sourceUnderTest = AsciiDocWriter.toString(documentUnderTest);
         
-        String actualAdoc = AsciiDocWriter.toString(doc);
-        System.out.println(actualAdoc); //debug
+        if(debugEnabled) {
+            System.out.println("======= Generated Adoc Source =======");
+            System.out.println(sourceUnderTest);
+            System.out.println("=====================================");
+        }
         
         _Text.assertTextEquals(
-                _Text.readLinesFromResource(this.getClass(), "admonition.adoc", StandardCharsets.UTF_8), 
-                actualAdoc);
+                _Text.readLinesFromResource(this.getClass(), adocSourceResourceLocation, StandardCharsets.UTF_8), 
+                sourceUnderTest);
     }
     
-    @Test @Disabled
-    void reverseTestAdmonition() throws IOException {
-    
-        val adocRef = _Strings.readFromResource(this.getClass(), "admonition.adoc", StandardCharsets.UTF_8);
+    protected void assertReferenceDocumentIsCorrectlyWritten() {
+        val adocRef = _Strings.readFromResource(this.getClass(), adocSourceResourceLocation, StandardCharsets.UTF_8);
         val asciidoctor = Asciidoctor.Factory.create();
         val refDoc = asciidoctor.load(adocRef, new HashMap<String, Object>());
         
-        Debug.debug(refDoc);
+        if(debugEnabled) {
+            _Debug.debug(refDoc);
+        }
         
         String actualAdoc = AsciiDocWriter.toString(refDoc);
-        System.out.println(actualAdoc); //debug
+        if(debugEnabled) {
+            System.out.println("== Generated Adoc Source (Ref. Factory) ==");
+            System.out.println(actualAdoc);
+            System.out.println("==========================================");
+        }
         
         _Text.assertTextEquals(adocRef, actualAdoc);
     }
     
+    @Test
+    void testReferenceDocumentIsCorrectlyWritten() throws IOException {
+        assertReferenceDocumentIsCorrectlyWritten();
+    }
+   
     
-
 }
diff --git a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AdmonitionTest.java b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AdmonitionTest.java
index a70761b..7071d39 100644
--- a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AdmonitionTest.java
+++ b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AdmonitionTest.java
@@ -19,31 +19,26 @@
 package org.apache.isis.tooling.adocmodel.test;
 
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
 
-import org.asciidoctor.Asciidoctor;
 import org.asciidoctor.ast.Document;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
-import org.apache.isis.commons.internal.base._Strings;
-import org.apache.isis.commons.internal.base._Text;
 import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
-import org.apache.isis.tooling.model4adoc.AsciiDocWriter;
 
 import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.doc;
 
 import lombok.val;
 
-class AdmonitionTest {
+class AdmonitionTest extends AbstractAsciiDocWriterTest {
 
     private Document doc;
 
     @BeforeEach
     void setUp() throws Exception {
         doc = doc();
+        super.adocSourceResourceLocation = "admonition.adoc";
+        super.debugEnabled = false;
     }
 
     //[NOTE]
@@ -63,29 +58,8 @@ class AdmonitionTest {
         
         AsciiDocFactory.tip(doc, "Here's something worth knowing...");
         
-        String actualAdoc = AsciiDocWriter.toString(doc);
-        System.out.println(actualAdoc); //debug
-        
-        _Text.assertTextEquals(
-                _Text.readLinesFromResource(this.getClass(), "admonition.adoc", StandardCharsets.UTF_8), 
-                actualAdoc);
-    }
-    
-    @Test @Disabled
-    void reverseTestAdmonition() throws IOException {
-    
-        val adocRef = _Strings.readFromResource(this.getClass(), "admonition.adoc", StandardCharsets.UTF_8);
-        val asciidoctor = Asciidoctor.Factory.create();
-        val refDoc = asciidoctor.load(adocRef, new HashMap<String, Object>());
-        
-        Debug.debug(refDoc);
-        
-        String actualAdoc = AsciiDocWriter.toString(refDoc);
-        System.out.println(actualAdoc); //debug
-        
-        _Text.assertTextEquals(adocRef, actualAdoc);
+        assertDocumentIsCorrectlyWritten(doc);
     }
     
-    
 
 }
diff --git a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AsciiDocWriterTest.java b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AsciiDocWriterTest.java
deleted file mode 100644
index dd6f5ed..0000000
--- a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AsciiDocWriterTest.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- *  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.
- */
-package org.apache.isis.tooling.adocmodel.test;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-
-import org.asciidoctor.Asciidoctor;
-import org.asciidoctor.ast.Document;
-import org.asciidoctor.ast.ListItem;
-import org.asciidoctor.ast.Table;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import org.apache.isis.commons.internal.base._NullSafe;
-import org.apache.isis.commons.internal.base._Strings;
-import org.apache.isis.commons.internal.base._Text;
-import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
-import org.apache.isis.tooling.model4adoc.AsciiDocWriter;
-
-import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.attrNotice;
-import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.block;
-import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.cell;
-import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.doc;
-import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.headCell;
-import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.list;
-import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.listItem;
-import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.table;
-
-import lombok.val;
-
-class AsciiDocWriterTest {
-
-    private Document doc;
-
-    @BeforeEach
-    void setUp() throws Exception {
-        doc = doc();
-    }
-
-    @AfterEach
-    void tearDown() throws Exception {
-    }
-
-    @Test
-    void testDocTitle() throws IOException {
-        
-        doc.setTitle("Hello World");
-        
-        String actualAdoc = AsciiDocWriter.toString(doc); 
-        String expectedAdoc = "= Hello World\n";
-        
-        // System.out.println(actualAdoc); // debug
-        
-        assertEquals(expectedAdoc, actualAdoc);
-    }
-    
-    //= Sample
-    //:Notice: my special license
-    //
-    //hi
-    @Test
-    void testDocHeader() throws IOException {
-        
-        doc.setTitle("Sample");
-        
-        attrNotice(doc, "my special license");
-        
-        block(doc).getLines().add("hi");
-        
-        String actualAdoc = AsciiDocWriter.toString(doc);
-        
-        _Text.assertTextEquals(
-                _Text.readLinesFromResource(this.getClass(), "document-header.adoc", StandardCharsets.UTF_8), 
-                actualAdoc);
-    }
-    
-    @Test @Disabled
-    void reverseTestDocHeader() throws IOException {
-    
-        val adocRef = _Strings.readFromResource(this.getClass(), "document-header.adoc", StandardCharsets.UTF_8);
-        val asciidoctor = Asciidoctor.Factory.create();
-        val refDoc = asciidoctor.load(adocRef, new HashMap<String, Object>());
-        
-        Debug.debug(refDoc);
-        
-        String actualAdoc = AsciiDocWriter.toString(refDoc);
-        System.out.println(actualAdoc); //debug
-        
-        _Text.assertTextEquals(adocRef, actualAdoc);
-    }
-    
-    @Test
-    void testSimpleTable() throws IOException {
-        
-        val table = table(doc);
-        table.setTitle("Table");
-        
-        headCell(table, 0, 0, "Col-1");
-        headCell(table, 0, 1, "Col-2");
-        headCell(table, 0, 2, "Col-3");
-        
-        cell(table, 0, 0, "1-1");
-        cell(table, 0, 1, "1-2");
-        cell(table, 0, 2, "1-3");
-        
-        cell(table, 1, 0, "2-1");
-        cell(table, 1, 1, "2-2");
-        cell(table, 1, 2, "2-3");
-        
-        String actualAdoc = AsciiDocWriter.toString(doc); 
-        
-        //System.out.println(actualAdoc); //debug
-        
-        _Text.assertTextEquals(
-                _Text.readLinesFromResource(this.getClass(), "table-simple.adoc", StandardCharsets.UTF_8), 
-                actualAdoc);
-    }
-    
-    @Test
-    void testSimpleList() throws IOException {
-        
-        val list = list(doc);
-        list.setTitle("SimpleList");
-        
-        listItem(list, "Item-1");
-        listItem(list, "Item-2");
-        
-        String actualAdoc = AsciiDocWriter.toString(doc); 
-        
-        System.out.println(actualAdoc); //debug
-        
-        _Text.assertTextEquals(
-                _Text.readLinesFromResource(this.getClass(), "list-simple.adoc", StandardCharsets.UTF_8), 
-                actualAdoc);
-    }
-    
-    @SuppressWarnings("unused")
-    @Test
-    void testNestedList() throws IOException {
-        
-        val list = list(doc);
-        list.setTitle("NestedList");
-        
-        val item1 = listItem(list, "Item-1");
-        val item2 = listItem(list, "Item-2");
-        
-        val list1 = list(item1);
-        
-        val item11 = listItem(list1, "Item-1-1");
-        val item12 = listItem(list1, "Item-1-2");
-        
-        val list12 = list(item12);
-        
-        val item121 = listItem(list12, "Item-1-2-1");
-        
-        String actualAdoc = AsciiDocWriter.toString(doc); 
-        
-        System.out.println(actualAdoc); //debug
-        
-        _Text.assertTextEquals(
-                _Text.readLinesFromResource(this.getClass(), "list-nested.adoc", StandardCharsets.UTF_8), 
-                actualAdoc);
-    }
-    
-    @Test @Disabled
-    void reverseTestNestedList() throws IOException {
-    
-        val adocRef = _Strings.readFromResource(this.getClass(), "list-nested.adoc", StandardCharsets.UTF_8);
-        val asciidoctor = Asciidoctor.Factory.create();
-        val refDoc = asciidoctor.load(adocRef, new HashMap<String, Object>());
-        
-        String actualAdoc = AsciiDocWriter.toString(refDoc);
-        
-        debug((org.asciidoctor.ast.List)refDoc.getBlocks().get(0));
-        
-        System.out.println(actualAdoc); //debug
-        
-        _Text.assertTextEquals(adocRef, actualAdoc);
-    }
-
-    
-    //* ListItem 1
-    //+
-    //--
-    //Here's an example of a document title:
-    //
-    //----
-    //= Document Title
-    //----
-    //
-    //NOTE: The header is optional.
-    //--
-    //* ListItem 2
-    //+
-    //--
-    //paragr 1 
-    //
-    //paragr 2
-    //--
-    @Test
-    void testListWithOpenBlockContinuation() throws IOException {
-        
-        val list = list(doc);
-        
-        val item1 = listItem(list, "ListItem 1");
-        val item2 = listItem(list, "ListItem 2");
-        
-        val openBlock1 = AsciiDocFactory.openBlock(item1);
-        val openBlock2 = AsciiDocFactory.openBlock(item2);
-        
-        val block11 = AsciiDocFactory.block(openBlock1);
-        val block12 = AsciiDocFactory.block(openBlock1);
-        val block13 = AsciiDocFactory.block(openBlock1);
-        
-        block11.setSource("Here's an example of a document title:");
-        block12.setSource("----\n= Document Title\n----");
-        block13.setSource("NOTE: The header is optional.");
-        
-        val block21 = AsciiDocFactory.block(openBlock2);
-        val block22 = AsciiDocFactory.block(openBlock2);
-        
-        block21.setSource("paragr 1");
-        block22.setSource("paragr 2");
-        
-        String actualAdoc = AsciiDocWriter.toString(doc); 
-        
-        //System.out.println(actualAdoc); //debug
-        
-        _Text.assertTextEquals(
-                _Text.readLinesFromResource(this.getClass(), "list-open-block-continuation.adoc", StandardCharsets.UTF_8), 
-                actualAdoc);
-    }
-    
-    
-    
-    @Test @Disabled
-    void reverseTestListWithOpenBlockContinuation() throws IOException {
-    
-        val adocRef = _Strings.readFromResource(this.getClass(), "list-open-block-continuation.adoc", StandardCharsets.UTF_8);
-        val asciidoctor = Asciidoctor.Factory.create();
-        val refDoc = asciidoctor.load(adocRef, new HashMap<String, Object>());
-        
-        String actualAdoc = AsciiDocWriter.toString(refDoc);
-        
-        Debug.debug(refDoc);
-        
-        System.out.println(actualAdoc); //debug
-        
-        _Text.assertTextEquals(adocRef, actualAdoc);
-    }
-
-
-    @Test
-    void testAttributedTable() throws IOException {
-        
-        val table = table(doc);
-        table.setTitle("Some table");
-        table.setAttribute("cols", "3m,2a", true);
-        table.setAttribute("header-option", "", true);
-        
-        headCell(table, 0, 0, "Col-1");
-        headCell(table, 0, 1, "Col-2");
-        
-        cell(table, 0, 0, "1-1");
-        cell(table, 0, 1, "1-2");
-        
-        String actualAdoc = AsciiDocWriter.toString(doc); 
-        
-        System.out.println(actualAdoc); // debug
-        
-        _Text.assertTextEquals(
-                _Text.readLinesFromResource(this.getClass(), "table-attributed.adoc", StandardCharsets.UTF_8), 
-                actualAdoc);
-        
-    }
-    
-    @Test @Disabled
-    void reverseTestSimpleTableModel() throws IOException {
-    
-        val adocRef = _Strings.readFromResource(this.getClass(), "table-simple.adoc", StandardCharsets.UTF_8);
-        val asciidoctor = Asciidoctor.Factory.create();
-        val refDoc = asciidoctor.load(adocRef, new HashMap<String, Object>());
-        
-        String actualAdoc = AsciiDocWriter.toString(refDoc);
-        
-        //debug((Table)refDoc.getBlocks().get(0));
-        
-        //System.out.println(actualAdoc); //debug
-        
-        _Text.assertTextEquals(adocRef, actualAdoc);
-    }
-    
-    @Test
-    void testAttributedTableModel() throws IOException {
-    
-        val adocRef = _Strings.readFromResource(this.getClass(), "table-attributed.adoc", StandardCharsets.UTF_8);
-        val asciidoctor = Asciidoctor.Factory.create();
-        val refDoc = asciidoctor.load(adocRef, new HashMap<String, Object>());
-        
-        String actualAdoc = AsciiDocWriter.toString(refDoc);
-        
-        //debug(refDoc);
-        
-        //System.out.println(actualAdoc); // debug
-        
-        _Text.assertTextEquals(adocRef, actualAdoc);
-    }
-    
-    @SuppressWarnings("unused")
-    private static void debug(Table refTable) {
-        val refCol = refTable.getColumns().get(0);
-        val refRow = refTable.getBody().get(0);
-        val refCell = refRow.getCells().get(0);
-        
-        val refHead = refTable.getHeader().get(0);
-        
-        
-        System.out.println("tab attrib: " + refTable.getAttributes());
-        System.out.println("tab caption: " + refTable.getCaption());
-        System.out.println("tab title: " + refTable.getTitle());
-        
-        System.out.println("col attrib: " + refCol.getAttributes());
-        System.out.println("col context: " + refCol.getContext());
-        System.out.println("col id: " + refCol.getId());
-        System.out.println("col reftex: " + refCol.getReftext());
-        System.out.println("col nodeName: " + refCol.getNodeName());
-        System.out.println("col role: " + refCol.getRole());
-        
-        
-        System.out.println("cell source: " + refCell.getSource());
-        
-        System.out.println("head source: " + refHead.getCells().get(0).getSource());
-    }
-    
-    @SuppressWarnings("unused")
-    private static void debug(org.asciidoctor.ast.List refList) {
-        System.out.println("list blocks: " + refList.getBlocks());
-        System.out.println("list items: " + refList.getItems());
-        System.out.println("list level: " + refList.getLevel());
-        for(val item0 : refList.getItems()) {
-            val item = (ListItem) item0;
-            System.out.println("\t *");
-            System.out.println("\t item level: " + item.getLevel());
-            System.out.println("\t item class: " + item.getClass());
-            System.out.println("\t item caption: " + item.getCaption());
-            System.out.println("\t item nodename: " + item.getNodeName());
-            System.out.println("\t item source: " + item.getSource());
-            System.out.println("\t item blocks: " + item.getBlocks());
-            _NullSafe.stream(item.getBlocks())
-            .forEach(block->debug((org.asciidoctor.ast.List)block));
-        }
-        
-    }
-    
-
-}
diff --git a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AttributedTableTest.java b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AttributedTableTest.java
new file mode 100644
index 0000000..8e9bba1
--- /dev/null
+++ b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/AttributedTableTest.java
@@ -0,0 +1,63 @@
+/*
+ *  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.
+ */
+package org.apache.isis.tooling.adocmodel.test;
+
+import java.io.IOException;
+
+import org.asciidoctor.ast.Document;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.cell;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.doc;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.headCell;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.table;
+
+import lombok.val;
+
+class AttributedTableTest extends AbstractAsciiDocWriterTest {
+
+    private Document doc;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        doc = doc();
+        super.adocSourceResourceLocation = "table-attributed.adoc";
+        super.debugEnabled = false;
+    }
+
+    @Test
+    void testTable() throws IOException {
+        
+        val table = table(doc);
+        table.setTitle("Some table");
+        table.setAttribute("cols", "3m,2a", true);
+        table.setAttribute("header-option", "", true);
+        
+        headCell(table, 0, 0, "Col-1");
+        headCell(table, 0, 1, "Col-2");
+        
+        cell(table, 0, 0, "1-1");
+        cell(table, 0, 1, "1-2");
+        
+        assertDocumentIsCorrectlyWritten(doc);
+    }
+    
+
+}
diff --git a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/DocumentHeaderTest.java b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/DocumentHeaderTest.java
new file mode 100644
index 0000000..ca08df0
--- /dev/null
+++ b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/DocumentHeaderTest.java
@@ -0,0 +1,59 @@
+/*
+ *  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.
+ */
+package org.apache.isis.tooling.adocmodel.test;
+
+import java.io.IOException;
+
+import org.asciidoctor.ast.Document;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.attrNotice;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.block;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.doc;
+
+class DocumentHeaderTest extends AbstractAsciiDocWriterTest {
+
+    private Document doc;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        doc = doc();
+        super.adocSourceResourceLocation = "document-header.adoc";
+        super.debugEnabled = false;
+    }
+
+    //= Sample
+    //:Notice: my special license
+    //
+    //hi
+    @Test
+    void testDocHeader() throws IOException {
+        
+        doc.setTitle("Sample");
+        
+        attrNotice(doc, "my special license");
+        
+        block(doc).getLines().add("hi");
+        
+        assertDocumentIsCorrectlyWritten(doc);
+    }
+    
+
+}
diff --git a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/FootnoteTest.java b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/FootnoteTest.java
index 931eb18..952f788 100644
--- a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/FootnoteTest.java
+++ b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/FootnoteTest.java
@@ -19,32 +19,29 @@
 package org.apache.isis.tooling.adocmodel.test;
 
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
 
-import org.asciidoctor.Asciidoctor;
 import org.asciidoctor.ast.Document;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import org.apache.isis.commons.internal.base._Strings;
-import org.apache.isis.commons.internal.base._Text;
 import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
-import org.apache.isis.tooling.model4adoc.AsciiDocWriter;
 
 import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.doc;
 
 import lombok.val;
 
-class FootnoteTest {
+class FootnoteTest extends AbstractAsciiDocWriterTest {
 
     private Document doc;
 
     @BeforeEach
     void setUp() throws Exception {
         doc = doc();
+        super.adocSourceResourceLocation = "footnote.adoc";
+        super.debugEnabled = false;
     }
 
+    
     //<.> fn-1
     //+
     //--
@@ -87,29 +84,10 @@ class FootnoteTest {
         
         AsciiDocFactory.tip(doc, "Here's something worth knowing...");
         
-        String actualAdoc = AsciiDocWriter.toString(doc);
-        System.out.println(actualAdoc); //debug
-        
-        _Text.assertTextEquals(
-                _Text.readLinesFromResource(this.getClass(), "footnote.adoc", StandardCharsets.UTF_8), 
-                actualAdoc);
+        assertDocumentIsCorrectlyWritten(doc);
     }
     
-    @Test //@Disabled
-    void reverseTestFootnote() throws IOException {
-    
-        val adocRef = _Strings.readFromResource(this.getClass(), "footnote.adoc", StandardCharsets.UTF_8);
-        val asciidoctor = Asciidoctor.Factory.create();
-        val refDoc = asciidoctor.load(adocRef, new HashMap<String, Object>());
-        
-        Debug.debug(refDoc);
-        
-        String actualAdoc = AsciiDocWriter.toString(refDoc);
-        System.out.println(actualAdoc); //debug
-        
-        _Text.assertTextEquals(adocRef, actualAdoc);
-    }
-    
-    
+
 
 }
+
diff --git a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/NestedListTest.java b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/NestedListTest.java
new file mode 100644
index 0000000..1940d1c
--- /dev/null
+++ b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/NestedListTest.java
@@ -0,0 +1,67 @@
+/*
+ *  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.
+ */
+package org.apache.isis.tooling.adocmodel.test;
+
+import java.io.IOException;
+
+import org.asciidoctor.ast.Document;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.doc;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.list;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.listItem;
+
+import lombok.val;
+
+class NestedListTest extends AbstractAsciiDocWriterTest {
+
+    private Document doc;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        doc = doc();
+        super.adocSourceResourceLocation = "list-nested.adoc";
+        super.debugEnabled = false;
+    }
+
+    @SuppressWarnings("unused")
+    @Test
+    void testList() throws IOException {
+        
+        val list = list(doc);
+        list.setTitle("NestedList");
+        
+        val item1 = listItem(list, "Item-1");
+        val item2 = listItem(list, "Item-2");
+        
+        val list1 = list(item1);
+        
+        val item11 = listItem(list1, "Item-1-1");
+        val item12 = listItem(list1, "Item-1-2");
+        
+        val list12 = list(item12);
+        
+        val item121 = listItem(list12, "Item-1-2-1");
+        
+        assertDocumentIsCorrectlyWritten(doc);
+    }
+    
+
+}
diff --git a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/OpenBlockTest.java b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/OpenBlockTest.java
new file mode 100644
index 0000000..acaab07
--- /dev/null
+++ b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/OpenBlockTest.java
@@ -0,0 +1,89 @@
+/*
+ *  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.
+ */
+package org.apache.isis.tooling.adocmodel.test;
+
+import java.io.IOException;
+
+import org.asciidoctor.ast.Document;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
+
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.block;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.doc;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.list;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.listItem;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.openBlock;
+
+import lombok.val;
+
+class OpenBlockTest extends AbstractAsciiDocWriterTest {
+
+    private Document doc;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        doc = doc();
+        super.adocSourceResourceLocation = "list-open-block-continuation.adoc";
+        super.debugEnabled = true;
+    }
+
+    //* ListItem 1
+    //+
+    //--
+    //Here's an example of a document title:
+    //
+    //----
+    //= Document Title
+    //----
+    //
+    //NOTE: The header is optional.
+    //--
+    //* ListItem 2
+    //+
+    //--
+    //paragr 1 
+    //
+    //paragr 2
+    //--
+    @SuppressWarnings("unused")
+    @Test
+    void testOpenBlock() throws IOException {
+        
+        val list = list(doc);
+        
+        val item1 = listItem(list, "ListItem 1");
+        val item2 = listItem(list, "ListItem 2");
+        
+        val openBlock1 = openBlock(item1);
+        val openBlock2 = openBlock(item2);
+        
+        val block11 = block(openBlock1, "Here's an example of a document title:");
+        val block12 = AsciiDocFactory.listingBlock(openBlock1, "= Document Title");
+        val block13 = block(openBlock1, "NOTE: The header is optional.");
+        
+        val block21 = block(openBlock2, "paragr 1");
+        val block22 = block(openBlock2, "paragr 2");
+        
+        assertDocumentIsCorrectlyWritten(doc);
+    }
+    
+
+}
diff --git a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/SimpleListTest.java b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/SimpleListTest.java
new file mode 100644
index 0000000..b68a4ca
--- /dev/null
+++ b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/SimpleListTest.java
@@ -0,0 +1,57 @@
+/*
+ *  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.
+ */
+package org.apache.isis.tooling.adocmodel.test;
+
+import java.io.IOException;
+
+import org.asciidoctor.ast.Document;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.doc;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.list;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.listItem;
+
+import lombok.val;
+
+class SimpleListTest extends AbstractAsciiDocWriterTest {
+
+    private Document doc;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        doc = doc();
+        super.adocSourceResourceLocation = "list-simple.adoc";
+        super.debugEnabled = false;
+    }
+
+    @Test
+    void testList() throws IOException {
+        
+        val list = list(doc);
+        list.setTitle("SimpleList");
+        
+        listItem(list, "Item-1");
+        listItem(list, "Item-2");
+        
+        assertDocumentIsCorrectlyWritten(doc);
+    }
+    
+
+}
diff --git a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/SimpleTableTest.java b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/SimpleTableTest.java
new file mode 100644
index 0000000..9cc568a
--- /dev/null
+++ b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/SimpleTableTest.java
@@ -0,0 +1,67 @@
+/*
+ *  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.
+ */
+package org.apache.isis.tooling.adocmodel.test;
+
+import java.io.IOException;
+
+import org.asciidoctor.ast.Document;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.cell;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.doc;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.headCell;
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.table;
+
+import lombok.val;
+
+class SimpleTableTest extends AbstractAsciiDocWriterTest {
+
+    private Document doc;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        doc = doc();
+        super.adocSourceResourceLocation = "table-simple.adoc";
+        super.debugEnabled = false;
+    }
+
+    @Test
+    void testTable() throws IOException {
+        
+        val table = table(doc);
+        table.setTitle("Table");
+        
+        headCell(table, 0, 0, "Col-1");
+        headCell(table, 0, 1, "Col-2");
+        headCell(table, 0, 2, "Col-3");
+        
+        cell(table, 0, 0, "1-1");
+        cell(table, 0, 1, "1-2");
+        cell(table, 0, 2, "1-3");
+        
+        cell(table, 1, 0, "2-1");
+        cell(table, 1, 1, "2-2");
+        cell(table, 1, 2, "2-3");
+        
+        assertDocumentIsCorrectlyWritten(doc);
+    }
+    
+
+}
diff --git a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/Debug.java b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/_Debug.java
similarity index 62%
rename from tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/Debug.java
rename to tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/_Debug.java
index 45a8f32..3ba8337 100644
--- a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/Debug.java
+++ b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/adocmodel/test/_Debug.java
@@ -31,7 +31,7 @@ import org.apache.isis.commons.internal.exceptions._Exceptions;
 
 import lombok.val;
 
-final class Debug {
+final class _Debug {
     
     static void debug(Document node) {
         debug(node, 0);
@@ -50,6 +50,7 @@ final class Debug {
         .forEach((k, v)->{
             print(level+1, " - %s->%s", k, v);
         });
+        printAdditionalFor(node, level);
         
         if(node.getBlocks().size()>0) {
             print(level, "%s child blocks: %d ...", simpleName, node.getBlocks().size());
@@ -82,6 +83,56 @@ final class Debug {
         throw _Exceptions.unsupportedOperation("node type not supported %s", node.getClass());
     }
 
+    private static void printAdditionalFor(StructuralNode node, int level) {
+        if(node instanceof Document) {
+            //((Document)node);
+            return;
+        }
+        if(node instanceof Table) {
+            debug((Table)node, level);
+            return;
+        }
+        if(node instanceof org.asciidoctor.ast.List) {
+            debug((org.asciidoctor.ast.List)node, level);
+            return;
+        }
+        if(node instanceof ListItem) {
+            //Optional.ofNullable(((ListItem)node).getSource());
+            return;
+        }
+        if(node instanceof Block) {
+            return;
+        }    
+        throw _Exceptions.unsupportedOperation("node type not supported %s", node.getClass());
+    }
+    
+    private static void debug(Table table, int level) {
+        val refCol = table.getColumns().get(0);
+        val refRow = table.getBody().get(0);
+        val refCell = refRow.getCells().get(0);
+        
+        val refHead = table.getHeader().get(0);
+        
+        print(level, "tab caption: " + table.getCaption());
+        
+        print(level, "col attrib: " + refCol.getAttributes());
+        print(level, "col context: " + refCol.getContext());
+        print(level, "col id: " + refCol.getId());
+        print(level, "col reftex: " + refCol.getReftext());
+        print(level, "col nodeName: " + refCol.getNodeName());
+        print(level, "col role: " + refCol.getRole());
+       
+        print(level, "cell source: " + refCell.getSource());
+        
+        print(level, "head source: " + refHead.getCells().get(0).getSource());
+    }
+    
+    private static void debug(org.asciidoctor.ast.List list, int level) {
+        print(level, "%d list blocks: ", list.getBlocks().size());
+        print(level, "%d list items: ", list.getItems().size());
+        print(level, "%d list level: ", list.getLevel());
+    }
+    
     private static void print(int level, String format, Object... args) {
         val indent = _Strings.padEnd("", level*2, ' ');
         System.out.println(String.format("%s%s", indent, String.format(format, args)));