Skip to content

Commit 418fec5

Browse files
committed
Merge remote-tracking branch 'origin/fix-casts' into flonum-platform
2 parents daf7102 + 2cabb9a commit 418fec5

File tree

19 files changed

+752
-487
lines changed

19 files changed

+752
-487
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ hooks:
5858
echo "make fmt" >>.git/hooks/pre-commit
5959

6060
fmt:
61-
raco fmt -i $(shell find . -name '*.rkt')
61+
@raco fmt -i $(shell find egg-herbie/ src/ infra/ -name '*.rkt')
6262

6363
# This rule is run by herbie.uwplse.org on every commit to Github.
6464
# It does not restart the demo server, but it does pull new static content
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
; This example is taken from the Image Processing domain and referred to
2+
; as "Logarithmic Transform". This in its basic form is used to bring out
3+
; details in dark parts of an image. This instantiation of the idea is for 1D
4+
; as opposed to 2D images.
5+
6+
(FPCore (c x y)
7+
:name "Logarithmic Transform"
8+
:alt
9+
(* c (log1p (* (expm1 x) y)))
10+
11+
(* c (log (+ 1.0 (* (- (pow E x) 1.0) y)))))

infra/testApi.mjs

Lines changed: 136 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ import { strict as assert } from 'node:assert'; // use strict equality everywhe
33
// Future TODO: before this API becomes set in stone/offered publicly, we should change the results of these methods to be just the output data rather than duplicating input values.
44

55
// Reusable testing data
6+
const SAMPLE_SIZE = 8000
67
const FPCoreFormula = '(FPCore (x) (- (sqrt (+ x 1)) (sqrt x)))'
78
const FPCoreFormula2 = '(FPCore (x) (- (sqrt (+ x 1))))'
89
const eval_sample = [[[1], -1.4142135623730951]]
910

1011
// improve endpoint
11-
const improveResponse = await callHerbie(`/improve?formula=${encodeURIComponent(FPCoreFormula2)}`, { method: 'GET' })
12+
const improveResponse = await fetch(makeEndpoint(`/improve?formula=${encodeURIComponent(FPCoreFormula2)}`), { method: 'GET' })
1213
assert.equal(improveResponse.status, 200)
1314
let redirect = improveResponse.url.split("/")
1415
const jobID = redirect[3].split(".")[0]
@@ -18,18 +19,18 @@ const jobID = redirect[3].split(".")[0]
1819
// assert.equal(improveHTML.length, improveHTMLexpectedCount, `HTML response character count should be ${improveHTMLexpectedCount} unless HTML changes.`)
1920

2021
// timeline
21-
const timelineRSP = await callHerbie(`/timeline/${jobID}`, { method: 'GET' })
22+
const timelineRSP = await fetch(makeEndpoint(`/timeline/${jobID}`), { method: 'GET' })
2223
assert.equal(timelineRSP.status, 201)
2324
const timeline = await timelineRSP.json()
2425
assert.equal(timeline.length > 0, true)
2526

2627
// Test with a likely missing job-id
27-
const badTimelineRSP = await callHerbie(`/timeline/42069`, { method: 'GET' })
28+
const badTimelineRSP = await fetch(makeEndpoint("/timeline/42069"), { method: 'GET' })
2829
assert.equal(badTimelineRSP.status, 404)
2930

