@@ -0,0 +1,210 @@
1+:: Direct request-value watchability for a synthetic program over the real todo API.
2+/+ jibb, jibb-import
3+/* prelude %jibb /lib/jibb/prelude/jibb
4+/* internal %jibb /lib/jibb/internal/jibb
5+/* sur %txt /tests/type-api-paths/todo-sur/txt
6+/* action %txt /tests/type-api-paths/todo-action/txt
7+/* todos %txt /tests/type-api-paths/todos/txt
8+/* update %txt /tests/type-api-paths/todo-update/txt
9+/* item %txt /tests/type-api-paths/todo-item/txt
10+/* api %txt /tests/type-api-paths/api/txt
11+|%
12+++ text
13+ |= lines=wain
14+ ^- @t
15+ (rap 3 (turn lines |=(line=@t (cat 3 line '\0a'))))
16+::
17+++ program-watch-prepared
18+ |= [public=@t private=@t]
19+ ^- (unit iprelude:jibb)
20+ =/ extra=@t '\0a+$ element |$ [M] [%node item=M]\0a+$ program |$ [D X M]\0a [init=$-(D X) update=$-([M X] [X (list (cmd M))]) view=$-(X (element M)) subs=$-(X (list (sub M)))]\0a++ program |= [init=$-(D X) update=$-([M X] [X (list (cmd M))]) view=$-(X (element M)) subs=$-(X (list (sub M)))]\0a ^- (program D X M) [init update view subs]\0a'
21+ (prepare-prelude-with-internal:jibb (cat 3 public extra) private)
22+::
23+++ program-watch-detailed
24+ |= [at=path src=@t externals=iexternals:jibb marks=imark-externals:jibb modules=jbundle:jibb prepared=iprelude:jibb]
25+ ^- jfile-detailed-result:jibb
26+ (infer-jibb-file-detailed:jibb at src externals marks modules ~[at] values.prepared molds.prepared ~ `iface.prepared)
27+::
28+++ program-watch-source
29+ |= [extra=@t subscriptions=@t]
30+ ^- @t
31+ %+ rap 3
32+ :~ '/= api /ui/api/todo\0a'
33+ '+$ model [count=@ud]\0a'
34+ '+$ msg\0a [%got todos=(list item.api)]\0a [%one item=todo-item.api]\0a %other\0a'
35+ extra
36+ '++ main (program init update view subs)\0a'
37+ '++ init |= input=@t ^- model [count=0]\0a'
38+ '++ update |= [m=msg state=model]\0a ^- [model (list (cmd msg))] [state ~]\0a'
39+ '++ view |= state=model ^- (element msg) [%node %other]\0a'
40+ subscriptions
41+ ==
42+::
43+++ program-watch-agent-source
44+ ^- @t
45+ %+ rap 3
46+ :~ '/= api /ui/api/todo\0a'
47+ '+$ model [count=@ud]\0a'
48+ '++ receive |= input=[mark=@tas state=(unit *) fact=*]\0a ^- [state=* message=@t] [state=0 message="ok"]\0a'
49+ '++ request-path ^- path ~[%todos]\0a'
50+ '++ request ^- (ask @t)\0a [%agent api="/ui/api/todo" case=%todos agent=%todo path=request-path scry=~ receive=receive]\0a'
51+ '++ main (program init update view subs)\0a'
52+ '++ init |= input=@t ^- model [count=0]\0a'
53+ '++ update |= [m=@t state=model]\0a ^- [model (list (cmd @t))] [state ~]\0a'
54+ '++ view |= state=model ^- (element @t) [%node "ok"]\0a'
55+ '++ subs |= state=model\0a ^- (list (sub @t))\0a ~[[%watch request]]\0a'
56+ ==
57+::
58+++ program-watch-errors
59+ |= [public=@t private=@t sur=@t action=@t todos=@t update=@t item=@t api=@t]
60+ ^- (list tape)
61+ =/ prepared=(unit iprelude:jibb) (program-watch-prepared public private)
62+ ?~ prepared ~["synthetic program prelude did not prepare"]
63+ =/ todo=type -:(ride -:!>(..zuse) sur)
64+ =/ subject=type [%cell [%face %todo todo] -:!>(..zuse)]
65+ =/ ma=* (read-mark:jibb-import %todo-action -:(ride subject action))
66+ =/ mt=* (read-mark:jibb-import %todos -:(ride subject todos))
67+ =/ mu=* (read-mark:jibb-import %todo-update -:(ride subject update))
68+ =/ mi=* (read-mark:jibb-import %todo-item -:(ride subject item))
69+ =/ marks=imark-externals:jibb ~[[%todo-action ma] [%todos mt] [%todo-update mu] [%todo-item mi]]
70+ =/ item-input=* (read-named:jibb-import %todo %item todo)
71+ =/ externals=iexternals:jibb ~[[%todo %item item-input]]
72+ =/ api-at=path /ui/api/todo/jibb
73+ =/ api-result=jfile-detailed-result:jibb
74+ (program-watch-detailed api-at api externals marks ~ u.prepared)
75+ ?: ?=(%| -.api-result) ~["real todo API did not check"]
76+ =/ api-iface=ifile:jibb iface.p.api-result
77+ ?~ graph.api-iface ~["real todo API evidence is missing"]
78+ =/ direct-subs=@t '++ subs |= state=model\0a ^- (list (sub msg))\0a ~[[%watch (todos.api |=%got)]]\0a'
79+ =/ island=@t (program-watch-source '' direct-subs)
80+ =/ at=path /tests/program-watch/island/jibb
81+ =/ modules=jbundle:jibb ~[[api-at api]]
82+ =/ detailed=jfile-detailed-result:jibb
83+ (program-watch-detailed at island externals marks modules u.prepared)
84+ ?: ?=(%| -.detailed) ~[(weld "direct request watch was rejected: " (trip message.p.detailed))]
85+ =/ checked=ifile:jibb iface.p.detailed
86+ ?~ graph.checked ~["program request graph evidence is missing"]
87+ =/ legacy=jfile-result:jibb
88+ (infer-jibb-file:jibb at island externals marks modules ~[at] values.u.prepared molds.u.prepared ~ `iface.u.prepared)
89+ ?: ?=(%| -.legacy) ~["legacy adapter rejected a direct request watch"]
90+ ?. =(values.checked values.iface.p.legacy) ~["structured and legacy interface values differ"]
91+ =/ subs=(unit ischeme:jibb) (ienv-lookup:jibb %subs values.checked)
92+ =/ main=(unit ischeme:jibb) (ienv-lookup:jibb %main values.checked)
93+ ?~ subs ~["subs interface is missing"]
94+ ?~ main ~["main interface is missing"]
95+ ?. &(?=(~ vars.u.subs) ?=(~ (itype-vars:jibb typ.u.subs))) ~["subs interface is not closed"]
96+ =/ subs-fields=(list itype:jibb) (record-fields-named:jibb %subs typ.u.main ~)
97+ ?. ?=([* ~] subs-fields) ~["closed program does not have one subs field"]
98+ =/ model=(unit ischeme:jibb) (find-jibb-mold:jibb %model checked)
99+ =/ msg=(unit ischeme:jibb) (find-jibb-mold:jibb %msg checked)
100+ =/ list-template=(unit ischeme:jibb) (find-jibb-mold:jibb %list iface.u.prepared)
101+ =/ sub=(unit ischeme:jibb) (find-jibb-mold:jibb %sub iface.u.prepared)
102+ ?~ model ~["model mold is missing"]
103+ ?~ msg ~["message mold is missing"]
104+ ?~ list-template ~["list mold is missing"]
105+ ?~ sub ~["sub mold is missing"]
106+ =/ message-sub=(unit itype:jibb) (template-apply:jibb u.sub ~[typ.u.msg])
107+ ?~ message-sub ~["message subscription type did not instantiate"]
108+ =/ subs-result=(unit itype:jibb) (template-apply:jibb u.list-template ~[u.message-sub])
109+ ?~ subs-result ~["subscription list type did not instantiate"]
110+ =/ expected-subs=itype:jibb [%fn typ.u.model u.subs-result]
111+ ?. =(typ.u.subs expected-subs) ~["subs interface has the wrong exact type"]
112+ ?. =((lent requests.u.graph.checked) (lent requests.u.graph.api-iface)) ~["merged API evidence count differs"]
113+ ?. (levy requests.u.graph.checked |=(r=irequest-evidence:jibb (lien requests.u.graph.api-iface |=(a=irequest-evidence:jibb =(r a))))) ~["merged API evidence differs"]
114+ =/ matching=(list irequest-evidence:jibb)
115+ (skim requests.u.graph.checked |=(r=irequest-evidence:jibb &(=(api-at.r api-at) =(%todos name.r))))
116+ ?. ?=([* ~] matching) ~["direct todos evidence is not unique"]
117+ =/ evidence=irequest-evidence:jibb i.matching
118+ ?. =(api-source.evidence api) ~["request evidence does not retain the exact API source"]
119+ ?. &(?=(~ scry.path.path.evidence) ?=(~ diffs.path.evidence) ?=(~ diffs.path.path.evidence))
120+ ~["plain todos evidence acquired scry or diffs"]
121+ ?: (lien segments.path.path.evidence |=(p=pseg:jibb !?=(%knot -.p))) ~["plain todos evidence acquired parameters"]
122+ =/ consumer-at=path /tests/program-watch/consumer/jibb
123+ =/ consumer=@t '/= island /tests/program-watch/island\0a++ imported subs.island\0a'
124+ =/ imported=jfile-detailed-result:jibb
125+ (program-watch-detailed consumer-at consumer externals marks [[at island] modules] u.prepared)
126+ ?: ?=(%| -.imported) ~["downstream program import was rejected"]
127+ =/ imported-subs=(unit ischeme:jibb) (ienv-lookup:jibb %imported values.iface.p.imported)
128+ ?~ imported-subs ~["downstream imported subs is missing"]
129+ =/ expected-import=itype:jibb (itype-in-import:jibb typ.u.subs checked %island `iface.u.prepared)
130+ ?. &(?=(~ vars.u.imported-subs) =(typ.u.imported-subs expected-import)) ~["downstream imported subs type differs"]
131+ =/ parsed (parse:jibb at island)
132+ ?: ?=(%| -.parsed) ~["program source no longer parses"]
133+ =/ main-def=(unit def:jibb) (program-main-def:jibb defs.p.parsed)
134+ ?~ main-def ~["program main definition is missing"]
135+ =/ parts (program-main-parts:jibb u.main-def)
136+ ?~ parts ~["program main parts are missing"]
137+ =/ resolved=ijimports:jibb ~[[%api api-iface]]
138+ =/ others=(list irequest-evidence:jibb)
139+ (skim requests.u.graph.checked |=(r=irequest-evidence:jibb !&(=(api-at.r api-at) =(%todos name.r))))
140+ =/ missing=irequest-graph:jibb u.graph.checked(requests others)
141+ =/ mismatch=irequest-graph:jibb u.graph.checked(requests [evidence(api-source 'mismatched') others])
142+ =/ scry=irequest-graph:jibb u.graph.checked(requests [evidence(scry.path.path `~[[%knot ~.peek]]) others])
143+ =/ ambiguous=irequest-graph:jibb u.graph.checked(requests [evidence requests.u.graph.checked])
144+ =/ evidence-cases=(list [label=tape graph=irequest-graph:jibb])
145+ :~ ["missing evidence" missing]
146+ ["API-source mismatch" mismatch]
147+ ["scry declaration evidence" scry]
148+ ["ambiguous evidence" ambiguous]
149+ ==
150+ =/ evidence-failures=(list tape)
151+ %+ murn evidence-cases
152+ |= c=[label=tape graph=irequest-graph:jibb]
153+ ?: (program-main-closed:jibb u.parts defs.p.parsed values.checked `iface.u.prepared resolved graph.c)
154+ `label.c
155+ ~
156+ ?^ evidence-failures ~[(weld "bad evidence passed watchability: " i.evidence-failures)]
157+ =/ ordinary-values=ienv:jibb
158+ (skim values.api-iface |=(entry=[name=term scheme=ischeme:jibb] !=(%todos name.entry)))
159+ =/ forged=ifile:jibb
160+ api-iface(values [[%todos [[%fn [%atom %t] [%atom %t]] ~]] ordinary-values])
161+ ?: (program-main-closed:jibb u.parts defs.p.parsed values.checked `iface.u.prepared ~[[%api forged]] u.graph.checked)
162+ ~["same-named non-derived member passed watchability"]
163+ =/ detached=ifile:jibb api-iface(graph `u.graph.api-iface(requests ~))
164+ ?: (program-main-closed:jibb u.parts defs.p.parsed values.checked `iface.u.prepared ~[[%api detached]] u.graph.checked)
165+ ~["evidence outside the selected interface passed watchability"]
166+ =/ incoherent=irequest-evidence:jibb evidence(name.path.path %other)
167+ =/ api-others=(list irequest-evidence:jibb)
168+ (skim requests.u.graph.api-iface |=(r=irequest-evidence:jibb !&(=(api-at.r api-at) =(%todos name.r))))
169+ =/ incoherent-api=ifile:jibb api-iface(graph `u.graph.api-iface(requests [incoherent api-others]))
170+ =/ incoherent-graph=irequest-graph:jibb u.graph.checked(requests [incoherent others])
171+ ?: (program-main-closed:jibb u.parts defs.p.parsed values.checked `iface.u.prepared ~[[%api incoherent-api]] incoherent-graph)
172+ ~["inconsistent request case names passed watchability"]
173+ =/ kind-error=@t (crip "module kind needs unsupported inference: {(spud at)}")
174+ =/ negatives=(list [label=tape src=@t])
175+ :~ :- "pure watch"
176+ (program-watch-source '' '++ subs |= state=model\0a ^- (list (sub msg))\0a ~[[%watch (pure %other)]]\0a')
177+ :- "correctly typed hand-built agent"
178+ program-watch-agent-source
179+ :- "request helper"
180+ (program-watch-source '++ request ^- (ask msg) (todos.api |=%got)\0a' '++ subs |= state=model\0a ^- (list (sub msg))\0a ~[[%watch request]]\0a')
181+ :- "request alias"
182+ (program-watch-source '++ request todos.api\0a' '++ subs |= state=model\0a ^- (list (sub msg))\0a ~[[%watch (request |=%got)]]\0a')
183+ :- "parameterized todo-by-id"
184+ (program-watch-source '' '++ subs |= state=model\0a ^- (list (sub msg))\0a ~[[%watch (todo-by-id.api 1 |=%one)]]\0a')
185+ :- "diff changes"
186+ (program-watch-source '++ fold |= [d=[%todo-update todo-update.api] s=todos.api] s\0a' '++ subs |= state=model\0a ^- (list (sub msg))\0a ~[[%watch (changes.api |=%got fold)]]\0a')
187+ :- "multi-item subscriptions"
188+ (program-watch-source '++ first ^- (sub msg) [%watch (todos.api |=%got)]\0a++ second ^- (sub msg) [%watch (pure %other)]\0a' '++ subs |= state=model\0a ^- (list (sub msg))\0a ~[first second]\0a')
189+ ==
190+ %+ weld (turn evidence-failures |=(reason=tape reason))
191+ %+ murn negatives
192+ |= c=[label=tape src=@t]
193+ =/ bad=jfile-detailed-result:jibb
194+ (program-watch-detailed at src.c externals marks modules u.prepared)
195+ ?: ?=(%& -.bad) `[(weld label.c ": accepted")]
196+ ?. =(message.p.bad kind-error) `[(weld label.c ": did not reach watchability")]
197+ ~
198+::
199+++ test-program-watch
200+ ^- tang
201+ ?~ sur ~[leaf+"program-watch fixture sur is missing"]
202+ ?~ action ~[leaf+"program-watch fixture action is missing"]
203+ ?~ todos ~[leaf+"program-watch fixture todos is missing"]
204+ ?~ update ~[leaf+"program-watch fixture update is missing"]
205+ ?~ item ~[leaf+"program-watch fixture item is missing"]
206+ ?~ api ~[leaf+"program-watch fixture api is missing"]
207+ =/ failures=(list tape)
208+ (program-watch-errors prelude internal (text sur) (text action) (text todos) (text update) (text item) (text api))
209+ (turn failures |=(reason=tape leaf+reason))
210+--