clucumber 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +4 -9
  3. data/lib/clucumber/clucumber-bootstrap.lisp +32 -0
  4. data/lib/clucumber/vendor/cl-interpol/alias.lisp +55 -0
  5. data/lib/clucumber/vendor/cl-interpol/cl-interpol.asd +56 -0
  6. data/lib/clucumber/vendor/cl-interpol/load.lisp +53 -0
  7. data/lib/clucumber/vendor/cl-interpol/packages.lisp +40 -0
  8. data/lib/clucumber/vendor/cl-interpol/read.lisp +716 -0
  9. data/lib/clucumber/vendor/cl-interpol/specials.lisp +113 -0
  10. data/lib/clucumber/vendor/cl-interpol/test/packages.lisp +34 -0
  11. data/lib/clucumber/vendor/cl-interpol/test/tests.lisp +128 -0
  12. data/lib/clucumber/vendor/cl-interpol/test.lisp +177 -0
  13. data/lib/clucumber/vendor/cl-interpol/test2.lisp +6254 -0
  14. data/lib/clucumber/vendor/cl-interpol/unicode.lisp +13912 -0
  15. data/lib/clucumber/vendor/cl-interpol/util.lisp +122 -0
  16. data/lib/clucumber/vendor/cl-ppcre/api.lisp +1262 -0
  17. data/lib/clucumber/vendor/cl-ppcre/charmap.lisp +152 -0
  18. data/lib/clucumber/vendor/cl-ppcre/charset.lisp +242 -0
  19. data/lib/clucumber/vendor/cl-ppcre/chartest.lisp +98 -0
  20. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-test.asd +34 -0
  21. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode/packages.lisp +38 -0
  22. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode/resolver.lisp +61 -0
  23. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode.asd +58 -0
  24. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre.asd +79 -0
  25. data/lib/clucumber/vendor/cl-ppcre/closures.lisp +471 -0
  26. data/lib/clucumber/vendor/cl-ppcre/convert.lisp +875 -0
  27. data/lib/clucumber/vendor/cl-ppcre/errors.lisp +84 -0
  28. data/lib/clucumber/vendor/cl-ppcre/lexer.lisp +737 -0
  29. data/lib/clucumber/vendor/cl-ppcre/lispworks-defsystem.lisp +57 -0
  30. data/lib/clucumber/vendor/cl-ppcre/load.lisp +67 -0
  31. data/lib/clucumber/vendor/cl-ppcre/optimize.lisp +578 -0
  32. data/lib/clucumber/vendor/cl-ppcre/packages.lisp +68 -0
  33. data/lib/clucumber/vendor/cl-ppcre/parser.lisp +319 -0
  34. data/lib/clucumber/vendor/cl-ppcre/ppcre-tests.lisp +269 -0
  35. data/lib/clucumber/vendor/cl-ppcre/regex-class-util.lisp +555 -0
  36. data/lib/clucumber/vendor/cl-ppcre/regex-class.lisp +259 -0
  37. data/lib/clucumber/vendor/cl-ppcre/repetition-closures.lisp +833 -0
  38. data/lib/clucumber/vendor/cl-ppcre/scanner.lisp +506 -0
  39. data/lib/clucumber/vendor/cl-ppcre/specials.lisp +172 -0
  40. data/lib/clucumber/vendor/cl-ppcre/test/packages.lisp +37 -0
  41. data/lib/clucumber/vendor/cl-ppcre/test/perl-tests.lisp +150 -0
  42. data/lib/clucumber/vendor/cl-ppcre/test/tests.lisp +159 -0
  43. data/lib/clucumber/vendor/cl-ppcre/test/unicode-tests.lisp +80 -0
  44. data/lib/clucumber/vendor/cl-ppcre/util.lisp +201 -0
  45. data/lib/clucumber/vendor/cl-unicode/alias.lisp +135 -0
  46. data/lib/clucumber/vendor/cl-unicode/api.lisp +412 -0
  47. data/lib/clucumber/vendor/cl-unicode/build/char-info.lisp +133 -0
  48. data/lib/clucumber/vendor/cl-unicode/build/dump.lisp +239 -0
  49. data/lib/clucumber/vendor/cl-unicode/build/read.lisp +280 -0
  50. data/lib/clucumber/vendor/cl-unicode/build/util.lisp +182 -0
  51. data/lib/clucumber/vendor/cl-unicode/cl-unicode.asd +90 -0
  52. data/lib/clucumber/vendor/cl-unicode/conditions.lisp +54 -0
  53. data/lib/clucumber/vendor/cl-unicode/derived.lisp +120 -0
  54. data/lib/clucumber/vendor/cl-unicode/hash-tables.lisp +20 -0
  55. data/lib/clucumber/vendor/cl-unicode/lists.lisp +10 -0
  56. data/lib/clucumber/vendor/cl-unicode/methods.lisp +15 -0
  57. data/lib/clucumber/vendor/cl-unicode/packages.lisp +76 -0
  58. data/lib/clucumber/vendor/cl-unicode/specials.lisp +135 -0
  59. data/lib/clucumber/vendor/cl-unicode/test/packages.lisp +34 -0
  60. data/lib/clucumber/vendor/cl-unicode/test/tests.lisp +150 -0
  61. data/lib/clucumber/vendor/cl-unicode/test-functions.lisp +94 -0
  62. data/lib/clucumber/vendor/cl-unicode/util.lisp +274 -0
  63. data/lib/clucumber/vendor/lift/compare/fiveam-tests.lisp +14 -0
  64. data/lib/clucumber/vendor/lift/compare/lift-tests.lisp +13 -0
  65. data/lib/clucumber/vendor/lift/compare/rt-tests.lisp +16 -0
  66. data/lib/clucumber/vendor/lift/compare/xlunit-tests.lisp +15 -0
  67. data/lib/clucumber/vendor/lift/dev/changes.lisp +61 -0
  68. data/lib/clucumber/vendor/lift/dev/config.lisp +354 -0
  69. data/lib/clucumber/vendor/lift/dev/copy-file.lisp +117 -0
  70. data/lib/clucumber/vendor/lift/dev/introspection.lisp +232 -0
  71. data/lib/clucumber/vendor/lift/dev/lift-interface.lisp +56 -0
  72. data/lib/clucumber/vendor/lift/dev/lift-notes.lisp +202 -0
  73. data/lib/clucumber/vendor/lift/dev/lift-randomized.lisp +45 -0
  74. data/lib/clucumber/vendor/lift/dev/lift.lisp +2383 -0
  75. data/lib/clucumber/vendor/lift/dev/macros.lisp +229 -0
  76. data/lib/clucumber/vendor/lift/dev/measuring.lisp +156 -0
  77. data/lib/clucumber/vendor/lift/dev/packages.lisp +161 -0
  78. data/lib/clucumber/vendor/lift/dev/port.lisp +151 -0
  79. data/lib/clucumber/vendor/lift/dev/prototypes.lisp +282 -0
  80. data/lib/clucumber/vendor/lift/dev/random-testing.lisp +124 -0
  81. data/lib/clucumber/vendor/lift/dev/report-locations.lisp +13 -0
  82. data/lib/clucumber/vendor/lift/dev/reports.lisp +916 -0
  83. data/lib/clucumber/vendor/lift/dev/utilities.lisp +242 -0
  84. data/lib/clucumber/vendor/lift/docs/package.lisp +6 -0
  85. data/lib/clucumber/vendor/lift/docs/setup.lisp +17 -0
  86. data/lib/clucumber/vendor/lift/examples/basic-examples.lisp +289 -0
  87. data/lib/clucumber/vendor/lift/examples/random-testing.lisp +32 -0
  88. data/lib/clucumber/vendor/lift/lift-documentation.asd +28 -0
  89. data/lib/clucumber/vendor/lift/lift-test.asd +35 -0
  90. data/lib/clucumber/vendor/lift/lift.asd +77 -0
  91. data/lib/clucumber/vendor/lift/test/equality-tests.lisp +40 -0
  92. data/lib/clucumber/vendor/lift/test/finding-tests.lisp +32 -0
  93. data/lib/clucumber/vendor/lift/test/lift-test.lisp +783 -0
  94. data/lib/clucumber/vendor/lift/test/order-of-operations.lisp +54 -0
  95. data/lib/clucumber/vendor/lift/test/packages.lisp +17 -0
  96. data/lib/clucumber/vendor/lift/test/test-config-files.lisp +20 -0
  97. data/lib/clucumber/vendor/lift/test/test-dynamic-variables.lisp +57 -0
  98. data/lib/clucumber/vendor/lift/test/test-maximum-problems.lisp +74 -0
  99. data/lib/clucumber/vendor/lift/test/test-prototypes.lisp +278 -0
  100. data/lib/clucumber/vendor/lift/test/test-timeout.lisp +37 -0
  101. data/lib/clucumber/vendor/lift/test/tests-in-progress.lisp +62 -0
  102. data/lib/clucumber/vendor/lift/test/testsuite-expects.lisp +60 -0
  103. data/lib/clucumber/vendor/lift/timeout/package.lisp +13 -0
  104. data/lib/clucumber/vendor/lift/timeout/with-timeout.lisp +123 -0
  105. data/lib/clucumber/vendor/lift/website/stuff/Temp.lisp +34 -0
  106. data/lib/clucumber/vendor/st-json/st-json.asd +3 -0
  107. data/lib/clucumber/vendor/st-json/st-json.lisp +310 -0
  108. data/lib/clucumber/vendor/trivial-backtrace/dev/backtrace.lisp +127 -0
  109. data/lib/clucumber/vendor/trivial-backtrace/dev/fallback.lisp +10 -0
  110. data/lib/clucumber/vendor/trivial-backtrace/dev/map-backtrace.lisp +103 -0
  111. data/lib/clucumber/vendor/trivial-backtrace/dev/mucking.lisp +75 -0
  112. data/lib/clucumber/vendor/trivial-backtrace/dev/packages.lisp +13 -0
  113. data/lib/clucumber/vendor/trivial-backtrace/dev/utilities.lisp +104 -0
  114. data/lib/clucumber/vendor/trivial-backtrace/test/packages.lisp +5 -0
  115. data/lib/clucumber/vendor/trivial-backtrace/test/test-setup.lisp +4 -0
  116. data/lib/clucumber/vendor/trivial-backtrace/test/tests.lisp +16 -0
  117. data/lib/clucumber/vendor/trivial-backtrace/trivial-backtrace-test.asd +22 -0
  118. data/lib/clucumber/vendor/trivial-backtrace/trivial-backtrace.asd +35 -0
  119. data/lib/clucumber/vendor/usocket/backend/allegro.lisp +199 -0
  120. data/lib/clucumber/vendor/usocket/backend/armedbear.lisp +491 -0
  121. data/lib/clucumber/vendor/usocket/backend/clisp.lisp +260 -0
  122. data/lib/clucumber/vendor/usocket/backend/cmucl.lisp +266 -0
  123. data/lib/clucumber/vendor/usocket/backend/lispworks.lisp +741 -0
  124. data/lib/clucumber/vendor/usocket/backend/mcl.lisp +369 -0
  125. data/lib/clucumber/vendor/usocket/backend/openmcl.lisp +206 -0
  126. data/lib/clucumber/vendor/usocket/backend/sbcl.lisp +424 -0
  127. data/lib/clucumber/vendor/usocket/backend/scl.lisp +261 -0
  128. data/lib/clucumber/vendor/usocket/condition.lisp +227 -0
  129. data/lib/clucumber/vendor/usocket/package.lisp +82 -0
  130. data/lib/clucumber/vendor/usocket/server.lisp +45 -0
  131. data/lib/clucumber/vendor/usocket/test/package.lisp +13 -0
  132. data/lib/clucumber/vendor/usocket/test/test-usocket.lisp +166 -0
  133. data/lib/clucumber/vendor/usocket/usocket-test.asd +26 -0
  134. data/lib/clucumber/vendor/usocket/usocket.asd +37 -0
  135. data/lib/clucumber/vendor/usocket/usocket.lisp +542 -0
  136. data/lib/clucumber/vendor/usocket/vendor/kqueue.lisp +1 -0
  137. data/lib/clucumber/vendor/usocket/vendor/split-sequence.lisp +245 -0
  138. data/lib/clucumber.rb +29 -7
  139. metadata +151 -5
