-# This template is used for generating a rollup EARL report. It expects to be -# called with a single tests local with the following structure -# -# { -# “@context”: {…}, -# “@id”: “”, -# “@type”: “earl:Software”, -# “name”: “…”, -# “bibRef”: “[[…]]”, -# “assertions”: [“./rdf.rb-earl.ttl”], -# “testSubjects”: [ -# { -# “@id”: “rubygems.org/gems/rdf-turtle”, -# “@type”: “earl:TestSubject”, -# “name”: “RDF::Turtle” -# }, -# … -# ], -# “tests”: [{ -# “@id”: “dvcs.w3.org/hg/rdf/raw-file/default/rdf-turtle/tests-ttl/manifest.ttl#turtle-syntax-file-01”, -# “@type”: [“earl:TestCriterion”, “earl:TestCase”], -# “title”: “subm-test-00”, -# “description”: “Blank subject”, -# “testAction”: “dvcs.w3.org/hg/rdf/raw-file/default/rdf-turtle/tests-ttl/turtle-syntax-file-01.ttl”, -# “testResult”: “dvcs.w3.org/hg/rdf/raw-file/default/rdf-turtle/tests-ttl/turtle-syntax-file-01.out” -# “mode”: “earl:automatic”, -# “assertions”: [ -# { -# “@type”: “earl:Assertion”, -# “assertedBy”: “greggkellogg.net/foaf#me”, -# “test”: “svn.apache.org/repos/asf/jena/Experimental/riot-reader/testing/RIOT/Lang/TurtleSubm/manifest.ttl#testeval00”, -# “subject”: “rubygems.org/gems/rdf-turtle”, -# “result”: { -# “@type”: “earl:TestResult”, -# “outcome”: “earl:passed” -# } -# } -# ] -# }] -# }

!!! 5 %html

- subjects = tests['testSubjects'].sort_by {|s| s['name'].to_s.downcase}
%head
  %meta{"http-equiv" => "Content-Type", content: "text/html;charset=utf-8"}
  %link{rel: "alternate", href: "earl.ttl"}
  %link{rel: "alternate", href: "earl.jsonld"}
  %link{rel: "stylesheet", href: "https://www.w3.org/StyleSheets/TR/base"}
  - tests['assertions'].each do |file|
    %link{rel: "related", href: file}
  %title
    = tests['name']
    Implementation Report
  :css
    span[property='dc:description rdfs:comment'] { display: none; }
    td.PASS { color: green; }
    td.FAIL { color: red; }
    table.report {
      border-width: 1px;
      border-spacing: 2px;
      border-style: outset;
      border-color: gray;
      border-collapse: separate;
      background-color: white;
    }
    table.report th {
      border-width: 1px;
      padding: 1px;
      border-style: inset;
      border-color: gray;
      background-color: white;
      -moz-border-radius: ;
    }
    table.report td {
      border-width: 1px;
      padding: 1px;
      border-style: inset;
      border-color: gray;
      background-color: white;
      -moz-border-radius: ;
    }
    tr.summary {font-weight: bold;}
    td.passed-all {color: green;}
    td.passed-most {color: darkorange;}
    td.passed-some {color: red;}
    em.rfc2119 { 
      text-transform: lowercase;
      font-variant:   small-caps;
      font-style:     normal;
      color:          #900;
    }
    a.testlink {
      color: inherit;
      text-decoration: none;
    }
    a.testlink:hover {
      text-decoration: underline;
    }
    pre > code {
      color: #C83500;
    }
