earl-report 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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