@@ -0,0 +1,916 @@
1
+ (in-package #:lift)
2
+
3
+ ;; dribble
4
+ ;; full output for all tests on separate pages per suite? whatever.
5
+ ;; test environment
6
+
7
+ #|
8
+ For *standard-input*: an input stream
9
+
10
+ For *error-output*, *standard-output*, and *trace-output*: an output stream.
11
+
12
+ For *debug-io*, *query-io*: a bidirectional stream.
13
+ |#
14
+
15
+ #|
16
+ (progn
17
+ (setf (test-result-property *test-result* :style-sheet) "test-style.css")
18
+ (setf (test-result-property *test-result* :title) "Test Results X")
19
+ (setf (test-result-property *test-result* :if-exists) :supersede)
20
+ (test-result-report *test-result* #p"/tmp/report.html" :html))
21
+
22
+ lift::(progn
23
+ (setf (test-result-property *test-result* :style-sheet) "test-style.css")
24
+ (setf (test-result-property *test-result* :title) "Merge LUBM 8000")
25
+ (setf (test-result-property *test-result* :if-exists) :error)
26
+ (test-result-report *test-result* #p "/fi/internal/people/gwking/agraph/testing/report/" :html))
27
+
28
+ lift::(progn
29
+ (setf (test-result-property *test-result* :style-sheet) "test-style.css")
30
+ (setf (test-result-property *test-result* :title) "lubm-50")
31
+ (setf (test-result-property *test-result* :unique-name) t)
32
+ (test-result-report *test-result* #p "/fi/internal/people/gwking/agraph/testing/report/2008-08-21-lubm-50-prolog" :html))
33
+
34
+ lift::(progn
35
+ (setf (test-result-property *test-result* :style-sheet)
36
+ "test-style.css")
37
+ (setf (test-result-property *test-result* :title)
38
+ "Ugh")
39
+ (setf (test-result-property *test-result* :if-exists)
40
+ :error)
41
+ (test-result-report *test-result* #p"report-20080813a.sav" :save))
42
+
43
+ (run-tests :suite '(lift-test test-cursors))
44
+
45
+ (run-tests :suite 'lift-test-ensure)
46
+
47
+ (test-result-property *test-result* :title)
48
+ |#
49
+
50
+
51
+ (defgeneric start-report-output (result stream format)
52
+ )
53
+
54
+ (defgeneric summarize-test-result (result stream format)
55
+ )
56
+
57
+ (defgeneric summarize-test-environment (result stream format)
58
+ )
59
+
60
+ (defgeneric summarize-test-problems (result stream format)
61
+ )
62
+
63
+ (defgeneric summarize-test-problems-of-type
64
+ (problems stream id heading)
65
+ )
66
+
67
+ (defgeneric summarize-single-test
68
+ (format suite-name test-case-name data &key stream)
69
+ )
70
+
71
+ (defgeneric generate-detailed-reports (result stream format)
72
+ )
73
+
74
+ (defgeneric summarize-tests-run (result stream format)
75
+ )
76
+
77
+ (defgeneric end-report-output (result stream format)
78
+ )
79
+
80
+ (defgeneric html-header (stream title style-sheet)
81
+ )
82
+
83
+ ;; when it doubt, add a special
84
+ (defvar *report-environment* nil
85
+ "Used internally by LIFT reports.")
86
+
87
+ (defun make-report-environment ()
88
+ nil)
89
+
90
+ ;; env variables need to be part saved in result
91
+
92
+ (defgeneric test-result-report (result output format
93
+ &key package &allow-other-keys)
94
+ )
95
+
96
+ (defmethod test-result-report (result output format
97
+ &rest args
98
+ &key (package *package*) &allow-other-keys)
99
+ (declare (ignore args))
100
+ (let ((*report-environment* (make-report-environment))
101
+ (*package* (or (find-package package) *package*)))
102
+ (cond ((or (stringp output)
103
+ (pathnamep output))
104
+ (with-open-file (stream
105
+ output
106
+ :direction :output
107
+ :if-does-not-exist :create
108
+ :if-exists (or (test-result-property
109
+ result :if-exists)
110
+ :error))
111
+ (%test-result-report-stream result stream format)))
112
+ ((streamp output)
113
+ (%test-result-report-stream result output format))
114
+ (t
115
+ (error "Don't know how to send a report to ~s" output)))))
116
+
117
+ (defun %test-result-report-stream (result stream format)
118
+ (start-report-output result stream format)
119
+ (summarize-test-result result stream format)
120
+ (summarize-test-environment result stream format)
121
+ (when (or (failures result) (errors result)
122
+ (expected-failures result) (expected-errors result))
123
+ (summarize-test-problems result stream format))
124
+ (summarize-tests-run result stream format)
125
+ (end-report-output result stream format)
126
+ (generate-detailed-reports result stream format))
127
+
128
+ (defmethod start-report-output (result stream format)
129
+ (declare (ignore result stream format))
130
+ )
131
+
132
+ (defmethod summarize-test-result (result stream format)
133
+ (declare (ignore format))
134
+ (format stream"~&Test results for: ~a~%"
135
+ (results-for result))
136
+ (let ((complete-success? (and (null (errors result))
137
+ (null (failures result)))))
138
+ (cond (complete-success?
139
+ (format stream"~&~A Successful test~:P~%"
140
+ (length (tests-run result))))
141
+ (t
142
+ (format stream "~&~A Test~:P~[~:;, ~:*~A Failure~:P~]~[~:;, ~:*~A Error~:P~].~%"
143
+ (length (tests-run result))
144
+ (length (failures result))
145
+ (length (errors result)))))))
146
+
147
+ (defmethod summarize-test-environment (result stream format)
148
+ (declare (ignore result stream format))
149
+ )
150
+
151
+ (defmethod summarize-test-problems (result stream format)
152
+ (declare (ignore result stream format))
153
+ )
154
+
155
+ (defmethod generate-detailed-reports (result stream format)
156
+ (declare (ignore result stream format))
157
+ )
158
+
159
+ (defmethod summarize-tests-run (result stream format)
160
+ (declare (ignore result stream format)))
161
+
162
+ (defmethod end-report-output (result stream format)
163
+ (declare (ignore result stream format))
164
+ )
165
+
166
+ #+(or)
167
+ (defun summarize-test-environment (result stream format)
168
+ (loop for symbol in (sort `((*lift-dribble-pathname*)
169
+ (*lift-debug-output* interpret-lift-stream)
170
+ (*lift-standard-output* interpret-lift-stream)
171
+ (*test-break-on-errors?*)
172
+ (*test-do-children?*)
173
+ (*lift-equality-test*)
174
+ (*test-print-length*)
175
+ (*test-print-level*)
176
+ (*lift-if-dribble-exists*))
177
+ 'string-lessp :key 'first) do
178
+
179
+ (print)))
180
+
181
+
182
+ ;; some cruft stolen from cl-markdown
183
+ (defvar *html-meta*
184
+ '((name (:author :description :copyright :keywords :date))
185
+ (http-equiv (:refresh :expires))))
186
+
187
+ (defmethod start-report-output (result stream (format (eql :html)))
188
+ (html-header
189
+ stream
190
+ (test-result-property result :title)
191
+ (test-result-property result :style-sheet)))
192
+
193
+ (defmethod html-header (stream title style-sheet)
194
+ (format stream "~&<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
195
+ \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">")
196
+ (format stream "~&<html>~&<head>")
197
+ (when title
198
+ (format stream "~&<title>~a</title>" title))
199
+ (when style-sheet
200
+ (unless (search ".css" style-sheet)
201
+ (setf style-sheet (concatenate 'string style-sheet ".css")))
202
+ (format stream "~&<link type='text/css' href='~a' rel='stylesheet' />"
203
+ style-sheet))
204
+ (format stream "~&</head>~&<body>"))
205
+
206
+ (defmethod summarize-test-result (result stream (format (eql :html)))
207
+ (format stream "~&<div id=\"summary\">")
208
+ (format stream "~&<h1>Test results for: ~a</h1>~%"
209
+ (results-for result))
210
+ (let ((complete-success? (and (null (errors result))
211
+ (null (failures result)))))
212
+ (cond (complete-success?
213
+ (format stream "~&<h2>~A Successful test~:P</h2>~%"
214
+ (length (tests-run result))))
215
+ (t
216
+ (format stream
217
+ "~&<h2>~A Test~:P~[~:;, ~:*~A Failure~:P~]~[~:;, ~:*~A Error~:P~].</h2>~%"
218
+ (length (tests-run result))
219
+ (length (failures result))
220
+ (length (errors result)))))
221
+
222
+ (when (or (expected-errors result) (expected-failures result))
223
+ (format stream "~&<h3>~[~:;~:*Expected failure~p: ~:*~a~]~[~:;, ~]~[~:;~:*Expected error~p: ~:*~a~]</h3>~%"
224
+ (length (expected-failures result))
225
+ ;; zero if only one or the other (so we don't need a separator...)
226
+ (* (length (expected-failures result))
227
+ (length (expected-errors result)))
228
+ (length (expected-errors result))))
229
+
230
+ (when (and (slot-boundp result 'end-time-universal)
231
+ (numberp (end-time-universal result))
232
+ (numberp (start-time-universal result)))
233
+ (format stream "~&<h3>Testing took: ~:d seconds</h3>"
234
+ (- (end-time-universal result)
235
+ (start-time-universal result))))
236
+ #+(or)
237
+ (when (and (numberp (real-end-time result))
238
+ (numberp (real-start-time result)))
239
+ (format stream "~&Time: ~,2f real-time"
240
+ (/ (- (real-end-time result) (real-start-time result))
241
+ internal-time-units-per-second))))
242
+ (format stream "~&</div>"))
243
+
244
+ (defmethod summarize-test-environment (result stream (format (eql :html)))
245
+ (declare (ignore result))
246
+ (format stream "~&<div id=\"environment\">")
247
+
248
+ (format stream "~&</div>"))
249
+
250
+ (defmethod summarize-test-problems (result stream (format (eql :html)))
251
+ (format stream "~&<div id=\"problem-summary\">")
252
+ (format stream "~&<h2>Problem Summary:</h2>")
253
+ (when (failures result)
254
+ (summarize-test-problems-of-type
255
+ (failures result) stream "failure-summary" "Failures"))
256
+ (when (errors result)
257
+ (summarize-test-problems-of-type
258
+ (errors result) stream "error-summary" "Errors"))
259
+ (when (expected-failures result)
260
+ (summarize-test-problems-of-type
261
+ (expected-failures result)
262
+ stream "expected-failure-summary" "Expected Failures"))
263
+ (when (expected-errors result)
264
+ (summarize-test-problems-of-type
265
+ (expected-errors result) stream "expected-failure-summary"
266
+ "Expected Errors"))
267
+ (format stream "~&</div>"))
268
+
269
+ (defmethod summarize-test-problems-of-type
270
+ (problems stream id heading)
271
+ (format stream "~&<div id=\"~a\">" id)
272
+ (format stream "~&<h3>~a</h3>" heading)
273
+ (report-tests-by-suite
274
+ (mapcar (lambda (problem)
275
+ `(,(type-of (testsuite problem))
276
+ ,(test-method problem)
277
+ (:problem ,problem)))
278
+ problems) stream)
279
+ (format stream "~&</div>"))
280
+
281
+ (defmethod summarize-tests-run (result stream (format (eql :html)))
282
+ (format stream "~&<div id=\"results\">")
283
+ (format stream "~&<h2>Tests Run:</h2>")
284
+ (report-tests-by-suite (tests-run result) stream)
285
+ (format stream "~&</div>"))
286
+
287
+ (defun report-tests-by-suite (tests stream)
288
+ (let ((current-suite nil))
289
+ (loop for rest = (sort
290
+ ;; FIXME - this is a hack intended to show tests
291
+ ;; in the order they were run (even if it works, it's
292
+ ;; bound to be fragile)
293
+ (copy-list tests)
294
+ #+(or) (nreverse (copy-list tests))
295
+ 'string-lessp :key 'first) then (rest rest)
296
+ while rest
297
+ for (suite test-name datum) = (first rest) do
298
+ (unless (eq current-suite suite)
299
+ (when current-suite
300
+ (format stream "</div>"))
301
+ (setf current-suite suite)
302
+ (format stream "~&<div class=\"testsuite\">")
303
+ (let* ((this-suite-end (or
304
+ (position-if
305
+ (lambda (datum)
306
+ (not (eq current-suite (first datum))))
307
+ rest)
308
+ (length rest)))
309
+ (error-count (count-if
310
+ (lambda (datum)
311
+ (and (getf (third datum) :problem)
312
+ (typep (getf (third datum) :problem)
313
+ 'test-error)))
314
+ rest
315
+ :end this-suite-end))
316
+ (failure-count (count-if
317
+ (lambda (datum)
318
+ (and (getf (third datum) :problem)
319
+ (typep (getf (third datum) :problem)
320
+ 'test-failure)))
321
+ rest
322
+ :end this-suite-end))
323
+ (extra-class (cond ((and (= error-count 0) (= failure-count 0))
324
+ 'testsuite-all-passed)
325
+ ((> error-count 0)
326
+ 'testsuite-some-errors)
327
+ (t
328
+ 'testsuite-some-failures))))
329
+ (format stream "~&<div class=\"testsuite-title\"><table class=\"~a\"><tr><td>~a</td>" extra-class suite)
330
+ (format stream "<td class=\"testsuite-test-count\">~:d test~:p</td>"
331
+ this-suite-end)
332
+ (format stream "<td class=\"testsuite-summary\">")
333
+ (cond ((and (= error-count 0) (= failure-count 0))
334
+ (format stream "all passed"))
335
+ (t
336
+ (format stream "~[~:;~:*~:d failure~:p~]"
337
+ failure-count)
338
+ (when (and (> error-count 0) (> failure-count 0))
339
+ (format stream ", "))
340
+ (format stream "~[~:;~:*~a error~:p~]"
341
+ error-count)))
342
+ (format stream "</td></tr></table>")
343
+ (format stream "</div>")))
344
+ (format stream "~&<div class=\"test-case\">")
345
+ (let ((problem (getf datum :problem)))
346
+ (cond ((typep problem 'test-failure)
347
+ (format stream "~&<span class=\"test-name\"><a href=\"~a\" title=\"details\">~a</a></span>"
348
+ (details-link stream suite test-name)
349
+ test-name)
350
+ (format stream
351
+ "~&<span class=\"test-failure\">failure</span>" ))
352
+ ((typep problem 'test-error)
353
+ (format stream "~&<span class=\"test-name\"><a href=\"~a\" title=\"details\">~a [during ~a]</a></span>"
354
+ (details-link stream suite test-name)
355
+ test-name
356
+ (test-step problem))
357
+ (format stream "~&<span class=\"test-error\">error</span>"))
358
+ (t
359
+ (format stream "~&<span class=\"test-name\">~a</span>"
360
+ test-name)
361
+ (let ((seconds (getf datum :seconds))
362
+ (conses (getf datum :conses)))
363
+ (when seconds
364
+ (format stream "<span class=\"test-time\">~,3f</span>"
365
+ seconds))
366
+ (when conses
367
+ (format stream "<span class=\"test-space\">~:d</span>"
368
+ conses)))))
369
+ (format stream "~&</div>")))
370
+ (when current-suite
371
+ (format stream "</div>"))))
372
+
373
+ (defun get-details-links-table ()
374
+ (let ((hash (getf *report-environment* :details-links)))
375
+ (or hash
376
+ (setf (getf *report-environment* :details-links)
377
+ (make-hash-table :test 'equal)))))
378
+
379
+ #+(or)
380
+ (get-details-links-table)
381
+
382
+ (defun details-link (stream suite name)
383
+ (declare (ignore stream))
384
+ (let* ((hash (get-details-links-table)))
385
+ (or (gethash (cons suite name) hash)
386
+ (progn
387
+ (incf (getf *report-environment* :details-links-count 0))
388
+ (setf (gethash (cons suite name) hash)
389
+ (make-pathname
390
+ :name (format nil "details-~a"
391
+ (getf *report-environment* :details-links-count))
392
+ :type "html"))))))
393
+
394
+ (defmethod end-report-output (result stream (format (eql :html)))
395
+ (let ((style-sheet (test-result-property result :style-sheet)))
396
+ (when style-sheet
397
+ (ignore-errors
398
+ (copy-file (asdf:system-relative-pathname
399
+ 'lift "resources/test-style.css")
400
+ (make-pathname
401
+ :name (pathname-name style-sheet)
402
+ :type (pathname-type style-sheet)
403
+ :defaults (pathname stream))
404
+ :if-exists :supersede))))
405
+ (html-footer stream))
406
+
407
+ (defun html-footer (stream)
408
+ (format stream "<div id=\"footer\">")
409
+ (format stream "~&generated on ~a"
410
+ #+allegro
411
+ (excl:locale-print-time
412
+ (get-universal-time)
413
+ :fmt "%B %d, %Y %T GMT%z" :stream nil)
414
+ #-allegro
415
+ (get-universal-time))
416
+ (format stream "</div>")
417
+ (format stream "~&</body></html>"))
418
+
419
+ (defmethod generate-detailed-reports (result stream (format (eql :html)))
420
+ (loop for (suite test-name datum) in (tests-run result)
421
+ when (getf datum :problem) do
422
+ (let ((output-pathname (merge-pathnames
423
+ (details-link stream suite test-name)
424
+ stream)))
425
+ (ensure-directories-exist output-pathname)
426
+ (let ((*print-right-margin* 64))
427
+ (with-open-file (out output-pathname
428
+ :direction :output
429
+ :if-does-not-exist :create
430
+ :if-exists :supersede)
431
+ (html-header
432
+ out
433
+ (format nil "Test ~a details | ~a"
434
+ test-name (test-result-property result :title))
435
+ (test-result-property result :style-sheet))
436
+ (format out "~&<h2>Test ~a details</h2>" test-name)
437
+ (format out "~&<a href=\"~a\">Back</a>"
438
+ (namestring (make-pathname :name (pathname-name stream)
439
+ :type (pathname-type stream))))
440
+ (format out "~&<pre>")
441
+ (format out "~a"
442
+ (wrap-encode-pre
443
+ (with-output-to-string (s)
444
+ (print-test-problem "" (getf datum :problem) s t))
445
+ :width (test-result-property
446
+ *test-result* :print-width 60)))
447
+ (format out "~&</pre>")
448
+ (html-footer out))))))
449
+
450
+ #+(or)
451
+ (defmethod summarize-test-environment (result stream format)
452
+ (loop for symbol in (sort `((*lift-dribble-pathname*)
453
+ (*lift-debug-output* interpret-lift-stream)
454
+ (*lift-standard-output* interpret-lift-stream)
455
+ (*test-break-on-errors?*)
456
+ (*test-do-children?*)
457
+ (*lift-equality-test*)
458
+ (*test-print-length*)
459
+ (*test-print-level*)
460
+ (*lift-if-dribble-exists*))
461
+ 'string-lessp :key 'first) do
462
+
463
+ (print)))
464
+
465
+ (defun wrap-encode-pre (string &key (width 80))
466
+ ;; Copied from CL-Markdown
467
+ ;; Copied from HTML-Encode
468
+ ;;?? this is very consy
469
+ ;;?? crappy name
470
+ (declare (simple-string string))
471
+ (let ((output (make-array (truncate (length string) 2/3)
472
+ :element-type 'character
473
+ :adjustable t
474
+ :fill-pointer 0))
475
+ (column 0))
476
+ (with-output-to-string (out output)
477
+ (loop for char across string
478
+ do (case char
479
+ ((#\&) (incf column) (write-string "&amp;" out))
480
+ ((#\<) (incf column) (write-string "&lt;" out))
481
+ ((#\>) (incf column) (write-string "&gt;" out))
482
+ ((#\Tab #\Space #\Return #\Newline)
483
+ (cond ((or (>= column width)
484
+ (char= char #\Return)
485
+ (char= char #\Newline))
486
+ (setf column 0)
487
+ (terpri out))
488
+ ((char= char #\Space)
489
+ (incf column)
490
+ (write-char char out))
491
+ ((char= char #\Tab)
492
+ (incf column 4)
493
+ (write-string " " out))))
494
+ (t (incf column) (write-char char out)))))
495
+ (coerce output 'simple-string)))
496
+
497
+ ;;;;;
498
+
499
+ (defmethod summarize-test-result (result stream (format (eql :describe)))
500
+ (describe result stream))
501
+
502
+ (defmethod summarize-tests-run (result stream (format (eql :describe)))
503
+ (declare (ignore result stream))
504
+ )
505
+
506
+ ;;;;;
507
+
508
+ (defmethod summarize-test-result (result stream (format (eql :save)))
509
+ (flet ((add-property (name)
510
+ (when (slot-boundp result name)
511
+ (format stream "~&\(~s ~a\)"
512
+ (intern (symbol-name name) :keyword)
513
+ (slot-value result name)))))
514
+ (format stream "\(~%")
515
+ (add-property 'results-for)
516
+ (format stream "~&\(:date-time ~a\)" (get-universal-time))
517
+ (add-property 'real-start-time-universal)
518
+ (add-property 'start-time-universal)
519
+ (add-property 'end-time-universal)
520
+ (add-property 'real-end-time-universal)
521
+ (format stream "~&\(:tests-run ")
522
+ (loop for (suite name data) in
523
+ ;; FIXME - this is a hack intended to show tests
524
+ ;; in the order they were run (even if it works, it's
525
+ ;; bound to be fragile)
526
+ (copy-list (tests-run result)) do
527
+ (summarize-single-test format suite name data :stream stream))
528
+ (format stream "~&\)")
529
+ (format stream "~&\)")))
530
+
531
+ #+(or)
532
+ (progn
533
+ (setf (test-result-property *test-result* :if-exists) :supersede)
534
+ (test-result-report *test-result* #p"/tmp/report.save" :save))
535
+
536
+ (defun symbol->turtle (symbol)
537
+ (let ((upcase? nil))
538
+ (coerce
539
+ (loop for char across (string-downcase (symbol-name symbol))
540
+ when (char= char #\-) do (setf upcase? t)
541
+ else collect (if upcase?
542
+ (prog1 (char-upcase char)
543
+ (setf upcase? nil))
544
+ char))
545
+ 'string)))
546
+
547
+ (defun turtlefy (thing)
548
+ (typecase thing
549
+ (string thing)
550
+ (pathname (namestring thing))
551
+ (number
552
+ (etypecase thing
553
+ (integer (format nil "\"~a\"^^xsd:integer" thing))
554
+ (double-float (format nil "\"~f\"^^xsd:double" thing))
555
+ (single-float (format nil "\"~f\"^^xsd:single" thing))))
556
+ (symbol (symbol-name thing))
557
+ (t (format nil "\"~a\"" thing))))
558
+
559
+ (defun ensure-symbol (thing)
560
+ (etypecase thing
561
+ (symbol thing)
562
+ (string (intern thing))))
563
+
564
+ #+(or)
565
+ (symbol->turtle 'real-start-time-universal)
566
+
567
+ (defun date->turtle (&key (datetime (get-universal-time)) (include-time? nil))
568
+ (multiple-value-bind
569
+ (second minute hour day month year day-of-the-week)
570
+ (decode-universal-time datetime)
571
+ (declare (ignore day-of-the-week))
572
+ (let ((date-part (format nil "~d-~2,'0d-~2,'0d" year month day))
573
+ (time-part (and include-time?
574
+ (format nil "T-~2,'0d:~2,'0d:~2,'0d"
575
+ hour minute second)))
576
+ (data-type (if include-time?
577
+ "xsd:dateTime" "xsd:date")))
578
+ (concatenate 'string "\"" date-part time-part "\"" "^^" data-type))))
579
+
580
+ ;; http://www.dajobe.org/2004/01/turtle/
581
+ (defmethod summarize-test-result (result stream (format (eql :turtle)))
582
+ (labels ((convert-value (value type)
583
+ (ecase type
584
+ (string (turtlefy value))
585
+ (symbol (ensure-symbol value))
586
+ (date (date->turtle :datetime value))
587
+ (dateTime (date->turtle :datetime value :include-time? t))))
588
+ (add-property (name type)
589
+ (let ((value (slot-value result name)))
590
+ (when value
591
+ (format stream "~&:~a ~s ;"
592
+ (symbol->turtle name)
593
+ (convert-value value type))))))
594
+ (format stream
595
+ "~&@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .~%")
596
+ (format stream
597
+ "~&@prefix : <http://www.metabang.com/2007/04/lift#> .~%")
598
+ (format stream "\[~%")
599
+ (add-property 'results-for 'string)
600
+ (add-property 'real-start-time 'dateTime)
601
+ (add-property 'start-time 'dateTime)
602
+ (add-property 'end-time 'dateTime)
603
+ (add-property 'real-end-time 'dateTime)
604
+ (format stream "~&\:testsRun (")
605
+ (loop for (suite name data) in
606
+ ;; FIXME - this is a hack intended to show tests
607
+ ;; in the order they were run (even if it works, it's
608
+ ;; bound to be fragile)
609
+ (copy-list (tests-run result))
610
+ #+(or)
611
+ (nreverse (copy-list (tests-run result))) do
612
+ (labels ((write-datum (name type &key (source data))
613
+ (let* ((key (intern (symbol-name name) :keyword))
614
+ (value (getf source key)))
615
+ (when value
616
+ (format stream "~& :~a ~a ;"
617
+ (symbol->turtle name)
618
+ (convert-value value type)))))
619
+ (prop (name type)
620
+ (write-datum name type :source (getf data :properties))))
621
+ (format stream "~&\[ ")
622
+ (format stream ":testSuite ~s ;" (symbol-name suite))
623
+ (format stream "~& :testName ~s ;" (symbol-name name))
624
+ ;; FIXME - we could make these extensible
625
+ (write-datum 'start-time 'dateTime)
626
+ (write-datum 'end-time 'dateTime)
627
+ (write-datum 'result 'string)
628
+ (write-datum 'seconds 'string)
629
+ (write-datum 'conses 'string)
630
+ (loop for stuff in (getf data :properties) by #'cddr do
631
+ (prop stuff 'string))
632
+ (format stream " \]")))
633
+ (format stream " ) ~&\] . ")))
634
+
635
+ #+(or)
636
+ (progn
637
+ (setf (test-result-property *test-result* :if-exists) :supersede)
638
+ (test-result-report *test-result* #p"/tmp/report.n3" :turtle))
639
+
640
+ ;;;;
641
+
642
+ (defmacro append-to-report ((var output-to) &body body)
643
+ (let ((gclosep (gensym "closep"))
644
+ (gstream (gensym "stream")))
645
+ `(let* ((,gclosep nil)
646
+ (,gstream ,output-to)
647
+ (,var (etypecase ,gstream
648
+ (stream ,gstream)
649
+ ((or pathname string)
650
+ (setf ,gclosep t)
651
+ (open ,gstream
652
+ :if-does-not-exist :create
653
+ :if-exists :append
654
+ :direction :output)))))
655
+ (unwind-protect
656
+ (labels ((out (key value)
657
+ (when value
658
+ (let ((*print-readably* nil))
659
+ (format out "~&\(~s ~s\)" key value)))))
660
+ (declare (ignorable (function out)))
661
+ (progn ,@body))
662
+ (when ,gclosep
663
+ (close ,var))))))
664
+
665
+ (defvar *lift-report-header-hook* nil)
666
+
667
+ (defvar *lift-report-footer-hook* nil)
668
+
669
+ (defvar *lift-report-detail-hook* nil)
670
+
671
+ (defun write-report-header (stream result args)
672
+ (append-to-report (out stream)
673
+ (format out "~&\(")
674
+ (out :results-for (results-for result))
675
+ (out :arguments args)
676
+ (out :features (copy-list *features*))
677
+ (out :datetime (get-universal-time))
678
+ (loop for hook in *lift-report-header-hook* do
679
+ (funcall hook out result))
680
+ (format out "~&\)~%")))
681
+
682
+ (defun write-report-footer (stream result)
683
+ (append-to-report (out stream)
684
+ (format out "~&\(")
685
+ (out :test-case-count (length (tests-run result)))
686
+ (out :test-suite-count (length (suites-run result)))
687
+ (out :failure-count (length (failures result)))
688
+ (out :error-count (length (errors result)))
689
+ (out :expected-failure-count (length (expected-failures result)))
690
+ (out :expected-error-count (length (expected-errors result)))
691
+ (out :start-time-universal (start-time-universal result))
692
+ (when (slot-boundp result 'end-time-universal)
693
+ (out :end-time-universal (end-time-universal result)))
694
+ (out :errors (collect-testsuite-summary result :errors))
695
+ (out :failures (collect-testsuite-summary result :failures))
696
+ (out :expected-errors
697
+ (collect-testsuite-summary result :expected-errors))
698
+ (out :expected-failures
699
+ (collect-testsuite-summary result :expected-failures))
700
+ (loop for hook in *lift-report-footer-hook* do
701
+ (funcall hook out result))
702
+ (format out "~&\)~%")))
703
+
704
+ (defmethod summarize-single-test :around
705
+ (format suite-name test-case-name data &key stream)
706
+ (append-to-report (out stream)
707
+ (call-next-method format suite-name test-case-name data :stream out)))
708
+
709
+ (defmethod summarize-single-test
710
+ ((format (eql :save)) suite-name test-case-name data
711
+ &key (stream *standard-output*))
712
+ (labels ((out (key value)
713
+ (when value
714
+ (format stream "~&\(~s ~s\)" key value)))
715
+ (write-datum (name &key (source data))
716
+ (let* ((key (intern (symbol-name name) :keyword))
717
+ (value (getf source key)))
718
+ (out key value)))
719
+ (prop (name)
720
+ (write-datum name :source (getf data :properties))))
721
+ (format stream "~&\(~%")
722
+ (format stream "~&\(:suite ~a\)" suite-name)
723
+ (format stream "~&\(:name ~a\)" test-case-name)
724
+ ;; FIXME - we could make these extensible
725
+ (write-datum 'start-time-universal)
726
+ (write-datum 'end-time-universal)
727
+ (write-datum 'result)
728
+ (write-datum 'seconds)
729
+ (write-datum 'conses)
730
+ (loop for stuff in (getf data :properties) by #'cddr do
731
+ (prop stuff))
732
+ (cond ((getf data :problem)
733
+ (let ((problem (getf data :problem)))
734
+ (out :problem-kind (test-problem-kind problem))
735
+ (out :problem-step (test-step problem))
736
+ (out :problem-condition
737
+ (let ((*print-readably* nil))
738
+ (format nil "~s" (test-condition problem))))
739
+ (out :problem-condition-description
740
+ (format nil "~a" (test-condition problem)))
741
+ (when (slot-exists-p problem 'backtrace)
742
+ (out :problem-backtrace (backtrace problem)))))
743
+ (t
744
+ (out :result t)))
745
+ (loop for hook in *lift-report-detail-hook* do
746
+ (funcall hook stream data))
747
+ (format stream "\)~%")))
748
+
749
+ ;;;;
750
+
751
+ (defun collect-testsuite-summary (result kind)
752
+ (let ((list (slot-value result (intern (symbol-name kind)
753
+ (find-package :lift)))))
754
+ (flet ((encode-symbol (symbol)
755
+ (cons (symbol-name symbol)
756
+ (package-name (symbol-package symbol)))))
757
+ (mapcar (lambda (glitch)
758
+ (list (encode-symbol (type-of (testsuite glitch)))
759
+ (encode-symbol (test-method glitch))))
760
+ list))))
761
+
762
+ #+(or)
763
+ (collect-testsuite-summary lift:*test-result* :failures)
764
+
765
+ ;;;;;
766
+
767
+
768
+
769
+ #+allegro
770
+ (defun cancel-current-profile (&key force?)
771
+ (when (prof::current-profile-actual prof::*current-profile*)
772
+ (unless force?
773
+ (assert (member (prof:profiler-status) '(:inactive))))
774
+ (prof:stop-profiler)
775
+ (setf prof::*current-profile* (prof::make-current-profile))))
776
+
777
+ #+allegro
778
+ (defun current-profile-sample-count ()
779
+ (ecase (prof::profiler-status :verbose nil)
780
+ ((:inactive :analyzed) 0)
781
+ ((:suspended :saved)
782
+ (slot-value (prof::current-profile-actual prof::*current-profile*)
783
+ 'prof::samples))
784
+ (:sampling (warn "Can't determine count while sampling"))))
785
+
786
+ #+allegro
787
+ (defun show-flat-profile (output)
788
+ (let ((prof:*significance-threshold*
789
+ (or *profiling-threshold* 0.01)))
790
+ (prof:show-flat-profile :stream output)))
791
+
792
+ #+allegro
793
+ (defun show-call-graph (output)
794
+ (let ((prof:*significance-threshold*
795
+ (or *profiling-threshold* 0.01)))
796
+ (prof:show-call-graph :stream output)))
797
+
798
+ #+allegro
799
+ (defun show-call-counts (output)
800
+ (format output "~%~%Call counts~%")
801
+ (let ((*standard-output* output))
802
+ (prof:show-call-counts)))
803
+
804
+
805
+ #-allegro
806
+ (defun show-flat-profile (output)
807
+ (format output "~%~%Flat profile: unavailable for this Lisp~%"))
808
+
809
+ #-allegro
810
+ (defun show-call-graph (output)
811
+ (format output "~%~%Call graph: unavailable for this Lisp~%"))
812
+
813
+ #-allegro
814
+ (defun show-call-counts (output)
815
+ (format output "~%~%Call counts: unavailable for this Lisp~%"))
816
+
817
+ #+allegro
818
+ (defun with-profile-report-fn
819
+ (name style fn body &key
820
+ (log-name *benchmark-log-path*)
821
+ (count-calls-p *count-calls-p*)
822
+ (timeout nil))
823
+ (assert (member style '(:time :space :count-only)))
824
+ (cancel-current-profile :force? t)
825
+ (let* ((seconds 0.0) (conses 0)
826
+ error
827
+ results
828
+ (profile-fn (make-profiled-function fn)))
829
+ (unwind-protect
830
+ (multiple-value-bind (result measures errorp)
831
+ (while-measuring (t measure-seconds measure-space)
832
+ (handler-case
833
+ (with-timeout (timeout)
834
+ (funcall profile-fn style count-calls-p))
835
+ (timeout-error
836
+ (c)
837
+ (declare (ignore c)))
838
+ (error (c)
839
+ (error c))))
840
+ (setf seconds (first measures) conses (second measures)
841
+ results result error errorp))
842
+ ;; cleanup / ensure we get report
843
+ (generate-profile-log-entry log-name name seconds conses results error)
844
+ (when (> (current-profile-sample-count) 0)
845
+ (let ((pathname (unique-filename
846
+ (merge-pathnames
847
+ (make-pathname
848
+ :type "prof"
849
+ :name (format nil "~a-~a-" name style))
850
+ log-name))))
851
+ (write-profile-report pathname name style body
852
+ seconds conses error count-calls-p))))
853
+ (values-list (if (atom results) (list results) results))))
854
+
855
+ (defun write-profile-report (pathname name style body seconds conses
856
+ error count-calls-p)
857
+ (format t "~&Profiling output being sent to ~a" pathname)
858
+ (with-open-file (output pathname
859
+ :direction :output
860
+ :if-does-not-exist :create
861
+ :if-exists :append)
862
+ (format output "~&Profile data for ~a" name)
863
+ (format output "~&Date: ~a" (date-stamp :include-time? t))
864
+ (format output "~& Total time: ~,2F; Total space: ~:d \(~:*~d\)"
865
+ seconds conses)
866
+ (format output "~%~%")
867
+ (when error
868
+ (format output "~&Error occured during profiling: ~a~%~%" error))
869
+ (let ((*standard-output* output))
870
+ (when *current-test*
871
+ (write-profile-information *current-test*)))
872
+ (when body
873
+ (format output "~&Profiling: ~%")
874
+ (let ((*print-length* 10)
875
+ (*print-level* 10))
876
+ (dolist (form body)
877
+ (pprint form output)))
878
+ (format output "~%~%"))
879
+ (when (or (eq :time style)
880
+ (eq :space style))
881
+ (show-flat-profile output)
882
+ (show-call-graph output)
883
+ (when count-calls-p
884
+ (show-call-counts output)))
885
+ #+allegro
886
+ (when *functions-to-profile*
887
+ (loop for thing in *functions-to-profile* do
888
+ (let ((*standard-output* output)
889
+ (*print-readably* nil))
890
+ (handler-case
891
+ (cond ((thing-names-generic-function-p thing)
892
+ (format output "~%~%Disassemble generic-function ~s:~%"
893
+ thing)
894
+ (prof:disassemble-profile thing)
895
+ (mapc
896
+ (lambda (m)
897
+ (format t "~2%~a~%"
898
+ (make-string 60 :initial-element #\-))
899
+ (format t "~&Method: ~a~2%" m)
900
+ (prof:disassemble-profile (clos:method-function m)))
901
+ (clos:generic-function-methods
902
+ (symbol-function thing))))
903
+ (t
904
+ (format output "~%~%Disassemble function ~s:~%"
905
+ thing)
906
+ (prof:disassemble-profile thing)))
907
+ (error (c)
908
+ (format
909
+ output "~2%Error ~a while trying to disassemble-profile ~s~2%"
910
+ c thing))))))))
911
+
912
+ ;; stolen from cl-markdown and modified
913
+ (defun thing-names-generic-function-p (thing)
914
+ (and (symbolp thing)
915
+ (fboundp thing)
916
+ (typep (symbol-function thing) 'standard-generic-function)))