diff --git a/TODO.rst b/TODO.rst
index c4066d2..d998844 100644
--- a/TODO.rst
+++ b/TODO.rst
@@ -12,16 +12,15 @@ Cleanup
=======
- A proper public interface to the various artifact classes
+- Expose reader interface to public
Testing
=======
-- Reader
- - Test the reader system in general
- - Test the Lisp reader implementation
- Artifacts
- Come up with a proper artifacts interface
- Test the individual artifact implementations (function `WRITE-ARTIFACT`)
+- Update reader tests to public interface once it is done
Blog
@@ -46,3 +45,17 @@ Cleanup
- How much of each artifact's internals need to be exposed? Make accessor
functions? Constructor functions over `MAKE-INSTANCE`?
- Static page metadata without binding (see comment in definition)
+
+Testing
+=======
+
+Everything
+
+
+CommonMark reader
+#################
+
+Testing
+=======
+
+Everything
diff --git a/hssg.asd b/hssg.asd
index 3abcd71..0b5eabd 100644
--- a/hssg.asd
+++ b/hssg.asd
@@ -56,4 +56,7 @@
:components ((:module "hssg"
:components ((:file "package")
(:file "main")
- (:file "template")))))))
+ (:file "template")
+ (:file "reader")
+ (:module "readers"
+ :components ((:file "lisp")))))))))
diff --git a/src/hssg/package.lisp b/src/hssg/package.lisp
index dcee286..367e263 100644
--- a/src/hssg/package.lisp
+++ b/src/hssg/package.lisp
@@ -21,7 +21,7 @@
(defpackage #:hssg.reader
(:documentation "Interface to the various content readers.")
(:use :cl)
- (:export get-reader register-reader with-readers))
+ (:export get-reader register-reader unregister-reader with-readers))
(defpackage #:hssg.artifact
(:documentation "Helper package, defines the artifact protocl.")
diff --git a/src/hssg/reader.lisp b/src/hssg/reader.lisp
index cbac802..9ff5476 100644
--- a/src/hssg/reader.lisp
+++ b/src/hssg/reader.lisp
@@ -37,6 +37,14 @@
(declare (type string type))
(push (cons type reader) *file-readers*))
+(defun unregister-reader (type)
+ (declare (type string type))
+ (flet ((matches-type-p (entry)
+ (string-equal type (car entry))))
+ (setf *file-readers*
+ (remove-if #'matches-type-p
+ *file-readers*))))
+
(defmacro with-readers ((&rest reader-spec) &body body)
"Evaluate the BODY expressions with temporarily registered readers. Each
reader specification is a list of to elements of the form (TYPE READER). The
diff --git a/test/hssg/package.lisp b/test/hssg/package.lisp
index 8d0caf0..8bf24c6 100644
--- a/test/hssg/package.lisp
+++ b/test/hssg/package.lisp
@@ -20,4 +20,4 @@
(defpackage #:hssg/test
(:documentation "Main test package")
(:use #:cl #:fiveam)
- (:export test-all all-tests))
+ (:export test-all all-tests hssg))
diff --git a/test/hssg/reader.lisp b/test/hssg/reader.lisp
new file mode 100644
index 0000000..f3a4513
--- /dev/null
+++ b/test/hssg/reader.lisp
@@ -0,0 +1,70 @@
+;;;; SPDX-License-Identifier AGPL-3.0-or-later
+
+;;;; compound.lisp Compound artifact implementation
+;;;; Copyright (C) 2022 Alejandro "HiPhish" Sanchez
+;;;;
+;;;; This file is part of CL-HSSG.
+;;;;
+;;;; CL-HSSG is free software: you can redistribute it and/or modify it under
+;;;; the terms of the GNU Affero General Public License as published by the
+;;;; Free Software Foundation, either version 3 of the License, or (at your
+;;;; option) any later version.
+;;;;
+;;;; CL-HSSG is distributed in the hope that it will be useful, but WITHOUT ANY
+;;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+;;;; FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+;;;; more details.
+;;;;
+;;;; You should have received a copy of the GNU Affero General Public License
+;;;; along with CL-HSSG If not, see .(in-package #:hssg.artifact)
+(defpackage #:hssg/test/reader
+ (:use #:cl))
+(in-package #:hssg/test/reader)
+
+(defun dummy-reader (pathname)
+ "A dummy reader which does nothing useful."
+ (declare (ignore pathname))
+ '())
+
+(fiveam:def-suite hssg/reader
+ :description "Tests for the reader interface"
+ :in hssg/test:hssg)
+
+(fiveam:in-suite hssg/reader)
+
+(fiveam:test retrieve-reader
+ "A registered reader can be retrieved by its type"
+ (let ((hssg.reader::*file-readers* `(("foo" . ,#'dummy-reader))))
+ (fiveam:is-true (eq #'dummy-reader (hssg.reader:get-reader "foo")))))
+
+(fiveam:test retrieve-missing-reader
+ "Retrieving a reader that has not been registered signals a condition"
+ (let ((hssg.reader::*file-readers* '()))
+ (fiveam:signals (error)
+ (hssg.reader:get-reader "foo"))))
+
+(fiveam:test add-reader
+ "A new reader can be added by file type"
+ (let ((original hssg.reader::*file-readers*))
+ (unwind-protect
+ (progn
+ (hssg.reader:register-reader "foo" #'dummy-reader)
+ (fiveam:is-true (eq #'dummy-reader (hssg.reader:get-reader "foo"))))
+ (setf hssg.reader::*file-readers* original))))
+
+(fiveam:test remove-reader
+ "An added reader can be removed"
+ (let ((original hssg.reader::*file-readers*))
+ (unwind-protect
+ (progn
+ (hssg.reader:register-reader "foo" #'dummy-reader)
+ (hssg.reader:unregister-reader "foo")
+ (fiveam:is-true (equal original hssg.reader::*file-readers*)))
+ (setf hssg.reader::*file-readers* original))))
+
+(fiveam:test temporary-reader
+ "Register a reader for the duration of the body expressions only"
+ (hssg.reader:with-readers (("foo" #'dummy-reader))
+ (fiveam:is-true (eq #'dummy-reader (hssg.reader:get-reader "foo"))))
+ (fiveam:signals (error)
+ (hssg.reader:get-reader "foo")))
diff --git a/test/hssg/readers/lisp.lisp b/test/hssg/readers/lisp.lisp
new file mode 100644
index 0000000..1129494
--- /dev/null
+++ b/test/hssg/readers/lisp.lisp
@@ -0,0 +1,49 @@
+;;;; SPDX-License-Identifier AGPL-3.0-or-later
+
+;;;; compound.lisp Compound artifact implementation
+;;;; Copyright (C) 2022 Alejandro "HiPhish" Sanchez
+;;;;
+;;;; This file is part of CL-HSSG.
+;;;;
+;;;; CL-HSSG is free software: you can redistribute it and/or modify it under
+;;;; the terms of the GNU Affero General Public License as published by the
+;;;; Free Software Foundation, either version 3 of the License, or (at your
+;;;; option) any later version.
+;;;;
+;;;; CL-HSSG is distributed in the hope that it will be useful, but WITHOUT ANY
+;;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+;;;; FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+;;;; more details.
+;;;;
+;;;; You should have received a copy of the GNU Affero General Public License
+;;;; along with CL-HSSG If not, see .(in-package #:hssg.artifact)
+(defpackage #:hssg/test/reader/lisp
+ (:use #:cl))
+(in-package #:hssg/test/reader/lisp)
+
+(fiveam:def-suite hssg/reader/lisp
+ :description "Tests for the Lisp reader"
+ :in hssg/test:hssg)
+
+(fiveam:in-suite hssg/reader/lisp)
+
+(fiveam:test lisp-reader-is-registered
+ "The Lisp reader is registered by default"
+ (fiveam:is-true (eq (hssg.reader:get-reader "lisp") #'hssg.reader.lisp::read-lisp-metadata)))
+
+(fiveam:test lisp-reader-can-read-files
+ "The Lisp reader can read the contents of a Lisp file"
+ (let* ((reader (hssg.reader:get-reader "lisp"))
+ (data (funcall reader "test/hssg/sample-files/metadata.lisp")))
+ (hssg:let-metadata data ((foo :foo)
+ (bar :bar)
+ (baz :baz))
+ (fiveam:is-true (string-equal "foo" foo))
+ (fiveam:is-true (string-equal "bar" bar))
+ (fiveam:is-true (string-equal "baz" baz)))))
+
+(fiveam:test lisp-reader-does-not-pollute
+ "The Lisp reader does not leak symbols from the file"
+ (let* ((reader (hssg.reader:get-reader "lisp")))
+ (funcall reader "test/hssg/sample-files/metadata.lisp")
+ (fiveam:is-true (null (find-symbol "THROWAWAY-FUNCTION")))))
diff --git a/test/hssg/sample-files/metadata.lisp b/test/hssg/sample-files/metadata.lisp
new file mode 100644
index 0000000..6f3581b
--- /dev/null
+++ b/test/hssg/sample-files/metadata.lisp
@@ -0,0 +1,7 @@
+(defun throwaway-function ()
+ "This function must not leak out of this file"
+ "foo")
+
+`((:foo . ,(throwaway-function))
+ (:bar . "bar")
+ (:baz . "baz"))