guile-jsonld/test-modules/online.scm

online.scm

1
;;;; Copyright (C) 2019, 2020 Julien Lepiller <julien@lepiller.eu>
2
;;;; 
3
;;;; This library is free software; you can redistribute it and/or
4
;;;; modify it under the terms of the GNU Lesser General Public
5
;;;; License as published by the Free Software Foundation; either
6
;;;; version 3 of the License, or (at your option) any later version.
7
;;;; 
8
;;;; This library is distributed in the hope that it will be useful,
9
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
;;;; Lesser General Public License for more details.
12
;;;; 
13
;;;; You should have received a copy of the GNU Lesser General Public
14
;;;; License along with this library; if not, write to the Free Software
15
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
;;;; 
17
18
(define-module (test-modules online)
19
  #:use-module (ice-9 match)
20
  #:use-module (srfi srfi-1)
21
  #:use-module (srfi srfi-9)
22
  #:use-module (test-modules download)
23
  #:use-module (test-modules result)
24
  #:use-module (test-modules testsuite)
25
  #:use-module (jsonld download)
26
  #:use-module (jsonld json)
27
  #:use-module (jsonld)
28
  #:use-module (jsonld options)
29
  #:use-module (jsonld iri)
30
  #:export (run-test-suite
31
            run-test-suites
32
            get-test-doc))
