guile-rdf/test-modules/online.scm

online.scm

1
;;;; Copyright (C) 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 (rnrs bytevectors)
21
  #:use-module (srfi srfi-1)
22
  #:use-module (test-modules result)
23
  #:use-module ((rdf entailment rdf) #:prefix rdf:)
24
  #:use-module ((rdf entailment rdfs) #:prefix rdfs:)
25
  #:use-module ((rdf entailment simple) #:prefix simple:)
26
  #:use-module (rdf rdf)
27
  #:use-module ((rdf xsd) #:prefix xsd:)
28
  #:use-module (srfi srfi-1)
29
  #:use-module (nquads tordf)
30
  #:use-module (turtle tordf)
31
  #:use-module (web client)
32
  #:use-module (web response)
33
  #:export (run-test-suite
34
            run-test-suites))
35
36
(define (find-rest node graph)
37
  (rdf-triple-object
38
    (car
39
      (filter
40
        (lambda (triple)
41
          (and (equal? (rdf-triple-subject triple) node)
42
               (equal? (rdf-triple-predicate triple)
43
                       (string-append "http://www.w3.org/1999/02/22-rdf-syntax-ns"
44
                                      "#rest"))))
45
        graph))))
46
47
(define (find-first node graph)
48
  (rdf-triple-object
49
    (car
50
      (filter
51
        (lambda (triple)
52
          (and (equal? (rdf-triple-subject triple) node)
53
               (equal? (rdf-triple-predicate triple)
54
                       (string-append "http://www.w3.org/1999/02/22-rdf-syntax-ns"
55
                                      "#first"))))
56
        graph))))