%body{prefix: "bibo: http://purl.org/ontology/bibo/ earl: http://www.w3.org/ns/earl# doap: http://usefulinc.com/ns/doap# mf: http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", vocab: "http://www.w3.org/ns/earl#"}
  - test_info = {}
  - test_refs = {}
  - subject_refs = {}
  - passed_tests = []
  - tests['entries'].each {|m| m['title'] ||= m['rdfs:label'] || m['description'] || m['rdfs:comment']}
  - subjects.each_with_index do |subject, index|
    - subject_refs[subject['@id']] = "subj_#{index}"
  %div.head{role: :contentinfo}
    %p
      %a{href: "http://www.w3.org/"}
        %img{width: 72, height: 48, src: "https://www.w3.org/Icons/w3c_home", alt: "W3C"}
    %h1.title.p-name#title{property: "dc:title"}=tests['name']
    %h2#w3c-document-28-october-2015
      %abbr{title: "World Wide Web Consortium"}="W3C"
      Document
      %time.dt-published{property: "dc:issued", datetime: Time.now.strftime('%Y-%m-%d')}
        = Time.now.strftime("%d %B %Y")
    %dl
      %dt="Editor:"
      - editors.each do |ed|
        %dd.p-author.h-card.vcard{property: "bibo:editor", inlist: true}<>
          %span{property: "rdf:first", typeof: "foaf:Person"}<>
            %meta{property: "foaf:name", content: ed[:name]}<>
            %a.url.fn.u-url.p-name{property: "foaf:homepage", href: ed[:url]}<>
              = ed[:name]
    %p
      This document is also available in these non-normative formats:
      %a{re: "alternate", href: "earl.ttl"}
      and
      %a{re: "alternate", href: "earl.jsonld"}
      = "."
    %p.copyright
      %a{href: "http://www.w3.org/Consortium/Legal/ipr-notice#Copyright"}
        Copyright
      © 2010-2015
      %a{href: "http://www.w3.org/"}
        %sup="®"
      (
      %a{href: "http://www.csail.mit.edu/"}<>
        %abbr{title: "Massachusetts Institute of Technology"}<>="MIT"
      = ", "
      %a{href: "http://www.ercim.eu/"}<>
        %abbr{title: "European Research Consortium for Informatics and Mathematics"}<>="ERCIM"
      = ", "
      %a{href: "http://www.keio.ac.jp/"}<>="Keio"
      = ", "
      %a{href: "http://ev.buaa.edu.cn/"}<>="Beihang"
      ).
      %abbr{title: "World Wide Web Consortium"}="W3C"
      %a{href: "http://www.w3.org/Consortium/Legal/ipr-notice#Legal_Disclaimer"}="liability"
      = ","
      %a{href: "http://www.w3.org/Consortium/Legal/ipr-notice#W3C_Trademarks"}="trademark"
      and
      %a{rel: "license", href: "http://www.w3.org/Consortium/Legal/copyright-documents"}="document use"
      rules apply.
    %hr
  %section#abstract{about: tests['@id'], typeof: Array(tests['@type']).join(" ")}
    %h2="Abstract"
    %p
      This document report test subject conformance for and related specifications for
      %span{property: "doap:name"}<=tests['name']
      %span{property: "dc:bibliographicCitation"}<
        = tests['bibRef']
      according to the requirements of the Evaluation and Report Language (EARL) 1.0 Schema [[EARL10-SCHEMA]].
    %p
      This report is also available in alternate formats:
      %a{rel: "xhv:alternate", href: "earl.ttl"}
        Turtle
      and
      %a{rel: "xhv:alternate", href: "earl.jsonld"}
        JSON-LD
  %section#sodt
    %h2#h-sotd{resource: "#h-sotd"}
      %span{property: "xhv:role", resource: "xhv:heading"}
        Status of This Document
    %p
      This document is merely a
      %abbr{title: "World Wide Web Consortium"}<>="W3C"
      ="-internal  document."
      It has no official standing of any kind and does not represent consensus of the
      %abbr{title: "World Wide Web Consortium"}="W3C"
      Membership.
    %p
      This report describes the state of implementation conformance at the time of publication.
  %section#toc
    %h2.introductory#h-toc{resource: "#h-toc"}
      %span{property: "xhv:role", resource: "xhv:heading"}
        Table of Contents
    %ul.toc#respecContents{role: "directory"}
      %li.tocline
        %a.tocxref{href: "#instructions-for-submitting-implementation-reports"}
          %span.secno="1."
          Instructions for submitting implementation reports
      %li.tocline
        %a.tocxref{href: "#test-manifests"}
          %span.secno="2."
          Test Manifests
        %ul.toc
          - tests['entries'].sort_by {|m| m['title'].to_s.downcase}.each_with_index do |manifest, ndx|
            %li.tocline
              %span.secno="2.#{ndx+1}"
              %a.tocxref{href: "##{manifest['rdfs:comment'].gsub(' ', '-')}"}
                ~ manifest['rdfs:comment']
      %li.tocline
        %a.tocxref{href: "#test-subjects"}
          %span.secno="A."
          Test Subjects
        %ul.toc
          - subjects.each_with_index do |subject, ndx|
            %li.tocline
              %span.secno="A.#{ndx+1}"
              %a.tocxref{href: "#" + subject_refs[subject['@id']]}= subject['name']
      %li.tocline
        %a.tocxref{href: "#individual-test-results"}
          %span.secno="B."
          Individual Test Results
      %li.tocline
        %a.tocxref{href: "#test-definitions"}
          %span.secno="C."
          Test Definitions
      %li.tocline
        %a.tocxref{href: "#report-generation-software"}
          %span.secno="D."
          Report Generation Software
  %section#instructions-for-submitting-implementation-reports
    :markdown
      ## Instructions for submitting implementation reports

        Tests should be run using the test manifests defined in the 
        [Test Manifests](#test-manifests) Section.

        The assumed base URI for the tests is `<http://example/base/>` if needed.

        Reports should be submitted in Turtle format to [xxx](xxx)
        and include an `earl:Assertion`
        for each test, referencing the test resource from the associated manifest
        and the test subject being reported upon. An example test entry is be the following:

            [ a earl:Assertion;
              earl:assertedBy <#{foaf[:url]}>;
              earl:subject <--your-software-identifier-->;
              earl:test <--uri-of-test-from-manifest>;
              earl:result [
                a earl:TestResult;
                earl:outcome earl:passed;
                dc:date "2016-12-26T10:18:04-08:00"^^xsd:dateTime];
              earl:mode earl:automatic ] .

        The Test Subject should be defined as a `doap:Project`, including the name,
        homepage and developer(s) of the software (see [DOAP](https://github.com/edumbill/doap/wiki)). Optionally, including the
        project description and programming language. An example test subject description is the following:

            <> foaf:primaryTopic <--your-software-identifier--> ;
              dc:issued "2016-12-26T10:18:04-08:00"^^xsd:dateTime ;
              foaf:maker <#{foaf[:url]}> .

            <--your-software-identifier--> a doap:Project, earl:TestSubject, earl:Software ;
              doap:name          "#{foaf[:name]}" ;
              doap:homepage      <--your-software-homepace--> ;
              doap:license       <--license-for-your-software--> ;
              doap:shortdesc     "--your-short-project-description--"@en ;
              doap:description   "--your-project-description--"@en ;
              doap:created       "2016-12-09"^^xsd:date ;
              doap:programming-language "--your-implementation-language--" ;
              doap:implements    <--specification-uri--> ;
              doap:category      <--category-uris-for-specification-framework-and-implementation-language--> ;
              doap:download-page <--your-project-repository--> ;
              doap:mailing-list  <--specification-public-mailing-list--@w3.org> ;
              doap:bug-database  <--your-project-repository--/issues> ;
              doap:blog          <--your-blog--> ;
              doap:developer     <#{foaf[:url]}> ;
              foaf:maker         <#{foaf[:url]}> ;
              dc:title           "--your-project-name--" ;
              dc:description     "--your-project-description--"@en ;
              dc:date            "2016-12-09"^^xsd:date ;
              dc:creator         <#{foaf[:url]}> ;
              dc:isPartOf        <--your-implementation-framework--> .

        The software developer, either an organization or one or more individuals SHOULD be
        referenced from `doap:developer` using [FOAF](http://xmlns.com/foaf/spec). For example:

            <--your-software-identifier--> a foaf:Person, earl:Assertor;
              foaf:name "#{foaf[:name]}";
              foaf:title "Implementor";
              foaf:homepage <#{foaf[:url]}> .
  %section#test-manifests
    %h2
      %span.secno="2."
      Test Manifests
    - tests['entries'].each_with_index do |manifest, ndx2|
      - test_cases = manifest['entries']
      %section{id: manifest['rdfs:comment'].gsub(' ', '-'), typeof: manifest['@type'].join(" "), resource: manifest['@id']}
        %h2
          %span.secno="2.#{ndx2+1}"
          %span{property: "dc:title mf:name"}<
            = manifest['title'] ||  'Test Manifest'
        - Array(manifest['description']).each do |desc|
          - desc = desc['@value'] if desc.is_a?(Hash)
          %p{property: "rdfs:comment", lang: 'en'}<
            ~ CGI.escapeHTML desc.to_s
        %table.report
          - skip_subject = {}
          - passed_tests[ndx2] = []
          %tr
            %th
              Test
            - subjects.each_with_index do |subject, index|
              -# If subject is untested for every test in this manifest, skip it
              - skip_subject[subject['@id']] = manifest['entries'].all? {|t| t['assertions'][index]['result']['outcome'] == 'earl:untested'}
              - unless skip_subject[subject['@id']]
                %th
                  %a{href: '#' + subject_refs[subject['@id']]}<=subject['name']
          - test_cases.each do |test|
            - test['title'] ||= test['rdfs:label']
            - test['title'] = Array(test['title']).first
            - tid = "test_#{Digest::MD5.hexdigest(test['@id'])}"
            - (test_info[tid] ||= []) << test
            - test_refs[test['@id']] = tid
            %tr{rel: "mf:entries", typeof: test['@type'].join(" "), resource: test['@id'], inlist: true}
              %td
                %a{href: "##{tid}"}<
                  ~ CGI.escapeHTML test['title'].to_s
              -# Order assertions by subject name
              - subjects.each_with_index do |subject, ndx|
                - next if skip_subject[subject['@id']]
                - assertion = test['assertions'].detect {|a| a['subject'] == subject['@id']}
                - pass_fail = assertion['result']['outcome'].split(':').last.upcase.sub(/(PASS|FAIL)ED$/, '\1')
                - passed_tests[ndx2][ndx] = (passed_tests[ndx2][ndx] || 0) + (pass_fail == 'PASS' ? 1 : 0)
                %td{class: pass_fail, typeof: assertion['@type']}
                  - if assertion['assertedBy'] && !assertion['assertedBy'].start_with?('_:')
                    %link{property: "earl:assertedBy", href: assertion['assertedBy']}
                  - if assertion['test'] && !assertion['test'].start_with?('_:')
                    %link{property: "earl:test", href: assertion['test']}
                  - if assertion['subject'] && !assertion['subject'].start_with?('_:')
                    %link{property: "earl:subject", href: assertion['subject']}
                  - if assertion['mode']
                    %link{property: 'earl:mode', href: assertion['mode']}
                  %span{property: "earl:result", typeof: assertion['result']['@type']}
                    %span{property: 'earl:outcome', resource: assertion['result']['outcome']}
                      = pass_fail
          %tr.summary
            %td
              = "Percentage passed out of #{manifest['entries'].length} Tests"
            - passed_tests[ndx2].compact.each do |r|
              - pct = (r * 100.0) / manifest['entries'].length
              %td{class: (pct == 100.0 ? 'passed-all' : (pct >= 95.0 ? 'passed-most' : 'passed-some'))}
                = "#{'%.1f' % pct}%"
  %section.appendix#test-subjects
    %h2
      %span.secno="A."
      Test Subjects
    %p
      This report was tested using the following test subjects:
    %dl
      - subjects.each_with_index do |subject, index|
        %dt{id: subject_refs[subject['@id']]}
          %span.secno="A.#{index+1}"
          %a{href: subject['@id']}
            %span{about: subject['@id'], property: "doap:name"}<= subject['name']
        %dd{property: "earl:testSubjects", resource: subject['@id'], typeof: Array(subject['@type']).join(" ")}
          %dl
            - if subject['doapDesc']
              - subject['doapDesc'] = subject['doapDesc']['@value'] if subject['doapDesc'].is_a?(Hash)
              %dt= "Description"
              %dd{property: "doap:description", lang: 'en'}<
                ~ CGI.escapeHTML subject['doapDesc']
            - if subject['release']
              - subject['release'] = subject['release'].first if subject['release'].is_a?(Array)
              - subject['release']['revision'] = subject['release']['revision']['@value'] if subject['release']['revision'].is_a?(Hash)
              %dt= "Release"
              %dd{property: "doap:release"}<
                %span{property: "doap:revision"}<
                  ~ CGI.escapeHTML subject['release']['revision'].to_s
            - if subject['language']
              - subject['language'] = subject['language']['@value'] if subject['language'].is_a?(Hash)
              %dt= "Programming Language"
              %dd{property: "doap:programming-language"}<
                ~ CGI.escapeHTML subject['language'].to_s
            - if subject['homepage']
              %dt= "Home Page"
              %dd
                %a{property: "doap:homepage", href: subject['homepage']}
                  ~ CGI.escapeHTML subject['homepage'].to_s
            - if subject['developer']
              %dt= "Developer"
              - subject['developer'].each do |dev|
                %dd{rel: "doap:developer"}
                  %div{resource: dev['@id'], typeof: Array(dev['@type']).join(" ")}
                    - if dev.has_key?('@id')
                      %a{href: dev['@id']}
                        %span{property: "foaf:name"}<
                          ~ CGI.escapeHTML dev['foaf:name'].to_s
                    - else
                      %span{property: "foaf:name"}<
                    - if dev['foaf:homepage']
                      %a{property: "foaf:homepage", href: dev['foaf:homepage']}
                        ~ CGI.escapeHTML dev['foaf:homepage']
            %dt
              Test Suite Compliance
            %dd
              %table.report
                %tbody
                  - tests['entries'].each_with_index do |manifest, ndx|
                    - passed = passed_tests[ndx][index].to_i
                    - next if passed == 0
                    - total = manifest['entries'].length
                    - pct = (passed * 100.0) / total
                    %tr
                      %td
                        ~ manifest['title']
                      %td{class: (pct == 100.0 ? 'passed-all' : (pct >= 85.0 ? 'passed-most' : 'passed-some'))}
                        = "#{passed}/#{total} (#{'%.1f' % pct}%)"
  - unless tests['assertions'].empty?
    %section.appendix#individual-test-results{rel: "xhv:related mf:report"}
      %h2
        %span.secno="B."
        Individual Test Results
      %p
        Individual test results used to construct this report are available here:
      %ul
        - tests['assertions'].each do |file|
          %li
            %a.source{href: file}<= file
  %section.appendix#test-definitions
    %h2
      %span.secno="C."
      Test Definitions
    %dl
      - tests['entries'].each do |manifest|
        %div{property: "mf:entries", inlist: true, resource: manifest['@id']}
          - manifest['entries'].each do |test|
            - test['description'] = test['description']['@value'] if test['description'].is_a?(Hash)
            %dt{id: test_refs[test['@id']], resource: test['@id']}
              Test
              %span{property: "dc:title mf:name"}<
                ~ CGI.escapeHTML test['title'].to_s
            %dd{resource: test['@id']}
              %p{property: "dc:description rdfs:comment"}<
                ~ CGI.escapeHTML test['description'].to_s
              %pre{class: "example actionDoc", property: "mf:action", resource: test['testAction'], title: "#{test['title']} Input"}<
                ~ URI.open(test['testAction']) {|f| f.set_encoding(Encoding::UTF_8); CGI.escapeHTML(f.read).gsub(/\n/, '<br/>')} rescue "#{test['testAction']} not loaded"
              - if test['testResult']
                %pre{class: "example resultDoc", property: "mf:result", resource: test['testResult'], title: "#{test['title']} Result"}<
                  ~ URI.open(test['testResult']) {|f| f.set_encoding(Encoding::UTF_8); CGI.escapeHTML(f.read).gsub(/\n/, '<br/>')} rescue "#{test['testResult']} not loaded"
  %section.appendix#report-generation-software{property: "earl:generatedBy", resource: tests['generatedBy']['@id'], typeof: tests['generatedBy']['@type'].join(' ')}
    %h2
      %span.secno="D."
      Report Generation Software
    - doap = tests['generatedBy']
    - rel = doap['release']
    %p
      This report generated by
      %span{property: "doap:name"}<
        %a{href: tests['generatedBy']['@id']}<
          = doap['name']
      %meta{property: "doap:shortdesc", content: doap['shortdesc']}
      %meta{property: "doap:description", content: doap['doapDesc']}
      version
      %span{property: "doap:release", resource: rel['@id'], typeof: 'doap:Version'}
        %span{property: "doap:revision"}<=rel['revision']
        %meta{property: "doap:name", content: rel['name']}
        - if rel['created']
          %meta{property: "doap:created", content: rel['created'], datatype: "xsd:date"}
      an
      %a{property: "doap:license", href: doap['license']}<="Unlicensed"
      %span{property: "doap:programming-language"}<="Ruby"
      application. More information is available at
      %a{property: "doap:homepage", href: doap['homepage']}<=doap['homepage']
      = "."
    %p{property: "doap:developer", resource: "https://greggkellogg.net/foaf#me", typeof: "foaf:Person"}
      This software is provided by
      %a{property: "foaf:homepage", href: "https://greggkellogg.net/"}<
        %span{about: "https://greggkellogg.net/foaf#me", property: "foaf:name"}<
          Gregg Kellogg
      in hopes that it might make the lives of conformance testers easier.