1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
package logic

import (
	"io"
	"path/filepath"
	"rss-kakapo/dal"
	"rss-kakapo/shared"
	"testing"
	"time"
)

func newListsRepo(t *testing.T) dal.IRepo {
	t.Helper()
	cfg := &shared.Config{
		DbFile: filepath.Join(t.TempDir(), "test.db"),
		Birb:   &shared.UserInfo{User: "birb"},
	}
	repo := dal.NewRepo(cfg, shared.NewLogger(io.Discard, "Error"))
	repo.InitUpdateDb()
	return repo
}

func TestBlockedFeedsEmptyBlocksNothing(t *testing.T) {
	bf := NewBlockedFeeds(newListsRepo(t))
	if blocked, err := bf.IsBlocked("https://blog.example.org/feed"); blocked || err != nil {
		t.Errorf("IsBlocked = %v, %v; want false, nil", blocked, err)
	}
}

func TestBlockedFeedsMatchesWithoutSchemeOrCase(t *testing.T) {
	repo := newListsRepo(t)
	entry := NormaliseFeedUrl("HTTPS://Blog.example.org/feed ")
	if err := repo.AddToList(dal.BlockedFeeds, []string{entry}, time.Now()); err != nil {
		t.Fatal(err)
	}
	bf := NewBlockedFeeds(repo)
	for url, want := range map[string]bool{
		"https://blog.example.org/feed": true,
		"http://BLOG.example.org/feed":  true,
		"https://other.example.org/rss": false,
	} {
		if got, err := bf.IsBlocked(url); got != want || err != nil {
			t.Errorf("IsBlocked(%q) = %v, %v; want %v", url, got, err, want)
		}
	}

	// Removed while running: the next lookup sees it.
	if _, err := repo.RemoveFromList(dal.BlockedFeeds, []string{entry}); err != nil {
		t.Fatal(err)
	}
	if blocked, _ := bf.IsBlocked("https://blog.example.org/feed"); blocked {
		t.Error("still blocked after removal")
	}
}

func TestRequesterAllowlist(t *testing.T) {
	repo := newListsRepo(t)

	if ok, err := isRequesterAllowed(false, repo, "@anyone@example.org"); !ok || err != nil {
		t.Errorf("unrestricted: %v, %v; want true, nil", ok, err)
	}
	// Restricted with an empty list: closed.
	if ok, err := isRequesterAllowed(true, repo, "@anyone@example.org"); ok || err != nil {
		t.Errorf("restricted, empty list: %v, %v; want false, nil", ok, err)
	}

	// Stored without the '@' and in lower case, whichever way it was given.
	if err := repo.AddToList(dal.AllowedRequesters,
		[]string{NormaliseMoniker("@Alice@Example.org")}, time.Now()); err != nil {
		t.Fatal(err)
	}
	for moniker, want := range map[string]bool{
		"@alice@example.org": true,
		"alice@EXAMPLE.org":  true,
		"@bob@example.org":   false,
	} {
		if got, err := isRequesterAllowed(true, repo, moniker); got != want || err != nil {
			t.Errorf("isRequesterAllowed(%q) = %v, %v; want %v", moniker, got, err, want)
		}
	}
}

func TestListAddIsIdempotentAndRemoveReportsMissing(t *testing.T) {
	repo := newListsRepo(t)
	for i := 0; i < 2; i++ {
		if err := repo.AddToList(dal.BlockedFeeds, []string{"b.example/feed", "a.example/feed"}, time.Now()); err != nil {
			t.Fatal(err)
		}
	}
	list, err := repo.GetList(dal.BlockedFeeds)
	if err != nil || len(list) != 2 || list[0] != "a.example/feed" || list[1] != "b.example/feed" {
		t.Errorf("GetList = %v, %v; want [a.example/feed b.example/feed]", list, err)
	}
	notFound, err := repo.RemoveFromList(dal.BlockedFeeds, []string{"a.example/feed", "c.example/feed"})
	if err != nil || len(notFound) != 1 || notFound[0] != "c.example/feed" {
		t.Errorf("RemoveFromList: not found %v, %v; want [c.example/feed]", notFound, err)
	}
	// The two lists are separate.
	if empty, err := repo.IsListEmpty(dal.AllowedRequesters); !empty || err != nil {
		t.Errorf("allowlist empty = %v, %v; want true", empty, err)
	}
}