Latest Chapter correction: one numeric input, owner-gated (#149)
This commit is contained in:
@@ -3238,3 +3238,136 @@ func TestSeriesPollCapsBody(t *testing.T) {
|
||||
t.Errorf("an oversized body still stamped the request:\n%s", body)
|
||||
}
|
||||
}
|
||||
// The correction route validates at the boundary: a non-numeric, zero,
|
||||
// negative or non-finite chapter answers 400 and never reaches the store, and
|
||||
// a finite number greater than zero stores the number, the derived label and
|
||||
// the stamp. The answer is the freshly rendered meta fragment, so the figures
|
||||
// describe the state after the press (#149).
|
||||
func TestCorrectLatestChapterRoute(t *testing.T) {
|
||||
st, dsn := newTestStoreURL(t)
|
||||
db, err := sql.Open("pgx", dsn)
|
||||
if err != nil {
|
||||
t.Fatalf("open %s: %v", dsn, err)
|
||||
}
|
||||
defer db.Close()
|
||||
seedSeriesRow(t, st, db, seriesRowSeed{
|
||||
key: "asura:solo", url: "u", checkedAt: 9000, bookmarks: 1, latestNum: floatPtr(3),
|
||||
})
|
||||
router := newRouter(st, testConfig())
|
||||
cookie := sessionCookie(t, st)
|
||||
|
||||
for _, body := range []string{
|
||||
"chapter=abc", "chapter=", "chapter=0", "chapter=-1", "chapter=NaN", "chapter=Inf",
|
||||
} {
|
||||
req := httptest.NewRequest(http.MethodPost, "/admin/series/asura:solo/latest", strings.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.AddCookie(cookie)
|
||||
rr := httptest.NewRecorder()
|
||||
router.ServeHTTP(rr, req)
|
||||
if rr.Code != http.StatusBadRequest {
|
||||
t.Errorf("POST latest with body %q: status = %d, want 400", body, rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing reached the store: the seeded number stands, unstamped.
|
||||
var num float64
|
||||
var stamp int64
|
||||
if err := db.QueryRow(`
|
||||
SELECT latest_chapter_num, latest_corrected_at
|
||||
FROM series WHERE site = 'asura' AND series_id = 'solo'`).
|
||||
Scan(&num, &stamp); err != nil {
|
||||
t.Fatalf("read back: %v", err)
|
||||
}
|
||||
if num != 3 || stamp != 0 {
|
||||
t.Fatalf("after 400s the row is num %v, stamp %d; want 3, 0", num, stamp)
|
||||
}
|
||||
|
||||
// A good press stores the number, the derived label and the stamp, and
|
||||
// answers with the meta fragment describing the state after the press.
|
||||
req := httptest.NewRequest(http.MethodPost, "/admin/series/asura:solo/latest", strings.NewReader("chapter=12.5"))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.AddCookie(cookie)
|
||||
rr := httptest.NewRecorder()
|
||||
router.ServeHTTP(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("POST latest status = %d, want 200 (body %s)", rr.Code, rr.Body.String())
|
||||
}
|
||||
body := rr.Body.String()
|
||||
if !strings.Contains(body, `id="detail-meta"`) {
|
||||
t.Errorf("correction answer is not the meta fragment:\n%s", body)
|
||||
}
|
||||
if !strings.Contains(body, `<span class="mark">corrected `) {
|
||||
t.Errorf("correction answer lacks the fresh corrected marker:\n%s", body)
|
||||
}
|
||||
var label string
|
||||
if err := db.QueryRow(`
|
||||
SELECT latest_chapter, latest_chapter_num, latest_corrected_at
|
||||
FROM series WHERE site = 'asura' AND series_id = 'solo'`).
|
||||
Scan(&label, &num, &stamp); err != nil {
|
||||
t.Fatalf("read back: %v", err)
|
||||
}
|
||||
if label != "Chapter 12.5" || num != 12.5 {
|
||||
t.Errorf("stored = %q, %v; want the derived label and 12.5", label, num)
|
||||
}
|
||||
if stamp == 0 {
|
||||
t.Error("stamp = 0, want the correction stamp written")
|
||||
}
|
||||
}
|
||||
|
||||
// The detail page offers the one-input correction with the plain copy, and
|
||||
// the corrected marker rides the meta line while the stamp is set — then
|
||||
// disappears the moment a machine writes the number (#149).
|
||||
func TestAdminSeriesDetailCorrectionMarker(t *testing.T) {
|
||||
st, dsn := newTestStoreURL(t)
|
||||
db, err := sql.Open("pgx", dsn)
|
||||
if err != nil {
|
||||
t.Fatalf("open %s: %v", dsn, err)
|
||||
}
|
||||
defer db.Close()
|
||||
seedSeriesRow(t, st, db, seriesRowSeed{key: "asura:solo", url: "u", checkedAt: 9000, bookmarks: 1})
|
||||
router := newRouter(st, testConfig())
|
||||
cookie := sessionCookie(t, st)
|
||||
|
||||
body := seriesDetailPage(t, router, st, "asura:solo")
|
||||
for _, want := range []string{
|
||||
`name="chapter"`,
|
||||
`hx-post="/admin/series/asura:solo/latest"`,
|
||||
"The next successful Poll overwrites this value.",
|
||||
} {
|
||||
if !strings.Contains(body, want) {
|
||||
t.Errorf("detail page lacks %q:\n%s", want, body)
|
||||
}
|
||||
}
|
||||
if strings.Contains(body, "corrected ") {
|
||||
t.Errorf("uncorrected detail already carries the marker:\n%s", body)
|
||||
}
|
||||
|
||||
// The press lands the marker on the meta line.
|
||||
req := httptest.NewRequest(http.MethodPost, "/admin/series/asura:solo/latest", strings.NewReader("chapter=7"))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.AddCookie(cookie)
|
||||
rr := httptest.NewRecorder()
|
||||
router.ServeHTTP(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("POST latest status = %d, want 200", rr.Code)
|
||||
}
|
||||
body = seriesDetailPage(t, router, st, "asura:solo")
|
||||
if !strings.Contains(body, `<span class="mark">corrected `) {
|
||||
t.Errorf("detail page lacks the corrected marker after the press:\n%s", body)
|
||||
}
|
||||
if !strings.Contains(body, "ch 7") {
|
||||
t.Errorf("detail page does not show the corrected number:\n%s", body)
|
||||
}
|
||||
|
||||
// A machine write (the poller's setter) kills the marker.
|
||||
if err := st.SetLatestChapter("asura", "solo", "Chapter 8", 8); err != nil {
|
||||
t.Fatalf("SetLatestChapter: %v", err)
|
||||
}
|
||||
body = seriesDetailPage(t, router, st, "asura:solo")
|
||||
if strings.Contains(body, "corrected ") {
|
||||
t.Errorf("marker survives a machine write:\n%s", body)
|
||||
}
|
||||
if !strings.Contains(body, "ch 8") {
|
||||
t.Errorf("detail page does not show the machine-written number:\n%s", body)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user