57
58
(define (find-list node graph)
59
  (if (blank-node? node)
60
      (let loop ((node node) (result '()))
61
        (let ((first (find-first node graph))
62
              (node (find-rest node graph)))
63
          (if (blank-node? node)
64
              (loop node (cons first result))
65
              (cons first result))))
66
      '()))
67
68
(define (get-objects triples predicate)
69
  (map
70
    rdf-triple-object
71
    (filter
72
      (lambda (t)
73
        (equal? (rdf-triple-predicate t) predicate))
74
      triples)))
75
76
(define (lexical->value value)
77
  (cond
78
    ((rdf-literal? value)
79
     (rdf-literal-lexical-form value))
80
    ((blank-node? value)
81
     (string-append "_:" (number->string value)))
82
    (else value)))
83
84
(define (execute-test test)
85
  (let* ((predicates (test-case-document test))
86
         (type (car (get-objects predicates "http://www.w3.org/1999/02/22-rdf-syntax-ns#type")))
87
         (type (car (reverse (string-split type #\#))))
88
         (action (car (get-objects predicates "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#action"))))
89
    (cond
90
      ((member type '("TestTurtlePositiveSyntax" "TestTurtleNegativeSyntax"
91
                      "TestTurtleEval" "PositiveEntailmentTest"
92
                      "NegativeEntailmentTest"))
93
       (turtle->rdf (get-test-doc action) action))
94
      ((member type '("TestNQuadsNegativeSyntax" "TestNQuadsPositiveSyntax"))
95
       (nquads->rdf (get-test-doc action))))))
96
97
(define (run-test test)
98
  (let* ((predicates (test-case-document test))
99
         (type (car (get-objects predicates "http://www.w3.org/1999/02/22-rdf-syntax-ns#type")))
100
         (type (car (reverse (string-split type #\#))))
101
         (result
102
           (catch #t
103
             (lambda ()
104
               (execute-test test))
105
             (lambda (key . value)
106
               (cons key value)))))
107
    (cond
108
      ((member type '("TestTurtlePositiveSyntax" "TestTriGPositiveSyntax"
109
                      "TestNTriplesPositiveSyntax" "TestNQuadsPositiveSyntax"))
110
       (match result
111
         (((? symbol? key) . value)
112
          (update-test-case test
113
            #:result 'fail
114
            #:reason (format #f "failed with ~a: ~a" key value)))
115
         (_ (update-test-case test #:result 'pass))))
116
      ((member type '("TestTurtleNegativeSyntax" "TestTriGNegativeSyntax"
117
                      "TestNTriplesNegativeSyntax" "TestNQuadsNegativeSyntax"
118
                      "TestXMLNegativeSyntax" "TestTurtleNegativeEval"))
119
       (match result
120
         (((? symbol? key) . value) (update-test-case test #:result 'pass))
121
         (_ (update-test-case test
122
              #:result 'fail
123
              #:reason "Expected failure but got success"))))
124
      ((equal? type "TestTurtleEval")
125
       (let* ((expected (car (get-objects predicates "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#result")))
126
              (expected
127
                (catch #t
128
                  (lambda ()
129
                    (if (string? expected)
130
                        (turtle->rdf (get-test-doc expected) expected)
131
                        #f))
132
                  (lambda (key . value)
133
                    (cons key value)))))
134
         (match result
135
           (((? symbol? key) . value)
136
            (update-test-case test
137
              #:result 'fail
138
              #:reason (format #f "failed with ~a: ~a" key value)))
139
           (_
140
             (if (rdf-isomorphic? result expected)
141
                 (update-test-case test #:result 'pass)
142
                 (update-test-case test
143
                   #:result 'fail
144
                   #:reason (format #f "expected ~a but got ~a"
145
                                    expected result)))))))
146
      ((member type '("PositiveEntailmentTest" "NegativeEntailmentTest"))
147
       (pk 'predicates predicates)
148
       (let* ((regime (rdf-literal-lexical-form
149
                        (car
150
                          (get-objects
151
                            predicates
152
                            (string-append
153
                              "http://www.w3.org/2001/sw/DataAccess/tests/"
154
                              "test-manifest#entailmentRegime")))))
155
              (recognized
156
                (car
157
                  (pk 'recognized-nodes
158
                  (get-objects
159
                    predicates
160
                    (string-append "http://www.w3.org/2001/sw/DataAccess/tests/"
161
                                   "test-manifest#recognizedDatatypes"))))
162
                )
163
              (recognized (pk 'lst-reco (find-list recognized predicates)))
164
              (recognized
165
                (map
166
                  (lambda (iri)
167
                    (let loop ((types (cons* rdf:XMLLiteral rdf:langString
168
                                             xsd:datatypes)))
169
                      (match types
170
                        (() (throw 'didnotrecognize iri))
171
                        ((type types ...)
172
                         (if (member iri (rdf-datatype-iris type))
173
                             (pk 'recognized-type type)
174
                             (loop types))))))
175
                  recognized))
176
              (recognized (pk 'reco (append (list xsd:string rdf:langString) recognized)))
177
              (vocabulary (make-rdf-vocabulary recognized xsd:order xsd:compatible?))
178
              (expected
179
                (car
180
                  (get-objects
181
                    predicates
182
                    (string-append "http://www.w3.org/2001/sw/DataAccess/tests/"
183
                                   "test-manifest#result"))))
184
              (expected
185
                (catch #t
186
                  (lambda ()
187
                    (if (string? expected)
188
                        (turtle->rdf (get-test-doc expected) expected)
189
                        #f))
190
                  (lambda (key . value)
191
                    (cons key value)))))
192
         (match regime
193
           ("simple"
194
            (if (if (equal? expected #f)
195
                    (not (simple:consistent-graph? result))
196
                    (simple:entails? result expected))
197
                (if (equal? type "PositiveEntailmentTest")
198
                    (update-test-case test #:result 'pass)
199
                    (update-test-case test
200
                      #:result 'fail
201
                      #:reason "Expected negative result, got positive"))
202
                (if (equal? type "PositiveEntailmentTest")
203
                    (update-test-case test
204
                      #:result 'fail
205
                      #:reason (format #f "Expected positive result, got negative"))
206
                    (update-test-case test #:result 'pass))))
207
           ("RDF"
208
            (if (if (equal? expected #f)
209
                    (not (rdf:consistent-graph? result vocabulary))
210
                    (rdf:entails? result expected vocabulary))
211
                (if (equal? type "PositiveEntailmentTest")
212
                    (update-test-case test #:result 'pass)
213
                    (update-test-case test
214
                      #:result 'fail
215
                      #:reason "Expected negative result, got positive"))
216
                (if (equal? type "PositiveEntailmentTest")
217
                    (update-test-case test
218
                      #:result 'fail
219
                      #:reason (format #f "Expected positive result, got negative"))
220
                    (update-test-case test #:result 'pass))))
221
           ("RDFS"
222
            (if (if (equal? expected #f)
223
                    (not (rdfs:consistent-graph? result vocabulary))
224
                    (rdfs:entails? result expected vocabulary))
225
                (if (equal? type "PositiveEntailmentTest")
226
                    (update-test-case test #:result 'pass)
227
                    (update-test-case test
228
                      #:result 'fail
229
                      #:reason "Expected negative result, got positive"))
230
                (if (equal? type "PositiveEntailmentTest")
231
                    (update-test-case test
232
                      #:result 'fail
233
                      #:reason (format #f "Expected positive result, got negative"))
234
                    (update-test-case test #:result 'pass))))
235
           (_ (update-test-case test
236
                #:result 'skip
237
                #:reason (format #f "Unrecognized entailment regime: ~a"
238
                                 regime))))))
239
      (else
240
        (update-test-case test
241
          #:result 'skip
242
          #:reason (format #f "Unrecognized test type: ~a" type))))))
243
244
(define (run-tests tests expected-failures driver)
245
  "Run all the tests of the @var{tests} test suite, using identifiers starting
246
from @var{id}.  Return is undefined."
247
  (fold
248
    (lambda (test results)
249
      (let* ((result (run-test test))
250
             (result
251
               (if (assoc-ref expected-failures (test-case-id test))
252
                   (update-test-case result
253
                     #:result (cond
254
                                ((equal? 'skip (test-case-result result))
255
                                 'skip)
256
                                ((equal? 'fail (test-case-result result))
257
                                 'xfail)
258
                                ((equal? 'pass (test-case-result result))
259
                                 'xpass))
260
                     #:reason (assoc-ref expected-failures (test-case-id test)))
261
                   result)))
262
        ((test-driver-print driver) result)
263
        (cons result results)))
264
    '()
265
    tests))
266
267
(define (get-test-doc url)
268
  "Get a test suite object from the manifest at @var{url}."
269
  (call-with-values
270
    (lambda ()
271
      (http-get url))
272
    (lambda (hdr body)
273
      (if (equal? (response-code hdr) 200)
274
          (if (string? body)
275
              body
276
              (utf8->string body))
277
          (throw 'error-fetching-test-manifest (response-code hdr))))))
278
279
(define* (get-test-plan url #:key (num 1))
280
  (define document (get-test-doc url))
281
282
  (define manifest (turtle->rdf document url))
283
284
  (define tests-node
285
    (rdf-triple-object
286
      (car
287
        (filter
288
          (lambda (triple)
289
            (and (equal? (rdf-triple-subject triple) url)
290
                 (equal? (rdf-triple-predicate triple)
291
                         (string-append "http://www.w3.org/2001/sw/DataAccess/"
292
                                        "tests/test-manifest#entries"))))
293
          manifest))))
294
295
  (define tests (find-list tests-node manifest))
296
297
  (define (subgraph-at graph node)
298
    (let ((nodes (filter
299
                   (lambda (t)
300
                     (equal? (rdf-triple-subject t) node))
301
                   graph)))
302
      (if (null? nodes)
303
          '()
304
          (apply append nodes
305
                 (map
306
                   (lambda (n)
307
                     (subgraph-at graph (rdf-triple-object n)))
308
                   nodes)))))
309
310
  (cdr
311
    (fold
312
      (lambda (test result)
313
        (let* ((num (car result))
314
               (result (cdr result))
315
               (test-predicates (subgraph-at manifest test))
316
               (name (lexical->value (car (get-objects test-predicates "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#name"))))
317
               (description (lexical->value (car (get-objects test-predicates "http://www.w3.org/2000/01/rdf-schema#comment")))))
318
          (cons (+ 1 num)
319
                (cons (make-test-case test num name description test-predicates
320
                                      #f #f)
321
                      result))))
322
      `(,num . ())
323
      tests)))
324
325
(define (run-test-suite manifest expected-failures driver)
326
  "Run a test suite described by @var{manifest}."
327
  (let* ((plan (reverse (get-test-plan manifest))))
328
    ((test-driver-init driver) plan)
329
    ((test-driver-finalize driver) (run-tests plan expected-failures driver))))
330
331
(define (run-test-suites manifests expected-failures driver)
332
  "Run multiple test suites described by @var{manifests}."
333
  (let* ((plan
334
           (fold
335
             (lambda (manifest plan)
336
               (append plan (reverse (get-test-plan
337
                                       manifest #:num (+ (length plan) 1)))))
338
             '()
339
             manifests)))
340
    ((test-driver-init driver) plan)
341
    ((test-driver-finalize driver) (run-tests plan expected-failures driver))))
342