Files
sm-bm-plugin/controllers/api/json_test.go
Jakub Zych 9436fb62d6 feat: personal pins on materials
A per-user jz_bm_material_pins table and PUT/DELETE /materials/{id}/pin
on the student API and its token twins: 204 for a material the caller
may see, idempotent, 404 otherwise. List rows, course rows and the
detail carry pinned. The plain list lists the caller's pins first
(newest pin first); with q the relevance order stays. A pin writes only
the pins table and never changes the material's revision.
2026-11-09 13:13:54 +01:00

122 lines
3.6 KiB
Go

package api
import (
"encoding/json"
"strings"
"testing"
"git.golem15.com/jakub/sm-bm-plugin/models"
)
// TestReadingJSONCarriesMeetingID checks that meeting_id is always present
// in a reading, as a number or as null.
func TestReadingJSONCarriesMeetingID(t *testing.T) {
id := uint(4)
for _, tc := range []struct {
meeting *uint
want string
}{
{&id, `"meeting_id":4`},
{nil, `"meeting_id":null`},
} {
b, err := json.Marshal(readingJSON{ID: 1, Title: "Lektura", MeetingID: tc.meeting})
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(b), tc.want) {
t.Errorf("reading JSON %s does not contain %s", b, tc.want)
}
}
}
// TestMaterialJSONCarriesMeetingID checks that meeting_id is always present
// in a material, as a number or as null.
func TestMaterialJSONCarriesMeetingID(t *testing.T) {
id := uint(4)
for _, tc := range []struct {
meeting *uint
want string
}{
{&id, `"meeting_id":4`},
{nil, `"meeting_id":null`},
} {
b, err := json.Marshal(newMaterialListJSON(models.Material{ID: 1, Title: "Materiał", Type: "pdf", MeetingID: tc.meeting}, 0))
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(b), tc.want) {
t.Errorf("material JSON %s does not contain %s", b, tc.want)
}
}
}
// TestMaterialJSONCarriesPrivacy checks that is_private is always present in
// a material and that the detail carries can_manage, false by default.
func TestMaterialJSONCarriesPrivacy(t *testing.T) {
for _, tc := range []struct {
private bool
want string
}{
{true, `"is_private":true`},
{false, `"is_private":false`},
} {
b, err := json.Marshal(newMaterialListJSON(models.Material{ID: 1, Title: "Materiał", Type: "pdf", IsPrivate: tc.private}, 0))
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(b), tc.want) {
t.Errorf("material JSON %s does not contain %s", b, tc.want)
}
}
b, err := json.Marshal(materialDetailJSON{materialListJSON: newMaterialListJSON(models.Material{ID: 1, Title: "Materiał", Type: "pdf"}, 0)})
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(b), `"can_manage":false`) {
t.Errorf("material detail JSON %s does not contain can_manage false", b)
}
}
// TestMaterialJSONCarriesPinned checks that pinned is always present in a
// material row, false unless the caller set it, and that the detail carries
// the row's value.
func TestMaterialJSONCarriesPinned(t *testing.T) {
row := newMaterialListJSON(models.Material{ID: 1, Title: "Materiał", Type: "notatka"}, 0)
b, err := json.Marshal(row)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(b), `"pinned":false`) {
t.Errorf("material JSON %s does not contain pinned false", b)
}
row.Pinned = true
b, err = json.Marshal(row)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(b), `"pinned":true`) {
t.Errorf("pinned material JSON %s does not contain pinned true", b)
}
b, err = json.Marshal(materialDetailJSON{materialListJSON: row})
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(b), `"pinned":true`) {
t.Errorf("pinned material detail JSON %s does not contain pinned true", b)
}
}
// TestVisibleMaterialSQL checks the visibility fragment: public, the author,
// or a share of the caller, with the caller id bound twice.
func TestVisibleMaterialSQL(t *testing.T) {
got := visibleMaterialSQL("m")
for _, want := range []string{"m.is_private = FALSE", "m.author_user_id = ?", "jz_bm_material_shares", ".material_id = m.id"} {
if !strings.Contains(got, want) {
t.Errorf("visibleMaterialSQL(m) = %q, missing %q", got, want)
}
}
if n := strings.Count(got, "?"); n != 2 {
t.Errorf("visibleMaterialSQL(m) has %d placeholders, want 2", n)
}
}