earl-report 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -78,7 +78,7 @@ The `earl-report` command may be used to directly create a report from zero or m
78
78
 
79
79
  gem install earl-report
80
80
 
81
- earl \
81
+ earl-report \
82
82
  --base # Base URI to use when loading test manifest
83
83
  --bibRef # ReSpec BibRef of specification being reported upon
84
84
  --format # Format of output, one of 'ttl', 'json', or 'html'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
data/bin/earl-report CHANGED
@@ -6,15 +6,12 @@ require 'earl_report'
6
6
  require 'getoptlong'
7
7
  require 'yaml'
8
8
 
9
- def run(input, options)
10
- end
11
-
12
9
  OPT_ARGS = [
13
10
  ["--base", GetoptLong::REQUIRED_ARGUMENT,"Base URI to use when loading test manifest"],
14
11
  ["--bibRef", GetoptLong::REQUIRED_ARGUMENT,"ReSpec BibRef of specification being reported upon"],
15
12
  ["--format", "-f", GetoptLong::REQUIRED_ARGUMENT,"Format of output, one of 'ttl', 'json', or 'html'"],
16
13
  ["--json", GetoptLong::NO_ARGUMENT, "Input is a JSON-LD formatted result"],
17
- ["--manifest", GetoptLong::REQUIRED_ARGUMENT,"Test manifest"],
14
+ ["--manifest", GetoptLong::REQUIRED_ARGUMENT,"Test manifest(s)"],
18
15
  ["--name", GetoptLong::REQUIRED_ARGUMENT,"Name of specification"],
19
16
  ["--output", "-o", GetoptLong::REQUIRED_ARGUMENT,"Output report to file"],
20
17
  ["--query", GetoptLong::REQUIRED_ARGUMENT,"Query, or file containing query for extracting information from Test manifest"],
@@ -58,8 +55,8 @@ opts.each do |opt, arg|
58
55
  when '--base' then options[:base] = arg
59
56
  when '--bibRef' then options[:bibRef] = arg
60
57
  when '--format' then options[:format] = arg.to_sym
61
- when '--manifest' then options[:manifest] = arg
62
- when '--query' then options[:manifest] = arg
58
+ when '--manifest' then options[:manifest] = arg.split(',').map(&:strip)
59
+ when '--query' then options[:query] = arg
63
60
  when '--base' then options[:base] = arg
64
61
  when '--json' then options[:json] = true
65
62
  when '--name' then options[:name] = arg
data/lib/earl_report.rb CHANGED
@@ -11,18 +11,26 @@ class EarlReport
11
11
 
12
12
  attr_reader :graph
13
13
 
14
+ # Return information about each test, and for the first test in the
15
+ # manifest, about the manifest itself
14
16
  MANIFEST_QUERY = %(
15
17
  PREFIX dc: <http://purl.org/dc/terms/>
16
18
  PREFIX mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#>
17
19
  PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
18
20
  PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
19
21
 
20
- SELECT ?lh ?uri ?title ?description ?testAction ?testResult
22
+ SELECT ?lh ?uri ?type ?title ?description ?testAction ?testResult ?manUri ?manComment
21
23
  WHERE {
22
- ?uri mf:name ?title; mf:action ?testAction.
23
- OPTIONAL { ?uri rdfs:comment ?description. }
24
- OPTIONAL { ?uri mf:result ?testResult. }
25
- OPTIONAL { [ mf:entries ?lh] . ?lh rdf:first ?uri . }
24
+ ?uri a ?type;
25
+ mf:name ?title;
26
+ mf:action ?testAction .
27
+ OPTIONAL { ?uri rdfs:comment ?description . }
28
+ OPTIONAL { ?uri mf:result ?testResult . }
29
+ OPTIONAL {
30
+ ?manUri a mf:Manifest; mf:entries ?lh .
31
+ ?lh rdf:first ?uri .
32
+ OPTIONAL { ?manUri rdfs:comment ?manComment . }
33
+ }
26
34
  }
27
35
  ).freeze
28
36
 
@@ -37,9 +45,9 @@ class EarlReport
37
45
  OPTIONAL { ?uri doap:homepage ?homepage . }
38
46
  OPTIONAL { ?uri doap:description ?doapDesc . }
39
47
  OPTIONAL { ?uri doap:programming-language ?language . }
48
+ OPTIONAL { ?developer a ?devType .}
40
49
  OPTIONAL { ?developer foaf:name ?devName .}
41
- OPTIONAL { ?developer a ?devType . }
42
- OPTIONAL { ?developer foaf:homepage ?devHomepage . }
50
+ OPTIONAL { ?developer foaf:homepage ?devHomepage .}
43
51
  }
