<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <link rel="stylesheet" href="../../coverage.css"/> <title> dog_and_duck/quack/picky.clj </title> </head> <body> <span class="covered" title="1 out of 1 forms covered"> 001 (ns dog-and-duck.quack.picky "Fault-finder for ActivityPub documents. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 002 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 003 Generally, each `-faults` function will return: </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 004 1. `nil` if no faults were found; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 005 2. a sequence of fault objects if faults were found. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 006 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 007 Each fault object shall have the properties: </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 008 1. `:@context` whose value shall be the URL of a </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 009 document specifying this vocabulary; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 010 2. `:type` whose value shall be `Fault`; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 011 3. `:severity` whose value shall be one of </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 012 `minor`, `should`, `must` or `critical`; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 013 4. `:fault` whose value shall be a unique token </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 014 representing the particular fault type; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 015 5. `:narrative` whose value shall be a natural </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 016 language description of the fault type. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 017 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 018 Note that the reason for the `:fault` property is </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 019 to be able to have a well known place, linked to </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 020 from the @context URL, which allows narratives </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 021 for each fault type to be served in as many </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 022 natural languages as possible. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 023 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 024 The idea further is that it should ultimately be </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 025 possible to serialise a fault report as a </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 026 document which in its own right conforms to the </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 027 ActivityStreams spec." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 028 (:require [dog-and-duck.utils.process :refer [pid]])) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 029 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 030 (def ^:const severity </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 031 "Severity of faults found, as follows: </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 032 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 033 1. `:minor` things which I consider to be faults, but which </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 034 don't actually breach the spec; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 035 2. `:should` instances where the spec says something SHOULD </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 036 be done, which isn't; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 037 3. `:must` instances where the spec says something MUST </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 038 be done, which isn't; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 039 4. `:critical` instances where I believe the fault means that </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 040 the object cannot be meaningfully processed." </span><br/> <span class="covered" title="5 out of 5 forms covered"> 041 #{:minor :should :must :critical}) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 042 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 043 (def ^:const severity-filters </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 044 "Hack for implementing a severity hierarchy" </span><br/> <span class="covered" title="7 out of 7 forms covered"> 045 {:all #{} </span><br/> <span class="covered" title="2 out of 2 forms covered"> 046 :minor #{:minor} </span><br/> <span class="covered" title="3 out of 3 forms covered"> 047 :should #{:minor :should} </span><br/> <span class="covered" title="4 out of 4 forms covered"> 048 :must #{:minor :should :must} </span><br/> <span class="covered" title="1 out of 1 forms covered"> 049 :critical severity}) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 050 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 051 (defn filter-severity </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 052 "Return a list of reports taken from these `reports` where the severity </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 053 of the report is greater than this `severity`." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 054 [reports severity] </span><br/> <span class="not-covered" title="0 out of 11 forms covered"> 055 (assert </span><br/> <span class="not-covered" title="0 out of 10 forms covered"> 056 (and </span><br/> <span class="not-covered" title="0 out of 3 forms covered"> 057 (coll? reports) </span><br/> <span class="not-covered" title="0 out of 4 forms covered"> 058 (every? map? reports) </span><br/> <span class="not-covered" title="0 out of 2 forms covered"> 059 (every? :severity reports))) </span><br/> <span class="not-covered" title="0 out of 3 forms covered"> 060 (remove </span><br/> <span class="not-covered" title="0 out of 7 forms covered"> 061 #((severity-filters severity) (:severity %)) </span><br/> <span class="not-covered" title="0 out of 1 forms covered"> 062 reports)) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 063 </span><br/> <span class="covered" title="2 out of 2 forms covered"> 064 (def ^:const activitystreams-context-uri </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 065 "The URI of the context of an ActivityStreams object is expected to be this </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 066 literal string." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 067 "https://www.w3.org/ns/activitystreams") </span><br/> <span class="blank" title="0 out of 0 forms covered"> 068 </span><br/> <span class="covered" title="2 out of 2 forms covered"> 069 (def ^:const validation-fault-context-uri </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 070 "The URI of the context of a validation fault report object shall be this </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 071 literal string." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 072 "https://simon-brooke.github.io/dog-and-duck/codox/Validation_Faults.html") </span><br/> <span class="blank" title="0 out of 0 forms covered"> 073 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 074 (defn context? </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 075 "Returns `true` iff `x` quacks like an ActivityStreams context, else false. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 076 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 077 A context is either </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 078 1. the URI (actually an IRI) `activitystreams-context-uri`, or </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 079 2. a collection comprising that URI and a map." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 080 [x] </span><br/> <span class="partial" title="4 out of 6 forms covered"> 081 (cond </span><br/> <span class="covered" title="3 out of 3 forms covered"> 082 (nil? x) false </span><br/> <span class="covered" title="11 out of 11 forms covered"> 083 (string? x) (and (= x activitystreams-context-uri) true) </span><br/> <span class="partial" title="19 out of 20 forms covered"> 084 (coll? x) (and (context? (first (remove map? x))) </span><br/> <span class="covered" title="4 out of 4 forms covered"> 085 (= (count x) 2) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 086 true) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 087 :else false)) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 088 </span><br/> <span class="partial" title="38 out of 40 forms covered"> 089 (defmacro has-context? </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 090 "True if `x` is an ActivityStreams object with a valid context, else `false`." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 091 [x] </span><br/> <span class="covered" title="1 out of 1 forms covered"> 092 `(context? ((keyword "@context") ~x))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 093 </span><br/> <span class="blank" title="0 out of 0 forms covered"> 094 </span><br/> <span class="blank" title="0 out of 0 forms covered"> 095 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 096 (defn make-fault-object </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 097 "Return a fault object with these `severity`, `fault` and `narrative` values. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 098 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 099 An ActivityPub object MUST have a globally unique ID. Whether this is </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 100 meaningful depends on whether we persist fault report objects and serve </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 101 them, which at present I have no plans to do." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 102 [severity fault narrative] </span><br/> <span class="not-covered" title="0 out of 9 forms covered"> 103 (assoc {} </span><br/> <span class="not-covered" title="0 out of 4 forms covered"> 104 (keyword "@context") validation-fault-context-uri </span><br/> <span class="not-covered" title="0 out of 5 forms covered"> 105 :id (str "https://" </span><br/> <span class="not-covered" title="0 out of 2 forms covered"> 106 (.. java.net.InetAddress getLocalHost getHostName) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 107 "/fault/" </span><br/> <span class="not-covered" title="0 out of 1 forms covered"> 108 pid </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 109 ":" </span><br/> <span class="not-covered" title="0 out of 3 forms covered"> 110 (inst-ms (java.util.Date.))) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 111 :type "Fault" </span><br/> <span class="not-covered" title="0 out of 1 forms covered"> 112 :severity severity </span><br/> <span class="not-covered" title="0 out of 1 forms covered"> 113 :fault fault </span><br/> <span class="not-covered" title="0 out of 1 forms covered"> 114 :narrative narrative)) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 115 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 116 (defn object-faults </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 117 [x] </span><br/> <span class="not-covered" title="0 out of 2 forms covered"> 118 (remove </span><br/> <span class="not-covered" title="0 out of 1 forms covered"> 119 empty? </span><br/> <span class="not-covered" title="0 out of 2 forms covered"> 120 (list </span><br/> <span class="not-covered" title="0 out of 3 forms covered"> 121 (when-not </span><br/> <span class="not-covered" title="0 out of 5 forms covered"> 122 (has-context? x) </span><br/> <span class="not-covered" title="0 out of 5 forms covered"> 123 (make-fault-object </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 124 :should </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 125 :no-context </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 126 "Section 3 of the ActivityPub specification states </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 127 `Implementers SHOULD include the ActivityPub context in </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 128 their object definitions`.") </span><br/> <span class="not-covered" title="0 out of 6 forms covered"> 129 (when-not (:type x) </span><br/> <span class="not-covered" title="0 out of 5 forms covered"> 130 (make-fault-object </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 131 :minor </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 132 :no-type </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 133 "The ActivityPub specification states that the `type` field is </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 134 optional, but it is hard to process objects with no known type.")) </span><br/> <span class="not-covered" title="0 out of 7 forms covered"> 135 (when-not (contains? x :id) </span><br/> <span class="not-covered" title="0 out of 5 forms covered"> 136 (make-fault-object </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 137 :minor </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 138 :no-id-transient </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 139 "The ActivityPub specification allows objects without `id` fields </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 140 only if they are intentionally transient; even so it is preferred </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 141 that the object should have an explicit null id." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 142 )) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 143 )))) </span><br/> </body> </html>