Files
larksuite-cli/internal/qualitygate/rules/output_test.go
2026-06-17 16:29:33 +08:00

135 lines
4.5 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package rules
import (
"encoding/json"
"strings"
"testing"
"github.com/larksuite/cli/internal/qualitygate/manifest"
"github.com/larksuite/cli/internal/qualitygate/report"
)
func TestCheckDefaultOutputWarnsListWithoutLimit(t *testing.T) {
m := manifest.Manifest{Commands: []manifest.Command{{
Path: "im messages list",
Runnable: true,
}}}
diags, facts := CheckDefaultOutput(m)
if len(diags) == 0 || diags[0].Rule != "default_output" || diags[0].Action != report.ActionWarning {
t.Fatalf("got diagnostics %#v", diags)
}
if diags[0].CommandPath != "im messages list" || diags[0].SubjectType != "output" {
t.Fatalf("default output diagnostic subject = %#v", diags[0])
}
if len(facts) != 1 || !facts[0].IsList || facts[0].HasDefaultLimit {
t.Fatalf("got facts %#v", facts)
}
}
func TestCheckDefaultOutputDoesNotEmitEstimatedByteFacts(t *testing.T) {
m := manifest.Manifest{Commands: []manifest.Command{{
Path: "im messages list",
Runnable: true,
}}}
diags, facts := CheckDefaultOutput(m)
for _, diag := range diags {
if diag.Rule == "default_output_budget" {
t.Fatalf("default_output_budget must not rely on estimated bytes: %#v", diags)
}
}
data, err := json.Marshal(facts[0])
if err != nil {
t.Fatalf("marshal output fact: %v", err)
}
if strings.Contains(string(data), "default_bytes") || strings.Contains(string(data), "sample_bytes") {
t.Fatalf("output fact must not carry estimated byte fields: %s", data)
}
}
func TestCheckDefaultOutputDoesNotSpecialCaseGeneratedServiceListWithoutFields(t *testing.T) {
m := manifest.Manifest{Commands: []manifest.Command{{
Path: "mail messages list",
Runnable: true,
Source: manifest.SourceService,
Generated: true,
Flags: []manifest.Flag{{Name: "page-limit", DefValue: "10"}},
}}}
diags, _ := CheckDefaultOutput(m)
if len(diags) != 0 {
t.Fatalf("generated service commands are excluded from v1 manifest and should not have a special output reject, got %#v", diags)
}
}
func TestCheckDefaultOutputAcceptsDefaultLimit(t *testing.T) {
m := manifest.Manifest{Commands: []manifest.Command{{
Path: "im messages list",
Runnable: true,
Flags: []manifest.Flag{{Name: "page-size", DefValue: "20"}},
}}}
diags, facts := CheckDefaultOutput(m)
if len(diags) != 0 {
t.Fatalf("got diagnostics %#v", diags)
}
if len(facts) != 1 || !facts[0].HasDefaultLimit {
t.Fatalf("got facts %#v", facts)
}
}
func TestCheckDefaultOutputDoesNotTreatZeroDefaultAsLimit(t *testing.T) {
m := manifest.Manifest{Commands: []manifest.Command{{
Path: "im messages list",
Runnable: true,
Flags: []manifest.Flag{{Name: "page-limit", DefValue: "0"}},
}}}
diags, facts := CheckDefaultOutput(m)
if len(diags) == 0 || diags[0].Rule != "default_output" {
t.Fatalf("expected missing default limit warning, got %#v", diags)
}
if len(facts) != 1 || facts[0].HasDefaultLimit {
t.Fatalf("page-limit=0 should not count as bounded default limit: %#v", facts)
}
}
func TestDefaultOutputRejectsListWithoutLimitOrDecisionFields(t *testing.T) {
m := manifest.Manifest{Commands: []manifest.Command{{
Path: "im messages list",
Runnable: true,
Flags: []manifest.Flag{{Name: "fields"}},
DefaultFields: []string{"raw_payload"},
}}}
diags, facts := CheckDefaultOutput(m)
if len(diags) == 0 || diags[0].Action != report.ActionReject || diags[0].Rule != "default_output_contract" {
t.Fatalf("expected default output reject, got %#v", diags)
}
if diags[0].CommandPath != "im messages list" || diags[0].SubjectType != "output" {
t.Fatalf("default output contract diagnostic subject = %#v", diags[0])
}
if facts[0].HasDecisionField {
t.Fatalf("raw_payload should not satisfy decision field family")
}
}
func TestCheckDefaultOutputDoesNotTreatSubstringsAsDecisionFields(t *testing.T) {
m := manifest.Manifest{Commands: []manifest.Command{{
Path: "drive files list",
Runnable: true,
Flags: []manifest.Flag{{Name: "page-size", DefValue: "20"}},
DefaultFields: []string{
"width",
"filename",
"runtime",
"curl",
},
}}}
diags, facts := CheckDefaultOutput(m)
if len(diags) != 1 || diags[0].Action != report.ActionReject || diags[0].Rule != "default_output_contract" {
t.Fatalf("substring-only decision fields should reject, got %#v", diags)
}
if len(facts) != 1 || facts[0].HasDecisionField {
t.Fatalf("substring-only fields should not satisfy decision field family: %#v", facts)
}
}