33
34
;; The JsonLD specification comes with a test suite.  It consists in on JsonLD
35
;; document per API function.  The test suite is designed for the latest
36
;; version of the API, but can be used for older versions.  Tests for newer
37
;; versions or specific to older versions are clearly marked, so we can
38
;; select them.
39
;; Each JsonLD document is a manifest listing a huge list of tests that require
40
;; us to download a few other JsonLD documents, run a function on them and compare
41
;; the result.  This is what this file does.
42
43
(define (execute-test test)
44
  "Execute one test described by a Json object @var{test}.  Return a Json object
45
as the output of the test, or throws an exception if something went wrong."
46
  (let* ((document (test-case-document test))
47
         (input (assoc-ref document "input"))
48
         (context (assoc-ref document "context"))
49
         (type (array->list (assoc-ref document "@type")))
50
         (options (assoc-ref document "option"))
51
         (spec-version (assoc-ref options "specVersion"))
52
         (document-loader (get-test-document-loader options)))
53
    (cond
54
      ((equal? spec-version "json-ld-1.0")
55
       (throw 'unsupported-spec 1.0))
56
      ((member "jld:CompactTest" type)
57
       (compact (string-append jsonld-test-url input)
58
                (string-append jsonld-test-url context)
59
                #:options
60
                (apply
61
                  new-jsonld-options
62
                  #:ordered? #t
63
                  #:document-loader document-loader
64
                  `(,@(if (assoc-ref options "base")
65
                          `(#:base ,(assoc-ref options "base"))
66
                          '())
67
                    ,@(if (assoc-ref options "processingMode")
68
                          `(#:processing-mode ,(assoc-ref options "processingMode"))
69
                          '())
70
                    ,@(if (assoc-ref options "extractAllScripts")
71
                          `(#:extract-all-scripts?
72
                            ,(assoc-ref options "extractAllScripts"))
73
                          '())
74
                    ,@(if (json-has-key? options "compactArrays")
75
                          `(#:compact-arrays? ,(assoc-ref options "compactArrays"))
76
                          '())))))
77
      ((member "jld:ExpandTest" type)
78
       (expand (string-append jsonld-test-url input)
79
               #:options
80
               (apply
81
                 new-jsonld-options
82
                 #:ordered? #t
83
                 #:document-loader document-loader
84
                 `(,@(if (assoc-ref options "base")
85
                         `(#:base ,(assoc-ref options "base"))
86
                         '())
87
                   ,@(if (assoc-ref options "extractAllScripts")
88
                         `(#:extract-all-scripts?
89
                           ,(assoc-ref options "extractAllScripts"))
90
                         '())
91
                   ,@(if (assoc-ref options "processingMode")
92
                         `(#:processing-mode ,(assoc-ref options "processingMode"))
93
                         '())
94
                   ,@(if (assoc-ref options "expandContext")
95
                         `(#:expand-context ,(string-append jsonld-test-url
96
                                                            (assoc-ref options "expandContext")))
97
                         '())))))
98
      ((member "jld:FlattenTest" type)
99
       (flatten (string-append jsonld-test-url input)
100
                #:context
101
                (if context
102
                  (string-append jsonld-test-url context)
103
                  #f)
104
                #:options
105
                (apply
106
                  new-jsonld-options
107
                  #:ordered? #t
108
                  #:document-loader document-loader
109
                  `(,@(if (assoc-ref options "base")
110
                          `(#:base ,(assoc-ref options "base"))
111
                          '())
112
                    ,@(if (assoc-ref options "processingMode")
113
                          `(#:processing-mode ,(assoc-ref options "processingMode"))
114
                          '())
115
                    ,@(if (assoc-ref options "extractAllScripts")
116
                          `(#:extract-all-scripts?
117
                            ,(assoc-ref options "extractAllScripts"))
118
                          '())
119
                    ,@(if (json-has-key? options "compactArrays")
120
                          `(#:compact-arrays? ,(assoc-ref options "compactArrays"))
121
                          '())))))
122
      (else (throw 'unrecognized-test type)))))
123
124
(define (run-test test)
125
  "Run one test described by the Json object @var{test}, whose @var{id} is
126
an identifier.  @var{id} is used as the test number for the test driver.  Return
127
is undefined.  As a side-effect, outputs one line on the standard output to
128
report the test status."
129
  (let* ((document (test-case-document test))
130
         (description (or (assoc-ref document "purpose") (test-case-name test)))
131
         (description (string-append (test-case-id test) ": " description))
132
         (expect (assoc-ref document "expect"))
133
         (expect-error (assoc-ref document "expectErrorCode"))
134
         (type (array->list (assoc-ref document "@type")))
135
         (option (assoc-ref document "option"))
136
         (result
137
           (catch #t
138
             (lambda ()
139
               (execute-test test))
140
             (lambda (key . value)
141
               (cons key value)))))
142
    (if (member "jld:NegativeEvaluationTest" type)
143
      (match result
144
        (((? symbol? key) . value)
145
         (cond
146
           ((equal? key 'unrecognized-test)
147
            (update-test-case test
148
              #:result 'skip
149
              #:reason "unrecognized test type"))
150
           ((equal? key 'unsupported-spec)
151
            (update-test-case test
152
              #:result 'skip
153
              #:reason "unsupported specification version"))
154
           ((equal? key 'unsupported-version-test)
155
            (update-test-case test
156
              #:result 'skip
157
              #:reason "unsupported JsonLD version"))
158
           ((equal? (jsonld-error->string key) expect-error)
159
            (update-test-case test #:result 'pass))
160
           (else
161
             (update-test-case test
162
               #:result 'fail
163
               #:reason (format #f "Expected ~a but got ~a: ~a"
164
                                expect-error key value)))))
165
        (_ (begin
166
             (update-test-case test
167
               #:result 'fail
168
               #:reason (format #f "Expected ~a but got success"
169
                                expect-error)))))
170
      (match result
171
        (((? symbol? key) . value)
172
         (cond
173
           ((equal? key 'unrecognized-test)
174
            (update-test-case test
175
              #:result 'skip
176
              #:reason "unrecognized test type"))
177
           ((equal? key 'unsupported-spec)
178
            (update-test-case test
179
              #:result 'skip
180
              #:reason "unsupported specification version"))
181
           ((equal? key 'unsupported-version-test)
182
            (update-test-case test
183
              #:result 'skip
184
              #:reason "unsupported JsonLD version"))
185
           (else
186
            (update-test-case test
187
              #:result 'fail
188
              #:reason (format #f "Expected success but got ~a: ~a"
189
                               key value)))))
190
        (_ (let ((expected (json-document-document
191
                             (download-json
192
                               (string-append jsonld-test-url expect)))))
193
             (if (same-json? result expected)
194
                 (update-test-case test #:result 'pass)
195
                 (update-test-case test
196
                   #:result 'fail
197
                   #:reason (format #f "Expected ~a but got ~a"
198
                                    expected result)))))))))
199
200
(define (run-tests tests expected-failures driver)
201
  "Run all the tests of the @var{tests} test suite, using identifiers starting
202
from @var{id}.  Return is undefined."
203
  (fold
204
    (lambda (test results)
205
      (let* ((result (run-test test))
206
             (result
207
               (if (assoc-ref expected-failures (test-case-id test))
208
                   (update-test-case result
209
                     #:result (cond
210
                                ((equal? 'skip (test-case-result result))
211
                                 'skip)
212
                                ((equal? 'fail (test-case-result result))
213
                                 'xfail)
214
                                ((equal? 'pass (test-case-result result))
215
                                 'xpass))
216
                     #:reason (assoc-ref expected-failures (test-case-id test)))
217
                   result)))
218
        ((test-driver-print driver) result)
219
        (cons result results)))
220
    '()
221
    tests))
222
223
(define (get-test-doc url)
224
  "Get a test suite object from the manifest at @var{url}."
225
  (assoc-ref (json-document-document (download-json url)) "sequence"))
226
227
(define* (get-test-plan url #:key (num 1))
228
  (define document (get-test-doc url))
229
230
  (cdr
231
    (fold
232
      (lambda (test result)
233
        (let* ((num (car result))
234
               (result (cdr result))
235
               (name (assoc-ref test "name"))
236
               (@id (assoc-ref test "@id"))
237
               (name (string-append @id ": " name))
238
               (description (or (assoc-ref test "purpose") name))
239
               (description (string-append @id ": " description)))
240
          (cons (+ 1 num)
241
                (cons (make-test-case (string-append url @id)
242
                                      num name description test #f #f)
243
                      result))))
244
      `(,num . ())
245
      (array->list document))))
246
247
(define (run-test-suite manifest expected-failures driver)
248
  "Run a test suite described by @var{manifest}."
249
  (let* ((plan (reverse (get-test-plan manifest))))
250
    ((test-driver-init driver) plan)
251
    ((test-driver-finalize driver) (run-tests plan expected-failures driver))))
252
253
(define (run-test-suites manifests expected-failures driver)
254
  "Run multiple test suites described by @var{manifests}."
255
  (let* ((plan
256
           (fold
257
             (lambda (manifest plan)
258
               (append plan (reverse (get-test-plan
259
                                       manifest #:num (+ (length plan) 1)))))
260
             '()
261
             manifests)))
262
    ((test-driver-init driver) plan)
263
    ((test-driver-finalize driver) (run-tests plan expected-failures driver))))
264