earl-report 0.5.3 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +13 -3
- data/VERSION +1 -1
- data/bin/earl-report +4 -2
- data/lib/earl_report/views/earl_report.html.haml +2 -2
- data/lib/earl_report.rb +117 -94
- data/spec/earl_report_spec.rb +113 -17
- data/spec/spec_helper.rb +33 -8
- data/spec/test-files/report-no-test.ttl +48 -0
- data/spec/test-files/results.html +17 -17
- data/spec/test-files/results.jsonld +82 -74
- data/spec/test-files/results.ttl +27 -27
- metadata +90 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6dcbb408bb40367d46daa74a9992ccb11b5ccec84d63ab89eb75cc94ad45fdb
|
4
|
+
data.tar.gz: 5731c42e85ff773264d754c3cf7aea3ecb7eedfa0507e5c7289e7390de669f11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76722b2059adaf67a4ab6166e9d7c8ed1f1216f9026598f93597ec0bfcaf724b7ea09f8612045f86857c47cf51e8943a3bc274b3e1d1397c3ccdee04b938c95c
|
7
|
+
data.tar.gz: cd209db5e59d358121730784e2b2f76da344dd2d324e50df5bc2b70013ccabd4aff341c58d637fc11a11f3adccc7ebaf52cf86912ac051ec4ac647df6c8dc707
|
data/README.md
CHANGED
@@ -78,11 +78,21 @@ can be used by specifying a customized manifest query, but may require a custom
|
|
78
78
|
The report template is in [ReSpec][] form using [Haml]() to generate individual report elements.
|
79
79
|
|
80
80
|
## Changes from previous versions
|
81
|
-
Version 0.
|
81
|
+
### Version 0.7
|
82
|
+
Version 0.7 creates incompatibilities with previous result formats. Previously, terms were "added" to the EARL vocabulary to help with coordination. This version pulls that back, but does depend on an added `earl:Report` class which acts as an appropriate container for for collections of `earl:Assertion`.
|
83
|
+
|
84
|
+
Within an `earl:TestCase`, the former `earl:assertions` property is replaced with a reverse property on `earl:test` so that, in the JSON-LD representation, an `earl:TestCase` will contain a property representing the related assertions.
|
85
|
+
|
86
|
+
Also, `earl:assertions` had been miss-appropriated to reference the sources of the individual test results provided for each test subject. A new property as appropriated from the Test Manifest vocabulary: `mf:report`. The alias `assertions` continues to be used within the JSON-LD representation, although it now maps to `mf:report` at the top level, and as mentioned, is a reverse property of `earl:test` within an `earl:TestCase`.
|
87
|
+
|
88
|
+
These changes may require updates to customized Haml templates.
|
89
|
+
|
90
|
+
### Version 0.3
|
91
|
+
Version 0.3 and prior re-constructed the test manifest used to create the body of the report, which caused information not described within the query to be lost. Starting with 0.4, all manifests and assertions are read into a single graph, and each test references a list of assertions against it using a list referenced by `mf:assertions`. Additionally, all included manifests are included in a top-level entity referenced via `mf:entries`. For example:
|
82
92
|
|
83
93
|
<> a earl:Software, doap:Project;
|
84
94
|
mf:entries (<http://example/manifest.ttl>);
|
85
|
-
|
95
|
+
mf:assertions (<spec/test-files/report-complete.ttl>) .
|
86
96
|
|
87
97
|
<http://example/manifest.ttl> a mf:Manifest, earl:Report;
|
88
98
|
mf:name "Example Test Cases";
|
@@ -94,7 +104,7 @@ Version 0.3 and prior re-constructed the test manifest used to create the body o
|
|
94
104
|
rdfs:comment "Blank subject";
|
95
105
|
mf:action <http://example/test-00.ttl>;
|
96
106
|
mf:result <http://example/test-00.out>;
|
97
|
-
|
107
|
+
mf:assertions ([
|
98
108
|
a earl:Assertion;
|
99
109
|
earl:assertedBy <https://greggkellogg.net/foaf#me>;
|
100
110
|
earl:mode earl:automatic;
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.1
|
data/bin/earl-report
CHANGED
@@ -15,6 +15,7 @@ OPT_ARGS = [
|
|
15
15
|
["--output", "-o", GetoptLong::REQUIRED_ARGUMENT,"Output report to file"],
|
16
16
|
["--query", GetoptLong::REQUIRED_ARGUMENT,"Query, or file containing query for extracting information from Test manifest"],
|
17
17
|
["--rc", GetoptLong::NO_ARGUMENT, "Write options to run-control file"],
|
18
|
+
["--strict", GetoptLong::NO_ARGUMENT, "Fails if any skipped result is found"],
|
18
19
|
["--template", GetoptLong::OPTIONAL_ARGUMENT,"Specify or return default report template"],
|
19
20
|
["--verbose", GetoptLong::NO_ARGUMENT, "Detail on execution"],
|
20
21
|
["--help", "-?", GetoptLong::NO_ARGUMENT, "This message"]
|
@@ -65,6 +66,7 @@ opts.each do |opt, arg|
|
|
65
66
|
when '--name' then options[:name] = arg
|
66
67
|
when '--output' then options[:io] = File.open(arg, "w")
|
67
68
|
when '--rc' then options[:rc] = true
|
69
|
+
when '--strict' then options[:strict] = true
|
68
70
|
when '--template' then options[:template] = (File.open(arg, "r") unless arg.empty?)
|
69
71
|
when '--verbose' then options[:verbose] = true
|
70
72
|
when '--help' then usage
|
@@ -94,6 +96,6 @@ if options.has_key?(:template) && options[:template].nil?
|
|
94
96
|
elsif ARGV.empty?
|
95
97
|
usage
|
96
98
|
else
|
97
|
-
earl = EarlReport.new(*ARGV, options)
|
98
|
-
earl.generate(options)
|
99
|
+
earl = EarlReport.new(*ARGV, **options)
|
100
|
+
earl.generate(**options)
|
99
101
|
end
|
@@ -333,7 +333,7 @@
|
|
333
333
|
- assertion = test['assertions'].detect {|a| a['subject'] == subject['@id']}
|
334
334
|
- pass_fail = assertion['result']['outcome'].split(':').last.upcase.sub(/(PASS|FAIL)ED$/, '\1')
|
335
335
|
- passed_tests[ndx2][ndx] = (passed_tests[ndx2][ndx] || 0) + (pass_fail == 'PASS' ? 1 : 0)
|
336
|
-
%td{class: pass_fail,
|
336
|
+
%td{class: pass_fail, typeof: assertion['@type']}
|
337
337
|
- if assertion['assertedBy'] && !assertion['assertedBy'].start_with?('_:')
|
338
338
|
%link{property: "earl:assertedBy", href: assertion['assertedBy']}
|
339
339
|
- if assertion['test'] && !assertion['test'].start_with?('_:')
|
@@ -418,7 +418,7 @@
|
|
418
418
|
%td{class: (pct == 100.0 ? 'passed-all' : (pct >= 85.0 ? 'passed-most' : 'passed-some'))}
|
419
419
|
= "#{passed}/#{total} (#{'%.1f' % pct}%)"
|
420
420
|
- unless tests['assertions'].empty?
|
421
|
-
%section.appendix#individual-test-results{rel: "xhv:related
|
421
|
+
%section.appendix#individual-test-results{rel: "xhv:related mf:report"}
|
422
422
|
%h2
|
423
423
|
%span.secno="B."
|
424
424
|
Individual Test Results
|
data/lib/earl_report.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# EARL reporting
|
2
|
-
require '
|
2
|
+
require 'json/ld'
|
3
|
+
require 'rdf/ordered_repo'
|
4
|
+
require 'rdf/turtle'
|
5
|
+
require 'rdf/vocab'
|
3
6
|
require 'sparql'
|
4
7
|
require 'haml'
|
5
8
|
require 'open-uri'
|
@@ -11,6 +14,7 @@ class EarlReport
|
|
11
14
|
autoload :VERSION, 'earl_report/version'
|
12
15
|
|
13
16
|
attr_reader :graph
|
17
|
+
attr_reader :verbose
|
14
18
|
|
15
19
|
# Return information about each test.
|
16
20
|
# Tests all have an mf:action property.
|
@@ -90,12 +94,20 @@ class EarlReport
|
|
90
94
|
"foaf" => "http://xmlns.com/foaf/0.1/",
|
91
95
|
"rdfs" => "http://www.w3.org/2000/01/rdf-schema#",
|
92
96
|
"assertedBy" => {"@type" => "@id"},
|
93
|
-
"assertions" => {"@type" => "@id", "@container" => "@set"},
|
97
|
+
"assertions" => {"@id" => "mf:report", "@type" => "@id", "@container" => "@set"},
|
94
98
|
"bibRef" => {"@id" => "dc:bibliographicCitation"},
|
95
99
|
"created" => {"@id" => "doap:created", "@type" => "xsd:date"},
|
96
100
|
"description" => {"@id" => "rdfs:comment", "@language" => "en"},
|
97
101
|
"developer" => {"@id" => "doap:developer", "@type" => "@id", "@container" => "@set"},
|
98
102
|
"doapDesc" => {"@id" => "doap:description", "@language" => "en"},
|
103
|
+
"entries" => {
|
104
|
+
"@id" => "mf:entries", "@type" => "@id", "@container" => "@list",
|
105
|
+
"@context" => {
|
106
|
+
"assertions" => {
|
107
|
+
"@reverse" => "earl:test", "@type" => "@id", "@container" => "@set"
|
108
|
+
},
|
109
|
+
}
|
110
|
+
},
|
99
111
|
"generatedBy" => {"@type" => "@id"},
|
100
112
|
"homepage" => {"@id" => "doap:homepage", "@type" => "@id"},
|
101
113
|
"language" => {"@id" => "doap:programming-language"},
|
@@ -111,7 +123,6 @@ class EarlReport
|
|
111
123
|
"testAction" => {"@id" => "mf:action", "@type" => "@id"},
|
112
124
|
"testResult" => {"@id" => "mf:result", "@type" => "@id"},
|
113
125
|
"title" => {"@id" => "mf:name"},
|
114
|
-
"entries" => {"@id" => "mf:entries", "@type" => "@id", "@container" => "@list"},
|
115
126
|
"testSubjects" => {"@type" => "@id", "@container" => "@set"},
|
116
127
|
"xsd" => {"@id" => "http://www.w3.org/2001/XMLSchema#"}
|
117
128
|
},
|
@@ -181,34 +192,41 @@ class EarlReport
|
|
181
192
|
).gsub(/^ /, '')
|
182
193
|
|
183
194
|
# Convenience vocabularies
|
184
|
-
class EARL < RDF::Vocabulary("http://www.w3.org/ns/earl#"); end
|
185
195
|
class MF < RDF::Vocabulary("http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#"); end
|
186
196
|
|
187
197
|
##
|
188
198
|
# Load test assertions and look for referenced software and developer information
|
189
|
-
#
|
190
|
-
#
|
191
|
-
# @
|
192
|
-
#
|
193
|
-
#
|
194
|
-
#
|
195
|
-
#
|
196
|
-
#
|
197
|
-
#
|
198
|
-
#
|
199
|
-
#
|
200
|
-
#
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
199
|
+
#
|
200
|
+
# @param [Array<String>] files Assertions
|
201
|
+
# @param [String] base (nil) Base IRI for loading Manifest
|
202
|
+
# @param [String] bibRef ('Unknown reference')
|
203
|
+
# ReSpec bibliography reference for specification being tested
|
204
|
+
# @param [Boolean] json (false) File is in the JSON format of a report.
|
205
|
+
# @param [String, Array<String>] manifest (nil) Test manifest(s)
|
206
|
+
# @param [String] name ('Unknown') Name of specification
|
207
|
+
# @param [String] query (MANIFEST_QUERY)
|
208
|
+
# Query, or file containing query for extracting information from Test manifests
|
209
|
+
# @param [Boolean] strict (false) Abort on any warning
|
210
|
+
# @param [Boolean] verbose (false)
|
211
|
+
def initialize(*files,
|
212
|
+
base: nil,
|
213
|
+
bibRef: 'Unknown reference',
|
214
|
+
json: false,
|
215
|
+
manifest: nil,
|
216
|
+
name: 'Unknown',
|
217
|
+
query: MANIFEST_QUERY,
|
218
|
+
strict: false,
|
219
|
+
verbose: false,
|
220
|
+
**options)
|
221
|
+
@verbose = verbose
|
222
|
+
raise "Test Manifests must be specified with :manifest option" unless manifest || json
|
206
223
|
raise "Require at least one input file" if files.empty?
|
207
224
|
@files = files
|
208
225
|
@prefixes = {}
|
226
|
+
@warnings = 0
|
209
227
|
|
210
|
-
# If provided
|
211
|
-
if
|
228
|
+
# If provided json, it is used for generating all other output forms
|
229
|
+
if json
|
212
230
|
@json_hash = ::JSON.parse(File.read(files.first))
|
213
231
|
# Add a base_uri so relative subjects aren't dropped
|
214
232
|
JSON::LD::Reader.open(files.first, base_uri: "http://example.org/report") do |r|
|
@@ -223,25 +241,25 @@ class EarlReport
|
|
223
241
|
end
|
224
242
|
|
225
243
|
# Load manifests, possibly with base URI
|
226
|
-
status "read #{
|
244
|
+
status "read #{manifest.inspect}"
|
227
245
|
man_opts = {}
|
228
|
-
man_opts[:base_uri] = RDF::URI(
|
246
|
+
man_opts[:base_uri] = RDF::URI(base) if base
|
229
247
|
@graph = RDF::Graph.new
|
230
|
-
Array(
|
248
|
+
Array(manifest).each do |man|
|
231
249
|
g = RDF::Graph.load(man, unique_bnodes: true, **man_opts)
|
232
250
|
status " loaded #{g.count} triples from #{man}"
|
233
251
|
graph << g
|
234
252
|
end
|
235
253
|
|
236
254
|
# Hash test cases by URI
|
237
|
-
tests = SPARQL.execute(
|
255
|
+
tests = SPARQL.execute(query, graph)
|
238
256
|
.to_a
|
239
257
|
.inject({}) {|memo, soln| memo[soln[:uri]] = soln; memo}
|
240
258
|
|
241
259
|
if tests.empty?
|
242
260
|
raise "no tests found querying manifest.\n" +
|
243
261
|
"Results are found using the following query, this can be overridden using the --query option:\n" +
|
244
|
-
"#{
|
262
|
+
"#{query}"
|
245
263
|
end
|
246
264
|
|
247
265
|
# Manifests in graph
|
@@ -262,7 +280,7 @@ class EarlReport
|
|
262
280
|
status "read #{file}"
|
263
281
|
file_graph = RDF::Graph.load(file)
|
264
282
|
if file_graph.first_object(predicate: RDF::URI('http://www.w3.org/ns/earl#testSubjects'))
|
265
|
-
|
283
|
+
warn " skip #{file}, which seems to be a previous rollup earl report"
|
266
284
|
@files -= [file]
|
267
285
|
else
|
268
286
|
status " loaded #{file_graph.count} triples"
|
@@ -293,19 +311,22 @@ class EarlReport
|
|
293
311
|
end
|
294
312
|
|
295
313
|
# Load developers referenced from Test Subjects
|
296
|
-
if !solutions.
|
314
|
+
if !solutions.all? {|s| s[:developer]}
|
297
315
|
warn "\nNo developer identified for #{solutions.first[:uri]}"
|
298
|
-
elsif !solutions.
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
316
|
+
elsif !solutions.all? {|s| s[:devName]}
|
317
|
+
solutions.reject {|s| s[:devName]}.each do |no_foaf|
|
318
|
+
status " read description for developer #{no_foaf[:developer].inspect}"
|
319
|
+
begin
|
320
|
+
foaf_graph = RDF::Graph.load(no_foaf[:developer])
|
321
|
+
status " loaded #{foaf_graph.count} triples"
|
322
|
+
file_graph << foaf_graph.to_a
|
323
|
+
rescue
|
324
|
+
warn "\nfailed to load FOAF from #{no_foaf[:developer]}: #{$!}"
|
325
|
+
end
|
308
326
|
end
|
327
|
+
|
328
|
+
# Reload solutions
|
329
|
+
solutions = SPARQL.execute(TEST_SUBJECT_QUERY, file_graph)
|
309
330
|
end
|
310
331
|
|
311
332
|
release = nil
|
@@ -314,15 +335,15 @@ class EarlReport
|
|
314
335
|
subjects[solution[:uri]] = RDF::URI(file)
|
315
336
|
|
316
337
|
# Add TestSubject information to main graph
|
317
|
-
|
338
|
+
doapName = solution[:name].to_s if solution[:name]
|
318
339
|
language = solution[:language].to_s if solution[:language]
|
319
340
|
doapDesc = solution[:doapDesc] if solution[:doapDesc]
|
320
341
|
doapDesc.language ||= :en if doapDesc
|
321
342
|
devName = solution[:devName].to_s if solution[:devName]
|
322
343
|
graph << RDF::Statement(solution[:uri], RDF.type, RDF::Vocab::DOAP.Project)
|
323
|
-
graph << RDF::Statement(solution[:uri], RDF.type, EARL.TestSubject)
|
324
|
-
graph << RDF::Statement(solution[:uri], RDF.type, EARL.Software)
|
325
|
-
graph << RDF::Statement(solution[:uri], RDF::Vocab::DOAP.name,
|
344
|
+
graph << RDF::Statement(solution[:uri], RDF.type, RDF::Vocab::EARL.TestSubject)
|
345
|
+
graph << RDF::Statement(solution[:uri], RDF.type, RDF::Vocab::EARL.Software)
|
346
|
+
graph << RDF::Statement(solution[:uri], RDF::Vocab::DOAP.name, doapName)
|
326
347
|
graph << RDF::Statement(solution[:uri], RDF::Vocab::DOAP.developer, solution[:developer])
|
327
348
|
graph << RDF::Statement(solution[:uri], RDF::Vocab::DOAP.homepage, solution[:homepage]) if solution[:homepage]
|
328
349
|
graph << RDF::Statement(solution[:uri], RDF::Vocab::DOAP.description, doapDesc) if doapDesc
|
@@ -350,12 +371,12 @@ class EarlReport
|
|
350
371
|
subject = solution[:subject]
|
351
372
|
unless tests[solution[:test]]
|
352
373
|
assertion_stats["Skipped"] = assertion_stats["Skipped"].to_i + 1
|
353
|
-
|
374
|
+
warn "Skipping result for #{solution[:test]} for #{subject}, which is not defined in manifests"
|
354
375
|
next
|
355
376
|
end
|
356
377
|
unless subjects[subject]
|
357
378
|
assertion_stats["Missing Subject"] = assertion_stats["Missing Subject"].to_i + 1
|
358
|
-
|
379
|
+
warn "No test result subject found for #{subject}: in #{subjects.keys.join(', ')}"
|
359
380
|
next
|
360
381
|
end
|
361
382
|
found_solutions ||= true
|
@@ -366,19 +387,19 @@ class EarlReport
|
|
366
387
|
ary = test_assertion_lists[solution[:test]]
|
367
388
|
|
368
389
|
ary[ndx] = a = RDF::Node.new
|
369
|
-
graph << RDF::Statement(a, RDF.type, EARL.Assertion)
|
370
|
-
graph << RDF::Statement(a, EARL.subject, subject)
|
371
|
-
graph << RDF::Statement(a, EARL.test, solution[:test])
|
372
|
-
graph << RDF::Statement(a, EARL.assertedBy, solution[:by])
|
373
|
-
graph << RDF::Statement(a, EARL.mode, solution[:mode]) if solution[:mode]
|
390
|
+
graph << RDF::Statement(a, RDF.type, RDF::Vocab::EARL.Assertion)
|
391
|
+
graph << RDF::Statement(a, RDF::Vocab::EARL.subject, subject)
|
392
|
+
graph << RDF::Statement(a, RDF::Vocab::EARL.test, solution[:test])
|
393
|
+
graph << RDF::Statement(a, RDF::Vocab::EARL.assertedBy, solution[:by])
|
394
|
+
graph << RDF::Statement(a, RDF::Vocab::EARL.mode, solution[:mode]) if solution[:mode]
|
374
395
|
r = RDF::Node.new
|
375
|
-
graph << RDF::Statement(a, EARL.result, r)
|
376
|
-
graph << RDF::Statement(r, RDF.type, EARL.TestResult)
|
377
|
-
graph << RDF::Statement(r, EARL.outcome, solution[:outcome])
|
396
|
+
graph << RDF::Statement(a, RDF::Vocab::EARL.result, r)
|
397
|
+
graph << RDF::Statement(r, RDF.type, RDF::Vocab::EARL.TestResult)
|
398
|
+
graph << RDF::Statement(r, RDF::Vocab::EARL.outcome, solution[:outcome])
|
378
399
|
end
|
379
400
|
|
380
401
|
# See if subject did not report results, which may indicate a formatting error in the EARL source
|
381
|
-
|
402
|
+
warn "No results found for #{subject} using #{ASSERTION_QUERY}" unless found_solutions
|
382
403
|
end
|
383
404
|
end
|
384
405
|
|
@@ -390,17 +411,14 @@ class EarlReport
|
|
390
411
|
unless a
|
391
412
|
assertion_stats["Untested"] = assertion_stats["Untested"].to_i + 1
|
392
413
|
ary[ndx] = a = RDF::Node.new
|
393
|
-
graph << RDF::Statement(a, RDF.type, EARL.Assertion)
|
394
|
-
graph << RDF::Statement(a, EARL.subject, subjects.keys[ndx])
|
395
|
-
graph << RDF::Statement(a, EARL.test, test)
|
414
|
+
graph << RDF::Statement(a, RDF.type, RDF::Vocab::EARL.Assertion)
|
415
|
+
graph << RDF::Statement(a, RDF::Vocab::EARL.subject, subjects.keys[ndx])
|
416
|
+
graph << RDF::Statement(a, RDF::Vocab::EARL.test, test)
|
396
417
|
r = RDF::Node.new
|
397
|
-
graph << RDF::Statement(a, EARL.result, r)
|
398
|
-
graph << RDF::Statement(r, RDF.type, EARL.TestResult)
|
399
|
-
graph << RDF::Statement(r, EARL.outcome, EARL.untested)
|
418
|
+
graph << RDF::Statement(a, RDF::Vocab::EARL.result, r)
|
419
|
+
graph << RDF::Statement(r, RDF.type, RDF::Vocab::EARL.TestResult)
|
420
|
+
graph << RDF::Statement(r, RDF::Vocab::EARL.outcome, RDF::Vocab::EARL.untested)
|
400
421
|
end
|
401
|
-
|
402
|
-
# This counts on order being preserved in default repository so we can avoid using an rdf:List
|
403
|
-
graph << RDF::Statement(test, EARL.assertions, a)
|
404
422
|
end
|
405
423
|
end
|
406
424
|
|
@@ -409,10 +427,10 @@ class EarlReport
|
|
409
427
|
# Add report wrapper to graph
|
410
428
|
ttl = TURTLE_PREFIXES + %(
|
411
429
|
<> a earl:Software, doap:Project;
|
412
|
-
doap:name #{quoted(
|
413
|
-
dc:bibliographicCitation "#{
|
430
|
+
doap:name #{quoted(name)};
|
431
|
+
dc:bibliographicCitation "#{bibRef}";
|
414
432
|
earl:generatedBy <https://rubygems.org/gems/earl-report>;
|
415
|
-
|
433
|
+
mf:report #{subjects.values.map {|f| f.to_ntriples}.join(",\n ")};
|
416
434
|
earl:testSubjects #{subjects.keys.map {|f| f.to_ntriples}.join(",\n ")};
|
417
435
|
mf:entries (#{man_uris.map {|f| f.to_ntriples}.join("\n ")}) .
|
418
436
|
).gsub(/^ /, '') +
|
@@ -421,19 +439,21 @@ class EarlReport
|
|
421
439
|
|
422
440
|
# Each manifest is an earl:Report
|
423
441
|
man_uris.each do |u|
|
424
|
-
graph << RDF::Statement.new(u, RDF.type, EARL.Report)
|
442
|
+
graph << RDF::Statement.new(u, RDF.type, RDF::Vocab::EARL.Report)
|
425
443
|
end
|
426
444
|
|
427
445
|
# Each subject is an earl:TestSubject
|
428
446
|
subjects.keys.each do |u|
|
429
|
-
graph << RDF::Statement.new(u, RDF.type, EARL.TestSubject)
|
447
|
+
graph << RDF::Statement.new(u, RDF.type, RDF::Vocab::EARL.TestSubject)
|
430
448
|
end
|
431
449
|
|
432
450
|
# Each assertion test is a earl:TestCriterion and earl:TestCase
|
433
451
|
test_resources.each do |u|
|
434
|
-
graph << RDF::Statement.new(u, RDF.type, EARL.TestCriterion)
|
435
|
-
graph << RDF::Statement.new(u, RDF.type, EARL.TestCase)
|
452
|
+
graph << RDF::Statement.new(u, RDF.type, RDF::Vocab::EARL.TestCriterion)
|
453
|
+
graph << RDF::Statement.new(u, RDF.type, RDF::Vocab::EARL.TestCase)
|
436
454
|
end
|
455
|
+
|
456
|
+
raise "Warnings issued in strict mode" if strict && @warnings > 0
|
437
457
|
end
|
438
458
|
|
439
459
|
##
|
@@ -441,48 +461,47 @@ class EarlReport
|
|
441
461
|
#
|
442
462
|
# If no `io` option is provided, the output is returned as a string
|
443
463
|
#
|
464
|
+
# @param [Symbol] format (:html)
|
465
|
+
# @param [IO] io (nil)
|
466
|
+
# `IO` to output results
|
444
467
|
# @param [Hash{Symbol => Object}] options
|
445
|
-
# @
|
446
|
-
#
|
447
|
-
# Optional `IO` to output results
|
468
|
+
# @param [String] template
|
469
|
+
# HAML template for generating report
|
448
470
|
# @return [String] serialized graph, if `io` is nil
|
449
|
-
def generate(
|
450
|
-
options = {format: :html}.merge(options)
|
471
|
+
def generate(format: :html, io: nil, template: nil, **options)
|
451
472
|
|
452
|
-
|
453
|
-
|
454
|
-
status("generate: #{options[:format]}")
|
473
|
+
status("generate: #{format}")
|
455
474
|
##
|
456
475
|
# Retrieve Hashed information in JSON-LD format
|
457
|
-
case
|
476
|
+
case format
|
458
477
|
when :jsonld, :json
|
459
478
|
json = json_hash.to_json(JSON::LD::JSON_STATE)
|
460
479
|
io.write(json) if io
|
461
480
|
json
|
462
481
|
when :turtle, :ttl
|
463
482
|
if io
|
464
|
-
earl_turtle(
|
483
|
+
earl_turtle(io: io)
|
465
484
|
else
|
466
485
|
io = StringIO.new
|
467
|
-
earl_turtle(
|
486
|
+
earl_turtle(io: io)
|
468
487
|
io.rewind
|
469
488
|
io.read
|
470
489
|
end
|
471
490
|
when :html
|
472
|
-
|
473
|
-
when String then
|
474
|
-
when IO, StringIO then
|
491
|
+
haml = case template
|
492
|
+
when String then template
|
493
|
+
when IO, StringIO then template.read
|
475
494
|
else
|
476
495
|
File.read(File.expand_path('../earl_report/views/earl_report.html.haml', __FILE__))
|
477
496
|
end
|
478
497
|
|
479
498
|
# Generate HTML report
|
480
|
-
html = Haml::Engine.new(
|
499
|
+
html = Haml::Engine.new(haml, format: :xhtml).render(self, tests: json_hash)
|
481
500
|
io.write(html) if io
|
482
501
|
html
|
483
502
|
else
|
484
|
-
writer = RDF::Writer.for(
|
485
|
-
writer.dump(@graph, io,
|
503
|
+
writer = RDF::Writer.for(format)
|
504
|
+
writer.dump(@graph, io, standard_prefixes: true, **options)
|
486
505
|
end
|
487
506
|
end
|
488
507
|
|
@@ -519,12 +538,11 @@ class EarlReport
|
|
519
538
|
|
520
539
|
##
|
521
540
|
# Output consoloated EARL report as Turtle
|
522
|
-
# @param [
|
523
|
-
#
|
541
|
+
# @param [IO] io ($stdout)
|
542
|
+
# `IO` to output results
|
524
543
|
# @return [String]
|
525
|
-
def earl_turtle(
|
544
|
+
def earl_turtle(io: $stdout)
|
526
545
|
context = JSON::LD::Context.parse(json_hash['@context'])
|
527
|
-
io = options[:io]
|
528
546
|
io.write(TURTLE_PREFIXES + "\n")
|
529
547
|
|
530
548
|
# Write project header
|
@@ -564,7 +582,11 @@ class EarlReport
|
|
564
582
|
when '@type'
|
565
583
|
"a " + ttl_value(dv)
|
566
584
|
when 'assertions'
|
567
|
-
|
585
|
+
if dv.all? {|a| a.is_a?(String)}
|
586
|
+
"mf:report #{ttl_value(dv, whitespace: "\n ")}"
|
587
|
+
else
|
588
|
+
"earl:assertions #{dv.map {|a| ttl_assertion(a)}.join(", ")}"
|
589
|
+
end
|
568
590
|
when 'entries'
|
569
591
|
"mf:entries #{ttl_value({'@list' => dv}, whitespace: "\n ")}"
|
570
592
|
when 'release'
|
@@ -628,10 +650,11 @@ class EarlReport
|
|
628
650
|
end
|
629
651
|
|
630
652
|
def warn(message)
|
653
|
+
@warnings += 1
|
631
654
|
$stderr.puts message
|
632
655
|
end
|
633
656
|
|
634
657
|
def status(message)
|
635
|
-
$stderr.puts message if
|
658
|
+
$stderr.puts message if verbose
|
636
659
|
end
|
637
660
|
end
|