44
52
  ).freeze
45
53
 
@@ -101,7 +109,7 @@ class EarlReport
101
109
  test: {"@type" => "@id"},
102
110
  testAction: {"@id" => "mf:action", "@type" => "@id"},
103
111
  testResult: {"@id" => "mf:result", "@type" => "@id"},
104
- tests: {"@type" => "@id", "@container" => "@list"},
112
+ entries: {"@id" => "mf:entries", "@type" => "@id", "@container" => "@list"},
105
113
  testSubjects: {"@type" => "@id", "@container" => "@list"},
106
114
  title: {"@id" => "dc:title"},
107
115
  xsd: {"@id" => "http://www.w3.org/2001/XMLSchema#"}
@@ -120,14 +128,14 @@ class EarlReport
120
128
  # @option options [String] :bibRef
121
129
  # ReSpec bibliography reference for specification being tested
122
130
  # @option options [String] :json Result of previous JSON-LD generation
123
- # @option options [String] :manifest Test manifest
131
+ # @option options [String, Array<String>] :manifest Test manifest
124
132
  # @option options [String] :name Name of specification
125
133
  # @option options [String] :query
126
- # Query, or file containing query for extracting information from Test manifest
134
+ # Query, or file containing query for extracting information from Test manifests
127
135
  def initialize(*files)
128
136
  @options = files.last.is_a?(Hash) ? files.pop.dup : {}
129
137
  @options[:query] ||= MANIFEST_QUERY
130
- raise "Test Manifest must be specified with :manifest option" unless @options[:manifest] || @options[:json]
138
+ raise "Test Manifests must be specified with :manifest option" unless @options[:manifest] || @options[:json]
131
139
  raise "Require at least one input file" if files.empty?
132
140
  @files = files
133
141
  @prefixes = {}
@@ -136,12 +144,16 @@ class EarlReport
136
144
  return
137
145
  end
138
146
 
139
- # Load manifest, possibly with base URI
140
- status "read #{@options[:manifest]}"
147
+ # Load manifests, possibly with base URI
148
+ status "read #{@options[:manifest].inspect}"
141
149
  man_opts = {}
142
150
  man_opts[:base_uri] = RDF::URI(@options[:base]) if @options[:base]
143
- @graph = RDF::Graph.load(@options[:manifest], man_opts)
144
- status " loaded #{@graph.count} triples"
151
+ @graph = RDF::Graph.new
152
+ [@options[:manifest]].flatten.compact.each do |man|
153
+ g = RDF::Graph.load(man, man_opts)
154
+ status " loaded #{g.count} triples from #{man}"
155
+ @graph << g
156
+ end
145
157
 
146
158
  # Read test assertion files
147
159
  files.flatten.each do |file|
@@ -244,8 +256,8 @@ class EarlReport
244
256
  {
245
257
  "@context" => TEST_CONTEXT,
246
258
  "@id" => "",
247
- "@type" => "earl:Report",
248
- 'title' => @options[:name],
259
+ "@type" => %w(earl:Software doap:Project),
260
+ 'name' => @options[:name],
249
261
  'bibRef' => @options[:bibRef],
250
262
  'generatedBy' => {
251
263
  "@id" => "http://rubygems.org/gems/earl-report",
@@ -270,9 +282,9 @@ class EarlReport
270
282
  "foaf:homepage" => "http://greggkellogg.net/"
271
283
  }
272
284
  },
273
- "assertions" => @files,
274
- 'testSubjects' => json_test_subject_info,
275
- 'tests' => json_result_info
285
+ "assertions" => @files,
286
+ 'testSubjects' => json_test_subject_info,
287
+ 'entries' => json_result_info
276
288
  }
277
289
  end
278
290
  end
@@ -298,7 +310,7 @@ class EarlReport
298
310
  dev['foaf:homepage'] = solution[:devHomepage].to_s if solution[:devHomepage]
299
311
  (info['developer'] ||= []) << dev
300
312
  end
