Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  behavior_baseline_test.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

package main

import (
 "context"
 "encoding/json"
 "fmt"
 "os"
 "path/filepath"
 "runtime"
 "strings"
 "testing"
)

type behaviorReplacePair struct {
 From string `json:"from"`
 To   string `json:"to"`
}

type behaviorRule struct {
 Method       string                `json:"method"`
 MatchAll     []string              `json:"match_all"`
 ResponseFile string                `json:"response_file,omitempty"`
 ReplacePairs []behaviorReplacePair `json:"replace_pairs,omitempty"`
}

type behaviorFixture struct {
 Name                      string         `json:"name"`
 Mode                      string         `json:"mode"`
 RelPath                   string         `json:"rel_path"`
 SourceFile                string         `json:"source_file"`
 ExpectedFile              string         `json:"expected_file,omitempty"`
 ExpectedErrorContains     string         `json:"expected_error_contains,omitempty"`
 ExpectedOutputContains    []string       `json:"expected_output_contains,omitempty"`
 ExpectedOutputNotContains []string       `json:"expected_output_not_contains,omitempty"`
 Rules                     []behaviorRule `json:"rules"`
}

type behaviorFixtureTranslator struct {
 t     *testing.T
 dir   string
 rules []behaviorRule
}

func (tr *behaviorFixtureTranslator) Translate(_ context.Context, text, _, _ string) (string, error) {
 return tr.run("masked", text), nil
}

func (tr *behaviorFixtureTranslator) TranslateRaw(_ context.Context, text, _, _ string) (string, error) {
 return tr.run("raw", text), nil
}

func (tr *behaviorFixtureTranslator) Close() {}

func (tr *behaviorFixtureTranslator) run(method, text string) string {
 tr.t.Helper()
 for _, rule := range tr.rules {
  if rule.Method != method {
   continue
  }
  if !matchesAll(text, rule.MatchAll) {
   continue
  }
  switch {
  case rule.ResponseFile != "":
   return readFixtureTextInDir(tr.t, tr.dir, rule.ResponseFile)
  case len(rule.ReplacePairs) > 0:
   out := text
   for _, pair := range rule.ReplacePairs {
    out = strings.ReplaceAll(out, pair.From, pair.To)
   }
   return out
  default:
   return text
  }
 }
 return text
}

func matchesAll(text string, fragments []string) bool {
 for _, fragment := range fragments {
  if !strings.Contains(text, fragment) {
   return false
  }
 }
 return true
}

func TestDocsI18nBehaviorBaselines(t *testing.T) {
 t.Parallel()

 root := filepath.Join("testdata", "behavior")
 entries, err := os.ReadDir(root)
 if err != nil {
  t.Fatalf("ReadDir(%q): %v", root, err)
 }

 found := false
 for _, entry := range entries {
  if !entry.IsDir() {
   continue
  }
  found = true
  dir := filepath.Join(root, entry.Name())
  fixture := loadBehaviorFixture(t, dir)
  name := fixture.Name
  if name == "" {
   name = entry.Name()
  }
  t.Run(name, func(t *testing.T) {
   t.Parallel()
   runBehaviorFixture(t, dir, fixture)
  })
 }

 if !found {
  t.Fatalf("no behavior fixtures found under %s", root)
 }
}

func loadBehaviorFixture(t *testing.T, dir string) behaviorFixture {
 t.Helper()
 data, err := os.ReadFile(filepath.Join(dir, "case.json"))
 if err != nil {
  t.Fatalf("ReadFile(case.json): %v", err)
 }
 var fixture behaviorFixture
 if err := json.Unmarshal(data, &fixture); err != nil {
  t.Fatalf("Unmarshal(case.json): %v", err)
 }
 return fixture
}

