175 lines
6.3 KiB
Common Lisp
175 lines
6.3 KiB
Common Lisp
(in-package :cl-user)
|
|
(defpackage prove.reporter
|
|
(:use :cl)
|
|
(:import-from :prove.report
|
|
:report
|
|
:test-report
|
|
:description)
|
|
(:import-from :prove.output
|
|
:*default-reporter*)
|
|
(:export :*indent-level*
|
|
:indent-space
|
|
:format/indent
|
|
:reporter
|
|
:format-report
|
|
:print-error-report
|
|
:print-plan-report
|
|
:print-finalize-report
|
|
:with-additional-indent))
|
|
(in-package :prove.reporter)
|
|
|
|
(defparameter *indent-level* 0
|
|
"Level for nested test-cases output.
|
|
Number of spaces, added for each indentation level
|
|
is described in reporter's indent-space slot.
|
|
|
|
Also, macro shift-indent could be used to slightly
|
|
indent content inside the main indentation level.
|
|
|
|
full-indent = indent-space * indent-level + additional-indent
|
|
|
|
Here is an example of the output:
|
|
|
|
1| x Blah minor.
|
|
2| Next line of description:
|
|
3|
|
|
4| x Nested test.
|
|
5| Also has multiline description.
|
|
|
|
In this example, indent-space is 4, that is why
|
|
text on lines 1 and 4 have 4 spaces between the 'x'
|
|
horizontally.
|
|
|
|
Outputting the first line \" x \", reporter sets
|
|
*additional-indent* to 4. That is why these additional
|
|
4 lines are prepended to the rest lines of the main
|
|
test case description.
|
|
|
|
When inner testcase runs, it increments *indent-level*,
|
|
which shifts output to another 4 spaces (indent-space)
|
|
to the right, simultaneously resetting *additional-indent*
|
|
to zero.
|
|
|
|
For nested test, reporter writes \" x \" and again,
|
|
sets *additional-indent* to 4 and every other lines now
|
|
shifted by 1 * 4 + 4 = 8 spaces.
|
|
")
|
|
|
|
(defparameter *additional-indent* 0
|
|
"Number of spaces to add to each line. see *indent-level* docstring for full description.")
|
|
|
|
(defvar *debug-indentation* nil
|
|
"If True, then indentation will have '=' and '-' symbols for main indentaion and additional, instead of spaces.")
|
|
|
|
(defun indent (space &optional (count *indent-level*))
|
|
"Creates a string with a number of spaces to indent new line
|
|
of a test report."
|
|
(if *debug-indentation*
|
|
(concatenate 'string
|
|
(make-string (* count space)
|
|
:initial-element #\=)
|
|
(make-string *additional-indent*
|
|
:initial-element #\-))
|
|
(make-string (+ (* count space)
|
|
*additional-indent*)
|
|
:initial-element #\space)))
|
|
|
|
|
|
(defmacro with-additional-indent ((reporter stream control-string &rest format-arguments) &body body)
|
|
(declare (ignorable reporter stream control-string))
|
|
(let* ((need-new-line (ppcre:scan "^~&" control-string))
|
|
(string (apply #'format nil control-string format-arguments))
|
|
(increment (length string)))
|
|
`(with-slots (indent-space) reporter
|
|
(let* ((first-line-indent (indent indent-space))
|
|
(*additional-indent* ,(if need-new-line
|
|
increment
|
|
`(+ *additional-indent*
|
|
,increment))))
|
|
(declare (ignorable first-line-indent))
|
|
,(if need-new-line
|
|
`(progn (fresh-line stream)
|
|
(write-string first-line-indent ,stream)
|
|
;; because we just started a new line, we
|
|
;; should use format/indent to write string
|
|
;; taking into account a main indentation level
|
|
(format/indent ,reporter ,stream ,string))
|
|
;; otherwise, just output our prefix
|
|
`(write-string ,string ,stream))
|
|
|
|
|
|
,@body))))
|
|
|
|
|
|
|
|
(defun format/indent (reporter stream control-string &rest format-arguments)
|
|
"Writes a text to given stream with indentation, dictated by
|
|
*indent-level* and *additional-indent*.
|
|
|
|
If first line start with ~&, then output will start from a fresh line.
|
|
Otherwise, all lines except the first one are indented."
|
|
|
|
(with-slots (indent-space) reporter
|
|
(let ((output (apply #'format nil control-string format-arguments)))
|
|
;; if string starts with new line, then we have to add indentation
|
|
;; otherwise we think it is already written to the stream
|
|
(when (ppcre:scan "^~&" control-string)
|
|
(fresh-line stream)
|
|
(format stream (indent indent-space)))
|
|
|
|
;; if this (?!$) is indended to not insert spaces
|
|
;; into empty lines, then (?m) should be inserted
|
|
;; before
|
|
;; TODO: make a pull-request
|
|
(write-string (ppcre:regex-replace-all
|
|
"(\\n)(?!$)"
|
|
output
|
|
(format nil "\\1~A"
|
|
(indent indent-space)))
|
|
stream))))
|
|
|
|
|
|
(defclass reporter ()
|
|
((indent-space :initform 2)))
|
|
|
|
(defun find-reporter (name)
|
|
(make-instance
|
|
(intern (format nil "~:@(~A~)-~A" name #.(string :reporter))
|
|
(intern (format nil "~A.~:@(~A~)"
|
|
#.(string :prove.reporter)
|
|
name)
|
|
:keyword))))
|
|
|
|
(defgeneric format-report (stream reporter report &rest args)
|
|
(:method (stream (reporter null) (report report) &rest args)
|
|
(apply #'format-report
|
|
stream
|
|
(find-reporter *default-reporter*)
|
|
report
|
|
args))
|
|
(:method (stream (reporter reporter) (report report) &rest args)
|
|
(declare (ignore args))
|
|
(format/indent reporter stream "~&~A~%"
|
|
(slot-value report 'description))))
|
|
|
|
(defgeneric print-error-report (reporter report stream)
|
|
(:method ((reporter reporter) (report report) stream)
|
|
;; Do nothing.
|
|
)
|
|
(:method ((reporter null) (report test-report) stream)
|
|
(print-error-report (find-reporter *default-reporter*) report stream)))
|
|
|
|
(defgeneric print-plan-report (reporter num stream)
|
|
(:method ((reporter null) num stream)
|
|
(print-plan-report (find-reporter *default-reporter*) num stream))
|
|
(:method ((reporter t) num stream)
|
|
(declare (ignore reporter num))
|
|
;; Do nothing
|
|
))
|
|
|
|
(defgeneric print-finalize-report (reporter plan reports stream)
|
|
(:method ((reporter null) plan reports stream)
|
|
(print-finalize-report (find-reporter *default-reporter*)
|
|
plan
|
|
reports
|
|
stream)))
|