package main import ( "bytes" "context" "io" "strings" "testing" commandkit "gitea.maximumdirect.net/eric/CommandKit" "gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig" "go.yaml.in/yaml/v4" ) func TestSimpleAppComparesFixturesAndKeepsDefaultCommands(t *testing.T) { app, err := newApp() if err != nil { t.Fatal(err) } var output bytes.Buffer outcome := app.Execute(context.Background(), []string{"config", "diff", "--config", "fixtures/before.yml", "--against-config", "fixtures/after.yml"}, commandkit.Streams{Out: &output, Err: io.Discard}) if outcome.Kind != commandkit.OutcomeSuccess { t.Fatalf("fixture comparison outcome = %#v", outcome) } var report yaml.Node if err := yaml.Unmarshal(output.Bytes(), &report); err != nil { t.Fatalf("comparison report is not YAML: %q: %v", output.String(), err) } changes := field(report.Content[0], "changes") greeting := field(changes, "greeting") if greeting == nil || greeting.Value != "Goodbye" { t.Fatalf("fixture comparison report = %q", output.String()) } output.Reset() outcome = app.Execute(context.Background(), []string{"config", "diff", "--config", "fixtures/before.yml", "--against-config", "fixtures/before.yml"}, commandkit.Streams{Out: &output, Err: io.Discard}) if outcome.Kind != commandkit.OutcomeSuccess { t.Fatalf("equal fixture comparison outcome = %#v", outcome) } if reportNode, err := decodeReport(output.Bytes()); err != nil || len(field(reportNode, "additions").Content) != 0 || len(field(reportNode, "changes").Content) != 0 || len(field(reportNode, "deletions").Content) != 0 { t.Fatalf("equal fixture report = %q, decode error %v", output.String(), err) } output.Reset() outcome = app.Execute(context.Background(), []string{"config", "show"}, commandkit.Streams{Out: &output, Err: io.Discard}) if outcome.Kind != commandkit.OutcomeSuccess || output.String() != "greeting: Hello\nschema:\n version: 2\n" { t.Fatalf("default show outcome/output = %#v / %q", outcome, output.String()) } output.Reset() outcome = app.Execute(context.Background(), []string{"greet"}, commandkit.Streams{Out: &output, Err: io.Discard}) if outcome.Kind != commandkit.OutcomeSuccess || len(output.String()) == 0 || output.String()[:5] != "Hello" { t.Fatalf("default greeting outcome/output = %#v / %q", outcome, output.String()) } } func TestSimpleLoaderDoesNotReplaceExplicitEmptyConfiguration(t *testing.T) { _, err := loadAppConfiguration(context.Background(), ckconfig.Selection{Config: commandkit.Supplied[string]{Set: true}}) if err == nil { t.Fatal("explicit empty configuration fell back to the default source") } } func TestSimpleConfigurationReportingModes(t *testing.T) { for _, test := range []struct { name string args []string wantOutput string wantDiagnostic string quiet bool }{ { name: "ordinary output hides provider warning", args: []string{"config", "show", "--config", "fixtures/before.yml"}, wantOutput: "greeting: Hello\nschema:\n version: 1\n", }, { name: "quiet suppresses configuration report", args: []string{"config", "show", "--config", "fixtures/before.yml", "--quiet"}, quiet: true, }, { name: "verbose shows ConfigKit warning", args: []string{"config", "show", "--config", "fixtures/before.yml", "--verbose"}, wantOutput: "greeting: Hello\nschema:\n version: 1\n", wantDiagnostic: "schema version 1 is supported", }, } { t.Run(test.name, func(t *testing.T) { outcome, output, diagnostics := executeSimple(t, test.args...) if outcome.Kind != commandkit.OutcomeSuccess || outcome.Cause != nil { t.Fatalf("outcome = %#v", outcome) } if output != test.wantOutput { t.Errorf("output = %q, want %q", output, test.wantOutput) } if test.wantDiagnostic != "" && !strings.Contains(diagnostics, test.wantDiagnostic) { t.Errorf("diagnostics = %q, want provider warning %q", diagnostics, test.wantDiagnostic) } if test.wantDiagnostic == "" && diagnostics != "" { t.Errorf("diagnostics = %q, want no warning outside verbose mode", diagnostics) } if strings.Contains(diagnostics, "ERROR:") { t.Errorf("diagnostics %q unexpectedly contain a terminal failure", diagnostics) } if test.quiet && (outcome.Presentation.Output.State != commandkit.DeliverySuppressed || outcome.Presentation.Diagnostics.State != commandkit.DeliverySuppressed) { t.Errorf("quiet presentation = %#v, want report and provider warning suppressed", outcome.Presentation) } }) } } func TestSimpleCustomCommandUsesSharedReportingFlags(t *testing.T) { outcome, output, diagnostics := executeSimple(t, "greet", "--quiet") if outcome.Kind != commandkit.OutcomeSuccess || output != "" || diagnostics != "" { t.Fatalf("quiet greet outcome/output/diagnostics = %#v / %q / %q", outcome, output, diagnostics) } } func executeSimple(t *testing.T, args ...string) (commandkit.Outcome, string, string) { t.Helper() app, err := newApp() if err != nil { t.Fatal(err) } var output, diagnostics bytes.Buffer outcome := app.Execute(context.Background(), args, commandkit.Streams{Out: &output, Err: &diagnostics}) return outcome, output.String(), diagnostics.String() } func field(mapping *yaml.Node, name string) *yaml.Node { if mapping == nil || mapping.Kind != yaml.MappingNode { return nil } for index := 0; index+1 < len(mapping.Content); index += 2 { if mapping.Content[index].Value == name { return mapping.Content[index+1] } } return nil } func decodeReport(data []byte) (*yaml.Node, error) { var document yaml.Node if err := yaml.Unmarshal(data, &document); err != nil { return nil, err } return document.Content[0], nil }