+(defvar *error-count* 0)
+
+(defun run-tests-append-report-file (report-file)
+ (with-open-file (out report-file :direction :output
+ :if-exists :append
+ :if-does-not-exist :create)
+ (run-tests out)))
+
+(defun run-tests (&optional (*report-stream* *standard-output*))
+ (let ((specs (read-specs))
+ (*error-count* 0))
+ (unless specs
+ (warn "Not running tests because test configuration file is missing")
+ (return-from run-tests :skipped))
+ (load-necessary-systems specs)
+ (dolist (db-type +all-db-types+)
+ (unless (and (eq db-type :aodbc)
+ (not (member :allegro cl:*features*)))
+ (when (db-type-spec db-type specs)
+ (do-tests-for-backend db-type))))
+ (zerop *error-count*)))
+
+(defun load-necessary-systems (specs)
+ (dolist (db-type +all-db-types+)
+ (when (db-type-spec db-type specs)
+ (db-type-ensure-system db-type))))
+
+(defun do-tests-for-backend (db-type)
+ (test-connect-to-database db-type)
+
+ (unwind-protect
+ (multiple-value-bind (test-forms skip-tests)
+ (compute-tests-for-backend db-type *test-database-underlying-type*)
+
+ (format *report-stream*
+ "~&
+******************************************************************************
+*** CLSQL Test Suite begun at ~A
+*** ~A
+*** ~A
+*** Database ~A backend~A.
+******************************************************************************
+"
+(clsql-base:format-time nil (clsql-base:utime->time (get-universal-time)))
+(lisp-implementation-type)
+(lisp-implementation-version)
+db-type
+(if (not (eq db-type *test-database-underlying-type*))
+ (format nil " with underlying type ~A" *test-database-underlying-type*)
+ "")
+)
+
+ (test-initialise-database)
+
+ (regression-test:rem-all-tests)
+ (dolist (test-form test-forms)
+ (eval test-form))
+
+ (let ((remaining (rtest:do-tests *report-stream*)))
+ (when (consp remaining)
+ (incf *error-count* (length remaining))))
+
+ (format *report-stream* "~&Tests skipped:")
+ (if skip-tests
+ (dolist (skipped skip-tests)
+ (format *report-stream*
+ "~& ~20A ~A~%" (car skipped) (cdr skipped)))
+ (format *report-stream* " None~%")))
+ (disconnect)))