windows-iso-downloader/cli/homepage_test.go
Shekhar Vaidya 3994a82d6d feat(cli): homepage landing screen for bare msdl; fix search substring bug
The bare `msdl` invocation showed all 22 products (17 consumer + 5
eval) as a flat numbered list. Replaces it with a curated landing
screen: 5 popular products (picked from real usage telemetry) plus a
2-item eval shortlist, with "list" as an escape hatch to today's full
picker and free text routed through the existing search flow.

Also fixes a search bug: querying "windows 10" incorrectly matched
Windows 11 24H2 because "10" is a substring of its build number
(26100.1742). Query words now must start at a word boundary rather
than matching anywhere, so digit fragments inside unrelated numbers
can no longer collide -- while "arm" still fuzzy-matches "ARM64".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-13 12:24:43 +05:30

166 lines
4.6 KiB
Go

package main
import (
"bytes"
"io"
"os"
"strings"
"testing"
)
func testFeatured() []Product {
return []Product{
{ID: "3262", Name: "Windows 11 25H2 (26200.6584)"},
{ID: "2618", Name: "Windows 10 22H2 v1 (19045.2965)"},
}
}
func testEvalShortlist() []EvalProduct {
return []EvalProduct{
{Slug: "server-2025", Name: "Windows Server 2025"},
{Slug: "win11-ent", Name: "Windows 11 Enterprise"},
}
}
func TestParseHomepageInput_product(t *testing.T) {
choice, err := parseHomepageInput("1", testFeatured(), testEvalShortlist())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if choice.kind != homepageKindProduct || choice.productID != "3262" {
t.Errorf("got %+v, want product 3262", choice)
}
}
func TestParseHomepageInput_eval(t *testing.T) {
choice, err := parseHomepageInput("3", testFeatured(), testEvalShortlist())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if choice.kind != homepageKindEval || choice.evalSlug != "server-2025" {
t.Errorf("got %+v, want eval server-2025", choice)
}
}
func TestParseHomepageInput_evalSecond(t *testing.T) {
choice, err := parseHomepageInput("4", testFeatured(), testEvalShortlist())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if choice.kind != homepageKindEval || choice.evalSlug != "win11-ent" {
t.Errorf("got %+v, want eval win11-ent", choice)
}
}
func TestParseHomepageInput_outOfRange(t *testing.T) {
_, err := parseHomepageInput("5", testFeatured(), testEvalShortlist())
if err == nil {
t.Fatal("expected error for out-of-range choice")
}
}
func TestParseHomepageInput_listCaseInsensitive(t *testing.T) {
for _, s := range []string{"list", "List", "LIST"} {
choice, err := parseHomepageInput(s, testFeatured(), testEvalShortlist())
if err != nil {
t.Fatalf("unexpected error for %q: %v", s, err)
}
if choice.kind != homepageKindList {
t.Errorf("input %q: got kind %v, want list", s, choice.kind)
}
}
}
func TestParseHomepageInput_searchFallback(t *testing.T) {
choice, err := parseHomepageInput("windows 10", testFeatured(), testEvalShortlist())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if choice.kind != homepageKindSearch || choice.query != "windows 10" {
t.Errorf("got %+v, want search query \"windows 10\"", choice)
}
}
func TestParseHomepageInput_emptyInput(t *testing.T) {
_, err := parseHomepageInput(" ", testFeatured(), testEvalShortlist())
if err == nil {
t.Fatal("expected error for empty input")
}
}
// captureHomepage runs showHomepage with stdin/stderr redirected to pipes so
// the rendered output and the parsed choice can both be inspected without a
// real terminal.
func captureHomepage(t *testing.T, stdin string, latestVersion string) (homepageChoice, string) {
t.Helper()
oldStdin, oldStderr := os.Stdin, os.Stderr
defer func() { os.Stdin, os.Stderr = oldStdin, oldStderr }()
inR, inW, err := os.Pipe()
if err != nil {
t.Fatal(err)
}
os.Stdin = inR
inW.WriteString(stdin)
inW.Close()
outR, outW, err := os.Pipe()
if err != nil {
t.Fatal(err)
}
os.Stderr = outW
choice, hpErr := showHomepage(latestVersion)
outW.Close()
var buf bytes.Buffer
io.Copy(&buf, outR)
if hpErr != nil {
t.Fatalf("unexpected error: %v", hpErr)
}
return choice, buf.String()
}
func TestShowHomepage_rendersFeaturedAndEval(t *testing.T) {
choice, output := captureHomepage(t, "1\n", "")
if choice.kind != homepageKindProduct || choice.productID != "3262" {
t.Errorf("got %+v, want product 3262", choice)
}
for _, want := range []string{
"1. Windows 11 25H2 (26200.6584)",
"2. Windows 10 22H2 v1 (19045.2965)",
"6. Windows Server 2025",
"7. Windows 11 Enterprise",
`Commands: --list (full catalog) · --help`,
`Choice [1-7], search by name, or "list":`,
} {
if !strings.Contains(output, want) {
t.Errorf("output missing %q, got:\n%s", want, output)
}
}
}
func TestShowHomepage_updateAvailableFooter(t *testing.T) {
oldVersion := Version
Version = "0.3.3"
defer func() { Version = oldVersion }()
_, output := captureHomepage(t, "1\n", "0.3.4")
if !strings.Contains(output, "Version 0.3.3 (Update Available 0.3.4)") {
t.Errorf("output missing update-available footer, got:\n%s", output)
}
}
func TestShowHomepage_noUpdateFooter(t *testing.T) {
oldVersion := Version
Version = "0.3.4"
defer func() { Version = oldVersion }()
_, output := captureHomepage(t, "1\n", "0.3.4")
if strings.Contains(output, "Update Available") {
t.Errorf("footer should not mention an update when already current, got:\n%s", output)
}
if !strings.Contains(output, "Version 0.3.4 - a TechLatest Open-source Contribution") {
t.Errorf("output missing plain version footer, got:\n%s", output)
}
}