103 lines
2.9 KiB
Go
103 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"golang.org/x/net/html"
|
|
)
|
|
|
|
func TestInferAssignmentDate(t *testing.T) {
|
|
now := time.Date(2026, 3, 28, 10, 0, 0, 0, time.UTC)
|
|
got := inferAssignmentDate("Jan 20", now)
|
|
want := time.Date(2026, 1, 20, 0, 0, 0, 0, time.UTC)
|
|
if !got.Equal(want) {
|
|
t.Fatalf("got %s want %s", got, want)
|
|
}
|
|
}
|
|
|
|
func TestInferAssignmentDateRollsBackYear(t *testing.T) {
|
|
now := time.Date(2026, 3, 28, 10, 0, 0, 0, time.UTC)
|
|
got := inferAssignmentDate("Dec 15", now)
|
|
want := time.Date(2025, 12, 15, 0, 0, 0, 0, time.UTC)
|
|
if !got.Equal(want) {
|
|
t.Fatalf("got %s want %s", got, want)
|
|
}
|
|
}
|
|
|
|
func TestInferUpcomingDateRollsForwardYear(t *testing.T) {
|
|
now := time.Date(2026, 12, 28, 10, 0, 0, 0, time.UTC)
|
|
got := inferUpcomingDate("Jan 03", now)
|
|
want := time.Date(2027, 1, 3, 0, 0, 0, 0, time.UTC)
|
|
if !got.Equal(want) {
|
|
t.Fatalf("got %s want %s", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFilterUpcomingAssignments(t *testing.T) {
|
|
now := time.Date(2026, 3, 28, 10, 0, 0, 0, time.UTC)
|
|
assignments := []Assignment{
|
|
{DueDate: time.Date(2026, 3, 29, 0, 0, 0, 0, time.UTC), Title: "Soon"},
|
|
{DueDate: time.Date(2026, 4, 20, 0, 0, 0, 0, time.UTC), Title: "Later"},
|
|
}
|
|
got := filterUpcomingAssignments(assignments, now, 14)
|
|
if len(got) != 1 || got[0].Title != "Soon" {
|
|
t.Fatalf("unexpected filtered assignments: %#v", got)
|
|
}
|
|
}
|
|
|
|
func TestDedupeAssignments(t *testing.T) {
|
|
assignment := Assignment{
|
|
DueDate: time.Date(2026, 4, 1, 0, 0, 0, 0, time.UTC),
|
|
Title: "Preparedness",
|
|
Link: "https://example.invalid/a",
|
|
}
|
|
got := dedupeAssignments([]Assignment{assignment, assignment})
|
|
if len(got) != 1 {
|
|
t.Fatalf("got %d items", len(got))
|
|
}
|
|
}
|
|
|
|
func TestExtractLikeLiveMissingTable(t *testing.T) {
|
|
doc := mustParseHTML(`
|
|
<table class="pure-table pure-table-horizontal missing-assignments">
|
|
<tbody>
|
|
<tr>
|
|
<td>Mar<br>25</td>
|
|
<td>
|
|
<small><a href="/class/1">US History</a></small>
|
|
<a data-alma-modal="StudentAssignmentDetailsModal" href="/assignment/1">HW: Timeline Events</a>
|
|
</td>
|
|
<td><i title="Missing"></i></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>`)
|
|
|
|
table := findNode(doc, func(n *html.Node) bool {
|
|
return n.Type == html.ElementNode && n.Data == "table" && hasClass(n, "missing-assignments")
|
|
})
|
|
if table == nil {
|
|
t.Fatal("missing table not found")
|
|
}
|
|
row := findNode(table, func(n *html.Node) bool { return n.Type == html.ElementNode && n.Data == "tr" })
|
|
cells := directChildrenByTag(row, "td")
|
|
if got := nodeText(cells[0]); got != "Mar 25" {
|
|
t.Fatalf("got %q", got)
|
|
}
|
|
link := findNode(cells[1], func(n *html.Node) bool {
|
|
return n.Type == html.ElementNode && n.Data == "a" && attr(n, "data-alma-modal") != ""
|
|
})
|
|
if got := nodeText(link); got != "HW: Timeline Events" {
|
|
t.Fatalf("got %q", got)
|
|
}
|
|
}
|
|
|
|
func mustParseHTML(text string) *html.Node {
|
|
doc, err := html.Parse(strings.NewReader(text))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return doc
|
|
}
|