3031
// improve-start endpoint
3132
const URIencodedBody = "formula=" + encodeURIComponent(FPCoreFormula)
32-
const startResponse = await callHerbie(`/improve-start`, {
33+
const startResponse = await fetch(makeEndpoint("/api/start/improve"), {
3334
method: 'POST',
3435
headers: {
3536
'Content-Type': 'application/x-www-form-urlencoded',
@@ -38,122 +39,164 @@ const startResponse = await callHerbie(`/improve-start`, {
3839
})
3940
const testResult = (startResponse.status == 201 || startResponse.status == 202)
4041
assert.equal(testResult, true)
41-
const path = startResponse.headers.get("location")
42+
const improveResultPath = startResponse.headers.get("location")
43+
let counter = 0
44+
let cap = 100
45+
// Check status endpoint
46+
let checkStatus = await fetch(makeEndpoint(improveResultPath), { method: 'GET' })
47+
/*
48+
This is testing if the /api/start/improve test at the beginning has been completed. The cap and counter is a sort of timeout for the test. Ends up being 10 seconds max.
49+
*/
50+
while (checkStatus.status != 201 && counter < cap) {
51+
counter += 1
52+
checkStatus = await fetch(makeEndpoint(improveResultPath), { method: 'GET' })
53+
await new Promise(r => setTimeout(r, 100)); // ms
54+
}
55+
assert.equal(checkStatus.statusText, 'Job complete')
4256

4357
// up endpoint
44-
const up = await callHerbie("/up", { method: 'GET' })
58+
const up = await fetch(makeEndpoint("/up"), { method: 'GET' })
4559
assert.equal('Up', up.statusText)
4660
// TODO how do I test down state?
4761

4862
// Sample endpoint
49-
const sampleRSP = await callHerbie("/api/sample", { method: 'POST', body: JSON.stringify({ formula: FPCoreFormula2, seed: 5 }) })
63+
const sampleBody = {
64+
method: 'POST',
65+
body: JSON.stringify({ formula: FPCoreFormula2, seed: 5 })
66+
}
67+
const sampleRSP = await fetch(makeEndpoint("/api/sample"), sampleBody)
68+
const sampleAsyncResult = await callAsyncAndWaitJSONResult("/api/start/sample", sampleBody)
5069
const jid = sampleRSP.headers.get("x-herbie-job-id")
5170
assert.notEqual(jid, null)
52-
5371
const sample = await sampleRSP.json()
72+
assertIdAndPath(sampleAsyncResult)
73+
assert.ok(sampleAsyncResult.points)
74+
assert.equal(sampleAsyncResult.points.length, SAMPLE_SIZE)
5475
assertIdAndPath(sample)
55-
56-
const SAMPLE_SIZE = 8000
5776
assert.ok(sample.points)
58-
const points = sample.points
59-
assert.equal(points.length, SAMPLE_SIZE, `sample size should be ${SAMPLE_SIZE}`)
77+
assert.equal(sample.points.length, SAMPLE_SIZE, `sample size should be ${SAMPLE_SIZE}`)
6078

61-
const sample2RPS = await callHerbie("/api/sample", { method: 'POST', body: JSON.stringify({ formula: FPCoreFormula2, seed: 5 }) })
79+
// Make second call to test that results are the same
80+
const sample2RPS = await fetch(makeEndpoint("/api/sample"), sampleBody)
6281
const jid2 = sample2RPS.headers.get("x-herbie-job-id")
6382
assert.notEqual(jid2, null)
6483
const sample2 = await sample2RPS.json()
65-
const points2 = sample2.points
6684
assertIdAndPath(sample2)
67-
assert.deepEqual(points[1], points2[1])
85+
assert.deepEqual(sample.points[1], sample2.points[1])
86+
87+
//Explanations endpoint
88+
const explainBody = {
89+
method: 'POST',
90+
body: JSON.stringify({
91+
formula: FPCoreFormula, sample: sample2.points
92+
})
93+
}
94+
const explain = await (await fetch(makeEndpoint("/api/explanations"), explainBody)).json()
95+
assertIdAndPath(explain)
96+
assert.equal(explain.explanation.length > 0, true, 'explanation should not be empty');
97+
const explainAsyncResult = await callAsyncAndWaitJSONResult("/api/start/explanations", explainBody)
98+
assertIdAndPath(explainAsyncResult)
99+
assert.equal(explainAsyncResult.explanation.length > 0, true, 'explanation should not be empty');
68100

69101
// Analyze endpoint
70-
const errors = await callHerbie("/api/analyze", {
102+
const errorsBody = {
71103
method: 'POST', body: JSON.stringify({
72104
formula: FPCoreFormula, sample: [[[
73105
14.97651307489794
74106
], 0.12711304680349078]]
75107
})
76-
})
108+
}
109+
const errors = await (await fetch(makeEndpoint("/api/analyze"), errorsBody)).json()
77110
assertIdAndPath(errors)
78111
assert.deepEqual(errors.points, [[[14.97651307489794], "2.3"]])
112+
const analyzeAsyncResult = await callAsyncAndWaitJSONResult("/api/start/analyze", errorsBody)
113+
assertIdAndPath(analyzeAsyncResult)
114+
assert.deepEqual(analyzeAsyncResult.points, [[[14.97651307489794], "2.3"]])
115+
116+
// Exacts endpoint
117+
const exactsBody = {
118+
method: 'POST', body: JSON.stringify({
119+
formula: FPCoreFormula2, sample: eval_sample
120+
})
121+
}
122+
const exacts = await (await fetch(makeEndpoint("/api/exacts"), exactsBody)).json()
123+
assertIdAndPath(exacts)
124+
assert.deepEqual(exacts.points, [[[1], -1.4142135623730951]])
125+
const exactsAsyncResult = await callAsyncAndWaitJSONResult("/api/start/exacts", exactsBody)
126+
assertIdAndPath(exactsAsyncResult)
127+
assert.deepEqual(exactsAsyncResult.points, [[[1], -1.4142135623730951]])
128+
129+
// Calculate endpoint
130+
const calculateBody = {
131+
method: 'POST', body: JSON.stringify({
132+
formula: FPCoreFormula2, sample: eval_sample
133+
})
134+
}
135+
const calculate = await (await fetch(makeEndpoint("/api/calculate"), calculateBody)).json()
136+
assertIdAndPath(calculate)
137+
assert.deepEqual(calculate.points, [[[1], -1.4142135623730951]])
138+
const calculateAsyncResult = await callAsyncAndWaitJSONResult("/api/start/calculate", calculateBody)
139+
assertIdAndPath(calculateAsyncResult)
140+
assert.deepEqual(calculateAsyncResult.points, [[[1], -1.4142135623730951]])
79141

80142
// Local error endpoint
81-
const localError = await callHerbie("/api/localerror", {
143+
const localErrorBody = {
82144
method: 'POST', body: JSON.stringify({
83145
formula: FPCoreFormula, sample: sample2.points
84146
})
85-
})
147+
}
148+
const localError = await (await fetch(makeEndpoint("/api/localerror"), localErrorBody)).json()
86149
assertIdAndPath(localError)
87150
assert.equal(localError.tree['avg-error'] > 0, true)
151+
const localErrorAsyncResult = await callAsyncAndWaitJSONResult("/api/start/localerror", localErrorBody)
152+
assertIdAndPath(localErrorAsyncResult)
153+
assert.equal(localErrorAsyncResult.tree['avg-error'] > 0, true)
88154

89-
const json1 = JSON.stringify({
90-
formula: FPCoreFormula, sample: [[[2.852044568544089e-150], 1e+308]], seed: 5
91-
})
92-
const json2 = JSON.stringify({
93-
formula: FPCoreFormula, sample: [[[1.5223342548065899e-15], 1e+308]], seed: 5
94-
})
95-
const localError1 = await callHerbie("/api/localerror", {
96-
method: 'POST', body: json1
97-
})
98-
const localError2 = await callHerbie("/api/localerror", {
99-
method: 'POST', body: json2
100-
})
155+
const localError1 = await (await fetch(makeEndpoint("/api/localerror"), {
156+
method: 'POST', body: JSON.stringify({
157+
formula: FPCoreFormula, sample: [[[2.852044568544089e-150], 1e+308]], seed: 5
158+
})
159+
})).json()
160+
const localError2 = await (await fetch(makeEndpoint("/api/localerror"), {
161+
method: 'POST', body: JSON.stringify({
162+
formula: FPCoreFormula, sample: [[[1.5223342548065899e-15], 1e+308]], seed: 5
163+
})
164+
})).json()
101165
// Test that different sample points produce different job ids ensuring that different results are served for these inputs.
102166
assert.notEqual(localError1.job, localError2.job)
103167

104168
// Alternatives endpoint
105-
106-
const alternatives = await callHerbie("/api/alternatives", {
169+
const altBody = {
107170
method: 'POST', body: JSON.stringify({
108171
formula: FPCoreFormula, sample: [[[
109172
14.97651307489794
110173
], 0.12711304680349078]]
111174
})
112-
})
175+
}
176+
const alternatives = await (await fetch(makeEndpoint("/api/alternatives"), altBody)).json()
113177
assertIdAndPath(alternatives)
114178
assert.equal(Array.isArray(alternatives.alternatives), true)
115-
116-
//Explanations endpoint
117-
const sampleExp = (await (await fetch('http://127.0.0.1:8000/api/sample', { method: 'POST', body: JSON.stringify({ formula: FPCoreFormula2, seed: 5 }) })).json())
118-
const explain = await callHerbie("/api/explanations", {
119-
method: 'POST', body: JSON.stringify({
120-
formula: FPCoreFormula, sample: sampleExp.points
121-
})
122-
})
123-
assertIdAndPath(explain)
124-
assert.equal(explain.explanation.length > 0, true, 'explanation should not be empty');
125-
// Exacts endpoint
126-
const exacts = await callHerbie("/api/exacts", {
127-
method: 'POST', body: JSON.stringify({
128-
formula: FPCoreFormula2, sample: eval_sample
129-
})
130-
})
131-
assertIdAndPath(exacts)
132-
assert.deepEqual(exacts.points, [[[1], -1.4142135623730951]])
133-
134-
// Calculate endpoint
135-
const calculate = await callHerbie("/api/calculate", {
136-
method: 'POST', body: JSON.stringify({
137-
formula: FPCoreFormula2, sample: eval_sample
138-
})
139-
})
140-
assertIdAndPath(calculate)
141-
assert.deepEqual(calculate.points, [[[1], -1.4142135623730951]])
179+
const alternativesAsyncResult = await callAsyncAndWaitJSONResult("/api/start/alternatives", altBody)
180+
assertIdAndPath(alternativesAsyncResult)
181+
assert.equal(Array.isArray(alternativesAsyncResult.alternatives), true)
142182

143183
// Cost endpoint
144-
const cost = await callHerbie("/api/cost", {
184+
const costBody = {
145185
method: 'POST', body: JSON.stringify({
146186
formula: FPCoreFormula2, sample: eval_sample
147187
})
148-
})
188+
}
189+
const cost = await (await fetch(makeEndpoint("/api/cost"), costBody)).json()
149190
assertIdAndPath(cost)
150191
assert.equal(cost.cost > 0, true)
192+
const costAsyncResult = await callAsyncAndWaitJSONResult("/api/start/cost", costBody)
193+
assertIdAndPath(costAsyncResult)
194+
assert.equal(costAsyncResult.cost > 0, true)
151195

152-
// // MathJS endpoint
153-
const mathjs = await callHerbie("/api/mathjs", {
154-
method: 'POST',
155-
body: JSON.stringify({ formula: FPCoreFormula })
156-
})
196+
// MathJS endpoint
197+
const mathjs = await (await fetch(makeEndpoint("/api/mathjs"), {
198+
method: 'POST', body: JSON.stringify({ formula: FPCoreFormula })
199+
})).json()
157200
assert.equal(mathjs.mathjs, "sqrt(x + 1.0) - sqrt(x)")
158201

159202
// Translate endpoint
@@ -170,52 +213,46 @@ const expectedExpressions = {
170213
}
171214

172215
for (const e in expectedExpressions) {
173-
const translatedExpr = await callHerbie("/api/translate", {
216+
const translatedExpr = await (await fetch(makeEndpoint("/api/translate"), {
174217
method: 'POST', body: JSON.stringify(
175218
{ formula: FPCoreFormula, language: e })
176-
})
219+
})).json()
177220

178221
assert.equal(translatedExpr.result, expectedExpressions[e])
179222
}
180223

181-
let counter = 0
182-
let cap = 100
183-
// Check status endpoint
184-
let checkStatus = await callHerbie(path, { method: 'GET' })
185-
/*
186-
This is testing if the /improve-start test at the beginning has been completed. The cap and counter is a sort of timeout for the test. Ends up being 10 seconds max.
187-
*/
188-
while (checkStatus.status != 201 && counter < cap) {
189-
counter += 1
190-
checkStatus = await callHerbie(path, { method: 'GET' })
191-
await new Promise(r => setTimeout(r, 100)); // ms
192-
}
193-
assert.equal(checkStatus.statusText, 'Job complete')
194-
195224
// Results.json endpoint
196-
const jsonResults = await callHerbie("/results.json", { method: 'GET' })
225+
const jsonResults = await (await fetch(makeEndpoint("/results.json"), { method: 'GET' })).json()
197226

198227
// Basic test that checks that there are the two results after the above test.
199228
// TODO add a way to reset the results.json file?
200229
assert.equal(jsonResults.tests.length, 2)
201230

202-
async function callHerbie(endPoint, body) {
203-
const url = new URL(`http://127.0.0.1:8000${endPoint}`)
204-
const pathname = url.pathname
205-
const rsp = await fetch(url, body)
206-
if (pathname == "/improve" ||
207-
pathname == "/improve-start" ||
208-
pathname.includes("check-status") ||
209-
pathname.includes("timeline") ||
210-
pathname.includes("sample") ||
211-
pathname == "/up") {
212-
return rsp
213-
} else {
214-
return rsp.json()
215-
}
231+
// Helper Functions
232+
function makeEndpoint(endpoint) {
233+
return new URL(`http://127.0.0.1:8000${endpoint}`)
216234
}
217235

218236
function assertIdAndPath(json) {
219237
assert.equal(json.job.length > 0, true)
220238
assert.equal(json.path.includes("."), true)
239+
}
240+
241+
async function callAsyncAndWaitJSONResult(endpoint, body) {
242+
let counter = 0
243+
let cap = 100
244+
// Check status endpoint
245+
let jobInfo = await fetch(makeEndpoint(endpoint), body)
246+
/*
247+
The cap and counter is a sort of timeout for the test. Ends up being 10 seconds max.
248+
*/
249+
const jobJSON = await jobInfo.json()
250+
const checkStatus = await fetch(makeEndpoint(`/check-status/${jobJSON.job}`), { method: 'GET' })
251+
while (checkStatus.status != 201 && counter < cap) {
252+
counter += 1
253+
checkStatus = await fetch(makeEndpoint(`/check-status/${jobJSON.job}`), { method: 'GET' })
254+
await new Promise(r => setTimeout(r, 100)); // ms
255+
}
256+
const result = await fetch(makeEndpoint(`/api/result/${jobJSON.job}`), { method: 'GET' })
257+
return await result.json()
221258
}

0 commit comments

Comments
 (0)