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