package api import ( "net/http/httptest" "strings" "testing" ) // #33 sweep: the create API must enforce the same expiry window as the UI // (1 minute .. 1 year). Previously -1h, 0s, 1ns and 30000h were all accepted, // producing pastes that were born expired or effectively permanent. func TestCreatePasteExpiryBounds(t *testing.T) { s := testServer(t) h := s.routes() cases := []struct { expiresIn string wantCode int }{ {"-1h", 400}, {"-0s", 400}, {"0s", 400}, {"1ns", 400}, {"59s", 400}, {"1m", 201}, {"90s", 201}, {"8760h", 201}, // exactly 1 year {"8785h", 400}, // 1 year + 1 day: over the max {"30000h", 400}, // ~3.4 years, over the max } globalLimiter = newLimiter() // one fresh bucket for the whole table for _, c := range cases { globalLimiter = newLimiter() // avoid create rate limit between cases req := httptest.NewRequest("POST", "/api/pastes", strings.NewReader(`{"content":"x","expires_in":"`+c.expiresIn+`"}`)) rec := httptest.NewRecorder() h.ServeHTTP(rec, req) if rec.Code != c.wantCode { t.Errorf("expires_in %q: got %d want %d (%s)", c.expiresIn, rec.Code, c.wantCode, rec.Body.String()) } } } // #33 sweep: HTML paste views must increment view_count. The increment was // missing from handlePasteView, so the counter only moved on /raw. func TestPasteViewIncrementsViewCount(t *testing.T) { s := testServer(t) h := s.routes() req := httptest.NewRequest("POST", "/api/pastes", strings.NewReader(`{"content":"vc"}`)) rec := httptest.NewRecorder() h.ServeHTTP(rec, req) id := jsonField(t, rec.Body.String(), "id") // first render counts (no ?created=1 here: that's the just-created banner case) req = httptest.NewRequest("GET", "/"+id, nil) rec = httptest.NewRecorder() h.ServeHTTP(rec, req) if rec.Code != 200 { t.Fatalf("view: got %d", rec.Code) } req = httptest.NewRequest("GET", "/"+id, nil) rec = httptest.NewRecorder() h.ServeHTTP(rec, req) req = httptest.NewRequest("GET", "/api/pastes/"+id, nil) rec = httptest.NewRecorder() h.ServeHTTP(rec, req) if rec.Code != 200 { t.Fatalf("api get: got %d", rec.Code) } body := rec.Body.String() if !strings.Contains(body, `"view_count":2`) { t.Fatalf("expected view_count 2 after two HTML views, got: %s", body) } } // #33 sweep: the just-created banner render (?created=1) must NOT count as a // view for the creator. func TestJustCreatedViewDoesNotCount(t *testing.T) { s := testServer(t) h := s.routes() req := httptest.NewRequest("POST", "/api/pastes", strings.NewReader(`{"content":"jc"}`)) rec := httptest.NewRecorder() h.ServeHTTP(rec, req) id := jsonField(t, rec.Body.String(), "id") req = httptest.NewRequest("GET", "/"+id+"?created=1&token=t", nil) rec = httptest.NewRecorder() h.ServeHTTP(rec, req) req = httptest.NewRequest("GET", "/api/pastes/"+id, nil) rec = httptest.NewRecorder() h.ServeHTTP(rec, req) if strings.Contains(rec.Body.String(), `"view_count":1`) { t.Fatalf("just-created render counted as a view: %s", rec.Body.String()) } }