301
- info['developer'] = info['developer'].uniq
313
+ info['developer'] = info['developer'].uniq if info['developer']
302
314
  end
303
315
 
304
316
  # Map ids and values to array entries
@@ -319,8 +331,9 @@ class EarlReport
319
331
  # Return result information for each test.
320
332
  # This counts on hash maintaining insertion order
321
333
  #
322
- # @return [Array]
334
+ # @return [Array<Hash>] List of manifests
323
335
  def json_result_info
336
+ manifests = []
324
337
  test_cases = {}
325
338
  subjects = json_test_subject_info.map {|s| s['@id']}
326
339
 
@@ -330,44 +343,67 @@ class EarlReport
330
343
  .inject({}) {|memo, soln| memo[soln[:uri]] = soln; memo}
331
344
 
332
345
  # If test cases are in a list, maintain order
333
- solution_list = if first_soln = solutions.values.detect {|s| s[:lh]}
334
- RDF::List.new(first_soln[:lh], @graph)
335
- else
336
- solutions.keys # Any order will do
337
- end
346
+ solutions.values.select {|s| s[:manUri]}.each do |man_soln|
347
+ # Get tests for this manifest in list order
348
+ solution_list = RDF::List.new(man_soln[:lh], @graph)
349
+
350
+ # Set up basic manifest information
351
+ man_info = manifests.detect {|m| m['@id'] == man_soln[:manUri].to_s}
352
+ unless man_info
353
+ status "manifest: #{man_soln[:manUri]}"
354
+ man_info = {
355
+ '@id' => man_soln[:manUri].to_s,
356
+ "@type" => %w{earl:Report mf:Manifest},
357
+ 'title' => man_soln[:manComment].to_s,
358
+ 'entries' => []
359
+ }
360
+ manifests << man_info
361
+ end
338
362
 
