| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- package gog
- import (
- "context"
- "net/http"
- "net/http/httptest"
- "os"
- "strings"
- "testing"
- )
- // serveHome serves the given HTML for all requests.
- func serveHome(t *testing.T, html string) *Client {
- t.Helper()
- srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
- w.Header().Set("Content-Type", "text/html; charset=UTF-8")
- w.Write([]byte(html))
- }))
- t.Cleanup(srv.Close)
- c := NewClient()
- c.HTTP = srv.Client()
- // Point the client at the test server by overriding the home URL via
- // BaseURL-like behavior: homeURL is a package const, so we test through
- // the extraction path instead.
- _ = srv
- return c
- }
- // The live homepage embeds the giveaway in gogcom-store-state JSON.
- func TestLiveFixture_GiveawayFromStoreState(t *testing.T) {
- html, err := os.ReadFile("testdata/home.html")
- if err != nil {
- t.Fatal(err)
- }
- state := extractStoreState(string(html))
- if state == "" {
- t.Fatal("gogcom-store-state script not found in live fixture")
- }
- sec, err := parseGiveawaySection([]byte(state))
- if err != nil {
- t.Fatalf("parse giveaway: %v", err)
- }
- if sec == nil {
- t.Fatal("no giveaway section found in live fixture")
- }
- if sec.Product == nil || sec.Product.Title == "" || sec.Product.Slug == "" {
- t.Fatalf("giveaway product incomplete: %+v", sec.Product)
- }
- if sec.Product.Slug != "a_new_beginning" {
- t.Errorf("slug = %q, want a_new_beginning (live giveaway Oct 2026)", sec.Product.Slug)
- }
- if sec.Product.ID == "" {
- t.Error("product id missing")
- }
- if sec.EndDate.IsZero() {
- t.Error("giveaway endDate missing")
- }
- }
- // Regression: the section is identified by STRUCTURE (endDate + product with
- // slug/title), not by a fixed section UUID — survives layout changes.
- func TestGiveawayRecognitionIsStructural(t *testing.T) {
- // A section with endDate + product anywhere in the state is found,
- // even under an arbitrary key.
- state := `{"someKey":{"x":{"endDate":"2026-11-02T16:00:59.000+02:00","product":{"id":"123","title":"Test Game","slug":"test_game"}}},"other":{"endDate":"2020-01-01T00:00:00Z","product":{"id":"0","title":"Old","slug":"old"}}}`
- sec, err := parseGiveawaySection([]byte(state))
- if err != nil {
- t.Fatal(err)
- }
- if sec == nil || sec.Product.Slug != "test_game" {
- t.Fatalf("structural detection failed: %+v", sec)
- }
- }
- // No store-state script → explicit error (the client must not pretend
- // success with an empty list).
- func TestMissingStoreStateIsAnError(t *testing.T) {
- if state := extractStoreState("<html><body>nothing here</body></html>"); state != "" {
- t.Fatalf("expected empty state, got %q", state)
- }
- }
- // A store-state without any giveaway object → nil section, no error.
- func TestStateWithoutGiveawayYieldsNoSection(t *testing.T) {
- sec, err := parseGiveawaySection([]byte(`{"pageMetadata":{"locale":"en-US"}}`))
- if err != nil {
- t.Fatal(err)
- }
- if sec != nil {
- t.Fatalf("expected no section, got %+v", sec)
- }
- }
- // Broken store-state JSON → error, not panic.
- func TestBrokenStoreStateJSONIsAnError(t *testing.T) {
- if _, err := parseGiveawaySection([]byte("{not json")); err == nil {
- t.Fatal("expected error for broken JSON")
- }
- }
- // The extraction handles the script tag with trailing content after </script>.
- func TestExtractStoreStateTrimsScript(t *testing.T) {
- html := `<html><head><script id="gogcom-store-state" type="application/json">{"a":1}</script></head></html>`
- state := extractStoreState(html)
- if strings.TrimSpace(state) != `{"a":1}` {
- t.Fatalf("state = %q", state)
- }
- }
- // End-to-end via HTTP: client fetches the (test) homepage and extracts the
- // giveaway. Uses a package-level URL override to avoid network.
- func TestGetFreeGamesEndToEnd(t *testing.T) {
- html, err := os.ReadFile("testdata/home.html")
- if err != nil {
- t.Fatal(err)
- }
- srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
- w.Write(html)
- }))
- t.Cleanup(srv.Close)
- c := NewClient()
- c.HTTP = srv.Client()
- c.HomeURL = srv.URL
- games, err := c.GetFreeGames(context.Background())
- if err != nil {
- t.Fatal(err)
- }
- if len(games) != 1 {
- t.Fatalf("want exactly 1 giveaway, got %d", len(games))
- }
- g := games[0]
- if g.Store != "gog" || g.Kind != "free-now" {
- t.Errorf("store/kind = %s/%s, want gog/free-now", g.Store, g.Kind)
- }
- if !strings.HasPrefix(g.ID, "gog-") {
- t.Errorf("id = %q, want gog- prefix", g.ID)
- }
- if g.URL == "" {
- t.Error("url missing")
- }
- }
|