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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47de1e3c1d07adb1a2ae440c1c53f72ceeb2c7b4e33d947739474225c802ed50
4
- data.tar.gz: 611468fcef85b3a812ae184759d3c9806106ac2d15611f63cdbbe08fe194202b
3
+ metadata.gz: c6dcbb408bb40367d46daa74a9992ccb11b5ccec84d63ab89eb75cc94ad45fdb
4
+ data.tar.gz: 5731c42e85ff773264d754c3cf7aea3ecb7eedfa0507e5c7289e7390de669f11
5
5
  SHA512:
6
- metadata.gz: e023c3c5a1c42da0dbfc976149e50e590b3c9b770e0e66372794f68b2e881de064a515d0c6d8f73ac7a2acf1920cc95e0b35735a3a4897742ac6cb9d3385d8fa
7
- data.tar.gz: e1c6bc8836bc9629fd36c0bc67e2f5dd30694a28f64da9ee06d864e29b0ce3d1636a83e755f878cb756d424f93b739f01246e08156085d73e8ccc48867c8bc09
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.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 `earl:assertions`. Additionally, all included manifests are included in a top-level entity referenced via `mf:entries`. For example:
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
- earl:assertions (<spec/test-files/report-complete.ttl>) .
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
- earl:assertions ([
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.5.3
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, property: "earl:assertions", typeof: assertion['@type']}
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 earl:assertions"}
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 'linkeddata'
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
- # @overload initialize(*files)
190
- # @param [Array<String>] files Assertions
191
- # @overload initialize(*files, options = {})
192
- # @param [Hash{Symbol => Object}] options
193
- # @option options [Boolean] :verbose (true)
194
- # @option options [String] :base Base IRI for loading Manifest
195
- # @option options [String] :bibRef
196
- # ReSpec bibliography reference for specification being tested
197
- # @option options [String] :json Result of previous JSON-LD generation
198
- # @option options [String, Array<String>] :manifest Test manifest
199
- # @option options [String] :name Name of specification
200
- # @option options [String] :query
201
- # Query, or file containing query for extracting information from Test manifests
202
- def initialize(*files)
203
- @options = files.last.is_a?(Hash) ? files.pop.dup : {}
204
- @options[:query] ||= MANIFEST_QUERY
205
- raise "Test Manifests must be specified with :manifest option" unless @options[:manifest] || @options[:json]
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 :json, it is used for generating all other output forms
211
- if @options[:json]
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 #{@options[:manifest].inspect}"
244
+ status "read #{manifest.inspect}"
227
245
  man_opts = {}
228
- man_opts[:base_uri] = RDF::URI(@options[:base]) if @options[:base]
246
+ man_opts[:base_uri] = RDF::URI(base) if base
229
247
  @graph = RDF::Graph.new
230
- Array(@options[:manifest]).each do |man|
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(@options[:query], graph)
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
- "#{@options[:query]}"
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
- status " skip #{file}, which seems to be a previous rollup earl report"
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.first[:developer]
314
+ if !solutions.all? {|s| s[:developer]}
297
315
  warn "\nNo developer identified for #{solutions.first[:uri]}"
298
- elsif !solutions.first[:devName]
299
- status " read description for developer #{solutions.first[:developer].inspect}"
300
- begin
301
- foaf_graph = RDF::Graph.load(solutions.first[:developer])
302
- status " loaded #{foaf_graph.count} triples"
303
- file_graph << foaf_graph.to_a
304
- # Reload solutions
305
- solutions = SPARQL.execute(TEST_SUBJECT_QUERY, file_graph)
306
- rescue
307
- warn "\nfailed to load FOAF from #{solutions.first[:developer]}: #{$!}"
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
- name = solution[:name].to_s if solution[:name]
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, 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
- $stderr.puts "Skipping result for #{solution[:test]} for #{subject}, which is not defined in manifests"
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
- $stderr.puts "No test result subject found for #{subject}: in #{subjects.keys.join(', ')}"
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
- $stderr.puts "No results found for #{subject} using #{ASSERTION_QUERY}" unless found_solutions
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(@options.fetch(:name, 'Unknown'))};
413
- dc:bibliographicCitation "#{@options.fetch(:bibRef, 'Unknown reference')}";
430
+ doap:name #{quoted(name)};
431
+ dc:bibliographicCitation "#{bibRef}";
414
432
  earl:generatedBy <https://rubygems.org/gems/earl-report>;
415
- earl:assertions #{subjects.values.map {|f| f.to_ntriples}.join(",\n ")};
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
- # @option options [Symbol] format (:html)
446
- # @option options[IO] :io
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(options = {})
450
- options = {format: :html}.merge(options)
471
+ def generate(format: :html, io: nil, template: nil, **options)
451
472
 
452
- io = options[:io]
453
-
454
- status("generate: #{options[:format]}")
473
+ status("generate: #{format}")
455
474
  ##
456
475
  # Retrieve Hashed information in JSON-LD format
457
- case options[:format]
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(options)
483
+ earl_turtle(io: io)
465
484
  else
466
485
  io = StringIO.new
467
- earl_turtle(options.merge(io: io))
486
+ earl_turtle(io: io)
468
487
  io.rewind
469
488
  io.read
470
489
  end
471
490
  when :html
472
- template = case options[:template]
473
- when String then options[:tempate]
474
- when IO, StringIO then options[:template].read
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(template, format: :xhtml).render(self, tests: json_hash)
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(options[:format])
485
- writer.dump(@graph, io, options.merge(standard_prefixes: true))
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 [Hash{Symbol => Object}] options
523
- # @option options [IO, StringIO] :io
541
+ # @param [IO] io ($stdout)
542
+ # `IO` to output results
524
543
  # @return [String]
525
- def earl_turtle(options)
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
- "earl:assertions #{dv.map {|a| ttl_assertion(a)}.join(", ")}"
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 @options[:verbose]
658
+ $stderr.puts message if verbose
636
659
  end
637
660
  end