339
- # Collect each TestCase
340
- solution_list.each do |uri|
341
- solution = solutions[uri]
342
- tc_hash = {
343
- '@id' => uri.to_s,
344
- '@type' => %w(earl:TestCriterion earl:TestCase),
345
- 'title' => solution[:title].to_s,
346
- 'testAction' => solution[:testAction].to_s,
347
- 'assertions' => []
348
- }
349
- tc_hash['description'] = solution[:description].to_s if solution[:description]
350
- tc_hash['testResult'] = solution[:testResult].to_s if solution[:testResult]
351
-
352
- # Pre-initialize results for each subject to untested
353
- subjects.each do |siri|
354
- tc_hash['assertions'] << {
355
- '@type' => 'earl:Assertion',
356
- 'test' => uri.to_s,
357
- 'subject' => siri,
358
- 'result' => {
359
- '@type' => 'earl:TestResult',
360
- 'outcome' => 'earl:untested'
363
+ # Collect each TestCase
364
+ solution_list.each do |uri|
365
+ solution = solutions[uri]
366
+
367
+ # Create entry for this test case, if it doesn't already exist
368
+ tc = man_info['entries'].detect {|t| t['@id'] == uri}
369
+ unless tc
370
+ tc = {
371
+ '@id' => uri.to_s,
372
+ '@type' => %w(earl:TestCriterion earl:TestCase),
373
+ 'title' => solution[:title].to_s,
374
+ 'testAction' => solution[:testAction].to_s,
375
+ 'assertions' => []
361
376
  }
362
- }
377
+ tc['@type'] << solution[:type].to_s if solution[:type]
378
+ tc['description'] = solution[:description].to_s if solution[:description]
379
+ tc['testResult'] = solution[:testResult].to_s if solution[:testResult]
380
+
381
+ # Pre-initialize results for each subject to untested
382
+ subjects.each do |siri|
383
+ tc['assertions'] << {
384
+ '@type' => 'earl:Assertion',
385
+ 'test' => uri.to_s,
386
+ 'subject' => siri,
387
+ 'mode' => 'earl:automatic',
388
+ 'result' => {
389
+ '@type' => 'earl:TestResult',
390
+ 'outcome' => 'earl:untested'
391
+ }
392
+ }
393
+ end
394
+
395
+ test_cases[uri.to_s] = tc
396
+ man_info['entries'] << tc
397
+ end
363
398
  end
364
399
 
365
- test_cases[uri.to_s] = tc_hash
400
+ raise "No test cases found" if man_info['entries'].empty?
401
+ status "Test cases:\n #{man_info['entries'].map {|tc| tc['@id']}.join("\n ")}"
366
402
  end
367
403
 
368
- raise "No test cases found" if test_cases.empty?
404
+ raise "No manifests found" if manifests.empty?
405
+ status "Manifests:\n #{manifests.map {|m| m['@id']}.join("\n ")}"
369
406
 
370
- status "Test cases:\n #{test_cases.keys.join("\n ")}"
371
407
  # Iterate through assertions and add to appropriate test case
372
408
  SPARQL.execute(ASSERTION_QUERY, @graph).each do |solution|
373
409
  tc = test_cases[solution[:test].to_s]
@@ -380,7 +416,7 @@ class EarlReport
380
416
  ta_hash['result']['outcome'] = "earl:#{solution[:outcome].to_s.split('#').last}"
381
417
  end
382
418
 
383
- test_cases.values
419
+ manifests.sort_by {|m| m['title']}
384
420
  end
385
421
 
386
422
  ##
@@ -407,18 +443,17 @@ class EarlReport
407
443
  io.puts
408
444
 
409
445
  # Write earl:Software for the report
446
+ man_defs = json_hash['entries'].map {|defn| as_resource(defn['@id'])}.join("\n ")
410
447
  io.puts %{
411
448
  #{as_resource(json_hash['@id'])} a #{[json_hash['@type']].flatten.join(', ')};
412
- dc:title "#{json_hash['title']}";
449
+ doap:name "#{json_hash['name']}";
413
450
  dc:bibliographicCitation "#{json_hash['bibRef']}";
414
451
  earl:generatedBy #{as_resource json_hash['generatedBy']['@id']};
415
452
  earl:assertions
416
453
  #{json_hash['assertions'].map {|a| as_resource(a)}.join(",\n ")};
417
454
  earl:testSubjects (
418
455
  #{json_hash['testSubjects'].map {|a| as_resource(a['@id'])}.join("\n ")});
419
- earl:tests (
420
- #{json_hash['tests'].map {|a| as_resource(a['@id'])}.join("\n ")}) .
421
-
456
+ mf:entries (\n #{man_defs}) .
422
457
  }.gsub(/^ /, '')
423
458
 
424
459
  # Write generating software information
@@ -435,16 +470,34 @@ class EarlReport
435
470
 
436
471
  }.gsub(/^ /, '')
437
472
 
473
+ # Output Manifest definitions
474
+ # along with test cases and assertions
475
+ test_cases = []
476
+ io.puts %(\n# Manifests)
477
+ json_hash['entries'].each do |man|
478
+ io.puts %(#{as_resource(man['@id'])} a earl:Report, mf:Manifest;)
479
+ io.puts %( dc:title "#{man['title']}";)
480
+ io.puts %( mf:name "#{man['title']}";)
481
+
482
+ # Test Cases
483
+ test_defs = man['entries'].map {|defn| as_resource(defn['@id'])}.join("\n ")
484
+ io.puts %( mf:entries (\n #{test_defs}) .\n\n)
485
+
486
+ test_cases += man['entries']
487
+ end
488
+
438
489
  # Write out each earl:TestSubject
439
490
  io.puts %(#\n# Subject Definitions\n#)
440
491
  json_hash['testSubjects'].each do |ts_desc|
441
492
  io.write(test_subject_turtle(ts_desc))
442
493
  end
443
-
494
+
444
495
  # Write out each earl:TestCase
445
496
  io.puts %(#\n# Test Case Definitions\n#)
446
- json_hash['tests'].each do |test_case|
447
- io.write(tc_turtle(test_case))
497
+ json_hash['entries'].each do |manifest|
498
+ manifest['entries'].each do |test_case|
499
+ io.write(tc_turtle(test_case))
500
+ end
448
501
  end
449
502
  end
450
503
 
@@ -5,7 +5,7 @@
5
5
  -# "@context": {...},
6
6
  -# "@id": "",
7
7
  -# "@type": "earl:Software",
8
- -# "title": "...",
8
+ -# "name": "...",
9
9
  -# "bibRef": "[[...]]",
10
10
  -# "assertions": ["./rdf.rb-earl.ttl"],
11
11
  -# "testSubjects": [
@@ -38,15 +38,15 @@
38
38
  -# ]
39
39
  -# }]
40
40
  -# }
41
+ - require 'cgi'
41
42
 
42
43
  !!! 5
43
44
  %html{:prefix => "earl: http://www.w3.org/ns/earl# doap: http://usefulinc.com/ns/doap# mf: http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#"}
44
45
  - subjects = tests['testSubjects']
45
- - test_cases = tests['tests']
46
46
  %head
47
47
  %meta{"http-equiv" => "Content-Type", :content => "text/html;charset=utf-8"}
48
48
  %title
49
- = tests['title']
49
+ = tests['name']
50
50
  %script.remove{:type => "text/javascript", :src => "http://www.w3.org/Tools/respec/respec-w3c-common"}
51
51
  :javascript
52
52
  var respecConfig = {
@@ -148,79 +148,139 @@
148
148
  background-color: white;
149
149
  -moz-border-radius: ;
150
150
  }
151
- %body
152
- %section#abstract{:about => tests['@id'], :typeof => [tests['@type']].flatten.join(' ')}
151
+ tr.summary {font-weight: bold;}
152
+ td.passed-all {color: green;}
153
+ td.passed-most {color: darkorange;}
154
+ td.passed-some {color: red;}
155
+ %body{:prefix => "earl: http://www.w3.org/ns/earl# doap: http://usefulinc.com/ns/doap# mf: http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#"}
156
+ %section#abstract{:about => tests['@id'], :typeof => [tests['@type']].flatten.join(" ")}
153
157
  %p
154
- This document report processor conformance for and related specifications for
155
- %span{:property => "dc:title"}<=tests['title']
158
+ This document report test subject conformance for and related specifications for
159
+ %span{:property => "doap:name"}<=tests['name']
156
160
  %span{:property => "dc:bibliographicCitation"}<
157
161
  = tests['bibRef']
158
162
  according to the requirements of the Evaluation and Report Language (EARL) 1.0 Schema [[EARL10-SCHEMA]].
163
+ %p
164
+ This report is also available in alternate formats:
165
+ %a{:href => "earl.ttl"}
166
+ Turtle
167
+ and
168
+ %a{:href => "earl.jsonld"}
169
+ JSON-LD
159
170
  %section#sodt
160
171
  %section
172
+ - test_info = {}
161
173
  - test_refs = {}
162
174
  - subject_refs = {}
163
175
  %h2
164
- Results
165
- %table.report
166
- %tr
167
- %th
168
- Test
169
- - subjects.each_with_index do |subject, i|
170
- - subject_refs[subject['@id']] = "subj_#{i}"
171
- %th
172
- %a{:href => '#' + subject_refs[subject['@id']]}<=subject['name']
173
- - test_cases.each do |test|
174
- - test_refs[test['@id']] = 'test_' + (test['@id'][0,2] == '_:' ? test['@id'][2..-1] : test['@id'].split('#').last)
175
- %tr{:resource => test['@id']}
176
- %td
177
- %a{:href => '#' + test_refs[test['@id']]}<= test['title']
178
- - test['assertions'].each do |assertion|
179
- - pass_fail = assertion['result']['outcome'].split(':').last.upcase.sub(/ED$/, '')
180
- %td{:class => pass_fail, :property => "earl:assertions", :typeof => assertion['@type'], :inlist => true}
181
- - if assertion['assertedBy']
182
- %link{:property => "earl:assertedBy", :href => assertion['assertedBy']}
183
- %link{:property => "earl:test", :href => assertion['test']}
184
- %link{:property => "earl:subject", :href => assertion['subject']}
185
- - if assertion['mode']
186
- %link{:property => 'earl:mode', :href => assertion['mode']}
187
- %span{:property => "earl:result", :typeof => assertion['result']['@type']}
188
- %span{:property => 'earl:outcome', :resource => assertion['result']['outcome']}
189
- = pass_fail
176
+ Test Manifests
177
+ - tests['entries'].each do |manifest|
178
+ - test_cases = manifest['entries']
179
+ %section{:typeof => manifest['@type'].join(" "), :resource => manifest['@id']}
180
+ %h2<=manifest['title']
181
+ - [manifest['description']].flatten.compact.each do |desc|
182
+ %p<
183
+ ~ CGI.escapeHTML desc
184
+ %table.report
185
+ - skip_subject = {}
186
+ - passed_tests = []
187
+ %tr
188
+ %th
189
+ Test
190
+ - subjects.each_with_index do |subject, index|
191
+ - subject_refs[subject['@id']] = "subj_#{index}"
192
+ -# If subject is untested for every test in this manifest, skip it
193
+ - skip_subject[subject['@id']] = manifest['entries'].all? {|t| t['assertions'][index]['result']['outcome'] == 'earl:untested'}
194
+ - unless skip_subject[subject['@id']]
195
+ %th
196
+ %a{:href => '#' + subject_refs[subject['@id']]}<=subject['name']
197
+ - test_cases.each do |test|
198
+ - tid = 'test_' + (test['@id'][0,2] == '_:' ? test['@id'][2..-1] : test['@id'].split('#').last)
199
+ - (test_info[tid] ||= []) << test
200
+ - test_refs[test['@id']] = tid
201
+ %tr{:rel => "mf:entries", :typeof => test['@type'].join(" "), :resource => test['@id'], :inlist => true}
202
+ %td
203
+ %a{:href => "##{tid}"}<
204
+ ~ CGI.escapeHTML test['title']
205
+ - test['assertions'].each_with_index do |assertion, ndx|
206
+ - next if skip_subject[assertion['subject']]
207
+ - pass_fail = assertion['result']['outcome'].split(':').last.upcase.sub(/(PASS|FAIL)ED$/, '\1')
208
+ - passed_tests[ndx] = (passed_tests[ndx] || 0) + (pass_fail == 'PASS' ? 1 : 0)
209
+ %td{:class => pass_fail, :property => "earl:assertions", :typeof => assertion['@type'], :inlist => true}
210
+ - if assertion['assertedBy']
211
+ %link{:property => "earl:assertedBy", :href => assertion['assertedBy']}
212
+ %link{:property => "earl:test", :href => assertion['test']}
213
+ %link{:property => "earl:subject", :href => assertion['subject']}
214
+ - if assertion['mode']
215
+ %link{:property => 'earl:mode', :href => assertion['mode']}
216
+ %span{:property => "earl:result", :typeof => assertion['result']['@type']}
217
+ %span{:property => 'earl:outcome', :resource => assertion['result']['outcome']}
218
+ = pass_fail
219
+ %tr.summary
220
+ %td
221
+ = "Percentage passed out of #{manifest['entries'].length} Tests"
222
+ - passed_tests.compact.each do |r|
223
+ - pct = (r * 100.0) / manifest['entries'].length
224
+ %td{:class => (pct == 100.0 ? 'passed-all' : (pct >= 95.0 ? 'passed-most' : 'passed-some'))}
225
+ = "#{'%.1f' % pct}%"
190
226
  %section.appendix
191
227
  %h2
192
228
  Test Subjects
193
229
  %p
194
230
  This report was tested using the following test subjects:
195
231
  %dl
196
- - subjects.each do |subject|
197
- %dt{:id => subject_refs[subject['@id']]}<
232
+ - subjects.each_with_index do |subject, index|
233
+ %dt{:id => subject_refs[subject['@id']]}
198
234
  %a{:href => subject['@id']}
199
235
  %span{:about => subject['@id'], :property => "doap:name"}<= subject['name']
200
236
  %dd{:property => "earl:testSubjects", :resource => subject['@id'], :typeof => [subject['@type']].flatten.join(" "), :inlist => true}
201
237
  %dl
202
238
  - if subject['doapDesc']
203
239
  %dt= "Description"
204
- %dd{:property => "doap:description", :lang => 'en'}<= subject['doapDesc']
240
+ %dd{:property => "doap:description", :lang => 'en'}<
241
+ ~ CGI.escapeHTML subject['doapDesc']
205
242
  - if subject['language']
206
243
  %dt= "Programming Language"
207
- %dd{:property => "doap:programming-language"}<= subject['language']
244
+ %dd{:property => "doap:programming-language"}<
245
+ ~ CGI.escapeHTML subject['language']
246
+ - if subject['homepage']
247
+ %dt= "Home Page"
248
+ %dd{:property => "doap:homepage"}
249
+ %a{:href=> subject['homepage']}
250
+ ~ CGI.escapeHTML subject['homepage']
208
251
  - if subject['developer']
209
252
  %dt= "Developer"
210
253
  %dd{:rel => "doap:developer"}
211
254
  - subject['developer'].each do |dev|
212
- %div{:resource => dev['@id'], :typeof => dev['@type']}
255
+ %div{:resource => dev['@id'], :typeof => [dev['@type']].flatten.join(" ")}
213
256
  - if dev.has_key?('@id')
214
257
  %a{:href => dev['@id']}
215
- %span{:property => "foaf:name"}<= dev['foaf:name']
258
+ %span{:property => "foaf:name"}<
259
+ ~ CGI.escapeHTML dev['foaf:name']
216
260
  - else
217
- %span{:property => "foaf:name"}<= dev['foaf:name']
261
+ %span{:property => "foaf:name"}<
262
+ ~ CGI.escapeHTML dev['foaf:name']
218
263
  - if dev['foaf:homepage']
219
264
  %dt
220
265
  Home Page
221
266
  %dd
222
267
  %a{:property => "foaf:homepage", :href=> dev['foaf:homepage']}
223
- = dev['foaf:homepage']
268
+ ~ CGI.escapeHTML dev['foaf:homepage']
269
+ %dt
270
+ Test Suite Compliance
271
+ %dd
272
+ %table.report
273
+ %tbody
274
+ - tests['entries'].each do |manifest|
275
+ - passed = manifest['entries'].select {|t| t['assertions'][index]['result']['outcome'] == 'earl:passed' }.length
276
+ - next if passed == 0
277
+ - total = manifest['entries'].length
278
+ - pct = (passed * 100.0) / total
279
+ %tr
280
+ %td
281
+ ~ manifest['title']
282
+ %td{:class => (pct == 100.0 ? 'passed-all' : (pct >= 85.0 ? 'passed-most' : 'passed-some'))}
283
+ = "#{passed}/#{total} (#{'%.1f' % pct}%)"
224
284
  - unless tests['assertions'].empty?
225
285
  %section.appendix{:rel => "earl:assertions"}
226
286
  %h2
@@ -235,19 +295,21 @@
235
295
  %h2
236
296
  Test Definitions
237
297
  %dl
238
- - tests['tests'].each do |test|
239
- %dt{:id => test_refs[test['@id']], :resource => test['@id']}
240
- Test
241
- %span{:property => "dc:title"}<= test['title']
242
- %dd{:property => "earl:tests", :resource => test['@id'], :typeof => [test['@type']].flatten.join(' '), :inlist => true}
243
- %p{:property => "dc:description", :lang => 'en'}<= test['description']
244
- %dl
245
- %dt
298
+ - tests['entries'].each do |manifest|
299
+ %div{:property => "mf:entries", :inlist => true, :resource => manifest['@id']}
300
+ - manifest['entries'].each do |test|
301
+ %dt{:id => test_refs[test['@id']], :resource => test['@id']}
302
+ Test
303
+ %span{:property => "dc:title mf:name"}<
304
+ ~ CGI.escapeHTML test['title']
305
+ %dd{:resource => test['@id']}
306
+ %p{:property => "dc:description", :lang => 'en'}<
307
+ ~ CGI.escapeHTML test['description']
246
308
  %pre{:class => "example actionDoc", :property => "mf:action", :resource => test['testAction'], :title => "#{test['title']} Input"}<
247
- ~ Kernel.open(test['testAction']) {|f| CGI.escapeHTML(f.read).gsub(/\n/, '<br/>')} rescue "#{test['testAction']} not loaded"
309
+ ~ CGI.escapeHTML Kernel.open(test['testAction']) {|f| CGI.escapeHTML(f.read).gsub(/\n/, '<br/>')} rescue "#{test['testAction']} not loaded"
248
310
  - if test['testResult']
249
311
  %pre{:class => "example resultDoc", :property => "mf:result", :resource => test['testResult'], :title => "#{test['title']} Result"}<
250
- ~ Kernel.open(test['testResult']) {|f| CGI.escapeHTML(f.read).gsub(/\n/, '<br/>')} rescue "#{test['testResult']} not loaded"
312
+ ~ CGI.escapeHTML Kernel.open(test['testResult']) {|f| CGI.escapeHTML(f.read).gsub(/\n/, '<br/>')} rescue "#{test['testResult']} not loaded"
251
313
  %section#appendix{:property => "earl:generatedBy", :resource => tests['generatedBy']['@id'], :typeof => tests['generatedBy']['@type']}
252
314
  %h2
253
315
  Report Generation Software