func runBehaviorFixture(t *testing.T, dir string, fixture behaviorFixture) {
 t.Helper()

 source := readFixtureTextInDir(t, dir, fixture.SourceFile)
 translator := &behaviorFixtureTranslator{
  t:     t,
  dir:   dir,
  rules: fixture.Rules,
 }

 var (
  got string
  err error
 )

 switch fixture.Mode {
 case "doc_body_chunked":
  got, err = translateDocBodyChunked(context.Background(), translator, fixture.RelPath, source, "en", "zh-CN")
 case "frontmatter_scalar":
  got, err = translateSnippet(
   context.Background(),
   translator,
   &TranslationMemory{entries: map[string]TMEntry{}},
   fixture.RelPath+":frontmatter:title",
   source,
   "en",
   "zh-CN",
  )
 default:
  t.Fatalf("unsupported fixture mode %q", fixture.Mode)
 }

 if fixture.ExpectedErrorContains != "" {
  if err == nil {
   t.Fatalf("expected error containing %q, got nil", fixture.ExpectedErrorContains)
  }
  if !strings.Contains(err.Error(), fixture.ExpectedErrorContains) {
   t.Fatalf("expected error containing %q, got %v", fixture.ExpectedErrorContains, err)
  }
  return
 }
 if err != nil {
  t.Fatalf("unexpected error: %v", err)
 }

 if fixture.ExpectedFile != "" {
  want := readFixtureTextInDir(t, dir, fixture.ExpectedFile)
  if normalizeBehaviorText(got) != normalizeBehaviorText(want) {
   t.Fatalf("unexpected output\nwant:\n%s\n\ngot:\n%s", want, got)
  }
 }

 for _, fragment := range fixture.ExpectedOutputContains {
  if !strings.Contains(got, fragment) {
   t.Fatalf("expected output to contain %q\noutput:\n%s", fragment, got)
  }
 }
 for _, fragment := range fixture.ExpectedOutputNotContains {
  if strings.Contains(got, fragment) {
   t.Fatalf("expected output to exclude %q\noutput:\n%s", fragment, got)
  }
 }
}

func readFixtureText(t *testing.T, path string) string {
 t.Helper()
 data, err := os.ReadFile(path)
 if err != nil {
  t.Fatalf("ReadFile(%q): %v", path, err)
 }
 return string(data)
}

func readFixtureTextInDir(t *testing.T, dir, name string) string {
 t.Helper()
 resolvedPath, err := resolveFixturePathInDir(dir, name)
 if err != nil {
  t.Fatal(err)
 }
 return readFixtureText(t, resolvedPath)
}

func resolveFixturePathInDir(dir, name string) (string, error) {
 if filepath.IsAbs(name) {
  return "", fmt.Errorf("absolute fixture paths are not allowed: %q", name)
 }
 clean := filepath.Clean(name)
 if clean == ".." || strings.HasPrefix(clean, ".."+string(filepath.Separator)) {
  return "", fmt.Errorf("fixture path escapes dir: %q", name)
 }

 joined := filepath.Join(dir, clean)
 resolvedDir, err := filepath.EvalSymlinks(dir)
 if err != nil {
  return "", fmt.Errorf("EvalSymlinks(%q): %w", dir, err)
 }
 resolvedPath, err := filepath.EvalSymlinks(joined)
 if err != nil {
  return "", fmt.Errorf("EvalSymlinks(%q): %w", joined, err)
 }

 rel, err := filepath.Rel(resolvedDir, resolvedPath)
 if err != nil {
  return "", fmt.Errorf("Rel(%q, %q): %w", resolvedDir, resolvedPath, err)
 }
 if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
  return "", fmt.Errorf("fixture path resolves outside dir: %q", name)
 }

 return resolvedPath, nil
}

func normalizeBehaviorText(value string) string {
 return strings.TrimSpace(strings.ReplaceAll(value, "\r\n", "\n"))
}

func TestResolveFixturePathInDirRejectsSymlinkEscape(t *testing.T) {
 t.Parallel()

 root := t.TempDir()
 fixtureDir := filepath.Join(root, "fixture")
 if err := os.MkdirAll(fixtureDir, 0o755); err != nil {
  t.Fatalf("MkdirAll(%q): %v", fixtureDir, err)
 }

 outsidePath := filepath.Join(root, "outside.txt")
 if err := os.WriteFile(outsidePath, []byte("outside\n"), 0o644); err != nil {
  t.Fatalf("WriteFile(%q): %v", outsidePath, err)
 }

 linkPath := filepath.Join(fixtureDir, "outside-link.txt")
 if err := os.Symlink(outsidePath, linkPath); err != nil {
  if os.IsPermission(err) || runtime.GOOS == "windows" {
   t.Skipf("symlink creation unavailable in this test environment: %v", err)
  }
  t.Fatalf("Symlink(%q, %q): %v", outsidePath, linkPath, err)
 }

 _, err := resolveFixturePathInDir(fixtureDir, "outside-link.txt")
 if err == nil {
  t.Fatal("expected symlink escape to fail")
 }
 if !strings.Contains(err.Error(), "resolves outside dir") {
  t.Fatalf("expected outside-dir error, got %v", err)
 }
}

[Dauer der Verarbeitung: 0.26 Sekunden, vorverarbeitet 2026-04-27]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge