diff --git a/CHANGELOG.md b/CHANGELOG.md
index 435c72a9..d9a48603 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,24 @@ because it turns other people's test suites red.
### Added
+- **The website in twenty-two languages.** Beside English and Polish it now
+ reads in Simplified and Traditional Chinese, Japanese, German, French,
+ Spanish, Brazilian Portuguese, Italian, Indonesian, Russian, Turkish, Czech,
+ Vietnamese, Hindi, Korean, Arabic, Romanian, Dutch, Ukrainian and Thai.
+ Every page exists in every language, with the same facts: the numbers come
+ from the program, the same as before. A menu in the header lists the
+ languages by the names they call themselves. Arabic reads from right to
+ left, and commands and code stay left to right in it. Each page tells a
+ search engine which language it is in and where its translations are, so
+ somebody searching in their own language is sent to the page in it. The
+ pages of Latin-script languages have addresses in the language
+ (`/de/dokumentation/`), the others keep the English words under the
+ language prefix (`/ja/docs/`). The window and the command line are not
+ part of this.
+- **Two guides on the website.** How to make a corrupt file for testing, with
+ the damages listed from the program itself, and how to generate test files in
+ a CI pipeline, with a GitHub Actions workflow, a GitLab job and the
+ PowerShell catch. Both are in every language of the site.
- **A Tools tab, and `tfg tool`.** Small things to do with files you already
have, in the window and on the command line with the same settings. The
first works out the checksum of a file - md5, sha1, sha256, sha512 or crc32,
@@ -76,6 +94,9 @@ because it turns other people's test suites red.
### Fixed
+- **The FAQ on the website said a deliberately broken file was not possible
+ yet.** `tfg damage` has been in the tool since 0.3.0, and the answer still
+ called it a planned feature. It now says how to make one, in every language.
- **The window no longer offers to write into a folder it cannot or should
not write into.** Started from Finder on macOS it offered `/tfg-out`,
which is read-only, so the first run ended in a refusal from the system.
diff --git a/internal/guard/edgeexample_test.go b/internal/guard/edgeexample_test.go
index 3e1e223e..d7437e8b 100644
--- a/internal/guard/edgeexample_test.go
+++ b/internal/guard/edgeexample_test.go
@@ -16,10 +16,10 @@ import (
// The three files every first page shows - one byte under a 1 MB limit, the
// limit, one byte over - are what size-boundaries actually writes.
//
-// They stand in four places a stranger reads before anything else: the social
-// card, the README, and the site's first page in both languages. All four
-// carry them as literals, and the card says outright that everything on it is
-// real. Nothing asked the program. An outside review of #148 named it, and
+// They stand in the places a stranger reads before anything else: the social
+// card, the README, and the site's first page in every language. All of them
+// carry the files as literals, and the card says outright that everything on it
+// is real. Nothing asked the program. An outside review of #148 named it, and
// asking showed it was already half untrue: the card before that one printed
// "tfg generate --preset size-boundaries --limit 1mb", which the program
// refuses, because the default spread would need a file of 0 B.
@@ -52,48 +52,64 @@ func TestTheLimitExampleIsWhatThePresetWrites(t *testing.T) {
}
root := repoRoot(t)
- places := []struct {
+ type place struct {
file string
spaced bool
outcomes map[string]string
command bool
- }{
+ }
+ places := []place{
{"web/templates/social.html", true, map[string]string{"accept": "accept", "reject": "reject"}, false},
{"README.md", false, map[string]string{"accept": "**accept**", "reject": "**reject**"}, true},
{"web/content/en/index.html", false, map[string]string{"accept": "accept", "reject": "reject"}, true},
{"web/content/pl/index.html", false, map[string]string{"accept": "przyjąć", "reject": "odrzucić"}, true},
}
- for _, place := range places {
- body, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(place.file)))
+ // Every other translation of the first page is held to the same answer. The
+ // words are asked for rather than guessed: a language whose first page shows
+ // the three files in a form nobody listed here is a page this guard cannot
+ // read, and silence about it would be the defect the guard exists for.
+ for _, l := range languagesOnDisk(t) {
+ if l.Code == "en" || l.Code == "pl" {
+ continue
+ }
+ words, ok := translatedLimitWords[l.Code]
+ if !ok {
+ t.Errorf("the first page in %s is not held to the limit example - add the words it uses for accept and reject to translatedLimitWords", l.Code)
+ continue
+ }
+ places = append(places, place{"web/content/" + l.Code + "/index.html", false, map[string]string{"accept": words[0], "reject": words[1]}, true})
+ }
+ for _, at := range places {
+ body, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(at.file)))
if err != nil {
- t.Fatalf("reading %s: %v", place.file, err)
+ t.Fatalf("reading %s: %v", at.file, err)
}
text := string(body)
- if place.command && !strings.Contains(text, command) {
+ if at.command && !strings.Contains(text, command) {
t.Errorf("%s no longer prints %q, so the files it shows come from a command this guard does not run",
- place.file, command)
+ at.file, command)
}
for _, f := range manifest.Files {
line := lineNaming(text, f.Name)
if line == "" {
- t.Errorf("%s does not show %s, and the command writes it", place.file, f.Name)
+ t.Errorf("%s does not show %s, and the command writes it", at.file, f.Name)
continue
}
size := strconv.FormatInt(f.Bytes, 10)
- if place.spaced {
+ if at.spaced {
size = spacedBytes(f.Bytes) + " B"
}
if !strings.Contains(line, size) {
- t.Errorf("%s shows %s without its %s:\n%s", place.file, f.Name, size, line)
+ t.Errorf("%s shows %s without its %s:\n%s", at.file, f.Name, size, line)
}
- word, ok := place.outcomes[f.Expected.Outcome]
+ word, ok := at.outcomes[f.Expected.Outcome]
if !ok {
- t.Errorf("the manifest declares %q for %s, and %s has no word for it", f.Expected.Outcome, f.Name, place.file)
+ t.Errorf("the manifest declares %q for %s, and %s has no word for it", f.Expected.Outcome, f.Name, at.file)
continue
}
if !strings.Contains(line, word) {
t.Errorf("%s shows %s without the outcome the manifest declares (%s):\n%s",
- place.file, f.Name, word, line)
+ at.file, f.Name, word, line)
}
}
}
@@ -128,3 +144,34 @@ func spacedBytes(n int64) string {
}
return b.String()
}
+
+// translatedLimitWords are the two words each translated first page uses for
+// what the manifest declares - accept first, reject second - in the form that
+// stands on the line naming a file.
+//
+// A word is not unique to a language, and a translation inflects it. Polish
+// writes the infinitive in the table and so the list says przyjąć rather than
+// przyjmie, and each entry is exactly the form the page shows. The key is the
+// language tag, the same as the directory under web/content.
+var translatedLimitWords = map[string][2]string{
+ "de": {"akzeptieren", "ablehnen"},
+ "es": {"aceptar", "rechazar"},
+ "fr": {"accepter", "refuser"},
+ "it": {"accettare", "rifiutare"},
+ "pt-BR": {"aceitar", "rejeitar"},
+ "nl": {"accepteren", "weigeren"},
+ "ro": {"accepte", "respingă"},
+ "cs": {"přijmout", "odmítnout"},
+ "id": {"menerima", "menolak"},
+ "tr": {"kabul etmeli", "reddetmeli"},
+ "vi": {"chấp nhận", "từ chối"},
+ "ru": {"принять", "отклонить"},
+ "uk": {"прийняти", "відхилити"},
+ "zh-Hans": {"接受", "拒绝"},
+ "zh-Hant": {"接受", "拒絕"},
+ "ja": {"受け入れる", "拒否する"},
+ "ko": {"수락", "거부"},
+ "ar": {"قبول", "رفض"},
+ "hi": {"मंज़ूर करना", "अस्वीकार करना"},
+ "th": {"ยอมรับ", "ปฏิเสธ"},
+}
diff --git a/internal/guard/site_test.go b/internal/guard/site_test.go
index ed5b126f..e474cc8a 100644
--- a/internal/guard/site_test.go
+++ b/internal/guard/site_test.go
@@ -16,6 +16,7 @@ import (
"testing"
"github.com/donislawdev/TestingFilesGenerator/internal/cli"
+ "github.com/donislawdev/TestingFilesGenerator/internal/damage"
"github.com/donislawdev/TestingFilesGenerator/internal/format"
_ "github.com/donislawdev/TestingFilesGenerator/internal/format/all"
"github.com/donislawdev/TestingFilesGenerator/internal/site"
@@ -121,6 +122,7 @@ func factsFromTheProgram(t *testing.T) site.Facts {
Version: version.Version,
Formats: formats,
ExitCodes: exitCodesInOrder(),
+ Damages: damagesTheProgramHas(),
Presets: presetFactsFromTheProgram(t),
Commands: commandsTheToolPrints(t),
Downloads: declaredDownloads(),
@@ -141,6 +143,17 @@ func factsFromTheProgram(t *testing.T) site.Facts {
}
}
+// damagesTheProgramHas is every damage in the order tfg damage lists it, with
+// the smallest file it takes at its defaults - the number that command prints,
+// from the same call.
+func damagesTheProgramHas() []site.Damage {
+ out := make([]site.Damage, 0, len(damage.All()))
+ for _, d := range damage.All() {
+ out = append(out, site.Damage{ID: d.ID, Smallest: d.Floor(d.Defaults()), Settings: d.ParameterNames()})
+ }
+ return out
+}
+
// languagesOnDisk reads every language description under web/content.
func languagesOnDisk(t *testing.T) []site.Language {
t.Helper()
@@ -486,47 +499,6 @@ func TestEveryPageExistsInEveryLanguage(t *testing.T) {
}
}
-// TestThePolishTextStaysOnThePolishPages holds the boundary the owner set when
-// the site was allowed into this repository on 2026-08-26.
-//
-// D9 says text in the repository is English, and the criterion is the place
-// rather than the reader. The site extends that rule to a second language and
-// the extension is only as good as its border - so the border is machine
-// checked here rather than remembered. Anything outside a pl directory that
-// carries a character above ASCII is either a translation that leaked or an
-// English page somebody typed a curly quote into, and both are defects.
-func TestThePolishTextStaysOnThePolishPages(t *testing.T) {
- root := webRoot(t)
- text := map[string]bool{".html": true, ".json": true, ".css": true, ".xml": true, ".txt": true}
- err := filepath.WalkDir(root, func(p string, d os.DirEntry, err error) error {
- if err != nil || d.IsDir() || !text[strings.ToLower(filepath.Ext(p))] {
- return err
- }
- rel, relErr := filepath.Rel(root, p)
- if relErr != nil {
- return relErr
- }
- slashed := filepath.ToSlash(rel)
- polish := strings.Contains(slashed, "/pl/") || strings.HasPrefix(slashed, "pl/")
- b, readErr := os.ReadFile(p)
- if readErr != nil {
- return readErr
- }
- for n, line := range strings.Split(string(b), "\n") {
- for col, r := range line {
- if r > 127 && !polish {
- t.Errorf("web/%s:%d:%d holds %q - only the Polish pages may carry it", slashed, n+1, col+1, r)
- return nil
- }
- }
- }
- return nil
- })
- if err != nil {
- t.Fatalf("walking the site: %v", err)
- }
-}
-
// TestTheSiteFollowsThePunctuationRule applies rule 13 to the site.
//
// Fenced samples are left alone, the same way the README guard leaves licence
diff --git a/internal/guard/sitelanguages_test.go b/internal/guard/sitelanguages_test.go
new file mode 100644
index 00000000..4307685f
--- /dev/null
+++ b/internal/guard/sitelanguages_test.go
@@ -0,0 +1,249 @@
+package guard
+
+import (
+ "os"
+ "path/filepath"
+ "regexp"
+ "slices"
+ "strings"
+ "testing"
+
+ "github.com/donislawdev/TestingFilesGenerator/internal/damage"
+ "github.com/donislawdev/TestingFilesGenerator/internal/site"
+)
+
+// TestTranslatedTextStaysOnTheTranslatedPages holds the boundary the owner set
+// when the site was allowed into this repository on 2026-08-26.
+//
+// D9 says text in the repository is English, and the criterion is the place
+// rather than the reader. The site extends that rule to the languages it is
+// translated into and the extension is only as good as its border - so the
+// border is machine checked here rather than remembered. A character above
+// ASCII may stand in the text of a language that is not the root one, and in
+// the pages rendered from it. Anywhere else it is either a translation that
+// leaked or an English page somebody typed a curly quote into, and both are
+// defects.
+//
+// One thing from a translation is allowed to appear on every page, and it is
+// the list of languages in the header. A visitor reading English has to be
+// shown the way to Deutsch and to the Japanese, in the names those languages
+// call themselves - a menu that said "German" would not be found by the person
+// it is for. So the list is cut out of a page before the page is read, and
+// nothing else is: a language name anywhere else in English text is a leak.
+//
+// This was a check on Polish alone until 2026-10-01, when the site was
+// translated into a further twenty languages at the owner's request. The
+// border moved with them: it is read from the language files, so a twenty
+// third language needs no edit here, and a language that is not listed has no
+// directory the border would let its text into.
+func TestTranslatedTextStaysOnTheTranslatedPages(t *testing.T) {
+ root := webRoot(t)
+ languageMenu := regexp.MustCompile(`(?s)
.*?
`)
+ // Relative to the web directory, with a trailing slash so that content/de
+ // does not let content/deutsch in.
+ var homes []string
+ for _, l := range languagesOnDisk(t) {
+ if l.Dir == "" {
+ continue
+ }
+ homes = append(homes, "content/"+l.Code+"/", "public/"+l.Dir+"/")
+ }
+ text := map[string]bool{".html": true, ".json": true, ".css": true, ".xml": true, ".txt": true}
+ err := filepath.WalkDir(root, func(p string, d os.DirEntry, err error) error {
+ if err != nil || d.IsDir() || !text[strings.ToLower(filepath.Ext(p))] {
+ return err
+ }
+ rel, relErr := filepath.Rel(root, p)
+ if relErr != nil {
+ return relErr
+ }
+ slashed := filepath.ToSlash(rel)
+ translated := slices.ContainsFunc(homes, func(home string) bool { return strings.HasPrefix(slashed, home) })
+ b, readErr := os.ReadFile(p)
+ if readErr != nil {
+ return readErr
+ }
+ page := string(b)
+ if !translated {
+ page = languageMenu.ReplaceAllString(page, "")
+ }
+ for n, line := range strings.Split(page, "\n") {
+ for col, r := range line {
+ if r > 127 && !translated {
+ t.Errorf("web/%s:%d:%d holds %q - only the pages of a translation may carry it", slashed, n+1, col+1, r)
+ return nil
+ }
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ t.Fatalf("walking the site: %v", err)
+ }
+}
+
+// TestEveryPageSaysWhichLanguageItIsAndWhereItsTranslationsAre holds what a
+// search engine needs to serve the right language to the right reader.
+//
+// The site is generated, so each page is consistent with the language file it
+// came from. What nothing else asks is whether those files, taken together,
+// say one coherent thing to a crawler. Every page has to name its own language
+// and carry the full set of alternates, its own included, plus x-default - and
+// the page an alternate points at has to point back. A pair that does not
+// reciprocate is dropped by Google, and the page it was meant to connect goes
+// on competing with its own translation. The same page may not reuse the title
+// or the description of a sibling in its language either: two pages with one
+// title are one result to a search engine, and a snippet it writes itself.
+func TestEveryPageSaysWhichLanguageItIsAndWhereItsTranslationsAre(t *testing.T) {
+ s := siteUnderTest(t)
+ rendered, err := s.Render()
+ if err != nil {
+ t.Fatalf("rendering the site: %v", err)
+ }
+ var root site.Language
+ byDir := map[string]site.Language{}
+ for _, l := range s.Languages {
+ if l.Dir == "" {
+ root = l
+ continue
+ }
+ byDir[l.Dir] = l
+ }
+ languageOf := func(file string) site.Language {
+ first, _, _ := strings.Cut(file, "/")
+ if l, ok := byDir[first]; ok {
+ return l
+ }
+ return root
+ }
+ fileOf := func(address string) string {
+ path := strings.Trim(strings.TrimPrefix(address, siteOrigin), "/")
+ if path == "" {
+ return "index.html"
+ }
+ return path + "/index.html"
+ }
+
+ htmlTag := regexp.MustCompile(``)
+ alternate := regexp.MustCompile(``)
+ canonical := regexp.MustCompile(``)
+ locale := regexp.MustCompile(``)
+ title := regexp.MustCompile(`([^<]*)`)
+ description := regexp.MustCompile(``)
+
+ pages := map[string]map[string]string{}
+ canonicals := map[string]string{}
+ seenTitle, seenDescription := map[string]string{}, map[string]string{}
+ for file, body := range rendered {
+ if filepath.Base(file) != "index.html" {
+ continue
+ }
+ text := string(body)
+ lang := languageOf(file)
+ tag := htmlTag.FindStringSubmatch(text)
+ if tag == nil || tag[1] != lang.Code || (tag[2] != "") != lang.RTL {
+ t.Errorf("%s should open as lang=%q with dir=rtl %v and says %q", file, lang.Code, lang.RTL, tag)
+ }
+ if m := locale.FindStringSubmatch(text); m == nil || m[1] != lang.Locale {
+ t.Errorf("%s should carry og:locale %q and says %q", file, lang.Locale, m)
+ }
+ if m := canonical.FindStringSubmatch(text); m == nil {
+ t.Errorf("%s has no canonical address", file)
+ } else {
+ canonicals[file] = m[1]
+ }
+ found := map[string]string{}
+ for _, m := range alternate.FindAllStringSubmatch(text, -1) {
+ found[m[1]] = m[2]
+ }
+ pages[file] = found
+
+ for _, l := range s.Languages {
+ if _, ok := found[l.Code]; !ok {
+ t.Errorf("%s does not name its %s translation, so a search engine is not told it exists", file, l.Code)
+ }
+ }
+ if _, ok := found["x-default"]; !ok || len(found) != len(s.Languages)+1 {
+ t.Errorf("%s names %d alternates, and the languages are %d plus x-default", file, len(found), len(s.Languages))
+ }
+ for _, field := range []struct {
+ name string
+ pattern *regexp.Regexp
+ seen map[string]string
+ }{{"title", title, seenTitle}, {"description", description, seenDescription}} {
+ m := field.pattern.FindStringSubmatch(text)
+ if m == nil {
+ t.Errorf("%s has no %s", file, field.name)
+ continue
+ }
+ key := lang.Code + "\x00" + m[1]
+ if other, dup := field.seen[key]; dup {
+ t.Errorf("%s and %s have one %s in %s: %q", file, other, field.name, lang.Code, m[1])
+ }
+ field.seen[key] = file
+ }
+ }
+ for file, found := range pages {
+ lang := languageOf(file)
+ if found[lang.Code] != canonicals[file] {
+ t.Errorf("%s names %q as its own %s address and its canonical is %q", file, found[lang.Code], lang.Code, canonicals[file])
+ }
+ for code, address := range found {
+ if code == "x-default" {
+ continue
+ }
+ other, ok := pages[fileOf(address)]
+ if !ok {
+ t.Errorf("%s names %s as its %s translation and nothing is published there", file, address, code)
+ continue
+ }
+ if back := other[lang.Code]; back != canonicals[file] {
+ t.Errorf("%s names %s as its %s translation, and that page points back to %q instead of %q", file, address, code, back, canonicals[file])
+ }
+ }
+ }
+}
+
+// TestEveryLanguageDescribesEveryDamage holds the page about corrupt files to
+// what the program can break a file with.
+//
+// The table of damages is made from the registry, so a damage added there is a
+// row on every page - and a row needs a sentence in every language, or the page
+// would show a blank where the explanation goes. Read the other way as well: a
+// sentence about a damage the program no longer has is a description of
+// something that cannot be asked for. In English the sentence is the one the
+// program prints under the name, word for word, because those are one sentence
+// in two places and nothing else compares them.
+func TestEveryLanguageDescribesEveryDamage(t *testing.T) {
+ facts := factsFromTheProgram(t)
+ if len(facts.Damages) == 0 {
+ t.Fatal("the program lists no damage, so this guard would pass against any language file")
+ }
+ for _, lang := range languagesOnDisk(t) {
+ for _, d := range facts.Damages {
+ said, ok := lang.Damages[d.ID]
+ if !ok {
+ t.Errorf("the damage %q has no sentence in %s, so its row would be blank", d.ID, lang.Code)
+ continue
+ }
+ if lang.Code == "en" && said != damageDetail(t, d.ID) {
+ t.Errorf("tfg damage describes %q as %q and the English page says %q", d.ID, damageDetail(t, d.ID), said)
+ }
+ }
+ for id := range lang.Damages {
+ if !slices.ContainsFunc(facts.Damages, func(d site.Damage) bool { return d.ID == id }) {
+ t.Errorf("%s describes a damage %q that the program does not have", lang.Code, id)
+ }
+ }
+ }
+}
+
+// damageDetail is the sentence the program prints under one damage.
+func damageDetail(t *testing.T, id string) string {
+ t.Helper()
+ d, err := damage.Get(id)
+ if err != nil {
+ t.Fatalf("the program has no damage %q: %v", id, err)
+ }
+ return d.Detail
+}
diff --git a/internal/site/languages.go b/internal/site/languages.go
new file mode 100644
index 00000000..3be9efe2
--- /dev/null
+++ b/internal/site/languages.go
@@ -0,0 +1,100 @@
+// This file holds what a language has to look like before anything is
+// rendered from it.
+//
+// A language file is written by hand, and the values in it end up in places
+// nobody reads twice: the lang of a page, the hreflang of its alternates, the
+// og:locale of a shared link, the address of every page and the line of the
+// sitemap. A typo in any of them does not break a page. It makes a search
+// engine quietly ignore one - an hreflang it cannot parse is dropped, and so
+// is the page it was meant to connect. So the values are checked here, once,
+// and the render stops and names the language instead.
+
+package site
+
+import (
+ "fmt"
+ "regexp"
+)
+
+var (
+ // languageTag is a BCP 47 tag of the shapes this site uses: a language, an
+ // optional script and an optional region, as in de, zh-Hans and pt-BR.
+ languageTag = regexp.MustCompile(`^[a-z]{2,3}(-[A-Z][a-z]{3})?(-[A-Z]{2})?$`)
+
+ // openGraphLocale is language and region joined by an underscore, which is
+ // the only form the Open Graph protocol defines.
+ openGraphLocale = regexp.MustCompile(`^[a-z]{2,3}_[A-Z]{2}$`)
+)
+
+// checkLanguages refuses a set of languages that would put a wrong or a
+// repeated value on a page.
+//
+// It asks about the languages as a set because most of what can go wrong is a
+// repetition: two languages under one prefix write their pages over each other,
+// and two with one tag give a page two alternates that disagree.
+func checkLanguages(langs []Language) error {
+ roots := 0
+ claims := claimed{}
+ for _, l := range langs {
+ if err := checkLanguage(l); err != nil {
+ return err
+ }
+ if l.Dir == "" {
+ roots++
+ }
+ if err := claims.add(l); err != nil {
+ return err
+ }
+ }
+ if roots != 1 {
+ return fmt.Errorf("%d languages are served at the root and exactly one has to be, because x-default points at it", roots)
+ }
+ return nil
+}
+
+// claimed remembers which language holds each value that has to be unique.
+type claimed map[string]string
+
+// add records the values of one language, or says which earlier language
+// already holds one of them.
+func (c claimed) add(l Language) error {
+ // In a fixed order, so the same mistake always reads the same.
+ for _, v := range [][2]string{{"code", l.Code}, {"locale", l.Locale}, {"directory", l.Dir}} {
+ if v[0] == "directory" && v[1] == "" {
+ continue
+ }
+ key := v[0] + " " + v[1]
+ if other, taken := c[key]; taken {
+ return fmt.Errorf("the %s %q is used by both %s and %s", v[0], v[1], other, l.Code)
+ }
+ c[key] = l.Code
+ }
+ return nil
+}
+
+// checkLanguage asks the questions that need one language only.
+func checkLanguage(l Language) error {
+ if !languageTag.MatchString(l.Code) {
+ return fmt.Errorf("the language %q has a code that is not a BCP 47 tag such as de, zh-Hans or pt-BR", l.Code)
+ }
+ if !openGraphLocale.MatchString(l.Locale) {
+ return fmt.Errorf("the %s language has the locale %q, and Open Graph wants language and region with an underscore, as in de_DE", l.Code, l.Locale)
+ }
+ if l.Name == "" {
+ return fmt.Errorf("the %s language has no name, so the link that leads to it would be blank", l.Code)
+ }
+ if l.Dir != "" && !addressable.MatchString(l.Dir) {
+ return fmt.Errorf("the %s language is served under %q, which cannot be part of an address - lower case letters, digits and single dashes can", l.Code, l.Dir)
+ }
+ seen := map[string]string{}
+ for _, p := range l.Pages {
+ if p.Slug != "" && !addressable.MatchString(p.Slug) {
+ return fmt.Errorf("the %s page %q has the slug %q, which cannot be part of an address - lower case letters, digits and single dashes can", l.Code, p.Key, p.Slug)
+ }
+ if other, taken := seen[p.Slug]; taken {
+ return fmt.Errorf("the %s pages %q and %q share the address %q, so one would be written over the other", l.Code, other, p.Key, p.Slug)
+ }
+ seen[p.Slug] = p.Key
+ }
+ return nil
+}
diff --git a/internal/site/render.go b/internal/site/render.go
index c6262919..0c56b53d 100644
--- a/internal/site/render.go
+++ b/internal/site/render.go
@@ -51,6 +51,9 @@ func (s Site) Render() (map[string][]byte, error) {
if len(s.Languages) == 0 {
return nil, fmt.Errorf("a site with no languages has no pages to render")
}
+ if err := checkLanguages(s.Languages); err != nil {
+ return nil, err
+ }
out := map[string][]byte{}
// Every language is filled in with the facts before anything is rendered,
@@ -183,7 +186,7 @@ func (s Site) viewFor(lang Language, page Page) (view, error) {
}
v.Alternates = append(v.Alternates, Alternate{Lang: other.Code, URL: s.Origin() + pageURL(other, mate)})
if other.Code != lang.Code {
- v.Switches = append(v.Switches, Switch{Name: other.Name, URL: pageURL(other, mate), Code: other.Code})
+ v.Switches = append(v.Switches, Switch{Name: other.Name, URL: pageURL(other, mate), Code: other.Code, Locale: other.Locale})
}
}
if root, ok := s.rootLanguage(); ok {
diff --git a/internal/site/site.go b/internal/site/site.go
index 16adab40..3aa22f91 100644
--- a/internal/site/site.go
+++ b/internal/site/site.go
@@ -110,6 +110,19 @@ type Command struct {
Summary string
}
+// Damage is one way this build can break a file on purpose, as the page about
+// corrupt files lists it.
+//
+// The identifier, the smallest file and the names of the settings come from
+// the registry. What the damage does is a sentence, and a sentence belongs to a
+// language, so it is looked up in the language file by the identifier - the
+// same split as a command and its summary.
+type Damage struct {
+ ID string
+ Smallest int64
+ Settings []string
+}
+
// Download says which architectures a system actually gets.
//
// Both lists are here because they differ, and a page that flattened them into
@@ -134,6 +147,11 @@ type Facts struct {
Presets []PresetFacts
Downloads []Download
+ // Damages is every way the program can break a file, in the order it
+ // lists them. It exists so the page about corrupt files cannot go on
+ // describing one when the program has two.
+ Damages []Damage
+
// Commands is what tfg --help prints, in the order it prints it, read out
// of that help rather than out of a list beside it. Taking it from the
// help is the point: it is the text a visitor is comparing the page
@@ -205,37 +223,53 @@ type Page struct {
Description string `json:"description"`
Nav string `json:"nav"`
- // The three below are never written in site.json. They are set on the
- // pages made from a list rather than by hand - one per preset - and say
- // which page they sit under, which content file holds their text, and
- // which item of the list they are about. A page with a parent is left out
- // of the header, and the parent is marked there while it is open.
- Parent string `json:"-"`
+ // Parent is the key of the page this one sits under. A page with a parent
+ // is left out of the header, and the parent is marked there while it is
+ // open. The pages made from a list - one per preset - get one set in
+ // code, and a page written by hand may name its own in site.json.
+ Parent string `json:"parent,omitempty"`
+
+ // The two below are never written in site.json. They are set on the
+ // pages made from a list, and say which content file holds their text and
+ // which item of the list they are about.
Template string `json:"-"`
Item string `json:"-"`
}
// Language is one whole version of the site.
//
-// Dir is the path prefix. It is empty for the language served at the root,
-// which is the one search engines are pointed at by x-default.
+// Code is the BCP 47 tag, and it is three things at once: the lang of every
+// page, the hreflang other pages name it by, and the directory under
+// web/content that holds its text. Locale is the same language the way Open
+// Graph spells it, language and region with an underscore - sharing a link in
+// German is og:locale de_DE, and a bare "de" is a value the specification does
+// not define. Dir is the path prefix, which is a different thing again: lower
+// case, so zh-Hans is served under /zh-hans/.
//
-// Endings, Terms, Presets, Commands and Outcomes are the places where a word
-// has to exist for every value the program can produce, and a missing one is
-// an error rather than a gap left in English. Endings is keyed by the exit code
-// written out in decimal, Terms by the kind, unit or shape exactly as the
-// registry spells it, Presets by the identifier, Commands by the name
-// tfg --help prints, and Outcomes by the reaction a manifest declares.
+// Dir is empty for the language served at the root, which is the one search
+// engines are pointed at by x-default. RTL says the language is written right
+// to left, which puts dir="rtl" on every page of it.
+//
+// Endings, Terms, Presets, Commands, Outcomes and Damages are the places where
+// a word has to exist for every value the program can produce, and a missing
+// one is an error rather than a gap left in English. Endings is keyed by the
+// exit code written out in decimal, Terms by the kind, unit or shape exactly
+// as the registry spells it, Presets by the identifier, Commands by the name
+// tfg --help prints, Outcomes by the reaction a manifest declares and Damages
+// by the identifier of the damage.
type Language struct {
Code string `json:"code"`
+ Locale string `json:"locale"`
Name string `json:"name"`
Dir string `json:"dir"`
+ RTL bool `json:"rtl,omitempty"`
Words map[string]string `json:"words"`
Endings map[string]string `json:"endings"`
Terms map[string]string `json:"terms"`
Presets map[string]PresetText `json:"presets"`
Commands map[string]string `json:"commands"`
Outcomes map[string]string `json:"outcomes"`
+ Damages map[string]string `json:"damages"`
Pages []Page `json:"pages"`
Faq []QA `json:"faq"`
}
@@ -280,9 +314,10 @@ type NavItem struct {
// Switch is the link to this page in another language.
type Switch struct {
- Name string
- URL string
- Code string
+ Name string
+ URL string
+ Code string
+ Locale string
}
// Origin is the address the site is served from, without a trailing slash.
diff --git a/internal/site/view.go b/internal/site/view.go
index d4fb75ec..e5784de6 100644
--- a/internal/site/view.go
+++ b/internal/site/view.go
@@ -70,6 +70,7 @@ func (l Language) expand(f Facts) (Language, error) {
out.Terms = everyValue(l.Terms)
out.Commands = everyValue(l.Commands)
out.Outcomes = everyValue(l.Outcomes)
+ out.Damages = everyValue(l.Damages)
if l.Presets != nil {
out.Presets = make(map[string]PresetText, len(l.Presets))
for id, text := range l.Presets {
@@ -175,6 +176,35 @@ func (v view) CommandList() ([]Command, error) {
return out, nil
}
+// DamageRow is one row of the table of damages.
+type DamageRow struct {
+ ID string
+ Effect string
+ Smallest int64
+ Settings []string
+ // None is the word for a damage that takes no settings, so a blank cell
+ // is never what says so.
+ None string
+}
+
+// DamageList is every damage the program has, with what each does in the
+// language being rendered.
+func (v view) DamageList() ([]DamageRow, error) {
+ none, err := v.Word("noSettings")
+ if err != nil {
+ return nil, err
+ }
+ out := make([]DamageRow, 0, len(v.Facts.Damages))
+ for _, d := range v.Facts.Damages {
+ effect, ok := v.Lang.Damages[d.ID]
+ if !ok {
+ return nil, fmt.Errorf("the damage %q has no sentence written in %s", d.ID, v.Lang.Code)
+ }
+ out = append(out, DamageRow{ID: d.ID, Effect: effect, Smallest: d.Smallest, Settings: d.Settings, None: none})
+ }
+ return out, nil
+}
+
// AllowedOf says what one setting accepts, in the language being rendered.
//
// The numbers come from the registry and the words from the language file. A
diff --git a/web/assets/site.css b/web/assets/site.css
index c60dcaac..6b90b60e 100644
--- a/web/assets/site.css
+++ b/web/assets/site.css
@@ -82,18 +82,18 @@ body {
.skip {
position: absolute;
- left: -9999px;
+ inset-inline-start: -9999px;
top: 0;
background: var(--accent);
color: var(--on-bright);
padding: 10px 16px;
- border-radius: 0 0 var(--radius) 0;
+ border-end-end-radius: var(--radius);
font-weight: 600;
z-index: 100;
}
.skip:focus {
- left: 0;
+ inset-inline-start: 0;
}
/* ------------------------------------------------------------------ topbar */
@@ -110,7 +110,7 @@ body {
.topbar-inner {
display: flex;
align-items: center;
- gap: 24px;
+ gap: 16px;
min-height: 62px;
flex-wrap: wrap;
}
@@ -132,15 +132,16 @@ body {
.mainnav {
display: flex;
- gap: 4px;
+ gap: 2px;
flex-wrap: wrap;
- margin-right: auto;
+ flex: 1 1 0;
+ min-width: 0;
}
.mainnav a {
color: var(--text-dim);
text-decoration: none;
- padding: 6px 10px;
+ padding: 6px 7px;
border-radius: 8px;
font-size: 15px;
}
@@ -155,25 +156,85 @@ body {
background: var(--surface-2);
}
-.langswitch {
- display: flex;
- gap: 6px;
+.langmenu {
+ position: relative;
+ margin-inline-start: auto;
}
-.langswitch a {
+.langmenu > summary {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ cursor: pointer;
+ list-style: none;
font-size: 14px;
- color: var(--muted);
- text-decoration: none;
+ color: var(--text-dim);
border: 1px solid var(--border);
- padding: 4px 10px;
+ padding: 5px 12px;
border-radius: 999px;
+ user-select: none;
+}
+
+.langmenu > summary::-webkit-details-marker {
+ display: none;
+}
+
+.langmenu > summary::after {
+ content: "";
+ width: 6px;
+ height: 6px;
+ margin-top: -3px;
+ border-inline-end: 1.5px solid currentColor;
+ border-bottom: 1.5px solid currentColor;
+ transform: rotate(45deg);
+}
+
+.langmenu[open] > summary::after {
+ margin-top: 3px;
+ transform: rotate(225deg);
}
-.langswitch a:hover {
+.langmenu > summary:hover,
+.langmenu[open] > summary {
color: var(--text);
border-color: var(--accent-dim);
}
+.langlist {
+ position: absolute;
+ inset-inline-end: 0;
+ top: calc(100% + 8px);
+ z-index: 50;
+ list-style: none;
+ margin: 0;
+ padding: 8px;
+ width: min(520px, calc(100vw - 40px));
+ max-height: 70vh;
+ overflow-y: auto;
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 2px;
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
+}
+
+.langlist a {
+ display: block;
+ padding: 7px 10px;
+ border-radius: 8px;
+ font-size: 15px;
+ line-height: 1.4;
+ color: var(--text-dim);
+ text-decoration: none;
+}
+
+.langlist a:hover {
+ color: var(--text);
+ background: var(--surface-2);
+}
+
/* ------------------------------------------------------------- typography */
main {
@@ -456,14 +517,14 @@ ul.plain li {
.ticks li {
position: relative;
- padding-left: 26px;
+ padding-inline-start: 26px;
margin-bottom: 10px;
}
.ticks li::before {
content: "";
position: absolute;
- left: 4px;
+ inset-inline-start: 4px;
top: 0.62em;
width: 8px;
height: 8px;
@@ -489,7 +550,7 @@ table.data {
table.data th,
table.data td {
- text-align: left;
+ text-align: start;
padding: 10px 14px;
border-bottom: 1px solid var(--border-soft);
vertical-align: top;
@@ -516,7 +577,7 @@ table.data tbody tr:hover td {
}
table.data .num {
- text-align: right;
+ text-align: end;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
@@ -553,6 +614,14 @@ pre code {
white-space: pre;
}
+/* The short answer of a page is a sentence with a whole command in it, and a
+ * command can be longer than a phone is wide. A span that cannot break pushes
+ * the page sideways, so inside a note it may break where it has to. */
+.note code {
+ white-space: normal;
+ overflow-wrap: anywhere;
+}
+
/* --------------------------------------------------------------------- faq */
.faq {
@@ -610,7 +679,8 @@ pre code {
}
.qa-body {
- padding: 0 20px 18px 46px;
+ padding: 0 20px 18px;
+ padding-inline-start: 46px;
}
.qa-body p:last-child {
@@ -620,15 +690,16 @@ pre code {
/* ------------------------------------------------------------------ callout */
.note {
- border-left: 3px solid var(--accent);
+ border-inline-start: 3px solid var(--accent);
background: var(--surface);
- border-radius: 0 var(--radius) var(--radius) 0;
+ border-start-end-radius: var(--radius);
+ border-end-end-radius: var(--radius);
padding: 16px 20px;
margin: 24px 0;
}
.note.warn {
- border-left-color: var(--warning);
+ border-inline-start-color: var(--warning);
}
.note p:last-child {
@@ -652,14 +723,14 @@ pre code {
.steps > li {
counter-increment: step;
position: relative;
- padding-left: 46px;
+ padding-inline-start: 46px;
margin-bottom: 30px;
}
.steps > li::before {
content: counter(step);
position: absolute;
- left: 0;
+ inset-inline-start: 0;
top: 0;
width: 30px;
height: 30px;
@@ -737,6 +808,12 @@ pre code {
padding-top: 40px;
}
+ /* Sticky is a luxury of a header one row high. With the longer labels of
+ * some languages it takes a third of a phone, so it scrolls away here. */
+ .topbar {
+ position: static;
+ }
+
.topbar-inner {
gap: 12px;
padding-top: 10px;
@@ -745,8 +822,8 @@ pre code {
.mainnav {
order: 3;
+ flex-basis: 100%;
width: 100%;
- margin-right: 0;
}
.footer-inner {
@@ -755,6 +832,91 @@ pre code {
}
.qa-body {
- padding-left: 20px;
+ padding-inline-start: 20px;
+ }
+
+ .langlist {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
+
+/* --------------------------------------------------------------- languages */
+
+/* The site loads no font in any language it is served in, so what a page is
+ * drawn in is whatever the visitor's system carries.
+ * The stacks below only put the right one first. A language tag on the page
+ * already tells a browser which regional form of a Han character to draw, but
+ * an unlucky default can still pick a face with no glyphs for the script, and
+ * naming the system faces is cheaper than finding out from a bug report.
+ * Every name is a face the operating system ships - nothing here is fetched. */
+
+:root:lang(zh-Hans) {
+ --sans: system-ui, -apple-system, "PingFang SC", "Hiragino Sans GB",
+ "Microsoft YaHei", "Noto Sans CJK SC", "Noto Sans SC", sans-serif;
+}
+
+:root:lang(zh-Hant) {
+ --sans: system-ui, -apple-system, "PingFang TC", "Microsoft JhengHei",
+ "Noto Sans CJK TC", "Noto Sans TC", sans-serif;
+}
+
+:root:lang(ja) {
+ --sans: system-ui, -apple-system, "Hiragino Sans", "Hiragino Kaku Gothic ProN",
+ "Yu Gothic", Meiryo, "Noto Sans CJK JP", "Noto Sans JP", sans-serif;
+}
+
+/* Japanese has no spaces to break a line at, so a browser that can read the
+ * phrases breaks between them rather than in the middle of one, and the strict
+ * rules keep small kana and the long vowel mark off the start of a line. A
+ * browser that does not know the first property ignores it and breaks as it
+ * always did. */
+:root:lang(ja) {
+ word-break: auto-phrase;
+ line-break: strict;
+}
+
+:root:lang(ko) {
+ --sans: system-ui, -apple-system, "Apple SD Gothic Neo", "Malgun Gothic",
+ "Noto Sans CJK KR", "Noto Sans KR", sans-serif;
+}
+
+:root:lang(hi) {
+ --sans: system-ui, -apple-system, "Kohinoor Devanagari", "Nirmala UI",
+ "Noto Sans Devanagari", sans-serif;
+}
+
+:root:lang(th) {
+ --sans: system-ui, -apple-system, "Thonburi", "Leelawadee UI",
+ "Noto Sans Thai", sans-serif;
+}
+
+:root:lang(ar) {
+ --sans: system-ui, -apple-system, "Segoe UI", "Geeza Pro", Tahoma,
+ "Noto Sans Arabic", sans-serif;
+}
+
+/* Thai and Devanagari carry marks above and below the line, and the body
+ * line height that suits Latin text crowds them. */
+:root:lang(th) body,
+:root:lang(hi) body {
+ line-height: 1.85;
+}
+
+/* Tracking is a Latin habit. Arabic letters join, so any space between them
+ * breaks a word apart, and in Devanagari and Thai it pulls the marks away
+ * from the letters they belong to. The headings and the small capitals above
+ * are tracked, so it is switched off for the whole page. */
+:root:lang(ar) *,
+:root:lang(hi) *,
+:root:lang(th) * {
+ letter-spacing: normal;
+}
+
+/* Code is always left to right, in a page that reads right to left as well.
+ * Isolated, so the dashes and brackets of a flag stay where they were typed
+ * instead of being reordered by the sentence around them. */
+pre,
+code {
+ direction: ltr;
+ unicode-bidi: isolate;
+}
diff --git a/web/content/ar/ci.html b/web/content/ar/ci.html
new file mode 100644
index 00000000..46488b45
--- /dev/null
+++ b/web/content/ar/ci.html
@@ -0,0 +1,183 @@
+{{ with .Up }}
+ الملف الثنائي الثابت في المستودع يبقى في سجله إلى الأبد، ولا يمكن مراجعته في diff، ويصبح مستحيلًا
+ حين يكبر الملف. ولِّد الملفات بدلًا من ذلك داخل الخط من وصفة. الوصفة نص، والبايتات تخرج متطابقة في
+ كل مرة، وخطوة أخيرة تثبت أن شيئًا لم يتحرك.
+
+
+
+
الجواب المختصر
+
+ ثبّت tfg، وشغّل tfg generate fixtures.yaml --out ./fixtures قبل
+ الاختبارات، وtfg verify ./fixtures/manifest.json بعدها. كلتا الخطوتين تُفشلان
+ البناء من تلقاء نفسيهما، برمز خروج يقول السبب.
+
+
+
+
+
لماذا لا نودعها
+
لماذا لا ينبغي أن يعيش الملف الثابت في المستودع
+
+
+ يبقى في السجل. حذف ملف ثنائي لاحقًا لا يصغّر النسخة المستنسخة، لأن كل إصدار منه ما
+ زال هناك.
+
+
+ الـ diff لا يُظهر ما تغيّر. يرى المراجع أن ملف PDF مختلف ولا شيء غير ذلك. أما
+ الوصفة فتتغيّر بسطر واحد.
+
+
+ الملفات الكبيرة لا تتسع. يرفض GitHub دفعة تحتوي ملفًا أكبر من 100 ميغابايت، فلا يجد
+ اختبار حد رفع 500 ميغابايت ما يودعه.
+
+
+
+ الذي يُودَع هو الوصفة. الوصفة نفسها مع البذرة نفسها تكتب البايتات نفسها على أي جهاز، فالملف المولَّد
+ في الخط هو الملف الذي كان عندك على حاسوبك المحمول.
+
+
+
+
+
الوصفة
+
وصفة تعيش بجانب الاختبارات
+
+ تكتب هذه خمسًا وعشرين فاتورة ينبغي قبولها وصورتين فوق الحد ينبغي رفضهما، ويسجّل البيان التوقعين
+ معًا:
+
+ لكل نهاية رمز خروج خاص بها، فتفشل الخطوة من تلقاء نفسها ويقول السجل أيّها كان. هذه هي التي يصادفها
+ الخط:
+
+
+
3 - الوصفة غير صالحة. لم يُكتب شيء، ويُسمّى كل خلل
+
4 - الصيغة لا تستطيع ما طُلب منها، مثل حجم أقل من أصغر حجم لها
+
6 - لا توجد مساحة كافية على القرص
+
7 - وجد tfg verify ملفًا لا يطابق بيانه
+
8 - انتهى التشغيل لكن لم يُنتَج كل شيء
+
+
+ التشغيل الفاشل لا يطبع شيئًا على الخرج القياسي، فلا يحسب محلل السجلات خطأً بيانات أبدًا. الجدول
+ الكامل في صفحة التوثيق.
+
+
+
+
+
PowerShell
+
سكربت PowerShell يحتاج سطرًا إضافيًا
+
+ لا ينقل PowerShell رمز خروج برنامج إلى خارج ملف .ps1. شغّل واحدًا بـ -File
+ فيجيب السكربت 0 حتى حين رفضت الأداة داخله العمل، فيتحول بناء كان ينبغي أن يكون أحمر
+ إلى أخضر. السطر الأخير هو الإصلاح كله:
+
+ هكذا يتصرف PowerShell، وليس في الأمر شيء يخص هذه الأداة. أما cmd وbash
+ وzsh فلا تحتاج إلى شيء إضافي.
+
+
+
+
+
عدة مهام
+
مشاركة الملفات الثابتة بين المهام
+
+ لا حاجة عادةً إلى رفعها. لأن الوصفة نفسها تكتب البايتات نفسها، تستطيع كل مهمة تشغيل tfg
+ generate الخاص بها، وهذا أسرع من الرفع ثم التنزيل. وحين تحتاج مهمة إلى استلام ملفات من
+ أخرى، شغّل tfg verify على البيان بعد النقل، فيخبرك هل ما وصل هو ما كُتب.
+
+ المدقق الذي لم يُعرض عليه إلا ملفات سليمة لم يُختبر حقًّا. إليك طريقة الحصول على ملف أُتلف عمدًا،
+ ويخرج بالحجم الذي تطلبه تمامًا، ويحمل بيانًا يقول ما الذي ينبغي أن يفعله نظامك
+ به.
+
+
+
+
الجواب المختصر
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out يكتب ملف PNG حجمه
+ 2097152 بايتًا بالضبط، وبايتاته الأولى أصفار، ويسجّل البيان المجاور له أن نظامك ينبغي أن يرفضه.
+
+
+
+
+
الطريقة المعتادة
+
لماذا يُعدّ الملف المتلف يدويًا اختبارًا رديئًا
+
+ الطرق المعتادة هي محرر سداسي عشري، أو سكربت يقلب بضع بايتات عشوائية، أو قصّ الملف بـ
+ head أو truncate. تنجح مرة واحدة، ثم تكلّفك:
+
+
+
+ يختلف في كل مرة. البايت العشوائي يقع في مكان جديد عند كل تشغيل، فقد لا يعود فشل يوم
+ الثلاثاء يوم الأربعاء.
+
+
+ يغيّر الحجم. الملف المقصوص أصغر من الحد الذي كان ينبغي أن يبقى تحته، فيجيب فحص
+ الحجم قبل فحص المحتوى، ويمرّ الاختبار لسبب خاطئ.
+
+
+ كثيرًا ما يمرّ دون أن يلاحظه أحد. النص العادي يبقى مقروءًا مع تغيير بايت في الوسط،
+ وقارئ الصور المتسامح يرسمه ببساطة، فيُقبل الملف الذي كان يُفترض أن يكون تالفًا.
+
+
+ لا يقول شيئًا عمّا ينبغي أن يحدث. الملف مجرد بايتات، ومن يقرأ الاختبار لاحقًا عليه
+ أن يخمّن هل كان المقصود القبول أم الرفض.
+
+
+
+
+
+
ما تحصل عليه
+
الملف التالف يبقى بالحجم الذي طلبته
+
+ يُولَّد الملف كالمعتاد ثم يُتلَف في طريقه إلى القرص. يحتفظ بالحجم الذي طلبته، ويكتب الأمر نفسه
+ البايتات نفسها مرة أخرى.
+
+ تُكتب الإعدادات بعد النقطتين. يمكن تكرار الخيار، وتُطبَّق أنواع التلف بالترتيب الذي تكتبه. ويعمل مع
+ كل واحدة من {{ .Facts.FormatCount }} صيغة.
+
+
+
+
+
ما الذي يستطيعه
+
ما أنواع التلف المتاحة؟
+
+ هذه هي القائمة التي يطبعها البرنامج، وتُقرأ منه عند بناء هذه الصفحة. يطبع tfg damage
+ القائمة نفسها، ويبيّن tfg damage <id> ما يقبله واحد منها.
+
+ {{ template "damagesTable" . }}
+
+ يكتب zero-head أصفارًا فوق بداية الملف. معظم القارئات تنظر إلى هناك أولًا، إلى التوقيع
+ والترويسة اللذين يقولان ما هو الملف، فتلاحظ ذلك أي قارئة تقريبًا. والنص العادي والسجلات لا توقيع
+ لها وتُرفض أيضًا، لأن سلسلة من البايتات الصفرية ليست نصًّا. وتحت أربعة بايتات تخرج بعض الصيغ
+ بتلف لا تشتكي منه أي قارئة، ولهذا يبدأ الإعداد من أربعة.
+
+
+
+
+
ما يقوله البيان
+
بيان يقول ما ينبغي أن يحدث
+
+ كل ملف تالف يحصل على مدخل يقول إن نظامك ينبغي أن يرفضه، ويُسجَّل التلف بجانبه:
+
+ يُرفض طلبان قبل أن يُكتب أي شيء، لأن كلًّا منهما سيترك على القرص ملفًا يصفه البيان وصفًا خاطئًا:
+
+
+
ملف أصغر مما يحتاجه التلف، وكان سيخرج دون تغيير
+
+ expected: accept بجانب تلف، لأن لا شيء يمكنه تحقيق ذلك. اكتب sanitize إن
+ كان نظامك مقصودًا به إصلاح الملف، أو unspecified إن كان هذا هو السؤال الذي تطرحه
+
+
+
+
+
+
في وصفة
+
ملفات سليمة وتالفة في تشغيل واحد
+
+ ضع الاثنين في وصفة واحدة، فيحمل البيان المتوقَّع لكل ملف، ولا يحتاج الاختبار إلى قائمة تقول أيها
+ أيّ:
+
+ يقرأ الاختبار البيان ويتحقق من أن ما حدث هو ما أُعلن. لا يحتاج إلى قائمة بأسماء الملفات:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ الرفض الجيد هو الرفض النظيف. رسالة تقول ما الخطأ هي الجواب الذي تريده. أما خطأ الخادم أو التعليق أو
+ ملف حُفظ نصفه فهو العيب الذي وُجد هذا الاختبار لاكتشافه.
+
+
diff --git a/web/content/ar/docs.html b/web/content/ar/docs.html
new file mode 100644
index 00000000..73c6f221
--- /dev/null
+++ b/web/content/ar/docs.html
@@ -0,0 +1,269 @@
+
التوثيق
+
+ كل ما تفعله الأداة، مرتبًا على هيئة الأسئلة التي يأتي بها الناس فعلًا. ملف
+ README في المستودع هو المرجع الكامل ويطابق دائمًا الإصدار الذي
+ نزّلته.
+
+
+
+
ما الأوامر المتاحة؟
+
كل أمر يؤدي مهمة واحدة:
+ {{ template "commandList" . }}
+
+
+
+
كيف أولّد ملفًا واحدًا بحجم دقيق؟
+
+ حدد الصيغة والحجم ووجهة الملف. تُعدّ الأحجام بالمضاعفات 1024، فـ2mb تساوي 2097152
+ بايتًا. وعدد البايتات المجرد يصلح أيضًا، فـ--size 10485761 يطلب هذا العدد بالضبط.
+
+
tfg generate --format png --size 2mb --out ./out
+
الخيارات المفيدة في generate:
+
+
+
الخيار
ما يفعله
+
+
--format <id>
صيغة الملفات، مثل txt
+
--size <size>
الحجم الدقيق لكل ملف، مثل 10mb أو عدد بايتات مجرد
+
--size-range <a-b>
حجم يُسحب لكل ملف من نطاق، مثل 1kb-8kb. يأتي السحب من البذرة
+
--boundary <size>
ثلاثة ملفات حول حد: أقل بايتًا واحدًا، والحد نفسه، وأكثر بايتًا واحدًا
+
--count <n>
عدد الملفات المراد إنتاجها. الافتراضي 1
+
--name <template>
قالب الاسم، مثل invoice_{index:04}.txt
+
--out <dir>
المجلد الذي يُكتب فيه
+
--seed <n>
بذرة التشغيل. البذرة نفسها تعطي البايتات نفسها
+
--set <k>=<v>
إعداد صيغة، يمكن تكراره
+
--damage <name>
إتلاف الملفات عمدًا، يمكن تكراره ويُطبَّق بالترتيب. شغّل tfg damage للاطلاع على القائمة
+
--expected <outcome>
accept أو reject أو sanitize أو unspecified
+
--dry-run
عدّ وأظهر، ولا تكتب شيئًا إطلاقًا
+
--json
اكتب البيان إلى المخرج القياسي
+
+
+
+
+
+
+
كيف أصنع ملفًا تالفًا عمدًا؟
+
+ كل ملف آخر تكتبه هذه الأداة صحيح بحكم بنائه، وهذا يجيب عن اثنين من ثلاثة أسئلة يطرحها مدقق الرفع.
+ أما --damage فيجيب عن الثالث: هل يُفتح الملف أصلًا. يُنتَج الملف بشكل طبيعي ثم
+ يُتلف، فيبقى بالحجم الذي طلبته.
+
+ يحصل الملف التالف على expected: reject في البيان، مع تسجيل الإتلاف بجانبه. يُرفض أمران
+ قبل كتابة أي شيء، لأن كلًّا منهما كان سيضع على القرص ملفًا يصفه البيان وصفًا خاطئًا:
+
+
+
ملف أصغر مما يحتاجه الإتلاف، لأنه كان سيخرج دون تغيير
+
+ expected: accept بجانب إتلاف، لأن لا شيء يمكن أن يحققه. اكتب sanitize إن
+ كان المقصود أن يصلح النظام قيد الاختبار الملف، أو unspecified إن كان هذا هو
+ السؤال الذي تطرحه
+
+
+
+ أما الثالث فلا يمكن معرفته مسبقًا. إذا نُفّذ إتلاف ولم يحرّك أي بايت، يُسقَط ذلك الملف بدل كتابته،
+ ويستمر التشغيل ويذكر أي ملف كان، وينتهي برمز الخروج الجزئي.
+
+ الوصفة ملف YAML يصف تشغيلًا كاملًا. أودعها بجانب اختباراتك فتتوقف بيانات الاختبار عن كونها ملفات
+ ثنائية في مستودعك، ويستطيع أي شخص إعادة بنائها، بايتًا ببايت، من ملف بضع مئات من الأحرف.
+
+ يحتاج كل هدف إلى واحد فقط من size أو size-range أو boundary
+ أو contains. اثنان خطأ، وعدم وجود أي منها خطأ كذلك. الوصفة غير الصالحة لا
+ تكتب أي ملف وتبلّغ عن كل المشكلات دفعة واحدة لا عن أولها فقط، وتسمّي كل مشكلة الإعداد
+ الذي تخصه.
+
+
+
+
+
كيف أصرّح بما يجب أن يفعله نظامي بملف ما؟
+
الصيغة القصيرة حين تكفي النتيجة، والطويلة حين يهم السبب:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ النتائج هي accept وreject وsanitize
+ وunspecified. الأسباب قائمة مغلقة ليتمكن التقرير من التجميع بحسبها:
+ content_malformed وcount_limit وdimensions_limit
+ وduplicate وencoding_invalid وextension_rule
+ وfilename_invalid وfilename_too_long وfilename_traversal
+ وmalware_signature وmime_mismatch وnesting_depth
+ وnone وsize_limit وsize_zero.
+
+
+ يسمّي السبب القاعدة المعنية لا الحكم. ولهذا يمكن أن يقع السبب نفسه تحت أي من
+ النتيجتين: ملف أقل من الحد بايتًا واحدًا نتيجته accept، والقاعدة المعنية تبقى
+ size_limit.
+
+
+
+
+
ماذا يوجد في البيان؟
+
+ يُكتب بجانب الملفات في نهاية كل تشغيل، بما في ذلك التشغيل الذي أُوقف. عنصر واحد لكل ملف:
+
+ يُضاف recipe_hash حين يأتي التشغيل من وصفة، ويُضاف preset مع
+ overrides حين يأتي من إعداد مسبق، فيمكن دائمًا تتبّع البيان إلى ما أنتجه.
+
+
+ يحمل كل عنصر أيضًا target_id، وهو معرّف الهدف في الوصفة الذي أنتج الملف، ويحصي
+ summary.by_target الملفات التي انتهى إليها كل هدف. وهكذا يمكن فحص وصفة متعددة
+ الأهداف هدفًا هدفًا دون قراءة أسماء الملفات.
+
+
+
+
+
ما الإعداد المسبق؟
+
+ مجموعة ملفات جاهزة تجيب عن سؤال اختبار شائع، فلا تحتاج إلى تصميم المجموعة بنفسك. الإعدادات المسبقة
+ وصفات عادية في جوهرها، ويطبع eject الوصفة لتعدّلها من هناك. لكل إعداد مسبق
+ صفحة خاصة تذكر ما يكتشفه عادةً، وما في المجموعة، وكل إعداد يقبله.
+
+ يخبرك show بكلفة المجموعة قبل أن تبنيها، ويقول صراحةً حين يكون رقم ما قيمة مؤقتة منا لا
+ حدًّا منك.
+
+
+
+
+
ما معنى رموز الخروج؟
+
+ لكل نهاية رمزها الخاص، وتذهب المخرجات المقروءة آليًا إلى المخرج القياسي، ولا يطبع التشغيل الفاشل
+ شيئًا هناك. الجدول عقد مجمّد، وتغيير معنى رمز يتطلب رفع الإصدار الرئيسي.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ التشغيل الموقوف بـ Ctrl+C يترك بيانًا ولا يترك أبدًا ملفًا مكتوبًا نصفه، لذا يمكن للمهمة التالية أن
+ تنظّف مهمة أُلغيت.
+
+ نعم، المحرك نفسه بنافذة فوقه، للاختبار الذي لا يُكتب له سكربت. وهي ليست نسخة مبتورة: يقارن اختبار
+ الواجهتين ميزةً ميزة، وكل ما تستطيع إحداهما فعله دون الأخرى يجب أن يُعلَن ويُبرَّر بدل أن
+ يتباعدا بصمت.
+
+
+ الشاشات هي دفعة واحدة، والإعدادات المسبقة، وعدة دفعات معًا، وحول. تُظهر كلفة التشغيل قبل كتابة أي
+ شيء، وتبلّغ عن التقدم أثناء العمل، ويمكن إلغاؤها في منتصف الطريق دون ترك ملف مكتوب نصفه. لا تفتح
+ ملف وصفة بعد، فالوصفات شأن سطر الأوامر حاليًا، وتبني النافذة دفعاتها في النموذج.
+
+
diff --git a/web/content/ar/exact-size.html b/web/content/ar/exact-size.html
new file mode 100644
index 00000000..9d6614a2
--- /dev/null
+++ b/web/content/ar/exact-size.html
@@ -0,0 +1,141 @@
+
كيف تنشئ ملفًا بحجم دقيق
+
+ لكل نظام أمر لذلك، والثلاثة كلها أدناه. تعطيك ملفًا بعدد البايتات الصحيح تمامًا، وفي كثير من
+ الاختبارات هذا كل ما تحتاجه. كل أمر في هذه الصفحة جُرِّب قبل النشر على النظام
+ الذي ينتمي إليه.
+
+ تعني 10MB في PowerShell ما قدره 10485760 بايتًا، وهو العدّ نفسه بأساس 1024 الذي يستخدمه
+ مستكشف الملفات، فيُنتج الأمران أعلاه الحجم نفسه.
+
+
+
+
+
لينكس
+
dd وtruncate وfallocate، والفرق الذي يوقع الناس
+
dd هو الأمر الذي يعرفه الجميع. يكتب البايتات فعلًا:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate فوري، وهنا الفخ. قيس على Alpine Linux، فأبلغ الملف عن 10485760 بايتًا وشغل
+ صفر كتل، فهو ملف متناثر. كل ما يقرؤه يحصل على عشرة ميغابايت من
+ الأصفار، لكن القرص لم يتنازل عن المساحة قط:
+
+
truncate -s 10M test10mb.bin
+
+ هذا مناسب لاختبار حد الرفع، ومضلل لاختبار حصة القرص. أما fallocate فهو ما تلجأ إليه حين
+ يجب أن تكون المساحة حقيقية:
+
+
fallocate -l 10M test10mb.bin
+
وحين يجب أن يكون المحتوى غير قابل للضغط، حتى لا يستطيع أداة الأرشفة تصغيره من جديد:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
ماك
+
mkfile، وهو غير متناثر، والأمران اللذان تعرفهما بالفعل
+
+ يأتي ماك مع mkfile. قيس على macOS 26.6.2: 10485760 بايتًا و20480 كتلة، فالمساحة مخصصة
+ فعلًا لا موعودة فقط:
+
+ كل ما سبق يعطيك كتلة من الأصفار. وهذا يكفي حين لا ينظر الشيء المختبَر إلا إلى الحجم، كحد الرفع أو
+ الحصة أو النقل. ويتوقف عن الكفاية لحظة أن يفتح أي شيء الملف.
+
+
+ قيس، وهو يستحق أن تجرّبه بنفسك: أنشئ ملفًا بحجم 2 MB بـ fsutil، وسمّه
+ photo.png، وسلّمه إلى مكتبة صور. تجيب Pillow بـ cannot identify image
+ file. إنه ليس PNG. ولم يكن كذلك قط، فالاسم وحده قال ذلك.
+
+
+ هذا أهم مما يبدو، بسبب الاتجاه الذي يفشل فيه الاختبار بعد ذلك. ترفض نقطة الرفع عندك
+ الملف، فيصبح اختبارك أخضر، وتستنتج أن حد الحجم يعمل. لم ترفضه بسبب الحجم. رفضته لأن البايتات لم
+ تكن صورة، ولم تُبلَغ القاعدة التي أردت اختبارها قط.
+
+
+
محلل يرفضه قبل النظر في أي قاعدة للحجم
+
تفشل خطوة الصورة المصغرة، والخطأ الذي تقرؤه عن الصورة المصغرة
+
يرفضه برنامج مكافحة فيروسات أو فحص محتوى لسبب ثالث
+
عارض لا يظهر شيئًا، ولا أحد يستطيع الجزم إن كان هذا هو الخطأ
+
+
+
+
+
الطريق الآخر
+
ملف حقيقي من تلك الصيغة، بالحجم الذي طلبته تمامًا
+
+ هذا ما يفعله Testing Files Generator. الملف ملف أصيل من صيغته، يُفتح في البرنامج الذي يملكه، وعدد
+ بايتاته هو ما طلبته بالضبط، حتى البايت:
+
+ اطلب حجمًا لا تستطيع الصيغة بلوغه فتحصل على خطأ يذكر الحد الأدنى وسببه، لا ملفًا بحجم خاطئ أبدًا.
+ تسرد صفحة الصيغ كل صيغة مع أصغر ملف تستطيع إنتاجه.
+
+
والحد حالات اختبار ثلاث لا حالة واحدة، لذا تبني الأداة الثلاث كلها:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ وهذا يعطيك 10485759 و10485760 و10485761 بايتًا، وبيانًا يقول أيها يجب أن يقبله نظامك وأيها يجب أن
+ يرفضه. تستعرض صفحة حالات الاستخدام هذا وأربع مهام أخرى بُنيت الأداة
+ لها.
+
+ {{ template "downloadCta" . }}
+
+
+
+
فأيهما تستخدم؟
+
+
+
استخدم أمر النظام
+
+ حين لا يفتح أي شيء الملف. اختبار حد حجم على نقطة تفحص الحجم أولًا، أو نقل، أو حصة، أو قرص ممتلئ. سطر
+ واحد، وهو مثبّت أصلًا.
+
+
+
+
استخدم مولّدًا حقيقيًا
+
+ حين يحلّل شيء ما الملف أو يعرضه أو يستورده أو يفكّه، وحين تحتاج غدًا إلى بيانات الاختبار نفسها على
+ جهاز آخر، بايتًا ببايت.
+
+
+
+
+ الاثنان في هذه الصفحة لأن كلًّا منهما صواب في بعض الأحيان. الخطأ الذي ينبغي تجنبه هو استخدام الأول
+ حيث يلزم الثاني وقراءة الاختبار الأخضر كدليل.
+
+
diff --git a/web/content/ar/faq.html b/web/content/ar/faq.html
new file mode 100644
index 00000000..b526637d
--- /dev/null
+++ b/web/content/ar/faq.html
@@ -0,0 +1,18 @@
+
الأسئلة الشائعة
+
+ الترخيص والخصوصية وقابلية إعادة الإنتاج وما يتحقق منه الناس قبل إدخال مولّد في خط بناء. إذا لم يكن
+ سؤالك هنا، فإن متتبع المشكلات مفتوح.
+
{{ .Facts.FormatCount }} صيغة ملف، كلٌّ منها يُولَّد بحجم دقيق
+
+ كلٌّ منها ملف حقيقي من تلك الصيغة. يُفتح في البرنامج الذي يملكه، وعدد بايتاته هو ما
+ طلبته بالضبط. ولا واحد منها أصفار حشوية أُلصق بها امتداد.
+
+
+{{ template "formatsTable" . }}
+
+
+
معنى الأعمدة
+
+
+
أصغر ملف
+
+ أقل عدد من البايتات تقبله هذه الأداة لتلك الصيغة، شاملًا الوسم الذي تكتبه داخل الملف. اطلب أقل فتحصل
+ على خطأ يذكر الحد الأدنى وسببه، لا ملفًا بحجم خاطئ أبدًا.
+
+
+
+
الاكتمال
+
+ مدى اكتمال الملف. تعني full أن قارئًا يحلل الصيغة فعلًا يقبله، لا أن الامتداد يطابق
+ فحسب.
+
+
+
+
يُتحقق منه بواسطة
+
+ القارئ المستقل الذي يفتح كل ملف مولَّد قبل إصدار الصيغة، وهو تنفيذ منفصل، لا شيفرتنا نحن تصحّح
+ واجباتها بنفسها.
+
+
+
+
+ وتتكرر كل صيغة حتى البايت أيضًا: الوصفة نفسها والبذرة نفسها تنتجان ملفات متطابقة على أي جهاز، وهذا
+ ما يجعل إيداع وصفة بدل بيانات الاختبار نفسها أمرًا آمنًا.
+
+
+
+
+
الإعدادات التي تقبلها كل صيغة
+
+ لمعظم الصيغ إعدادات خاصة بها: أبعاد الصورة، وجودة JPEG، وعدد صفحات PDF، والصفوف والأعمدة في جدول
+ بيانات، وعدد العناصر داخل الأرشيف. اضبطها بـ --set key=value في سطر الأوامر أو تحت
+ properties: في وصفة.
+
+ القيمة الواقعة خارج ما يقبله الإعداد تُرفض برسالة تسمّي الإعداد والنطاق المسموح وما يُستخدم بدلًا
+ منه. والإعداد المجهول خطأ أيضًا، وليس قيمة افتراضية صامتة أبدًا، فخطأ مطبعي يُقبل بصمت يعطي
+ ملفًا بإعدادات خاطئة وساعة من التساؤل عن سبب نجاح اختبار كان ينبغي ألا ينجح.
+
+
+ شغّل tfg formats <id> لترى بالضبط ما تقبله صيغة واحدة في الإصدار الذي لديك.
+
+
+
+
+
الأرشيفات تحتوي ملفات حقيقية
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} و{{ end }}{{ $c.ID }}{{ end }} يمكن
+ ملؤها بعناصر بدل تركها قشرة فارغة. الأرشيف المولَّد يحتوي فعلًا على المستندات التي يدّعي
+ احتواءها، فكل ما يفكّه أثناء اختبار يجد بداخله ملفات حقيقية.
+
+ PDF وPNG وDOCX وZIP، {{ .Facts.FormatCount }} صيغة في المجمل، وكلٌّ منها ملف حقيقي
+ يُفتح في البرنامج الذي يملكه، وبـالحجم الذي طلبته تمامًا. كما يدوّن كل تشغيل ما
+ يجب أن يفعله تطبيقك بكل ملف. سطر أوامر ونافذة سطح مكتب، مجاني ومفتوح المصدر، ويعمل بالكامل على
+ جهازك.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ نافذة سطح المكتب، مجهّزة لكتابة دفعة من الملفات. المحرك نفسه يعمل خلف سطر الأوامر.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
صيغة حقيقية، وكلٌّ منها يُفتح في البرنامج الذي يملكه
+
+
+ 1 بايت
+
دقة كل حجم تطلبه، دون تقريب صامت أبدًا
+
+
+ 0
+
اتصالات إلى أي مكان - لا حساب ولا قياسات عن بُعد ولا فحص للتحديثات
+
+
+
+
+
المشكلة
+
صنع ملف اختبار واحد سهل. صنع الألف الصحيحة هو الجزء المرهق
+
أنت تختبر برنامجًا يقبل ملفات من الناس. عاجلًا أم آجلًا ستحتاج إلى:
+
+
ملف PDF بحجم 10 MB تمامًا، لتعرف إن كان حد الرفع حقيقيًا
+
الملفات الثلاثة على جانبي هذا الحد، لاصطياد أخطاء الفرق بواحد
+
10,000 ملف سجل، لترى ماذا تفعل المهمة الليلية حين يكون المجلد كبيرًا
+
ملف ZIP يحتوي فعلًا على 200 مستند، لا قشرة فارغة بالامتداد الصحيح
+
ملف بحجم 4 GB دون الاحتفاظ بملف 4 GB في مستودعك
+
بيانات الاختبار نفسها على حاسوبك المحمول وعلى خادم البناء، بايتًا ببايت
+
+
+ هذا ما يحل محله هذا المولّد. صُمم لمهندسي ضمان الجودة وأتمتة الاختبار، ولكل من خلف شيفرته نموذج رفع
+ أو روتين استيراد أو محلل أو حصة تخزين.
+
+
+
+
+
ما الذي يميّزه
+
المولّدات الأخرى تتوقف عند البايتات. هذا المولّد يجيب عما يسأله اختبارك فعلًا
+
+ مجلد من الملفات يتركك تقرر بنفسك ما يُفترض أن يثبته كل ملف. يكتب كل تشغيل هنا ملف
+ manifest.json بجانب الملفات، وهو قائمة بسيطة بكل ما أُنتج، ولكل عنصر توقّع
+ معلن.
+
+
لنفترض أن نقطة الرفع عندك تسمح بـ 1 MB. اطلب الملفات الثلاثة الواقعة على هذا الخط:
+ يسجّل unspecified بدل اختلاق توقّع. المولّد الذي يخمّن يصنع إخفاقات زائفة، ومجموعة
+ الاختبارات التي تطلق إنذارات كاذبة يُوقف العمل بها.
+
+
+
+
+
+
الإعدادات المسبقة
+
اختر السؤال، واحصل على المجموعة كاملة
+
+ الإعداد المسبق مجموعة ملفات اختبار مصممة حول سؤال اختبار واحد، فلا تحتاج إلى معرفة أي الملفات يثبت
+ ماذا. لكل منها صفحة تذكر ما يكتشفه عادةً، وما في المجموعة، وكل إعداد يقبله.
+
+ عشرة آلاف ملف سجل، حجم كل منها بين واحد وثمانية كيلوبايت، تُسحب الأحجام من البذرة ليعطي الغد
+ المجموعة نفسها. امنح كل تشغيل مجلده الخاص، فالبيان هو السجل الوحيد لما كتبه
+ التشغيل، لذا ترفض الأداة كتابة بيان ثانٍ فوقه:
+
+ تُعدّ الأحجام بالمضاعفات 1024 كما يفعل مدير الملفات لديك، فـ2mb تعني 2097152 بايتًا.
+ وعدد البايتات المجرد يصلح أيضًا. يغطي التوثيق الوصفات والبيان ورموز
+ الخروج.
+
+
+
+
+
ما تحصل عليه
+
مبني لمجموعة اختبارات تعمل دون إشراف
+
+
+
حجم دقيق، حتى البايت
+
اطلب 10485761 بايتًا واحصل على هذا العدد بالضبط. الحجم الذي لا تستطيع الصيغة بلوغه خطأ مع سبب، وليس ملفًا بحجم خاطئ أبدًا.
+
+
+
{{ .Facts.FormatCount }} صيغة حقيقية
+
ليست أصفارًا حشوية بامتداد. يُفتح ملف PNG المولَّد في عارض الصور، ويُفتح DOCX في Word، ويُفك ضغط ZIP. وتُفحص كل صيغة بقرّاء مستقلين قبل إصدارها.
+
+
+
بيان هو مرجع للاختبار
+
المسار والحجم وSHA-256 والصيغة والبذرة وإصدار الأداة، وما يجب أن يفعله نظامك بالملف.
+
+
+
قابل لإعادة الإنتاج
+
الوصفة نفسها والبذرة نفسها تعطيان البايتات نفسها على أي جهاز. أودع وصفة YAML صغيرة بدل بيانات اختبار ثنائية كبيرة.
+
+
+
واجهتان ومحرك واحد
+
سطر أوامر مبني للتكامل المستمر، ونافذة سطح مكتب للاختبار الاستكشافي. ليست أيٌّ منهما نسخة مبتورة من الأخرى، ويقارنهما اختبار ميزةً ميزة.
+
+
+
دون اتصال بالكامل
+
لا حساب ولا سحابة ولا قياسات عن بُعد ولا فحص للتحديثات. والملف التنفيذي لسطر الأوامر لا تُترجَم فيه حزمة شبكة أصلًا.
+
+
+
+
+
+
التنزيل
+
اختر الإصدار المناسب لنظامك
+
+ فك ضغط الأرشيف وشغّل الملف. tfg هو سطر الأوامر وtfg-gui هو نافذة سطح
+ المكتب. لا يوجد مثبّت ولا شيء يُضاف إلى جهازك.
+
+ {{ template "downloadsTable" . }}
+
+
ما الموقَّع وما غير الموقَّع
+
+ تنزيلات ويندوز وماك موقّعة، لذا تبدأ دون تحذير من مطوّر غير معروف. أما تنزيلات لينكس فغير موقّعة،
+ لأن لينكس المكتبي لا يملك ما يوقَّع به. وكل أرشيف مدرج في verify-SHA256SUMS.txt
+ على صفحة الإصدارات، لتتحقق مما نزّلته.
+
+ يبني الإعداد المسبق {{ .ID }} بأمر واحد مجموعة كاملة من ملفات الاختبار الحقيقية لهذا
+ السؤال، وبجانبها manifest.json يحدد كيف يجب أن يتفاعل نظامك مع كل ملف. كل ما يلي
+ مقروء من البرنامج، عند القيم الافتراضية لهذا الإصدار.
+
+
+{{ if .Catches }}
+
+
ماذا يكتشف عادةً؟
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
ماذا في المجموعة؟
+
عند القيم الافتراضية، كما يبلّغ tfg preset show {{ .ID }}:
+
+
+
+
الملفات
{{ .Budget.Files }}
+
الأهداف في وصفته
{{ .Budget.Targets }}
+
الحجم الإجمالي
{{ .Bytes }} B
+
الصيغ
{{ join .Budget.Formats ", " }}
+
+
+
+
وما يتوقعه بيان تلك المجموعة من نظامك:
+
+
+
+
المتوقع
المعنى
الملفات
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
ما الذي يمكنك تغييره؟
+ {{- if .Settings }}
+
+
+
+
الإعداد
يقبل
الافتراضي
ما يفعله
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} هذه القيمة الافتراضية مؤقتة منا، وليست قيمة نظامك. مرّر قيمتك أنت.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
لا إعدادات لهذا الإعداد المسبق. المجموعة هي نفسها في كل مرة.
+ {{- end }}
+
+
+
+
كيف تشغّله؟
+
اطّلع على كلفة المجموعة، أو ابنِها، أو خذ وصفتها لتعدّلها:
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/ar/presets.html b/web/content/ar/presets.html
new file mode 100644
index 00000000..679ae87a
--- /dev/null
+++ b/web/content/ar/presets.html
@@ -0,0 +1,29 @@
+
إعدادات مسبقة لملفات الاختبار، مجموعة لكل سؤال اختبار
+
+ الإعداد المسبق مجموعة كاملة من ملفات الاختبار مصممة حول سؤال واحد، مع بيان يحدد كيف يجب أن يتفاعل
+ نظامك مع كل ملف. أنت تختار السؤال، والأداة تبني المجموعة. لكل إعداد مسبق صفحته الخاصة التي تذكر ما
+ يكتشفه عادةً، وما في المجموعة، وكل إعداد يقبله.
+
+
+{{ template "presetsList" . }}
+
+
+
بماذا يختلف الإعداد المسبق عن الوصفة؟
+
+ في جوهره، لا يختلف. الإعداد المسبق وصفة تكتبها الأداة لك من بضعة إعدادات. يطبع tfg preset
+ eject تلك الوصفة لتحتفظ بها بجانب اختباراتك وتعدّلها، ويمكن لوصفة خاصة بك أن تبني على
+ إعداد مسبق بسطر واحد: extends: preset: يليه معرّفه.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
هل يمكنني الوثوق بالقيم الافتراضية؟
+
+ بالنسبة إلى الملفات، نعم. أما الرقم الذي لا يعرفه إلا نظامك، مثل حد نموذج الرفع، فالقيمة الافتراضية
+ قيمة مؤقتة منا، وتقول الأداة ذلك في كل مرة تستخدم فيها واحدة. وتعلّم صفحة كل إعداد مسبق تلك
+ الإعدادات، ويقول tfg preset show ذلك قبل كتابة أي شيء.
+
+
diff --git a/web/content/ar/site.json b/web/content/ar/site.json
new file mode 100644
index 00000000..a23bceb3
--- /dev/null
+++ b/web/content/ar/site.json
@@ -0,0 +1,329 @@
+{
+ "code": "ar",
+ "locale": "ar_AR",
+ "name": "العربية",
+ "dir": "ar",
+ "rtl": true,
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "الرئيسية",
+ "title": "مولّد ملفات الاختبار لضمان الجودة - حجم دقيق، {{ .Facts.FormatCount }} صيغة حقيقية",
+ "description": "مولّد ملفات اختبار مجاني ومفتوح المصدر لضمان الجودة. ملفات PDF وDOCX وPNG وZIP حقيقية بحجم دقيق، مع بيان يحدد كيف يجب أن يتفاعل نظامك."
+ },
+ {
+ "key": "formats",
+ "slug": "formats",
+ "nav": "الصيغ",
+ "title": "{{ .Facts.FormatCount }} صيغة ملف مدعومة - PDF وDOCX وPNG وZIP وغيرها",
+ "description": "كل صيغ الملفات التي يولّدها المولّد، وأصغر ملف ممكن لكل صيغة، والإعدادات التي تقبلها. تُفتح كل الصيغ الـ {{ .Facts.FormatCount }} في برامجها الأصلية."
+ },
+ {
+ "key": "presets",
+ "slug": "presets",
+ "nav": "الإعدادات المسبقة",
+ "title": "إعدادات مسبقة لملفات الاختبار - مجموعات جاهزة لأسئلة ضمان الجودة",
+ "description": "مجموعات جاهزة من ملفات الاختبار، تجيب كل منها عن سؤال اختبار واحد: حدود الرفع، وأسماء الملفات، والترميزات، واستيراد الجداول، والملفات الفارغة، والتحقق."
+ },
+ {
+ "key": "docs",
+ "slug": "docs",
+ "nav": "التوثيق",
+ "title": "التوثيق - الأوامر والوصفات والبيان ورموز الخروج",
+ "description": "كيف تولّد ملفات اختبار من سطر الأوامر أو من وصفة YAML، وما يحتويه البيان، وما معنى كل رمز خروج عند التشغيل في CI."
+ },
+ {
+ "key": "use-cases",
+ "slug": "use-cases",
+ "nav": "حالات الاستخدام",
+ "title": "حالات الاستخدام - حدود الرفع وبيانات CI والاختبار الكمي",
+ "description": "اختبار حد حجم الرفع، وبناء بيانات اختبار قابلة لإعادة الإنتاج لـ CI، وتوليد عشرة آلاف ملف، وملء الأرشيفات بمحتوى حقيقي."
+ },
+ {
+ "key": "exact-size",
+ "slug": "create-file-exact-size",
+ "nav": "الحجم الدقيق",
+ "title": "كيف تنشئ ملفًا بحجم محدد - ويندوز ولينكس وماك",
+ "description": "fsutil وdd وtruncate وmkfile، كلٌّ منها مُقاس على نظامه، ولماذا لا يصلح ملف منشأ بهذه الطريقة عندما يحتاج الاختبار إلى PDF أو PNG."
+ },
+ {
+ "key": "faq",
+ "slug": "faq",
+ "nav": "الأسئلة الشائعة",
+ "title": "الأسئلة الشائعة - عن توليد ملفات الاختبار",
+ "description": "بماذا يختلف عن dd وfsutil، وهل يمكن إيداع الملفات بأمان، وهل تتكرر التشغيلات بايتًا ببايت، وماذا يحدث إذا تعذر بلوغ حجم ما."
+ },
+ {
+ "key": "damage",
+ "slug": "corrupt-test-files",
+ "nav": "ملفات تالفة",
+ "title": "ملفات اختبار تالفة - ملفات معطوبة بحجم دقيق",
+ "description": "ملف أُتلف عمدًا بحجم دقيق، مع بيان يقول إن نظامك ينبغي أن يرفضه. لاختبار التحقق من الرفع والمحللات.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "test-files-in-ci",
+ "nav": "ملفات الاختبار في CI",
+ "title": "ملفات الاختبار في CI - GitHub Actions وGitLab CI وPowerShell",
+ "description": "ولّد ملفات الاختبار في الخط بدل إيداع الملفات الثنائية: سير عمل GitHub Actions، ومهمة GitLab، ورموز الخروج، وفخ PowerShell.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "تخطَّ إلى المحتوى",
+ "navLabel": "القائمة الرئيسية",
+ "langLabel": "اللغة",
+ "breadcrumbHome": "الرئيسية",
+ "imageAlt": "Testing Files Generator - ملفات اختبار حقيقية بحجم دقيق، مع بيان يحدد كيف يجب أن يتفاعل نظامك مع كل ملف",
+ "schemaDescription": "مولّد ملفات اختبار مجاني ومفتوح المصدر لضمان الجودة. ينتج ملفات حقيقية بـ {{ .Facts.FormatCount }} صيغة وبحجم دقيق، ويكتب بيانًا يحدد كيف يجب أن يتفاعل النظام قيد الاختبار مع كل ملف.",
+ "ctaDownload": "تنزيل",
+ "ctaSource": "عرض الشيفرة المصدرية",
+ "ctaNote": "مجاني ومفتوح المصدر، GPL-3.0. لا حاجة إلى التسجيل. تنزيلات ويندوز وماك موقّعة وتعمل دون تحذير.",
+ "colFormat": "الصيغة",
+ "colName": "الاسم",
+ "colExtension": "الامتداد",
+ "colSmallest": "أصغر ملف",
+ "colFidelity": "الاكتمال",
+ "colChecked": "يُتحقق منه بواسطة",
+ "colSetting": "الإعداد",
+ "colAccepts": "القيم المقبولة",
+ "colSystem": "النظام",
+ "colCli": "سطر الأوامر",
+ "colWindow": "نافذة سطح المكتب",
+ "noBinary": "لا يوجد ملف تنفيذي بعد",
+ "colCode": "الرمز",
+ "colMeaning": "المعنى",
+ "footerBlurb": "ملفات اختبار لضمان الجودة بحجم دقيق، مع بيان يحدد كيف يجب أن يتفاعل نظامك مع كل ملف.",
+ "footerProject": "المشروع",
+ "footerSource": "الشيفرة المصدرية على GitHub",
+ "footerReleases": "التنزيلات",
+ "footerIssues": "الإبلاغ عن مشكلة",
+ "footerSupport": "ادعم المشروع",
+ "footerPages": "الصفحات",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. مُصدَر بموجب رخصة جنو العمومية العامة، الإصدار 3. الملفات التي تولّدها ملكك، فالرخصة تشمل الأداة لا مخرجاتها.",
+ "footerPrivacy": "لا يحمّل هذا الموقع خطوطًا ولا سكربتات ولا متتبعات من أي مكان. ولا يضبط ملفات تعريف الارتباط.",
+ "notFoundTitle": "هذه الصفحة غير موجودة",
+ "notFoundLead": "العنوان الذي اتبعته لا يطابق أي صفحة في هذا الموقع.",
+ "notFoundBack": "العودة إلى الصفحة الرئيسية",
+ "read.format": "صيغة كل ملف في المجموعة. إنه خيار في الأداة نفسها، والإعداد المسبق يمنحه قيمة افتراضية فقط.",
+ "readTakes.format": "معرّف صيغة من صفحة الصيغ",
+ "colDamage": "التلف",
+ "colEffect": "ما يفعله بالبايتات",
+ "colSettings": "الإعدادات",
+ "noSettings": "لا شيء"
+ },
+ "endings": {
+ "0": "عمل كل شيء.",
+ "1": "خطأ غير متوقع داخل الأداة.",
+ "2": "أمر أو خيار خاطئ.",
+ "3": "الوصفة غير صالحة.",
+ "4": "لا تستطيع الصيغة فعل ما طُلب منها.",
+ "5": "فشلت قراءة أو كتابة.",
+ "6": "لا توجد مساحة كافية على القرص.",
+ "7": "وجد verify عدم تطابق.",
+ "8": "انتهى التشغيل لكن لم يُنتَج كل شيء.",
+ "130": "أُوقف بواسطة Ctrl+C.",
+ "143": "أوقفته إشارة، وهذا ما يبدو عليه انتهاء مهلة CI."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "هل يمر ملف صالح بأصغر حجم تسمح به الصيغة؟",
+ "title": "الفارغ والأدنى",
+ "pageTitle": "أصغر ملفات اختبار صالحة وفارغة في كل صيغة",
+ "description": "أصغر ملف صالح تكتبه الأداة في كل صيغة من صيغها الـ {{ .Facts.FormatCount }}، وملف فارغ حيث تسمح الصيغة، ومع كل ملف التفاعل المتوقع.",
+ "catches": [
+ "ملف صالح يُرفض لأنه صغير جدًا، لأن الفحص يعدّ البايتات بدل قراءتها",
+ "ملف فارغ يُسقط القارئ بدل أن يُبلَّغ عنه",
+ "صورة بعرض بكسل واحد تقسم على صفر في طريقها إلى الصورة المصغرة",
+ "تخزين يقرأ صفر بايت على أنه رفع فاشل ويواصل إعادة المحاولة"
+ ],
+ "details": {
+ "formats": "الصيغ التي تتكون منها المجموعة. اتركها على all لكل صيغ هذا الإصدار، أو سمِّ الصيغ التي يقبلها نظامك."
+ }
+ },
+ "filename-handling": {
+ "question": "هل سيخزّن نظامي ويعرض ويعيد اسم ملف لم يتوقعه؟",
+ "title": "التعامل مع أسماء الملفات",
+ "pageTitle": "أسماء ملفات إشكالية للاختبار - يونيكود والطول",
+ "description": "ملفات بأسماء تكسر الرفع والتخزين: أنظمة كتابة أخرى ورموز تعبيرية، وعكس اتجاه الكتابة، وأحرف غير مرئية، وصيغ shell وSQL، وحدود الطول.",
+ "catches": [
+ "اسم يبدو كاسم آخر على الشاشة أو في السجل أو في قائمة",
+ "اسم يُقطع أو يُقص أو يُعاد كتابته بين الرفع والتخزين",
+ "حد للطول يُحسب بالأحرف بينما يحسب التخزين بالبايتات"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "هل يُطبَّق حد الحجم تمامًا حيث أُعلن عنه؟",
+ "title": "حدود الحجم",
+ "pageTitle": "اختبار حد حجم الرفع - ملفات عند الحد تمامًا",
+ "description": "ملفات أقل بايتًا واحدًا من الحد الذي يعلنه نظامك، وعنده تمامًا، وأكثر منه بايتًا واحدًا، مع خطوات أوسع على الجانبين، وكل ملف مُعلَّم بما إذا كان يجب قبوله.",
+ "catches": [
+ "أخطاء الفرق بواحد عند الحد",
+ "خلط MB مع MiB، أي 4.8 بالمئة، وهذا كافٍ لتمرير ملف لا ينبغي أن يمر",
+ "حد يُطبَّق في المتصفح لا على الخادم"
+ ],
+ "details": {
+ "limit": "حد الحجم الذي يعلنه نظامك. كل شيء آخر يُقاس منه.",
+ "spread": "إلى أي مدى يمتد على جانبي الحد، كقائمة أحجام."
+ }
+ },
+ "tabular-import": {
+ "question": "هل يصمد استيراد الجداول عندي أمام ما تصدّره الأدوات الحقيقية؟",
+ "title": "استيراد الجداول",
+ "pageTitle": "ملفات اختبار استيراد CSV وExcel - الفواصل والعناوين",
+ "description": "ملفات CSV بفواصل أخرى ونهايات أسطر CR LF وبلا ترويسة وبعلامات اقتباس مختلفة، وجدول عريض جدًا، وكتاب Excel، وJSON بتخطيطات عدة.",
+ "catches": [
+ "ملف بفاصلة منقوطة يُقرأ كعمود واحد، لأن الفاصل افتُرض بدل أن يُبحث عنه",
+ "ملف CRLF يُقسَّم إلى صفوف مع صف فارغ بعد كل صف",
+ "جدول بلا ترويسة يُبتلع صف بياناته الأول كأسماء أعمدة",
+ "استيراد يحتفظ بالأعمدة التي يستطيع عرضها ويُسقط الباقي دون كلمة",
+ "قارئ يأخذ سجلات JSON سطرًا سطرًا ويتوقف عند أول مستند بمسافة بادئة"
+ ],
+ "details": {
+ "rows": "عدد الصفوف في الجدول. يُكتب الملف بالحجم الذي تُعبَّأ إليه هذه الصفوف تمامًا، لذا تتحرك الميزانية أعلاه مع هذه القيمة.",
+ "columns": "عدد الأعمدة في كل صف من الجدول. لحاصل ضرب الصفوف في الأعمدة سقف، وأي طلب يتجاوزه يُرفض قبل أن يُكتب أي شيء."
+ }
+ },
+ "text-encoding": {
+ "question": "هل يعرف قارئي ترميز الملف، أم يخمّن؟",
+ "title": "ترميز النص",
+ "pageTitle": "ملفات اختبار ترميز النص - UTF-8 وUTF-16 وBOM وCRLF",
+ "description": "النص نفسه بترميز UTF-8 وUTF-16LE وUTF-16BE، مع علامة ترتيب البايتات وبدونها، ونهايات أسطر CR LF وLF، لاختبار كيف يفك القارئ ترميز النص.",
+ "catches": [
+ "قارئ يفترض UTF-8 فيعرض ملف UTF-16 بحرف واحد من كل ثلاثة أو كصفوف من المربعات",
+ "علامة ترتيب بايتات تُقرأ كمحتوى، فيبدأ أول حقل في الاستيراد بثلاثة أحرف غريبة",
+ "مستورد يخمّن الترميز من البايتات الأولى ويخمّن بشكل مختلف مع ملف أطول",
+ "ملف CRLF يُقسَّم إلى صفوف مع صف فارغ بعد كل صف، أو حرف إرجاع الحامل يبقى داخل الحقل الأخير"
+ ],
+ "details": {
+ "sample": "حجم كل ملف في المجموعة. يخزّن UTF-16 بايتين لكل حرف، لذا يُرفض العدد الفردي."
+ }
+ },
+ "upload-validation": {
+ "question": "هل يقبل نموذج الرفع عندي ما يجب قبوله ويرفض الباقي؟",
+ "title": "التحقق من الرفع",
+ "pageTitle": "ملفات اختبار التحقق من الرفع - النوع والحجم والاسم",
+ "description": "ملفات لاختبار نموذج الرفع: أنواع مسموحة ومرفوضة، ومحتوى لا يطابق الامتداد، وحد الحجم على جانبيه، وأسماء خبيثة، ورفع جماعي.",
+ "catches": [
+ "حد يُطبَّق في المتصفح لا على الخادم",
+ "ملف SVG أو HTML يُؤخذ على أنه صورة أو نص عادي، وهي طريقة لتمرير سكربت عبر نموذج",
+ "ملف يُفحص بامتداده ولا يُفتح أبدًا، فيمر ملف PDF اسمه .jpg",
+ "نموذج يقرأ الجسم كله في الذاكرة قبل أن ينظر كم حجمه",
+ "رفع باسم PHOTO.JPG يُرفض بينما يُقبل photo.jpg، أو العكس",
+ "اسم فيه مسافات أو أقواس أو أحرف خارج ASCII يُكتب على القرص دون تغيير"
+ ],
+ "details": {
+ "limit": "حد الحجم الذي يعلنه نموذج الرفع عندك. تأخذ هذه المجموعة خطوة واحدة على كل جانب منه، ولملف عند كل مسافة شغّل الإعداد المسبق size-boundaries.",
+ "allow": "الأنواع التي يجب أن يقبلها نموذجك. يصير كل نوع ملفًا حقيقيًا من ذلك النوع، وتشكّل الشاهد الإيجابي للمجموعة كلها.",
+ "deny": "الامتدادات التي يجب أن يرفضها نموذجك. الامتداد الذي لا صيغة له في هذا الإصدار يحصل مع ذلك على ملف بهذا الاسم يحتوي نصًا عاديًا.",
+ "far-over": "إلى أي مدى يتجاوز الملف الكبير الوحيد الحد. أوقفه حيث لا يستحق كتابة أضعاف الحد مساحة القرص.",
+ "bulk": "عدد الملفات في الرفع الجماعي. الصفر يُخرج هذه المجموعة من المجموعة كليًا."
+ }
+ }
+ },
+ "commands": {
+ "generate": "توليد ملفات، من وصفة أو من خيارات",
+ "validate": "فحص وصفة دون كتابة شيء",
+ "verify": "فحص مجلد مقابل بيان",
+ "cleanup": "حذف الملفات التي يسردها بيان",
+ "recipe fmt": "طباعة وصفة بشكلها المستقر",
+ "preset": "بناء مجموعة ملفات من سؤال اختبار مُسمّى",
+ "formats": "سرد الصيغ التي يدعمها هذا الإصدار",
+ "damage": "سرد الطرق التي يستطيع بها هذا الإصدار إتلاف ملف عمدًا",
+ "tool": "أدوات صغيرة للملفات التي لديك بالفعل",
+ "version": "طباعة إصدار الأداة",
+ "license": "طباعة الرخصة ومعناها للملفات المولَّدة"
+ },
+ "outcomes": {
+ "accept": "ينبغي أن يقبل نظامك الملف.",
+ "reject": "ينبغي أن يرفض نظامك الملف.",
+ "sanitize": "ينبغي أن يقبل نظامك الملف وينظّفه، مثلًا بإعادة تسميته.",
+ "unspecified": "يعتمد على قواعد نظامك. أنت من يقرر، ثم تتحقق من أن ما يحدث هو ما قصدته."
+ },
+ "damages": {
+ "zero-head": "يكتب أصفارًا فوق أول بايتات الملف دون المساس بطوله. معظم القارئات تنظر إلى هناك أولًا، فيلاحظ هذا التلف كل شيء تقريبًا."
+ },
+ "terms": {
+ "oracleNone": "غير منطبق",
+ "int": "أي عدد صحيح",
+ "choice": "واحد من مجموعة ثابتة",
+ "bool": "صحيح أو خاطئ",
+ "size": "حجم مثل 2mb",
+ "text": "نص",
+ "pixels": "بكسل",
+ "paragraphs": "فقرات",
+ "rows": "صفوف",
+ "columns": "أعمدة",
+ "slides": "شرائح",
+ "hertz": "هرتز",
+ "megapixels": "ميغابكسل",
+ "million cells": "مليون خلية",
+ "entries per second": "إدخال في الثانية",
+ "files": "ملفات",
+ "sizes separated by commas": "أحجام مفصولة بفواصل",
+ "format ids separated by commas": "معرّفات صيغ مفصولة بفواصل",
+ "format ids separated by commas, or all": "معرّفات صيغ مفصولة بفواصل، أو all",
+ "extensions separated by commas": "امتدادات مفصولة بفواصل",
+ "the id of a format, as tfg formats lists them": "معرّف صيغة، كما يسردها tfg formats",
+ "the password, in plain text": "كلمة المرور، كنص عادي",
+ "any text": "أي نص",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "تاريخ مثل 2024-02-29 أو 2024-02-29T13:45:00+02:00، أو none"
+ },
+ "faq": [
+ {
+ "q": "بماذا يختلف عن dd أو fsutil أو truncate؟",
+ "a": "تلك الأوامر تعطيك ملفًا بالحجم الصحيح مملوءًا بلا شيء. ملف بحجم 2 MB باسم photo.png صُنع بهذه الطريقة ليس PNG، فكل ما يحلله فعلًا يرفضه لسبب خاطئ، ويمر اختبارك أيضًا لسبب خاطئ. هذه الأداة تنتج ملف PNG حقيقيًا بحجم 2 MB تمامًا يُفتح في عارض الصور، ويصل مع بيان عن كيفية معاملة نظامك له.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "هل هو مجاني، وهل يمكنني استخدامه في العمل؟",
+ "a": "نعم في الحالتين. صدر بموجب GPL-3.0 ولا يكلّف شيئًا. لا يوجد حساب ولا مفتاح ترخيص ولا مستوى مدفوع."
+ },
+ {
+ "q": "هل يمكنني استخدام الملفات المولَّدة في منتج مغلق المصدر؟",
+ "a": "نعم. الرخصة تشمل شيفرة الأداة لا ما تنتجه. الملفات والوصفات والبيانات المولَّدة مخرجات لا أعمال مشتقة، فيمكنك إيداعها وتوزيعها دون أي التزام."
+ },
+ {
+ "q": "هل تحتوي الملفات المولَّدة على بيانات شخصية حقيقية؟",
+ "a": "لا. كل ما بداخلها يُركَّب من بذرة. لا تُقرأ أي مجموعة بيانات، ولا يُتصل بأي خدمة، ولا يُضمَّن أي محتوى من طرف ثالث. عامل عنوان البريد الإلكتروني المولَّد على أنه غير صالح للاستخدام لا على أنه غير مستخدم، لأن أي سلسلة عشوائية قد تتطابق مصادفة مع سلسلة حقيقية."
+ },
+ {
+ "q": "هل سأحصل على الملفات نفسها تمامًا على جهاز آخر؟",
+ "a": "نعم، بايتًا ببايت، مع الوصفة نفسها والبذرة نفسها. يختبر المشروع ذلك مع كل تغيير، وكسره يتطلب رفع الإصدار الرئيسي. وهذا ما يتيح لك إيداع وصفة صغيرة بدل بيانات اختبار ثنائية كبيرة."
+ },
+ {
+ "q": "هل يحتاج إلى اتصال بالإنترنت؟",
+ "a": "أبدًا. لا توجد قياسات عن بُعد ولا فحص للتحديثات ولا عميل سحابي، والملف التنفيذي لسطر الأوامر لا تُترجَم فيه حزمة شبكة أصلًا. يعمل على جهاز بلا شبكة وداخل بيئة مؤسسية مغلقة."
+ },
+ {
+ "q": "ماذا يحدث إذا طلبت حجمًا لا تستطيع الصيغة بلوغه؟",
+ "a": "تحصل على خطأ يذكر الصيغة وأصغر حجم ممكن وسبب هذا الحد الأدنى وما يجب فعله بدلًا من ذلك، ولا يُكتب أي ملف. الأداة لا تقرّب الحجم بصمت أبدًا. وكل حد أدنى مذكور في صفحة الصيغ.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "هل يمكنني توليد ملف تالف عمدًا؟",
+ "a": "نعم. أضف --damage zero-head فيخرج الملف بالحجم الذي طلبته تمامًا، وأول بايتاته مكتوب فوقها أصفار، فترفضه القارئة، ويقول البيان إن نظامك ينبغي أن يرفضه. التفاصيل في صفحة ملفات الاختبار التالفة.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "ما الصيغ القادمة؟",
+ "a": "7z وmp3 وmp4. تعمل اليوم {{ .Facts.FormatCount }} صيغة من البداية إلى النهاية."
+ },
+ {
+ "q": "على أي أنظمة يمكنني تشغيله؟",
+ "a": "يعمل سطر الأوامر على ويندوز ولينكس على معالجات Intel وARM، وعلى أجهزة ماك بمعالجات Apple Silicon. تُقدَّم نافذة سطح المكتب لويندوز على Intel، ولينكس على Intel، وأجهزة ماك بمعالجات Apple Silicon. أجهزة ماك بمعالجات Intel غير مدعومة ولا يُبنى لها شيء."
+ },
+ {
+ "q": "هل أحتاج إلى تثبيت شيء؟",
+ "a": "لا. نزّل الأرشيف الخاص بنظامك وفك ضغطه وشغّل الملف التنفيذي. لا يوجد مثبّت ولا بيئة تشغيل تُضاف ولا اعتماديات تُحل. وإذا كان لديك Go فيكفي أمر go install واحد أيضًا.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "لماذا يكون التشغيل على آلاف الملفات أبطأ على ويندوز؟",
+ "a": "لأن ويندوز يتقاضى أكثر عن كل مسار ينظر فيه، والأمر الذي يمر على آلاف الملفات ينظر في آلاف المسارات. قيس على جهاز واحد فيه 3000 ملف بحجم 1 kB، فاستغرق verify نحو 0.9 ثانية على ويندوز ونحو 0.2 ثانية على لينكس داخل حاوية. ويصغّر مسار الإخراج الأقصر رقم ويندوز، لأن كل مجلد فوق الملفات جزء مما يُنظر فيه."
+ }
+ ]
+}
diff --git a/web/content/ar/use-cases.html b/web/content/ar/use-cases.html
new file mode 100644
index 00000000..5f7347c7
--- /dev/null
+++ b/web/content/ar/use-cases.html
@@ -0,0 +1,124 @@
+
فيمَ يستخدمه الناس
+
+ خمس مهام تظهر في كل مشروع تقريبًا يقبل ملفات من الناس، والأمر الذي ينفذ كلًّا منها. كل مثال أدناه
+ يعمل كما هو مكتوب.
+
+
+
+
حدود الرفع
+
اختبار ما إذا كان حد حجم الملف يُطبَّق حيث يقول إنه يُطبَّق
+
+ الحد ثلاث حالات اختبار لا حالة واحدة: أقل منه بقليل، وعنده تمامًا، وأعلى منه بقليل. الحصول عليها
+ يدويًا يعني حساب أعداد البايتات والأمل في ألا تخطئ بواحد. اطلب المجموعة بدلًا من ذلك:
+
+ تحصل على ثلاثة ملفات PDF حقيقية بحجم 1048575 و1048576 و1048577 بايتًا، وبيان يقول إن الأولين يجب
+ قبولهما والثالث يُرفض بسبب size_limit. يقرأ اختبارك التوقّع بدل أن تكتب ثلاثة
+ تأكيدات يدويًا، وحين يتغير الحد تغيّر رقمًا واحدًا وتعيد التشغيل.
+
+
+ ويعمل الأمر نفسه دون إعداد مسبق حين تريد مجموعة حدود واحدة داخل الأمر:
+
+ بيانات الاختبار الثنائية الكبيرة تُبطئ استنساخ المستودع وتُصعّب مراجعته، ولا أحد يعرف ما الذي تغيّر
+ حين تُستبدل واحدة. الوصفة بضع مئات من أحرف YAML تعيد بناء الملفات المطابقة، بايتًا ببايت
+ وعلى أي جهاز، لأن كل ملف مشتق من بذرة التشغيل.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ لكل نهاية رمز خروج خاص بها، فيستطيع خط البناء التمييز بين وصفة سيئة وقرص ممتلئ وعدم تطابق في التحقق.
+ والتشغيل الفاشل لا يطبع شيئًا على المخرج القياسي، فلا يقرأ محلل السجلات خطأً على أنه بيانات.
+
+
+
+
+
الحجم الكبير
+
معرفة ما يحدث حين يكون المجلد كبيرًا
+
+ تتصرف روتينات الاستيراد والمهام الليلية وقوائم المجلدات بشكل مختلف عند عشرة آلاف ملف عنه عند عشرة.
+ الأحجام المسحوبة من نطاق تجعل المجموعة تبدو كحركة حقيقية لا كعشرة آلاف ملف متطابق، ويأتي السحب
+ من البذرة، فتكون المجموعة نفسها غدًا.
+
+ عمق التداخل وعدد العناصر وحجم ما بالداخل كلها أمور لروتين الاستيراد رأي فيها، وهكذا تعرف ما هي تلك
+ الآراء.
+
+
+
+
+
المحللات والعارضات
+
التحقق من أن شيفرتك تقرأ الصيغة كما يفعل البرنامج الحقيقي
+
+ كل صيغة هنا تُفحص بقارئ مستقل قبل إصدارها: يُفتح PNG وتُقارَن بكسلاته، ويُقرأ DOCX من جديد بمكتبات
+ منفصلة، ويُفك أرشيف. وهذا يعني أن ملفًا يرفضه محللك هو نتيجة عن محللك، لا عن المولّد.
+
+ تسرد صفحة الصيغ الإعدادات التي تقبلها كل صيغة وأصغر ملف يمكن أن تكونه.
+
+
+
+
+
أدلة
+
اثنان منها بتفصيل أكبر
+
+
+ ملفات اختبار تالفة - ملف أُتلف عمدًا بحجم دقيق، وما ينبغي أن
+ يحدث له مكتوب في البيان.
+
+
+ ملفات الاختبار في CI - سير عمل لـ GitHub Actions ومهمة في GitLab
+ ورموز الخروج التي تُفشل البناء.
+
+
+
+
+
+
لمن هذا
+
+ لمهندسي ضمان الجودة وأتمتة الاختبار، ولكل من خلف شيفرته نموذج رفع أو روتين استيراد أو محلل أو حصة
+ تخزين. يعمل على جهاز بلا شبكة إطلاقًا، وهذا مهم في بيئة مؤسسية مغلقة لا يكون فيها المولّد القائم
+ على المتصفح خيارًا.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/cs/ci.html b/web/content/cs/ci.html
new file mode 100644
index 00000000..e522a130
--- /dev/null
+++ b/web/content/cs/ci.html
@@ -0,0 +1,187 @@
+{{ with .Up }}
+ Binární fixture v repozitáři zůstává navždy v jeho historii, nedá se posoudit v diffu a při velkém
+ souboru přestává být možný. Generujte soubory raději v pipeline z receptu. Recept je text, bajty
+ vycházejí pokaždé stejné a poslední krok dokáže, že se nic nepohnulo.
+
+
+
+
Stručná odpověď
+
+ Nainstalujte tfg, před testy spusťte tfg generate fixtures.yaml --out
+ ./fixtures a po nich tfg verify ./fixtures/manifest.json. Oba kroky shodí
+ build samy, s návratovým kódem, který říká proč.
+
+
+
+
+
Proč je necommitovat
+
Proč fixture nepatří do repozitáře
+
+
+ Zůstává v historii. Pozdější smazání binárního souboru klon nezmenší, protože každá
+ jeho verze je tam pořád.
+
+
+ Diff neukáže, co se změnilo. Recenzent vidí, že PDF je jiné, a nic víc. Recept se
+ změní o jeden řádek.
+
+
+ Velké soubory se nevejdou. GitHub odmítne push, který obsahuje soubor větší než 100
+ MB, takže test limitu nahrávání 500 MB nemá co commitovat.
+
+
+
+ Commitovat je třeba recept. Stejný recept a stejný seed zapíší na každém počítači stejné bajty,
+ takže soubor vygenerovaný v pipeline je soubor, který jste měli na notebooku.
+
+
+
+
+
Recept
+
Recept, který leží vedle testů
+
+ Tento zapíše pětadvacet faktur, které se mají přijmout, a dva obrázky nad limitem, které se mají
+ odmítnout, a manifest zaznamená obě očekávání:
+
+ Řádek s kontrolním součtem porovná archiv se souborem verify-SHA256SUMS.txt ze stejného
+ vydání. Verze je pevně daná, takže nové vydání nikdy nezmění build, na který jste nesáhli.
+
+ Každý konec má vlastní návratový kód, takže krok selže sám a log řekne který. Ty, které pipeline
+ potká:
+
+
+
3 - recept není platný. Nic se nezapsalo a každý problém je pojmenován
+
4 - formát neumí, co se chtělo, například velikost pod svým minimem
+
6 - na disku není dost místa
+
7 - tfg verify našel soubor, který nesedí s manifestem
+
8 - běh skončil, ale ne všechno se vytvořilo
+
+
+ Neúspěšný běh nevypíše nic na standardní výstup, takže parser logů nikdy nevezme chybu za data. Celá
+ tabulka je na stránce dokumentace.
+
+
+
+
+
PowerShell
+
Skript PowerShellu potřebuje ještě jeden řádek
+
+ PowerShell nevynese návratový kód programu ze souboru .ps1. Spusťte ho s
+ -File a skript odpoví 0, i když nástroj uvnitř práci odmítl, takže
+ build, který měl být červený, zezelená. Poslední řádek je celá oprava:
+
+ Tak se PowerShell chová, nejde o vlastnost tohoto nástroje. cmd, bash a
+ zsh nepotřebují nic navíc.
+
+
+
+
+
Více jobů
+
Sdílení fixtures mezi joby
+
+ Nahrávat je obvykle není třeba. Protože stejný recept zapisuje stejné bajty, může každý job spustit
+ vlastní tfg generate, což je rychlejší než nahrání a stažení. Když má job přijmout
+ soubory od jiného, spusťte po přenosu tfg verify nad manifestem a řekne vám, zda
+ to, co dorazilo, je to, co bylo zapsáno.
+
+ Validátor, kterému se ukazovaly jen zdravé soubory, nebyl opravdu otestován. Tady je postup, jak
+ získat soubor záměrně rozbitý, který vyjde přesně v požadované velikosti a nese
+ manifest říkající, co s ním má váš systém udělat.
+
+
+
+
Stručná odpověď
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out zapíše PNG o přesně
+ 2097152 bajtech, jehož první bajty jsou nuly, a manifest vedle něj zaznamená, že ho má váš
+ systém odmítnout.
+
+
+
+
+
Obvyklý způsob
+
Proč je ručně poškozený soubor špatný test
+
+ Obvykle se sáhne po hexadecimálním editoru, skriptu, který převrátí pár náhodných bajtů, nebo po
+ zkrácení souboru pomocí head či truncate. Jednou to funguje a pak to
+ stojí:
+
+
+
+ Pokaždé je to jiné. Náhodný bajt padne při každém spuštění jinam, takže chyba z
+ úterý se ve středu nemusí vrátit.
+
+
+ Mění to velikost. Zkrácený soubor je menší než limit, pod kterým měl zůstat, takže
+ kontrola velikosti odpoví dřív než kontrola obsahu a test projde z nesprávného důvodu.
+
+
+ Často si toho nikdo nevšimne. Prostý text se dá číst i se změněným bajtem uprostřed
+ a shovívavá čtečka obrázků ho prostě vykreslí, takže soubor, který měl být rozbitý, se přijme.
+
+
+ Neříká, co se má stát. Soubor jsou jen bajty a ten, kdo test čte později, musí
+ hádat, zda se mělo přijmout, nebo odmítnout.
+
+
+
+
+
+
Co dostanete
+
Poškozený soubor má stále velikost, kterou jste chtěli
+
+ Soubor se vygeneruje normálně a poškodí se až potom, cestou na disk. Zachová velikost, kterou jste
+ chtěli, a stejný příkaz zapíše znovu stejné bajty.
+
+ Nastavení se píše za dvojtečku. Přepínač lze opakovat a poškození se použijí v pořadí, v jakém je
+ zapíšete. Funguje s každým z {{ .Facts.FormatCount }} formátů.
+
+
+
+
+
Co umí
+
Jaká poškození existují?
+
+ Toto je seznam, který program vypisuje, načtený z něj při sestavení této stránky. tfg
+ damage vypíše totéž a tfg damage <id> řekne, co které z nich přijímá.
+
+ {{ template "damagesTable" . }}
+
+ zero-head zapíše nuly přes začátek souboru. Většina čteček se dívá nejdřív tam, na
+ signaturu a hlavičku, které říkají, co soubor je, takže si toho všimne téměř každá. Prostý text
+ a logy signaturu nemají a odmítnou se také, protože řada nulových bajtů není text. Pod čtyřmi
+ bajty některé formáty vyjdou s poškozením, na které si žádná čtečka nestěžuje, proto nastavení
+ začíná na čtyřech.
+
+
+
+
+
Co říká manifest
+
Manifest, který říká, co se má stát
+
+ Každý poškozený soubor dostane záznam, že ho má váš systém odmítnout, s poškozením zapsaným vedle:
+
+ Dva požadavky se odmítnou dřív, než se cokoli zapíše, protože každý by na disku nechal soubor, který
+ manifest popisuje špatně:
+
+
+
soubor menší, než poškození potřebuje, který by vyšel nezměněný
+
+ expected: accept vedle poškození, protože by to nic nemohlo splnit. Napište
+ sanitize, pokud má váš systém soubor opravit, nebo unspecified,
+ pokud je právě to vaše otázka
+
+
+
+
+
+
V receptu
+
Zdravé a rozbité soubory v jednom běhu
+
+ Dejte obojí do jednoho receptu a manifest ponese očekávání každého souboru, takže test nepotřebuje
+ seznam, který je který:
+
+ Test přečte manifest a ověří, že to, co se stalo, je to, co bylo uvedeno. Nepotřebuje seznam názvů
+ souborů:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Dobré odmítnutí je čisté. Zpráva, která říká, co bylo špatně, je odpověď, kterou chcete. Chyba
+ serveru, zaseknutí nebo napůl uložený soubor je vada, kterou má tento test najít.
+
+ Dokumentace obsahuje každý přepínač tfg generate.
+
+
+
diff --git a/web/content/cs/docs.html b/web/content/cs/docs.html
new file mode 100644
index 00000000..3c3423b0
--- /dev/null
+++ b/web/content/cs/docs.html
@@ -0,0 +1,276 @@
+
Dokumentace
+
+ Vše, co nástroj dělá, uspořádané podle otázek, se kterými lidé skutečně přicházejí.
+ README v repozitáři je úplná reference a vždy odpovídá verzi,
+ kterou jste stáhli.
+
+
+
+
Jaké příkazy existují?
+
Každý dělá jednu věc:
+ {{ template "commandList" . }}
+
+
+
+
Jak vygeneruji jeden soubor přesné velikosti?
+
+ Uveďte formát, velikost a kam soubor půjde. Velikosti se počítají po 1024, takže 2mb je
+ 2097152 bajtů. Funguje i prostý počet bajtů, takže --size 10485761 žádá přesně
+ tolik.
+
+
tfg generate --format png --size 2mb --out ./out
+
Užitečné přepínače příkazu generate:
+
+
+
Přepínač
Co dělá
+
+
--format <id>
formát souborů, například txt
+
--size <size>
přesná velikost každého souboru, například 10mb nebo prostý počet bajtů
+
--size-range <a-b>
velikost losovaná pro každý soubor z rozsahu, například 1kb-8kb. Losování vychází ze seedu
+
--boundary <size>
tři soubory kolem limitu: o bajt pod, limit, o bajt nad
+
--count <n>
kolik souborů vytvořit. Výchozí 1
+
--name <template>
šablona názvu, například invoice_{index:04}.txt
+
--out <dir>
adresář, do kterého se zapisuje
+
--seed <n>
seed běhu. Stejný seed dává stejné bajty
+
--set <k>=<v>
nastavení formátu, lze opakovat
+
--damage <name>
záměrně soubory poškodit, lze opakovat a uplatňuje se v pořadí. Seznam získáte příkazem tfg damage
+
--expected <outcome>
accept, reject, sanitize nebo unspecified
+
--dry-run
spočítat a ukázat, nic nezapisovat
+
--json
zapsat manifest na standardní výstup
+
+
+
+
+
+
+
Jak vytvořím soubor, který je záměrně rozbitý?
+
+ Každý jiný soubor, který tento nástroj zapíše, je správný z konstrukce, což odpovídá na dvě ze tří
+ otázek, které klade validátor nahrávání. --damage odpovídá na třetí - zda se soubor
+ vůbec otevře. Soubor se vytvoří normálně a pak se rozbije, takže má stále velikost, o kterou
+ jste požádali.
+
+ Nastavení se zadávají za dvojtečku. Přepínač se opakuje a pořadí, v jakém je napíšete, je pořadí, v
+ jakém se uplatní. tfg damage vypíše, co tato verze umí a co která varianta přijímá.
+
+
V receptu je klíč seznam, a to názvů nebo nastavení:
+ Poškozený soubor dostane v manifestu expected: reject a vedle toho zaznamenané
+ poškození. Dvě věci jsou odmítnuty dříve, než se cokoli zapíše, protože každá by jinak dala na
+ disk soubor, který manifest popisuje špatně:
+
+
+
soubor menší, než poškození potřebuje, protože by vyšel beze změny
+
+ expected: accept vedle poškození, protože nic by to nemohlo splnit. Napište
+ sanitize, pokud má testovaný systém soubor opravit, nebo
+ unspecified, pokud je to právě ta otázka, kterou kladete
+
+
+
+ Třetí se předem zjistit nedá. Pokud se poškození provede a nepohne žádným bajtem, soubor se zahodí
+ místo zapsání - běh pokračuje, řekne, o který soubor šlo, a skončí s částečným návratovým kódem.
+
+ Recept je soubor YAML popisující celý běh. Commitujte ho vedle testů a fixtures přestanou být
+ binárkami ve vašem repozitáři - kdokoli je může bajt po bajtu znovu sestavit ze souboru o
+ několika stovkách znaků.
+
+ Každý target potřebuje přesně jeden z klíčů size, size-range,
+ boundary nebo contains. Dva jsou chyba a žádný také. Neplatný recept
+ nezapíše žádné soubory a nahlásí všechny problémy najednou, ne jen první, každý
+ s názvem nastavení, kterého se týká.
+
+
+
+
+
Jak deklaruji, co má můj systém se souborem udělat?
+
Krátká forma, když stačí výsledek, dlouhá forma, když záleží na důvodu:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Výsledky jsou accept, reject, sanitize a
+ unspecified. Důvody tvoří uzavřený seznam, aby podle nich mohl report seskupovat:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit a size_zero.
+
+
+ Důvod pojmenovává pravidlo, o které jde, ne verdikt. Proto může stejný důvod stát
+ pod oběma výsledky - soubor o bajt pod limitem je accept a pravidlo, o které jde,
+ je stále size_limit.
+
+
+
+
+
Co obsahuje manifest?
+
+ Zapisuje se vedle souborů na konci každého běhu, včetně přerušeného. Jedna položka na soubor:
+
+ recipe_hash se přidá, když běh pochází z receptu, a preset s
+ overrides, když pochází z předvolby, takže manifest lze vždy dohledat k tomu, co ho
+ vytvořilo.
+
+
+ Každá položka nese také target_id, id targetu v receptu, který soubor vytvořil, a
+ summary.by_target počítá soubory, ke kterým každý target dospěl. Recept s více
+ targety lze tak kontrolovat target po targetu, aniž by se četly názvy souborů.
+
+
+
+
+
Co je předvolba?
+
+ Hotová sada souborů, která odpovídá na běžnou testovací otázku, abyste sadu nemuseli navrhovat sami.
+ Předvolby jsou pod povrchem obyčejné recepty a eject recept vypíše, takže ho můžete
+ odtud upravit. Každá předvolba má vlastní stránku s tím, co obvykle
+ najde, co je v sadě a jaké nastavení přijímá.
+
+ show vám řekne, kolik by sada stála, než ji sestavíte, a otevřeně řekne, když je číslo
+ naším zástupným údajem, a ne vaším limitem.
+
+
+
+
+
Co znamenají návratové kódy?
+
+ Každý konec má svůj kód, strojově čitelný výstup jde na standardní výstup a neúspěšný běh tam
+ nevypíše nic. Tabulka je zmrazená smlouva - změna významu kódu vyžaduje novou hlavní verzi.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Běh zastavený pomocí Ctrl+C po sobě stále zanechá manifest a nikdy nenechá napůl zapsaný soubor,
+ takže zrušenou úlohu může následující stále uklidit.
+
+ Ano, stejný motor s oknem navrch, pro testování, které se neskriptuje. Není to osekaná verze: test
+ porovnává obě rozhraní schopnost po schopnosti a cokoli, co umí jen jedno z nich, musí být
+ deklarováno a zdůvodněno, ne tiše se rozcházet.
+
+
+ Obrazovky jsou jedna dávka, předvolby, více dávek najednou a O aplikaci. Ukáže, kolik by běh stál,
+ než cokoli zapíše, hlásí průběh a lze ho zrušit uprostřed, aniž by zanechal napůl zapsaný
+ soubor. Soubor receptu zatím neotevře - recepty jsou zatím záležitostí příkazového řádku a okno
+ sestavuje své dávky ve formuláři.
+
+
diff --git a/web/content/cs/exact-size.html b/web/content/cs/exact-size.html
new file mode 100644
index 00000000..2d8185e4
--- /dev/null
+++ b/web/content/cs/exact-size.html
@@ -0,0 +1,143 @@
+
Jak vytvořit soubor přesné velikosti
+
+ Každý systém na to má příkaz a všechny tři jsou níže. Dají vám soubor s přesně správným počtem bajtů
+ - a pro mnoho testů je to vše, co potřebujete. Každý příkaz na této stránce byl před
+ zveřejněním spuštěn na systému, kam patří.
+
+
+
+
Krátká odpověď
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Velikosti jsou v bajtech a 10 MB
+ počítané tak, jak je počítá váš správce souborů, je 10485760.
+
+
+
+
+
Windows
+
fsutil a verze v PowerShellu, která nepotřebuje nic navíc
+
+ fsutil je součástí Windows. Bere velikost v bajtech, takže si číslo
+ nejdřív spočítejte - 10 MB je 10485760, 100 MB je 104857600, 1 GB je 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Změřeno na Windows 11: funguje z běžného příkazového řádku a nepotřebuje zvýšená oprávnění a soubor
+ vyjde přesně na 10485760 bajtů.
+
+
PowerShell umí totéž bez volání jiného programu a rozumí jednotkám:
+ 10MB v PowerShellu znamená 10485760 bajtů, tedy stejné počítání po 1024 jako
+ Průzkumník, takže oba příkazy výše vytvoří stejnou velikost.
+
+
+
+
+
Linux
+
dd, truncate a fallocate a rozdíl, který lidi chytí
+
dd zná každý. Bajty skutečně zapisuje:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate je okamžitý, a to je ten háček. Změřeno na Alpine Linuxu: soubor hlásí
+ 10485760 bajtů a zabírá nula bloků - je to řídký soubor.
+ Cokoli, co ho čte, dostane deset megabajtů nul, ale disk místo nikdy neuvolnil:
+
+
truncate -s 10M test10mb.bin
+
+ To stačí k testu limitu nahrávání a klame to při testu diskové kvóty. fallocate je ten
+ správný, když musí být místo skutečné:
+
+
fallocate -l 10M test10mb.bin
+
A když musí být obsah nestlačitelný, aby ho archivátor nemohl znovu zmenšit:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, který není řídký, a dva, které už znáte
+
+ macOS dodává mkfile. Změřeno na macOS 26.6.2: 10485760 bajtů a 20480 bloků, takže místo
+ je skutečně přiděleno, ne jen slíbeno:
+
+
mkfile 10m test10mb.bin
+
dd a truncate tam jsou také a chovají se jako na Linuxu:
Soubor správné velikosti není soubor správného druhu
+
+ Vše výše vám dá blok nul. To stačí, když testovaná věc hledí jen na velikost - limit nahrávání,
+ kvótu, přenos. Přestane to stačit ve chvíli, kdy soubor cokoli otevře.
+
+
+ Změřeno a stojí za to to zkusit samostatně: vytvořte pomocí fsutil soubor o 2 MB,
+ pojmenujte ho photo.png a předejte ho knihovně pro obrázky. Pillow odpoví
+ cannot identify image file. Není to PNG. Nikdy nebylo - tvrdil to jen název.
+
+
+ To je důležitější, než to zní, kvůli tomu, jakým směrem test pak selže. Váš
+ endpoint pro nahrávání soubor odmítne, váš test zezelená a vy usoudíte, že limit velikosti
+ funguje. Neodmítl ho kvůli velikosti. Odmítl ho proto, že bajty nebyly obrázek, a pravidlo,
+ které jste chtěli otestovat, nebylo nikdy dosaženo.
+
+
+
parser ho odmítne dřív, než se podívá na jakékoli pravidlo velikosti
+
selže krok náhledu a chyba, kterou čtete, je o náhledu
+
antivirus nebo kontrola obsahu ho odmítne z třetího důvodu
+
prohlížeč nezobrazí nic a nikdo nepozná, zda je to ta chyba
+
+
+
+
+
Druhá cesta
+
Skutečný soubor toho formátu, v přesně té velikosti, o kterou jste požádali
+
+ To je to, co dělá Testing Files Generator. Soubor je pravý soubor svého formátu - otevře se v
+ programu, kam patří - a má přesný počet bajtů, o který jste požádali, na bajt:
+
+ Požádejte o velikost, které formát nedosáhne, a dostanete chybu, která pojmenuje minimum a jeho
+ důvod, nikdy soubor špatné velikosti. Stránka formátů uvádí každý
+ formát s nejmenším souborem, který umí vytvořit.
+
+
A limit jsou tři testovací případy, ne jeden, takže nástroj sestaví všechny tři:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ To vám dá 10485759, 10485760 a 10485761 bajtů a manifest, který říká, které má váš systém přijmout a
+ které odmítnout. Stránka případů použití to probírá spolu se
+ čtyřmi dalšími úlohami, pro které je určen.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Tak který použít?
+
+
+
Použijte příkaz systému
+
+ Když soubor nic neotevírá. Test limitu velikosti na endpointu, který kontroluje velikost jako první,
+ přenos, kvóta, plný disk. Je to jeden řádek a už je nainstalovaný.
+
+
+
+
Použijte skutečný generátor
+
+ Když soubor cokoli zpracovává, vykresluje, importuje nebo rozbaluje - a když zítra na jiném počítači
+ potřebujete stejné fixtures, bajt po bajtu.
+
+
+
+
+ Oba jsou na této stránce, protože oba mají část času pravdu. Chybou, které je třeba se vyhnout, je
+ použít první tam, kde je třeba druhý, a číst zelený test jako důkaz.
+
+
diff --git a/web/content/cs/faq.html b/web/content/cs/faq.html
new file mode 100644
index 00000000..fa0c9d42
--- /dev/null
+++ b/web/content/cs/faq.html
@@ -0,0 +1,19 @@
+
Často kladené otázky
+
+ Licence, soukromí, opakovatelnost a věci, které lidé ověřují, než generátor zařadí do build
+ pipeline. Pokud tu vaše otázka není, sledování issues je
+ otevřené.
+
{{ .Facts.FormatCount }} formátů souborů, každý generovaný v přesné velikosti
+
+ Každý z nich je skutečný soubor toho formátu. Otevře se v programu, kam patří, a má
+ přesně tolik bajtů, kolik jste požádali. Žádný není vycpávka z nul s přilepenou příponou.
+
+
+{{ template "formatsTable" . }}
+
+
+
Co znamenají sloupce
+
+
+
Nejmenší soubor
+
+ Nejméně bajtů, které tento nástroj pro daný formát přijme, včetně štítku, který zapisuje do souboru.
+ Požádejte o méně a dostanete chybu, která pojmenuje minimum a jeho důvod, nikdy soubor
+ špatné velikosti.
+
+
+
+
Úplnost
+
+ Jak úplný soubor je. full znamená, že ho přijme čtečka, která formát skutečně
+ zpracovává, ne jen že přípona souhlasí.
+
+
+
+
Ověřeno pomocí
+
+ Nezávislá čtečka, která otevře každý vygenerovaný soubor, než se formát vydá - samostatná
+ implementace, ne náš vlastní kód, který opravuje své vlastní úkoly.
+
+
+
+
+ Každý formát se také opakuje na bajt: stejný recept a stejný seed vytvoří na jakémkoli počítači
+ identické soubory, a to dělá z receptu bezpečnou věc k commitování místo samotných fixtures.
+
+
+
+
+
Nastavení, která každý formát přijímá
+
+ Většina formátů má vlastní nastavení - rozměry obrázku, kvalitu JPEG, počet stránek PDF, řádky a
+ sloupce v tabulce, kolik položek jde do archivu. Nastavte je pomocí --set key=value
+ v příkazovém řádku nebo pod properties: v receptu.
+
+ Hodnota mimo to, co nastavení přijímá, je odmítnuta zprávou, která pojmenuje nastavení, povolený
+ rozsah a co použít místo toho. Neznámé nastavení je také chyba, nikdy tichá výchozí hodnota -
+ tiše přijatý překlep dá soubor se špatným nastavením a hodinu přemýšlení, proč test prochází,
+ když neměl.
+
+
+ Spusťte tfg formats <id> a uvidíte přesně, co jeden formát v dané verzi přijímá.
+
+
+
+
+
Archivy obsahují skutečné soubory
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} a {{ end }}{{ $c.ID }}{{ end }} lze
+ naplnit položkami, místo aby zůstaly prázdnou skořápkou. Vygenerovaný archiv skutečně obsahuje
+ dokumenty, které tvrdí, že obsahuje, takže cokoli ho během testu rozbalí, uvnitř najde skutečné
+ soubory.
+
Generujte skutečné testovací soubory v přesné velikosti
+
+ PDF, PNG, DOCX, ZIP - celkem {{ .Facts.FormatCount }} formátů a každý je skutečný
+ soubor, který se otevře v programu, kam patří, v přesně té velikosti, o kterou jste
+ požádali. Každý běh také zapisuje, co má vaše aplikace s každým souborem udělat.
+ Příkazový řádek a desktopové okno, zdarma a open source, celé na vašem počítači.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ Desktopové okno připravené zapsat dávku souborů. Za příkazovým řádkem běží stejný motor.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
skutečných formátů, každý se otevře v programu, kam patří
+
+
+ 1 bajt
+
přesnost každé požadované velikosti, nikdy mlčky nezaokrouhlená
+
+
+ 0
+
spojení kamkoli - žádný účet, žádná telemetrie, žádná kontrola aktualizací
+
+
+
+
+
Problém
+
Vytvořit jeden testovací soubor je snadné. Vytvořit těch správných tisíc je ta únavná část
+
Testujete software, který přijímá soubory od lidí. Dříve nebo později budete potřebovat:
+
+
PDF o přesně 10 MB, abyste zjistili, zda je limit nahrávání skutečný
+
tři soubory po obou stranách tohoto limitu, abyste zachytili chyby o jedna
+
10 000 souborů logu, abyste viděli, co udělá noční úloha, když je složka velká
+
ZIP, který skutečně obsahuje 200 dokumentů, ne prázdnou skořápku se správnou příponou
+
soubor o 4 GB, aniž byste ve svém repozitáři drželi soubor o 4 GB
+
stejné fixtures na notebooku i na build serveru, bajt po bajtu
+
+
+ To je to, co toto nahrazuje. Je určeno pro QA inženýry, automatizaci testů a každého, za jehož kódem
+ stojí formulář pro nahrávání, importní rutina, parser nebo kvóta úložiště.
+
+
+
+
+
Čím se liší
+
Jiné generátory končí u bajtů. Tento odpovídá na to, na co se váš test skutečně ptá
+
+ Složka souborů vás stále nechává rozhodovat, co má který dokazovat. Každý běh tady zapíše vedle
+ souborů manifest.json - prostý seznam všeho vytvořeného a u každé položky
+ deklarované očekávání.
+
+
Řekněme, že váš endpoint pro nahrávání povoluje 1 MB. Požádejte o tři soubory, které leží na té hranici:
Kde odpověď závisí na vaší vlastní politice, manifest to říká
+
+ Zapíše unspecified, místo aby vymýšlel očekávání. Generátor, který hádá, vytváří
+ falešná selhání a sada testů, která křičí vlk, bude vypnuta.
+
+
+
+
+
+
Předvolby
+
Vyberte otázku, získejte celou sadu
+
+ Předvolba je sada testovacích souborů navržená kolem jedné testovací otázky, abyste nemuseli
+ vymýšlet, které soubory co dokazují. Každá má stránku, která říká, co obvykle najde, co je v
+ sadě a jaké nastavení přijímá.
+
+ Deset tisíc souborů logu, každý mezi jedním a osmi kilobajty, s velikostmi losovanými ze seedu, aby
+ zítra vyšla stejná sada. Dejte každému běhu vlastní adresář - manifest je
+ jediný záznam o tom, co běh zapsal, takže nástroj odmítne zapsat druhý přes něj:
+
+ Velikosti se počítají po 1024, jak to dělá váš správce souborů, takže 2mb znamená
+ 2097152 bajtů. Funguje i prostý počet bajtů. Dokumentace pokrývá
+ recepty, manifest a návratové kódy.
+
+
+
+
+
Co získáte
+
Vytvořeno pro sadu testů, která běží bez dozoru
+
+
+
Přesná velikost, na bajt
+
Požádejte o 10485761 bajtů a dostanete přesně tolik. Velikost, které formát nedosáhne, je chyba s důvodem, nikdy soubor špatné velikosti.
+
+
+
{{ .Facts.FormatCount }} skutečných formátů
+
Ne vycpávkové nuly s příponou. Vygenerované PNG se otevře v prohlížeči obrázků, DOCX ve Wordu, ZIP se rozbalí. Každý formát je před vydáním ověřen nezávislými čtečkami.
+
+
+
Manifest, který je testovací orákulum
+
Cesta, velikost, SHA-256, formát, seed, verze nástroje - a co má váš systém se souborem udělat.
+
+
+
Opakovatelné
+
Stejný recept a stejný seed, stejné bajty, na jakémkoli počítači. Commitujte malý recept YAML místo velkých binárních fixtures.
+
+
+
Dvě rozhraní, jeden motor
+
Příkazový řádek vytvořený pro CI a desktopové okno pro průzkumné testování. Ani jedno není osekanou verzí druhého a test je porovnává schopnost po schopnosti.
+
+
+
Zcela offline
+
Žádný účet, žádný cloud, žádná telemetrie, žádná kontrola aktualizací. V binárce příkazového řádku není zkompilován vůbec žádný síťový zásobník.
+
+
+
+
+
+
Stažení
+
Vyberte verzi pro svůj systém
+
+ Rozbalte archiv a spusťte ho. tfg je příkazový řádek a tfg-gui je
+ desktopové okno. Není tu instalátor a nic, co by se do vašeho počítače přidávalo.
+
+ {{ template "downloadsTable" . }}
+
+
Co je podepsáno a co ne
+
+ Soubory ke stažení pro Windows a macOS jsou podepsané, takže se spustí bez varování o neznámém
+ vývojáři. Ty pro Linux ne, protože desktopový Linux nemá ekvivalent, kterým by je šlo
+ podepsat. Každý archiv je uveden v verify-SHA256SUMS.txt na stránce vydání, takže
+ můžete ověřit, co jste stáhli.
+
+ Předvolba {{ .ID }} sestaví jediným příkazem celou sadu skutečných testovacích souborů
+ pro tuto otázku a vedle nich manifest.json, který říká, jak má váš systém na každý
+ soubor reagovat. Vše níže se čte z programu při výchozích hodnotách této verze.
+
+
+{{ if .Catches }}
+
+
Co obvykle najde?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
Co je v sadě?
+
Při výchozích hodnotách, jak je hlásí tfg preset show {{ .ID }}:
+
+
+
+
Soubory
{{ .Budget.Files }}
+
Targety v receptu
{{ .Budget.Targets }}
+
Celková velikost
{{ .Bytes }} B
+
Formáty
{{ join .Budget.Formats ", " }}
+
+
+
+
A co od vašeho systému očekává manifest té sady:
+
+
+
+
Očekáváno
Význam
Soubory
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
Co můžete změnit?
+ {{- if .Settings }}
+
+
+
+
Nastavení
Přijímá
Výchozí
Co dělá
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Tato výchozí hodnota je náš zástupný údaj, ne hodnota vašeho systému. Zadejte vlastní.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
Tato předvolba nemá žádná nastavení. Sada je pokaždé stejná.
+ {{- end }}
+
+
+
+
Jak ji spustit?
+
Podívejte se, kolik by sada stála, sestavte ji, nebo si vezměte její recept k úpravě:
Nebo na ní stavte ve vlastním receptu vedle svých testů:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/cs/presets.html b/web/content/cs/presets.html
new file mode 100644
index 00000000..afab517a
--- /dev/null
+++ b/web/content/cs/presets.html
@@ -0,0 +1,31 @@
+
Předvolby testovacích souborů, jedna sada pro každou testovací otázku
+
+ Předvolba je celá sada testovacích souborů navržená kolem jedné otázky, s manifestem, který říká,
+ jak má váš systém na každý soubor reagovat. Vy vyberete otázku, nástroj sestaví sadu. Každá
+ předvolba má vlastní stránku s tím, co obvykle najde, co je v sadě a jaké nastavení přijímá.
+
+
+{{ template "presetsList" . }}
+
+
+
Čím se předvolba liší od receptu?
+
+ Pod povrchem ničím. Předvolba je recept, který za vás nástroj napíše z několika nastavení. tfg
+ preset eject tento recept vypíše, abyste si ho mohli ponechat vedle testů a upravovat, a
+ váš vlastní recept může na předvolbě stavět jedním řádkem, extends: preset:
+ následovaným jejím id.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Mohu výchozím hodnotám věřit?
+
+ U souborů ano. U čísla, které zná jen váš systém, například limitu formuláře pro nahrávání, je
+ výchozí hodnota naším zástupným údajem a nástroj to řekne pokaždé, když nějaký použije. Stránka
+ každé předvolby tato nastavení označuje a tfg preset show to řekne dřív, než se
+ cokoli zapíše.
+
+
diff --git a/web/content/cs/site.json b/web/content/cs/site.json
new file mode 100644
index 00000000..cc557440
--- /dev/null
+++ b/web/content/cs/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "cs",
+ "locale": "cs_CZ",
+ "name": "Čeština",
+ "dir": "cs",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Úvod",
+ "title": "Generátor testovacích souborů - přesná velikost, {{ .Facts.FormatCount }} formátů",
+ "description": "Bezplatný open source generátor testovacích souborů pro QA. Skutečné PDF, DOCX, PNG a ZIP v přesné velikosti a manifest s očekávanou reakcí vašeho systému."
+ },
+ {
+ "key": "formats",
+ "slug": "formaty",
+ "nav": "Formáty",
+ "title": "{{ .Facts.FormatCount }} podporovaných formátů souborů - PDF, DOCX, PNG, ZIP a další",
+ "description": "Všechny formáty, které generátor vytváří, nejmenší možný soubor každého z nich a jejich nastavení. Všech {{ .Facts.FormatCount }} se otevře ve svém programu."
+ },
+ {
+ "key": "presets",
+ "slug": "predvolby",
+ "nav": "Předvolby",
+ "title": "Předvolby testovacích souborů - hotové sady pro QA",
+ "description": "Hotové sady testovacích souborů, každá odpovídá na jednu otázku: limity nahrávání, názvy souborů, kódování, import tabulek, prázdné soubory a validace."
+ },
+ {
+ "key": "docs",
+ "slug": "dokumentace",
+ "nav": "Dokumentace",
+ "title": "Dokumentace - příkazy, recepty, manifest, návratové kódy",
+ "description": "Jak generovat testovací soubory z příkazového řádku nebo z receptu YAML, co obsahuje manifest a co znamená každý návratový kód při běhu v CI."
+ },
+ {
+ "key": "use-cases",
+ "slug": "pripady-pouziti",
+ "nav": "Případy použití",
+ "title": "Případy použití - limity nahrávání, fixtures pro CI, testy",
+ "description": "Test limitu velikosti nahrávání, opakovatelné fixtures pro CI, vygenerování deseti tisíc souborů a archivy naplněné skutečným obsahem."
+ },
+ {
+ "key": "exact-size",
+ "slug": "vytvoreni-souboru-presne-velikosti",
+ "nav": "Přesná velikost",
+ "title": "Vytvoření souboru přesné velikosti - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate a mkfile, každý změřený na svém systému, a proč takto vytvořený soubor není PDF ani PNG, když to test potřebuje."
+ },
+ {
+ "key": "faq",
+ "slug": "faq",
+ "nav": "FAQ",
+ "title": "FAQ - otázky ke generování testovacích souborů",
+ "description": "Čím se liší od dd a fsutil, zda lze soubory commitovat, zda se běhy opakují bajt po bajtu a co se stane, když nelze velikosti dosáhnout."
+ },
+ {
+ "key": "damage",
+ "slug": "poskozene-testovaci-soubory",
+ "nav": "Poškozené soubory",
+ "title": "Poškozené testovací soubory - rozbité soubory přesné velikosti",
+ "description": "Soubor záměrně rozbitý, přesné velikosti, s manifestem, který říká, že ho má váš systém odmítnout. Pro testování validace nahrávání a parserů.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "testovaci-soubory-v-ci",
+ "nav": "Testovací soubory v CI",
+ "title": "Testovací soubory v CI - GitHub Actions, GitLab CI a PowerShell",
+ "description": "Generujte testovací soubory v pipeline místo commitování binárek: workflow pro GitHub Actions, job v GitLabu, návratové kódy a past PowerShellu.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "Přejít na obsah",
+ "navLabel": "Hlavní",
+ "langLabel": "Jazyk",
+ "breadcrumbHome": "Úvod",
+ "imageAlt": "Testing Files Generator - skutečné testovací soubory v přesné velikosti s manifestem, který říká, jak má váš systém na každý z nich reagovat",
+ "schemaDescription": "Bezplatný open source generátor testovacích souborů pro QA. Vytváří skutečné soubory v {{ .Facts.FormatCount }} formátech v přesné velikosti a zapisuje manifest, který říká, jak má testovaný systém na každý z nich reagovat.",
+ "ctaDownload": "Stáhnout",
+ "ctaSource": "Zobrazit zdrojový kód",
+ "ctaNote": "Zdarma a open source, GPL-3.0. Žádná registrace. Stažené soubory pro Windows a macOS jsou podepsané a spustí se bez varování.",
+ "colFormat": "Formát",
+ "colName": "Název",
+ "colExtension": "Přípona",
+ "colSmallest": "Nejmenší soubor",
+ "colFidelity": "Úplnost",
+ "colChecked": "Ověřeno pomocí",
+ "colSetting": "Nastavení",
+ "colAccepts": "Přijímá",
+ "colSystem": "Systém",
+ "colCli": "Příkazový řádek",
+ "colWindow": "Desktopové okno",
+ "noBinary": "zatím bez binárky",
+ "colCode": "Kód",
+ "colMeaning": "Význam",
+ "footerBlurb": "Testovací soubory pro QA v přesné velikosti s manifestem, který říká, jak má váš systém na každý z nich reagovat.",
+ "footerProject": "Projekt",
+ "footerSource": "Zdrojový kód na GitHubu",
+ "footerReleases": "Stažení",
+ "footerIssues": "Nahlásit problém",
+ "footerSupport": "Podpořit projekt",
+ "footerPages": "Stránky",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. Vydáno pod licencí GNU General Public License, verze 3. Soubory, které vygenerujete, jsou vaše - licence se vztahuje na nástroj, ne na jeho výstup.",
+ "footerPrivacy": "Tento web odnikud nenačítá písma, skripty ani sledovače. Nenastavuje cookies.",
+ "notFoundTitle": "Tato stránka tu není",
+ "notFoundLead": "Adresa, kterou jste následovali, neodpovídá žádné stránce tohoto webu.",
+ "notFoundBack": "Přejít na úvodní stránku",
+ "read.format": "Formát každého souboru v sadě. Je to přepínač samotného nástroje a předvolba mu jen dává výchozí hodnotu.",
+ "readTakes.format": "id formátu ze stránky formátů",
+ "colDamage": "Poškození",
+ "colEffect": "Co dělá s bajty",
+ "colSettings": "Nastavení",
+ "noSettings": "žádné"
+ },
+ "endings": {
+ "0": "Vše fungovalo.",
+ "1": "Neočekávaná chyba uvnitř nástroje.",
+ "2": "Špatný příkaz nebo přepínač.",
+ "3": "Recept není platný.",
+ "4": "Formát neumí to, co bylo požadováno.",
+ "5": "Čtení nebo zápis selhal.",
+ "6": "Nedostatek místa na disku.",
+ "7": "verify našel nesrovnalost.",
+ "8": "Běh skončil, ale nebylo vytvořeno všechno.",
+ "130": "Přerušeno pomocí Ctrl+C.",
+ "143": "Zastaveno signálem, tak vypadá vypršení času v CI."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "Projde platný soubor tak malý, jak formát dovolí?",
+ "title": "Prázdné a minimální",
+ "pageTitle": "Nejmenší platné a prázdné testovací soubory v každém formátu",
+ "description": "Nejmenší platný soubor, který nástroj zapíše v každém ze svých {{ .Facts.FormatCount }} formátů, a prázdný soubor tam, kde to formát dovolí, vždy s očekávanou reakcí.",
+ "catches": [
+ "platný soubor odmítnutý jako příliš malý, protože kontrola počítá bajty místo toho, aby je četla",
+ "prázdný soubor, který shodí čtečku, místo aby byl nahlášen",
+ "obrázek široký jeden pixel, který cestou k náhledu dělí nulou",
+ "úložiště, které čte nula bajtů jako selhané nahrání a stále to opakuje"
+ ],
+ "details": {
+ "formats": "Z jakých formátů se sada skládá. Ponechte all pro všechny formáty této verze, nebo uveďte ty, které váš systém přijímá."
+ }
+ },
+ "filename-handling": {
+ "question": "Uloží, zobrazí a vrátí můj systém název souboru, který nečekal?",
+ "title": "Zacházení s názvy souborů",
+ "pageTitle": "Problematické názvy souborů pro testování - Unicode a délka",
+ "description": "Soubory s názvy, které rozbíjejí nahrávání a úložiště: jiná písma a emoji, přepsání směru textu, neviditelné znaky, syntaxe shellu a SQL, limity délky.",
+ "catches": [
+ "název, který na obrazovce, v logu nebo v seznamu vypadá jako jiný",
+ "název oříznutý, zkrácený nebo přepsaný mezi nahráním a uložením",
+ "limit délky počítaný ve znacích tam, kde úložiště počítá bajty"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "Je limit velikosti vynucován přesně tam, kde je deklarován?",
+ "title": "Hranice velikosti",
+ "pageTitle": "Test limitu velikosti nahrávání - soubory přesně na hranici",
+ "description": "Soubory o bajt pod, přesně na a o bajt nad limitem, který váš systém deklaruje, a širší kroky na obě strany, každý označený, zda má být přijat.",
+ "catches": [
+ "chyby o jedna na hranici limitu",
+ "MB zaměněné za MiB, což je 4,8 procenta a stačí to k propuštění souboru, který projít neměl",
+ "limit vynucovaný v prohlížeči a ne na serveru"
+ ],
+ "details": {
+ "limit": "Limit velikosti, který váš systém deklaruje. Vše ostatní se měří od něj.",
+ "spread": "Jak daleko na obě strany od limitu zajít, jako seznam velikostí."
+ }
+ },
+ "tabular-import": {
+ "question": "Přežije můj import tabulek to, co exportují skutečné nástroje?",
+ "title": "Import tabulek",
+ "pageTitle": "Testovací soubory pro import CSV a Excelu - oddělovače",
+ "description": "CSV s jinými oddělovači, konci řádků CR LF, bez hlavičky a s jinými uvozovkami, velmi široká tabulka, sešit Excelu a JSON v několika rozloženích.",
+ "catches": [
+ "soubor se středníky přečtený jako jediný sloupec, protože oddělovač se předpokládal, místo aby se hledal",
+ "soubor CRLF rozdělený na řádky s prázdným řádkem za každým",
+ "tabulka bez hlavičky, jejíž první datový řádek se spolkne jako názvy sloupců",
+ "import, který ponechá sloupce, které umí zobrazit, a zbytek beze slova zahodí",
+ "čtečka, která bere záznamy JSON po jednom řádku a zastaví se u prvního odsazeného dokumentu"
+ ],
+ "details": {
+ "rows": "Kolik řádků tabulka obsahuje. Zapisuje se přesně v takové velikosti, jakou tolik řádků zabere, takže rozpočet výše se s touto hodnotou posouvá.",
+ "columns": "Kolik sloupců má každý řádek tabulky. Řádky krát sloupce mají strop a požadavek nad ním je odmítnut dříve, než se cokoli zapíše."
+ }
+ },
+ "text-encoding": {
+ "question": "Ví moje čtečka, v jakém kódování soubor je, nebo hádá?",
+ "title": "Kódování textu",
+ "pageTitle": "Testovací soubory kódování textu - UTF-8, UTF-16, BOM, CRLF",
+ "description": "Stejný text v UTF-8, UTF-16LE a UTF-16BE, s označením pořadí bajtů i bez něj, a konce řádků CR LF a LF, k ověření, jak čtečka dekóduje text.",
+ "catches": [
+ "čtečka, která předpokládá UTF-8 a zobrazí soubor UTF-16 jako každý třetí znak nebo jako řady čtverečků",
+ "označení pořadí bajtů přečtené jako obsah, takže první pole importu začíná třemi cizími znaky",
+ "importér, který hádá kódování z prvních bajtů a u delšího souboru hádá jinak",
+ "soubor CRLF rozdělený na řádky s prázdným řádkem za každým, nebo návrat vozíku zůstávající v posledním poli"
+ ],
+ "details": {
+ "sample": "Jak velký je každý soubor sady. UTF-16 ukládá dva bajty na znak, takže lichý počet je odmítnut."
+ }
+ },
+ "upload-validation": {
+ "question": "Přijme můj formulář pro nahrávání to, co má, a zbytek odmítne?",
+ "title": "Validace nahrávání",
+ "pageTitle": "Testovací soubory validace nahrávání - typ, velikost a název",
+ "description": "Soubory k testu formuláře pro nahrávání: povolené a zakázané typy, obsah neodpovídající příponě, limit velikosti, nepřátelské názvy a hromadné nahrání.",
+ "catches": [
+ "limit vynucovaný v prohlížeči a ne na serveru",
+ "SVG nebo HTML považované za obrázek či prostý text, což je způsob, jak protlačit skript formulářem",
+ "soubor kontrolovaný podle přípony a nikdy neotevřený, takže PDF s názvem .jpg projde",
+ "formulář, který načte celé tělo do paměti, než se podívá, jak je velké",
+ "nahrání s názvem PHOTO.JPG odmítnuté tam, kde se photo.jpg přijme, nebo naopak",
+ "název s mezerami, závorkami nebo znaky mimo ASCII zapsaný na disk beze změny"
+ ],
+ "details": {
+ "limit": "Limit velikosti, který váš formulář pro nahrávání deklaruje. Tato sada udělá jeden krok na každou stranu - pro soubor v každé vzdálenosti spusťte předvolbu size-boundaries.",
+ "allow": "Které typy má váš formulář přijímat. Každý se stane skutečným souborem toho typu a tvoří pozitivní kontrolu celé sady.",
+ "deny": "Které přípony má váš formulář odmítat. Přípona, pro kterou tato verze nemá formát, přesto dostane soubor s tímto názvem, obsahující prostý text.",
+ "far-over": "Jak daleko za limit sahá jediný velký soubor. Vypněte, kde zapsání několikanásobku limitu nestojí za místo na disku.",
+ "bulk": "Kolik souborů obsahuje hromadné nahrání. Nula tuto skupinu ze sady úplně vynechá."
+ }
+ }
+ },
+ "commands": {
+ "generate": "vytvořit soubory z receptu nebo z přepínačů",
+ "validate": "zkontrolovat recept a nic nezapisovat",
+ "verify": "zkontrolovat adresář proti manifestu",
+ "cleanup": "odstranit soubory, které manifest uvádí",
+ "recipe fmt": "vypsat recept v ustáleném tvaru",
+ "preset": "sestavit sadu souborů z pojmenované testovací otázky",
+ "formats": "vypsat formáty, které tato verze podporuje",
+ "damage": "vypsat způsoby, jak tato verze umí soubor schválně poškodit",
+ "tool": "drobné pomůcky pro soubory, které už máte",
+ "version": "vypsat verzi nástroje",
+ "license": "vypsat licenci a co znamená pro generované soubory"
+ },
+ "outcomes": {
+ "accept": "Váš systém má soubor přijmout.",
+ "reject": "Váš systém má soubor odmítnout.",
+ "sanitize": "Váš systém má soubor přijmout a vyčistit, například přejmenováním.",
+ "unspecified": "Záleží na pravidlech vašeho systému. Rozhodnete vy, a pak ověříte, že to, co se stane, je to, co jste chtěli."
+ },
+ "damages": {
+ "zero-head": "Přepíše prvních několik bajtů souboru nulami a jeho délku nechá být. Většina čteček se dívá nejdřív tam, takže si tohoto poškození všimne téměř cokoli."
+ },
+ "terms": {
+ "oracleNone": "nelze použít",
+ "int": "libovolné celé číslo",
+ "choice": "jedna z pevné množiny",
+ "bool": "pravda nebo nepravda",
+ "size": "velikost, například 2mb",
+ "text": "text",
+ "pixels": "pixelů",
+ "paragraphs": "odstavců",
+ "rows": "řádků",
+ "columns": "sloupců",
+ "slides": "snímků",
+ "hertz": "hertzů",
+ "megapixels": "megapixelů",
+ "million cells": "milionů buněk",
+ "entries per second": "položek za sekundu",
+ "files": "souborů",
+ "sizes separated by commas": "velikosti oddělené čárkami",
+ "format ids separated by commas": "id formátů oddělená čárkami",
+ "format ids separated by commas, or all": "id formátů oddělená čárkami, nebo all",
+ "extensions separated by commas": "přípony oddělené čárkami",
+ "the id of a format, as tfg formats lists them": "id formátu tak, jak je vypisuje tfg formats",
+ "the password, in plain text": "heslo ve formě prostého textu",
+ "any text": "libovolný text",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "datum, například 2024-02-29 nebo 2024-02-29T13:45:00+02:00, nebo none"
+ },
+ "faq": [
+ {
+ "q": "Čím se to liší od dd, fsutil nebo truncate?",
+ "a": "Ty vám dají soubor správné velikosti plný ničeho. Soubor o 2 MB pojmenovaný photo.png vytvořený takto není PNG, takže ho cokoli, co ho skutečně zpracovává, odmítne z nesprávného důvodu a váš test pak projde také z nesprávného důvodu. Tohle vytvoří skutečné PNG o přesně 2 MB, které se otevře v prohlížeči obrázků, a přichází s prohlášením, jak s ním má váš systém naložit.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "Je to zdarma a mohu to používat v práci?",
+ "a": "Ano k obojímu. Je vydáno pod GPL-3.0 a nestojí nic. Není tu účet, licenční klíč ani placená úroveň."
+ },
+ {
+ "q": "Mohu generované soubory použít v produktu s uzavřeným zdrojovým kódem?",
+ "a": "Ano. Licence se vztahuje na kód nástroje, ne na to, co nástroj vytváří. Generované soubory, recepty a manifesty jsou výstup, nikoli odvozená díla, takže je můžete commitovat a dodávat bez jakékoli povinnosti."
+ },
+ {
+ "q": "Obsahují generované soubory skutečné osobní údaje?",
+ "a": "Ne. Vše uvnitř je syntetizováno ze seedu. Nečte se žádný datový soubor, nekontaktuje se žádná služba a nevkládá se obsah třetích stran. Vygenerovanou e-mailovou adresu považujte za nepoužitelnou, ne za nepoužitou, protože libovolný náhodný řetězec se může shodou okolností shodovat se skutečným."
+ },
+ {
+ "q": "Dostanu na jiném počítači přesně stejné soubory?",
+ "a": "Ano, bajt po bajtu, při stejném receptu a stejném seedu. Projekt to testuje při každé změně a porušit to vyžaduje novou hlavní verzi. Díky tomu můžete commitovat malý recept místo velkých binárních fixtures."
+ },
+ {
+ "q": "Potřebuje připojení k internetu?",
+ "a": "Nikdy. Není tu telemetrie, kontrola aktualizací ani cloudový klient a do binárky příkazového řádku není zkompilován žádný síťový zásobník. Funguje na počítači bez sítě i v uzavřeném firemním prostředí."
+ },
+ {
+ "q": "Co se stane, když požádám o velikost, které formát nedosáhne?",
+ "a": "Dostanete chybu, která pojmenuje formát, nejmenší možnou velikost, důvod tohoto minima a co dělat místo toho, a nezapíše se žádný soubor. Nástroj nikdy velikost mlčky nezaokrouhlí. Každé minimum je uvedeno na stránce formátů.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "Mohu vygenerovat soubor, který je záměrně rozbitý?",
+ "a": "Ano. Přidejte --damage zero-head a soubor vyjde v přesně požadované velikosti, s prvními bajty přepsanými nulami, takže ho čtečka odmítne, a manifest říká, že ho má váš systém odmítnout. Podrobnosti jsou na stránce o poškozených testovacích souborech.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "Které formáty přijdou dál?",
+ "a": "7z, mp3 a mp4. Dnes funguje od začátku do konce {{ .Facts.FormatCount }} formátů."
+ },
+ {
+ "q": "Na kterých systémech to mohu spustit?",
+ "a": "Příkazový řádek běží na Windows a Linuxu na Intelu i ARM a na Macích s Apple Silicon. Desktopové okno se dodává pro Windows na Intelu, Linux na Intelu a Macy s Apple Silicon. Intel Macy nejsou podporovány a nic se pro ně nesestavuje."
+ },
+ {
+ "q": "Musím něco instalovat?",
+ "a": "Ne. Stáhněte archiv pro svůj systém, rozbalte ho a spusťte binárku. Není tu instalátor, běhové prostředí k doplnění ani závislost k vyřešení. Pokud máte Go, funguje i jediný příkaz go install.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "Proč je běh nad tisíci soubory na Windows pomalejší?",
+ "a": "Protože Windows si účtuje víc za každou cestu, na kterou se podívá, a příkaz, který prochází tisíce souborů, se dívá na tisíce cest. Změřeno na jednom počítači s 3000 soubory po 1 kB: verify trvá na Windows asi 0,9 sekundy a na Linuxu v kontejneru asi 0,2 sekundy. Kratší výstupní cesta číslo na Windows zmenší, protože každá složka nad soubory je součástí toho, na co se dívá."
+ }
+ ]
+}
diff --git a/web/content/cs/use-cases.html b/web/content/cs/use-cases.html
new file mode 100644
index 00000000..3d2376fc
--- /dev/null
+++ b/web/content/cs/use-cases.html
@@ -0,0 +1,129 @@
+
K čemu to lidé používají
+
+ Pět úloh, které se objevují téměř v každém projektu přijímajícím soubory od lidí, a příkaz, který
+ každou provede. Každý příklad níže běží tak, jak je napsán.
+
+
+
+
Limity nahrávání
+
Test, zda je limit velikosti souboru vynucován tam, kde se tvrdí
+
+ Limit jsou tři testovací případy, ne jeden: těsně pod, přesně na něm a těsně nad. Získat je ručně
+ znamená počítat počty bajtů a doufat, že jste se nespletli o jedna. Požádejte raději o sadu:
+
+ Dostanete tři skutečná PDF o 1048575, 1048576 a 1048577 bajtech a manifest, který říká, že první dvě
+ mají být přijata a třetí odmítnuto pro size_limit. Váš test čte očekávání místo
+ toho, abyste ručně psali tři aserce - a když se limit změní, změníte jedno číslo a spustíte
+ znovu.
+
+
+ Totéž funguje bez předvolby, když chcete jedinou sadu hranic přímo v příkazu:
+
Držet fixtures mimo repozitář, aniž byste o ně přišli
+
+ Velké binární fixtures zpomalují klonování repozitáře a znepříjemňují revizi a nikdo nepozná, co se
+ změnilo, když se jeden vymění. Recept je pár set znaků YAML, které znovu sestaví totožné soubory
+ - bajt po bajtu, na jakémkoli počítači - protože každý soubor je odvozen ze
+ seedu běhu.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Každý konec má svůj vlastní návratový kód, takže pipeline rozliší špatný recept od plného disku a od
+ nesrovnalosti při ověření. Neúspěšný běh nevypíše na standardní výstup nic, takže parser logu
+ nečte chybu jako data.
+
+
+
+
+
Rozsah
+
Zjistit, co se stane, když je složka velká
+
+ Importní rutiny, noční úlohy a výpisy adresářů se chovají při deseti tisících souborů jinak než při
+ deseti. Velikosti losované z rozsahu dělají ze sady něco, co vypadá jako skutečný provoz, a ne
+ deset tisíc stejných souborů, a losování vychází ze seedu, takže sada je zítra stejná.
+
+ Běh větší než volné místo na disku je odmítnut dřív, než se zapíše první bajt, místo aby zaplnil
+ disk a selhal v půlce.
+
+
+
+
+
Archivy
+
Test rozbalovače s archivem, který skutečně obsahuje soubory
+
+ Prázdný archiv se správnou příponou nic nedokazuje o kódu, který ho otevírá a prochází, co je
+ uvnitř. Deklarujte obsah a archiv ho skutečně obsahuje:
+
+ Hloubka vnoření, počet položek a velikost toho, co je uvnitř, jsou věci, o kterých má importní
+ rutina názor, a takto zjistíte, jaké ty názory jsou.
+
+
+
+
+
Parsery a prohlížeče
+
Ověření, že váš vlastní kód čte formát tak, jak to dělá skutečný software
+
+ Každý formát zde je před vydáním ověřen nezávislou čtečkou - PNG se otevře a porovnají se jeho
+ pixely, DOCX čtou zpět samostatné knihovny, archiv se rozbalí. To znamená, že soubor, který váš
+ parser odmítne, je zjištění o vašem parseru, ne o generátoru.
+
+ Stránka formátů uvádí nastavení, která každý formát přijímá, a nejmenší
+ soubor, jakým každý může být.
+
+
+
+
+
Návody
+
Dva z nich podrobněji
+
+
+ Poškozené testovací soubory - soubor záměrně rozbitý,
+ přesné velikosti, s tím, co se s ním má stát, zapsaným v manifestu.
+
+
+ Testovací soubory v CI - workflow pro GitHub Actions, job
+ v GitLabu a návratové kódy, které shodí build.
+
+
+
+
+
+
Pro koho to je
+
+ QA inženýry, automatizaci testů a každého, za jehož kódem stojí formulář pro nahrávání, importní
+ rutina, parser nebo kvóta úložiště. Běží na počítači bez jakékoli sítě, na čem záleží v
+ uzavřeném firemním prostředí, kde generátor v prohlížeči není možnost.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/de/ci.html b/web/content/de/ci.html
new file mode 100644
index 00000000..95320a8f
--- /dev/null
+++ b/web/content/de/ci.html
@@ -0,0 +1,194 @@
+{{ with .Up }}
+ Ein binäres Fixture in einem Repository bleibt für immer in dessen Verlauf, lässt sich in einem Diff
+ nicht prüfen und geht bei großen Dateien gar nicht mehr. Erzeugen Sie die Dateien stattdessen in
+ der Pipeline aus einem Rezept. Das Rezept ist Text, die Bytes sind jedes Mal dieselben, und ein
+ letzter Schritt beweist, dass sich nichts verändert hat.
+
+
+
+
Die kurze Antwort
+
+ Installieren Sie tfg, führen Sie vor den Tests tfg generate fixtures.yaml --out
+ ./fixtures aus und danach tfg verify ./fixtures/manifest.json. Beide
+ Schritte lassen den Build von selbst scheitern, mit einem Exit-Code, der sagt, warum.
+
+
+
+
+
Warum nicht einchecken
+
Warum ein Fixture nicht im Repository liegen sollte
+
+
+ Es bleibt im Verlauf. Eine Binärdatei später zu löschen macht einen Klon nicht
+ kleiner, denn jede ihrer Versionen ist weiterhin da.
+
+
+ Ein Diff zeigt nicht, was sich geändert hat. Der Reviewer sieht, dass eine PDF
+ anders ist, und sonst nichts. Ein Rezept ändert sich um eine Zeile.
+
+
+ Große Dateien passen nicht. GitHub lehnt einen Push mit einer Datei über 100 MB ab,
+ also gibt es für den Test eines Upload-Limits von 500 MB nichts einzuchecken.
+
+
+
+ Einzuchecken ist das Rezept. Dasselbe Rezept mit demselben Seed schreibt auf jeder Maschine
+ dieselben Bytes, die in der Pipeline erzeugte Datei ist also die Datei, die Sie auf dem Laptop
+ hatten.
+
+
+
+
+
Das Rezept
+
Ein Rezept, das neben den Tests liegt
+
+ Dieses schreibt fünfundzwanzig Rechnungen, die angenommen werden sollen, und zwei Bilder über einem
+ Limit, die abgewiesen werden sollen, und das Manifest hält beide Erwartungen fest:
+
+ Die Prüfsummenzeile vergleicht das Archiv mit verify-SHA256SUMS.txt aus demselben
+ Release. Die Version ist festgelegt, ein neues Release ändert also nie einen Build, den Sie
+ nicht angefasst haben.
+
+ Jedes Ende hat seinen eigenen Exit-Code, der Schritt scheitert also von selbst, und das Log sagt,
+ welcher es war. Die, denen eine Pipeline begegnet:
+
+
+
3 - das Rezept ist ungültig. Es wurde nichts geschrieben, und jedes Problem wird genannt
+
4 - das Format kann nicht, was verlangt wurde, zum Beispiel eine Größe unter seinem Minimum
+
6 - es ist nicht genug Speicherplatz da
+
7 - tfg verify hat eine Datei gefunden, die nicht zu ihrem Manifest passt
+
8 - der Lauf ist fertig, aber nicht alles wurde erzeugt
+
+
+ Ein fehlgeschlagener Lauf gibt nichts auf der Standardausgabe aus, sodass ein Log-Parser nie einen
+ Fehler für Daten hält. Die ganze Tabelle steht auf der
+ Dokumentationsseite.
+
+
+
+
+
PowerShell
+
Ein PowerShell-Skript braucht eine Zeile mehr
+
+ PowerShell trägt den Exit-Code eines Programms nicht aus einer .ps1-Datei heraus.
+ Starten Sie eine mit -File, und das Skript antwortet 0, auch wenn das
+ Tool darin die Arbeit verweigert hat, sodass ein Build, der rot sein sollte, grün wird. Die
+ letzte Zeile ist die ganze Lösung:
+
+ So verhält sich PowerShell, es liegt nicht an diesem Tool. cmd, bash und
+ zsh brauchen nichts zusätzlich.
+
+
+
+
+
Mehrere Jobs
+
Fixtures zwischen Jobs teilen
+
+ Hochladen ist meist nicht nötig. Weil dasselbe Rezept dieselben Bytes schreibt, kann jeder Job sein
+ eigenes tfg generate ausführen, und das geht schneller als Hoch- und Herunterladen.
+ Muss ein Job Dateien von einem anderen erhalten, führen Sie nach der Übertragung tfg
+ verify auf dem Manifest aus, und es sagt, ob das Angekommene dem Geschriebenen
+ entspricht.
+
+ Ein Validator, dem man nur gesunde Dateien gezeigt hat, ist nicht wirklich getestet. So bekommen Sie
+ eine Datei, die absichtlich kaputt ist, genau die Größe hat, die Sie verlangen,
+ und ein Manifest mitbringt, das sagt, was Ihr System damit tun soll.
+
+
+
+
Die kurze Antwort
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out schreibt ein PNG
+ von genau 2097152 Byte, dessen erste Bytes Nullen sind, und das Manifest daneben hält fest, dass
+ Ihr System es ablehnen soll.
+
+
+
+
+
Der übliche Weg
+
Warum eine von Hand beschädigte Datei ein schlechter Test ist
+
+ Üblich sind ein Hex-Editor, ein Skript, das ein paar zufällige Bytes kippt, oder eine Datei, die mit
+ head oder truncate gekürzt wird. Das funktioniert einmal, und dann
+ kostet es Sie:
+
+
+
+ Es ist jedes Mal anders. Ein zufälliges Byte landet bei jedem Lauf woanders, ein
+ Fehler vom Dienstag kommt am Mittwoch womöglich nicht wieder.
+
+
+ Es verändert die Größe. Eine gekürzte Datei ist kleiner als das Limit, unter dem
+ sie liegen sollte, also antwortet die Größenprüfung vor der Inhaltsprüfung, und der Test
+ besteht aus dem falschen Grund.
+
+
+ Es fällt oft nicht auf. Reiner Text lässt sich mit einem geänderten Byte in der
+ Mitte weiterlesen, und ein nachsichtiger Bildleser zeichnet es einfach, sodass die Datei, die
+ kaputt sein sollte, angenommen wird.
+
+
+ Es sagt nichts darüber, was geschehen soll. Die Datei besteht nur aus Bytes, und
+ wer den Test später liest, muss raten, ob Annahme oder Ablehnung gemeint war.
+
+
+
+
+
+
Was Sie bekommen
+
Eine beschädigte Datei hat trotzdem die verlangte Größe
+
+ Die Datei wird normal erzeugt und erst danach auf dem Weg zur Festplatte beschädigt. Sie behält die
+ verlangte Größe, und derselbe Befehl schreibt wieder dieselben Bytes.
+
+ Einstellungen stehen nach einem Doppelpunkt. Die Option lässt sich wiederholen, und die
+ Beschädigungen werden in der Reihenfolge angewendet, in der Sie sie schreiben. Es funktioniert
+ mit allen {{ .Facts.FormatCount }} Formaten.
+
+
+
+
+
Was möglich ist
+
Welche Beschädigungen gibt es?
+
+ Das ist die Liste, die das Programm ausgibt, beim Erstellen dieser Seite aus ihm gelesen. tfg
+ damage gibt dieselbe aus, und tfg damage <id> sagt, was eine davon
+ annimmt.
+
+ {{ template "damagesTable" . }}
+
+ zero-head schreibt Nullen über den Anfang der Datei. Die meisten Leser schauen zuerst
+ dorthin, auf die Signatur und den Header, die sagen, was die Datei ist, deshalb bemerkt es fast
+ jeder Leser. Reiner Text und Logs haben keine Signatur und werden ebenfalls abgewiesen, weil
+ eine Folge von Nullbytes kein Text ist. Unter vier Bytes entstehen bei manchen Formaten Schäden,
+ über die sich kein Leser beschwert, deshalb beginnt die Einstellung bei vier.
+
+
+
+
+
Was das Manifest sagt
+
Ein Manifest, das sagt, was geschehen soll
+
+ Jede beschädigte Datei bekommt einen Eintrag, der besagt, dass Ihr System sie ablehnen soll, mit der
+ Beschädigung daneben:
+
+ Zwei Anfragen werden abgelehnt, bevor etwas geschrieben wird, denn jede würde eine Datei
+ hinterlassen, die das Manifest falsch beschreibt:
+
+
+
eine Datei, die kleiner ist, als die Beschädigung braucht, und unverändert herauskäme
+
+ expected: accept neben einer Beschädigung, weil nichts es erfüllen könnte. Schreiben
+ Sie sanitize, wenn Ihr System die Datei reparieren soll, oder
+ unspecified, wenn genau das Ihre Frage ist
+
+
+
+
+
+
In einem Rezept
+
Gesunde und kaputte Dateien in einem Lauf
+
+ Legen Sie beides in ein Rezept, dann trägt das Manifest die Erwartung jeder Datei, und der Test
+ braucht keine Liste, welche welche ist:
+
+ Der Test liest das Manifest und prüft, ob das, was geschah, dem Erklärten entspricht. Er braucht
+ keine Liste von Dateinamen:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Eine gute Ablehnung ist eine saubere. Eine Meldung, die sagt, was falsch war, ist die gewünschte
+ Antwort. Ein Serverfehler, ein Hänger oder eine halb gespeicherte Datei ist der Fehler, den
+ dieser Test finden soll.
+
+
+
+
+
Weiter
+
Wohin es von hier geht
+
+
+ Das Preset upload-validation stellt einem Formular die
+ beiden anderen Fragen, die nach Größe und die nach Typ.
+
+
+ Testdateien in CI führt ein Rezept wie dieses in einer Pipeline
+ aus.
+
+
diff --git a/web/content/de/docs.html b/web/content/de/docs.html
new file mode 100644
index 00000000..763b4e6c
--- /dev/null
+++ b/web/content/de/docs.html
@@ -0,0 +1,285 @@
+
Dokumentation
+
+ Alles, was das Tool kann, geordnet nach den Fragen, mit denen die Leute tatsächlich kommen. Die
+ README im Repository ist die vollständige Referenz und passt immer
+ zu dem Build, den du heruntergeladen hast.
+
+
+
+
Welche Befehle gibt es?
+
Jeder tut genau eine Sache:
+ {{ template "commandList" . }}
+
+
+
+
Wie erzeuge ich eine einzelne Datei in exakter Größe?
+
+ Nenne das Format, die Größe und das Ziel. Größen zählen in 1024ern, 2mb sind also
+ 2097152 Bytes. Eine einfache Byte-Zahl funktioniert auch, --size 10485761 verlangt
+ also genau so viele.
+
+
tfg generate --format png --size 2mb --out ./out
+
Die nützlichen Flags von generate:
+
+
+
Flag
Was es tut
+
+
--format <id>
Format der Dateien, zum Beispiel txt
+
--size <size>
exakte Größe jeder Datei, etwa 10mb oder eine einfache Byte-Zahl
+
--size-range <a-b>
eine Größe, die pro Datei aus einem Bereich gezogen wird, etwa 1kb-8kb. Die Ziehung kommt aus dem Seed
+
--boundary <size>
drei Dateien rund um ein Limit: ein Byte darunter, das Limit, ein Byte darüber
+
--count <n>
wie viele Dateien erzeugt werden. Standard 1
+
--name <template>
Namensvorlage, zum Beispiel invoice_{index:04}.txt
+
--out <dir>
Verzeichnis, in das geschrieben wird
+
--seed <n>
Seed des Laufs. Derselbe Seed ergibt dieselben Bytes
+
--set <k>=<v>
eine Formateinstellung, wiederholbar
+
--damage <name>
Dateien absichtlich beschädigen, wiederholbar und der Reihe nach angewendet. Mit tfg damage bekommst du die Liste
+
--expected <outcome>
accept, reject, sanitize oder unspecified
+
--dry-run
zählen und anzeigen, überhaupt nichts schreiben
+
--json
das Manifest auf die Standardausgabe schreiben
+
+
+
+
+
+
+
Wie erzeuge ich eine absichtlich kaputte Datei?
+
+ Jede andere Datei, die dieses Tool schreibt, ist per Konstruktion korrekt, was zwei der drei Fragen
+ beantwortet, die ein Upload-Validator stellt. --damage beantwortet die dritte -
+ lässt sich die Datei überhaupt öffnen. Die Datei wird normal erzeugt und dann beschädigt, sie
+ hat also weiterhin die verlangte Größe.
+
+ Einstellungen stehen hinter einem Doppelpunkt. Das Flag lässt sich wiederholen, und die Reihenfolge,
+ in der du sie schreibst, ist die Reihenfolge, in der sie angewendet werden. tfg
+ damage listet auf, was dieser Build kann und was jede Variante annimmt.
+
+
In einem Rezept ist der Schlüssel eine Liste, aus Namen oder aus Einstellungen:
+ Eine beschädigte Datei bekommt im Manifest expected: reject, mit der daneben
+ festgehaltenen Beschädigung. Zwei Dinge werden abgelehnt, bevor etwas geschrieben wird, weil
+ sonst jeweils eine Datei auf die Platte käme, die das Manifest falsch beschreibt:
+
+
+
eine Datei, die kleiner ist, als die Beschädigung braucht, weil sie unverändert herauskäme
+
+ expected: accept neben einer Beschädigung, weil es keine Datei geben kann, die das
+ erfüllt. Schreibe sanitize, wenn das getestete System die Datei reparieren soll,
+ oder unspecified, wenn genau das die Frage ist, die du stellst
+
+
+
+ Eine dritte lässt sich nicht im Voraus wissen. Wenn eine Beschädigung läuft und kein Byte verändert,
+ wird diese Datei verworfen statt geschrieben - der Lauf macht weiter, sagt, um welche Datei es
+ ging, und endet mit dem Exit-Code für teilweise erfolgreiche Läufe.
+
+ Ein Rezept ist eine YAML-Datei, die einen ganzen Lauf beschreibt. Checke sie neben deinen Tests ein,
+ und die Fixtures sind keine Binärdateien mehr in deinem Repository - jeder kann sie Byte für
+ Byte aus einer Datei von wenigen hundert Zeichen neu erzeugen.
+
+ Jedes Target braucht genau eines von size, size-range,
+ boundary oder contains. Zwei davon sind ein Fehler, und keines
+ ebenfalls. Ein ungültiges Rezept schreibt überhaupt keine Dateien und meldet
+ alle Probleme auf einmal statt nur das erste, jedes mit der Einstellung, um die es geht.
+
+
+
+
+
Wie lege ich fest, was mein System mit einer Datei tun soll?
+
Kurzform, wenn das Ergebnis reicht, Langform, wenn der Grund zählt:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Die Ergebnisse sind accept, reject, sanitize und
+ unspecified. Die Gründe sind eine geschlossene Liste, damit ein Report danach
+ gruppieren kann: content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit und
+ size_zero.
+
+
+ Ein Grund benennt die Regel, um die es geht, nicht das Urteil. Deshalb kann
+ derselbe Grund unter beiden Ergebnissen stehen - eine Datei ein Byte unter einem Limit ist
+ accept, und die Regel, um die es geht, ist trotzdem size_limit.
+
+
+
+
+
Was steht im Manifest?
+
+ Es wird am Ende jedes Laufs neben die Dateien geschrieben, auch bei einem unterbrochenen Lauf. Ein
+ Eintrag pro Datei:
+
+ Ein recipe_hash kommt hinzu, wenn der Lauf aus einem Rezept stammt, und
+ preset mit overrides, wenn er aus einem Preset stammt, sodass sich ein
+ Manifest immer auf das zurückführen lässt, was es erzeugt hat.
+
+
+ Jeder Eintrag trägt außerdem target_id, die ID des Targets im Rezept, das die Datei
+ erzeugt hat, und summary.by_target zählt, auf wie viele Dateien jedes Target kam.
+ Ein Rezept mit mehreren Targets lässt sich so Target für Target prüfen, ohne Dateinamen zu
+ lesen.
+
+
+
+
+
Was ist ein Preset?
+
+ Ein fertiges Set aus Dateien, das eine gängige Testfrage beantwortet, damit du das Set nicht selbst
+ entwerfen musst. Presets sind darunter ganz normale Rezepte, und eject gibt das
+ Rezept aus, damit du es von dort aus bearbeiten kannst. Jedes Preset hat
+ eine eigene Seite mit dem, was es meist findet, was im Set steckt und
+ welche Einstellungen es kennt.
+
+ show sagt dir, was das Set kosten würde, bevor du es baust, und sagt
+ unmissverständlich, wenn eine Zahl ein Platzhalter von uns statt ein Limit von dir ist.
+
+
+
+
+
Was bedeuten die Exit-Codes?
+
+ Jedes Ende hat einen eigenen Code, maschinenlesbare Ausgabe geht auf die Standardausgabe, und ein
+ fehlgeschlagener Lauf gibt dort nichts aus. Die Tabelle ist ein eingefrorener Vertrag - die
+ Bedeutung eines Codes zu ändern erfordert einen Major-Versionssprung.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Ein mit Strg+C gestoppter Lauf hinterlässt trotzdem ein Manifest und nie eine halb geschriebene
+ Datei, sodass ein abgebrochener Job vom nächsten noch aufgeräumt werden kann.
+
+ Ja, dieselbe Engine mit einem Fenster davor, für das Testen, das nicht skriptbar ist. Es ist keine
+ abgespeckte Version: Ein Test vergleicht die beiden Oberflächen Fähigkeit für Fähigkeit, und
+ alles, was nur eine von beiden kann, muss deklariert und begründet werden, statt unbemerkt
+ auseinanderzudriften.
+
+
+ Die Bildschirme sind ein Stapel, Presets, mehrere Stapel gleichzeitig und Info. Es zeigt, was ein
+ Lauf kosten würde, bevor etwas geschrieben wird, meldet den Fortschritt während des Laufs und
+ lässt sich mittendrin abbrechen, ohne eine halb geschriebene Datei zu hinterlassen. Eine
+ Rezeptdatei öffnet es noch nicht - Rezepte gibt es vorerst nur auf der Kommandozeile, und das
+ Fenster baut seine Stapel im Formular.
+
+
diff --git a/web/content/de/exact-size.html b/web/content/de/exact-size.html
new file mode 100644
index 00000000..b76696e9
--- /dev/null
+++ b/web/content/de/exact-size.html
@@ -0,0 +1,154 @@
+
So erstellst du eine Datei in exakter Größe
+
+ Jedes System hat dafür einen Befehl, alle drei stehen unten. Sie liefern dir eine Datei mit genau
+ der richtigen Byte-Zahl - und für viele Tests ist das alles, was du brauchst. Jeder Befehl
+ auf dieser Seite wurde vor der Veröffentlichung ausgeführt, auf dem System, zu dem er
+ gehört.
+
+
+
+
Die kurze Antwort
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Größen werden in Bytes angegeben,
+ und 10 MB, so gezählt wie dein Dateimanager zählt, sind 10485760 davon.
+
+
+
+
+
Windows
+
fsutil und eine PowerShell-Variante, die nichts Zusätzliches braucht
+
+ fsutil gehört zu Windows. Es nimmt die Größe in Bytes, rechne die Zahl
+ also vorher aus - 10 MB sind 10485760, 100 MB sind 104857600, 1 GB ist 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Gemessen unter Windows 11: Es funktioniert in einer normalen Eingabeaufforderung und braucht keine
+ erhöhten Rechte, und die Datei hat genau 10485760 Bytes.
+
+
PowerShell kann dasselbe, ohne ein anderes Programm aufzurufen, und versteht Einheiten:
+ 10MB bedeutet in PowerShell 10485760 Bytes, dieselbe Zählung auf 1024er-Basis, die der
+ Explorer verwendet, die beiden Befehle oben erzeugen also dieselbe Größe.
+
+
+
+
+
Linux
+
dd, truncate und fallocate und der Unterschied, der Leute erwischt
+
dd kennt jeder. Es schreibt die Bytes wirklich:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate ist sofort fertig, und genau das ist der Haken. Gemessen unter Alpine Linux
+ meldet die Datei 10485760 Bytes und belegt null Blöcke - sie ist eine
+ Sparse-Datei. Wer sie liest, bekommt zehn Megabyte Nullen, aber der Datenträger
+ hat den Platz nie hergegeben:
+
+
truncate -s 10M test10mb.bin
+
+ Das ist für den Test eines Upload-Limits in Ordnung und für den Test einer Datenträgerquote
+ irreführend. fallocate ist das Mittel der Wahl, wenn der Platz wirklich belegt sein
+ muss:
+
+
fallocate -l 10M test10mb.bin
+
Und wenn der Inhalt inkompressibel sein muss, damit ein Archivierer ihn nicht wieder zusammendrücken kann:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, das nicht sparse ist, und die beiden, die du schon kennst
+
+ macOS liefert mkfile mit. Gemessen unter macOS 26.6.2: 10485760 Bytes und 20480 Blöcke,
+ der Platz ist also wirklich belegt statt nur versprochen:
+
+
mkfile 10m test10mb.bin
+
dd und truncate gibt es ebenfalls, und sie verhalten sich wie unter Linux:
Eine Datei in der richtigen Größe ist keine Datei der richtigen Art
+
+ Alles oben Genannte liefert dir einen Block aus Nullen. Das reicht, wenn das Getestete nur auf die
+ Größe schaut - ein Upload-Limit, eine Quote, eine Übertragung. Es reicht nicht mehr, sobald
+ irgendetwas die Datei öffnet.
+
+
+ Gemessen, und es lohnt sich, das selbst zu probieren: Erzeuge mit fsutil eine
+ 2-MB-Datei, nenne sie photo.png und gib sie einer Bildbibliothek. Pillow antwortet
+ cannot identify image file. Es ist kein PNG. Es war nie eines - nur der Name
+ behauptete es.
+
+
+ Das ist wichtiger, als es klingt, wegen der Richtung, in der der Test dann
+ fehlschlägt. Dein Upload-Endpunkt weist die Datei ab, dein Test wird grün, und du
+ schließt, dass das Größenlimit funktioniert. Er hat sie nicht wegen der Größe abgewiesen. Er hat
+ sie abgewiesen, weil die Bytes kein Bild waren, und die Regel, die du testen wolltest, wurde nie
+ erreicht.
+
+
+
ein Parser weist sie ab, bevor eine Größenregel angesehen wird
+
ein Vorschauschritt schlägt fehl, und der Fehler, den du liest, betrifft die Vorschau
+
ein Virenscanner oder eine Inhaltsprüfung lehnt sie aus einem dritten Grund ab
+
ein Viewer zeigt nichts an, und niemand kann sagen, ob das der Fehler ist
+
+
+
+
+
Der andere Weg
+
Eine echte Datei dieses Formats, in genau der Größe, die du verlangt hast
+
+ Das ist es, was Testing Files Generator tut. Die Datei ist eine echte ihres Formats - sie öffnet
+ sich in der Software, zu der sie gehört - und hat die exakte Byte-Zahl, die du verlangt hast,
+ auf das Byte genau:
+
+ Verlange eine Größe, die ein Format nicht erreichen kann, und du bekommst einen Fehler, der die
+ Untergrenze und ihren Grund nennt, nie eine Datei in der falschen Größe. Die
+ Formate-Seite listet jedes Format mit der kleinsten Datei auf, die es
+ erzeugen kann.
+
+
Und ein Limit sind drei Testfälle statt einem, deshalb baut das Tool alle drei:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Das ergibt 10485759, 10485760 und 10485761 Bytes und ein Manifest, das sagt, welche davon dein
+ System akzeptieren und welche es ablehnen soll. Die
+ Anwendungsfälle-Seite geht das und vier weitere Aufgaben
+ durch, für die es gebaut ist.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Was solltest du also verwenden?
+
+
+
Den Systembefehl verwenden
+
+ Wenn nichts die Datei öffnet. Ein Größenlimit an einem Endpunkt testen, der zuerst die Größe prüft,
+ eine Übertragung, eine Quote, ein voller Datenträger. Es ist eine Zeile, und es ist schon
+ installiert.
+
+
+
+
Einen echten Generator verwenden
+
+ Wenn irgendetwas die Datei parst, rendert, importiert oder entpackt - und wenn du morgen auf einem
+ anderen Rechner dieselben Fixtures brauchst, Byte für Byte.
+
+
+
+
+ Beides steht auf dieser Seite, weil beides manchmal richtig ist. Der Fehler, den es zu vermeiden
+ gilt, ist, das Erste zu verwenden, wo das Zweite nötig ist, und den grünen Test als Beweis zu
+ lesen.
+
+
diff --git a/web/content/de/faq.html b/web/content/de/faq.html
new file mode 100644
index 00000000..8f02a81d
--- /dev/null
+++ b/web/content/de/faq.html
@@ -0,0 +1,20 @@
+
Häufig gestellte Fragen
+
+ Lizenz, Datenschutz, Reproduzierbarkeit und das, was Leute prüfen, bevor sie einen Generator in eine
+ Build-Pipeline einbauen. Wenn deine Frage hier fehlt, ist der
+ Issue-Tracker offen.
+
+ Die Anwendungsfälle-Seite zeigt die Aufgaben, für die es gebaut
+ ist, und die Formate-Seite listet jedes Format mit der kleinsten
+ Datei auf, die es erzeugen kann. Die README im Repository ist
+ die vollständige Referenz.
+
{{ .Facts.FormatCount }} Dateiformate, jedes in exakter Größe erzeugt
+
+ Jedes davon ist eine echte Datei dieses Formats. Sie öffnet sich in der Software,
+ zu der sie gehört, und hat genau die Byte-Zahl, die du verlangt hast. Keines davon besteht aus
+ aufgefüllten Nullen mit einer angeklebten Endung.
+
+
+{{ template "formatsTable" . }}
+
+
+
Was die Spalten bedeuten
+
+
+
Kleinste Datei
+
+ Die wenigsten Bytes, die dieses Tool für das Format akzeptiert, einschließlich des Labels, das es in
+ die Datei schreibt. Verlangst du weniger, bekommst du einen Fehler, der die Untergrenze und
+ ihren Grund nennt, nie eine Datei in der falschen Größe.
+
+
+
+
Vollständigkeit
+
+ Wie vollständig die Datei ist. full heißt, dass ein Leser, der das Format wirklich
+ parst, sie akzeptiert, nicht nur, dass die Endung passt.
+
+
+
+
Geprüft mit
+
+ Der unabhängige Leser, der jede erzeugte Datei öffnet, bevor das Format ausgeliefert wird - eine
+ eigene Implementierung, nicht unser eigener Code, der seine Hausaufgaben selbst korrigiert.
+
+
+
+
+ Jedes Format wiederholt sich außerdem bis aufs Byte: Dasselbe Rezept und derselbe Seed erzeugen auf
+ jedem Rechner identische Dateien, und genau das macht ein Rezept sicher einzuchecken statt der
+ Fixtures selbst.
+
+
+
+
+
Einstellungen, die jedes Format kennt
+
+ Die meisten Formate haben eigene Einstellungen - Bildmaße, JPEG-Qualität, PDF-Seitenzahl, Zeilen und
+ Spalten in einer Tabelle, wie viele Einträge in ein Archiv kommen. Setze sie mit --set
+ key=value auf der Kommandozeile oder unter properties: in einem Rezept.
+
+ Ein Wert außerhalb dessen, was eine Einstellung zulässt, wird mit einer Meldung abgewiesen, die die
+ Einstellung, den erlaubten Bereich und eine Alternative nennt. Eine unbekannte Einstellung ist
+ ebenfalls ein Fehler, nie ein stiller Standardwert - ein stillschweigend akzeptierter Tippfehler
+ ergibt eine Datei mit den falschen Einstellungen und eine Stunde Rätselraten, warum der Test
+ besteht, obwohl er es nicht sollte.
+
+
+ Mit tfg formats <id> siehst du genau, was ein Format in dem Build akzeptiert, den
+ du hast.
+
+
+
+
+
Archive enthalten echte Dateien
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} und {{ end }}{{ $c.ID }}{{ end }}
+ lassen sich mit Einträgen füllen, statt als leere Hülle zu bleiben. Ein erzeugtes Archiv enthält
+ wirklich die Dokumente, die es zu enthalten vorgibt, sodass alles, was es während eines Tests
+ entpackt, echte Dateien darin findet.
+
+ PDF, PNG, DOCX, ZIP - insgesamt {{ .Facts.FormatCount }} Formate, und jedes ist
+ eine echte Datei, die sich in der Software öffnet, zu der sie gehört, in genau der
+ Größe, die du verlangt hast. Jeder Lauf hält außerdem fest, was deine Anwendung mit
+ jeder Datei tun soll. Kommandozeile und Desktop-Fenster, kostenlos und Open Source, vollständig
+ auf deinem Rechner.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ Das Desktop-Fenster, eingerichtet für einen Stapel Dateien. Dieselbe Engine läuft hinter der Kommandozeile.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
echte Formate, jedes öffnet sich in der Software, zu der es gehört
+
+
+ 1 Byte
+
die Genauigkeit jeder verlangten Größe, nie stillschweigend gerundet
+
+
+ 0
+
Verbindungen irgendwohin - kein Konto, keine Telemetrie, keine Update-Prüfung
+
+
+
+
+
Das Problem
+
Eine Testdatei zu machen ist einfach. Die richtigen tausend zu machen ist das Mühsame
+
Du testest Software, die Dateien von Menschen annimmt. Früher oder später brauchst du:
+
+
ein PDF von exakt 10 MB, um herauszufinden, ob das Upload-Limit echt ist
+
die drei Dateien beidseits dieses Limits, um Off-by-one-Fehler zu fangen
+
10.000 Logdateien, um zu sehen, was der nächtliche Job tut, wenn der Ordner groß ist
+
ein ZIP, das wirklich 200 Dokumente enthält, keine Attrappe mit der richtigen Endung
+
eine 4-GB-Datei, ohne eine 4-GB-Datei in deinem Repository zu halten
+
die gleichen Fixtures auf deinem Laptop und auf dem Build-Server, Byte für Byte
+
+
+ Genau das ersetzt dieses Tool. Es ist gebaut für QA-Engineers, Testautomatisierung und alle, deren
+ Code ein Upload-Formular, eine Importroutine, einen Parser oder ein Speicherkontingent hinter
+ sich hat.
+
+
+
+
+
Was es anders macht
+
Andere Generatoren hören bei den Bytes auf. Dieser beantwortet, was dein Test wirklich fragt
+
+ Ein Ordner voller Dateien lässt dich weiter entscheiden, was jede davon belegen soll. Jeder Lauf
+ schreibt hier ein manifest.json neben die Dateien - eine einfache Liste von allem,
+ was erzeugt wurde, und zu jedem Eintrag eine deklarierte Erwartung.
+
+
Angenommen, dein Upload-Endpunkt erlaubt 1 MB. Fordere die drei Dateien an, die auf dieser Linie liegen:
Wo die Antwort von deiner eigenen Richtlinie abhängt, sagt das Manifest das
+
+ Es hält unspecified fest, statt eine Erwartung zu erfinden. Ein Generator, der rät,
+ erzeugt falsche Fehlschläge, und eine Testsuite, die ständig Alarm schlägt, wird abgeschaltet.
+
+
+
+
+
+
Presets
+
Wähle die Frage, bekomme das ganze Set
+
+ Ein Preset ist ein Set aus Testdateien, das um eine Testfrage herum entworfen wurde, damit du nicht
+ selbst herausfinden musst, welche Dateien was belegen. Jedes hat eine eigene Seite mit dem, was
+ es meist findet, was im Set steckt und welche Einstellungen es kennt.
+
+ Zehntausend Logdateien, jede zwischen einem und acht Kilobyte, die Größen werden aus dem Seed
+ gezogen, sodass morgen dasselbe Set herauskommt. Gib jedem Lauf ein eigenes
+ Verzeichnis - das Manifest ist die einzige Aufzeichnung dessen, was ein Lauf
+ geschrieben hat, deshalb weigert sich das Tool, ein zweites darüber zu schreiben:
+
+ Größen zählen in 1024ern, wie es dein Dateimanager tut, 2mb bedeutet also 2097152
+ Bytes. Eine einfache Byte-Zahl funktioniert auch. Die
+ Dokumentation behandelt Rezepte, das Manifest und die
+ Exit-Codes.
+
+
+
+
+
Was du bekommst
+
Gebaut für eine Testsuite, die unbeaufsichtigt läuft
+
+
+
Exakte Größe, auf das Byte genau
+
Verlange 10485761 Bytes und bekomme genau das. Eine Größe, die ein Format nicht erreichen kann, ist ein Fehler mit Begründung, nie eine Datei in der falschen Größe.
+
+
+
{{ .Facts.FormatCount }} echte Formate
+
Keine aufgefüllten Nullen mit einer Endung. Ein erzeugtes PNG öffnet sich im Bildbetrachter, ein DOCX in Word, ein ZIP lässt sich entpacken. Jedes wird vor der Auslieferung mit unabhängigen Readern geprüft.
+
+
+
Ein Manifest, das ein Testorakel ist
+
Pfad, Größe, SHA-256, Format, Seed, Tool-Version - und was dein System mit der Datei tun soll.
+
+
+
Reproduzierbar
+
Gleiches Rezept und gleicher Seed, gleiche Bytes, auf jedem Rechner. Checke ein kleines YAML-Rezept ein statt großer binärer Fixtures.
+
+
+
Zwei Oberflächen, eine Engine
+
Eine Kommandozeile für die CI und ein Desktop-Fenster für exploratives Testen. Keine ist eine abgespeckte Version der anderen, und ein Test vergleicht sie Fähigkeit für Fähigkeit.
+
+
+
Komplett offline
+
Kein Konto, keine Cloud, keine Telemetrie, keine Update-Prüfung. In die Kommandozeilen-Binärdatei ist gar kein Netzwerkstack einkompiliert.
+
+
+
+
+
+
Download
+
Wähle den Build für dein System
+
+ Entpacke das Archiv und starte es. tfg ist die Kommandozeile und tfg-gui
+ das Desktop-Fenster. Es gibt keinen Installer und nichts, was auf deinem Rechner hinzugefügt
+ werden müsste.
+
+ {{ template "downloadsTable" . }}
+
+
Was signiert ist und was nicht
+
+ Die Downloads für Windows und macOS sind signiert und starten daher ohne Warnung vor einem
+ unbekannten Entwickler. Die für Linux nicht, weil es unter Desktop-Linux nichts Vergleichbares
+ zum Signieren gibt. Jedes Archiv steht auf der Release-Seite in
+ verify-SHA256SUMS.txt, sodass du prüfen kannst, was du heruntergeladen hast.
+
+ Das Preset {{ .ID }} baut mit einem Befehl ein ganzes Set echter Testdateien für diese
+ Frage und ein manifest.json daneben, das beschreibt, wie dein System auf jede Datei
+ reagieren soll. Alles unten wird aus dem Programm gelesen, mit den Standardwerten dieser Version.
+
+
+{{ if .Catches }}
+
+
Was findet es meistens?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
Was steckt im Set?
+
Mit den Standardwerten, wie es tfg preset show {{ .ID }} ausgibt:
+
+
+
+
Dateien
{{ .Budget.Files }}
+
Targets in seinem Rezept
{{ .Budget.Targets }}
+
Gesamtgröße
{{ .Bytes }} B
+
Formate
{{ join .Budget.Formats ", " }}
+
+
+
+
Und was das Manifest dieses Sets von deinem System erwartet:
+
+
+
+
Erwartet
Bedeutung
Dateien
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
Was kannst du ändern?
+ {{- if .Settings }}
+
+
+
+
Einstellung
Nimmt
Standard
Was es tut
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Dieser Standardwert ist unser Platzhalter, nicht der Wert deines Systems. Gib deinen eigenen an.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
Dieses Preset hat keine Einstellungen. Das Set ist jedes Mal dasselbe.
+ {{- end }}
+
+
+
+
Wie führst du es aus?
+
Sieh nach, was das Set kosten würde, baue es oder nimm sein Rezept zum Bearbeiten:
Oder baue in einem eigenen Rezept darauf auf, neben deinen Tests:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/de/presets.html b/web/content/de/presets.html
new file mode 100644
index 00000000..e560eb3f
--- /dev/null
+++ b/web/content/de/presets.html
@@ -0,0 +1,32 @@
+
Testdatei-Presets, ein Set für jede Testfrage
+
+ Ein Preset ist ein ganzes Set aus Testdateien, das um eine Frage herum entworfen wurde, mit einem
+ Manifest, das beschreibt, wie dein System auf jede Datei reagieren soll. Du wählst die Frage, das
+ Tool baut das Set. Jedes Preset hat eine eigene Seite mit dem, was es meist findet, was im Set
+ steckt und welche Einstellungen es kennt.
+
+
+{{ template "presetsList" . }}
+
+
+
Worin unterscheidet sich ein Preset von einem Rezept?
+
+ Darunter gar nicht. Ein Preset ist ein Rezept, das das Tool aus ein paar Einstellungen für dich
+ schreibt. tfg preset eject gibt dieses Rezept aus, damit du es neben deinen Tests
+ aufbewahren und bearbeiten kannst, und ein eigenes Rezept kann mit einer Zeile auf einem Preset
+ aufbauen, extends: preset: gefolgt von seiner ID.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Kann ich den Standardwerten trauen?
+
+ Bei den Dateien ja. Bei einer Zahl, die nur dein System kennt, etwa dem Limit eines
+ Upload-Formulars, ist ein Standardwert ein Platzhalter von uns, und das Tool sagt es jedes Mal,
+ wenn es einen verwendet. Die Seite jedes Presets markiert diese Einstellungen, und tfg
+ preset show sagt es, bevor etwas geschrieben wird.
+
+
diff --git a/web/content/de/site.json b/web/content/de/site.json
new file mode 100644
index 00000000..15d72aaa
--- /dev/null
+++ b/web/content/de/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "de",
+ "locale": "de_DE",
+ "name": "Deutsch",
+ "dir": "de",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Start",
+ "title": "Testdatei-Generator für QA - exakte Größe, {{ .Facts.FormatCount }} echte Formate",
+ "description": "Kostenloser Open-Source-Generator für QA. Echte PDF-, DOCX-, PNG- und ZIP-Dateien in jeder exakten Größe, dazu ein Manifest, wie dein System reagieren soll."
+ },
+ {
+ "key": "formats",
+ "slug": "formate",
+ "nav": "Formate",
+ "title": "{{ .Facts.FormatCount }} unterstützte Dateiformate - PDF, DOCX, PNG, ZIP und mehr",
+ "description": "Alle Dateiformate dieses Generators, die kleinste mögliche Datei je Format und die Einstellungen, die es kennt. Alle {{ .Facts.FormatCount }} öffnen sich in ihrer Software."
+ },
+ {
+ "key": "presets",
+ "slug": "presets",
+ "nav": "Presets",
+ "title": "Testdatei-Presets - fertige Sets für typische QA-Fragen",
+ "description": "Fertige Sets aus Testdateien, jedes beantwortet eine Testfrage: Upload-Limits, Dateinamen, Zeichenkodierungen, Tabellenimporte, leere Dateien und Upload-Validierung."
+ },
+ {
+ "key": "docs",
+ "slug": "dokumentation",
+ "nav": "Dokumentation",
+ "title": "Dokumentation - Befehle, Rezepte, Manifest, Exit-Codes",
+ "description": "So erzeugst du Testdateien über die Kommandozeile oder ein YAML-Rezept, was das Manifest enthält und was jeder Exit-Code bedeutet, wenn das Tool in der CI läuft."
+ },
+ {
+ "key": "use-cases",
+ "slug": "anwendungsfaelle",
+ "nav": "Anwendungsfälle",
+ "title": "Anwendungsfälle - Upload-Limits, CI-Fixtures, Massentests",
+ "description": "Ein Upload-Größenlimit testen, reproduzierbare Fixtures für die CI bauen, zehntausend Dateien erzeugen und Archive mit echtem Inhalt füllen."
+ },
+ {
+ "key": "exact-size",
+ "slug": "datei-bestimmter-groesse-erstellen",
+ "nav": "Dateigröße",
+ "title": "Datei mit bestimmter Größe erstellen - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate und mkfile, jeweils auf dem passenden System gemessen - und warum eine so erzeugte Datei kein PDF und kein PNG ist, wenn ein Test eines braucht."
+ },
+ {
+ "key": "faq",
+ "slug": "faq",
+ "nav": "FAQ",
+ "title": "FAQ - Fragen zum Erzeugen von Testdateien",
+ "description": "Worin sich das Tool von dd und fsutil unterscheidet, ob man die Dateien einchecken kann, ob Läufe reproduzierbar sind und was bei unerreichbaren Größen passiert."
+ },
+ {
+ "key": "damage",
+ "slug": "beschaedigte-testdateien",
+ "nav": "Beschädigte Dateien",
+ "title": "Beschädigte Testdateien - kaputte Dateien in exakter Größe",
+ "description": "Eine absichtlich kaputte Datei in exakt der verlangten Größe, mit einem Manifest, das sagt, dass Ihr System sie ablehnen soll. Für Upload-Validierung und Parser.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "testdateien-in-ci",
+ "nav": "Testdateien in CI",
+ "title": "Testdateien in CI - GitHub Actions, GitLab CI und PowerShell",
+ "description": "Testdateien in der Pipeline erzeugen statt einzuchecken: GitHub-Actions-Workflow, GitLab-Job, Exit-Codes, die den Build scheitern lassen, und die PowerShell-Falle.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "Zum Inhalt springen",
+ "navLabel": "Hauptnavigation",
+ "langLabel": "Sprache",
+ "breadcrumbHome": "Start",
+ "imageAlt": "Testing Files Generator - echte Testdateien in jeder exakten Größe, mit einem Manifest, das beschreibt, wie dein System auf jede einzelne reagieren soll",
+ "schemaDescription": "Ein kostenloser Open-Source-Generator für Testdateien in der QA. Er erzeugt echte Dateien in {{ .Facts.FormatCount }} Formaten in jeder exakten Größe und schreibt ein Manifest, das beschreibt, wie das getestete System auf jede Datei reagieren soll.",
+ "ctaDownload": "Herunterladen",
+ "ctaSource": "Quellcode ansehen",
+ "ctaNote": "Kostenlos und Open Source, GPL-3.0. Keine Anmeldung nötig. Die Downloads für Windows und macOS sind signiert und starten ohne Warnung.",
+ "colFormat": "Format",
+ "colName": "Name",
+ "colExtension": "Endung",
+ "colSmallest": "Kleinste Datei",
+ "colFidelity": "Vollständigkeit",
+ "colChecked": "Geprüft mit",
+ "colSetting": "Einstellung",
+ "colAccepts": "Erlaubt",
+ "colSystem": "System",
+ "colCli": "Kommandozeile",
+ "colWindow": "Desktop-Fenster",
+ "noBinary": "noch keine Binärdatei",
+ "colCode": "Code",
+ "colMeaning": "Bedeutung",
+ "footerBlurb": "Testdateien für die QA in jeder exakten Größe, mit einem Manifest, das beschreibt, wie dein System auf jede einzelne reagieren soll.",
+ "footerProject": "Projekt",
+ "footerSource": "Quellcode auf GitHub",
+ "footerReleases": "Downloads",
+ "footerIssues": "Problem melden",
+ "footerSupport": "Projekt unterstützen",
+ "footerPages": "Seiten",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. Veröffentlicht unter der GNU General Public License, Version 3. Die Dateien, die du erzeugst, gehören dir - die Lizenz gilt für das Tool, nicht für seine Ausgabe.",
+ "footerPrivacy": "Diese Website lädt von nirgendwo Schriften, Skripte oder Tracker. Sie setzt keine Cookies.",
+ "notFoundTitle": "Diese Seite gibt es nicht",
+ "notFoundLead": "Die Adresse, der du gefolgt bist, passt zu keiner Seite dieser Website.",
+ "notFoundBack": "Zur Startseite",
+ "read.format": "Das Format jeder Datei im Set. Es ist ein Flag des Tools selbst, das Preset gibt ihm nur einen Standardwert.",
+ "readTakes.format": "eine Format-ID von der Formate-Seite",
+ "colDamage": "Beschädigung",
+ "colEffect": "Was sie mit den Bytes macht",
+ "colSettings": "Einstellungen",
+ "noSettings": "keine"
+ },
+ "endings": {
+ "0": "Alles hat funktioniert.",
+ "1": "Ein unerwarteter Fehler im Tool.",
+ "2": "Falscher Befehl oder falsches Flag.",
+ "3": "Das Rezept ist ungültig.",
+ "4": "Das Format kann nicht, was verlangt wurde.",
+ "5": "Lesen oder Schreiben ist fehlgeschlagen.",
+ "6": "Nicht genug Speicherplatz.",
+ "7": "verify hat eine Abweichung gefunden.",
+ "8": "Der Lauf ist beendet, aber nicht alles wurde erzeugt.",
+ "130": "Mit Strg+C abgebrochen.",
+ "143": "Durch ein Signal beendet, so sieht ein CI-Timeout aus."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "Kommt eine gültige Datei durch, die so klein ist, wie das Format es erlaubt?",
+ "title": "Leer und minimal",
+ "pageTitle": "Kleinste gültige und leere Testdateien in jedem Format",
+ "description": "Die kleinste gültige Datei in jedem der {{ .Facts.FormatCount }} Formate, dazu eine leere Datei, wo das Format sie erlaubt, jeweils mit der erwarteten Reaktion.",
+ "catches": [
+ "eine gültige Datei, die als zu klein abgewiesen wird, weil die Prüfung Bytes zählt, statt sie zu lesen",
+ "eine leere Datei, die den Leser zum Absturz bringt, statt gemeldet zu werden",
+ "ein Bild mit einem Pixel Breite, das auf dem Weg zur Vorschau durch null teilt",
+ "ein Speicher, der null Bytes als fehlgeschlagenen Upload liest und immer wieder neu versucht"
+ ],
+ "details": {
+ "formats": "Aus welchen Formaten das Set besteht. Mit all werden alle Formate dieses Builds verwendet, oder du nennst die, die dein System akzeptiert."
+ }
+ },
+ "filename-handling": {
+ "question": "Speichert, zeigt und liefert mein System einen Dateinamen korrekt, mit dem es nicht gerechnet hat?",
+ "title": "Umgang mit Dateinamen",
+ "pageTitle": "Problematische Dateinamen zum Testen - Unicode und Länge",
+ "description": "Dateinamen, die Uploads und Speicher aus dem Tritt bringen: andere Schriften, Emoji, Rechts-nach-links-Override, Steuerzeichen, Shell- und SQL-Syntax, Längenlimits.",
+ "catches": [
+ "ein Name, der auf dem Bildschirm, in einem Log oder in einer Liste wie ein anderer aussieht",
+ "ein Name, der zwischen Upload und Speicherung abgeschnitten, gekürzt oder umgeschrieben wird",
+ "ein Längenlimit, das in Zeichen gezählt wird, obwohl der Speicher Bytes zählt"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "Wird ein Größenlimit genau dort durchgesetzt, wo es angegeben ist?",
+ "title": "Größengrenzen",
+ "pageTitle": "Upload-Größenlimit testen - Dateien an der exakten Grenze",
+ "description": "Dateien ein Byte unter, auf und über dem Größenlimit deines Systems, dazu weitere Stufen auf beiden Seiten, jeweils mit der Angabe, ob sie akzeptiert werden sollen.",
+ "catches": [
+ "Off-by-one-Fehler am Limit",
+ "MB mit MiB verwechselt, was 4,8 Prozent ausmacht und reicht, um eine Datei durchzulassen, die nicht durchkommen dürfte",
+ "ein Limit, das im Browser durchgesetzt wird und nicht auf dem Server"
+ ],
+ "details": {
+ "limit": "Das Größenlimit, das dein System angibt. Alles andere wird von hier aus gemessen.",
+ "spread": "Wie weit auf beiden Seiten des Limits gegangen wird, als Liste von Größen."
+ }
+ },
+ "tabular-import": {
+ "question": "Übersteht mein Tabellenimport das, was echte Tools exportieren?",
+ "title": "Tabellenimport",
+ "pageTitle": "Testdateien für CSV- und Excel-Import - Trennzeichen, Kopfzeilen",
+ "description": "CSV mit anderen Trennzeichen, CR-LF, ohne Kopfzeile und mit anderer Quotierung, eine sehr breite Tabelle, eine Excel-Arbeitsmappe und JSON in mehreren Layouts.",
+ "catches": [
+ "eine CSV-Datei mit Semikolon, die als eine Spalte gelesen wird, weil das Trennzeichen angenommen statt gesucht wurde",
+ "eine CRLF-Datei, die in Zeilen mit einer leeren Zeile nach jeder zerlegt wird",
+ "eine Tabelle ohne Kopfzeile, deren erste Datenzeile als Spaltennamen verschluckt wird",
+ "ein Import, der die Spalten behält, die er anzeigen kann, und den Rest kommentarlos verwirft",
+ "ein Leser, der JSON-Datensätze Zeile für Zeile liest und beim ersten eingerückten Dokument aufgibt"
+ ],
+ "details": {
+ "rows": "Wie viele Zeilen die Tabelle enthält. Die Datei wird in genau der Größe geschrieben, auf die sich so viele Zeilen verpacken lassen, daher verschiebt sich das Budget oben mit diesem Wert.",
+ "columns": "Wie viele Spalten jede Zeile der Tabelle hat. Zeilen mal Spalten hat eine Obergrenze, und wer darüber hinausgeht, wird abgewiesen, bevor etwas geschrieben wird."
+ }
+ },
+ "text-encoding": {
+ "question": "Weiß mein Leser, in welcher Kodierung eine Datei vorliegt, oder rät er?",
+ "title": "Textkodierung",
+ "pageTitle": "Testdateien für Textkodierung - UTF-8, UTF-16, BOM, CRLF",
+ "description": "Derselbe Text in UTF-8, UTF-16LE und UTF-16BE, mit und ohne Byte Order Mark, dazu Zeilenenden in CR LF und LF, um zu testen, wie ein Leser Text dekodiert.",
+ "catches": [
+ "ein Leser, der UTF-8 annimmt und eine UTF-16-Datei als jedes dritte Zeichen oder als Reihen von Kästchen anzeigt",
+ "eine Byte Order Mark, die als Inhalt gelesen wird, sodass das erste Feld eines Imports mit drei fremden Zeichen beginnt",
+ "ein Importer, der die Kodierung aus den ersten Bytes errät und bei einer längeren Datei anders rät",
+ "eine CRLF-Datei, die in Zeilen mit einer leeren Zeile nach jeder zerlegt wird, oder ein Wagenrücklauf, der im letzten Feld stehen bleibt"
+ ],
+ "details": {
+ "sample": "Wie groß jede Datei des Sets ist. UTF-16 speichert zwei Bytes pro Zeichen, daher wird eine ungerade Zahl abgewiesen."
+ }
+ },
+ "upload-validation": {
+ "question": "Nimmt mein Upload-Formular an, was es soll, und weist den Rest ab?",
+ "title": "Upload-Validierung",
+ "pageTitle": "Testdateien für die Upload-Validierung - Typ, Größe und Name",
+ "description": "Dateien zum Testen eines Upload-Formulars: erlaubte und verbotene Typen, Inhalt, der nicht zur Endung passt, Größenlimit, feindliche Namen und ein Massen-Upload.",
+ "catches": [
+ "ein Limit, das im Browser durchgesetzt wird und nicht auf dem Server",
+ "eine SVG- oder HTML-Datei, die für ein Bild oder für einfachen Text gehalten wird, womit sich ein Skript an einem Formular vorbeischleusen lässt",
+ "eine Datei, die nur an der Endung geprüft und nie geöffnet wird, sodass ein PDF namens .jpg durchgeht",
+ "ein Formular, das den ganzen Body in den Speicher liest, bevor es nachsieht, wie groß er ist",
+ "ein Upload namens PHOTO.JPG, der abgewiesen wird, während photo.jpg durchkommt, oder umgekehrt",
+ "ein Name mit Leerzeichen, Klammern oder Zeichen außerhalb von ASCII, der unverändert auf die Platte geschrieben wird"
+ ],
+ "details": {
+ "limit": "Das Größenlimit, das dein Upload-Formular angibt. Dieses Set geht je einen Schritt auf beiden Seiten davon - für eine Datei in jedem Abstand führe das Preset size-boundaries aus.",
+ "allow": "Welche Typen dein Formular akzeptieren soll. Jeder wird zu einer echten Datei dieses Typs, und sie sind die positive Kontrolle des ganzen Sets.",
+ "deny": "Welche Endungen dein Formular abweisen soll. Für eine Endung, zu der dieser Build kein Format hat, wird trotzdem eine Datei mit diesem Namen geschrieben, die einfachen Text enthält.",
+ "far-over": "Wie weit über dem Limit die eine große Datei liegt. Schalte sie ab, wo es das Vielfache des Limits auf der Platte nicht wert ist.",
+ "bulk": "Wie viele Dateien der Massen-Upload enthält. Bei null fällt diese Gruppe ganz aus dem Set."
+ }
+ }
+ },
+ "commands": {
+ "generate": "Dateien erzeugen, aus einem Rezept oder über Flags",
+ "validate": "ein Rezept prüfen und nichts schreiben",
+ "verify": "ein Verzeichnis gegen ein Manifest prüfen",
+ "cleanup": "die Dateien entfernen, die ein Manifest auflistet",
+ "recipe fmt": "ein Rezept in seiner festen Form ausgeben",
+ "preset": "ein Set von Dateien aus einer benannten Testfrage erzeugen",
+ "formats": "die Formate dieses Builds auflisten",
+ "damage": "die Arten auflisten, wie dieser Build eine Datei absichtlich beschädigen kann",
+ "tool": "kleine Helfer für Dateien, die du schon hast",
+ "version": "die Version des Tools ausgeben",
+ "license": "die Lizenz ausgeben und was sie für erzeugte Dateien bedeutet"
+ },
+ "outcomes": {
+ "accept": "Dein System soll die Datei annehmen.",
+ "reject": "Dein System soll die Datei abweisen.",
+ "sanitize": "Dein System soll die Datei annehmen und bereinigen, zum Beispiel durch Umbenennen.",
+ "unspecified": "Das hängt von den Regeln deines Systems ab. Du entscheidest, dann prüfst du, ob das Ergebnis dem entspricht, was du gemeint hast."
+ },
+ "damages": {
+ "zero-head": "Überschreibt die ersten Bytes der Datei mit Nullen und lässt ihre Länge unverändert. Die meisten Leser schauen zuerst dorthin, deshalb bemerkt fast alles diese Beschädigung."
+ },
+ "terms": {
+ "oracleNone": "nicht zutreffend",
+ "int": "jede ganze Zahl",
+ "choice": "eine aus einer festen Auswahl",
+ "bool": "wahr oder falsch",
+ "size": "eine Größe wie 2mb",
+ "text": "Text",
+ "pixels": "Pixel",
+ "paragraphs": "Absätze",
+ "rows": "Zeilen",
+ "columns": "Spalten",
+ "slides": "Folien",
+ "hertz": "Hertz",
+ "megapixels": "Megapixel",
+ "million cells": "Millionen Zellen",
+ "entries per second": "Einträge pro Sekunde",
+ "files": "Dateien",
+ "sizes separated by commas": "Größen, durch Kommas getrennt",
+ "format ids separated by commas": "Format-IDs, durch Kommas getrennt",
+ "format ids separated by commas, or all": "Format-IDs, durch Kommas getrennt, oder all",
+ "extensions separated by commas": "Endungen, durch Kommas getrennt",
+ "the id of a format, as tfg formats lists them": "die ID eines Formats, wie tfg formats sie auflistet",
+ "the password, in plain text": "das Passwort im Klartext",
+ "any text": "beliebiger Text",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "ein Datum wie 2024-02-29 oder 2024-02-29T13:45:00+02:00, oder none"
+ },
+ "faq": [
+ {
+ "q": "Worin unterscheidet sich das von dd, fsutil oder truncate?",
+ "a": "Diese Befehle liefern dir eine Datei in der richtigen Größe, gefüllt mit nichts. Eine 2 MB große Datei namens photo.png, die so entstanden ist, ist kein PNG. Alles, was sie wirklich parst, weist sie aus dem falschen Grund ab, und dein Test besteht dann ebenfalls aus dem falschen Grund. Dieses Tool erzeugt ein echtes PNG von genau 2 MB, das sich in einem Bildbetrachter öffnet und mit einer Aussage darüber geliefert wird, wie dein System damit umgehen soll.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "Ist es kostenlos, und darf ich es bei der Arbeit einsetzen?",
+ "a": "Ja, beides. Es steht unter der GPL-3.0 und kostet nichts. Es gibt kein Konto, keinen Lizenzschlüssel und keine kostenpflichtige Stufe."
+ },
+ {
+ "q": "Darf ich die erzeugten Dateien in einem Closed-Source-Produkt verwenden?",
+ "a": "Ja. Die Lizenz gilt für den Code des Tools, nicht für das, was das Tool erzeugt. Erzeugte Dateien, Rezepte und Manifeste sind Ausgabe und keine abgeleiteten Werke, du kannst sie also einchecken und ohne jede Verpflichtung weitergeben."
+ },
+ {
+ "q": "Enthalten die erzeugten Dateien echte personenbezogene Daten?",
+ "a": "Nein. Alles darin wird aus einem Seed synthetisch erzeugt. Es wird kein Datensatz gelesen, kein Dienst kontaktiert und kein Inhalt Dritter eingebettet. Behandle eine erzeugte E-Mail-Adresse als unbrauchbar statt als unbenutzt, denn jede Zufallszeichenfolge kann zufällig mit einer echten übereinstimmen."
+ },
+ {
+ "q": "Bekomme ich auf einem anderen Rechner genau dieselben Dateien?",
+ "a": "Ja, Byte für Byte, bei gleichem Rezept und gleichem Seed. Das Projekt testet das bei jeder Änderung, und es zu brechen erfordert einen Major-Versionssprung. Genau deshalb kannst du ein kleines Rezept einchecken statt großer binärer Fixtures."
+ },
+ {
+ "q": "Braucht es eine Internetverbindung?",
+ "a": "Nie. Es gibt keine Telemetrie, keine Update-Prüfung und keinen Cloud-Client, und die Kommandozeilen-Binärdatei hat gar keinen Netzwerkstack einkompiliert. Sie läuft auf einem Rechner ohne Netz und in einer abgeschotteten Unternehmensumgebung."
+ },
+ {
+ "q": "Was passiert, wenn ich eine Größe verlange, die ein Format nicht erreichen kann?",
+ "a": "Du bekommst einen Fehler, der das Format nennt, die kleinstmögliche Größe, den Grund für diese Untergrenze und was du stattdessen tun kannst, und es wird keine Datei geschrieben. Das Tool rundet eine Größe nie stillschweigend. Jede Untergrenze steht auf der Formate-Seite.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "Kann ich eine absichtlich kaputte Datei erzeugen?",
+ "a": "Ja. Fügen Sie --damage zero-head hinzu, und die Datei kommt in genau der verlangten Größe heraus, mit Nullen über den ersten Bytes, sodass ein Leser sie abweist, und das Manifest sagt, dass Ihr System sie ablehnen soll. Die Einzelheiten stehen auf der Seite über beschädigte Testdateien.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "Welche Formate kommen als Nächstes?",
+ "a": "7z, mp3 und mp4. {{ .Facts.FormatCount }} Formate funktionieren heute durchgängig."
+ },
+ {
+ "q": "Auf welchen Systemen läuft es?",
+ "a": "Die Kommandozeile läuft unter Windows und Linux auf Intel und ARM sowie auf Macs mit Apple Silicon. Das Desktop-Fenster gibt es für Windows auf Intel, Linux auf Intel und Macs mit Apple Silicon. Intel-Macs werden nicht unterstützt, und für sie wird nichts gebaut."
+ },
+ {
+ "q": "Muss ich etwas installieren?",
+ "a": "Nein. Lade das Archiv für dein System herunter, entpacke es und starte die Binärdatei. Es gibt keinen Installer, keine Laufzeitumgebung zum Nachrüsten und keine Abhängigkeit, die aufgelöst werden müsste. Wenn du Go hast, funktioniert auch ein einziger go-install-Befehl.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "Warum ist ein Lauf über Tausende Dateien unter Windows langsamer?",
+ "a": "Weil Windows für jeden Pfad, den es ansieht, mehr verlangt, und ein Befehl über Tausende Dateien sieht sich Tausende Pfade an. Gemessen auf einem Rechner mit 3000 Dateien zu je 1 kB braucht verify unter Windows etwa 0,9 Sekunden und unter Linux in einem Container etwa 0,2 Sekunden. Ein kürzerer Ausgabepfad verkleinert den Windows-Wert, denn jeder Ordner über den Dateien gehört zu dem, was angesehen wird."
+ }
+ ]
+}
diff --git a/web/content/de/use-cases.html b/web/content/de/use-cases.html
new file mode 100644
index 00000000..c5acce8d
--- /dev/null
+++ b/web/content/de/use-cases.html
@@ -0,0 +1,135 @@
+
Wofür Leute es einsetzen
+
+ Fünf Aufgaben, die in fast jedem Projekt vorkommen, das Dateien von Menschen annimmt, und der
+ Befehl, der jede erledigt. Jedes Beispiel unten läuft so, wie es geschrieben steht.
+
+
+
+
Upload-Limits
+
Testen, ob ein Dateigrößenlimit dort durchgesetzt wird, wo es angegeben ist
+
+ Ein Limit sind drei Testfälle, nicht einer: knapp darunter, genau darauf und knapp darüber. Die von
+ Hand zu bekommen heißt, Byte-Zahlen auszurechnen und zu hoffen, dass man sich nicht um eins
+ verzählt hat. Fordere stattdessen das Set an:
+
+ Du bekommst drei echte PDFs mit 1048575, 1048576 und 1048577 Bytes und ein Manifest, das sagt, dass
+ die ersten beiden akzeptiert und die dritte wegen size_limit abgelehnt werden soll.
+ Dein Test liest die Erwartung, statt dass du drei Assertions von Hand schreibst - und wenn sich
+ das Limit ändert, änderst du eine Zahl und startest neu.
+
+
+ Dasselbe geht ohne Preset, wenn du ein einzelnes Grenzen-Set inline willst:
+
Fixtures aus dem Repository heraushalten, ohne sie zu verlieren
+
+ Große binäre Fixtures machen ein Repository langsam beim Klonen und mühsam beim Review, und niemand
+ sieht, was sich geändert hat, wenn eine ersetzt wird. Ein Rezept sind ein paar hundert Zeichen
+ YAML, die die identischen Dateien neu erzeugen - Byte für Byte, auf jedem
+ Rechner - weil jede Datei aus dem Seed des Laufs abgeleitet wird.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Jedes Ende hat einen eigenen Exit-Code, sodass eine Pipeline ein schlechtes Rezept von einem vollen
+ Datenträger und von einer Abweichung bei der Prüfung unterscheiden kann. Ein fehlgeschlagener
+ Lauf gibt nichts auf der Standardausgabe aus, wodurch ein Log-Parser einen Fehler nicht als
+ Daten liest.
+
+
+
+
+
Skalierung
+
Herausfinden, was passiert, wenn der Ordner groß ist
+
+ Importroutinen, nächtliche Jobs und Verzeichnislisten verhalten sich bei zehntausend Dateien anders
+ als bei zehn. Aus einem Bereich gezogene Größen lassen das Set wie echten Datenverkehr aussehen
+ statt wie zehntausend identische Dateien, und die Ziehung kommt aus dem Seed, das Set ist also
+ morgen dasselbe.
+
+ Ein Lauf, der größer ist als der freie Platz auf dem Datenträger, wird vor dem ersten geschriebenen
+ Byte abgelehnt, statt den Datenträger zu füllen und auf halbem Weg zu scheitern.
+
+
+
+
+
Archive
+
Einen Entpacker mit einem Archiv testen, das wirklich Dateien enthält
+
+ Ein leeres Archiv mit der richtigen Endung beweist nichts über Code, der es öffnet und durchläuft,
+ was darin ist. Deklariere den Inhalt, und das Archiv enthält ihn wirklich:
+
+ Verschachtelungstiefe, Eintragszahlen und die Größe dessen, was darin liegt, sind alles Dinge, zu
+ denen eine Importroutine Meinungen hat, und so findest du heraus, welche das sind.
+
+
+
+
+
Parser und Viewer
+
Prüfen, dass dein eigener Code ein Format so liest wie echte Software
+
+ Jedes Format hier wird vor der Auslieferung mit einem unabhängigen Leser geprüft - ein PNG wird
+ geöffnet und seine Pixel verglichen, ein DOCX von separaten Bibliotheken zurückgelesen, ein
+ Archiv entpackt. Das heißt, eine Datei, die dein Parser abweist, ist ein Befund über deinen
+ Parser, nicht über den Generator.
+
+ Die Formate-Seite listet die Einstellungen jedes Formats und die kleinste
+ Datei auf, die es sein kann.
+
+
+
+
+
Anleitungen
+
Zwei davon im Detail
+
+
+ Beschädigte Testdateien - eine absichtlich kaputte Datei
+ in exakter Größe, mit dem Manifest als Angabe, was mit ihr geschehen soll.
+
+
+ Testdateien in CI - ein GitHub-Actions-Workflow, ein GitLab-Job
+ und die Exit-Codes, die einen Build scheitern lassen.
+
+
+
+
+
+
Für wen das gedacht ist
+
+ QA-Engineers, Testautomatisierung und alle, deren Code ein Upload-Formular, eine Importroutine,
+ einen Parser oder ein Speicherkontingent hinter sich hat. Es läuft auf einem Rechner ganz ohne
+ Netz, was in einer abgeschotteten Unternehmensumgebung zählt, wo ein browserbasierter Generator
+ keine Option ist.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/en/ci.html b/web/content/en/ci.html
new file mode 100644
index 00000000..73a959e9
--- /dev/null
+++ b/web/content/en/ci.html
@@ -0,0 +1,187 @@
+{{ with .Up }}
+ A binary fixture in a repository stays in its history for good, cannot be reviewed in a diff, and
+ stops being possible once the file is large. Generate the files inside the pipeline from a recipe
+ instead. The recipe is text, the bytes come out the same every time, and a last step proves that
+ nothing moved.
+
+
+
+
The short answer
+
+ Install tfg, run tfg generate fixtures.yaml --out ./fixtures before the
+ tests, and tfg verify ./fixtures/manifest.json after them. Both steps fail the build
+ by themselves, with an exit code that says why.
+
+
+
+
+
Why not commit them
+
Why a fixture should not live in the repository
+
+
+ It stays in the history. Deleting a binary later does not make a clone smaller,
+ because every version of it is still there.
+
+
+ A diff cannot show what changed. A reviewer sees that a PDF is different and
+ nothing else. A recipe changes by a line.
+
+
+ Large files do not fit. GitHub refuses a push that holds a file over 100 MB, so
+ a test of a 500 MB upload limit has nothing to commit.
+
+
+
+ The recipe is the thing to commit. The same recipe and seed write the same bytes on every machine,
+ so the file generated in the pipeline is the file you had on your laptop.
+
+
+
+
+
The recipe
+
A recipe that lives beside the tests
+
+ This one writes twenty five invoices that should be accepted and two images over a limit that
+ should be turned away, and the manifest records both expectations:
+
+ The checksum line compares the archive with verify-SHA256SUMS.txt from the same
+ release. The version is pinned, so a new release never changes a build you did not touch.
+
+ Every ending has its own exit code, so the step fails on its own and the log says which one. The
+ ones a pipeline meets:
+
+
+
3 - the recipe is not valid. Nothing was written, and every problem is named
+
4 - the format cannot do what was asked, for example a size below its smallest
+
6 - there is not enough disk space
+
7 - tfg verify found a file that does not match its manifest
+
8 - the run finished, but not everything was produced
+
+
+ A failed run prints nothing on standard output, so a log parser never reads an error as data. The
+ whole table is on the documentation page.
+
+
+
+
+
PowerShell
+
A PowerShell script needs one more line
+
+ PowerShell does not carry the exit code of a program out of a .ps1 file. Run one with
+ -File and the script answers 0 even when the tool inside refused the
+ work, so a build that should be red goes green. The last line is the whole fix:
+
+ That is how PowerShell behaves, not something about this tool. cmd,
+ bash and zsh need nothing extra.
+
+
+
+
+
Several jobs
+
Sharing the fixtures between jobs
+
+ There is usually no need to upload them. Because the same recipe writes the same bytes, each job
+ can run its own tfg generate, which is quicker than an upload and a download. When a
+ job has to receive files from another, run tfg verify on the manifest after the
+ transfer, and it tells you whether what arrived is what was written.
+
+
+
+
+
Next
+
Where to go from here
+
+
+ Corrupt test files adds files that are broken on purpose to
+ the same recipe.
+
+
+ The use cases show what else a run in a pipeline can check.
+
+ A validator that has only ever been shown healthy files has not really been tested. Here is how to
+ get a file that is broken on purpose, comes out at exactly the size you ask for,
+ and carries a manifest saying what your system should do with it.
+
+
+
+
The short answer
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out writes a PNG of
+ exactly 2097152 bytes whose first bytes are zeros, and the manifest beside it records that your
+ system should reject it.
+
+
+
+
+
The usual way
+
Why a file corrupted by hand makes a poor test
+
+ The usual ways are a hex editor, a script that flips a few random bytes, or cutting a file short
+ with head or truncate. They work once, and then they cost you:
+
+
+
+ It is different every time. A random byte lands somewhere new on each run, so a
+ failure on Tuesday may not come back on Wednesday.
+
+
+ It changes the size. A file cut short is smaller than the limit it was meant to
+ sit under, so the size check answers before the content check and the test passes for the wrong
+ reason.
+
+
+ It often goes unnoticed. Plain text still reads with a byte changed in the
+ middle, and a forgiving image reader just draws it, so the file you meant to be broken is
+ accepted.
+
+
+ It says nothing about what should happen. The file is only bytes, and whoever
+ reads the test next has to guess whether acceptance or rejection was intended.
+
+
+
+
+
+
What you get
+
A damaged file is still the size you asked for
+
+ The file is generated normally and broken afterwards, on its way to the disk. It keeps the size
+ you asked for, and the same command writes the same bytes again.
+
+ Settings go after a colon. The flag can be repeated, and the damages are applied in the order you
+ write them. It works with every one of the {{ .Facts.FormatCount }} formats.
+
+
+
+
+
What it can do
+
Which damages are there?
+
+ This is the list the program prints, read from it when this page is built. tfg damage
+ prints the same, and tfg damage <id> says what one of them takes.
+
+ {{ template "damagesTable" . }}
+
+ zero-head writes zeros over the start of the file. Most readers look there first, at
+ the signature and the header that say what the file is, so almost any reader notices. Plain text
+ and logs have no signature and are turned away as well, because a run of zero bytes is not text.
+ Below four bytes some formats come out with damage that no reader complains about, which is why
+ the setting starts at four.
+
+
+
+
+
What the manifest says
+
A manifest that says what should happen
+
+ Every damaged file gets an entry saying your system should reject it, with the damage recorded
+ beside it:
+
+ Two requests are refused before anything is written, because each would leave a file on disk that
+ the manifest describes wrongly:
+
+
+
a file smaller than the damage needs, which would come out unchanged
+
+ expected: accept beside a damage, because nothing could meet it. Write
+ sanitize if your system is meant to repair the file, or unspecified if
+ that is the question you are asking
+
+
+
+
+
+
In a recipe
+
Healthy and broken files in one run
+
+ Put both in one recipe, and the manifest carries the expectation of every file, so the test does
+ not need a list of which is which:
+
+ The test reads the manifest and checks that what happened is what was declared. It needs no list
+ of file names:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ A good refusal is a clean one. A message that says what was wrong is the answer you want. A server
+ error, a hang or a half stored file is the defect this test exists to find.
+
A run stopped with Ctrl+C still leaves a manifest and never leaves a half written file behind, so
a cancelled job can still be cleaned up by the next one.
+
diff --git a/web/content/en/site.json b/web/content/en/site.json
index 1e87bc0c..18ac8878 100644
--- a/web/content/en/site.json
+++ b/web/content/en/site.json
@@ -1,5 +1,6 @@
{
"code": "en",
+ "locale": "en_US",
"name": "English",
"dir": "",
"pages": [
@@ -51,11 +52,28 @@
"nav": "FAQ",
"title": "FAQ - Questions About Generating Test Files",
"description": "How this differs from dd and fsutil, whether the files are safe to commit, whether runs repeat byte for byte, and what happens when a size cannot be reached."
+ },
+ {
+ "key": "damage",
+ "slug": "corrupt-test-files",
+ "nav": "Corrupt test files",
+ "title": "Corrupt Test Files - Damaged Files of an Exact Size",
+ "description": "Make a file that is broken on purpose, at the exact size you ask for, with a manifest saying your system should reject it. For testing upload validation and parsers.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "test-files-in-ci",
+ "nav": "Test files in CI",
+ "title": "Test Files in CI - GitHub Actions, GitLab CI and PowerShell",
+ "description": "Generate test files in the pipeline instead of committing binaries: a GitHub Actions workflow, a GitLab job, exit codes that fail the build and the PowerShell catch.",
+ "parent": "use-cases"
}
],
"words": {
"skip": "Skip to content",
"navLabel": "Main",
+ "langLabel": "Language",
"breadcrumbHome": "Home",
"imageAlt": "Testing Files Generator - real test files at any exact size, with a manifest saying how your system should react to each one",
"schemaDescription": "A free and open source generator of test files for QA. It produces real files of {{ .Facts.FormatCount }} formats at any exact size and writes a manifest saying how the system under test should react to each one.",
@@ -89,7 +107,11 @@
"notFoundLead": "The address you followed does not match any page on this site.",
"notFoundBack": "Go to the home page",
"read.format": "The format of every file in the set. It is a flag of the tool itself, and the preset only gives it a default.",
- "readTakes.format": "a format id from the formats page"
+ "readTakes.format": "a format id from the formats page",
+ "colDamage": "Damage",
+ "colEffect": "What it does to the bytes",
+ "colSettings": "Settings",
+ "noSettings": "none"
},
"endings": {
"0": "Everything worked.",
@@ -279,7 +301,8 @@
},
{
"q": "Can I generate a file that is deliberately broken?",
- "a": "Not yet. Damaged and malformed files are a planned feature. Today every file the tool writes is a valid one of its format."
+ "a": "Yes. Add --damage zero-head and the file comes out at exactly the size you asked for with its first bytes overwritten by zeros, so a reader turns it away, and the manifest says your system should reject it. The page about corrupt test files has the details.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
},
{
"q": "Which formats are coming next?",
@@ -298,5 +321,8 @@
"q": "Why is a run over thousands of files slower on Windows?",
"a": "Because Windows charges more for every path it looks at, and a command that goes over thousands of files looks at thousands of paths. Measured on one machine with 3000 files of 1 kB, verify takes about 0.9 seconds on Windows and about 0.2 seconds on Linux in a container. A shorter output path makes the Windows figure smaller, because every folder above the files is part of what gets looked at."
}
- ]
+ ],
+ "damages": {
+ "zero-head": "Overwrites the first bytes of the file with zeros, leaving its length alone. Most readers look there first, so this is the damage almost anything notices."
+ }
}
diff --git a/web/content/en/use-cases.html b/web/content/en/use-cases.html
index 4ce91b67..b40ca638 100644
--- a/web/content/en/use-cases.html
+++ b/web/content/en/use-cases.html
@@ -105,6 +105,19 @@
Checking that your own code reads a format the way real software does
+
+
Guides
+
Two of these in more detail
+
+
+ Corrupt test files - a file broken on purpose, at an exact size, with what should happen to it written in the manifest.
+
+
+ Test files in CI - a GitHub Actions workflow, a GitLab job and the exit codes that fail a build.
+
+
+
+
Who this is for
diff --git a/web/content/es/ci.html b/web/content/es/ci.html
new file mode 100644
index 00000000..3bfdb861
--- /dev/null
+++ b/web/content/es/ci.html
@@ -0,0 +1,192 @@
+{{ with .Up }}
Cómo generar archivos de prueba en un pipeline de CI
+
+ Un fixture binario en un repositorio se queda para siempre en su historial, no se puede revisar en
+ un diff y deja de ser posible cuando el archivo es grande. Genera los archivos dentro del pipeline
+ a partir de una receta. La receta es texto, los bytes salen iguales cada vez y un último paso
+ demuestra que nada se movió.
+
+
+
+
La respuesta corta
+
+ Instala tfg, ejecuta tfg generate fixtures.yaml --out ./fixtures antes de
+ las pruebas y tfg verify ./fixtures/manifest.json después. Los dos pasos hacen
+ fallar la compilación por sí solos, con un código de salida que dice por qué.
+
+
+
+
+
Por qué no subirlos
+
Por qué un fixture no debe vivir en el repositorio
+
+
+ Se queda en el historial. Borrar un binario más tarde no hace más pequeño un clon,
+ porque todas sus versiones siguen ahí.
+
+
+ Un diff no muestra qué cambió. El revisor ve que un PDF es distinto y nada más. Una
+ receta cambia en una línea.
+
+
+ Los archivos grandes no caben. GitHub rechaza un push que contenga un archivo de
+ más de 100 MB, así que una prueba de un límite de subida de 500 MB no tiene nada que subir.
+
+
+
+ Lo que hay que subir es la receta. La misma receta y la misma semilla escriben los mismos bytes en
+ cualquier máquina, así que el archivo generado en el pipeline es el que tenías en tu portátil.
+
+
+
+
+
La receta
+
Una receta que vive junto a las pruebas
+
+ Esta escribe veinticinco facturas que deben aceptarse y dos imágenes por encima de un límite que
+ deben rechazarse, y el manifiesto registra las dos expectativas:
+
+ La línea de la suma de comprobación compara el archivo con verify-SHA256SUMS.txt de la
+ misma versión. La versión está fijada, así que una versión nueva nunca cambia una compilación
+ que no tocaste.
+
+ Cada final tiene su propio código de salida, así que el paso falla por sí solo y el registro dice
+ cuál fue. Los que encuentra un pipeline:
+
+
+
3 - la receta no es válida. No se escribió nada y se nombra cada problema
+
4 - el formato no puede hacer lo pedido, por ejemplo un tamaño por debajo de su mínimo
+
6 - no hay suficiente espacio en disco
+
7 - tfg verify encontró un archivo que no coincide con su manifiesto
+
8 - la ejecución terminó, pero no se produjo todo
+
+
+ Una ejecución fallida no imprime nada en la salida estándar, así que un analizador de registros
+ nunca toma un error por datos. La tabla completa está en la
+ página de documentación.
+
+
+
+
+
PowerShell
+
Un script de PowerShell necesita una línea más
+
+ PowerShell no saca el código de salida de un programa fuera de un archivo .ps1. Ejecuta
+ uno con -File y el script responde 0 incluso cuando la herramienta de
+ dentro rechazó el trabajo, así que una compilación que debería estar en rojo pasa a verde. La
+ última línea es toda la solución:
+
+ Así se comporta PowerShell, no es algo de esta herramienta. cmd, bash y
+ zsh no necesitan nada más.
+
+
+
+
+
Varios jobs
+
Compartir los fixtures entre jobs
+
+ Normalmente no hace falta subirlos. Como la misma receta escribe los mismos bytes, cada job puede
+ ejecutar su propio tfg generate, que es más rápido que subir y bajar. Cuando un job
+ tiene que recibir archivos de otro, ejecuta tfg verify sobre el manifiesto tras la
+ transferencia y te dice si lo que llegó es lo que se escribió.
+
+ Un validador al que solo se le han mostrado archivos sanos no está realmente probado. Así se
+ consigue un archivo roto a propósito, que sale con exactamente el tamaño que
+ pides y trae un manifiesto que dice qué debe hacer tu sistema con él.
+
+
+
+
La respuesta corta
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out escribe un PNG de
+ exactamente 2097152 bytes cuyos primeros bytes son ceros, y el manifiesto que lo acompaña
+ registra que tu sistema debe rechazarlo.
+
+
+
+
+
La forma habitual
+
Por qué un archivo corrompido a mano es una mala prueba
+
+ Lo habitual es un editor hexadecimal, un script que cambia unos cuantos bytes al azar o cortar un
+ archivo con head o truncate. Funciona una vez y después sale caro:
+
+
+
+ Es distinto cada vez. Un byte al azar cae en un sitio nuevo en cada ejecución, así
+ que un fallo del martes puede no volver el miércoles.
+
+
+ Cambia el tamaño. Un archivo cortado es más pequeño que el límite bajo el que debía
+ quedar, de modo que la comprobación de tamaño responde antes que la del contenido y la prueba
+ pasa por el motivo equivocado.
+
+
+ A menudo pasa inadvertido. El texto plano se sigue leyendo con un byte cambiado en
+ medio, y un lector de imágenes indulgente simplemente lo dibuja, así que el archivo que debía
+ estar roto se acepta.
+
+
+ No dice nada de lo que debe ocurrir. El archivo son solo bytes, y quien lea la
+ prueba después tiene que adivinar si se quería la aceptación o el rechazo.
+
+
+
+
+
+
Lo que obtienes
+
Un archivo dañado conserva el tamaño que pediste
+
+ El archivo se genera con normalidad y se rompe después, de camino al disco. Conserva el tamaño que
+ pediste, y el mismo comando vuelve a escribir los mismos bytes.
+
+ Los ajustes van después de dos puntos. La opción se puede repetir, y los daños se aplican en el
+ orden en que los escribes. Funciona con cada uno de los {{ .Facts.FormatCount }} formatos.
+
+
+
+
+
Lo que puede hacer
+
¿Qué daños hay?
+
+ Esta es la lista que imprime el programa, leída de él al construir esta página. tfg
+ damage imprime la misma, y tfg damage <id> dice qué admite cada uno.
+
+ {{ template "damagesTable" . }}
+
+ zero-head escribe ceros sobre el comienzo del archivo. La mayoría de los lectores miran
+ ahí primero, la firma y la cabecera que dicen qué es el archivo, así que casi cualquier lector
+ lo nota. El texto plano y los registros no tienen firma y también se rechazan, porque una serie
+ de bytes nulos no es texto. Por debajo de cuatro bytes algunos formatos salen con un daño del
+ que ningún lector se queja, por eso el ajuste empieza en cuatro.
+
+
+
+
+
Lo que dice el manifiesto
+
Un manifiesto que dice lo que debe ocurrir
+
+ Cada archivo dañado recibe una entrada que dice que tu sistema debe rechazarlo, con el daño anotado
+ al lado:
+
+ Se rechazan dos peticiones antes de escribir nada, porque cada una dejaría en el disco un archivo
+ que el manifiesto describe mal:
+
+
+
un archivo más pequeño de lo que el daño necesita, que saldría intacto
+
+ expected: accept junto a un daño, porque nada podría cumplirlo. Escribe
+ sanitize si tu sistema debe reparar el archivo, o unspecified si esa
+ es justo la pregunta que haces
+
+
+
+
+
+
En una receta
+
Archivos sanos y rotos en una sola ejecución
+
+ Pon ambos en una receta y el manifiesto lleva lo esperado de cada archivo, así que la prueba no
+ necesita una lista de cuál es cuál:
+
+ La prueba lee el manifiesto y comprueba que lo ocurrido es lo declarado. No necesita una lista de
+ nombres de archivo:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Un buen rechazo es un rechazo limpio. Un mensaje que dice qué estaba mal es la respuesta que
+ quieres. Un error de servidor, un bloqueo o un archivo guardado a medias es el defecto que esta
+ prueba existe para encontrar.
+
+
+
+
+
Siguiente
+
A dónde ir desde aquí
+
+
+ El preset upload-validation hace a un formulario las
+ otras dos preguntas, la del tamaño y la del tipo.
+
+
diff --git a/web/content/es/docs.html b/web/content/es/docs.html
new file mode 100644
index 00000000..92e8d695
--- /dev/null
+++ b/web/content/es/docs.html
@@ -0,0 +1,280 @@
+
Documentación
+
+ Todo lo que hace la herramienta, ordenado según las preguntas con las que la gente llega de verdad.
+ El README del repositorio es la referencia completa y siempre
+ coincide con la versión que descargaste.
+
+
+
+
¿Qué comandos hay?
+
Cada uno hace una sola cosa:
+ {{ template "commandList" . }}
+
+
+
+
¿Cómo genero un único archivo de tamaño exacto?
+
+ Indica el formato, el tamaño y dónde va. Los tamaños cuentan de 1024 en 1024, así que
+ 2mb son 2097152 bytes. Un número de bytes simple también sirve, de modo que
+ --size 10485761 pide exactamente esa cantidad.
+
+
tfg generate --format png --size 2mb --out ./out
+
Las opciones útiles de generate:
+
+
+
Opción
Qué hace
+
+
--format <id>
formato de los archivos, por ejemplo txt
+
--size <size>
tamaño exacto de cada archivo, como 10mb o un número de bytes simple
+
--size-range <a-b>
un tamaño sacado por archivo de un intervalo, como 1kb-8kb. El sorteo viene de la semilla
+
--boundary <size>
tres archivos alrededor de un límite: un byte por debajo, el límite, un byte por encima
+
--count <n>
cuántos archivos producir. Por defecto 1
+
--name <template>
plantilla de nombre, por ejemplo invoice_{index:04}.txt
+
--out <dir>
directorio donde escribir
+
--seed <n>
semilla de la ejecución. La misma semilla da los mismos bytes
+
--set <k>=<v>
un ajuste de formato, repetible
+
--damage <name>
romper los archivos a propósito, repetible y aplicado en orden. Ejecuta tfg damage para ver la lista
+
--expected <outcome>
accept, reject, sanitize o unspecified
+
--dry-run
contar y mostrar, sin escribir absolutamente nada
+
--json
escribir el manifiesto en la salida estándar
+
+
+
+
+
+
+
¿Cómo hago un archivo roto a propósito?
+
+ Todos los demás archivos que escribe esta herramienta son correctos por construcción, lo que
+ responde a dos de las tres preguntas que hace un validador de subidas. --damage
+ responde a la tercera - si el archivo se abre siquiera. El archivo se produce con normalidad y
+ luego se rompe, así que conserva el tamaño que pediste.
+
+ Los ajustes van después de dos puntos. La opción se repite, y el orden en que las escribes es el
+ orden en que se aplican. tfg damage lista lo que puede hacer esta versión y qué
+ admite cada una.
+
+
En una receta la clave es una lista, de nombres o de ajustes:
+ Un archivo dañado recibe expected: reject en el manifiesto, con el daño registrado a su
+ lado. Dos cosas se rechazan antes de escribir nada, porque cada una dejaría en disco un archivo
+ que el manifiesto describe mal:
+
+
+
un archivo más pequeño de lo que necesita el daño, porque saldría sin cambios
+
+ expected: accept junto a un daño, porque nada podría cumplirlo. Escribe
+ sanitize si el sistema bajo prueba debe reparar el archivo, o
+ unspecified si esa es la pregunta que haces
+
+
+
+ Una tercera no se puede saber de antemano. Si un daño se ejecuta y no mueve ningún byte, ese archivo
+ se descarta en lugar de escribirse - la ejecución continúa, dice de qué archivo se trató y
+ termina con el código de salida parcial.
+
+ Una receta es un archivo YAML que describe una ejecución completa. Súbela al repositorio junto a tus
+ pruebas y los fixtures dejan de ser binarios en tu repositorio - cualquiera puede
+ reconstruirlos, byte a byte, a partir de un archivo de unos cientos de caracteres.
+
+ Cada target necesita exactamente una de estas claves: size, size-range,
+ boundary o contains. Dos es un error y ninguna también. Una receta
+ inválida escribe ningún archivo e informa de todos los problemas a la vez en
+ lugar de solo del primero, cada uno nombrando el ajuste al que se refiere.
+
+
+
+
+
¿Cómo declaro qué debe hacer mi sistema con un archivo?
+
Forma corta cuando basta con el resultado, forma larga cuando importa el motivo:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Los resultados son accept, reject, sanitize y
+ unspecified. Los motivos son una lista cerrada para que un informe pueda
+ agruparlos: content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit y size_zero.
+
+
+ Un motivo nombra la regla en juego, no el veredicto. Por eso el mismo motivo puede
+ estar bajo cualquiera de los dos resultados - un archivo un byte por debajo de un límite es
+ accept, y la regla de la que trata sigue siendo size_limit.
+
+
+
+
+
¿Qué hay en el manifiesto?
+
+ Se escribe junto a los archivos al final de cada ejecución, incluida una ejecución interrumpida. Una
+ entrada por archivo:
+
+ Se añade un recipe_hash cuando la ejecución viene de una receta, y preset
+ con overrides cuando viene de un preset, de modo que un manifiesto siempre se puede
+ rastrear hasta lo que lo produjo.
+
+
+ Cada entrada lleva también target_id, el id del target de la receta que produjo el
+ archivo, y summary.by_target cuenta los archivos a los que llegó cada target. Una
+ receta con varios targets se puede comprobar así target por target sin leer nombres de archivo.
+
+
+
+
+
¿Qué es un preset?
+
+ Un conjunto de archivos listo que responde a una pregunta de prueba habitual, para que no tengas que
+ diseñar el conjunto tú. Los presets son recetas normales por debajo, y eject
+ imprime la receta para que la edites desde ahí. Cada preset tiene una
+ página propia con lo que suele encontrar, qué hay en el conjunto y cada ajuste que admite.
+
+ show te dice cuánto costaría el conjunto antes de construirlo, y dice sin rodeos cuándo
+ un número es un marcador nuestro en lugar de un límite tuyo.
+
+
+
+
+
¿Qué significan los códigos de salida?
+
+ Cada final tiene su propio código, la salida legible por máquina va a la salida estándar, y una
+ ejecución fallida no imprime nada allí. La tabla es un contrato congelado - cambiar lo que
+ significa un código exige una versión mayor.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Una ejecución detenida con Ctrl+C sigue dejando un manifiesto y nunca deja un archivo a medio
+ escribir, así que un trabajo cancelado aún puede limpiarlo el siguiente.
+
+ Sí, el mismo motor con una ventana encima, para las pruebas que no se automatizan. No es una versión
+ recortada: una prueba compara las dos interfaces capacidad por capacidad, y todo lo que solo una
+ de ellas puede hacer debe declararse y justificarse en lugar de divergir en silencio.
+
+
+ Las pantallas son un lote, presets, varios lotes a la vez y Acerca de. Muestra lo que costaría una
+ ejecución antes de escribir nada, informa del progreso mientras corre y se puede cancelar a
+ medias sin dejar un archivo a medio escribir. Todavía no abre un archivo de receta - por ahora
+ las recetas son cosa de la línea de comandos, y la ventana construye sus lotes en el formulario.
+
+
diff --git a/web/content/es/exact-size.html b/web/content/es/exact-size.html
new file mode 100644
index 00000000..83c13048
--- /dev/null
+++ b/web/content/es/exact-size.html
@@ -0,0 +1,145 @@
+
Cómo crear un archivo de un tamaño exacto
+
+ Cada sistema tiene un comando para ello, y los tres están abajo. Te dan un archivo con exactamente
+ el número correcto de bytes - y para muchas pruebas eso es todo lo que necesitas. Cada
+ comando de esta página se ejecutó antes de publicarse, en el sistema al que pertenece.
+
+
+
+
La respuesta corta
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Los tamaños son en bytes, y 10 MB
+ contados como los cuenta tu gestor de archivos son 10485760.
+
+
+
+
+
Windows
+
fsutil, y una versión de PowerShell que no necesita nada extra
+
+ fsutil viene con Windows. Toma el tamaño en bytes, así que calcula
+ antes el número - 10 MB son 10485760, 100 MB son 104857600, 1 GB es 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Medido en Windows 11: funciona desde un símbolo del sistema normal sin necesitar uno elevado, y el
+ archivo sale con exactamente 10485760 bytes.
+
+
PowerShell puede hacer lo mismo sin llamar a otro programa, y entiende unidades:
+ 10MB en PowerShell significa 10485760 bytes, el mismo recuento en base 1024 que usa el
+ Explorador, así que los dos comandos anteriores producen el mismo tamaño.
+
+
+
+
+
Linux
+
dd, truncate y fallocate, y la diferencia que pilla a la gente
+
dd es el que todo el mundo conoce. Escribe los bytes de verdad:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate es instantáneo, y esa es la trampa. Medido en Alpine Linux, el archivo informa
+ de 10485760 bytes y ocupa cero bloques - es un archivo
+ disperso. Cualquier cosa que lo lea obtiene diez megabytes de ceros, pero el disco
+ nunca cedió el espacio:
+
+
truncate -s 10M test10mb.bin
+
+ Eso sirve para probar un límite de subida y engaña para probar una cuota de disco.
+ fallocate es el que hay que usar cuando el espacio tiene que ser real:
+
+
fallocate -l 10M test10mb.bin
+
Y cuando el contenido tiene que ser incompresible, para que un compresor no pueda volver a reducirlo:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, que no es disperso, y los dos que ya conoces
+
+ macOS incluye mkfile. Medido en macOS 26.6.2: 10485760 bytes y 20480 bloques, así que
+ el espacio está realmente asignado en lugar de prometido:
+
+
mkfile 10m test10mb.bin
+
dd y truncate también están y se comportan como en Linux:
Un archivo del tamaño correcto no es un archivo del tipo correcto
+
+ Todo lo anterior te da un bloque de ceros. Eso basta cuando lo que se prueba solo mira el tamaño -
+ un límite de subida, una cuota, una transferencia. Deja de bastar en cuanto algo
+ abre el archivo.
+
+
+ Medido, y merece la pena que lo hagas tú: crea un archivo de 2 MB con fsutil, llámalo
+ photo.png y pásaselo a una biblioteca de imágenes. Pillow responde cannot
+ identify image file. No es un PNG. Nunca lo fue - solo lo decía el nombre.
+
+
+ Eso importa más de lo que parece, por la forma en que la prueba falla entonces. Tu
+ endpoint de subida rechaza el archivo, tu prueba se pone en verde y concluyes que el límite de
+ tamaño funciona. No lo rechazó por el tamaño. Lo rechazó porque los bytes no eran una imagen, y
+ la regla que querías probar nunca se alcanzó.
+
+
+
un analizador lo rechaza antes de mirar ninguna regla de tamaño
+
falla un paso de miniaturas y el error que lees trata de la miniatura
+
un antivirus o una comprobación de contenido lo rechaza por un tercer motivo
+
un visor no muestra nada, y nadie puede saber si ese es el fallo
+
+
+
+
+
La otra vía
+
Un archivo real de ese formato, con exactamente el tamaño que pediste
+
+ Esto es lo que hace Testing Files Generator. El archivo es uno genuino de su formato - se abre en el
+ programa que le corresponde - y tiene el número exacto de bytes que pediste, al byte:
+
+ Pide un tamaño que un formato no puede alcanzar y obtienes un error que nombra el suelo y su motivo,
+ nunca un archivo del tamaño equivocado. La página de formatos lista
+ cada formato con el archivo más pequeño que puede producir.
+
+
Y un límite son tres casos de prueba y no uno, así que la herramienta construye los tres:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Eso te da 10485759, 10485760 y 10485761 bytes, y un manifiesto que dice cuáles debe aceptar tu
+ sistema y cuáles rechazar. La página de casos de uso repasa eso
+ y otras cuatro tareas para las que está pensada.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Entonces, ¿cuál debes usar?
+
+
+
Usa el comando del sistema
+
+ Cuando nada abre el archivo. Probar un límite de tamaño en un endpoint que comprueba antes el
+ tamaño, una transferencia, una cuota, un disco lleno. Es una línea y ya está instalado.
+
+
+
+
Usa un generador real
+
+ Cuando algo analiza, renderiza, importa o extrae el archivo - y cuando necesitas los mismos fixtures
+ mañana, en otra máquina, byte a byte.
+
+
+
+
+ Ambos están en esta página porque ambos aciertan parte del tiempo. El error que conviene evitar es
+ usar el primero donde hace falta el segundo y leer la prueba en verde como una demostración.
+
+
diff --git a/web/content/es/faq.html b/web/content/es/faq.html
new file mode 100644
index 00000000..29dece9c
--- /dev/null
+++ b/web/content/es/faq.html
@@ -0,0 +1,20 @@
+
Preguntas frecuentes
+
+ Licencia, privacidad, reproducibilidad y lo que la gente comprueba antes de poner un generador en
+ una canalización de compilación. Si tu pregunta no está aquí, el
+ gestor de incidencias está abierto.
+
{{ .Facts.FormatCount }} formatos de archivo, cada uno generado a un tamaño exacto
+
+ Cada uno es un archivo real de ese formato. Se abre en el programa que le
+ corresponde y tiene exactamente el número de bytes que pediste. Ninguno es relleno de ceros con
+ una extensión pegada.
+
+
+{{ template "formatsTable" . }}
+
+
+
Qué significan las columnas
+
+
+
Archivo más pequeño
+
+ Los menos bytes que esta herramienta aceptará para ese formato, incluida la etiqueta que escribe
+ dentro del archivo. Pide menos y obtienes un error que nombra el suelo y su motivo, nunca un
+ archivo del tamaño equivocado.
+
+
+
+
Fidelidad
+
+ Cuán completo es el archivo. full significa que lo acepta un lector que analiza de
+ verdad el formato, no solo que la extensión coincida.
+
+
+
+
Comprobado con
+
+ El lector independiente que abre cada archivo generado antes de que el formato se publique - una
+ implementación aparte, no nuestro propio código corrigiendo sus propios deberes.
+
+
+
+
+ Cada formato también se repite byte a byte: la misma receta y la misma semilla producen archivos
+ idénticos en cualquier máquina, y eso es lo que hace seguro subir al repositorio una receta en
+ lugar de los fixtures mismos.
+
+
+
+
+
Ajustes que admite cada formato
+
+ La mayoría de los formatos tienen ajustes propios - dimensiones de imagen, calidad JPEG, número de
+ páginas de PDF, filas y columnas de una hoja de cálculo, cuántas entradas van dentro de un
+ archivo comprimido. Defínelos con --set key=value en la línea de comandos, o bajo
+ properties: en una receta.
+
+ Un valor fuera de lo que admite un ajuste se rechaza con un mensaje que nombra el ajuste, el
+ intervalo permitido y qué usar en su lugar. Un ajuste desconocido también es un error, nunca un
+ valor por defecto silencioso - una errata aceptada en silencio da un archivo con los ajustes
+ equivocados y una hora preguntándote por qué la prueba pasa cuando no debería.
+
+
+ Ejecuta tfg formats <id> para ver exactamente qué admite un formato en la versión
+ que tienes.
+
+
+
+
+
Los archivos comprimidos contienen archivos reales
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} y {{ end }}{{ $c.ID }}{{ end }} se
+ pueden llenar de entradas en lugar de quedar como un cascarón vacío. Un archivo comprimido
+ generado contiene de verdad los documentos que dice contener, así que todo lo que lo descomprima
+ durante una prueba encuentra archivos reales dentro.
+
+ PDF, PNG, DOCX, ZIP - {{ .Facts.FormatCount }} formatos en total, y cada uno es un
+ archivo real que se abre en el programa que le corresponde, con exactamente el tamaño
+ que pediste. Cada ejecución también anota qué debe hacer tu aplicación con cada
+ archivo. Línea de comandos y ventana de escritorio, gratis y de código abierto, funcionando por
+ completo en tu máquina.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ La ventana de escritorio, lista para escribir un lote de archivos. El mismo motor funciona detrás de la línea de comandos.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
formatos reales, cada uno se abre en el programa que le corresponde
+
+
+ 1 byte
+
la precisión de cada tamaño que pides, nunca redondeado en silencio
+
+
+ 0
+
conexiones a ningún sitio - sin cuenta, sin telemetría, sin comprobación de actualizaciones
+
+
+
+
+
El problema
+
Hacer un archivo de prueba es fácil. Hacer los mil correctos es la parte tediosa
+
Estás probando software que acepta archivos de personas. Tarde o temprano necesitas:
+
+
un PDF de exactamente 10 MB, para saber si el límite de subida es real
+
los tres archivos a ambos lados de ese límite, para cazar errores de uno
+
10 000 archivos de registro, para ver qué hace el trabajo nocturno cuando la carpeta es grande
+
un ZIP que de verdad contiene 200 documentos, no un cascarón con la extensión correcta
+
un archivo de 4 GB, sin guardar un archivo de 4 GB en tu repositorio
+
los mismos fixtures en tu portátil y en el servidor de compilación, byte a byte
+
+
+ Eso es lo que esto sustituye. Está pensado para ingenieros de QA, automatización de pruebas y
+ cualquiera cuyo código tenga detrás un formulario de subida, una rutina de importación, un
+ analizador o una cuota de almacenamiento.
+
+
+
+
+
Qué lo hace distinto
+
Otros generadores se quedan en los bytes. Este responde a lo que tu prueba realmente pregunta
+
+ Una carpeta de archivos te deja aún decidiendo qué se supone que demuestra cada uno. Cada ejecución
+ escribe aquí un manifest.json junto a los archivos - una lista simple de todo lo
+ producido y, para cada entrada, una expectativa declarada.
+
+
Supón que tu endpoint de subida permite 1 MB. Pide los tres archivos que están sobre esa línea:
Donde la respuesta depende de tu propia política, el manifiesto lo dice
+
+ Registra unspecified en lugar de inventar una expectativa. Un generador que adivina
+ produce falsos fallos, y un conjunto de pruebas que da falsas alarmas acaba apagado.
+
+
+
+
+
+
Presets
+
Elige la pregunta, obtén el conjunto entero
+
+ Un preset es un conjunto de archivos de prueba diseñado en torno a una pregunta de prueba, para que
+ no tengas que averiguar qué archivos demuestran qué. Cada uno tiene una página que dice qué
+ suele encontrar, qué hay en el conjunto y cada ajuste que admite.
+
+ Diez mil archivos de registro, cada uno de entre uno y ocho kilobytes, con los tamaños sacados de la
+ semilla para que mañana dé el mismo conjunto. Dale a cada ejecución su propio
+ directorio - el manifiesto es el único registro de lo que escribió una ejecución,
+ así que la herramienta se niega a escribir un segundo encima:
+
+ Los tamaños cuentan de 1024 en 1024, como hace tu gestor de archivos, así que 2mb
+ significa 2097152 bytes. Un número de bytes simple también sirve. La
+ documentación cubre las recetas, el manifiesto y los códigos de
+ salida.
+
+
+
+
+
Qué obtienes
+
Pensado para un conjunto de pruebas que corre sin supervisión
+
+
+
Tamaño exacto, al byte
+
Pide 10485761 bytes y obtén exactamente eso. Un tamaño que un formato no puede alcanzar es un error con un motivo, nunca un archivo del tamaño equivocado.
+
+
+
{{ .Facts.FormatCount }} formatos reales
+
No ceros de relleno con una extensión. Un PNG generado se abre en un visor de imágenes, un DOCX se abre en Word, un ZIP se extrae. Cada uno se comprueba con lectores independientes antes de publicarse.
+
+
+
Un manifiesto que es un oráculo de pruebas
+
Ruta, tamaño, SHA-256, formato, semilla, versión de la herramienta - y qué debe hacer tu sistema con el archivo.
+
+
+
Reproducible
+
Misma receta y misma semilla, mismos bytes, en cualquier máquina. Sube al repositorio una receta YAML pequeña en lugar de fixtures binarios grandes.
+
+
+
Dos interfaces, un motor
+
Una línea de comandos pensada para CI y una ventana de escritorio para pruebas exploratorias. Ninguna es una versión recortada de la otra, y una prueba las compara capacidad por capacidad.
+
+
+
Completamente sin conexión
+
Sin cuenta, sin nube, sin telemetría, sin comprobación de actualizaciones. El binario de la línea de comandos no lleva compilada ninguna pila de red.
+
+
+
+
+
+
Descarga
+
Elige la versión para tu sistema
+
+ Descomprime el archivo y ejecútalo. tfg es la línea de comandos y tfg-gui
+ es la ventana de escritorio. No hay instalador ni nada que añadir a tu máquina.
+
+ {{ template "downloadsTable" . }}
+
+
Qué está firmado y qué no
+
+ Las descargas de Windows y macOS están firmadas, así que se inician sin advertencia de desarrollador
+ desconocido. Las de Linux no, porque Linux de escritorio no tiene un equivalente con el que
+ firmarlas. Cada archivo aparece en verify-SHA256SUMS.txt en la página de
+ versiones, para que puedas comprobar lo que descargaste.
+
+ El preset {{ .ID }} construye con un solo comando un conjunto entero de archivos de
+ prueba reales para esta pregunta, y un manifest.json a su lado que dice cómo debe
+ reaccionar tu sistema a cada archivo. Todo lo de abajo se lee del programa, con los valores por
+ defecto de esta versión.
+
+
+{{ if .Catches }}
+
+
¿Qué suele encontrar?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
¿Qué hay en el conjunto?
+
Con sus valores por defecto, tal como lo informa tfg preset show {{ .ID }}:
+
+
+
+
Archivos
{{ .Budget.Files }}
+
Targets en su receta
{{ .Budget.Targets }}
+
Tamaño total
{{ .Bytes }} B
+
Formatos
{{ join .Budget.Formats ", " }}
+
+
+
+
Y lo que el manifiesto de ese conjunto espera de tu sistema:
+
+
+
+
Esperado
Significado
Archivos
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
¿Qué puedes cambiar?
+ {{- if .Settings }}
+
+
+
+
Ajuste
Admite
Por defecto
Qué hace
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Este valor por defecto es nuestro marcador, no el valor de tu sistema. Pasa el tuyo.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
Este preset no tiene ajustes. El conjunto es el mismo cada vez.
+ {{- end }}
+
+
+
+
¿Cómo se ejecuta?
+
Mira cuánto costaría el conjunto, constrúyelo o toma su receta para editarla:
O construye sobre él en una receta propia, junto a tus pruebas:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/es/presets.html b/web/content/es/presets.html
new file mode 100644
index 00000000..d62333af
--- /dev/null
+++ b/web/content/es/presets.html
@@ -0,0 +1,32 @@
+
Presets de archivos de prueba, un conjunto para cada pregunta de prueba
+
+ Un preset es un conjunto entero de archivos de prueba diseñado en torno a una pregunta, con un
+ manifiesto que dice cómo debe reaccionar tu sistema a cada archivo. Tú eliges la pregunta, la
+ herramienta construye el conjunto. Cada preset tiene su propia página con lo que suele encontrar,
+ qué hay en el conjunto y cada ajuste que admite.
+
+
+{{ template "presetsList" . }}
+
+
+
¿En qué se diferencia un preset de una receta?
+
+ Por debajo, en nada. Un preset es una receta que la herramienta escribe por ti a partir de unos
+ pocos ajustes. tfg preset eject imprime esa receta para que la guardes junto a tus
+ pruebas y la edites, y una receta tuya puede basarse en un preset con una línea, extends:
+ preset: seguido de su id.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
¿Puedo fiarme de los valores por defecto?
+
+ Para los archivos, sí. Para un número que solo conoce tu sistema, como el límite de un formulario de
+ subida, un valor por defecto es un marcador nuestro, y la herramienta lo dice cada vez que usa
+ uno. La página de cada preset marca esos ajustes, y tfg preset show lo dice antes
+ de escribir nada.
+
+
diff --git a/web/content/es/site.json b/web/content/es/site.json
new file mode 100644
index 00000000..795551ac
--- /dev/null
+++ b/web/content/es/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "es",
+ "locale": "es_ES",
+ "name": "Español",
+ "dir": "es",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Inicio",
+ "title": "Generador de archivos de prueba - tamaño exacto, {{ .Facts.FormatCount }} formatos",
+ "description": "Generador gratuito y de código abierto de archivos de prueba para QA. PDF, DOCX, PNG y ZIP reales al tamaño exacto, con un manifiesto de la reacción esperada."
+ },
+ {
+ "key": "formats",
+ "slug": "formatos",
+ "nav": "Formatos",
+ "title": "{{ .Facts.FormatCount }} formatos de archivo - PDF, DOCX, PNG, ZIP y más",
+ "description": "Todos los formatos que genera, el archivo más pequeño posible de cada uno y los ajustes que admite. Los {{ .Facts.FormatCount }} se abren en el programa que les corresponde."
+ },
+ {
+ "key": "presets",
+ "slug": "presets",
+ "nav": "Presets",
+ "title": "Presets de archivos de prueba - conjuntos listos para QA",
+ "description": "Conjuntos listos de archivos de prueba, cada uno responde a una pregunta: límites de subida, nombres, codificaciones, importación, archivos vacíos y validación."
+ },
+ {
+ "key": "docs",
+ "slug": "documentacion",
+ "nav": "Documentación",
+ "title": "Documentación - comandos, recetas, manifiesto, códigos de salida",
+ "description": "Cómo generar archivos de prueba desde la línea de comandos o con una receta YAML, qué contiene el manifiesto y qué significa cada código de salida en CI."
+ },
+ {
+ "key": "use-cases",
+ "slug": "casos-de-uso",
+ "nav": "Casos de uso",
+ "title": "Casos de uso - límites de subida, fixtures, pruebas masivas",
+ "description": "Probar un límite de tamaño de subida, crear fixtures reproducibles para CI, generar diez mil archivos y llenar archivos comprimidos con contenido real."
+ },
+ {
+ "key": "exact-size",
+ "slug": "crear-archivo-de-tamano-exacto",
+ "nav": "Tamaño exacto",
+ "title": "Crear un archivo de un tamaño exacto - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate y mkfile, medidos cada uno en su sistema, y por qué un archivo así creado no es un PDF ni un PNG cuando una prueba necesita uno."
+ },
+ {
+ "key": "faq",
+ "slug": "preguntas-frecuentes",
+ "nav": "FAQ",
+ "title": "Preguntas frecuentes - generar archivos de prueba",
+ "description": "En qué se diferencia de dd y fsutil, si los archivos se pueden subir al repositorio, si las ejecuciones se repiten byte a byte y qué pasa con un tamaño inalcanzable."
+ },
+ {
+ "key": "damage",
+ "slug": "archivos-de-prueba-corruptos",
+ "nav": "Archivos corruptos",
+ "title": "Archivos de prueba corruptos - archivos rotos de tamaño exacto",
+ "description": "Un archivo roto a propósito, con el tamaño exacto que pides y un manifiesto que dice que tu sistema debe rechazarlo. Para probar validación de subidas y parsers.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "archivos-de-prueba-en-ci",
+ "nav": "Archivos de prueba en CI",
+ "title": "Archivos de prueba en CI - GitHub Actions, GitLab CI y PowerShell",
+ "description": "Genera archivos de prueba en el pipeline en vez de subir binarios: workflow de GitHub Actions, job de GitLab, códigos de salida y la trampa de PowerShell.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "Saltar al contenido",
+ "navLabel": "Principal",
+ "langLabel": "Idioma",
+ "breadcrumbHome": "Inicio",
+ "imageAlt": "Testing Files Generator - archivos de prueba reales al tamaño exacto, con un manifiesto que dice cómo debe reaccionar tu sistema a cada uno",
+ "schemaDescription": "Un generador gratuito y de código abierto de archivos de prueba para QA. Produce archivos reales de {{ .Facts.FormatCount }} formatos al tamaño exacto y escribe un manifiesto que dice cómo debe reaccionar el sistema bajo prueba a cada uno.",
+ "ctaDownload": "Descargar",
+ "ctaSource": "Ver el código fuente",
+ "ctaNote": "Gratuito y de código abierto, GPL-3.0. Sin registro. Las descargas de Windows y macOS están firmadas y se inician sin advertencias.",
+ "colFormat": "Formato",
+ "colName": "Nombre",
+ "colExtension": "Extensión",
+ "colSmallest": "Archivo más pequeño",
+ "colFidelity": "Fidelidad",
+ "colChecked": "Comprobado con",
+ "colSetting": "Ajuste",
+ "colAccepts": "Admite",
+ "colSystem": "Sistema",
+ "colCli": "Línea de comandos",
+ "colWindow": "Ventana de escritorio",
+ "noBinary": "aún sin binario",
+ "colCode": "Código",
+ "colMeaning": "Significado",
+ "footerBlurb": "Archivos de prueba para QA, al tamaño exacto, con un manifiesto que dice cómo debe reaccionar tu sistema a cada uno.",
+ "footerProject": "Proyecto",
+ "footerSource": "Código en GitHub",
+ "footerReleases": "Descargas",
+ "footerIssues": "Informar de un problema",
+ "footerSupport": "Apoyar el proyecto",
+ "footerPages": "Páginas",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. Publicado bajo la Licencia Pública General de GNU, versión 3. Los archivos que generes son tuyos - la licencia cubre la herramienta, no su salida.",
+ "footerPrivacy": "Este sitio no carga fuentes, scripts ni rastreadores de ningún sitio. No usa cookies.",
+ "notFoundTitle": "Esa página no está aquí",
+ "notFoundLead": "La dirección que has seguido no coincide con ninguna página de este sitio.",
+ "notFoundBack": "Ir al inicio",
+ "read.format": "El formato de cada archivo del conjunto. Es una opción de la propia herramienta, y el preset solo le da un valor por defecto.",
+ "readTakes.format": "un id de formato de la página de formatos",
+ "colDamage": "Daño",
+ "colEffect": "Qué hace con los bytes",
+ "colSettings": "Ajustes",
+ "noSettings": "ninguno"
+ },
+ "endings": {
+ "0": "Todo ha funcionado.",
+ "1": "Un error inesperado dentro de la herramienta.",
+ "2": "Comando u opción incorrectos.",
+ "3": "La receta no es válida.",
+ "4": "El formato no puede hacer lo que se pidió.",
+ "5": "Ha fallado una lectura o una escritura.",
+ "6": "No hay espacio suficiente en disco.",
+ "7": "verify ha encontrado una discrepancia.",
+ "8": "La ejecución terminó, pero no se produjo todo.",
+ "130": "Interrumpido con Ctrl+C.",
+ "143": "Detenido por una señal, que es el aspecto de un tiempo de espera agotado en CI."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "¿Pasa un archivo válido y tan pequeño como permite el formato?",
+ "title": "Vacío y mínimo",
+ "pageTitle": "Archivos de prueba válidos mínimos y vacíos en cada formato",
+ "description": "El archivo válido más pequeño que escribe en cada uno de sus {{ .Facts.FormatCount }} formatos, más un archivo vacío donde el formato lo permite, cada uno con su reacción esperada.",
+ "catches": [
+ "un archivo válido rechazado por ser demasiado pequeño, porque la comprobación cuenta bytes en lugar de leerlos",
+ "un archivo vacío que hace caer al lector en vez de ser notificado",
+ "una imagen de un píxel de ancho que divide entre cero de camino a la miniatura",
+ "un almacenamiento que lee cero bytes como una subida fallida y sigue reintentando"
+ ],
+ "details": {
+ "formats": "De qué formatos se compone el conjunto. Déjalo en all para todos los formatos de esta versión, o nombra los que acepta tu sistema."
+ }
+ },
+ "filename-handling": {
+ "question": "¿Mi sistema guardará, mostrará y devolverá un nombre de archivo que no esperaba?",
+ "title": "Manejo de nombres de archivo",
+ "pageTitle": "Nombres de archivo problemáticos para probar - Unicode y longitud",
+ "description": "Archivos con nombres que rompen subidas y almacenamiento: otras escrituras, emoji, inversión de dirección, caracteres invisibles, sintaxis de shell y SQL, longitud.",
+ "catches": [
+ "un nombre que parece otro en pantalla, en un registro o en una lista",
+ "un nombre cortado, recortado o reescrito entre la subida y el almacenamiento",
+ "un límite de longitud contado en caracteres donde el almacenamiento cuenta bytes"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "¿Se aplica un límite de tamaño exactamente donde se declara?",
+ "title": "Límites de tamaño",
+ "pageTitle": "Probar un límite de tamaño de subida - archivos en el límite",
+ "description": "Archivos un byte por debajo, justo en y un byte por encima del límite que declara tu sistema, más pasos más amplios, cada uno marcado según deba aceptarse o no.",
+ "catches": [
+ "errores de uno en el límite",
+ "MB confundido con MiB, que son un 4,8 por ciento y bastan para dejar pasar un archivo que no debería pasar",
+ "un límite aplicado en el navegador y no en el servidor"
+ ],
+ "details": {
+ "limit": "El límite de tamaño que declara tu sistema. Todo lo demás se mide a partir de él.",
+ "spread": "Hasta dónde llegar a cada lado del límite, como una lista de tamaños."
+ }
+ },
+ "tabular-import": {
+ "question": "¿Sobrevive mi importación de tablas a lo que exportan las herramientas reales?",
+ "title": "Importación de tablas",
+ "pageTitle": "Archivos de prueba para importar CSV y Excel - delimitadores",
+ "description": "CSV con otros delimitadores, finales CR LF, sin cabecera y con otras comillas, una tabla muy ancha, un libro de Excel y JSON en varias formas.",
+ "catches": [
+ "un archivo con punto y coma leído como una sola columna, porque el delimitador se supuso en lugar de buscarse",
+ "un archivo CRLF partido en filas con una fila vacía después de cada una",
+ "una tabla sin cabecera cuya primera fila de datos se come como nombres de columna",
+ "una importación que conserva las columnas que puede mostrar y descarta el resto sin decir nada",
+ "un lector que toma los registros JSON de uno en uno por línea y se detiene en el primer documento con sangría"
+ ],
+ "details": {
+ "rows": "Cuántas filas contiene la hoja de cálculo. Se escribe exactamente con el tamaño que ocupan tantas filas, así que el presupuesto de arriba se mueve con este valor.",
+ "columns": "Cuántas columnas tiene cada fila de la hoja de cálculo. Filas por columnas tiene un techo, y pedir más se rechaza antes de escribir nada."
+ }
+ },
+ "text-encoding": {
+ "question": "¿Sabe mi lector en qué codificación está un archivo, o lo adivina?",
+ "title": "Codificación de texto",
+ "pageTitle": "Archivos de prueba de codificación - UTF-8, UTF-16, BOM, CRLF",
+ "description": "El mismo texto en UTF-8, UTF-16LE y UTF-16BE, con y sin marca de orden de bytes, y finales de línea CR LF y LF, para probar cómo decodifica un lector.",
+ "catches": [
+ "un lector que supone UTF-8 y muestra un archivo UTF-16 con un carácter de cada tres, o como filas de cuadros",
+ "una marca de orden de bytes leída como contenido, de modo que el primer campo de una importación empieza con tres caracteres extraños",
+ "un importador que adivina la codificación por los primeros bytes y adivina distinto con un archivo más largo",
+ "un archivo CRLF partido en filas con una fila vacía después de cada una, o un retorno de carro que queda dentro del último campo"
+ ],
+ "details": {
+ "sample": "El tamaño de cada archivo del conjunto. UTF-16 guarda dos bytes por carácter, así que un número impar se rechaza."
+ }
+ },
+ "upload-validation": {
+ "question": "¿Mi formulario de subida acepta lo que debe y rechaza el resto?",
+ "title": "Validación de subida",
+ "pageTitle": "Archivos de prueba de validación de subida - tipo, tamaño y nombre",
+ "description": "Archivos para probar un formulario de subida: tipos permitidos y denegados, contenido que no coincide con la extensión, tamaño límite, nombres hostiles y subida masiva.",
+ "catches": [
+ "un límite aplicado en el navegador y no en el servidor",
+ "un SVG o un HTML tomado por una imagen o por texto plano, que es una forma de colar un script por un formulario",
+ "un archivo comprobado por su extensión y nunca abierto, de modo que un PDF llamado .jpg pasa",
+ "un formulario que lee todo el cuerpo en memoria antes de mirar su tamaño",
+ "una subida llamada PHOTO.JPG rechazada donde photo.jpg se acepta, o al revés",
+ "un nombre con espacios, paréntesis o caracteres fuera de ASCII escrito en disco sin cambios"
+ ],
+ "details": {
+ "limit": "El límite de tamaño que declara tu formulario de subida. Este conjunto da un paso a cada lado - para un archivo a cada distancia, ejecuta el preset size-boundaries.",
+ "allow": "Qué tipos debe aceptar tu formulario. Cada uno se convierte en un archivo real de ese tipo, y son el control positivo de todo el conjunto.",
+ "deny": "Qué extensiones debe rechazar tu formulario. Una extensión para la que esta versión no tiene formato recibe igualmente un archivo con ese nombre, con texto plano.",
+ "far-over": "Cuánto se pasa del límite el único archivo grande. Desactívalo donde escribir varias veces el límite no compense el disco.",
+ "bulk": "Cuántos archivos contiene la subida masiva. Cero deja ese grupo fuera del conjunto por completo."
+ }
+ }
+ },
+ "commands": {
+ "generate": "producir archivos, desde una receta o desde opciones",
+ "validate": "comprobar una receta sin escribir nada",
+ "verify": "comprobar un directorio contra un manifiesto",
+ "cleanup": "eliminar los archivos que lista un manifiesto",
+ "recipe fmt": "imprimir una receta en su forma normalizada",
+ "preset": "construir un conjunto de archivos a partir de una pregunta de prueba con nombre",
+ "formats": "listar los formatos que admite esta versión",
+ "damage": "listar las formas en que esta versión puede romper un archivo a propósito",
+ "tool": "pequeñas utilidades para archivos que ya tienes",
+ "version": "imprimir la versión de la herramienta",
+ "license": "imprimir la licencia y qué significa para los archivos generados"
+ },
+ "outcomes": {
+ "accept": "Tu sistema debe aceptar el archivo.",
+ "reject": "Tu sistema debe rechazar el archivo.",
+ "sanitize": "Tu sistema debe aceptar el archivo y limpiarlo, por ejemplo cambiándole el nombre.",
+ "unspecified": "Depende de las reglas de tu sistema. Tú decides y después compruebas que lo que ocurre es lo que querías."
+ },
+ "damages": {
+ "zero-head": "Sobrescribe los primeros bytes del archivo con ceros sin tocar su longitud. La mayoría de los lectores miran ahí primero, así que casi todo nota este daño."
+ },
+ "terms": {
+ "oracleNone": "no aplicable",
+ "int": "cualquier número entero",
+ "choice": "uno de un conjunto fijo",
+ "bool": "verdadero o falso",
+ "size": "un tamaño como 2mb",
+ "text": "texto",
+ "pixels": "píxeles",
+ "paragraphs": "párrafos",
+ "rows": "filas",
+ "columns": "columnas",
+ "slides": "diapositivas",
+ "hertz": "hercios",
+ "megapixels": "megapíxeles",
+ "million cells": "millones de celdas",
+ "entries per second": "entradas por segundo",
+ "files": "archivos",
+ "sizes separated by commas": "tamaños separados por comas",
+ "format ids separated by commas": "ids de formato separados por comas",
+ "format ids separated by commas, or all": "ids de formato separados por comas, o all",
+ "extensions separated by commas": "extensiones separadas por comas",
+ "the id of a format, as tfg formats lists them": "el id de un formato, tal como lo lista tfg formats",
+ "the password, in plain text": "la contraseña, en texto plano",
+ "any text": "cualquier texto",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "una fecha como 2024-02-29 o 2024-02-29T13:45:00+02:00, o none"
+ },
+ "faq": [
+ {
+ "q": "¿En qué se diferencia de dd, fsutil o truncate?",
+ "a": "Esos comandos te dan un archivo del tamaño correcto lleno de nada. Un archivo de 2 MB llamado photo.png hecho así no es un PNG, de modo que cualquier cosa que lo analice de verdad lo rechaza por el motivo equivocado, y tu prueba también pasa por el motivo equivocado. Esto produce un PNG real de exactamente 2 MB que se abre en un visor de imágenes, y llega con una declaración de cómo debe tratarlo tu sistema.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "¿Es gratis, y puedo usarlo en el trabajo?",
+ "a": "Sí a ambas. Se publica bajo GPL-3.0 y no cuesta nada. No hay cuenta, ni clave de licencia, ni nivel de pago."
+ },
+ {
+ "q": "¿Puedo usar los archivos generados en un producto de código cerrado?",
+ "a": "Sí. La licencia cubre el código de la herramienta, no lo que la herramienta produce. Los archivos, recetas y manifiestos generados son una salida y no obras derivadas, así que puedes subirlos al repositorio y distribuirlos sin ninguna obligación."
+ },
+ {
+ "q": "¿Contienen los archivos generados datos personales reales?",
+ "a": "No. Todo lo que hay dentro se sintetiza a partir de una semilla. No se lee ningún conjunto de datos, no se contacta con ningún servicio y no se incrusta contenido de terceros. Trata una dirección de correo generada como inutilizable en lugar de como no usada, porque cualquier cadena aleatoria puede coincidir por casualidad con una real."
+ },
+ {
+ "q": "¿Obtendré exactamente los mismos archivos en otra máquina?",
+ "a": "Sí, byte a byte, con la misma receta y la misma semilla. El proyecto lo prueba en cada cambio, y romperlo exige una versión mayor. Eso es lo que te permite subir al repositorio una receta pequeña en lugar de fixtures binarios grandes."
+ },
+ {
+ "q": "¿Necesita conexión a internet?",
+ "a": "Nunca. No hay telemetría, ni comprobación de actualizaciones, ni cliente en la nube, y el binario de la línea de comandos no lleva compilada ninguna pila de red. Funciona en una máquina sin red y dentro de un entorno corporativo cerrado."
+ },
+ {
+ "q": "¿Qué pasa si pido un tamaño que un formato no puede alcanzar?",
+ "a": "Obtienes un error que nombra el formato, lo más pequeño que puede ser, el motivo de ese suelo y qué hacer en su lugar, y no se escribe ningún archivo. La herramienta nunca redondea un tamaño en silencio. Cada suelo aparece en la página de formatos.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "¿Puedo generar un archivo deliberadamente roto?",
+ "a": "Sí. Añade --damage zero-head y el archivo sale con exactamente el tamaño pedido, con sus primeros bytes sobrescritos por ceros, de modo que un lector lo rechaza, y el manifiesto dice que tu sistema debe rechazarlo. La página sobre archivos de prueba corruptos tiene los detalles.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "¿Qué formatos vienen después?",
+ "a": "7z, mp3 y mp4. Hoy funcionan de principio a fin {{ .Facts.FormatCount }} formatos."
+ },
+ {
+ "q": "¿En qué sistemas puedo ejecutarlo?",
+ "a": "La línea de comandos funciona en Windows y Linux, tanto en Intel como en ARM, y en Mac con Apple Silicon. La ventana de escritorio se entrega para Windows en Intel, Linux en Intel y Mac con Apple Silicon. Los Mac Intel no son compatibles y no se compila nada para ellos."
+ },
+ {
+ "q": "¿Tengo que instalar algo?",
+ "a": "No. Descarga el archivo de tu sistema, descomprímelo y ejecuta el binario. No hay instalador, ni entorno de ejecución que añadir, ni dependencia que resolver. Si tienes Go, también sirve un único comando go install.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "¿Por qué una ejecución sobre miles de archivos es más lenta en Windows?",
+ "a": "Porque Windows cobra más por cada ruta que mira, y un comando que recorre miles de archivos mira miles de rutas. Medido en una máquina con 3000 archivos de 1 kB, verify tarda unos 0,9 segundos en Windows y unos 0,2 segundos en Linux dentro de un contenedor. Una ruta de salida más corta reduce la cifra de Windows, porque cada carpeta por encima de los archivos forma parte de lo que se mira."
+ }
+ ]
+}
diff --git a/web/content/es/use-cases.html b/web/content/es/use-cases.html
new file mode 100644
index 00000000..1fcb3b67
--- /dev/null
+++ b/web/content/es/use-cases.html
@@ -0,0 +1,134 @@
+
Para qué lo usa la gente
+
+ Cinco tareas que aparecen en casi todos los proyectos que aceptan archivos de personas, y el comando
+ que hace cada una. Cada ejemplo de abajo se ejecuta tal como está escrito.
+
+
+
+
Límites de subida
+
Probar si un límite de tamaño de archivo se aplica donde dice que se aplica
+
+ Un límite son tres casos de prueba, no uno: justo por debajo, exactamente en él y justo por encima.
+ Conseguirlos a mano significa calcular números de bytes y esperar no haberte equivocado en uno.
+ Pide el conjunto en su lugar:
+
+ Obtienes tres PDF reales de 1048575, 1048576 y 1048577 bytes, y un manifiesto que dice que los dos
+ primeros deben aceptarse y el tercero rechazarse por size_limit. Tu prueba lee la
+ expectativa en lugar de que escribas tres aserciones a mano - y cuando cambia el límite, cambias
+ un número y vuelves a ejecutar.
+
+
+ Lo mismo funciona sin preset cuando quieres un único conjunto de límites en línea:
+
Mantener los fixtures fuera del repositorio sin perderlos
+
+ Los fixtures binarios grandes hacen lento clonar un repositorio y incómodo revisarlo, y nadie puede
+ decir qué cambió cuando se sustituye uno. Una receta son unos cientos de caracteres de YAML que
+ reconstruyen los archivos idénticos - byte a byte, en cualquier máquina -
+ porque cada archivo se deriva de la semilla de la ejecución.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Cada final tiene su propio código de salida, así que una canalización puede distinguir una receta
+ mala de un disco lleno y de una discrepancia de verificación. Una ejecución fallida no imprime
+ nada en la salida estándar, lo que evita que un analizador de registros lea un error como datos.
+
+
+
+
+
Escala
+
Descubrir qué pasa cuando la carpeta es grande
+
+ Las rutinas de importación, los trabajos nocturnos y los listados de directorios se comportan
+ distinto con diez mil archivos que con diez. Los tamaños sacados de un intervalo hacen que el
+ conjunto parezca tráfico real en lugar de diez mil archivos idénticos, y el sorteo viene de la
+ semilla, así que el conjunto es el mismo mañana.
+
+ Una ejecución mayor que el espacio libre del disco se rechaza antes de escribir el primer byte, en
+ lugar de llenar el disco y fallar a medias.
+
+
+
+
+
Archivos comprimidos
+
Probar un descompresor con un archivo comprimido que de verdad contiene archivos
+
+ Un archivo comprimido vacío con la extensión correcta no demuestra nada sobre el código que lo abre
+ y recorre lo que hay dentro. Declara el contenido y el archivo comprimido lo contiene de verdad:
+
+ La profundidad de anidamiento, el número de entradas y el tamaño de lo que hay dentro son cosas
+ sobre las que una rutina de importación tiene opiniones, y así descubres cuáles son.
+
+
+
+
+
Analizadores y visores
+
Comprobar que tu propio código lee un formato como lo hace el software real
+
+ Cada formato de aquí se comprueba con un lector independiente antes de publicarse - un PNG se abre y
+ se comparan sus píxeles, un DOCX lo vuelven a leer bibliotecas distintas, un archivo comprimido
+ se extrae. Eso significa que un archivo que tu analizador rechaza es un hallazgo sobre tu
+ analizador, no sobre el generador.
+
+ La página de formatos lista los ajustes que admite cada uno y el archivo
+ más pequeño que puede ser cada uno.
+
+
+
+
+
Guías
+
Dos de ellos con más detalle
+
+
+ Archivos de prueba corruptos - un archivo roto a
+ propósito, con el tamaño exacto y con lo que debe ocurrirle escrito en el manifiesto.
+
+
+ Archivos de prueba en CI - un workflow de GitHub
+ Actions, un job de GitLab y los códigos de salida que hacen fallar una compilación.
+
+
+
+
+
+
Para quién es
+
+ Ingenieros de QA, automatización de pruebas y cualquiera cuyo código tenga detrás un formulario de
+ subida, una rutina de importación, un analizador o una cuota de almacenamiento. Funciona en una
+ máquina sin red alguna, lo que importa en un entorno corporativo cerrado donde un generador
+ basado en navegador no es una opción.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/fr/ci.html b/web/content/fr/ci.html
new file mode 100644
index 00000000..7d054be5
--- /dev/null
+++ b/web/content/fr/ci.html
@@ -0,0 +1,194 @@
+{{ with .Up }}
Comment générer des fichiers de test dans un pipeline CI
+
+ Une fixture binaire dans un dépôt reste à jamais dans son historique, ne se relit pas dans un diff
+ et devient impossible dès que le fichier est gros. Générez plutôt les fichiers dans le pipeline à
+ partir d'une recette. La recette est du texte, les octets sortent identiques à chaque fois, et une
+ dernière étape prouve que rien n'a bougé.
+
+
+
+
La réponse courte
+
+ Installez tfg, lancez tfg generate fixtures.yaml --out ./fixtures avant
+ les tests et tfg verify ./fixtures/manifest.json après. Les deux étapes font
+ échouer le build d'elles-mêmes, avec un code de sortie qui dit pourquoi.
+
+
+
+
+
Pourquoi ne pas les commiter
+
Pourquoi une fixture ne doit pas vivre dans le dépôt
+
+
+ Elle reste dans l'historique. Supprimer un binaire plus tard ne rend pas un clone
+ plus petit, car chacune de ses versions est toujours là.
+
+
+ Un diff ne montre pas ce qui a changé. Le relecteur voit qu'un PDF est différent,
+ et rien de plus. Une recette change d'une ligne.
+
+
+ Les gros fichiers ne tiennent pas. GitHub refuse un push qui contient un fichier de
+ plus de 100 Mo, donc un test d'une limite d'envoi de 500 Mo n'a rien à commiter.
+
+
+
+ C'est la recette qu'il faut commiter. La même recette et la même graine écrivent les mêmes octets
+ sur toute machine, donc le fichier généré dans le pipeline est celui que vous aviez sur votre
+ portable.
+
+
+
+
+
La recette
+
Une recette qui vit à côté des tests
+
+ Celle-ci écrit vingt-cinq factures qui doivent être acceptées et deux images au-dessus d'une limite
+ qui doivent être refusées, et le manifeste note les deux attentes :
+
+ La ligne de somme de contrôle compare l'archive à verify-SHA256SUMS.txt de la même
+ version. La version est épinglée, donc une nouvelle version ne change jamais un build que vous
+ n'avez pas touché.
+
+ Chaque fin a son propre code de sortie, donc l'étape échoue d'elle-même et le journal dit lequel.
+ Ceux que rencontre un pipeline :
+
+
+
3 - la recette n'est pas valide. Rien n'a été écrit, et chaque problème est nommé
+
4 - le format ne sait pas faire ce qui a été demandé, par exemple une taille sous son minimum
+
6 - il n'y a pas assez d'espace disque
+
7 - tfg verify a trouvé un fichier qui ne correspond pas à son manifeste
+
8 - l'exécution est terminée, mais tout n'a pas été produit
+
+
+ Une exécution échouée n'écrit rien sur la sortie standard, donc un analyseur de journaux ne prend
+ jamais une erreur pour des données. Le tableau complet est sur
+ la page de documentation.
+
+
+
+
+
PowerShell
+
Un script PowerShell demande une ligne de plus
+
+ PowerShell ne fait pas sortir le code de sortie d'un programme d'un fichier .ps1.
+ Lancez-en un avec -File et le script répond 0 même quand l'outil à
+ l'intérieur a refusé le travail, si bien qu'un build qui devrait être rouge passe au vert. La
+ dernière ligne est toute la correction :
+
+ C'est ainsi que se comporte PowerShell, pas une particularité de cet outil. cmd,
+ bash et zsh n'ont besoin de rien de plus.
+
+
+
+
+
Plusieurs jobs
+
Partager les fixtures entre les jobs
+
+ Il n'y a généralement pas besoin de les envoyer. Comme la même recette écrit les mêmes octets,
+ chaque job peut lancer son propre tfg generate, ce qui est plus rapide qu'un envoi
+ suivi d'un téléchargement. Quand un job doit recevoir des fichiers d'un autre, lancez tfg
+ verify sur le manifeste après le transfert, et il dit si ce qui est arrivé est ce qui a
+ été écrit.
+
Comment fabriquer un fichier corrompu pour les tests
+
+ Un validateur à qui l'on n'a jamais montré que des fichiers sains n'a pas vraiment été testé. Voici
+ comment obtenir un fichier cassé volontairement, qui sort à exactement la taille
+ demandée et qui porte un manifeste disant ce que votre système doit en faire.
+
+
+
+
La réponse courte
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out écrit un PNG
+ d'exactement 2097152 octets dont les premiers octets sont des zéros, et le manifeste à côté note
+ que votre système doit le rejeter.
+
+
+
+
+
La méthode habituelle
+
Pourquoi un fichier corrompu à la main fait un mauvais test
+
+ Les moyens habituels sont un éditeur hexadécimal, un script qui inverse quelques octets au hasard,
+ ou un fichier raccourci avec head ou truncate. Ça marche une fois,
+ puis ça coûte :
+
+
+
+ C'est différent à chaque fois. Un octet tiré au hasard tombe ailleurs à chaque
+ exécution, donc un échec du mardi peut ne pas revenir le mercredi.
+
+
+ Ça change la taille. Un fichier coupé est plus petit que la limite sous laquelle il
+ devait se trouver, si bien que le contrôle de taille répond avant le contrôle du contenu et
+ que le test passe pour la mauvaise raison.
+
+
+ Ça passe souvent inaperçu. Un texte brut reste lisible avec un octet modifié au
+ milieu, et un lecteur d'images indulgent le dessine simplement, de sorte que le fichier censé
+ être cassé est accepté.
+
+
+ Ça ne dit rien de ce qui doit se passer. Le fichier n'est que des octets, et celui
+ qui lira le test ensuite doit deviner si l'acceptation ou le rejet était voulu.
+
+
+
+
+
+
Ce que vous obtenez
+
Un fichier abîmé garde la taille demandée
+
+ Le fichier est généré normalement puis cassé, en route vers le disque. Il garde la taille demandée,
+ et la même commande écrit de nouveau les mêmes octets.
+
+ Les réglages se placent après deux-points. L'option peut être répétée, et les dommages s'appliquent
+ dans l'ordre où vous les écrivez. Ça marche avec chacun des {{ .Facts.FormatCount }} formats.
+
+
+
+
+
Ce qu'il sait faire
+
Quels dommages existe-t-il ?
+
+ Voici la liste que le programme affiche, lue dans le programme au moment de construire cette page.
+ tfg damage affiche la même, et tfg damage <id> dit ce que prend
+ l'un d'eux.
+
+ {{ template "damagesTable" . }}
+
+ zero-head écrit des zéros sur le début du fichier. La plupart des lecteurs regardent
+ d'abord là, la signature et l'en-tête qui disent ce qu'est le fichier, donc presque tout lecteur
+ le remarque. Le texte brut et les journaux n'ont pas de signature et sont refusés eux aussi, car
+ une suite d'octets nuls n'est pas du texte. En dessous de quatre octets, certains formats
+ sortent avec un dommage dont aucun lecteur ne se plaint, c'est pourquoi le réglage commence à
+ quatre.
+
+
+
+
+
Ce que dit le manifeste
+
Un manifeste qui dit ce qui doit se passer
+
+ Chaque fichier abîmé reçoit une entrée disant que votre système doit le rejeter, avec le dommage
+ noté à côté :
+
+ Deux demandes sont refusées avant que rien ne soit écrit, car chacune laisserait sur le disque un
+ fichier que le manifeste décrit mal :
+
+
+
un fichier plus petit que ce dont le dommage a besoin, qui sortirait intact
+
+ expected: accept à côté d'un dommage, car rien ne pourrait le satisfaire. Écrivez
+ sanitize si votre système doit réparer le fichier, ou unspecified si
+ c'est justement la question que vous posez
+
+
+
+
+
+
Dans une recette
+
Fichiers sains et cassés dans une même exécution
+
+ Mettez les deux dans une seule recette, et le manifeste porte l'attente de chaque fichier, de sorte
+ que le test n'a pas besoin d'une liste disant lequel est lequel :
+
+ Le test lit le manifeste et vérifie que ce qui s'est passé est ce qui a été déclaré. Il n'a pas
+ besoin d'une liste de noms de fichiers :
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Un bon refus est un refus net. Un message qui dit ce qui n'allait pas est la réponse voulue. Une
+ erreur serveur, un blocage ou un fichier à moitié enregistré est le défaut que ce test existe
+ pour trouver.
+
+
+
+
+
Suite
+
Où aller ensuite
+
+
+ Le preset upload-validation pose à un formulaire
+ les deux autres questions, celle de la taille et celle du type.
+
+
diff --git a/web/content/fr/docs.html b/web/content/fr/docs.html
new file mode 100644
index 00000000..319c49c4
--- /dev/null
+++ b/web/content/fr/docs.html
@@ -0,0 +1,287 @@
+
Documentation
+
+ Tout ce que fait l'outil, rangé selon les questions avec lesquelles les gens arrivent vraiment. Le
+ README du dépôt est la référence complète et correspond toujours à
+ la version que vous avez téléchargée.
+
+
+
+
Quelles commandes existe-t-il ?
+
Chacune fait une seule chose :
+ {{ template "commandList" . }}
+
+
+
+
Comment générer un seul fichier de taille exacte ?
+
+ Nommez le format, la taille et la destination. Les tailles se comptent par 1024, donc
+ 2mb font 2097152 octets. Un nombre d'octets brut fonctionne aussi, donc
+ --size 10485761 demande exactement ce nombre.
+
+
tfg generate --format png --size 2mb --out ./out
+
Les options utiles de generate :
+
+
+
Option
Ce qu'elle fait
+
+
--format <id>
format des fichiers, par exemple txt
+
--size <size>
taille exacte de chaque fichier, comme 10mb ou un nombre d'octets brut
+
--size-range <a-b>
une taille tirée par fichier dans une plage, comme 1kb-8kb. Le tirage vient de la graine
+
--boundary <size>
trois fichiers autour d'une limite : un octet en dessous, la limite, un octet au-dessus
+
--count <n>
combien de fichiers produire. Par défaut 1
+
--name <template>
modèle de nom, par exemple invoice_{index:04}.txt
+
--out <dir>
répertoire où écrire
+
--seed <n>
graine de l'exécution. La même graine donne les mêmes octets
+
--set <k>=<v>
un réglage de format, répétable
+
--damage <name>
abîmer les fichiers exprès, répétable et appliqué dans l'ordre. Lancez tfg damage pour la liste
+
--expected <outcome>
accept, reject, sanitize ou unspecified
+
--dry-run
compter et montrer, sans rien écrire du tout
+
--json
écrire le manifeste sur la sortie standard
+
+
+
+
+
+
+
Comment fabriquer un fichier volontairement cassé ?
+
+ Tout autre fichier écrit par cet outil est correct par construction, ce qui répond à deux des trois
+ questions que pose un validateur d'envoi. --damage répond à la troisième - le
+ fichier s'ouvre-t-il seulement. Le fichier est produit normalement puis abîmé, il garde donc la
+ taille demandée.
+
+ Les réglages se placent après deux-points. L'option se répète, et l'ordre dans lequel vous les
+ écrivez est l'ordre dans lequel ils sont appliqués. tfg damage liste ce que cette
+ version sait faire et ce que chacun accepte.
+
+
Dans une recette, la clé est une liste, de noms ou de réglages :
+ Un fichier abîmé reçoit expected: reject dans le manifeste, avec l'altération notée à
+ côté. Deux choses sont refusées avant que rien ne soit écrit, car chacune mettrait sinon sur le
+ disque un fichier que le manifeste décrit à tort :
+
+
+
un fichier plus petit que ce dont l'altération a besoin, car il ressortirait inchangé
+
+ expected: accept à côté d'une altération, car rien ne pourrait y répondre. Écrivez
+ sanitize si le système testé doit réparer le fichier, ou unspecified
+ si c'est justement la question que vous posez
+
+
+
+ Une troisième ne peut pas être connue à l'avance. Si une altération s'exécute sans déplacer un seul
+ octet, ce fichier est abandonné plutôt qu'écrit - l'exécution continue, dit de quel fichier il
+ s'agissait et se termine avec le code de sortie partiel.
+
+ Une recette est un fichier YAML qui décrit toute une exécution. Commitez-la à côté de vos tests et
+ les fixtures cessent d'être des binaires dans votre dépôt - n'importe qui peut les reconstruire,
+ à l'octet près, à partir d'un fichier de quelques centaines de caractères.
+
+ Chaque cible exige exactement une de ces clés : size, size-range,
+ boundary ou contains. Deux est une erreur, et aucune aussi. Une
+ recette invalide n'écrit aucun fichier et signale tous les problèmes d'un coup
+ plutôt que le premier seulement, chacun nommant le réglage concerné.
+
+
+
+
+
Comment déclarer ce que mon système doit faire d'un fichier ?
+
Forme courte quand le résultat suffit, forme longue quand la raison compte :
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Les résultats sont accept, reject, sanitize et
+ unspecified. Les raisons forment une liste fermée pour qu'un rapport puisse les
+ regrouper : content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit et
+ size_zero.
+
+
+ Une raison nomme la règle en jeu, pas le verdict. C'est pourquoi la même raison
+ peut se trouver sous l'un ou l'autre résultat - un fichier un octet sous une limite est
+ accept, et la règle concernée reste size_limit.
+
+
+
+
+
Que contient le manifeste ?
+
+ Il est écrit à côté des fichiers à la fin de chaque exécution, y compris d'une exécution
+ interrompue. Une entrée par fichier :
+
+ Un recipe_hash est ajouté quand l'exécution vient d'une recette, et preset
+ avec overrides quand elle vient d'un préréglage, de sorte qu'un manifeste peut
+ toujours être rattaché à ce qui l'a produit.
+
+
+ Chaque entrée porte aussi target_id, l'identifiant de la cible de la recette qui a
+ produit le fichier, et summary.by_target compte les fichiers de chaque cible. Une
+ recette à plusieurs cibles peut donc être vérifiée cible par cible sans lire les noms de
+ fichiers.
+
+
+
+
+
Qu'est-ce qu'un préréglage ?
+
+ Un jeu de fichiers prêt à l'emploi qui répond à une question de test courante, pour que vous n'ayez
+ pas à concevoir le jeu vous-même. Les préréglages sont des recettes ordinaires en dessous, et
+ eject affiche la recette pour que vous puissiez la modifier. Chaque préréglage a
+ sa propre page qui dit ce qu'il trouve d'habitude, ce que
+ contient le jeu et chaque réglage qu'il accepte.
+
+ show vous dit ce que coûterait le jeu avant que vous ne le construisiez, et dit
+ franchement quand un nombre est un substitut de notre part plutôt qu'une limite de la vôtre.
+
+
+
+
+
Que signifient les codes de sortie ?
+
+ Chaque fin a son propre code, la sortie lisible par machine va sur la sortie standard, et une
+ exécution échouée n'y écrit rien. Le tableau est un contrat figé - changer le sens d'un code
+ exige une version majeure.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Une exécution arrêtée avec Ctrl+C laisse quand même un manifeste et ne laisse jamais de fichier à
+ moitié écrit, si bien qu'une tâche annulée peut encore être nettoyée par la suivante.
+
+ Oui, le même moteur avec une fenêtre, pour les tests qui ne sont pas scriptés. Ce n'est pas une
+ version amputée : un test compare les deux interfaces fonctionnalité par fonctionnalité, et
+ tout ce que seule l'une peut faire doit être déclaré et justifié au lieu de diverger
+ discrètement.
+
+
+ Les écrans sont un lot, les préréglages, plusieurs lots à la fois et À propos. Elle montre ce que
+ coûterait une exécution avant d'écrire quoi que ce soit, indique la progression pendant
+ l'exécution et peut être annulée en cours de route sans laisser de fichier à moitié écrit. Elle
+ n'ouvre pas encore de fichier de recette - les recettes sont pour l'instant une affaire de ligne
+ de commande, et la fenêtre construit ses lots dans le formulaire.
+
+
diff --git a/web/content/fr/exact-size.html b/web/content/fr/exact-size.html
new file mode 100644
index 00000000..918d447e
--- /dev/null
+++ b/web/content/fr/exact-size.html
@@ -0,0 +1,148 @@
+
Comment créer un fichier d'une taille exacte
+
+ Chaque système a une commande pour cela, et les trois sont ci-dessous. Elles donnent un fichier du
+ nombre d'octets exact - et pour beaucoup de tests, c'est tout ce qu'il faut. Chaque
+ commande de cette page a été exécutée avant publication, sur le système auquel elle
+ appartient.
+
+
+
+
La réponse courte
+
+ Windows : fsutil file createnew name 10485760. Linux : dd if=/dev/zero
+ of=name bs=1M count=10. macOS : mkfile 10m name. Les tailles sont en
+ octets, et 10 Mo comptés comme les compte votre gestionnaire de fichiers font 10485760 octets.
+
+
+
+
+
Windows
+
fsutil, et une version PowerShell qui n'a besoin de rien de plus
+
+ fsutil est fourni avec Windows. Il prend la taille en octets, calculez
+ donc le nombre d'abord - 10 Mo font 10485760, 100 Mo font 104857600, 1 Go fait 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Mesuré sous Windows 11 : cela fonctionne depuis une invite ordinaire sans exiger de droits
+ élevés, et le fichier fait exactement 10485760 octets.
+
+
PowerShell sait faire la même chose sans appeler un autre programme, et il comprend les unités :
+ 10MB en PowerShell signifie 10485760 octets, le même comptage par 1024 qu'utilise
+ l'Explorateur, donc les deux commandes ci-dessus produisent la même taille.
+
+
+
+
+
Linux
+
dd, truncate et fallocate, et la différence qui piège les gens
+
dd est celle que tout le monde connaît. Elle écrit vraiment les octets :
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate est instantané, et c'est là le piège. Mesuré sous Alpine Linux, le fichier
+ annonce 10485760 octets et occupe zéro bloc - c'est un fichier
+ creux. Tout ce qui le lit obtient dix mégaoctets de zéros, mais le disque n'a jamais
+ cédé la place :
+
+
truncate -s 10M test10mb.bin
+
+ C'est correct pour tester une limite d'envoi et trompeur pour tester un quota de disque.
+ fallocate est celui à choisir quand l'espace doit être réel :
+
+
fallocate -l 10M test10mb.bin
+
Et quand le contenu doit être incompressible, pour qu'un archiveur ne puisse pas le réduire à nouveau :
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, qui n'est pas creux, et les deux que vous connaissez déjà
+
+ macOS fournit mkfile. Mesuré sous macOS 26.6.2 : 10485760 octets et 20480 blocs,
+ donc l'espace est réellement alloué plutôt que promis :
+
+
mkfile 10m test10mb.bin
+
dd et truncate sont là aussi et se comportent comme sous Linux :
Un fichier de la bonne taille n'est pas un fichier du bon type
+
+ Tout ce qui précède donne un bloc de zéros. C'est suffisant quand ce qui est testé ne regarde que la
+ taille - une limite d'envoi, un quota, un transfert. Cela cesse de l'être dès que quelque chose
+ ouvre le fichier.
+
+
+ Mesuré, et cela vaut la peine de le faire vous-même : créez un fichier de 2 Mo avec
+ fsutil, appelez-le photo.png et donnez-le à une bibliothèque d'images.
+ Pillow répond cannot identify image file. Ce n'est pas un PNG. Cela n'en a jamais
+ été un - seul le nom le prétendait.
+
+
+ Cela compte plus qu'il n'y paraît, à cause de la façon dont le test échoue ensuite.
+ Votre point d'envoi refuse le fichier, votre test passe au vert et vous concluez que la limite
+ de taille fonctionne. Il ne l'a pas refusé pour sa taille. Il l'a refusé parce que les octets
+ n'étaient pas une image, et la règle que vous vouliez tester n'a jamais été atteinte.
+
+
+
un analyseur le refuse avant qu'aucune règle de taille ne soit examinée
+
une étape de miniature échoue et l'erreur que vous lisez concerne la miniature
+
un antivirus ou un contrôle de contenu le refuse pour une troisième raison
+
une visionneuse n'affiche rien, et personne ne peut dire si c'est le bogue
+
+
+
+
+
L'autre voie
+
Un vrai fichier de ce format, à la taille exacte que vous avez demandée
+
+ C'est ce que fait Testing Files Generator. Le fichier est un vrai fichier de son format - il s'ouvre
+ dans le logiciel qui lui correspond - et il fait le nombre d'octets exact que vous avez demandé,
+ à l'octet près :
+
+ Demandez une taille qu'un format ne peut pas atteindre et vous obtenez une erreur qui nomme le
+ plancher et sa raison, jamais un fichier de mauvaise taille. La page des
+ formats liste chaque format avec le plus petit fichier qu'il peut produire.
+
+
Et une limite, ce sont trois cas de test et non un, donc l'outil construit les trois :
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Cela donne 10485759, 10485760 et 10485761 octets, et un manifeste qui dit lesquels votre système
+ doit accepter et lesquels il doit refuser. La page des cas
+ d'usage passe en revue cela et quatre autres tâches pour lesquelles il est conçu.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Alors lequel utiliser ?
+
+
+
Utiliser la commande du système
+
+ Quand rien n'ouvre le fichier. Tester une limite de taille sur un point d'entrée qui vérifie d'abord
+ la taille, un transfert, un quota, un disque plein. C'est une ligne et c'est déjà installé.
+
+
+
+
Utiliser un vrai générateur
+
+ Quand quoi que ce soit analyse, affiche, importe ou extrait le fichier - et quand vous avez besoin
+ des mêmes fixtures demain, sur une autre machine, à l'octet près.
+
+
+
+
+ Les deux sont sur cette page parce que les deux sont justes une partie du temps. L'erreur à éviter
+ est d'utiliser la première là où il faut la seconde et de lire le test vert comme une preuve.
+
+
diff --git a/web/content/fr/faq.html b/web/content/fr/faq.html
new file mode 100644
index 00000000..c2f8ed1b
--- /dev/null
+++ b/web/content/fr/faq.html
@@ -0,0 +1,20 @@
+
Questions fréquentes
+
+ Licence, vie privée, reproductibilité et ce que les gens vérifient avant de mettre un générateur
+ dans un pipeline de build. Si votre question n'est pas ici, le suivi
+ des tickets est ouvert.
+
+ La page des cas d'usage montre les tâches pour lesquelles il est
+ conçu, et la page des formats liste chaque format avec le plus petit
+ fichier qu'il peut produire. Le README du dépôt est la référence
+ complète.
+
{{ .Facts.FormatCount }} formats de fichiers, chacun généré à une taille exacte
+
+ Chacun est un vrai fichier de ce format. Il s'ouvre dans le logiciel qui lui
+ correspond et fait exactement le nombre d'octets que vous avez demandé. Aucun n'est du remplissage
+ de zéros avec une extension collée dessus.
+
+
+{{ template "formatsTable" . }}
+
+
+
Ce que signifient les colonnes
+
+
+
Plus petit fichier
+
+ Le moins d'octets que cet outil accepte pour ce format, y compris l'étiquette qu'il écrit dans le
+ fichier. Demandez moins et vous obtenez une erreur qui nomme le plancher et sa raison,
+ jamais un fichier de mauvaise taille.
+
+
+
+
Fidélité
+
+ À quel point le fichier est complet. full signifie qu'un lecteur qui analyse vraiment
+ le format l'accepte, et pas seulement que l'extension correspond.
+
+
+
+
Vérifié avec
+
+ Le lecteur indépendant qui ouvre chaque fichier généré avant la livraison du format - une
+ implémentation distincte, pas notre propre code qui corrige ses propres devoirs.
+
+
+
+
+ Chaque format se répète aussi à l'octet près : la même recette et la même graine produisent des
+ fichiers identiques sur n'importe quelle machine, ce qui rend une recette sûre à commiter à la
+ place des fixtures elles-mêmes.
+
+
+
+
+
Réglages que chaque format accepte
+
+ La plupart des formats ont des réglages propres - dimensions d'image, qualité JPEG, nombre de pages
+ PDF, lignes et colonnes d'un tableur, nombre d'entrées dans une archive. Définissez-les avec
+ --set key=value en ligne de commande, ou sous properties: dans une
+ recette.
+
+ Une valeur hors de ce qu'un réglage accepte est refusée avec un message qui nomme le réglage, la
+ plage autorisée et quoi utiliser à la place. Un réglage inconnu est aussi une erreur, jamais une
+ valeur par défaut silencieuse - une faute de frappe acceptée en silence donne un fichier aux
+ mauvais réglages et une heure à se demander pourquoi le test passe alors qu'il ne devrait pas.
+
+
+ Lancez tfg formats <id> pour voir exactement ce qu'un format accepte dans la
+ version que vous avez.
+
+
+
+
+
Les archives contiennent de vrais fichiers
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} et {{ end }}{{ $c.ID }}{{ end }}
+ peuvent être remplis d'entrées plutôt que laissés en coquille vide. Une archive générée contient
+ réellement les documents qu'elle prétend contenir, si bien que tout ce qui la décompresse
+ pendant un test y trouve de vrais fichiers.
+
Générez de vrais fichiers de test à la taille exacte
+
+ PDF, PNG, DOCX, ZIP - {{ .Facts.FormatCount }} formats au total, et chacun est un
+ vrai fichier qui s'ouvre dans le logiciel qui lui correspond, à la taille exacte que
+ vous avez demandée. Chaque exécution note aussi ce que votre application doit faire de
+ chaque fichier. Ligne de commande et fenêtre de bureau, gratuit et open source, entièrement sur
+ votre machine.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ La fenêtre de bureau, prête à écrire un lot de fichiers. Le même moteur fonctionne derrière la ligne de commande.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
vrais formats, chacun s'ouvrant dans le logiciel qui lui correspond
+
+
+ 1 octet
+
la précision de chaque taille demandée, jamais arrondie en silence
+
+
+ 0
+
connexions vers où que ce soit - pas de compte, pas de télémétrie, pas de vérification de mises à jour
+
+
+
+
+
Le problème
+
Fabriquer un fichier de test est facile. Fabriquer les mille bons est la partie fastidieuse
+
Vous testez un logiciel qui reçoit des fichiers de la part de personnes. Tôt ou tard, il vous faut :
+
+
un PDF de exactement 10 Mo, pour savoir si la limite d'envoi est réelle
+
les trois fichiers de part et d'autre de cette limite, pour attraper les erreurs d'un
+
10 000 fichiers journaux, pour voir ce que fait la tâche de nuit quand le dossier est gros
+
un ZIP qui contient vraiment 200 documents, pas une coquille vide avec la bonne extension
+
un fichier de 4 Go, sans garder un fichier de 4 Go dans votre dépôt
+
les mêmes fixtures sur votre portable et sur le serveur de build, à l'octet près
+
+
+ C'est ce que cela remplace. C'est conçu pour les ingénieurs QA, l'automatisation de tests et tous
+ ceux dont le code a derrière lui un formulaire d'envoi, une routine d'import, un analyseur ou un
+ quota de stockage.
+
+
+
+
+
Ce qui le distingue
+
Les autres générateurs s'arrêtent aux octets. Celui-ci répond à ce que votre test demande vraiment
+
+ Un dossier de fichiers vous laisse encore décider ce que chacun est censé prouver. Chaque exécution
+ écrit ici un manifest.json à côté des fichiers - une simple liste de tout ce qui a
+ été produit et, pour chaque entrée, une attente déclarée.
+
+
Admettons que votre point d'envoi accepte 1 Mo. Demandez les trois fichiers situés sur cette ligne :
Trois fichiers, trois réponses différentes, sous forme lisible par machine. Votre test lit le manifeste au lieu que vous écriviez les assertions à la main :
Quand la réponse dépend de votre propre politique, le manifeste le dit
+
+ Il consigne unspecified plutôt que d'inventer une attente. Un générateur qui devine
+ produit de faux échecs, et une suite qui crie au loup finit par être désactivée.
+
+
+
+
+
+
Préréglages
+
Choisissez la question, obtenez tout le jeu
+
+ Un préréglage est un jeu de fichiers de test conçu autour d'une question de test, pour que vous
+ n'ayez pas à chercher quels fichiers prouvent quoi. Chacun a une page qui dit ce qu'il trouve
+ d'habitude, ce que contient le jeu et chaque réglage qu'il accepte.
+
+ Dix mille fichiers journaux, chacun entre un et huit kilooctets, avec des tailles tirées de la
+ graine pour que demain donne le même jeu. Donnez à chaque exécution son propre
+ répertoire - le manifeste est la seule trace de ce qu'une exécution a écrit, donc
+ l'outil refuse d'en écrire un second par-dessus :
+
+ Les tailles se comptent par 1024, comme le fait votre gestionnaire de fichiers, donc
+ 2mb signifie 2097152 octets. Un nombre d'octets brut fonctionne aussi. La
+ documentation couvre les recettes, le manifeste et les codes de
+ sortie.
+
+
+
+
+
Ce que vous obtenez
+
Conçu pour une suite qui tourne sans surveillance
+
+
+
Taille exacte, à l'octet près
+
Demandez 10485761 octets et obtenez exactement cela. Une taille qu'un format ne peut pas atteindre est une erreur avec une raison, jamais un fichier de mauvaise taille.
+
+
+
{{ .Facts.FormatCount }} vrais formats
+
Pas des zéros de remplissage avec une extension. Un PNG généré s'ouvre dans une visionneuse d'images, un DOCX s'ouvre dans Word, un ZIP se décompresse. Chacun est vérifié avec des lecteurs indépendants avant d'être livré.
+
+
+
Un manifeste qui fait office d'oracle de test
+
Chemin, taille, SHA-256, format, graine, version de l'outil - et ce que votre système doit faire du fichier.
+
+
+
Reproductible
+
Même recette et même graine, mêmes octets, sur n'importe quelle machine. Commitez une petite recette YAML plutôt que de gros fixtures binaires.
+
+
+
Deux interfaces, un seul moteur
+
Une ligne de commande conçue pour la CI et une fenêtre de bureau pour les tests exploratoires. Aucune n'est une version amputée de l'autre, et un test les compare fonctionnalité par fonctionnalité.
+
+
+
Entièrement hors ligne
+
Pas de compte, pas de cloud, pas de télémétrie, pas de vérification de mises à jour. Le binaire en ligne de commande n'a aucune pile réseau compilée dedans.
+
+
+
+
+
+
Téléchargement
+
Choisissez la version pour votre système
+
+ Décompressez l'archive et lancez-la. tfg est la ligne de commande et
+ tfg-gui est la fenêtre de bureau. Il n'y a pas d'installateur et rien à ajouter à
+ votre machine.
+
+ {{ template "downloadsTable" . }}
+
+
Ce qui est signé, et ce qui ne l'est pas
+
+ Les téléchargements Windows et macOS sont signés, ils démarrent donc sans avertissement sur un
+ développeur inconnu. Ceux de Linux ne le sont pas, car Linux de bureau n'a pas d'équivalent
+ pour les signer. Chaque archive est listée dans verify-SHA256SUMS.txt sur la page
+ des versions, pour que vous puissiez vérifier ce que vous avez téléchargé.
+
+ Le préréglage {{ .ID }} construit en une commande tout un jeu de vrais fichiers de test
+ pour cette question, avec un manifest.json à côté qui dit comment votre système doit
+ réagir à chaque fichier. Tout ce qui suit est lu depuis le programme, aux valeurs par défaut de
+ cette version.
+
+
+{{ if .Catches }}
+
+
Que trouve-t-il d'habitude ?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
Que contient le jeu ?
+
Aux valeurs par défaut, comme le rapporte tfg preset show {{ .ID }} :
+
+
+
+
Fichiers
{{ .Budget.Files }}
+
Cibles dans sa recette
{{ .Budget.Targets }}
+
Taille totale
{{ .Bytes }} B
+
Formats
{{ join .Budget.Formats ", " }}
+
+
+
+
Et ce que le manifeste de ce jeu attend de votre système :
+
+
+
+
Attendu
Signification
Fichiers
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
Que pouvez-vous modifier ?
+ {{- if .Settings }}
+
+
+
+
Réglage
Accepte
Par défaut
Ce qu'il fait
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Cette valeur par défaut est notre substitut, pas la valeur de votre système. Passez la vôtre.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
Ce préréglage n'a aucun réglage. Le jeu est le même à chaque fois.
+ {{- end }}
+
+
+
+
Comment le lancer ?
+
Voyez ce que coûterait le jeu, construisez-le ou prenez sa recette pour la modifier :
Ou bâtissez dessus dans une recette à vous, à côté de vos tests :
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/fr/presets.html b/web/content/fr/presets.html
new file mode 100644
index 00000000..a112ec21
--- /dev/null
+++ b/web/content/fr/presets.html
@@ -0,0 +1,32 @@
+
Préréglages de fichiers de test, un jeu pour chaque question de test
+
+ Un préréglage est tout un jeu de fichiers de test conçu autour d'une question, avec un manifeste qui
+ dit comment votre système doit réagir à chaque fichier. Vous choisissez la question, l'outil
+ construit le jeu. Chaque préréglage a sa propre page qui dit ce qu'il trouve d'habitude, ce que
+ contient le jeu et chaque réglage qu'il accepte.
+
+
+{{ template "presetsList" . }}
+
+
+
En quoi un préréglage diffère-t-il d'une recette ?
+
+ En dessous, il n'en diffère pas. Un préréglage est une recette que l'outil écrit pour vous à partir
+ de quelques réglages. tfg preset eject affiche cette recette pour que vous la
+ gardiez à côté de vos tests et la modifiiez, et une recette à vous peut s'appuyer sur un
+ préréglage en une ligne, extends: preset: suivi de son identifiant.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Puis-je me fier aux valeurs par défaut ?
+
+ Pour les fichiers, oui. Pour un nombre que seul votre système connaît, comme la limite d'un
+ formulaire d'envoi, une valeur par défaut est un substitut de notre part, et l'outil le dit
+ chaque fois qu'il en utilise une. La page de chaque préréglage marque ces réglages, et tfg
+ preset show le dit avant que rien ne soit écrit.
+
+
diff --git a/web/content/fr/site.json b/web/content/fr/site.json
new file mode 100644
index 00000000..1dfc1835
--- /dev/null
+++ b/web/content/fr/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "fr",
+ "locale": "fr_FR",
+ "name": "Français",
+ "dir": "fr",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Accueil",
+ "title": "Générateur de fichiers de test - taille exacte, {{ .Facts.FormatCount }} vrais formats",
+ "description": "Générateur gratuit et open source de fichiers de test pour la QA. De vrais PDF, DOCX, PNG et ZIP à la taille exacte, avec un manifeste de la réaction attendue."
+ },
+ {
+ "key": "formats",
+ "slug": "formats",
+ "nav": "Formats",
+ "title": "{{ .Facts.FormatCount }} formats de fichiers - PDF, DOCX, PNG, ZIP et plus",
+ "description": "Tous les formats générés, le plus petit fichier possible pour chacun et les réglages qu'il accepte. Les {{ .Facts.FormatCount }} s'ouvrent dans le logiciel qui leur correspond."
+ },
+ {
+ "key": "presets",
+ "slug": "prereglages",
+ "nav": "Préréglages",
+ "title": "Préréglages de fichiers de test - jeux prêts à l'emploi pour la QA",
+ "description": "Jeux de fichiers de test prêts à l'emploi, un par question : limites d'envoi, noms de fichiers, encodages, import de tableaux, fichiers vides, validation d'envoi."
+ },
+ {
+ "key": "docs",
+ "slug": "documentation",
+ "nav": "Documentation",
+ "title": "Documentation - commandes, recettes, manifeste, codes de sortie",
+ "description": "Comment générer des fichiers de test en ligne de commande ou avec une recette YAML, ce que contient le manifeste et ce que signifie chaque code de sortie en CI."
+ },
+ {
+ "key": "use-cases",
+ "slug": "cas-d-usage",
+ "nav": "Cas d'usage",
+ "title": "Cas d'usage - limites d'envoi, fixtures de CI, tests en masse",
+ "description": "Tester une limite de taille d'envoi, bâtir des fixtures reproductibles pour la CI, générer dix mille fichiers et remplir des archives avec du vrai contenu."
+ },
+ {
+ "key": "exact-size",
+ "slug": "creer-fichier-taille-exacte",
+ "nav": "Taille exacte",
+ "title": "Créer un fichier d'une taille précise - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate et mkfile, mesurés chacun sur son système, et pourquoi un fichier ainsi créé n'est ni un PDF ni un PNG quand un test en exige un."
+ },
+ {
+ "key": "faq",
+ "slug": "faq",
+ "nav": "FAQ",
+ "title": "FAQ - questions sur la génération de fichiers de test",
+ "description": "Différence avec dd et fsutil, fichiers commitables ou non, exécutions identiques à l'octet près, et ce qui arrive quand une taille est inatteignable."
+ },
+ {
+ "key": "damage",
+ "slug": "fichiers-de-test-corrompus",
+ "nav": "Fichiers corrompus",
+ "title": "Fichiers de test corrompus - fichiers cassés à taille exacte",
+ "description": "Un fichier cassé volontairement, à la taille exacte, avec un manifeste disant que votre système doit le rejeter. Pour tester la validation d'envoi et les parseurs.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "fichiers-de-test-en-ci",
+ "nav": "Fichiers de test en CI",
+ "title": "Fichiers de test en CI - GitHub Actions, GitLab CI et PowerShell",
+ "description": "Générez des fichiers de test dans le pipeline plutôt que de commiter des binaires : workflow GitHub Actions, job GitLab, codes de sortie et piège PowerShell.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "Aller au contenu",
+ "navLabel": "Navigation principale",
+ "langLabel": "Langue",
+ "breadcrumbHome": "Accueil",
+ "imageAlt": "Testing Files Generator - de vrais fichiers de test à la taille exacte, avec un manifeste qui dit comment votre système doit réagir à chacun",
+ "schemaDescription": "Un générateur gratuit et open source de fichiers de test pour la QA. Il produit de vrais fichiers dans {{ .Facts.FormatCount }} formats, à la taille exacte, et écrit un manifeste qui dit comment le système testé doit réagir à chacun.",
+ "ctaDownload": "Télécharger",
+ "ctaSource": "Voir le code source",
+ "ctaNote": "Gratuit et open source, GPL-3.0. Aucune inscription. Les téléchargements Windows et macOS sont signés et démarrent sans avertissement.",
+ "colFormat": "Format",
+ "colName": "Nom",
+ "colExtension": "Extension",
+ "colSmallest": "Plus petit fichier",
+ "colFidelity": "Fidélité",
+ "colChecked": "Vérifié avec",
+ "colSetting": "Réglage",
+ "colAccepts": "Accepte",
+ "colSystem": "Système",
+ "colCli": "Ligne de commande",
+ "colWindow": "Fenêtre de bureau",
+ "noBinary": "pas encore de binaire",
+ "colCode": "Code",
+ "colMeaning": "Signification",
+ "footerBlurb": "Des fichiers de test pour la QA, à la taille exacte, avec un manifeste qui dit comment votre système doit réagir à chacun.",
+ "footerProject": "Projet",
+ "footerSource": "Code source sur GitHub",
+ "footerReleases": "Téléchargements",
+ "footerIssues": "Signaler un problème",
+ "footerSupport": "Soutenir le projet",
+ "footerPages": "Pages",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. Publié sous la licence publique générale GNU, version 3. Les fichiers que vous générez vous appartiennent - la licence couvre l'outil, pas sa sortie.",
+ "footerPrivacy": "Ce site ne charge ni polices, ni scripts, ni traceurs, d'où que ce soit. Il ne dépose aucun cookie.",
+ "notFoundTitle": "Cette page n'existe pas",
+ "notFoundLead": "L'adresse que vous avez suivie ne correspond à aucune page de ce site.",
+ "notFoundBack": "Aller à l'accueil",
+ "read.format": "Le format de chaque fichier du jeu. C'est une option de l'outil lui-même, et le préréglage ne fait que lui donner une valeur par défaut.",
+ "readTakes.format": "un identifiant de format de la page des formats",
+ "colDamage": "Dommage",
+ "colEffect": "Ce qu'il fait aux octets",
+ "colSettings": "Réglages",
+ "noSettings": "aucun"
+ },
+ "endings": {
+ "0": "Tout a fonctionné.",
+ "1": "Une erreur inattendue dans l'outil.",
+ "2": "Commande ou option incorrecte.",
+ "3": "La recette n'est pas valide.",
+ "4": "Le format ne peut pas faire ce qui était demandé.",
+ "5": "Une lecture ou une écriture a échoué.",
+ "6": "Espace disque insuffisant.",
+ "7": "verify a trouvé une différence.",
+ "8": "L'exécution s'est terminée mais tout n'a pas été produit.",
+ "130": "Interrompu avec Ctrl+C.",
+ "143": "Arrêté par un signal, ce qui ressemble à un délai dépassé en CI."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "Un fichier valide et aussi petit que le format le permet passe-t-il ?",
+ "title": "Vide et minimal",
+ "pageTitle": "Fichiers de test valides minimaux et vides, dans chaque format",
+ "description": "Le plus petit fichier valide que cet outil écrit dans chacun de ses {{ .Facts.FormatCount }} formats, plus un fichier vide quand le format l'autorise, chacun avec la réaction attendue.",
+ "catches": [
+ "un fichier valide refusé parce que trop petit, quand le contrôle compte les octets au lieu de les lire",
+ "un fichier vide qui fait tomber le lecteur au lieu d'être signalé",
+ "une image d'un pixel de large qui divise par zéro en route vers la miniature",
+ "un stockage qui lit zéro octet comme un envoi échoué et recommence sans fin"
+ ],
+ "details": {
+ "formats": "Les formats dont le jeu est fait. Laissez all pour tous les formats de cette version, ou nommez ceux que votre système accepte."
+ }
+ },
+ "filename-handling": {
+ "question": "Mon système va-t-il stocker, afficher et restituer un nom de fichier auquel il ne s'attendait pas ?",
+ "title": "Gestion des noms de fichiers",
+ "pageTitle": "Noms de fichiers problématiques pour tester - Unicode et longueur",
+ "description": "Fichiers aux noms qui font échouer envois et stockage : autres écritures, emoji, inversion du sens d'écriture, caractères invisibles, syntaxe shell et SQL.",
+ "catches": [
+ "un nom qui ressemble à un autre à l'écran, dans un journal ou dans une liste",
+ "un nom coupé, rogné ou réécrit entre l'envoi et le stockage",
+ "une limite de longueur comptée en caractères là où le stockage compte en octets"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "Une limite de taille est-elle appliquée exactement là où elle est déclarée ?",
+ "title": "Limites de taille",
+ "pageTitle": "Tester une limite de taille d'envoi - fichiers à la limite exacte",
+ "description": "Des fichiers un octet sous, pile sur et un octet au-dessus de la limite de taille de votre système, plus des paliers plus larges, chacun marqué accepté ou refusé.",
+ "catches": [
+ "des erreurs d'un à la limite",
+ "Mo confondu avec Mio, soit 4,8 pour cent, assez pour laisser passer un fichier qui ne devrait pas passer",
+ "une limite appliquée dans le navigateur et pas sur le serveur"
+ ],
+ "details": {
+ "limit": "La limite de taille que déclare votre système. Tout le reste se mesure à partir d'elle.",
+ "spread": "Jusqu'où aller de part et d'autre de la limite, sous forme de liste de tailles."
+ }
+ },
+ "tabular-import": {
+ "question": "Mon import de tableaux résiste-t-il à ce qu'exportent les vrais outils ?",
+ "title": "Import de tableaux",
+ "pageTitle": "Fichiers de test d'import CSV et Excel - séparateurs, en-têtes",
+ "description": "CSV avec d'autres séparateurs, fins de ligne CR LF, sans en-tête, autres guillemets, tableau très large, classeur Excel et JSON en plusieurs dispositions.",
+ "catches": [
+ "un fichier à point-virgule lu comme une seule colonne, parce que le séparateur a été supposé au lieu d'être cherché",
+ "un fichier CRLF découpé en lignes avec une ligne vide après chacune",
+ "un tableau sans en-tête dont la première ligne de données est avalée comme noms de colonnes",
+ "un import qui garde les colonnes qu'il peut afficher et abandonne le reste sans un mot",
+ "un lecteur qui prend les enregistrements JSON une ligne à la fois et s'arrête au premier document indenté"
+ ],
+ "details": {
+ "rows": "Le nombre de lignes du tableur. Il est écrit exactement à la taille que font autant de lignes, donc le budget ci-dessus bouge avec cette valeur.",
+ "columns": "Le nombre de colonnes de chaque ligne du tableur. Lignes fois colonnes a un plafond, et le dépasser est refusé avant que rien ne soit écrit."
+ }
+ },
+ "text-encoding": {
+ "question": "Mon lecteur sait-il dans quel encodage est un fichier, ou devine-t-il ?",
+ "title": "Encodage du texte",
+ "pageTitle": "Fichiers de test d'encodage de texte - UTF-8, UTF-16, BOM, CRLF",
+ "description": "Le même texte en UTF-8, UTF-16LE et UTF-16BE, avec et sans BOM, et des fins de ligne CR LF et LF, pour tester le décodage d'un lecteur.",
+ "catches": [
+ "un lecteur qui suppose de l'UTF-8 et montre un fichier UTF-16 avec un caractère sur trois, ou en rangées de carrés",
+ "une marque d'ordre des octets lue comme du contenu, si bien que le premier champ d'un import commence par trois caractères parasites",
+ "un importeur qui devine l'encodage d'après les premiers octets et devine autrement pour un fichier plus long",
+ "un fichier CRLF découpé en lignes avec une ligne vide après chacune, ou un retour chariot resté dans le dernier champ"
+ ],
+ "details": {
+ "sample": "La taille de chaque fichier du jeu. L'UTF-16 stocke deux octets par caractère, donc un nombre impair est refusé."
+ }
+ },
+ "upload-validation": {
+ "question": "Mon formulaire d'envoi accepte-t-il ce qu'il doit et refuse-t-il le reste ?",
+ "title": "Validation d'envoi",
+ "pageTitle": "Fichiers de test de validation d'envoi - type, taille et nom",
+ "description": "Fichiers pour tester un formulaire d'envoi : types autorisés et refusés, contenu qui ne correspond pas à l'extension, limite de taille, noms hostiles, envoi en masse.",
+ "catches": [
+ "une limite appliquée dans le navigateur et pas sur le serveur",
+ "un SVG ou un HTML pris pour une image ou pour du texte brut, un moyen de faire passer un script à travers un formulaire",
+ "un fichier contrôlé par son extension et jamais ouvert, si bien qu'un PDF nommé .jpg passe",
+ "un formulaire qui lit tout le corps en mémoire avant de regarder sa taille",
+ "un envoi nommé PHOTO.JPG refusé là où photo.jpg est accepté, ou l'inverse",
+ "un nom avec des espaces, des parenthèses ou des caractères hors ASCII écrit sur le disque tel quel"
+ ],
+ "details": {
+ "limit": "La limite de taille que déclare votre formulaire d'envoi. Ce jeu fait un pas de chaque côté - pour un fichier à chaque distance, lancez le préréglage size-boundaries.",
+ "allow": "Les types que votre formulaire doit accepter. Chacun devient un vrai fichier de ce type, et ils forment le témoin positif de tout le jeu.",
+ "deny": "Les extensions que votre formulaire doit refuser. Une extension pour laquelle cette version n'a pas de format reçoit quand même un fichier à ce nom, contenant du texte brut.",
+ "far-over": "Jusqu'où le grand fichier dépasse la limite. Désactivez-le là où écrire plusieurs fois la limite ne vaut pas le disque.",
+ "bulk": "Le nombre de fichiers de l'envoi en masse. Zéro retire complètement ce groupe du jeu."
+ }
+ }
+ },
+ "commands": {
+ "generate": "produire des fichiers, depuis une recette ou des options",
+ "validate": "vérifier une recette sans rien écrire",
+ "verify": "comparer un répertoire à un manifeste",
+ "cleanup": "supprimer les fichiers qu'un manifeste liste",
+ "recipe fmt": "afficher une recette sous sa forme normalisée",
+ "preset": "construire un jeu de fichiers à partir d'une question de test nommée",
+ "formats": "lister les formats pris en charge par cette version",
+ "damage": "lister les façons dont cette version peut abîmer un fichier exprès",
+ "tool": "de petits outils pour des fichiers que vous avez déjà",
+ "version": "afficher la version de l'outil",
+ "license": "afficher la licence et ce qu'elle implique pour les fichiers générés"
+ },
+ "outcomes": {
+ "accept": "Votre système doit accepter le fichier.",
+ "reject": "Votre système doit refuser le fichier.",
+ "sanitize": "Votre système doit accepter le fichier et le nettoyer, par exemple en le renommant.",
+ "unspecified": "Cela dépend des règles de votre système. Vous décidez, puis vous vérifiez que ce qui se passe est ce que vous aviez voulu."
+ },
+ "damages": {
+ "zero-head": "Écrase les premiers octets du fichier avec des zéros, sans toucher à sa longueur. La plupart des lecteurs regardent d'abord là, donc presque tout remarque ce dommage."
+ },
+ "terms": {
+ "oracleNone": "sans objet",
+ "int": "tout nombre entier",
+ "choice": "une valeur d'un ensemble fixe",
+ "bool": "vrai ou faux",
+ "size": "une taille comme 2mb",
+ "text": "texte",
+ "pixels": "pixels",
+ "paragraphs": "paragraphes",
+ "rows": "lignes",
+ "columns": "colonnes",
+ "slides": "diapositives",
+ "hertz": "hertz",
+ "megapixels": "mégapixels",
+ "million cells": "millions de cellules",
+ "entries per second": "entrées par seconde",
+ "files": "fichiers",
+ "sizes separated by commas": "tailles séparées par des virgules",
+ "format ids separated by commas": "identifiants de format séparés par des virgules",
+ "format ids separated by commas, or all": "identifiants de format séparés par des virgules, ou all",
+ "extensions separated by commas": "extensions séparées par des virgules",
+ "the id of a format, as tfg formats lists them": "l'identifiant d'un format, comme le liste tfg formats",
+ "the password, in plain text": "le mot de passe, en clair",
+ "any text": "n'importe quel texte",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "une date comme 2024-02-29 ou 2024-02-29T13:45:00+02:00, ou none"
+ },
+ "faq": [
+ {
+ "q": "En quoi est-ce différent de dd, fsutil ou truncate ?",
+ "a": "Ces commandes donnent un fichier de la bonne taille rempli de rien. Un fichier de 2 Mo nommé photo.png fabriqué ainsi n'est pas un PNG, donc tout ce qui l'analyse vraiment le refuse pour la mauvaise raison, et votre test réussit alors lui aussi pour la mauvaise raison. Cet outil produit un vrai PNG d'exactement 2 Mo, qui s'ouvre dans une visionneuse d'images, accompagné d'une déclaration sur la façon dont votre système doit le traiter.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "Est-ce gratuit, et puis-je l'utiliser au travail ?",
+ "a": "Oui aux deux. Il est publié sous GPL-3.0 et ne coûte rien. Il n'y a ni compte, ni clé de licence, ni offre payante."
+ },
+ {
+ "q": "Puis-je utiliser les fichiers générés dans un produit propriétaire ?",
+ "a": "Oui. La licence couvre le code de l'outil, pas ce qu'il produit. Les fichiers, recettes et manifestes générés sont une sortie et non des œuvres dérivées, vous pouvez donc les commiter et les livrer sans aucune obligation."
+ },
+ {
+ "q": "Les fichiers générés contiennent-ils de vraies données personnelles ?",
+ "a": "Non. Tout ce qu'ils contiennent est synthétisé à partir d'une graine. Aucun jeu de données n'est lu, aucun service n'est contacté et aucun contenu tiers n'est intégré. Considérez une adresse e-mail générée comme inutilisable plutôt que comme inutilisée, car n'importe quelle chaîne aléatoire peut coïncider par hasard avec une vraie."
+ },
+ {
+ "q": "Obtiendrai-je exactement les mêmes fichiers sur une autre machine ?",
+ "a": "Oui, à l'octet près, avec la même recette et la même graine. Le projet le teste à chaque modification, et le casser exige un changement de version majeure. C'est ce qui vous permet de commiter une petite recette plutôt que de gros fixtures binaires."
+ },
+ {
+ "q": "Faut-il une connexion internet ?",
+ "a": "Jamais. Il n'y a ni télémétrie, ni vérification de mises à jour, ni client cloud, et le binaire en ligne de commande n'a aucune pile réseau compilée dedans. Il fonctionne sur une machine sans réseau et dans un environnement d'entreprise fermé."
+ },
+ {
+ "q": "Que se passe-t-il si je demande une taille qu'un format ne peut pas atteindre ?",
+ "a": "Vous obtenez une erreur qui nomme le format, la taille minimale possible, la raison de ce plancher et ce qu'il faut faire à la place, et aucun fichier n'est écrit. L'outil n'arrondit jamais une taille en silence. Chaque plancher est listé sur la page des formats.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "Puis-je générer un fichier volontairement cassé ?",
+ "a": "Oui. Ajoutez --damage zero-head et le fichier sort à la taille exacte demandée, avec ses premiers octets écrasés par des zéros, si bien qu'un lecteur le refuse, et le manifeste dit que votre système doit le rejeter. La page sur les fichiers de test corrompus donne le détail.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "Quels formats arrivent ensuite ?",
+ "a": "7z, mp3 et mp4. {{ .Facts.FormatCount }} formats fonctionnent de bout en bout aujourd'hui."
+ },
+ {
+ "q": "Sur quels systèmes puis-je l'exécuter ?",
+ "a": "La ligne de commande fonctionne sous Windows et Linux, sur Intel comme sur ARM, et sur les Mac Apple silicon. La fenêtre de bureau est fournie pour Windows sur Intel, Linux sur Intel et les Mac Apple silicon. Les Mac Intel ne sont pas pris en charge et rien n'est construit pour eux."
+ },
+ {
+ "q": "Dois-je installer quelque chose ?",
+ "a": "Non. Téléchargez l'archive de votre système, décompressez-la et lancez le binaire. Il n'y a pas d'installateur, pas d'environnement d'exécution à ajouter et pas de dépendance à résoudre. Si vous avez Go, une seule commande go install fonctionne aussi.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "Pourquoi une exécution sur des milliers de fichiers est-elle plus lente sous Windows ?",
+ "a": "Parce que Windows facture plus cher chaque chemin qu'il examine, et une commande qui parcourt des milliers de fichiers examine des milliers de chemins. Mesuré sur une machine avec 3000 fichiers de 1 ko, verify prend environ 0,9 seconde sous Windows et environ 0,2 seconde sous Linux dans un conteneur. Un chemin de sortie plus court réduit le chiffre de Windows, car chaque dossier au-dessus des fichiers fait partie de ce qui est examiné."
+ }
+ ]
+}
diff --git a/web/content/fr/use-cases.html b/web/content/fr/use-cases.html
new file mode 100644
index 00000000..ffe21af4
--- /dev/null
+++ b/web/content/fr/use-cases.html
@@ -0,0 +1,137 @@
+
À quoi les gens l'utilisent
+
+ Cinq tâches qui reviennent dans presque tous les projets qui reçoivent des fichiers de la part de
+ personnes, et la commande qui fait chacune. Chaque exemple ci-dessous s'exécute tel qu'il est
+ écrit.
+
+
+
+
Limites d'envoi
+
Tester si une limite de taille de fichier est appliquée là où elle le dit
+
+ Une limite, ce sont trois cas de test, pas un : juste en dessous, pile dessus et juste
+ au-dessus. Les obtenir à la main revient à calculer des nombres d'octets en espérant ne pas
+ s'être trompé d'un. Demandez plutôt le jeu :
+
+ Vous obtenez trois vrais PDF de 1048575, 1048576 et 1048577 octets, et un manifeste qui dit que les
+ deux premiers doivent être acceptés et le troisième refusé pour size_limit. Votre
+ test lit l'attente au lieu que vous écriviez trois assertions à la main - et quand la limite
+ change, vous changez un nombre et relancez.
+
+
+ La même chose fonctionne sans préréglage quand vous voulez un seul jeu de limites en ligne :
+
+ De gros fixtures binaires rendent un dépôt lent à cloner et pénible à relire, et personne ne peut
+ dire ce qui a changé quand l'un est remplacé. Une recette, ce sont quelques centaines de
+ caractères de YAML qui reconstruisent les fichiers identiques - à l'octet près, sur
+ n'importe quelle machine - parce que chaque fichier est dérivé de la graine de
+ l'exécution.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Chaque fin a son propre code de sortie, si bien qu'un pipeline peut distinguer une mauvaise recette
+ d'un disque plein et d'une différence de vérification. Une exécution échouée n'écrit rien sur la
+ sortie standard, ce qui évite qu'un analyseur de journaux lise une erreur comme une donnée.
+
+
+
+
+
Volume
+
Découvrir ce qui se passe quand le dossier est gros
+
+ Les routines d'import, les tâches de nuit et les listages de répertoires se comportent autrement à
+ dix mille fichiers qu'à dix. Des tailles tirées dans une plage donnent au jeu l'allure d'un vrai
+ trafic plutôt que de dix mille fichiers identiques, et le tirage vient de la graine, donc le jeu
+ est le même demain.
+
+ Une exécution plus grande que l'espace libre du disque est refusée avant que le premier octet soit
+ écrit, au lieu de remplir le disque et d'échouer à mi-chemin.
+
+
+
+
+
Archives
+
Tester un décompresseur avec une archive qui contient vraiment des fichiers
+
+ Une archive vide avec la bonne extension ne prouve rien sur le code qui l'ouvre et parcourt ce
+ qu'elle contient. Déclarez le contenu et l'archive le contient vraiment :
+
+ La profondeur d'imbrication, le nombre d'entrées et la taille de ce qu'il y a dedans sont autant de
+ choses sur lesquelles une routine d'import a des opinions, et c'est ainsi que vous découvrez
+ lesquelles.
+
+
+
+
+
Analyseurs et visionneuses
+
Vérifier que votre propre code lit un format comme le fait un vrai logiciel
+
+ Chaque format ici est vérifié avec un lecteur indépendant avant la livraison - un PNG est ouvert et
+ ses pixels comparés, un DOCX est relu par des bibliothèques distinctes, une archive est
+ extraite. Cela signifie qu'un fichier que votre analyseur refuse est une trouvaille sur votre
+ analyseur, pas sur le générateur.
+
+ La page des formats liste les réglages que chacun accepte et le plus
+ petit fichier que chacun peut être.
+
+
+
+
+
Guides
+
Deux d'entre eux en détail
+
+
+ Fichiers de test corrompus - un fichier cassé
+ volontairement, à la taille exacte, avec dans le manifeste ce qui doit lui arriver.
+
+
+ Fichiers de test en CI - un workflow GitHub Actions, un
+ job GitLab et les codes de sortie qui font échouer un build.
+
+
+
+
+
+
À qui cela s'adresse
+
+ Les ingénieurs QA, l'automatisation de tests et tous ceux dont le code a derrière lui un formulaire
+ d'envoi, une routine d'import, un analyseur ou un quota de stockage. Il fonctionne sur une
+ machine sans aucun réseau, ce qui compte dans un environnement d'entreprise fermé où un
+ générateur dans le navigateur n'est pas une option.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/hi/ci.html b/web/content/hi/ci.html
new file mode 100644
index 00000000..4891f0e3
--- /dev/null
+++ b/web/content/hi/ci.html
@@ -0,0 +1,187 @@
+{{ with .Up }}
+ रिपॉज़िटरी में बाइनरी फ़िक्स्चर उसके इतिहास में हमेशा के लिए रह जाता है, diff में उसकी समीक्षा नहीं
+ हो सकती, और फ़ाइल बड़ी हो तो वह संभव ही नहीं रहता। इसके बजाय फ़ाइलें पाइपलाइन के भीतर रेसिपी से
+ बनाएँ। रेसिपी पाठ है, बाइट हर बार एक जैसे निकलते हैं, और आख़िरी कदम साबित करता है कि कुछ नहीं
+ खिसका।
+
+
+
+
छोटा जवाब
+
+ tfg इंस्टॉल करें, टेस्ट से पहले tfg generate fixtures.yaml --out
+ ./fixtures चलाएँ और उनके बाद tfg verify ./fixtures/manifest.json। दोनों कदम
+ अपने आप बिल्ड को विफल करते हैं, एक ऐसे एग्ज़िट कोड के साथ जो कारण बताता है।
+
+
+
+
+
कमिट क्यों न करें
+
फ़िक्स्चर रिपॉज़िटरी में क्यों नहीं रहना चाहिए
+
+
+ यह इतिहास में रह जाता है। बाद में बाइनरी हटाने से क्लोन छोटा नहीं होता, क्योंकि
+ उसका हर संस्करण अब भी वहीं है।
+
+
+ diff नहीं दिखाता कि क्या बदला। समीक्षक को बस दिखता है कि PDF अलग है, और कुछ नहीं।
+ रेसिपी एक पंक्ति से बदलती है।
+
+
+ बड़ी फ़ाइलें समाती नहीं। GitHub 100 MB से बड़ी फ़ाइल वाले पुश को ठुकरा देता है,
+ इसलिए 500 MB की अपलोड सीमा के टेस्ट के पास कमिट करने को कुछ नहीं है।
+
+
+
+ कमिट करने की चीज़ रेसिपी है। वही रेसिपी और वही सीड हर मशीन पर वही बाइट लिखते हैं, इसलिए पाइपलाइन में
+ बनी फ़ाइल वही फ़ाइल है जो आपके लैपटॉप पर थी।
+
+
+
+
+
रेसिपी
+
टेस्ट के बगल में रहने वाली रेसिपी
+
+ यह पच्चीस चालान लिखती है जिन्हें स्वीकार होना चाहिए और सीमा से ऊपर की दो छवियाँ जिन्हें अस्वीकार
+ होना चाहिए, और मैनिफ़ेस्ट दोनों अपेक्षाएँ दर्ज करता है:
+
+ चेकसम वाली पंक्ति संग्रह को उसी रिलीज़ की verify-SHA256SUMS.txt से मिलाती है। संस्करण
+ तय कर दिया गया है, इसलिए नई रिलीज़ कभी ऐसे बिल्ड को नहीं बदलती जिसे आपने छुआ नहीं।
+
+ हर अंत का अपना एग्ज़िट कोड है, इसलिए कदम अपने आप विफल होता है और लॉग बताता है कि कौन-सा था। जो
+ पाइपलाइन को मिलते हैं:
+
+
+
3 - रेसिपी मान्य नहीं है। कुछ नहीं लिखा गया, और हर समस्या का नाम लिया गया है
+
4 - फ़ॉर्मैट वह नहीं कर सकता जो माँगा गया, जैसे अपने न्यूनतम से नीचे का आकार
+
6 - डिस्क पर पर्याप्त जगह नहीं है
+
7 - tfg verify को एक फ़ाइल मिली जो अपने मैनिफ़ेस्ट से मेल नहीं खाती
+
8 - रन पूरा हुआ, पर सब कुछ बना नहीं
+
+
+ विफल रन स्टैंडर्ड आउटपुट पर कुछ नहीं छापता, इसलिए लॉग पार्सर कभी किसी त्रुटि को डेटा नहीं समझता।
+ पूरी तालिका दस्तावेज़ के पेज पर है।
+
+
+
+
+
PowerShell
+
PowerShell स्क्रिप्ट को एक पंक्ति और चाहिए
+
+ PowerShell किसी प्रोग्राम का एग्ज़िट कोड .ps1 फ़ाइल से बाहर नहीं ले जाता। एक को
+ -File से चलाएँ तो स्क्रिप्ट 0 देती है, चाहे भीतर के टूल ने काम से
+ इनकार कर दिया हो, और जो बिल्ड लाल होना चाहिए वह हरा हो जाता है। आख़िरी पंक्ति ही पूरा सुधार है:
+
+ PowerShell ऐसा ही बरतता है, यह इस टूल की बात नहीं है। cmd, bash और
+ zsh को कुछ अतिरिक्त नहीं चाहिए।
+
+
+
+
+
कई जॉब
+
जॉब के बीच फ़िक्स्चर साझा करना
+
+ आम तौर पर उन्हें अपलोड करने की ज़रूरत नहीं होती। क्योंकि वही रेसिपी वही बाइट लिखती है, हर जॉब अपना
+ tfg generate चला सकता है, जो अपलोड और डाउनलोड से तेज़ है। जब किसी जॉब को दूसरे से
+ फ़ाइलें लेनी हों, तो ट्रांसफ़र के बाद मैनिफ़ेस्ट पर tfg verify चलाएँ, और वह बताएगा
+ कि जो पहुँचा वही है जो लिखा गया था।
+
+
+
+
+
आगे
+
यहाँ से कहाँ जाएँ
+
+
+ खराब टेस्ट फ़ाइलें उसी रेसिपी में जानबूझकर बिगाड़ी गई फ़ाइलें
+ जोड़ती हैं।
+
+
+ उपयोग के मामले दिखाते हैं कि पाइपलाइन में एक रन और क्या जाँच सकता है।
+
+
+ दस्तावेज़ में हर कमांड, हर रेसिपी कुंजी और हर एग्ज़िट कोड है।
+
+
+
diff --git a/web/content/hi/damage.html b/web/content/hi/damage.html
new file mode 100644
index 00000000..9d91a08b
--- /dev/null
+++ b/web/content/hi/damage.html
@@ -0,0 +1,171 @@
+{{ with .Up }}
+ जिस वैलिडेटर को केवल स्वस्थ फ़ाइलें दिखाई गई हों, उसे सचमुच परखा नहीं गया है। यहाँ बताया गया है कि
+ ऐसी फ़ाइल कैसे पाएँ जो जानबूझकर बिगाड़ी गई हो, ठीक उतने आकार की निकले जितना आपने
+ माँगा, और ऐसा मैनिफ़ेस्ट साथ लाए जो बताता है कि आपके सिस्टम को उसका क्या करना चाहिए।
+
+
+
+
छोटा जवाब
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out ठीक 2097152 बाइट की
+ एक PNG लिखता है जिसके शुरुआती बाइट शून्य हैं, और उसके बगल का मैनिफ़ेस्ट दर्ज करता है कि आपके
+ सिस्टम को उसे अस्वीकार करना चाहिए।
+
+
+
+
+
आम तरीका
+
हाथ से बिगाड़ी गई फ़ाइल खराब टेस्ट क्यों है
+
+ आम तरीके हैं हेक्स एडिटर, कुछ यादृच्छिक बाइट पलटने वाली स्क्रिप्ट, या head अथवा
+ truncate से फ़ाइल को छोटा काट देना। ये एक बार चलते हैं, फिर महँगे पड़ते हैं:
+
+
+
+ हर बार अलग होता है। यादृच्छिक बाइट हर रन में नई जगह पड़ता है, इसलिए मंगलवार की
+ विफलता बुधवार को लौटे, यह ज़रूरी नहीं।
+
+
+ यह आकार बदल देता है। कटी हुई फ़ाइल उस सीमा से छोटी होती है जिसके नीचे उसे रहना था,
+ इसलिए आकार की जाँच सामग्री की जाँच से पहले जवाब दे देती है और टेस्ट गलत कारण से पास हो जाता
+ है।
+
+
+ यह अक्सर किसी की नज़र में नहीं आता। सादा पाठ बीच में एक बाइट बदलने पर भी पढ़ा जाता
+ है, और उदार इमेज रीडर उसे बस बना देता है, इसलिए जो फ़ाइल खराब होनी थी वह स्वीकार हो जाती है।
+
+
+ यह नहीं बताता कि क्या होना चाहिए। फ़ाइल सिर्फ़ बाइट है, और जो बाद में टेस्ट पढ़ेगा
+ उसे अंदाज़ा लगाना पड़ेगा कि इरादा स्वीकार करने का था या अस्वीकार करने का।
+
+
+
+
+
+
आपको क्या मिलता है
+
खराब फ़ाइल का आकार वही रहता है जो आपने माँगा था
+
+ फ़ाइल सामान्य रूप से बनती है और बाद में, डिस्क तक जाते समय, बिगाड़ी जाती है। वह माँगा हुआ आकार बनाए
+ रखती है, और वही कमांड फिर वही बाइट लिखता है।
+
+ सेटिंग कोलन के बाद लिखी जाती है। विकल्प दोहराया जा सकता है, और बिगाड़ आपके लिखे क्रम में लागू होते
+ हैं। यह सभी {{ .Facts.FormatCount }} फ़ॉर्मैट के साथ चलता है।
+
+
+
+
+
यह क्या कर सकता है
+
कौन-कौन से बिगाड़ हैं?
+
+ यह वह सूची है जो प्रोग्राम छापता है, इस पेज को बनाते समय उसी से पढ़ी गई। tfg damage यही
+ सूची छापता है, और tfg damage <id> बताता है कि उनमें से एक क्या लेता है।
+
+ {{ template "damagesTable" . }}
+
+ zero-head फ़ाइल की शुरुआत पर शून्य लिख देता है। ज़्यादातर रीडर सबसे पहले वहीं देखते
+ हैं, उस सिग्नेचर और हेडर पर जो बताते हैं कि फ़ाइल क्या है, इसलिए लगभग हर रीडर इसे भाँप लेता है।
+ सादे पाठ और लॉग में सिग्नेचर नहीं होता और वे भी अस्वीकार होते हैं, क्योंकि शून्य बाइट की कतार
+ पाठ नहीं है। चार बाइट से नीचे कुछ फ़ॉर्मैट ऐसे बिगाड़ के साथ निकलते हैं जिसकी कोई रीडर शिकायत
+ नहीं करता, इसीलिए सेटिंग चार से शुरू होती है।
+
+
+
+
+
मैनिफ़ेस्ट क्या कहता है
+
एक मैनिफ़ेस्ट जो बताता है कि क्या होना चाहिए
+
+ हर खराब फ़ाइल को एक प्रविष्टि मिलती है जो कहती है कि आपके सिस्टम को उसे अस्वीकार करना चाहिए, और
+ बिगाड़ उसके बगल में दर्ज रहता है:
+
+ दो अनुरोध कुछ भी लिखे जाने से पहले ठुकरा दिए जाते हैं, क्योंकि हर एक डिस्क पर ऐसी फ़ाइल छोड़ देता
+ जिसका मैनिफ़ेस्ट गलत वर्णन करता:
+
+
+
बिगाड़ को जितना चाहिए उससे छोटी फ़ाइल, जो ज्यों की त्यों निकलती
+
+ बिगाड़ के साथ expected: accept, क्योंकि कोई भी उसे पूरा नहीं कर सकता। अगर आपके सिस्टम
+ को फ़ाइल सुधारनी है तो sanitize लिखें, या अगर आप यही सवाल पूछ रहे हैं तो
+ unspecified
+
+
+
+
+
+
रेसिपी में
+
एक रन में स्वस्थ और खराब फ़ाइलें
+
+ दोनों को एक रेसिपी में रखें, और मैनिफ़ेस्ट हर फ़ाइल की अपेक्षा साथ रखता है, इसलिए टेस्ट को यह बताने
+ वाली सूची नहीं चाहिए कि कौन-सी कौन-सी है:
+
+ टेस्ट मैनिफ़ेस्ट पढ़ता है और जाँचता है कि जो हुआ वही है जो घोषित किया गया था। उसे फ़ाइल नामों की
+ सूची नहीं चाहिए:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ अच्छा इनकार साफ़ इनकार होता है। जो संदेश बताए कि क्या गलत था, वही वह जवाब है जो आप चाहते हैं। सर्वर
+ त्रुटि, अटक जाना या आधी सहेजी फ़ाइल वह खराबी है जिसे ढूँढ़ने के लिए यह टेस्ट है।
+
+
diff --git a/web/content/hi/docs.html b/web/content/hi/docs.html
new file mode 100644
index 00000000..07707e6c
--- /dev/null
+++ b/web/content/hi/docs.html
@@ -0,0 +1,278 @@
+
दस्तावेज़ीकरण
+
+ टूल जो कुछ भी करता है, उन सवालों के रूप में सजाया गया जिन्हें लेकर लोग सच में आते हैं।
+ रिपॉज़िटरी का README पूरा संदर्भ है और हमेशा आपके डाउनलोड किए
+ बिल्ड से मेल खाता है।
+
+
+
+
कौन सी कमांड हैं?
+
हर एक सिर्फ़ एक काम करती है:
+ {{ template "commandList" . }}
+
+
+
+
सटीक आकार की एक फ़ाइल कैसे बनाऊँ?
+
+ फ़ॉर्मैट, आकार और जगह बताएँ। आकार 1024 के गुणकों में गिने जाते हैं, इसलिए 2mb 2097152
+ बाइट है। सादी बाइट संख्या भी चलती है, इसलिए --size 10485761 ठीक उतने ही बाइट माँगता
+ है।
+
+
tfg generate --format png --size 2mb --out ./out
+
generate के काम के फ़्लैग:
+
+
+
फ़्लैग
क्या करता है
+
+
--format <id>
फ़ाइलों का फ़ॉर्मैट, जैसे txt
+
--size <size>
हर फ़ाइल का सटीक आकार, जैसे 10mb या सादी बाइट संख्या
+
--size-range <a-b>
किसी सीमा में से हर फ़ाइल के लिए निकाला गया आकार, जैसे 1kb-8kb। निकालना सीड से होता है
+
--boundary <size>
सीमा के आसपास तीन फ़ाइलें: एक बाइट नीचे, सीमा, एक बाइट ऊपर
+
--count <n>
कितनी फ़ाइलें बनानी हैं। डिफ़ॉल्ट 1
+
--name <template>
नाम का साँचा, जैसे invoice_{index:04}.txt
+
--out <dir>
जिस डायरेक्टरी में लिखना है
+
--seed <n>
रन का सीड। वही सीड वही बाइट देता है
+
--set <k>=<v>
फ़ॉर्मैट की एक सेटिंग, दोहराई जा सकती है
+
--damage <name>
फ़ाइलों को जानबूझकर बिगाड़ें, दोहराया जा सकता है और क्रम से लागू होता है। सूची के लिए tfg damage चलाएँ
+
--expected <outcome>
accept, reject, sanitize या unspecified
+
--dry-run
गिनें और दिखाएँ, कुछ भी न लिखें
+
--json
मैनिफ़ेस्ट को स्टैंडर्ड आउटपुट पर लिखें
+
+
+
+
+
+
+
जानबूझकर टूटी फ़ाइल कैसे बनाऊँ?
+
+ यह टूल जो भी दूसरी फ़ाइल लिखता है वह बनावट से सही होती है, और इससे अपलोड वैलिडेटर के तीन सवालों में
+ से दो का जवाब मिल जाता है। --damage तीसरे का जवाब देता है - क्या फ़ाइल खुलती भी है।
+ फ़ाइल सामान्य रूप से बनती है और फिर बिगाड़ी जाती है, इसलिए उसका आकार वही रहता है जो आपने माँगा।
+
+ सेटिंग कोलन के बाद आती हैं। फ़्लैग दोहराया जा सकता है, और आप जिस क्रम में लिखते हैं वही उनके लागू
+ होने का क्रम है। tfg damage बताता है कि यह बिल्ड क्या कर सकता है और हर एक क्या लेता
+ है।
+
+
रेसिपी में कुंजी एक सूची है, नामों की या सेटिंग की:
+ बिगाड़ी गई फ़ाइल को मैनिफ़ेस्ट में expected: reject मिलता है, और बिगाड़ने का ब्योरा
+ उसके बगल में दर्ज होता है। दो चीज़ें कुछ भी लिखे जाने से पहले ठुकरा दी जाती हैं, क्योंकि हर एक
+ डिस्क पर ऐसी फ़ाइल छोड़ देती जिसे मैनिफ़ेस्ट गलत बताता:
+
+
+
बिगाड़ने के लिए ज़रूरी से छोटी फ़ाइल, क्योंकि वह बिना बदले निकल आती
+
+ बिगाड़ के बगल में expected: accept, क्योंकि कुछ भी उसे पूरा नहीं कर सकता। अगर जाँचे जा
+ रहे सिस्टम को फ़ाइल सुधारनी है तो sanitize लिखें, या अगर आप यही सवाल पूछ रहे हैं
+ तो unspecified
+
+
+
+ तीसरी बात पहले से नहीं जानी जा सकती। अगर कोई बिगाड़ चलता है और एक भी बाइट नहीं हिलाता, तो वह फ़ाइल
+ लिखे जाने के बजाय छोड़ दी जाती है - रन चलता रहता है, बताता है कि वह कौन सी फ़ाइल थी, और आंशिक
+ एग्ज़िट कोड के साथ ख़त्म होता है।
+
+ रेसिपी एक YAML फ़ाइल है जो पूरे रन का वर्णन करती है। इसे अपने टेस्ट के बगल में कमिट करें और
+ फ़िक्स्चर आपकी रिपॉज़िटरी में बाइनरी नहीं रह जाते - कोई भी उन्हें कुछ सौ अक्षरों की फ़ाइल से
+ बाइट-दर-बाइट दोबारा बना सकता है।
+
+ हर टार्गेट को size, size-range, boundary या
+ contains में से ठीक एक चाहिए। दो होना त्रुटि है और एक भी न होना भी। अमान्य रेसिपी
+ कोई फ़ाइल नहीं लिखती और सिर्फ़ पहली नहीं, सारी समस्याएँ एक साथ बताती है, हर एक
+ उस सेटिंग का नाम लेकर जिससे वह जुड़ी है।
+
+
+
+
+
मैं कैसे बताऊँ कि मेरे सिस्टम को किसी फ़ाइल के साथ क्या करना चाहिए?
+
जब नतीजा काफ़ी हो तो छोटा रूप, जब कारण मायने रखे तो लंबा रूप:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ नतीजे हैं accept, reject, sanitize और
+ unspecified। कारण एक बंद सूची हैं ताकि रिपोर्ट उनके आधार पर समूह बना सके:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit और size_zero।
+
+
+ कारण काम कर रहे नियम का नाम लेता है, फ़ैसले का नहीं। इसीलिए एक ही कारण किसी भी
+ नतीजे के नीचे आ सकता है - सीमा से एक बाइट नीचे की फ़ाइल accept है, और जिस नियम की
+ बात है वह फिर भी size_limit है।
+
+
+
+
+
मैनिफ़ेस्ट में क्या है?
+
+ यह हर रन के अंत में फ़ाइलों के बगल में लिखा जाता है, बीच में रोके गए रन में भी। हर फ़ाइल के लिए एक
+ प्रविष्टि:
+
+ रन रेसिपी से आया हो तो recipe_hash जुड़ता है, और प्रीसेट से आया हो तो
+ overrides के साथ preset, इसलिए मैनिफ़ेस्ट को हमेशा उसके स्रोत तक खोजा
+ जा सकता है।
+
+
+ हर प्रविष्टि में target_id भी होता है, यानी रेसिपी के उस टार्गेट का id जिसने फ़ाइल
+ बनाई, और summary.by_target गिनता है कि हर टार्गेट के हिस्से कितनी फ़ाइलें आईं।
+ इसलिए कई टार्गेट वाली रेसिपी को फ़ाइल नाम पढ़े बिना टार्गेट-दर-टार्गेट जाँचा जा सकता है।
+
+
+
+
+
प्रीसेट क्या है?
+
+ किसी आम टेस्ट सवाल का जवाब देने वाला फ़ाइलों का तैयार सेट, ताकि आपको सेट खुद डिज़ाइन न करना पड़े।
+ प्रीसेट अंदर से सामान्य रेसिपी हैं, और eject रेसिपी छापता है ताकि आप वहीं से उसे
+ संपादित कर सकें। हर प्रीसेट का अपना पेज है जो बताता है कि वह आम तौर
+ पर क्या पकड़ता है, सेट में क्या है और वह कौन सी सेटिंग लेता है।
+
+ show सेट बनाने से पहले बताता है कि उसकी क़ीमत क्या होगी, और साफ़ कहता है जब कोई संख्या
+ आपकी सीमा नहीं बल्कि हमारी अस्थायी जगह-धारक संख्या हो।
+
+
+
+
+
एग्ज़िट कोड का क्या अर्थ है?
+
+ हर अंत का अपना कोड है, मशीन के पढ़ने लायक आउटपुट स्टैंडर्ड आउटपुट पर जाता है, और विफल रन वहाँ कुछ
+ नहीं छापता। तालिका एक जमाया हुआ अनुबंध है - किसी कोड का अर्थ बदलने के लिए मुख्य संस्करण बढ़ाना
+ पड़ता है।
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Ctrl+C से रोका गया रन फिर भी मैनिफ़ेस्ट छोड़ता है और कभी आधी लिखी फ़ाइल नहीं छोड़ता, इसलिए रद्द किए
+ गए जॉब को अगला जॉब साफ़ कर सकता है।
+
+ हाँ, वही इंजन जिस पर एक विंडो लगी है, उस टेस्टिंग के लिए जो स्क्रिप्ट से नहीं होती। यह घटाया हुआ रूप
+ नहीं है: एक टेस्ट दोनों इंटरफ़ेस की क्षमता-दर-क्षमता तुलना करता है, और जो सिर्फ़ एक ही कर सकता
+ है उसे चुपचाप अलग होने देने के बजाय घोषित और उचित ठहराना पड़ता है।
+
+
+ स्क्रीन हैं एक बैच, प्रीसेट, एक साथ कई बैच, और परिचय। यह कुछ भी लिखने से पहले रन की क़ीमत दिखाती है,
+ चलते समय प्रगति बताती है, और बीच में रद्द की जा सकती है बिना आधी लिखी फ़ाइल छोड़े। यह अभी रेसिपी
+ फ़ाइल नहीं खोलती - फ़िलहाल रेसिपी कमांड लाइन की चीज़ हैं, और विंडो अपने बैच फ़ॉर्म में बनाती है।
+
+
diff --git a/web/content/hi/exact-size.html b/web/content/hi/exact-size.html
new file mode 100644
index 00000000..e0b94128
--- /dev/null
+++ b/web/content/hi/exact-size.html
@@ -0,0 +1,144 @@
+
सटीक आकार की फ़ाइल कैसे बनाएँ
+
+ हर सिस्टम में इसके लिए एक कमांड है, और तीनों नीचे हैं। वे आपको ठीक सही बाइट संख्या की फ़ाइल देती हैं
+ - और बहुत से टेस्ट के लिए आपको बस यही चाहिए। इस पेज की हर कमांड प्रकाशित करने से पहले उस
+ सिस्टम पर चलाई गई जिसकी वह है।
+
+
+
+
छोटा जवाब
+
+ Windows: fsutil file createnew name 10485760। Linux: dd if=/dev/zero of=name
+ bs=1M count=10। macOS: mkfile 10m name। आकार बाइट में होते हैं, और आपके
+ फ़ाइल मैनेजर के गिनने के तरीके से 10 MB यानी 10485760।
+
+
+
+
+
Windows
+
fsutil, और बिना किसी अतिरिक्त चीज़ वाला PowerShell रूप
+
+ fsutil Windows के साथ आता है। यह आकार बाइट में लेता है, इसलिए पहले
+ संख्या निकाल लें - 10 MB यानी 10485760, 100 MB यानी 104857600, 1 GB यानी 1073741824।
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Windows 11 पर मापा गया: यह सामान्य प्रॉम्प्ट से चलता है और उन्नत प्रॉम्प्ट नहीं माँगता, और फ़ाइल ठीक
+ 10485760 बाइट की बनती है।
+
+
PowerShell बिना किसी दूसरे प्रोग्राम को बुलाए यही कर सकता है, और इकाइयाँ समझता है:
+ PowerShell में 10MB का मतलब 10485760 बाइट है, वही 1024 आधारित गिनती जो एक्सप्लोरर
+ इस्तेमाल करता है, इसलिए ऊपर की दोनों कमांड एक ही आकार बनाती हैं।
+
+
+
+
+
Linux
+
dd, truncate और fallocate, और वह अंतर जो लोगों को फँसाता है
+
dd वह है जिसे सब जानते हैं। यह बाइट सच में लिखता है:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate तुरंत होता है, और यही पेंच है। Alpine Linux पर मापने पर फ़ाइल 10485760 बाइट
+ बताती है और शून्य ब्लॉक घेरती है - यह एक स्पार्स फ़ाइल है। जो
+ भी इसे पढ़ता है उसे दस मेगाबाइट शून्य मिलते हैं, पर डिस्क ने जगह कभी दी ही नहीं:
+
+
truncate -s 10M test10mb.bin
+
+ अपलोड सीमा परखने के लिए यह ठीक है और डिस्क कोटा परखने के लिए भ्रामक। जब जगह असली होनी चाहिए तब
+ fallocate की ओर जाएँ:
+
+
fallocate -l 10M test10mb.bin
+
और जब सामग्री असंपीड्य होनी चाहिए, ताकि कोई आर्काइवर उसे फिर से छोटा न कर सके:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, जो स्पार्स नहीं है, और वे दो जिन्हें आप पहले से जानते हैं
+
+ macOS में mkfile आता है। macOS 26.6.2 पर मापा गया: 10485760 बाइट और 20480 ब्लॉक, यानी
+ जगह वादे से नहीं, सच में आवंटित होती है:
+
+
mkfile 10m test10mb.bin
+
dd और truncate भी वहाँ हैं और Linux की तरह ही चलते हैं:
+ ऊपर की सारी चीज़ें आपको शून्यों का एक ब्लॉक देती हैं। जब जाँचा जा रहा हिस्सा सिर्फ़ आकार देखता है -
+ अपलोड सीमा, कोटा, ट्रांसफ़र - तब यह काफ़ी है। जिस पल कोई चीज़ फ़ाइल को खोलती
+ है, यह काफ़ी नहीं रहता।
+
+
+ मापा गया, और खुद करके देखना लायक है: fsutil से 2 MB की फ़ाइल बनाएँ, उसका नाम
+ photo.png रखें, और किसी इमेज लाइब्रेरी को दें। Pillow जवाब देता है cannot
+ identify image file। यह PNG नहीं है। यह कभी था ही नहीं - सिर्फ़ नाम ऐसा कहता था।
+
+
+ यह सुनने में जितना लगता है उससे ज़्यादा मायने रखता है, क्योंकि टेस्ट फिर किस तरफ़ विफल होता
+ है यही सवाल है। आपका अपलोड एंडपॉइंट फ़ाइल ठुकरा देता है, आपका टेस्ट हरा हो जाता है, और
+ आप मान लेते हैं कि आकार सीमा काम करती है। उसने फ़ाइल आकार की वजह से नहीं ठुकराई। उसने इसलिए
+ ठुकराई कि बाइट तस्वीर नहीं थे, और जिस नियम को आप जाँचना चाहते थे वह कभी छुआ ही नहीं गया।
+
+
+
कोई पार्सर आकार का कोई नियम देखे जाने से पहले ही उसे ठुकरा देता है
+
थंबनेल का चरण विफल होता है और जो त्रुटि आप पढ़ते हैं वह थंबनेल के बारे में होती है
+
कोई एंटीवायरस या सामग्री जाँच उसे तीसरे कारण से मना कर देती है
+
कोई व्यूअर कुछ नहीं दिखाता, और कोई नहीं बता सकता कि यही बग है या नहीं
+
+
+
+
+
दूसरा रास्ता
+
उस फ़ॉर्मैट की असली फ़ाइल, ठीक उसी आकार में जो आपने माँगा
+
+ Testing Files Generator यही करता है। फ़ाइल अपने फ़ॉर्मैट की सच्ची फ़ाइल है - वह अपने सॉफ़्टवेयर में
+ खुलती है - और उसमें ठीक उतने बाइट हैं जितने आपने माँगे, बाइट तक:
+
+ ऐसा आकार माँगें जिस तक कोई फ़ॉर्मैट नहीं पहुँच सकता और आपको न्यूनतम सीमा और उसका कारण बताने वाली
+ त्रुटि मिलती है, गलत आकार की फ़ाइल कभी नहीं। फ़ॉर्मैट पेज हर फ़ॉर्मैट
+ को उसकी सबसे छोटी संभव फ़ाइल के साथ सूचीबद्ध करता है।
+
+
और एक सीमा एक नहीं, तीन टेस्ट केस होती है, इसलिए टूल तीनों बनाता है:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ इससे आपको 10485759, 10485760 और 10485761 बाइट की फ़ाइलें मिलती हैं, और एक मैनिफ़ेस्ट जो बताता है कि
+ आपके सिस्टम को किन्हें स्वीकार करना चाहिए और किन्हें अस्वीकार। उपयोग के
+ मामलों का पेज इसे और चार दूसरे काम समझाता है जिनके लिए यह बना है।
+
+ {{ template "downloadCta" . }}
+
+
+
+
तो कौन सा इस्तेमाल करें?
+
+
+
सिस्टम की कमांड इस्तेमाल करें
+
+ जब कुछ भी फ़ाइल नहीं खोलता। ऐसे एंडपॉइंट पर आकार सीमा की जाँच जो पहले आकार देखता है, कोई ट्रांसफ़र,
+ कोटा, डिस्क भरने की स्थिति। यह एक पंक्ति है और पहले से इंस्टॉल है।
+
+
+
+
असली जनरेटर इस्तेमाल करें
+
+ जब कुछ भी फ़ाइल को पार्स, रेंडर, इंपोर्ट या एक्सट्रैक्ट करता है - और जब आपको कल दूसरी मशीन पर वही
+ फ़िक्स्चर बाइट-दर-बाइट फिर से चाहिए।
+
+
+
+
+ दोनों इस पेज पर इसलिए हैं क्योंकि दोनों कभी-कभी सही होते हैं। जिस गलती से बचना है वह है दूसरे की
+ ज़रूरत वाली जगह पहले को इस्तेमाल करना और हरे टेस्ट को सबूत मान लेना।
+
+
diff --git a/web/content/hi/faq.html b/web/content/hi/faq.html
new file mode 100644
index 00000000..2ce046b5
--- /dev/null
+++ b/web/content/hi/faq.html
@@ -0,0 +1,18 @@
+
अक्सर पूछे जाने वाले सवाल
+
+ लाइसेंस, निजता, दोहराव, और वे बातें जो लोग जनरेटर को बिल्ड पाइपलाइन में लगाने से पहले जाँचते हैं।
+ अगर आपका सवाल यहाँ नहीं है, तो इश्यू ट्रैकर खुला है।
+
{{ .Facts.FormatCount }} फ़ाइल फ़ॉर्मैट, हर एक सटीक आकार में बनाया गया
+
+ इनमें से हर एक उस फ़ॉर्मैट की असली फ़ाइल है। वह अपने सॉफ़्टवेयर में खुलती है और
+ उसमें ठीक उतने बाइट हैं जितने आपने माँगे। इनमें से कोई भी एक्सटेंशन चिपकाए गए भराव के शून्य नहीं
+ है।
+
+
+{{ template "formatsTable" . }}
+
+
+
कॉलम का अर्थ
+
+
+
सबसे छोटी फ़ाइल
+
+ उस फ़ॉर्मैट के लिए यह टूल जितने कम से कम बाइट स्वीकार करेगा, उस लेबल समेत जो वह फ़ाइल के अंदर लिखता
+ है। इससे कम माँगें और आपको न्यूनतम सीमा और उसका कारण बताने वाली त्रुटि मिलती है, गलत आकार की
+ फ़ाइल कभी नहीं।
+
+
+
+
पूर्णता
+
+ फ़ाइल कितनी पूरी है। full का मतलब है कि फ़ॉर्मैट को सच में पार्स करने वाला रीडर उसे
+ स्वीकार करता है, सिर्फ़ यह नहीं कि एक्सटेंशन मिलता है।
+
+
+
+
जाँच का साधन
+
+ वह स्वतंत्र रीडर जो फ़ॉर्मैट भेजे जाने से पहले हर बनाई गई फ़ाइल खोलता है - एक अलग कार्यान्वयन, हमारा
+ अपना कोड नहीं जो अपना ही गृहकार्य जाँचे।
+
+
+
+
+ हर फ़ॉर्मैट बाइट तक दोहराया भी जाता है: वही रेसिपी और वही सीड किसी भी मशीन पर एक जैसी फ़ाइलें बनाते
+ हैं, और इसी से फ़िक्स्चर की जगह रेसिपी कमिट करना सुरक्षित होता है।
+
+
+
+
+
हर फ़ॉर्मैट की स्वीकार की जाने वाली सेटिंग
+
+ ज़्यादातर फ़ॉर्मैट की अपनी सेटिंग होती हैं - इमेज के आयाम, JPEG गुणवत्ता, PDF के पेज, स्प्रेडशीट की
+ पंक्तियाँ और कॉलम, आर्काइव के अंदर कितनी प्रविष्टियाँ जाएँ। इन्हें कमांड लाइन पर --set
+ key=value से, या रेसिपी में properties: के नीचे सेट करें।
+
+ किसी सेटिंग की स्वीकार्य सीमा से बाहर का मान एक संदेश के साथ ठुकरा दिया जाता है जो सेटिंग, मान्य
+ सीमा और इसके बदले क्या इस्तेमाल करें यह बताता है। अज्ञात सेटिंग भी त्रुटि है, कभी चुपचाप
+ डिफ़ॉल्ट नहीं - चुपचाप मान ली गई टाइपो गलत सेटिंग की फ़ाइल देती है और एक घंटा यह सोचने में जाता
+ है कि जिस टेस्ट को विफल होना था वह पास क्यों हो रहा है।
+
+
+ जो बिल्ड आपके पास है उसमें कोई फ़ॉर्मैट ठीक क्या स्वीकार करता है, यह देखने के लिए tfg formats
+ <id> चलाएँ।
+
+
+
+
+
आर्काइव में असली फ़ाइलें होती हैं
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} और {{ end }}{{ $c.ID }}{{ end }} को
+ खाली खोल छोड़ने के बजाय प्रविष्टियों से भरा जा सकता है। बनाया गया आर्काइव सच में वे दस्तावेज़
+ रखता है जिनका वह दावा करता है, इसलिए टेस्ट के दौरान उसे खोलने वाली कोई भी चीज़ अंदर असली फ़ाइलें
+ पाती है।
+
+ PDF, PNG, DOCX, ZIP - कुल {{ .Facts.FormatCount }} फ़ॉर्मैट, और हर एक असली फ़ाइल है
+ जो अपने सॉफ़्टवेयर में खुलती है, ठीक उसी आकार में जो आपने माँगा। हर रन यह भी
+ लिखता है कि आपके एप्लिकेशन को हर फ़ाइल के साथ क्या करना चाहिए। कमांड लाइन और डेस्कटॉप विंडो,
+ मुफ़्त और ओपन सोर्स, पूरी तरह आपकी मशीन पर चलता है।
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ फ़ाइलों का बैच लिखने के लिए तैयार डेस्कटॉप विंडो। कमांड लाइन के पीछे वही इंजन चलता है।
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
असली फ़ॉर्मैट, हर एक अपने सॉफ़्टवेयर में खुलता है
+
+
+ 1 बाइट
+
आपके माँगे हर आकार की सटीकता, कभी चुपचाप राउंड नहीं की जाती
+
+
+ 0
+
कहीं भी कनेक्शन - न खाता, न टेलीमेट्री, न अपडेट जाँच
+
+
+
+
+
समस्या
+
एक टेस्ट फ़ाइल बनाना आसान है। सही हज़ार बनाना थकाऊ हिस्सा है
+
आप ऐसे सॉफ़्टवेयर को टेस्ट कर रहे हैं जो लोगों से फ़ाइलें लेता है। देर-सबेर आपको चाहिए होगा:
+
+
ठीक 10 MB की एक PDF, यह पता करने के लिए कि अपलोड सीमा असली है या नहीं
+
उस सीमा के दोनों ओर की तीन फ़ाइलें, एक से चूकने वाली गलतियाँ पकड़ने के लिए
+
10,000 लॉग फ़ाइलें, यह देखने के लिए कि फ़ोल्डर बड़ा होने पर रात का जॉब क्या करता है
+
एक ZIP जिसमें सच में 200 दस्तावेज़ हों, सही एक्सटेंशन वाला खोखला खोल नहीं
+
एक 4 GB की फ़ाइल, बिना अपनी रिपॉज़िटरी में 4 GB की फ़ाइल रखे
+
आपके लैपटॉप और बिल्ड सर्वर पर एक जैसे फ़िक्स्चर, बाइट-दर-बाइट
+
+
+ यही वह है जिसे यह बदलता है। यह QA इंजीनियरों, टेस्ट ऑटोमेशन और हर उस व्यक्ति के लिए बना है जिसके कोड
+ के पीछे अपलोड फ़ॉर्म, इंपोर्ट रूटीन, पार्सर या स्टोरेज कोटा है।
+
+
+
+
+
यह अलग क्यों है
+
दूसरे जनरेटर बाइट पर रुक जाते हैं। यह वह बताता है जो आपका टेस्ट असल में पूछता है
+
+ फ़ाइलों से भरा फ़ोल्डर आपको फिर भी तय करने देता है कि हर फ़ाइल क्या साबित करे। यहाँ हर रन फ़ाइलों के
+ बगल में एक manifest.json लिखता है - जो कुछ बना उसकी सादी सूची, और हर प्रविष्टि के
+ लिए एक घोषित अपेक्षा।
+
+
मान लें कि आपका अपलोड एंडपॉइंट 1 MB की अनुमति देता है। उस रेखा पर आने वाली तीन फ़ाइलें माँगें:
जहाँ जवाब आपकी अपनी नीति पर निर्भर है, वहाँ मैनिफ़ेस्ट यही कहता है
+
+ वह कोई अपेक्षा गढ़ने के बजाय unspecified दर्ज करता है। अंदाज़ा लगाने वाला जनरेटर झूठी
+ विफलताएँ पैदा करता है, और झूठा शोर मचाने वाला टेस्ट सूट आख़िरकार बंद कर दिया जाता है।
+
+
+
+
+
+
प्रीसेट
+
सवाल चुनें, पूरा सेट पाएँ
+
+ प्रीसेट एक टेस्ट सवाल के इर्द-गिर्द बनाया गया टेस्ट फ़ाइलों का सेट है, ताकि आपको खुद न सोचना पड़े कि
+ कौन सी फ़ाइल क्या साबित करती है। हर एक का एक पेज है जो बताता है कि वह आम तौर पर क्या पकड़ता है,
+ सेट में क्या है और वह कौन सी सेटिंग लेता है।
+
+ दस हज़ार लॉग फ़ाइलें, हर एक एक से आठ किलोबाइट के बीच, आकार सीड से निकाले गए ताकि कल वही सेट मिले।
+ हर रन को उसकी अपनी डायरेक्टरी दें - रन ने जो लिखा उसका एकमात्र रिकॉर्ड
+ मैनिफ़ेस्ट है, इसलिए टूल उसके ऊपर दूसरा लिखने से इनकार कर देता है:
+
+ आकार 1024 के गुणकों में गिने जाते हैं, जैसा आपका फ़ाइल मैनेजर करता है, इसलिए 2mb का
+ मतलब 2097152 बाइट है। सादी बाइट संख्या भी चलती है। दस्तावेज़ीकरण में
+ रेसिपी, मैनिफ़ेस्ट और एग्ज़िट कोड समझाए गए हैं।
+
+
+
+
+
आपको क्या मिलता है
+
बिना निगरानी के चलने वाले सूट के लिए बना
+
+
+
सटीक आकार, बाइट तक
+
10485761 बाइट माँगें और ठीक वही पाएँ। जिस आकार तक कोई फ़ॉर्मैट नहीं पहुँच सकता, वह कारण सहित त्रुटि है, गलत आकार की फ़ाइल कभी नहीं।
+
+
+
{{ .Facts.FormatCount }} असली फ़ॉर्मैट
+
एक्सटेंशन वाले भराव के शून्य नहीं। बनाई गई PNG इमेज व्यूअर में खुलती है, DOCX Word में खुलता है, ZIP खुल जाता है। हर एक को भेजने से पहले स्वतंत्र रीडरों से जाँचा जाता है।
+
+
+
टेस्ट ऑरेकल जैसा मैनिफ़ेस्ट
+
पाथ, आकार, SHA-256, फ़ॉर्मैट, सीड, टूल का संस्करण - और आपके सिस्टम को फ़ाइल के साथ क्या करना चाहिए।
+
+
+
दोहराए जा सकने वाला
+
वही रेसिपी और वही सीड, वही बाइट, किसी भी मशीन पर। बड़े बाइनरी फ़िक्स्चर की जगह एक छोटी YAML रेसिपी कमिट करें।
+
+
+
दो इंटरफ़ेस, एक इंजन
+
CI के लिए बनी कमांड लाइन और खोजपरक टेस्टिंग के लिए डेस्कटॉप विंडो। कोई भी दूसरे का घटाया हुआ रूप नहीं है, और एक टेस्ट दोनों की क्षमता-दर-क्षमता तुलना करता है।
+
+
+
पूरी तरह ऑफ़लाइन
+
कोई खाता नहीं, कोई क्लाउड नहीं, कोई टेलीमेट्री नहीं, कोई अपडेट जाँच नहीं। कमांड लाइन बाइनरी में नेटवर्क स्टैक कंपाइल ही नहीं किया गया है।
+
+
+
+
+
+
डाउनलोड
+
अपने सिस्टम का बिल्ड चुनें
+
+ आर्काइव खोलें और चलाएँ। tfg कमांड लाइन है और tfg-gui डेस्कटॉप विंडो। कोई
+ इंस्टॉलर नहीं और आपकी मशीन पर जोड़ने को कुछ नहीं।
+
+ {{ template "downloadsTable" . }}
+
+
क्या हस्ताक्षरित है, और क्या नहीं
+
+ Windows और macOS के डाउनलोड हस्ताक्षरित हैं, इसलिए वे अज्ञात डेवलपर की चेतावनी के बिना शुरू होते
+ हैं। Linux वाले नहीं हैं, क्योंकि डेस्कटॉप Linux में उन पर हस्ताक्षर करने का कोई समकक्ष तरीका
+ नहीं है। हर आर्काइव रिलीज़ पेज पर verify-SHA256SUMS.txt में सूचीबद्ध है, ताकि आप
+ जाँच सकें कि आपने क्या डाउनलोड किया।
+
+ {{ .ID }} प्रीसेट एक कमांड में इस सवाल के लिए असली टेस्ट फ़ाइलों का पूरा सेट बनाता है,
+ और उनके बगल में एक manifest.json जो बताता है कि आपके सिस्टम को हर फ़ाइल पर क्या
+ प्रतिक्रिया देनी चाहिए। नीचे सब कुछ इस संस्करण के डिफ़ॉल्ट पर प्रोग्राम से पढ़ा गया है।
+
या अपनी रेसिपी में, अपने टेस्ट के बगल में, इस पर आगे बनाएँ:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/hi/presets.html b/web/content/hi/presets.html
new file mode 100644
index 00000000..5528bfd4
--- /dev/null
+++ b/web/content/hi/presets.html
@@ -0,0 +1,32 @@
+
टेस्ट फ़ाइल प्रीसेट, हर टेस्ट सवाल के लिए एक सेट
+
+ प्रीसेट एक सवाल के इर्द-गिर्द बनाया गया टेस्ट फ़ाइलों का पूरा सेट है, एक मैनिफ़ेस्ट के साथ जो बताता
+ है कि आपके सिस्टम को हर फ़ाइल पर क्या प्रतिक्रिया देनी चाहिए। आप सवाल चुनते हैं, टूल सेट बनाता है।
+ हर प्रीसेट का अपना पेज है जो बताता है कि वह आम तौर पर क्या पकड़ता है, सेट में क्या है और वह कौन सी
+ सेटिंग लेता है।
+
+
+{{ template "presetsList" . }}
+
+
+
प्रीसेट और रेसिपी में क्या अंतर है?
+
+ अंदर से, कोई नहीं। प्रीसेट वह रेसिपी है जो टूल कुछ सेटिंग से आपके लिए लिखता है। tfg preset
+ eject उस रेसिपी को छापता है ताकि आप उसे अपने टेस्ट के बगल में रखकर संपादित कर सकें, और
+ आपकी अपनी रेसिपी एक पंक्ति से प्रीसेट पर आगे बन सकती है, extends: preset: और उसके
+ बाद उसका id।
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
क्या मैं डिफ़ॉल्ट पर भरोसा कर सकता हूँ?
+
+ फ़ाइलों के लिए, हाँ। ऐसी संख्या के लिए जो सिर्फ़ आपका सिस्टम जानता है, जैसे अपलोड फ़ॉर्म की सीमा,
+ डिफ़ॉल्ट हमारी अस्थायी जगह-धारक संख्या होती है, और टूल जब भी ऐसा कोई इस्तेमाल करता है तब यह
+ बताता है। हर प्रीसेट का पेज उन सेटिंग पर निशान लगाता है, और tfg preset show कुछ भी
+ लिखे जाने से पहले यह बता देता है।
+
+
diff --git a/web/content/hi/site.json b/web/content/hi/site.json
new file mode 100644
index 00000000..85ac5f3f
--- /dev/null
+++ b/web/content/hi/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "hi",
+ "locale": "hi_IN",
+ "name": "हिन्दी",
+ "dir": "hi",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "होम",
+ "title": "QA के लिए टेस्ट फ़ाइल जनरेटर - सटीक आकार, {{ .Facts.FormatCount }} असली फ़ॉर्मैट",
+ "description": "QA के लिए मुफ़्त, ओपन सोर्स टेस्ट फ़ाइल जनरेटर। सटीक आकार की असली PDF, DOCX, PNG और ZIP फ़ाइलें, और एक मैनिफ़ेस्ट जो बताता है कि आपके सिस्टम को क्या करना चाहिए।"
+ },
+ {
+ "key": "formats",
+ "slug": "formats",
+ "nav": "फ़ॉर्मैट",
+ "title": "{{ .Facts.FormatCount }} समर्थित फ़ाइल फ़ॉर्मैट - PDF, DOCX, PNG, ZIP और अन्य",
+ "description": "जनरेटर के सभी फ़ाइल फ़ॉर्मैट, हर फ़ॉर्मैट की सबसे छोटी संभव फ़ाइल, और उनकी सेटिंग। सभी {{ .Facts.FormatCount }} अपने सॉफ़्टवेयर में खुलते हैं।"
+ },
+ {
+ "key": "presets",
+ "slug": "presets",
+ "nav": "प्रीसेट",
+ "title": "टेस्ट फ़ाइल प्रीसेट - QA के सवालों के लिए तैयार सेट",
+ "description": "टेस्ट फ़ाइलों के तैयार सेट, हर सेट एक सवाल का जवाब देता है: अपलोड सीमा, फ़ाइल नाम, एन्कोडिंग, टेबल इंपोर्ट, खाली फ़ाइलें और अपलोड सत्यापन।"
+ },
+ {
+ "key": "docs",
+ "slug": "docs",
+ "nav": "दस्तावेज़ीकरण",
+ "title": "दस्तावेज़ीकरण - कमांड, रेसिपी, मैनिफ़ेस्ट, एग्ज़िट कोड",
+ "description": "कमांड लाइन या YAML रेसिपी से टेस्ट फ़ाइलें कैसे बनाएँ, मैनिफ़ेस्ट में क्या होता है, और CI में चलाने पर हर एग्ज़िट कोड का क्या अर्थ है।"
+ },
+ {
+ "key": "use-cases",
+ "slug": "use-cases",
+ "nav": "उपयोग के मामले",
+ "title": "उपयोग के मामले - अपलोड सीमा, CI फ़िक्स्चर, बड़े पैमाने पर टेस्ट",
+ "description": "अपलोड आकार सीमा की जाँच, CI के लिए दोहराए जा सकने वाले फ़िक्स्चर, दस हज़ार फ़ाइलें बनाना, और आर्काइव में असली सामग्री भरना।"
+ },
+ {
+ "key": "exact-size",
+ "slug": "create-file-exact-size",
+ "nav": "सटीक आकार",
+ "title": "तय आकार की फ़ाइल कैसे बनाएँ - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate और mkfile, हर एक अपने सिस्टम पर मापा गया, और जब टेस्ट को PDF या PNG चाहिए तब इस तरह बनी फ़ाइल क्यों काम नहीं आती।"
+ },
+ {
+ "key": "faq",
+ "slug": "faq",
+ "nav": "FAQ",
+ "title": "FAQ - टेस्ट फ़ाइलें बनाने के बारे में सवाल",
+ "description": "dd और fsutil से अंतर, क्या फ़ाइलें कमिट करना सुरक्षित है, क्या हर रन बाइट-दर-बाइट दोहराया जाता है, और आकार न मिल पाने पर क्या होता है।"
+ },
+ {
+ "key": "damage",
+ "slug": "corrupt-test-files",
+ "nav": "खराब फ़ाइलें",
+ "title": "खराब टेस्ट फ़ाइलें - सटीक आकार की बिगड़ी फ़ाइलें",
+ "description": "जानबूझकर बिगाड़ी गई, सटीक आकार की फ़ाइल, साथ में ऐसा मैनिफ़ेस्ट जो कहता है कि सिस्टम को उसे अस्वीकार करना चाहिए। अपलोड वैलिडेशन और पार्सर परखने के लिए।",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "test-files-in-ci",
+ "nav": "CI में टेस्ट फ़ाइलें",
+ "title": "CI में टेस्ट फ़ाइलें - GitHub Actions, GitLab CI और PowerShell",
+ "description": "बाइनरी कमिट करने के बजाय पाइपलाइन में टेस्ट फ़ाइलें बनाएँ: GitHub Actions वर्कफ़्लो, GitLab जॉब, एग्ज़िट कोड और PowerShell का जाल।",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "सामग्री पर जाएँ",
+ "navLabel": "मुख्य मेनू",
+ "langLabel": "भाषा",
+ "breadcrumbHome": "होम",
+ "imageAlt": "Testing Files Generator - सटीक आकार की असली टेस्ट फ़ाइलें, और एक मैनिफ़ेस्ट जो बताता है कि आपके सिस्टम को हर फ़ाइल पर क्या प्रतिक्रिया देनी चाहिए",
+ "schemaDescription": "QA के लिए मुफ़्त और ओपन सोर्स टेस्ट फ़ाइल जनरेटर। यह {{ .Facts.FormatCount }} फ़ॉर्मैट में सटीक आकार की असली फ़ाइलें बनाता है और एक मैनिफ़ेस्ट लिखता है जो बताता है कि जाँचे जा रहे सिस्टम को हर फ़ाइल पर क्या प्रतिक्रिया देनी चाहिए।",
+ "ctaDownload": "डाउनलोड करें",
+ "ctaSource": "सोर्स कोड देखें",
+ "ctaNote": "मुफ़्त और ओपन सोर्स, GPL-3.0। साइन अप की ज़रूरत नहीं। Windows और macOS के डाउनलोड हस्ताक्षरित हैं और बिना चेतावनी के शुरू होते हैं।",
+ "colFormat": "फ़ॉर्मैट",
+ "colName": "नाम",
+ "colExtension": "एक्सटेंशन",
+ "colSmallest": "सबसे छोटी फ़ाइल",
+ "colFidelity": "पूर्णता",
+ "colChecked": "जाँच का साधन",
+ "colSetting": "सेटिंग",
+ "colAccepts": "स्वीकार्य मान",
+ "colSystem": "सिस्टम",
+ "colCli": "कमांड लाइन",
+ "colWindow": "डेस्कटॉप विंडो",
+ "noBinary": "अभी बाइनरी नहीं",
+ "colCode": "कोड",
+ "colMeaning": "अर्थ",
+ "footerBlurb": "QA के लिए सटीक आकार की टेस्ट फ़ाइलें, और एक मैनिफ़ेस्ट जो बताता है कि आपके सिस्टम को हर फ़ाइल पर क्या प्रतिक्रिया देनी चाहिए।",
+ "footerProject": "प्रोजेक्ट",
+ "footerSource": "GitHub पर सोर्स कोड",
+ "footerReleases": "डाउनलोड",
+ "footerIssues": "समस्या बताएँ",
+ "footerSupport": "प्रोजेक्ट का समर्थन करें",
+ "footerPages": "पेज",
+ "footerLicence": "Copyright (C) 2026 DonislawDev। GNU जनरल पब्लिक लाइसेंस, संस्करण 3 के तहत जारी। आपकी बनाई फ़ाइलें आपकी हैं - लाइसेंस टूल पर लागू होता है, उसके आउटपुट पर नहीं।",
+ "footerPrivacy": "यह साइट कहीं से भी फ़ॉन्ट, स्क्रिप्ट या ट्रैकर लोड नहीं करती। यह कोई कुकी नहीं लगाती।",
+ "notFoundTitle": "यह पेज यहाँ नहीं है",
+ "notFoundLead": "आपने जो पता खोला वह इस साइट के किसी पेज से मेल नहीं खाता।",
+ "notFoundBack": "होम पेज पर जाएँ",
+ "read.format": "सेट की हर फ़ाइल का फ़ॉर्मैट। यह टूल का अपना फ़्लैग है, और प्रीसेट बस उसे एक डिफ़ॉल्ट देता है।",
+ "readTakes.format": "फ़ॉर्मैट पेज से एक फ़ॉर्मैट id",
+ "colDamage": "बिगाड़",
+ "colEffect": "बाइट के साथ क्या करता है",
+ "colSettings": "सेटिंग",
+ "noSettings": "कोई नहीं"
+ },
+ "endings": {
+ "0": "सब कुछ ठीक चला।",
+ "1": "टूल के अंदर एक अप्रत्याशित त्रुटि।",
+ "2": "गलत कमांड या फ़्लैग।",
+ "3": "रेसिपी मान्य नहीं है।",
+ "4": "फ़ॉर्मैट वह नहीं कर सकता जो माँगा गया।",
+ "5": "पढ़ना या लिखना विफल रहा।",
+ "6": "डिस्क पर पर्याप्त जगह नहीं है।",
+ "7": "verify को असंगति मिली।",
+ "8": "रन पूरा हुआ, पर सब कुछ नहीं बना।",
+ "130": "Ctrl+C से रोका गया।",
+ "143": "एक सिग्नल से रोका गया, CI का टाइमआउट ऐसा ही दिखता है।"
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "क्या फ़ॉर्मैट की अनुमति जितनी छोटी वैध फ़ाइल पास हो जाती है?",
+ "title": "खाली और न्यूनतम",
+ "pageTitle": "हर फ़ॉर्मैट की सबसे छोटी वैध और खाली टेस्ट फ़ाइलें",
+ "description": "यह टूल अपने {{ .Facts.FormatCount }} फ़ॉर्मैट में से हर एक में जो सबसे छोटी वैध फ़ाइल लिखता है, और जहाँ फ़ॉर्मैट अनुमति दे वहाँ एक खाली फ़ाइल, हर एक के साथ अपेक्षित प्रतिक्रिया।",
+ "catches": [
+ "एक वैध फ़ाइल जो बहुत छोटी होने के कारण ठुकरा दी जाती है, क्योंकि जाँच बाइट पढ़ने के बजाय गिनती है",
+ "एक खाली फ़ाइल जो रिपोर्ट होने के बजाय रीडर को क्रैश कर देती है",
+ "एक पिक्सेल चौड़ी तस्वीर जो थंबनेल तक के रास्ते में शून्य से भाग देती है",
+ "ऐसा स्टोरेज जो शून्य बाइट को असफल अपलोड समझकर बार-बार कोशिश करता रहता है"
+ ],
+ "details": {
+ "formats": "सेट किन फ़ॉर्मैट से बना है। इस बिल्ड के सभी फ़ॉर्मैट के लिए all रहने दें, या वे फ़ॉर्मैट लिखें जिन्हें आपका सिस्टम स्वीकार करता है।"
+ }
+ },
+ "filename-handling": {
+ "question": "क्या मेरा सिस्टम ऐसा फ़ाइल नाम सहेजेगा, दिखाएगा और लौटाएगा जिसकी उसे उम्मीद नहीं थी?",
+ "title": "फ़ाइल नाम का प्रबंधन",
+ "pageTitle": "टेस्टिंग के लिए समस्या वाले फ़ाइल नाम - Unicode और लंबाई",
+ "description": "ऐसे नामों वाली फ़ाइलें जो अपलोड और स्टोरेज बिगाड़ती हैं: अन्य लिपियाँ और इमोजी, दाएँ से बाएँ ओवरराइड, अदृश्य अक्षर, शेल और SQL सिंटैक्स, लंबाई की सीमाएँ।",
+ "catches": [
+ "ऐसा नाम जो स्क्रीन, लॉग या सूची में किसी और नाम जैसा दिखता है",
+ "ऐसा नाम जो अपलोड और स्टोरेज के बीच कट जाता है, छँट जाता है या दोबारा लिख दिया जाता है",
+ "अक्षरों में गिनी जाने वाली लंबाई की सीमा, जबकि स्टोरेज बाइट गिनता है"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "क्या आकार की सीमा ठीक वहीं लागू होती है जहाँ उसकी घोषणा की गई है?",
+ "title": "आकार की सीमाएँ",
+ "pageTitle": "अपलोड आकार सीमा की जाँच - ठीक सीमा पर की फ़ाइलें",
+ "description": "आपके सिस्टम की घोषित आकार सीमा से एक बाइट कम, ठीक बराबर और एक बाइट अधिक की फ़ाइलें, दोनों ओर चौड़े क़दम, हर एक पर चिह्न कि उसे स्वीकार होना चाहिए या नहीं।",
+ "catches": [
+ "सीमा पर एक से चूकने वाली गलतियाँ",
+ "MB और MiB का घालमेल, जो 4.8 प्रतिशत का फ़र्क है और ऐसी फ़ाइल निकल जाने देने के लिए काफ़ी है जिसे नहीं निकलना चाहिए",
+ "सीमा जो ब्राउज़र में लागू होती है, सर्वर पर नहीं"
+ ],
+ "details": {
+ "limit": "आपके सिस्टम की घोषित आकार सीमा। बाकी सब कुछ इसी से नापा जाता है।",
+ "spread": "सीमा के दोनों ओर कितनी दूर तक जाना है, आकारों की सूची के रूप में।"
+ }
+ },
+ "tabular-import": {
+ "question": "क्या मेरा टेबल इंपोर्ट वह झेल पाता है जो असली टूल एक्सपोर्ट करते हैं?",
+ "title": "टेबल इंपोर्ट",
+ "pageTitle": "CSV और Excel इंपोर्ट टेस्ट फ़ाइलें - डेलिमिटर, हेडर",
+ "description": "अलग डेलिमिटर, CR LF लाइन अंत, बिना हेडर और अलग कोटिंग वाली CSV, बहुत चौड़ी टेबल, एक Excel वर्कबुक और कई ढाँचों में JSON।",
+ "catches": [
+ "अर्धविराम वाली फ़ाइल जो एक ही कॉलम की तरह पढ़ी जाती है, क्योंकि डेलिमिटर खोजा नहीं गया, मान लिया गया",
+ "CRLF फ़ाइल जो पंक्तियों में बँट जाती है और हर पंक्ति के बाद एक खाली पंक्ति आ जाती है",
+ "बिना हेडर की टेबल जिसकी डेटा की पहली पंक्ति कॉलम नाम समझकर निगल ली जाती है",
+ "ऐसा इंपोर्ट जो दिखा सकने वाले कॉलम रखता है और बाकी चुपचाप गिरा देता है",
+ "ऐसा रीडर जो JSON रिकॉर्ड एक-एक पंक्ति में लेता है और पहले इंडेंट वाले दस्तावेज़ पर रुक जाता है"
+ ],
+ "details": {
+ "rows": "स्प्रेडशीट में कितनी पंक्तियाँ हैं। फ़ाइल ठीक उसी आकार में लिखी जाती है जितने में उतनी पंक्तियाँ पैक होती हैं, इसलिए ऊपर का बजट इस मान के साथ खिसकता है।",
+ "columns": "स्प्रेडशीट की हर पंक्ति में कितने कॉलम हैं। पंक्तियों गुणा कॉलम की एक ऊपरी सीमा है, और उससे आगे माँगने पर कुछ भी लिखे जाने से पहले ही इनकार कर दिया जाता है।"
+ }
+ },
+ "text-encoding": {
+ "question": "क्या मेरा रीडर जानता है कि फ़ाइल किस एन्कोडिंग में है, या अंदाज़ा लगा रहा है?",
+ "title": "टेक्स्ट एन्कोडिंग",
+ "pageTitle": "टेक्स्ट एन्कोडिंग टेस्ट फ़ाइलें - UTF-8, UTF-16, BOM, CRLF",
+ "description": "वही टेक्स्ट UTF-8, UTF-16LE और UTF-16BE में, बाइट ऑर्डर मार्क के साथ और बिना, और CR LF तथा LF लाइन अंत, यह जाँचने के लिए कि रीडर टेक्स्ट कैसे डिकोड करता है।",
+ "catches": [
+ "ऐसा रीडर जो UTF-8 मान लेता है और UTF-16 फ़ाइल को तीन में से एक अक्षर या डिब्बों की पंक्तियों की तरह दिखाता है",
+ "बाइट ऑर्डर मार्क जो सामग्री की तरह पढ़ा जाता है, जिससे इंपोर्ट का पहला फ़ील्ड तीन अनजान अक्षरों से शुरू होता है",
+ "ऐसा इंपोर्टर जो शुरुआती बाइट से एन्कोडिंग का अंदाज़ा लगाता है और लंबी फ़ाइल पर अलग अंदाज़ा लगाता है",
+ "CRLF फ़ाइल जो हर पंक्ति के बाद खाली पंक्ति के साथ बँट जाती है, या कैरिज रिटर्न जो आख़िरी फ़ील्ड में रह जाता है"
+ ],
+ "details": {
+ "sample": "सेट की हर फ़ाइल कितनी बड़ी है। UTF-16 हर अक्षर के लिए दो बाइट रखता है, इसलिए विषम संख्या अस्वीकार हो जाती है।"
+ }
+ },
+ "upload-validation": {
+ "question": "क्या मेरा अपलोड फ़ॉर्म वह लेता है जो उसे लेना चाहिए और बाकी को लौटा देता है?",
+ "title": "अपलोड सत्यापन",
+ "pageTitle": "अपलोड सत्यापन टेस्ट फ़ाइलें - प्रकार, आकार और नाम",
+ "description": "अपलोड फ़ॉर्म जाँचने की फ़ाइलें: अनुमत और निषिद्ध प्रकार, एक्सटेंशन से न मिलती सामग्री, आकार सीमा के दोनों ओर, हानिकारक नाम और एक साथ अपलोड।",
+ "catches": [
+ "सीमा जो ब्राउज़र में लागू होती है, सर्वर पर नहीं",
+ "SVG या HTML फ़ाइल जिसे तस्वीर या सादा टेक्स्ट समझ लिया जाता है, जो फ़ॉर्म से स्क्रिप्ट निकाल ले जाने का एक तरीका है",
+ "फ़ाइल जो सिर्फ़ एक्सटेंशन से जाँची जाती है और कभी खोली नहीं जाती, इसलिए .jpg नाम की PDF निकल जाती है",
+ "ऐसा फ़ॉर्म जो आकार देखने से पहले पूरी बॉडी मेमोरी में पढ़ लेता है",
+ "PHOTO.JPG नाम का अपलोड जो ठुकरा दिया जाता है जबकि photo.jpg ले लिया जाता है, या उल्टा",
+ "रिक्त स्थान, कोष्ठक या ASCII से बाहर के अक्षरों वाला नाम जो बिना बदले डिस्क पर लिख दिया जाता है"
+ ],
+ "details": {
+ "limit": "आपके अपलोड फ़ॉर्म की घोषित आकार सीमा। यह सेट इसके दोनों ओर एक-एक क़दम लेता है - हर दूरी की फ़ाइल के लिए size-boundaries प्रीसेट चलाएँ।",
+ "allow": "आपका फ़ॉर्म किन प्रकारों को स्वीकार करे। हर प्रकार उसी प्रकार की असली फ़ाइल बन जाता है, और ये पूरे सेट का सकारात्मक नियंत्रण हैं।",
+ "deny": "आपका फ़ॉर्म किन एक्सटेंशन को ठुकराए। जिस एक्सटेंशन का इस बिल्ड में कोई फ़ॉर्मैट नहीं है, उसे भी उसी नाम की एक फ़ाइल मिलती है जिसमें सादा टेक्स्ट होता है।",
+ "far-over": "एकमात्र बड़ी फ़ाइल सीमा से कितनी आगे जाती है। जहाँ सीमा के कई गुना लिखना डिस्क के लायक न हो, वहाँ इसे बंद कर दें।",
+ "bulk": "एक साथ अपलोड में कितनी फ़ाइलें हैं। शून्य होने पर वह समूह सेट से पूरी तरह हट जाता है।"
+ }
+ }
+ },
+ "commands": {
+ "generate": "रेसिपी या फ़्लैग से फ़ाइलें बनाएँ",
+ "validate": "रेसिपी जाँचें और कुछ न लिखें",
+ "verify": "किसी डायरेक्टरी को मैनिफ़ेस्ट से मिलाकर जाँचें",
+ "cleanup": "मैनिफ़ेस्ट में सूचीबद्ध फ़ाइलें हटाएँ",
+ "recipe fmt": "रेसिपी को उसके स्थिर रूप में छापें",
+ "preset": "किसी नामित टेस्ट सवाल से फ़ाइलों का सेट बनाएँ",
+ "formats": "इस बिल्ड के समर्थित फ़ॉर्मैट सूचीबद्ध करें",
+ "damage": "इस बिल्ड द्वारा किसी फ़ाइल को जानबूझकर बिगाड़ने के तरीके सूचीबद्ध करें",
+ "tool": "आपके पास पहले से मौजूद फ़ाइलों के लिए छोटे टूल",
+ "version": "टूल का संस्करण छापें",
+ "license": "लाइसेंस और बनाई गई फ़ाइलों के लिए उसका अर्थ छापें"
+ },
+ "outcomes": {
+ "accept": "आपके सिस्टम को फ़ाइल मंज़ूर करनी चाहिए।",
+ "reject": "आपके सिस्टम को फ़ाइल अस्वीकार करनी चाहिए।",
+ "sanitize": "आपके सिस्टम को फ़ाइल मंज़ूर करके उसे साफ़ करना चाहिए, जैसे उसका नाम बदलकर।",
+ "unspecified": "यह आपके सिस्टम के नियमों पर निर्भर है। आप तय करें, फिर जाँचें कि जो होता है वही है जो आप चाहते थे।"
+ },
+ "damages": {
+ "zero-head": "फ़ाइल के शुरुआती बाइट को शून्य से ढक देता है और लंबाई नहीं छेड़ता। ज़्यादातर रीडर सबसे पहले वहीं देखते हैं, इसलिए यह बिगाड़ लगभग हर चीज़ पकड़ लेती है।"
+ },
+ "terms": {
+ "oracleNone": "लागू नहीं",
+ "int": "कोई भी पूर्ण संख्या",
+ "choice": "एक तय समूह में से एक",
+ "bool": "सही या गलत",
+ "size": "2mb जैसा आकार",
+ "text": "टेक्स्ट",
+ "pixels": "पिक्सेल",
+ "paragraphs": "अनुच्छेद",
+ "rows": "पंक्तियाँ",
+ "columns": "कॉलम",
+ "slides": "स्लाइड",
+ "hertz": "हर्ट्ज़",
+ "megapixels": "मेगापिक्सेल",
+ "million cells": "दस लाख सेल",
+ "entries per second": "प्रति सेकंड प्रविष्टियाँ",
+ "files": "फ़ाइलें",
+ "sizes separated by commas": "अल्पविराम से अलग किए गए आकार",
+ "format ids separated by commas": "अल्पविराम से अलग किए गए फ़ॉर्मैट id",
+ "format ids separated by commas, or all": "अल्पविराम से अलग किए गए फ़ॉर्मैट id, या all",
+ "extensions separated by commas": "अल्पविराम से अलग किए गए एक्सटेंशन",
+ "the id of a format, as tfg formats lists them": "किसी फ़ॉर्मैट का id, जैसा tfg formats सूचीबद्ध करता है",
+ "the password, in plain text": "पासवर्ड, सादे टेक्स्ट में",
+ "any text": "कोई भी टेक्स्ट",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "2024-02-29 या 2024-02-29T13:45:00+02:00 जैसी तारीख, या none"
+ },
+ "faq": [
+ {
+ "q": "यह dd, fsutil या truncate से कैसे अलग है?",
+ "a": "वे आपको सही आकार की फ़ाइल देते हैं जो खालीपन से भरी होती है। इस तरह बनी photo.png नाम की 2 MB की फ़ाइल PNG नहीं होती, इसलिए जो भी उसे सच में पार्स करता है वह गलत कारण से उसे ठुकरा देता है, और आपका टेस्ट भी गलत कारण से पास हो जाता है। यह टूल ठीक 2 MB की असली PNG बनाता है जो इमेज व्यूअर में खुलती है, और उसके साथ यह घोषणा आती है कि आपके सिस्टम को उसके साथ क्या करना चाहिए।",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "क्या यह मुफ़्त है, और क्या मैं इसे काम पर इस्तेमाल कर सकता हूँ?",
+ "a": "दोनों के लिए हाँ। यह GPL-3.0 के तहत जारी है और इसकी कोई कीमत नहीं। कोई खाता, लाइसेंस कुंजी या सशुल्क स्तर नहीं है।"
+ },
+ {
+ "q": "क्या मैं बनाई गई फ़ाइलें क्लोज़्ड सोर्स उत्पाद में इस्तेमाल कर सकता हूँ?",
+ "a": "हाँ। लाइसेंस टूल के कोड पर लागू होता है, उस पर नहीं जो टूल बनाता है। बनाई गई फ़ाइलें, रेसिपी और मैनिफ़ेस्ट आउटपुट हैं, व्युत्पन्न कृतियाँ नहीं, इसलिए आप उन्हें बिना किसी बाध्यता के कमिट और वितरित कर सकते हैं।"
+ },
+ {
+ "q": "क्या बनाई गई फ़ाइलों में असली निजी डेटा होता है?",
+ "a": "नहीं। अंदर का सब कुछ एक सीड से बनाया जाता है। कोई डेटासेट नहीं पढ़ा जाता, किसी सेवा से संपर्क नहीं किया जाता और किसी तीसरे पक्ष की सामग्री नहीं जोड़ी जाती। बनाए गए ईमेल पते को अप्रयुक्त नहीं, बल्कि अनुपयोगी मानें, क्योंकि कोई भी यादृच्छिक स्ट्रिंग संयोग से किसी असली पते से मेल खा सकती है।"
+ },
+ {
+ "q": "क्या मुझे दूसरी मशीन पर ठीक वही फ़ाइलें मिलेंगी?",
+ "a": "हाँ, बाइट-दर-बाइट, उसी रेसिपी और उसी सीड के साथ। प्रोजेक्ट हर बदलाव पर इसका परीक्षण करता है, और इसे तोड़ने के लिए मुख्य संस्करण बढ़ाना पड़ता है। इसी वजह से आप बड़े बाइनरी फ़िक्स्चर की जगह एक छोटी रेसिपी कमिट कर सकते हैं।"
+ },
+ {
+ "q": "क्या इसे इंटरनेट कनेक्शन चाहिए?",
+ "a": "कभी नहीं। कोई टेलीमेट्री नहीं, कोई अपडेट जाँच नहीं और कोई क्लाउड क्लाइंट नहीं, और कमांड लाइन बाइनरी में नेटवर्क स्टैक कंपाइल ही नहीं किया गया है। यह बिना नेटवर्क की मशीन पर और बंद कॉर्पोरेट माहौल में भी चलता है।"
+ },
+ {
+ "q": "अगर मैं ऐसा आकार माँगूँ जो कोई फ़ॉर्मैट हासिल नहीं कर सकता, तो क्या होता है?",
+ "a": "आपको एक त्रुटि मिलती है जो फ़ॉर्मैट, सबसे छोटा संभव आकार, उस न्यूनतम सीमा का कारण और इसके बदले क्या करें यह बताती है, और कोई फ़ाइल नहीं लिखी जाती। टूल कभी आकार को चुपचाप राउंड नहीं करता। हर न्यूनतम सीमा फ़ॉर्मैट पेज पर सूचीबद्ध है।",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "क्या मैं जानबूझकर टूटी हुई फ़ाइल बना सकता हूँ?",
+ "a": "हाँ। --damage zero-head जोड़ें और फ़ाइल ठीक माँगे गए आकार में निकलती है, शुरुआती बाइट शून्य से ढके हुए, इसलिए रीडर उसे ठुकरा देता है, और मैनिफ़ेस्ट कहता है कि आपके सिस्टम को उसे अस्वीकार करना चाहिए। ब्योरा खराब टेस्ट फ़ाइलों वाले पेज पर है।",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "आगे कौन से फ़ॉर्मैट आ रहे हैं?",
+ "a": "7z, mp3 और mp4। आज {{ .Facts.FormatCount }} फ़ॉर्मैट शुरू से अंत तक काम करते हैं।"
+ },
+ {
+ "q": "मैं इसे किन सिस्टम पर चला सकता हूँ?",
+ "a": "कमांड लाइन Windows और Linux पर Intel और ARM दोनों पर, और Apple Silicon Mac पर चलती है। डेस्कटॉप विंडो Intel पर Windows, Intel पर Linux और Apple Silicon Mac के लिए आती है। Intel Mac समर्थित नहीं हैं और उनके लिए कुछ नहीं बनाया जाता।"
+ },
+ {
+ "q": "क्या मुझे कुछ इंस्टॉल करना होगा?",
+ "a": "नहीं। अपने सिस्टम का आर्काइव डाउनलोड करें, खोलें और बाइनरी चलाएँ। कोई इंस्टॉलर नहीं, जोड़ने के लिए कोई रनटाइम नहीं और सुलझाने के लिए कोई निर्भरता नहीं। अगर आपके पास Go है तो एक ही go install कमांड भी काम करती है।",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "हज़ारों फ़ाइलों पर रन Windows पर धीमा क्यों है?",
+ "a": "क्योंकि Windows हर उस पाथ के लिए ज़्यादा वसूलता है जिसे वह देखता है, और हज़ारों फ़ाइलों से गुज़रने वाली कमांड हज़ारों पाथ देखती है। 1 kB की 3000 फ़ाइलों वाली एक मशीन पर मापने पर, verify को Windows पर लगभग 0.9 सेकंड और कंटेनर में Linux पर लगभग 0.2 सेकंड लगे। छोटा आउटपुट पाथ Windows का आँकड़ा घटाता है, क्योंकि फ़ाइलों के ऊपर का हर फ़ोल्डर उसमें शामिल होता है जिसे देखा जाता है।"
+ }
+ ]
+}
diff --git a/web/content/hi/use-cases.html b/web/content/hi/use-cases.html
new file mode 100644
index 00000000..388419f9
--- /dev/null
+++ b/web/content/hi/use-cases.html
@@ -0,0 +1,131 @@
+
लोग इसका इस्तेमाल किसलिए करते हैं
+
+ पाँच काम जो लोगों से फ़ाइलें लेने वाले लगभग हर प्रोजेक्ट में आते हैं, और हर एक को करने वाली कमांड।
+ नीचे का हर उदाहरण जैसा लिखा है वैसा चलता है।
+
+
+
+
अपलोड सीमाएँ
+
यह जाँचना कि फ़ाइल आकार सीमा वहीं लागू होती है जहाँ वह कहती है
+
+ एक सीमा एक नहीं, तीन टेस्ट केस है: ठीक नीचे, ठीक पर, और ठीक ऊपर। इन्हें हाथ से बनाने का मतलब बाइट
+ संख्या निकालना और उम्मीद करना है कि आप एक से नहीं चूके। इसके बजाय सेट माँगें:
+
+ आपको 1048575, 1048576 और 1048577 बाइट की तीन असली PDF मिलती हैं, और एक मैनिफ़ेस्ट जो कहता है कि पहली
+ दो स्वीकार होनी चाहिए और तीसरी size_limit के कारण अस्वीकार। आपका टेस्ट तीन असर्शन
+ हाथ से लिखने के बजाय अपेक्षा पढ़ता है - और जब सीमा बदलती है तो आप एक संख्या बदलकर दोबारा चलाते
+ हैं।
+
+
+ जब आप इनलाइन एक ही सीमा सेट चाहें तो यही प्रीसेट के बिना भी चलता है:
+
+ बड़े बाइनरी फ़िक्स्चर रिपॉज़िटरी क्लोन करना धीमा और रिव्यू करना कठिन बनाते हैं, और किसी एक के बदले
+ जाने पर कोई नहीं बता सकता कि क्या बदला। रेसिपी कुछ सौ अक्षरों की YAML है जो वही फ़ाइलें दोबारा
+ बना देती है - किसी भी मशीन पर बाइट-दर-बाइट - क्योंकि हर फ़ाइल रन के सीड से
+ निकलती है।
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ हर अंत का अपना एग्ज़िट कोड है, इसलिए पाइपलाइन खराब रेसिपी, भरी डिस्क और सत्यापन असंगति में अंतर कर
+ सकती है। विफल रन स्टैंडर्ड आउटपुट पर कुछ नहीं छापता, जिससे लॉग पार्सर किसी त्रुटि को डेटा नहीं
+ पढ़ता।
+
+
+
+
+
पैमाना
+
यह जानना कि फ़ोल्डर बड़ा होने पर क्या होता है
+
+ इंपोर्ट रूटीन, रात के जॉब और डायरेक्टरी सूचियाँ दस हज़ार फ़ाइलों पर दस की तुलना में अलग व्यवहार करती
+ हैं। किसी सीमा से निकाले गए आकार सेट को दस हज़ार एक जैसी फ़ाइलों के बजाय असली ट्रैफ़िक जैसा
+ दिखाते हैं, और निकालना सीड से होता है, इसलिए सेट कल भी वही रहता है।
+
+ डिस्क की खाली जगह से बड़ा रन पहला बाइट लिखे जाने से पहले ठुकरा दिया जाता है, डिस्क भरकर बीच में विफल
+ होने के बजाय।
+
+
+
+
+
आर्काइव
+
ऐसे आर्काइव से अनपैकर का परीक्षण जिसमें सच में फ़ाइलें हैं
+
+ सही एक्सटेंशन वाला खाली आर्काइव उस कोड के बारे में कुछ साबित नहीं करता जो उसे खोलकर अंदर की चीज़ों
+ से गुज़रता है। सामग्री घोषित करें और आर्काइव सच में उसे रखता है:
+
+ नेस्टिंग की गहराई, प्रविष्टियों की संख्या और अंदर की चीज़ों का आकार, ये सब वे बातें हैं जिन पर
+ इंपोर्ट रूटीन की अपनी राय होती है, और इसी तरह आप जानते हैं कि वह राय क्या है।
+
+
+
+
+
पार्सर और व्यूअर
+
यह जाँचना कि आपका अपना कोड फ़ॉर्मैट को असली सॉफ़्टवेयर की तरह पढ़ता है
+
+ यहाँ का हर फ़ॉर्मैट भेजे जाने से पहले स्वतंत्र रीडर से जाँचा जाता है - PNG खोली जाती है और उसके
+ पिक्सेल मिलाए जाते हैं, DOCX अलग लाइब्रेरी से वापस पढ़ा जाता है, आर्काइव खोला जाता है। इसका मतलब
+ है कि जो फ़ाइल आपका पार्सर ठुकराता है वह आपके पार्सर के बारे में एक खोज है, जनरेटर के बारे में
+ नहीं।
+
+ फ़ॉर्मैट पेज हर एक की स्वीकार की जाने वाली सेटिंग और हर एक की सबसे छोटी
+ संभव फ़ाइल सूचीबद्ध करता है।
+
+
+
+
+
गाइड
+
इनमें से दो, विस्तार से
+
+
+ खराब टेस्ट फ़ाइलें - जानबूझकर बिगाड़ी गई, ठीक-ठीक आकार की
+ फ़ाइल, जिसके साथ क्या होना चाहिए वह मैनिफ़ेस्ट में लिखा है।
+
+
+ CI में टेस्ट फ़ाइलें - GitHub Actions का वर्कफ़्लो, GitLab का
+ जॉब और वे एग्ज़िट कोड जो बिल्ड को विफल करते हैं।
+
+
+
+
+
+
यह किसके लिए है
+
+ QA इंजीनियर, टेस्ट ऑटोमेशन और हर वह व्यक्ति जिसके कोड के पीछे अपलोड फ़ॉर्म, इंपोर्ट रूटीन, पार्सर या
+ स्टोरेज कोटा है। यह बिना किसी नेटवर्क की मशीन पर चलता है, जो बंद कॉर्पोरेट माहौल में मायने रखता
+ है जहाँ ब्राउज़र आधारित जनरेटर विकल्प नहीं होता।
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/id/ci.html b/web/content/id/ci.html
new file mode 100644
index 00000000..71d4d301
--- /dev/null
+++ b/web/content/id/ci.html
@@ -0,0 +1,189 @@
+{{ with .Up }}
+ Fixture biner di repositori tinggal selamanya dalam riwayatnya, tidak bisa ditinjau di diff, dan
+ menjadi mustahil ketika filenya besar. Buat file di dalam pipeline dari sebuah resep. Resep adalah
+ teks, byte keluar sama setiap kali, dan langkah terakhir membuktikan tidak ada yang bergeser.
+
+
+
+
Jawaban singkat
+
+ Pasang tfg, jalankan tfg generate fixtures.yaml --out ./fixtures sebelum
+ tes dan tfg verify ./fixtures/manifest.json sesudahnya. Kedua langkah menggagalkan
+ build dengan sendirinya, dengan kode keluar yang menyebut alasannya.
+
+
+
+
+
Mengapa tidak di-commit
+
Mengapa fixture tidak seharusnya tinggal di repositori
+
+
+ Ia tetap ada di riwayat. Menghapus file biner kemudian tidak mengecilkan klon,
+ karena setiap versinya masih ada.
+
+
+ Diff tidak menunjukkan apa yang berubah. Peninjau hanya melihat bahwa sebuah PDF
+ berbeda, tidak lebih. Resep berubah satu baris.
+
+
+ File besar tidak muat. GitHub menolak push yang berisi file lebih dari 100 MB, jadi
+ tes batas unggah 500 MB tidak punya apa pun untuk di-commit.
+
+
+
+ Yang di-commit adalah resepnya. Resep dan seed yang sama menulis byte yang sama di setiap mesin,
+ jadi file yang dibuat di pipeline adalah file yang Anda punya di laptop.
+
+
+
+
+
Resep
+
Resep yang tinggal di samping tes
+
+ Resep ini menulis dua puluh lima faktur yang harus diterima dan dua gambar di atas batas yang harus
+ ditolak, dan manifes mencatat kedua harapan itu:
+
+ Baris checksum membandingkan arsip dengan verify-SHA256SUMS.txt dari rilis yang sama.
+ Versinya dikunci, jadi rilis baru tidak pernah mengubah build yang tidak Anda sentuh.
+
Apa yang membuat sebuah langkah gagal, dan mengapa
+
+ Setiap akhir punya kode keluarnya sendiri, jadi langkah gagal dengan sendirinya dan log menyebut
+ yang mana. Yang dijumpai pipeline:
+
+
+
3 - resep tidak valid. Tidak ada yang ditulis, dan setiap masalah disebut
+
4 - format tidak bisa melakukan yang diminta, misalnya ukuran di bawah minimumnya
+
6 - ruang disk tidak cukup
+
7 - tfg verify menemukan file yang tidak cocok dengan manifesnya
+
8 - proses selesai, tetapi tidak semuanya dihasilkan
+
+
+ Proses yang gagal tidak mencetak apa pun ke keluaran standar, sehingga parser log tidak pernah salah
+ mengira error sebagai data. Tabel lengkapnya ada di halaman
+ dokumentasi.
+
+
+
+
+
PowerShell
+
Skrip PowerShell butuh satu baris lagi
+
+ PowerShell tidak membawa kode keluar sebuah program keluar dari file .ps1. Jalankan
+ satu dengan -File dan skrip menjawab 0 bahkan ketika alat di dalamnya
+ menolak pekerjaan, sehingga build yang seharusnya merah menjadi hijau. Baris terakhir adalah
+ seluruh perbaikannya:
+
+ Begitulah PowerShell bekerja, bukan sesuatu dari alat ini. cmd, bash, dan
+ zsh tidak butuh tambahan apa pun.
+
+
+
+
+
Beberapa job
+
Berbagi fixture antar job
+
+ Biasanya tidak perlu mengunggahnya. Karena resep yang sama menulis byte yang sama, setiap job bisa
+ menjalankan tfg generate sendiri, yang lebih cepat daripada mengunggah lalu
+ mengunduh. Ketika sebuah job harus menerima file dari job lain, jalankan tfg verify
+ pada manifes setelah transfer, dan ia menyatakan apakah yang tiba sama dengan yang ditulis.
+
+
+
+
+
Berikutnya
+
Ke mana dari sini
+
+
+ File uji yang rusak menambahkan file yang sengaja dirusak ke resep
+ yang sama.
+
+
+ Kasus penggunaan menunjukkan apa lagi yang bisa diperiksa sebuah
+ proses di pipeline.
+
+
+ Dokumentasi memuat setiap perintah, kunci resep, dan kode keluar.
+
+
+
diff --git a/web/content/id/damage.html b/web/content/id/damage.html
new file mode 100644
index 00000000..7922552b
--- /dev/null
+++ b/web/content/id/damage.html
@@ -0,0 +1,174 @@
+{{ with .Up }}
+ Validator yang hanya pernah diberi file sehat belum benar-benar diuji. Inilah cara mendapatkan file
+ yang sengaja dirusak, keluar dengan tepat sebesar yang Anda minta, dan membawa
+ manifes yang menyatakan apa yang harus dilakukan sistem Anda terhadapnya.
+
+
+
+
Jawaban singkat
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out menulis PNG
+ berukuran tepat 2097152 byte yang byte pertamanya nol, dan manifes di sebelahnya mencatat bahwa
+ sistem Anda harus menolaknya.
+
+
+
+
+
Cara yang biasa
+
Mengapa file yang dirusak dengan tangan adalah tes yang buruk
+
+ Cara yang biasa adalah editor hex, skrip yang membalik beberapa byte acak, atau memotong file dengan
+ head atau truncate. Berhasil sekali, lalu merugikan Anda:
+
+
+
+ Hasilnya berbeda setiap kali. Byte acak jatuh di tempat baru pada setiap proses,
+ jadi kegagalan hari Selasa mungkin tidak muncul lagi hari Rabu.
+
+
+ Ukurannya berubah. File yang dipotong lebih kecil daripada batas yang seharusnya
+ tidak dilewatinya, sehingga pemeriksaan ukuran menjawab sebelum pemeriksaan isi dan tes lulus
+ karena alasan yang salah.
+
+
+ Sering tidak terdeteksi. Teks biasa masih terbaca dengan satu byte berubah di
+ tengah, dan pembaca gambar yang toleran hanya menggambarnya, sehingga file yang seharusnya
+ rusak malah diterima.
+
+
+ Tidak mengatakan apa yang seharusnya terjadi. File hanyalah byte, dan siapa pun
+ yang membaca tes itu kemudian harus menebak apakah yang dimaksud penerimaan atau penolakan.
+
+
+
+
+
+
Yang Anda dapatkan
+
File yang rusak tetap berukuran seperti yang Anda minta
+
+ File dibuat seperti biasa lalu dirusak, dalam perjalanan ke disk. Ukurannya tetap seperti yang Anda
+ minta, dan perintah yang sama menulis byte yang sama lagi.
+
+ Pengaturan ditulis setelah titik dua. Opsi ini bisa diulang, dan kerusakan diterapkan menurut urutan
+ yang Anda tulis. Berlaku untuk semua {{ .Facts.FormatCount }} format.
+
+
+
+
+
Yang bisa dilakukan
+
Kerusakan apa saja yang ada?
+
+ Ini daftar yang dicetak program, dibaca darinya saat halaman ini dibangun. tfg damage
+ mencetak daftar yang sama, dan tfg damage <id> menjelaskan apa yang diterima
+ salah satunya.
+
+ {{ template "damagesTable" . }}
+
+ zero-head menulis nol di atas awal file. Sebagian besar pembaca melihat ke sana lebih
+ dulu, ke tanda pengenal dan header yang menyatakan file itu apa, jadi hampir semua pembaca
+ menyadarinya. Teks biasa dan log tidak punya tanda pengenal dan juga ditolak, karena deretan
+ byte nol bukan teks. Di bawah empat byte, sebagian format keluar dengan kerusakan yang tidak
+ dikeluhkan pembaca mana pun, itulah sebabnya pengaturan dimulai dari empat.
+
+
+
+
+
Yang dikatakan manifes
+
Manifes yang menyatakan apa yang harus terjadi
+
+ Setiap file yang rusak mendapat catatan yang menyatakan sistem Anda harus menolaknya, dengan
+ kerusakannya dicatat di sampingnya:
+
+ Dua permintaan ditolak sebelum apa pun ditulis, karena masing-masing akan meninggalkan file di disk
+ yang dijelaskan keliru oleh manifes:
+
+
+
file yang lebih kecil dari yang dibutuhkan kerusakan, yang akan keluar tanpa perubahan
+
+ expected: accept di samping kerusakan, karena tidak ada yang bisa memenuhinya. Tulis
+ sanitize jika sistem Anda memang harus memperbaiki file itu, atau
+ unspecified jika justru itu pertanyaan Anda
+
+
+
+
+
+
Dalam resep
+
File sehat dan rusak dalam satu proses
+
+ Taruh keduanya dalam satu resep, dan manifes membawa harapan setiap file, sehingga tes tidak butuh
+ daftar mana yang mana:
+
+ Tes membaca manifes dan memeriksa bahwa yang terjadi sama dengan yang dinyatakan. Tidak perlu daftar
+ nama file:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Penolakan yang baik adalah penolakan yang bersih. Pesan yang menyebut apa yang salah adalah jawaban
+ yang Anda inginkan. Kesalahan server, macet, atau file yang tersimpan setengah adalah cacat yang
+ ingin ditemukan tes ini.
+
+
+
+
+
Berikutnya
+
Ke mana dari sini
+
+
+ Preset upload-validation mengajukan dua pertanyaan lain
+ kepada sebuah formulir, soal ukuran dan soal jenis.
+
+
+ File uji di CI menjalankan resep seperti ini di pipeline.
+
+
diff --git a/web/content/id/docs.html b/web/content/id/docs.html
new file mode 100644
index 00000000..4b043388
--- /dev/null
+++ b/web/content/id/docs.html
@@ -0,0 +1,283 @@
+
Dokumentasi
+
+ Semua yang dilakukan alat ini, disusun sebagai pertanyaan yang benar-benar dibawa orang.
+ README di repositori adalah referensi lengkap dan selalu sesuai
+ dengan build yang Anda unduh.
+
+
+
+
Perintah apa saja yang ada?
+
Masing-masing melakukan satu hal:
+ {{ template "commandList" . }}
+
+
+
+
Bagaimana cara membuat satu file dengan ukuran tepat?
+
+ Sebutkan format, ukuran, dan tujuannya. Ukuran dihitung dalam kelipatan 1024, jadi 2mb
+ adalah 2097152 byte. Jumlah byte biasa juga bisa, jadi --size 10485761 meminta
+ persis sebanyak itu.
+
+
tfg generate --format png --size 2mb --out ./out
+
Opsi yang berguna pada generate:
+
+
+
Opsi
Fungsinya
+
+
--format <id>
format file, misalnya txt
+
--size <size>
ukuran tepat setiap file, seperti 10mb atau jumlah byte biasa
+
--size-range <a-b>
ukuran yang diundi per file dari suatu rentang, seperti 1kb-8kb. Undiannya berasal dari seed
+
--boundary <size>
tiga file di sekitar batas: satu byte di bawah, batas itu sendiri, satu byte di atas
+
--count <n>
berapa banyak file yang dibuat. Bawaan 1
+
--name <template>
templat nama, misalnya invoice_{index:04}.txt
+
--out <dir>
direktori tujuan penulisan
+
--seed <n>
seed run. Seed yang sama menghasilkan byte yang sama
+
--set <k>=<v>
pengaturan format, dapat diulang
+
--damage <name>
merusak file dengan sengaja, dapat diulang dan diterapkan berurutan. Jalankan tfg damage untuk daftarnya
+
--expected <outcome>
accept, reject, sanitize, atau unspecified
+
--dry-run
menghitung dan menampilkan, tidak menulis apa pun
+
--json
menulis manifes ke keluaran standar
+
+
+
+
+
+
+
Bagaimana membuat file yang sengaja dirusak?
+
+ Setiap file lain yang ditulis alat ini benar menurut konstruksinya, yang menjawab dua dari tiga
+ pertanyaan yang diajukan validator unggahan. --damage menjawab yang ketiga - apakah
+ file itu dapat dibuka sama sekali. File dibuat secara normal lalu dirusak, sehingga ukurannya
+ tetap seperti yang Anda minta.
+
+ Pengaturan ditulis setelah titik dua. Opsinya dapat diulang, dan urutan penulisannya adalah urutan
+ penerapannya. tfg damage mendaftar apa yang bisa dilakukan build ini dan apa yang
+ diterima masing-masing.
+
+
Dalam resep, kuncinya adalah daftar, berisi nama atau pengaturan:
+ File yang dirusak mendapat expected: reject di manifes, dengan kerusakan dicatat di
+ sampingnya. Dua hal ditolak sebelum apa pun ditulis, karena masing-masing akan menaruh file di
+ disk yang digambarkan manifes secara keliru:
+
+
+
file yang lebih kecil dari yang dibutuhkan kerusakan, karena akan keluar tanpa perubahan
+
+ expected: accept di samping kerusakan, karena tidak ada yang dapat memenuhinya. Tulis
+ sanitize bila sistem yang diuji dimaksudkan memperbaiki file, atau
+ unspecified bila itulah pertanyaan yang Anda ajukan
+
+
+
+ Yang ketiga tidak dapat diketahui sebelumnya. Bila suatu kerusakan berjalan dan tidak menggeser satu
+ byte pun, file itu dibuang alih-alih ditulis - run berlanjut, menyebut file mana itu, dan
+ berakhir dengan kode keluar parsial.
+
+ Resep adalah file YAML yang menggambarkan satu run utuh. Commit di samping pengujian Anda dan
+ fixture berhenti menjadi biner di repositori Anda - siapa pun dapat membangunnya kembali, byte
+ demi byte, dari file berisi beberapa ratus karakter.
+
+ Setiap target memerlukan tepat satu dari size, size-range,
+ boundary, atau contains. Dua adalah galat dan tidak ada juga galat.
+ Resep yang tidak valid menulis tidak ada file sama sekali dan melaporkan semua
+ masalah sekaligus, bukan hanya yang pertama, masing-masing menyebut pengaturan yang dimaksud.
+
+
+
+
+
Bagaimana menyatakan apa yang harus dilakukan sistem saya terhadap sebuah file?
+
Bentuk pendek bila hasilnya sudah cukup, bentuk panjang bila alasannya penting:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Hasilnya adalah accept, reject, sanitize, dan
+ unspecified. Alasannya adalah daftar tertutup agar laporan dapat mengelompokkan
+ berdasarkan itu: content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit, dan
+ size_zero.
+
+
+ Alasan menyebut aturan yang berlaku, bukan putusannya. Itulah sebabnya alasan yang
+ sama dapat berada di bawah kedua hasil - file satu byte di bawah batas adalah
+ accept, dan aturan yang dimaksud tetap size_limit.
+
+
+
+
+
Apa isi manifes?
+
+ Manifes ditulis di samping file pada akhir setiap run, termasuk run yang terhenti. Satu entri per
+ file:
+
+ recipe_hash ditambahkan bila run berasal dari resep, dan preset dengan
+ overrides bila berasal dari preset, sehingga manifes selalu dapat ditelusuri ke apa
+ yang menghasilkannya.
+
+
+ Setiap entri juga membawa target_id, id target dalam resep yang menghasilkan file, dan
+ summary.by_target menghitung file yang dihasilkan tiap target. Resep dengan
+ beberapa target dapat diperiksa target demi target tanpa membaca nama file.
+
+
+
+
+
Apa itu preset?
+
+ Set file siap pakai yang menjawab pertanyaan pengujian umum, sehingga Anda tidak perlu merancang
+ setnya sendiri. Preset pada dasarnya resep biasa, dan eject mencetak resepnya agar
+ dapat Anda sunting dari sana. Setiap preset memiliki halamannya
+ sendiri berisi apa yang biasanya ditemukan, isi set, dan setiap pengaturan yang diterimanya.
+
+ show memberi tahu berapa biaya set sebelum Anda membuatnya, dan menyatakan terus terang
+ bila sebuah angka adalah nilai sementara dari kami, bukan batas dari Anda.
+
+
+
+
+
Apa arti kode keluar?
+
+ Setiap akhir punya kodenya sendiri, keluaran yang terbaca mesin masuk ke keluaran standar, dan run
+ yang gagal tidak mencetak apa pun di sana. Tabelnya adalah kontrak beku - mengubah arti sebuah
+ kode memerlukan kenaikan versi mayor.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Run yang dihentikan dengan Ctrl+C tetap meninggalkan manifes dan tidak pernah meninggalkan file yang
+ tertulis setengah, sehingga job yang dibatalkan masih dapat dibersihkan oleh yang berikutnya.
+
+ Ada, mesin yang sama dengan jendela di atasnya, untuk pengujian yang tidak diskripkan. Ini bukan
+ versi terpangkas: sebuah pengujian membandingkan kedua antarmuka kemampuan demi kemampuan, dan
+ apa pun yang hanya dapat dilakukan salah satunya harus dinyatakan dan dibenarkan alih-alih
+ diam-diam menyimpang.
+
+
+ Layarnya adalah satu batch, preset, beberapa batch sekaligus, dan tentang. Jendela ini menunjukkan
+ biaya sebuah run sebelum menulis apa pun, melaporkan kemajuan selama berjalan, dan dapat
+ dibatalkan di tengah jalan tanpa meninggalkan file yang tertulis setengah. Jendela ini belum
+ membuka file resep - untuk saat ini resep urusan baris perintah, dan jendela membangun batch-nya
+ di formulir.
+
+
diff --git a/web/content/id/exact-size.html b/web/content/id/exact-size.html
new file mode 100644
index 00000000..b81ddd2a
--- /dev/null
+++ b/web/content/id/exact-size.html
@@ -0,0 +1,147 @@
+
Cara membuat file dengan ukuran tepat
+
+ Setiap sistem punya perintah untuk itu, dan ketiganya ada di bawah. Perintah-perintah itu memberi
+ Anda file dengan jumlah byte yang tepat - dan untuk banyak pengujian itu sudah cukup.
+ Setiap perintah di halaman ini dijalankan sebelum dipublikasikan, di sistem
+ tempat perintah itu berada.
+
+
+
+
Jawaban singkat
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Ukuran dalam byte, dan 10 MB yang
+ dihitung seperti pengelola file Anda menghitung adalah 10485760.
+
+
+
+
+
Windows
+
fsutil, dan versi PowerShell yang tidak memerlukan tambahan apa pun
+
+ fsutil disertakan dengan Windows. Perintah ini menerima ukuran dalam
+ byte, jadi hitung dulu angkanya - 10 MB adalah 10485760, 100 MB adalah 104857600, 1 GB
+ adalah 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Diukur di Windows 11: berjalan dari prompt biasa dan tidak memerlukan prompt dengan hak istimewa,
+ dan file keluar tepat 10485760 byte.
+
+
PowerShell dapat melakukan hal yang sama tanpa memanggil program lain, dan memahami satuan:
+ 10MB di PowerShell berarti 10485760 byte, hitungan berbasis 1024 yang sama dengan yang
+ dipakai Explorer, sehingga kedua perintah di atas menghasilkan ukuran yang sama.
+
+
+
+
+
Linux
+
dd, truncate, dan fallocate, dan perbedaan yang menjebak orang
+
dd adalah yang dikenal semua orang. Perintah ini benar-benar menulis byte:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate instan, dan di situlah jebakannya. Diukur di Alpine Linux, file melaporkan
+ 10485760 byte dan menempati nol blok - ini adalah sparse file.
+ Apa pun yang membacanya mendapat sepuluh megabyte nol, tetapi disk tidak pernah menyerahkan
+ ruangnya:
+
+
truncate -s 10M test10mb.bin
+
+ Itu baik untuk menguji batas unggahan dan menyesatkan untuk menguji kuota disk.
+ fallocate adalah yang dipakai bila ruangnya harus nyata:
+
+
fallocate -l 10M test10mb.bin
+
Dan bila isinya harus tak dapat dikompres, agar pengarsip tidak bisa memadatkannya kembali:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, yang bukan sparse, dan dua yang sudah Anda kenal
+
+ macOS menyertakan mkfile. Diukur di macOS 26.6.2: 10485760 byte dan 20480 blok,
+ sehingga ruangnya benar-benar dialokasikan, bukan dijanjikan:
+
+
mkfile 10m test10mb.bin
+
dd dan truncate juga ada dan berperilaku seperti di Linux:
File dengan ukuran yang benar bukan file dengan jenis yang benar
+
+ Semua di atas memberi Anda blok nol. Itu cukup bila yang diuji hanya melihat ukuran - batas
+ unggahan, kuota, transfer. Itu berhenti cukup begitu ada yang membuka file itu.
+
+
+ Diukur, dan layak Anda coba sendiri: buat file 2 MB dengan fsutil, namai
+ photo.png, dan serahkan ke pustaka gambar. Pillow menjawab cannot identify
+ image file. Itu bukan PNG. Tidak pernah - hanya namanya yang berkata begitu.
+
+
+ Itu lebih penting daripada kedengarannya, karena arah kegagalan pengujian itu
+ kemudian. Endpoint unggah Anda menolak file, pengujian Anda hijau, dan Anda
+ menyimpulkan batas ukuran berfungsi. Endpoint itu tidak menolaknya karena ukuran. Ia menolaknya
+ karena byte-nya bukan gambar, dan aturan yang ingin Anda uji tidak pernah tercapai.
+
+
+
parser menolaknya sebelum aturan ukuran apa pun diperiksa
+
langkah thumbnail gagal dan galat yang Anda baca adalah tentang thumbnail
+
antivirus atau pemeriksaan konten menolaknya karena alasan ketiga
+
penampil tidak menampilkan apa pun, dan tak seorang pun tahu apakah itu bug-nya
+
+
+
+
+
Jalan lainnya
+
File asli dari format itu, dengan ukuran persis seperti yang Anda minta
+
+ Inilah yang dilakukan Testing Files Generator. File itu adalah file asli dari formatnya - terbuka di
+ aplikasi yang memilikinya - dan berjumlah byte persis seperti yang Anda minta, sampai ke byte:
+
+ Minta ukuran yang tidak dapat dicapai suatu format dan Anda mendapat galat yang menyebut batas bawah
+ dan alasannya, tidak pernah file berukuran salah. Halaman format
+ mencantumkan setiap format beserta file terkecil yang dapat dibuatnya.
+
+
Dan sebuah batas adalah tiga kasus uji, bukan satu, jadi alat ini membuat ketiganya:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Itu memberi Anda 10485759, 10485760, dan 10485761 byte, dan manifes yang menyatakan mana yang harus
+ diterima sistem Anda dan mana yang harus ditolak. Halaman kasus
+ penggunaan membahas itu dan empat pekerjaan lain yang untuknya alat ini dibuat.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Jadi mana yang sebaiknya dipakai?
+
+
+
Pakai perintah sistem
+
+ Bila tidak ada yang membuka file. Menguji batas ukuran pada endpoint yang memeriksa ukuran lebih
+ dulu, transfer, kuota, disk penuh. Hanya satu baris dan sudah terpasang.
+
+
+
+
Pakai generator sungguhan
+
+ Bila ada yang mem-parsing, merender, mengimpor, atau mengekstrak file - dan bila Anda memerlukan
+ fixture yang sama besok, di mesin lain, byte demi byte.
+
+
+
+
+ Keduanya ada di halaman ini karena keduanya benar sebagian waktu. Kesalahan yang perlu dihindari
+ adalah memakai yang pertama di tempat yang kedua dibutuhkan dan membaca pengujian hijau sebagai
+ bukti.
+
+
diff --git a/web/content/id/faq.html b/web/content/id/faq.html
new file mode 100644
index 00000000..65aad8cb
--- /dev/null
+++ b/web/content/id/faq.html
@@ -0,0 +1,20 @@
+
Pertanyaan yang sering diajukan
+
+ Lisensi, privasi, reproduksibilitas, dan hal-hal yang diperiksa orang sebelum memasukkan generator
+ ke pipeline build. Bila pertanyaan Anda tidak ada di sini, pelacak
+ isu terbuka.
+
{{ .Facts.FormatCount }} format file, masing-masing dibuat dengan ukuran tepat
+
+ Masing-masing adalah file asli dari format itu. File terbuka di aplikasi yang
+ memilikinya dan persis berjumlah byte yang Anda minta. Tidak ada yang berupa nol pengisi dengan
+ ekstensi yang ditempelkan.
+
+
+{{ template "formatsTable" . }}
+
+
+
Arti kolom-kolom
+
+
+
File terkecil
+
+ Jumlah byte paling sedikit yang akan diterima alat ini untuk format itu, termasuk label yang
+ ditulisnya di dalam file. Minta lebih kecil dan Anda mendapat galat yang menyebut batas
+ bawah dan alasannya, tidak pernah file berukuran salah.
+
+
+
+
Kelengkapan
+
+ Seberapa lengkap file itu. full berarti pembaca yang benar-benar mem-parsing format
+ menerimanya, bukan sekadar ekstensinya cocok.
+
+
+
+
Diperiksa dengan
+
+ Pembaca independen yang membuka setiap file yang dihasilkan sebelum format dirilis - implementasi
+ terpisah, bukan kode kami sendiri yang menilai pekerjaan rumahnya sendiri.
+
+
+
+
+ Setiap format juga berulang sampai ke byte: resep dan seed yang sama menghasilkan file identik di
+ mesin mana pun, dan itulah yang membuat resep aman di-commit menggantikan fixture-nya.
+
+
+
+
+
Pengaturan yang diterima setiap format
+
+ Sebagian besar format punya pengaturan sendiri - dimensi gambar, kualitas JPEG, jumlah halaman PDF,
+ baris dan kolom spreadsheet, berapa banyak entri di dalam arsip. Atur dengan --set
+ key=value di baris perintah, atau di bawah properties: dalam resep.
+
+ Nilai di luar yang diterima suatu pengaturan ditolak dengan pesan yang menyebut pengaturan, rentang
+ yang diizinkan, dan apa yang dipakai sebagai gantinya. Pengaturan yang tidak dikenal juga galat,
+ tidak pernah nilai bawaan diam-diam - salah ketik yang diterima diam-diam menghasilkan file
+ dengan pengaturan yang salah dan satu jam bertanya-tanya mengapa pengujian lolos padahal
+ seharusnya tidak.
+
+
+ Jalankan tfg formats <id> untuk melihat persis apa yang diterima satu format pada
+ build yang Anda miliki.
+
+
+
+
+
Arsip berisi file asli
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} dan {{ end }}{{ $c.ID }}{{ end }}
+ dapat diisi dengan entri alih-alih dibiarkan sebagai cangkang kosong. Arsip yang dihasilkan
+ benar-benar berisi dokumen yang diklaimnya, sehingga apa pun yang mengekstraknya selama
+ pengujian menemukan file asli di dalamnya.
+
+ PDF, PNG, DOCX, ZIP - {{ .Facts.FormatCount }} format seluruhnya, dan setiap file
+ adalah file asli yang terbuka di aplikasi yang memilikinya, dengan ukuran persis seperti
+ yang Anda minta. Setiap run juga mencatat apa yang harus dilakukan aplikasi Anda
+ terhadap tiap file. Baris perintah dan jendela desktop, gratis dan open source, bekerja
+ sepenuhnya di mesin Anda.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ Jendela desktop, siap menulis sekumpulan file. Mesin yang sama berjalan di balik baris perintah.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
format asli, masing-masing terbuka di aplikasi yang memilikinya
+
+
+ 1 byte
+
ketepatan setiap ukuran yang Anda minta, tidak pernah dibulatkan diam-diam
+
+
+ 0
+
koneksi ke mana pun - tanpa akun, tanpa telemetri, tanpa pemeriksaan pembaruan
+
+
+
+
+
Masalahnya
+
Membuat satu file uji itu mudah. Membuat seribu yang tepat adalah bagian yang membosankan
+
Anda menguji perangkat lunak yang menerima file dari orang. Cepat atau lambat Anda memerlukan:
+
+
PDF berukuran tepat 10 MB, untuk mengetahui apakah batas unggahan itu nyata
+
tiga file di kedua sisi batas itu, untuk menangkap kesalahan selisih satu
+
10.000 file log, untuk melihat apa yang dilakukan job malam saat foldernya besar
+
ZIP yang benar-benar berisi 200 dokumen, bukan cangkang kosong dengan ekstensi yang tepat
+
file 4 GB, tanpa menyimpan file 4 GB di repositori Anda
+
fixture yang sama di laptop Anda dan di server build, byte demi byte
+
+
+ Itulah yang digantikan oleh alat ini. Dibuat untuk insinyur QA, otomasi pengujian, dan siapa pun
+ yang kodenya memiliki formulir unggah, rutinitas impor, parser, atau kuota penyimpanan di
+ baliknya.
+
+
+
+
+
Apa yang membuatnya berbeda
+
Generator lain berhenti di byte. Alat ini menjawab apa yang sebenarnya ditanyakan pengujian Anda
+
+ Sebuah folder berisi file masih membuat Anda yang memutuskan apa yang seharusnya dibuktikan tiap
+ file. Setiap run di sini menulis manifest.json di samping file - daftar sederhana
+ semua yang dihasilkan, dan untuk tiap entri sebuah ekspektasi yang dinyatakan.
+
+
Misalkan endpoint unggah Anda mengizinkan 1 MB. Mintalah tiga file yang berada di garis itu:
Bila jawabannya bergantung pada kebijakan Anda sendiri, manifes mengatakannya
+
+ Alat ini mencatat unspecified alih-alih mengarang ekspektasi. Generator yang menebak
+ menghasilkan kegagalan palsu, dan suite yang berteriak serigala akhirnya dimatikan.
+
+
+
+
+
+
Preset
+
Pilih pertanyaannya, dapatkan seluruh setnya
+
+ Preset adalah set file uji yang dirancang di sekitar satu pertanyaan pengujian, sehingga Anda tidak
+ perlu mencari tahu file mana yang membuktikan apa. Masing-masing punya halaman yang menjelaskan
+ apa yang biasanya ditemukan, isi set, dan setiap pengaturan yang diterimanya.
+
+ Sepuluh ribu file log, masing-masing antara satu dan delapan kilobyte, dengan ukuran diundi dari
+ seed sehingga besok menghasilkan set yang sama. Beri setiap run direktorinya
+ sendiri - manifes adalah satu-satunya catatan tentang apa yang ditulis sebuah run,
+ sehingga alat ini menolak menulis manifes kedua di atasnya:
+
+ Ukuran dihitung dalam kelipatan 1024, seperti pengelola file Anda, jadi 2mb berarti
+ 2097152 byte. Jumlah byte biasa juga bisa. Dokumentasi membahas
+ resep, manifes, dan kode keluar.
+
+
+
+
+
Yang Anda dapatkan
+
Dibuat untuk suite yang berjalan tanpa pengawasan
+
+
+
Ukuran tepat, sampai ke byte
+
Minta 10485761 byte dan dapatkan persis itu. Ukuran yang tidak dapat dicapai format adalah galat dengan alasan, tidak pernah file berukuran salah.
+
+
+
{{ .Facts.FormatCount }} format asli
+
Bukan nol pengisi dengan ekstensi. PNG yang dihasilkan terbuka di penampil gambar, DOCX terbuka di Word, ZIP bisa diekstrak. Masing-masing diperiksa dengan pembaca independen sebelum dirilis.
+
+
+
Manifes yang menjadi oracle pengujian
+
Path, ukuran, SHA-256, format, seed, versi alat - dan apa yang harus dilakukan sistem Anda terhadap file itu.
+
+
+
Dapat direproduksi
+
Resep dan seed yang sama, byte yang sama, di mesin mana pun. Commit resep YAML kecil alih-alih fixture biner besar.
+
+
+
Dua antarmuka, satu mesin
+
Baris perintah yang dibuat untuk CI dan jendela desktop untuk pengujian eksploratif. Tidak ada yang merupakan versi terpangkas dari yang lain, dan sebuah pengujian membandingkannya kemampuan demi kemampuan.
+
+
+
Sepenuhnya offline
+
Tanpa akun, tanpa cloud, tanpa telemetri, tanpa pemeriksaan pembaruan. Biner baris perintah sama sekali tidak memiliki stack jaringan yang dikompilasi di dalamnya.
+
+
+
+
+
+
Unduh
+
Pilih build untuk sistem Anda
+
+ Ekstrak arsip dan jalankan. tfg adalah baris perintah dan tfg-gui adalah
+ jendela desktop. Tidak ada installer dan tidak ada yang perlu ditambahkan ke mesin Anda.
+
+ {{ template "downloadsTable" . }}
+
+
Apa yang ditandatangani, dan apa yang tidak
+
+ Unduhan Windows dan macOS ditandatangani, sehingga berjalan tanpa peringatan tentang pengembang tak
+ dikenal. Yang untuk Linux tidak, karena Linux desktop tidak punya padanan untuk
+ menandatanganinya. Setiap arsip tercantum di verify-SHA256SUMS.txt pada halaman
+ rilis, sehingga Anda dapat memeriksa apa yang Anda unduh.
+
+ Preset {{ .ID }} membuat satu set lengkap file uji asli untuk pertanyaan ini dengan
+ satu perintah, dan manifest.json di sampingnya yang menyatakan bagaimana sistem Anda
+ harus bereaksi terhadap tiap file. Semua di bawah dibaca dari program, pada nilai bawaan versi
+ ini.
+
+
+{{ if .Catches }}
+
+
Apa yang biasanya ditemukan?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
Apa isi set?
+
Pada nilai bawaan, seperti yang dilaporkan tfg preset show {{ .ID }}:
+
+
+
+
File
{{ .Budget.Files }}
+
Target dalam resepnya
{{ .Budget.Targets }}
+
Ukuran total
{{ .Bytes }} B
+
Format
{{ join .Budget.Formats ", " }}
+
+
+
+
Dan apa yang diharapkan manifes set itu dari sistem Anda:
+
+
+
+
Diharapkan
Arti
File
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
Apa yang dapat Anda ubah?
+ {{- if .Settings }}
+
+
+
+
Pengaturan
Menerima
Bawaan
Fungsinya
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Nilai bawaan ini adalah nilai sementara dari kami, bukan nilai sistem Anda. Berikan nilai Anda sendiri.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
Preset ini tidak memiliki pengaturan. Setnya sama setiap kali.
+ {{- end }}
+
+
+
+
Bagaimana menjalankannya?
+
Lihat biaya set, buat, atau ambil resepnya untuk disunting:
Atau bangun di atasnya dalam resep Anda sendiri, di samping pengujian Anda:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/id/presets.html b/web/content/id/presets.html
new file mode 100644
index 00000000..463669c5
--- /dev/null
+++ b/web/content/id/presets.html
@@ -0,0 +1,32 @@
+
Preset file uji, satu set untuk setiap pertanyaan pengujian
+
+ Preset adalah satu set lengkap file uji yang dirancang di sekitar satu pertanyaan, dengan manifes
+ yang menyatakan bagaimana sistem Anda harus bereaksi terhadap tiap file. Anda memilih pertanyaan,
+ alat membuat setnya. Setiap preset punya halamannya sendiri berisi apa yang biasanya ditemukan,
+ isi set, dan setiap pengaturan yang diterimanya.
+
+
+{{ template "presetsList" . }}
+
+
+
Apa bedanya preset dengan resep?
+
+ Pada dasarnya tidak ada. Preset adalah resep yang ditulis alat untuk Anda dari beberapa pengaturan.
+ tfg preset eject mencetak resep itu agar dapat Anda simpan di samping pengujian dan
+ sunting, dan resep Anda sendiri dapat dibangun di atas preset dengan satu baris, extends:
+ preset: diikuti id-nya.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Bisakah saya memercayai nilai bawaan?
+
+ Untuk file, ya. Untuk angka yang hanya diketahui sistem Anda, seperti batas formulir unggah, nilai
+ bawaan adalah nilai sementara dari kami, dan alat menyatakannya setiap kali memakainya. Halaman
+ setiap preset menandai pengaturan itu, dan tfg preset show menyatakannya sebelum
+ apa pun ditulis.
+
+
diff --git a/web/content/id/site.json b/web/content/id/site.json
new file mode 100644
index 00000000..261fc605
--- /dev/null
+++ b/web/content/id/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "id",
+ "locale": "id_ID",
+ "name": "Bahasa Indonesia",
+ "dir": "id",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Beranda",
+ "title": "Generator File Uji untuk QA - Ukuran Tepat, {{ .Facts.FormatCount }} Format Asli",
+ "description": "Generator file uji gratis dan open source untuk QA. File PDF, DOCX, PNG, dan ZIP asli berukuran tepat, plus manifes tentang reaksi yang diharapkan dari sistem Anda."
+ },
+ {
+ "key": "formats",
+ "slug": "format",
+ "nav": "Format",
+ "title": "{{ .Facts.FormatCount }} Format File yang Didukung - PDF, DOCX, PNG, ZIP, dan Lainnya",
+ "description": "Semua format file yang dihasilkan, file terkecil yang mungkin untuk tiap format, dan pengaturan yang diterimanya. Semua {{ .Facts.FormatCount }} terbuka di aplikasi aslinya."
+ },
+ {
+ "key": "presets",
+ "slug": "preset",
+ "nav": "Preset",
+ "title": "Preset File Uji - Set Siap Pakai untuk QA",
+ "description": "Set file uji siap pakai, masing-masing menjawab satu pertanyaan pengujian: batas unggahan, nama file, enkoding, impor tabel, file kosong, dan validasi."
+ },
+ {
+ "key": "docs",
+ "slug": "dokumentasi",
+ "nav": "Dokumentasi",
+ "title": "Dokumentasi - Perintah, Resep, Manifes, Kode Keluar",
+ "description": "Cara membuat file uji dari baris perintah atau resep YAML, isi manifes, dan arti setiap kode keluar saat alat ini berjalan di CI."
+ },
+ {
+ "key": "use-cases",
+ "slug": "kasus-penggunaan",
+ "nav": "Kasus Penggunaan",
+ "title": "Kasus Penggunaan - Batas Unggahan, Fixture CI, Pengujian Massal",
+ "description": "Menguji batas ukuran unggahan, membuat fixture yang dapat direproduksi untuk CI, membuat sepuluh ribu file, dan mengisi arsip dengan isi sungguhan."
+ },
+ {
+ "key": "exact-size",
+ "slug": "membuat-file-ukuran-tepat",
+ "nav": "Ukuran Tepat",
+ "title": "Cara Membuat File dengan Ukuran Tertentu - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate, dan mkfile, masing-masing diukur di sistemnya, dan mengapa file yang dibuat begitu bukan PDF atau PNG saat pengujian membutuhkannya."
+ },
+ {
+ "key": "faq",
+ "slug": "faq",
+ "nav": "FAQ",
+ "title": "FAQ - Pertanyaan tentang Membuat File Uji",
+ "description": "Apa bedanya dengan dd dan fsutil, apakah file aman di-commit, apakah hasil run sama byte demi byte, dan apa yang terjadi bila ukuran tak tercapai."
+ },
+ {
+ "key": "damage",
+ "slug": "file-uji-rusak",
+ "nav": "File rusak",
+ "title": "File uji yang rusak - file rusak dengan ukuran tepat",
+ "description": "File yang sengaja dirusak, berukuran tepat, dengan manifes yang menyatakan sistem Anda harus menolaknya. Untuk menguji validasi unggahan dan parser.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "file-uji-di-ci",
+ "nav": "File uji di CI",
+ "title": "File uji di CI - GitHub Actions, GitLab CI, dan PowerShell",
+ "description": "Buat file uji di pipeline alih-alih meng-commit biner: workflow GitHub Actions, job GitLab, kode keluar, dan jebakan PowerShell.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "Lompat ke konten",
+ "navLabel": "Utama",
+ "langLabel": "Bahasa",
+ "breadcrumbHome": "Beranda",
+ "imageAlt": "Testing Files Generator - file uji asli dengan ukuran tepat, beserta manifes yang menyatakan bagaimana sistem Anda harus bereaksi terhadap tiap file",
+ "schemaDescription": "Generator file uji untuk QA yang gratis dan open source. Alat ini membuat file asli dalam {{ .Facts.FormatCount }} format dengan ukuran tepat dan menulis manifes yang menyatakan bagaimana sistem yang diuji harus bereaksi terhadap tiap file.",
+ "ctaDownload": "Unduh",
+ "ctaSource": "Lihat kode sumber",
+ "ctaNote": "Gratis dan open source, GPL-3.0. Tanpa pendaftaran. Unduhan Windows dan macOS sudah ditandatangani dan berjalan tanpa peringatan.",
+ "colFormat": "Format",
+ "colName": "Nama",
+ "colExtension": "Ekstensi",
+ "colSmallest": "File terkecil",
+ "colFidelity": "Kelengkapan",
+ "colChecked": "Diperiksa dengan",
+ "colSetting": "Pengaturan",
+ "colAccepts": "Menerima",
+ "colSystem": "Sistem",
+ "colCli": "Baris perintah",
+ "colWindow": "Jendela desktop",
+ "noBinary": "belum ada biner",
+ "colCode": "Kode",
+ "colMeaning": "Arti",
+ "footerBlurb": "File uji untuk QA dengan ukuran tepat, beserta manifes yang menyatakan bagaimana sistem Anda harus bereaksi terhadap tiap file.",
+ "footerProject": "Proyek",
+ "footerSource": "Kode sumber di GitHub",
+ "footerReleases": "Unduhan",
+ "footerIssues": "Laporkan masalah",
+ "footerSupport": "Dukung proyek ini",
+ "footerPages": "Halaman",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. Dirilis di bawah Lisensi Publik Umum GNU versi 3. File yang Anda buat adalah milik Anda - lisensi mencakup alatnya, bukan keluarannya.",
+ "footerPrivacy": "Situs ini tidak memuat font, skrip, atau pelacak dari mana pun. Situs ini tidak memasang cookie.",
+ "notFoundTitle": "Halaman itu tidak ada di sini",
+ "notFoundLead": "Alamat yang Anda ikuti tidak cocok dengan halaman mana pun di situs ini.",
+ "notFoundBack": "Ke beranda",
+ "read.format": "Format setiap file dalam set. Ini adalah opsi alat itu sendiri, dan preset hanya memberinya nilai bawaan.",
+ "readTakes.format": "id format dari halaman format",
+ "colDamage": "Kerusakan",
+ "colEffect": "Yang dilakukannya pada byte",
+ "colSettings": "Pengaturan",
+ "noSettings": "tidak ada"
+ },
+ "endings": {
+ "0": "Semuanya berjalan.",
+ "1": "Kesalahan tak terduga di dalam alat.",
+ "2": "Perintah atau opsi salah.",
+ "3": "Resep tidak valid.",
+ "4": "Format tidak dapat melakukan yang diminta.",
+ "5": "Pembacaan atau penulisan gagal.",
+ "6": "Ruang disk tidak cukup.",
+ "7": "verify menemukan ketidakcocokan.",
+ "8": "Run selesai tetapi tidak semuanya dihasilkan.",
+ "130": "Dihentikan dengan Ctrl+C.",
+ "143": "Dihentikan oleh sinyal, seperti tampilan batas waktu CI."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "Apakah file valid yang sekecil yang diizinkan format dapat lolos?",
+ "title": "Kosong dan minimal",
+ "pageTitle": "File Uji Valid Terkecil dan Kosong di Setiap Format",
+ "description": "File valid terkecil yang ditulis alat ini di setiap dari {{ .Facts.FormatCount }} formatnya, plus file kosong bila format mengizinkan, masing-masing dengan reaksi yang diharapkan.",
+ "catches": [
+ "file valid yang ditolak karena terlalu kecil, ketika pemeriksaan menghitung byte alih-alih membacanya",
+ "file kosong yang membuat pembaca crash alih-alih dilaporkan",
+ "gambar selebar satu piksel yang membagi dengan nol dalam perjalanan ke thumbnail",
+ "penyimpanan yang membaca nol byte sebagai unggahan gagal dan terus mencoba ulang"
+ ],
+ "details": {
+ "formats": "Dari format apa set dibuat. Biarkan all untuk setiap format build ini, atau sebutkan format yang diterima sistem Anda."
+ }
+ },
+ "filename-handling": {
+ "question": "Apakah sistem saya akan menyimpan, menampilkan, dan mengembalikan nama file yang tidak diduganya?",
+ "title": "Penanganan nama file",
+ "pageTitle": "Nama File Bermasalah untuk Pengujian - Unicode dan Panjang",
+ "description": "File dengan nama yang merusak unggahan dan penyimpanan: aksara lain dan emoji, pembalikan arah tulisan, karakter tak terlihat, sintaks shell dan SQL, batas panjang.",
+ "catches": [
+ "nama yang tampak seperti nama lain di layar, di log, atau dalam daftar",
+ "nama yang dipotong, dipangkas, atau ditulis ulang antara unggahan dan penyimpanan",
+ "batas panjang yang dihitung dalam karakter padahal penyimpanan menghitung byte"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "Apakah batas ukuran ditegakkan tepat di tempat batas itu dinyatakan?",
+ "title": "Batas ukuran",
+ "pageTitle": "Menguji Batas Ukuran Unggahan - File di Batas Tepat",
+ "description": "File satu byte di bawah, tepat di, dan satu byte di atas batas ukuran sistem Anda, plus langkah lebih lebar di kedua sisi, masing-masing ditandai apakah harus diterima.",
+ "catches": [
+ "kesalahan selisih satu di batas",
+ "MB tertukar dengan MiB, yaitu 4,8 persen dan cukup untuk meloloskan file yang seharusnya tidak lolos",
+ "batas yang ditegakkan di browser dan tidak di server"
+ ],
+ "details": {
+ "limit": "Batas ukuran yang dinyatakan sistem Anda. Semua yang lain diukur dari sini.",
+ "spread": "Seberapa jauh menjangkau di kedua sisi batas, sebagai daftar ukuran."
+ }
+ },
+ "tabular-import": {
+ "question": "Apakah impor tabel saya tahan terhadap apa yang diekspor alat sungguhan?",
+ "title": "Impor tabel",
+ "pageTitle": "File Uji Impor CSV dan Excel - Pemisah, Header",
+ "description": "CSV dengan pemisah lain, akhir baris CR LF, tanpa header, dan kutipan lain, tabel yang sangat lebar, buku kerja Excel, dan JSON dalam beberapa tata letak.",
+ "catches": [
+ "file titik koma yang terbaca sebagai satu kolom, karena pemisah diasumsikan alih-alih dicari",
+ "file CRLF yang terpecah menjadi baris dengan baris kosong setelah masing-masing",
+ "tabel tanpa header yang baris data pertamanya termakan sebagai nama kolom",
+ "impor yang mempertahankan kolom yang bisa ditampilkan dan membuang sisanya tanpa kata",
+ "pembaca yang mengambil record JSON satu baris sekaligus dan berhenti di dokumen berindentasi pertama"
+ ],
+ "details": {
+ "rows": "Berapa banyak baris yang dimuat spreadsheet. File ditulis tepat pada ukuran sebanyak itu baris, sehingga anggaran di atas bergeser mengikuti nilai ini.",
+ "columns": "Berapa banyak kolom di setiap baris spreadsheet. Baris kali kolom memiliki batas atas, dan meminta melebihinya ditolak sebelum apa pun ditulis."
+ }
+ },
+ "text-encoding": {
+ "question": "Apakah pembaca saya tahu enkoding suatu file, atau hanya menebak?",
+ "title": "Enkoding teks",
+ "pageTitle": "File Uji Enkoding Teks - UTF-8, UTF-16, BOM, CRLF",
+ "description": "Teks yang sama dalam UTF-8, UTF-16LE, dan UTF-16BE, dengan dan tanpa byte order mark, serta akhir baris CR LF dan LF, untuk menguji cara pembaca mendekode teks.",
+ "catches": [
+ "pembaca yang mengasumsikan UTF-8 dan menampilkan file UTF-16 sebagai satu karakter dari tiga, atau sebagai deretan kotak",
+ "byte order mark terbaca sebagai isi, sehingga kolom pertama impor dimulai dengan tiga karakter asing",
+ "importer yang menebak enkoding dari byte pembuka dan menebak berbeda untuk file yang lebih panjang",
+ "file CRLF yang terpecah menjadi baris dengan baris kosong setelah masing-masing, atau carriage return yang tertinggal di kolom terakhir"
+ ],
+ "details": {
+ "sample": "Seberapa besar setiap file dalam set. UTF-16 menyimpan dua byte untuk setiap karakter, sehingga angka ganjil ditolak."
+ }
+ },
+ "upload-validation": {
+ "question": "Apakah formulir unggah saya menerima yang seharusnya dan menolak sisanya?",
+ "title": "Validasi unggahan",
+ "pageTitle": "File Uji Validasi Unggahan - Tipe, Ukuran, dan Nama",
+ "description": "File untuk menguji formulir unggah: tipe yang diizinkan dan ditolak, isi yang tidak cocok dengan ekstensi, batas ukuran, nama berbahaya, dan unggahan massal.",
+ "catches": [
+ "batas yang ditegakkan di browser dan tidak di server",
+ "file SVG atau HTML yang dikira gambar atau teks biasa, yang merupakan cara meloloskan skrip lewat formulir",
+ "file yang diperiksa dari ekstensinya dan tak pernah dibuka, sehingga PDF bernama .jpg lolos",
+ "formulir yang membaca seluruh isi ke memori sebelum melihat seberapa besar isinya",
+ "unggahan bernama PHOTO.JPG yang ditolak sementara photo.jpg diterima, atau sebaliknya",
+ "nama dengan spasi, tanda kurung, atau karakter di luar ASCII yang ditulis ke disk tanpa perubahan"
+ ],
+ "details": {
+ "limit": "Batas ukuran yang dinyatakan formulir unggah Anda. Set ini mengambil satu langkah di tiap sisinya - untuk file di setiap jarak, jalankan preset size-boundaries.",
+ "allow": "Tipe apa yang seharusnya diterima formulir Anda. Masing-masing menjadi file asli bertipe itu, dan menjadi kontrol positif bagi seluruh set.",
+ "deny": "Ekstensi apa yang seharusnya ditolak formulir Anda. Ekstensi yang tidak punya format di build ini tetap mendapat file bernama itu, berisi teks biasa.",
+ "far-over": "Seberapa jauh di atas batas file besar tunggal itu. Matikan bila menulis beberapa kali batas tidak sepadan dengan disknya.",
+ "bulk": "Berapa banyak file dalam unggahan massal. Nol membuang kelompok itu dari set sepenuhnya."
+ }
+ }
+ },
+ "commands": {
+ "generate": "menghasilkan file, dari resep atau dari opsi",
+ "validate": "memeriksa resep tanpa menulis apa pun",
+ "verify": "memeriksa direktori terhadap manifes",
+ "cleanup": "menghapus file yang tercantum dalam manifes",
+ "recipe fmt": "mencetak resep dalam bentuk bakunya",
+ "preset": "membuat set file dari pertanyaan pengujian bernama",
+ "formats": "mendaftar format yang didukung build ini",
+ "damage": "mendaftar cara build ini dapat merusak file dengan sengaja",
+ "tool": "alat kecil untuk file yang sudah Anda miliki",
+ "version": "mencetak versi alat",
+ "license": "mencetak lisensi dan artinya bagi file yang dihasilkan"
+ },
+ "outcomes": {
+ "accept": "Sistem Anda harus menerima file ini.",
+ "reject": "Sistem Anda harus menolak file ini.",
+ "sanitize": "Sistem Anda harus menerima file ini dan membersihkannya, misalnya dengan mengganti namanya.",
+ "unspecified": "Tergantung pada aturan sistem Anda. Anda yang memutuskan, lalu memeriksa apakah yang terjadi sesuai maksud Anda."
+ },
+ "damages": {
+ "zero-head": "Menimpa byte pertama file dengan nol tanpa mengubah panjangnya. Sebagian besar pembaca melihat ke sana lebih dulu, jadi hampir semua hal menyadari kerusakan ini."
+ },
+ "terms": {
+ "oracleNone": "tidak berlaku",
+ "int": "bilangan bulat apa pun",
+ "choice": "salah satu dari himpunan tetap",
+ "bool": "benar atau salah",
+ "size": "ukuran seperti 2mb",
+ "text": "teks",
+ "pixels": "piksel",
+ "paragraphs": "paragraf",
+ "rows": "baris",
+ "columns": "kolom",
+ "slides": "slide",
+ "hertz": "hertz",
+ "megapixels": "megapiksel",
+ "million cells": "juta sel",
+ "entries per second": "entri per detik",
+ "files": "file",
+ "sizes separated by commas": "ukuran dipisahkan koma",
+ "format ids separated by commas": "id format dipisahkan koma",
+ "format ids separated by commas, or all": "id format dipisahkan koma, atau all",
+ "extensions separated by commas": "ekstensi dipisahkan koma",
+ "the id of a format, as tfg formats lists them": "id sebuah format, seperti yang didaftar tfg formats",
+ "the password, in plain text": "kata sandi, dalam teks biasa",
+ "any text": "teks apa pun",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "tanggal seperti 2024-02-29 atau 2024-02-29T13:45:00+02:00, atau none"
+ },
+ "faq": [
+ {
+ "q": "Apa bedanya dengan dd, fsutil, atau truncate?",
+ "a": "Perintah itu memberi Anda file berukuran benar yang berisi kekosongan. File 2 MB bernama photo.png yang dibuat begitu bukanlah PNG, sehingga apa pun yang benar-benar mem-parsing-nya akan menolaknya karena alasan yang salah, dan pengujian Anda pun lolos karena alasan yang salah juga. Alat ini menghasilkan PNG asli berukuran tepat 2 MB yang terbuka di penampil gambar, dan disertai pernyataan tentang bagaimana sistem Anda harus memperlakukannya.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "Apakah gratis, dan bisakah saya pakai di tempat kerja?",
+ "a": "Ya untuk keduanya. Dirilis di bawah GPL-3.0 dan tidak berbayar. Tidak ada akun, kunci lisensi, atau tingkat berbayar."
+ },
+ {
+ "q": "Bisakah saya memakai file yang dihasilkan dalam produk closed source?",
+ "a": "Bisa. Lisensi mencakup kode alatnya, bukan apa yang dihasilkan alat itu. File, resep, dan manifes yang dihasilkan adalah keluaran, bukan karya turunan, sehingga Anda dapat meng-commit dan mendistribusikannya tanpa kewajiban apa pun."
+ },
+ {
+ "q": "Apakah file yang dihasilkan berisi data pribadi sungguhan?",
+ "a": "Tidak. Semua isinya disintesis dari sebuah seed. Tidak ada dataset yang dibaca, tidak ada layanan yang dihubungi, dan tidak ada konten pihak ketiga yang disematkan. Perlakukan alamat e-mail yang dihasilkan sebagai tidak dapat dipakai, bukan sekadar belum dipakai, karena string acak apa pun bisa kebetulan sama dengan alamat sungguhan."
+ },
+ {
+ "q": "Apakah saya akan mendapat file yang persis sama di mesin lain?",
+ "a": "Ya, byte demi byte, dengan resep dan seed yang sama. Proyek ini mengujinya pada setiap perubahan, dan melanggarnya memerlukan kenaikan versi mayor. Itulah yang memungkinkan Anda meng-commit resep kecil alih-alih fixture biner besar."
+ },
+ {
+ "q": "Apakah memerlukan koneksi internet?",
+ "a": "Tidak pernah. Tidak ada telemetri, pemeriksaan pembaruan, atau klien cloud, dan biner baris perintah sama sekali tidak memiliki stack jaringan yang dikompilasi di dalamnya. Alat ini berjalan di mesin tanpa jaringan dan di lingkungan korporat yang tertutup."
+ },
+ {
+ "q": "Apa yang terjadi bila saya meminta ukuran yang tidak dapat dicapai suatu format?",
+ "a": "Anda mendapat galat yang menyebut format, ukuran terkecilnya, alasan batas bawah itu, dan apa yang harus dilakukan sebagai gantinya, dan tidak ada file yang ditulis. Alat ini tidak pernah membulatkan ukuran secara diam-diam. Setiap batas bawah tercantum di halaman format.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "Bisakah saya membuat file yang sengaja dirusak?",
+ "a": "Ya. Tambahkan --damage zero-head dan file keluar dengan ukuran tepat seperti yang diminta, dengan byte pertamanya ditimpa nol, sehingga pembaca menolaknya, dan manifes menyatakan sistem Anda harus menolaknya. Rinciannya ada di halaman tentang file uji yang rusak.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "Format apa yang akan hadir berikutnya?",
+ "a": "7z, mp3, dan mp4. Saat ini {{ .Facts.FormatCount }} format bekerja dari ujung ke ujung."
+ },
+ {
+ "q": "Di sistem apa saya bisa menjalankannya?",
+ "a": "Baris perintah berjalan di Windows dan Linux pada Intel maupun ARM, dan di Mac Apple Silicon. Jendela desktop disediakan untuk Windows di Intel, Linux di Intel, dan Mac Apple Silicon. Mac Intel tidak didukung dan tidak ada build untuknya."
+ },
+ {
+ "q": "Apakah saya harus menginstal sesuatu?",
+ "a": "Tidak. Unduh arsip untuk sistem Anda, ekstrak, dan jalankan binernya. Tidak ada installer, tidak ada runtime yang harus ditambahkan, dan tidak ada dependensi yang harus diselesaikan. Bila Anda punya Go, satu perintah go install juga bisa.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "Mengapa run atas ribuan file lebih lambat di Windows?",
+ "a": "Karena Windows membebankan lebih banyak untuk setiap path yang diperiksanya, dan perintah yang menelusuri ribuan file memeriksa ribuan path. Diukur di satu mesin dengan 3000 file berukuran 1 kB, verify memakan sekitar 0,9 detik di Windows dan sekitar 0,2 detik di Linux dalam container. Path keluaran yang lebih pendek memperkecil angka Windows, karena setiap folder di atas file ikut diperiksa."
+ }
+ ]
+}
diff --git a/web/content/id/use-cases.html b/web/content/id/use-cases.html
new file mode 100644
index 00000000..23879563
--- /dev/null
+++ b/web/content/id/use-cases.html
@@ -0,0 +1,132 @@
+
Untuk apa orang memakainya
+
+ Lima pekerjaan yang muncul di hampir setiap proyek yang menerima file dari orang, dan perintah yang
+ melakukan masing-masing. Setiap contoh di bawah berjalan sebagaimana tertulis.
+
+
+
+
Batas unggahan
+
Menguji apakah batas ukuran file ditegakkan di tempat yang dinyatakan
+
+ Sebuah batas adalah tiga kasus uji, bukan satu: tepat di bawah, tepat pada, dan tepat di atas.
+ Mendapatkannya secara manual berarti menghitung jumlah byte dan berharap tidak salah selisih
+ satu. Mintalah setnya:
+
+ Anda mendapat tiga PDF asli berukuran 1048575, 1048576, dan 1048577 byte, serta manifes yang
+ menyatakan dua yang pertama harus diterima dan yang ketiga ditolak karena
+ size_limit. Pengujian Anda membaca ekspektasi alih-alih Anda menulis tiga asersi
+ secara manual - dan bila batas berubah, Anda mengganti satu angka dan menjalankan ulang.
+
+
+ Hal yang sama berfungsi tanpa preset bila Anda menginginkan satu set batas inline:
+
Menjaga fixture di luar repositori tanpa kehilangannya
+
+ Fixture biner besar membuat repositori lambat di-clone dan sulit di-review, dan tak seorang pun tahu
+ apa yang berubah saat satu diganti. Resep adalah beberapa ratus karakter YAML yang membangun
+ ulang file identik - byte demi byte, di mesin mana pun - karena setiap file
+ diturunkan dari seed run.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Setiap akhir punya kode keluarnya sendiri, sehingga pipeline dapat membedakan resep yang buruk dari
+ disk penuh dan dari ketidakcocokan verifikasi. Run yang gagal tidak mencetak apa pun di keluaran
+ standar, sehingga parser log tidak membaca galat sebagai data.
+
+
+
+
+
Skala
+
Mencari tahu apa yang terjadi saat folder besar
+
+ Rutinitas impor, job malam, dan daftar direktori berperilaku berbeda pada sepuluh ribu file
+ dibanding sepuluh. Ukuran yang diundi dari suatu rentang membuat set tampak seperti lalu lintas
+ nyata alih-alih sepuluh ribu file identik, dan undiannya berasal dari seed, sehingga set itu
+ sama besok.
+
+ Run yang lebih besar dari ruang kosong di disk ditolak sebelum byte pertama ditulis, alih-alih
+ memenuhi disk dan gagal di tengah jalan.
+
+
+
+
+
Arsip
+
Menguji pengekstrak dengan arsip yang benar-benar berisi file
+
+ Arsip kosong dengan ekstensi yang tepat tidak membuktikan apa pun tentang kode yang membukanya dan
+ menelusuri isinya. Nyatakan isinya dan arsip benar-benar memuatnya:
+
+ Kedalaman bersarang, jumlah entri, dan ukuran isinya adalah hal-hal yang dipersoalkan rutinitas
+ impor, dan begitulah cara Anda mengetahui apa persoalan itu.
+
+
+
+
+
Parser dan penampil
+
Memeriksa bahwa kode Anda sendiri membaca format seperti perangkat lunak sungguhan
+
+ Setiap format di sini diperiksa dengan pembaca independen sebelum dirilis - PNG dibuka dan pikselnya
+ dibandingkan, DOCX dibaca kembali oleh pustaka terpisah, arsip diekstrak. Artinya file yang
+ ditolak parser Anda adalah temuan tentang parser Anda, bukan tentang generator.
+
+ Halaman format mencantumkan pengaturan yang diterima tiap format dan file
+ terkecil yang dapat dibuat tiap format.
+
+
+
+
+
Panduan
+
Dua di antaranya lebih rinci
+
+
+ File uji yang rusak - file yang sengaja dirusak, berukuran tepat,
+ dengan apa yang harus terjadi padanya tertulis di manifes.
+
+
+ File uji di CI - workflow GitHub Actions, job GitLab, dan kode
+ keluar yang menggagalkan build.
+
+
+
+
+
+
Untuk siapa ini
+
+ Insinyur QA, otomasi pengujian, dan siapa pun yang kodenya memiliki formulir unggah, rutinitas
+ impor, parser, atau kuota penyimpanan di baliknya. Berjalan di mesin tanpa jaringan sama sekali,
+ yang penting di lingkungan korporat tertutup di mana generator berbasis browser bukan pilihan.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/it/ci.html b/web/content/it/ci.html
new file mode 100644
index 00000000..4e064233
--- /dev/null
+++ b/web/content/it/ci.html
@@ -0,0 +1,192 @@
+{{ with .Up }}
+ Una fixture binaria in un repository resta per sempre nella sua cronologia, non si può rivedere in
+ un diff e diventa impossibile quando il file è grande. Genera invece i file dentro la pipeline a
+ partire da una ricetta. La ricetta è testo, i byte escono uguali ogni volta e un ultimo passo
+ dimostra che nulla si è mosso.
+
+
+
+
La risposta breve
+
+ Installa tfg, esegui tfg generate fixtures.yaml --out ./fixtures prima dei
+ test e tfg verify ./fixtures/manifest.json dopo. Entrambi i passi fanno fallire la
+ build da soli, con un codice di uscita che dice perché.
+
+
+
+
+
Perché non committarli
+
Perché una fixture non deve stare nel repository
+
+
+ Resta nella cronologia. Cancellare un binario in seguito non rende più piccolo un
+ clone, perché ogni sua versione è ancora lì.
+
+
+ Un diff non mostra cosa è cambiato. Chi rivede vede che un PDF è diverso e
+ nient'altro. Una ricetta cambia di una riga.
+
+
+ I file grandi non ci stanno. GitHub rifiuta un push che contiene un file sopra i
+ 100 MB, quindi un test di un limite di upload di 500 MB non ha nulla da committare.
+
+
+
+ Quello da committare è la ricetta. La stessa ricetta con lo stesso seme scrive gli stessi byte su
+ ogni macchina, quindi il file generato nella pipeline è il file che avevi sul portatile.
+
+
+
+
+
La ricetta
+
Una ricetta che vive accanto ai test
+
+ Questa scrive venticinque fatture che devono essere accettate e due immagini oltre un limite che
+ devono essere rifiutate, e il manifest registra entrambe le aspettative:
+
+ La riga della somma di controllo confronta l'archivio con verify-SHA256SUMS.txt della
+ stessa versione. La versione è fissata, quindi una nuova versione non cambia mai una build che
+ non hai toccato.
+
+ Ogni conclusione ha il suo codice di uscita, quindi il passo fallisce da solo e il log dice quale.
+ Quelli che incontra una pipeline:
+
+
+
3 - la ricetta non è valida. Non è stato scritto nulla e ogni problema è nominato
+
4 - il formato non può fare ciò che è stato chiesto, per esempio una dimensione sotto il suo minimo
+
6 - non c'è abbastanza spazio su disco
+
7 - tfg verify ha trovato un file che non corrisponde al suo manifest
+
8 - l'esecuzione è finita, ma non tutto è stato prodotto
+
+
+ Un'esecuzione fallita non stampa nulla sullo standard output, così un parser di log non scambia mai
+ un errore per dati. La tabella completa è nella pagina della
+ documentazione.
+
+
+
+
+
PowerShell
+
Uno script PowerShell richiede una riga in più
+
+ PowerShell non porta fuori da un file .ps1 il codice di uscita di un programma.
+ Eseguine uno con -File e lo script risponde 0 anche quando lo
+ strumento al suo interno ha rifiutato il lavoro, così una build che dovrebbe essere rossa
+ diventa verde. L'ultima riga è tutta la correzione:
+
+ È così che si comporta PowerShell, non qualcosa di questo strumento. cmd,
+ bash e zsh non richiedono nulla di più.
+
+
+
+
+
Più job
+
Condividere le fixture tra i job
+
+ Di solito non serve caricarle. Poiché la stessa ricetta scrive gli stessi byte, ogni job può
+ eseguire il proprio tfg generate, che è più rapido di un upload e di un download.
+ Quando un job deve ricevere file da un altro, esegui tfg verify sul manifest dopo
+ il trasferimento, e ti dice se ciò che è arrivato è ciò che è stato scritto.
+
+ Un validatore a cui sono stati mostrati solo file sani non è stato davvero testato. Ecco come
+ ottenere un file rotto di proposito, che esce con esattamente la dimensione
+ richiesta e porta un manifest che dice cosa il tuo sistema deve farne.
+
+
+
+
La risposta breve
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out scrive un PNG di
+ esattamente 2097152 byte i cui primi byte sono zeri, e il manifest accanto registra che il tuo
+ sistema deve rifiutarlo.
+
+
+
+
+
Il modo solito
+
Perché un file corrotto a mano è un cattivo test
+
+ I modi soliti sono un editor esadecimale, uno script che cambia qualche byte a caso o un file
+ accorciato con head o truncate. Funzionano una volta, poi costano:
+
+
+
+ È diverso ogni volta. Un byte casuale cade in un punto nuovo a ogni esecuzione,
+ quindi un errore del martedì può non ripresentarsi il mercoledì.
+
+
+ Cambia la dimensione. Un file tagliato è più piccolo del limite sotto cui doveva
+ stare, quindi il controllo della dimensione risponde prima di quello del contenuto e il test
+ passa per il motivo sbagliato.
+
+
+ Spesso passa inosservato. Il testo semplice si legge ancora con un byte cambiato
+ nel mezzo, e un lettore di immagini indulgente lo disegna e basta, così il file che doveva
+ essere rotto viene accettato.
+
+
+ Non dice nulla su cosa deve succedere. Il file è solo byte, e chi legge il test
+ dopo deve indovinare se si voleva l'accettazione o il rifiuto.
+
+
+
+
+
+
Cosa ottieni
+
Un file danneggiato ha ancora la dimensione richiesta
+
+ Il file viene generato normalmente e rotto dopo, mentre va verso il disco. Mantiene la dimensione
+ richiesta, e lo stesso comando riscrive gli stessi byte.
+
+ Le impostazioni vanno dopo i due punti. L'opzione si può ripetere, e i danni vengono applicati
+ nell'ordine in cui li scrivi. Funziona con ognuno dei {{ .Facts.FormatCount }} formati.
+
+
+
+
+
Cosa sa fare
+
Quali danni ci sono?
+
+ Questa è la lista che il programma stampa, letta da lui quando si costruisce questa pagina.
+ tfg damage stampa la stessa, e tfg damage <id> dice cosa accetta
+ ciascuno.
+
+ {{ template "damagesTable" . }}
+
+ zero-head scrive zeri sull'inizio del file. La maggior parte dei lettori guarda prima
+ lì, la firma e l'intestazione che dicono cos'è il file, quindi quasi ogni lettore se ne accorge.
+ Il testo semplice e i log non hanno firma e vengono rifiutati lo stesso, perché una serie di
+ byte nulli non è testo. Sotto i quattro byte alcuni formati escono con un danno di cui nessun
+ lettore si lamenta, ed è per questo che l'impostazione parte da quattro.
+
+
+
+
+
Cosa dice il manifest
+
Un manifest che dice cosa deve succedere
+
+ Ogni file danneggiato riceve una voce che dice che il tuo sistema deve rifiutarlo, con il danno
+ registrato accanto:
+
+ Due richieste vengono rifiutate prima che venga scritto qualcosa, perché ciascuna lascerebbe su
+ disco un file che il manifest descrive male:
+
+
+
un file più piccolo di quanto serve al danno, che uscirebbe intatto
+
+ expected: accept accanto a un danno, perché nulla potrebbe soddisfarlo. Scrivi
+ sanitize se il tuo sistema deve riparare il file, oppure unspecified
+ se è proprio questa la domanda che poni
+
+
+
+
+
+
In una ricetta
+
File sani e rotti in una sola esecuzione
+
+ Metti entrambi in una ricetta, e il manifest porta l'aspettativa di ogni file, così il test non ha
+ bisogno di un elenco di quale sia quale:
+
+ Il test legge il manifest e controlla che ciò che è successo sia ciò che era stato dichiarato. Non
+ ha bisogno di un elenco di nomi di file:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Un buon rifiuto è un rifiuto pulito. Un messaggio che dice cosa non andava è la risposta che vuoi.
+ Un errore del server, un blocco o un file salvato a metà è il difetto che questo test esiste per
+ trovare.
+
+
+
+
+
Avanti
+
Dove andare da qui
+
+
+ Il preset upload-validation pone a un modulo le altre
+ due domande, quella sulla dimensione e quella sul tipo.
+
+
+ File di test in CI esegue in una pipeline una ricetta come
+ questa.
+
+
diff --git a/web/content/it/docs.html b/web/content/it/docs.html
new file mode 100644
index 00000000..3c1d298f
--- /dev/null
+++ b/web/content/it/docs.html
@@ -0,0 +1,281 @@
+
Documentazione
+
+ Tutto ciò che fa lo strumento, organizzato come le domande con cui le persone arrivano davvero. Il
+ README nel repository è il riferimento completo e corrisponde
+ sempre alla build che hai scaricato.
+
+
+
+
Quali comandi esistono?
+
Ognuno fa una cosa sola:
+ {{ template "commandList" . }}
+
+
+
+
Come genero un singolo file di dimensione esatta?
+
+ Indica il formato, la dimensione e la destinazione. Le dimensioni si contano a 1024, quindi
+ 2mb sono 2097152 byte. Funziona anche un semplice numero di byte, quindi
+ --size 10485761 chiede esattamente quel numero.
+
+
tfg generate --format png --size 2mb --out ./out
+
Le opzioni utili di generate:
+
+
+
Opzione
Cosa fa
+
+
--format <id>
formato dei file, per esempio txt
+
--size <size>
dimensione esatta di ogni file, come 10mb o un semplice numero di byte
+
--size-range <a-b>
una dimensione estratta per file da un intervallo, come 1kb-8kb. L'estrazione viene dal seed
+
--boundary <size>
tre file attorno a un limite: un byte sotto, il limite, un byte sopra
+
--count <n>
quanti file produrre. Predefinito 1
+
--name <template>
modello del nome, per esempio invoice_{index:04}.txt
+
--out <dir>
directory in cui scrivere
+
--seed <n>
seed dell'esecuzione. Lo stesso seed dà gli stessi byte
+
--set <k>=<v>
un'impostazione di formato, ripetibile
+
--damage <name>
rompere i file di proposito, ripetibile e applicato in ordine. Esegui tfg damage per l'elenco
+
--expected <outcome>
accept, reject, sanitize oppure unspecified
+
--dry-run
contare e mostrare, senza scrivere assolutamente nulla
+
--json
scrivere il manifest sullo standard output
+
+
+
+
+
+
+
Come faccio un file rotto di proposito?
+
+ Ogni altro file che questo strumento scrive è corretto per costruzione, il che risponde a due delle
+ tre domande che pone un validatore di upload. --damage risponde alla terza - il
+ file si apre, almeno. Il file viene prodotto normalmente e poi rotto, quindi ha ancora la
+ dimensione che hai chiesto.
+
+ Le impostazioni vanno dopo i due punti. L'opzione si ripete, e l'ordine in cui le scrivi è l'ordine
+ in cui vengono applicate. tfg damage elenca cosa può fare questa versione e cosa
+ accetta ciascuno.
+
+
In una ricetta la chiave è un elenco, di nomi o di impostazioni:
+ Un file danneggiato riceve expected: reject nel manifest, con il danno registrato
+ accanto. Due cose vengono rifiutate prima di scrivere qualsiasi cosa, perché ciascuna metterebbe
+ su disco un file che il manifest descrive in modo sbagliato:
+
+
+
un file più piccolo di quanto serve al danno, perché uscirebbe invariato
+
+ expected: accept accanto a un danno, perché nulla potrebbe soddisfarlo. Scrivi
+ sanitize se il sistema sotto test deve riparare il file, oppure
+ unspecified se è proprio la domanda che stai ponendo
+
+
+
+ Una terza non si può sapere in anticipo. Se un danno viene eseguito e non sposta alcun byte, quel
+ file viene scartato invece di essere scritto - l'esecuzione prosegue, dice di quale file si
+ trattava e termina con il codice di uscita parziale.
+
+ Una ricetta è un file YAML che descrive un'intera esecuzione. Committala accanto ai tuoi test e le
+ fixture smettono di essere binari nel tuo repository - chiunque può ricostruirle, byte per byte,
+ da un file di poche centinaia di caratteri.
+
+ Ogni target richiede esattamente una di queste chiavi: size, size-range,
+ boundary o contains. Due è un errore, e anche nessuna. Una ricetta non
+ valida scrive nessun file e segnala tutti i problemi insieme invece del solo
+ primo, ognuno con il nome dell'impostazione a cui si riferisce.
+
+
+
+
+
Come dichiaro cosa deve fare il mio sistema con un file?
+
Forma breve quando basta l'esito, forma lunga quando conta il motivo:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Gli esiti sono accept, reject, sanitize e
+ unspecified. I motivi sono un elenco chiuso così un report può raggrupparli:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit e size_zero.
+
+
+ Un motivo nomina la regola in gioco, non il verdetto. Ecco perché lo stesso motivo
+ può stare sotto l'uno o l'altro esito - un file un byte sotto un limite è accept, e
+ la regola in questione resta size_limit.
+
+
+
+
+
Cosa c'è nel manifest?
+
+ Viene scritto accanto ai file alla fine di ogni esecuzione, compresa un'esecuzione interrotta. Una
+ voce per file:
+
+ Un recipe_hash viene aggiunto quando l'esecuzione viene da una ricetta, e
+ preset con overrides quando viene da un preset, così un manifest si
+ può sempre ricondurre a ciò che lo ha prodotto.
+
+
+ Ogni voce porta anche target_id, l'id del target della ricetta che ha prodotto il file,
+ e summary.by_target conta i file a cui è arrivato ciascun target. Una ricetta con
+ più target si può quindi controllare target per target senza leggere i nomi dei file.
+
+
+
+
+
Cos'è un preset?
+
+ Un set di file pronto che risponde a una domanda di test comune, così non devi progettare il set tu.
+ I preset sono ricette ordinarie sotto il cofano, e eject stampa la ricetta così
+ puoi modificarla da lì. Ogni preset ha una pagina tutta sua con cosa
+ trova di solito, cosa c'è nel set e ogni impostazione che accetta.
+
+ show ti dice quanto costerebbe il set prima di costruirlo, e dice apertamente quando un
+ numero è un segnaposto nostro anziché un limite tuo.
+
+
+
+
+
Cosa significano i codici di uscita?
+
+ Ogni conclusione ha il suo codice, l'output leggibile da macchina va sullo standard output, e
+ un'esecuzione fallita non vi stampa nulla. La tabella è un contratto congelato - cambiare il
+ significato di un codice richiede una versione maggiore.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Un'esecuzione fermata con Ctrl+C lascia comunque un manifest e non lascia mai un file scritto a
+ metà, così un job annullato può ancora essere ripulito dal successivo.
+
+ Sì, lo stesso motore con una finestra sopra, per il test che non è automatizzato. Non è una versione
+ ridotta: un test confronta le due interfacce capacità per capacità, e tutto ciò che può fare
+ solo una delle due va dichiarato e giustificato invece di divergere in silenzio.
+
+
+ Le schermate sono un lotto, i preset, più lotti insieme e Informazioni. Mostra quanto costerebbe
+ un'esecuzione prima di scrivere qualsiasi cosa, riporta l'avanzamento mentre gira e si può
+ annullare a metà senza lasciare un file scritto a metà. Non apre ancora un file di ricetta - per
+ ora le ricette sono una faccenda da riga di comando, e la finestra costruisce i suoi lotti nel
+ modulo.
+
+
diff --git a/web/content/it/exact-size.html b/web/content/it/exact-size.html
new file mode 100644
index 00000000..cea4e4d5
--- /dev/null
+++ b/web/content/it/exact-size.html
@@ -0,0 +1,145 @@
+
Come creare un file di dimensione esatta
+
+ Ogni sistema ha un comando per farlo, e tutti e tre sono qui sotto. Ti danno un file con esattamente
+ il numero giusto di byte - e per molti test è tutto ciò che serve. Ogni comando di questa
+ pagina è stato eseguito prima della pubblicazione, sul sistema a cui appartiene.
+
+
+
+
La risposta breve
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Le dimensioni sono in byte, e 10 MB
+ contati come li conta il tuo file manager sono 10485760.
+
+
+
+
+
Windows
+
fsutil, e una versione PowerShell che non richiede nulla di extra
+
+ fsutil è incluso in Windows. Prende la dimensione in byte, quindi
+ calcola prima il numero - 10 MB sono 10485760, 100 MB sono 104857600, 1 GB è 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Misurato su Windows 11: funziona da un prompt normale senza richiederne uno con privilegi elevati, e
+ il file esce di esattamente 10485760 byte.
+
+
PowerShell può fare lo stesso senza chiamare un altro programma, e capisce le unità:
+ 10MB in PowerShell significa 10485760 byte, lo stesso conteggio in base 1024 che usa
+ Esplora risorse, quindi i due comandi qui sopra producono la stessa dimensione.
+
+
+
+
+
Linux
+
dd, truncate e fallocate, e la differenza che frega le persone
+
dd è quello che conoscono tutti. Scrive davvero i byte:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate è istantaneo, ed è questa la trappola. Misurato su Alpine Linux, il file
+ riporta 10485760 byte e occupa zero blocchi - è un file
+ sparso. Qualsiasi cosa lo legga ottiene dieci megabyte di zeri, ma il disco non ha mai
+ ceduto lo spazio:
+
+
truncate -s 10M test10mb.bin
+
+ Va bene per testare un limite di upload ed è fuorviante per testare una quota di disco.
+ fallocate è quello da usare quando lo spazio deve essere reale:
+
+
fallocate -l 10M test10mb.bin
+
E quando il contenuto deve essere incomprimibile, così un archiviatore non può ridurlo di nuovo:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, che non è sparso, e i due che conosci già
+
+ macOS include mkfile. Misurato su macOS 26.6.2: 10485760 byte e 20480 blocchi, quindi
+ lo spazio è davvero allocato invece che promesso:
+
+
mkfile 10m test10mb.bin
+
Ci sono anche dd e truncate, e si comportano come su Linux:
Un file della dimensione giusta non è un file del tipo giusto
+
+ Tutto quanto sopra ti dà un blocco di zeri. Basta quando ciò che è sotto test guarda solo la
+ dimensione - un limite di upload, una quota, un trasferimento. Smette di bastare nel momento in
+ cui qualcosa apre il file.
+
+
+ Misurato, e vale la pena provarlo di persona: crea un file da 2 MB con fsutil, chiamalo
+ photo.png e passalo a una libreria di immagini. Pillow risponde cannot
+ identify image file. Non è un PNG. Non lo è mai stato - lo diceva solo il nome.
+
+
+ Conta più di quanto sembri, per via di come il test fallisce a quel punto. Il tuo
+ endpoint di upload rifiuta il file, il tuo test diventa verde e concludi che il limite di
+ dimensione funziona. Non lo ha rifiutato per la dimensione. Lo ha rifiutato perché i byte non
+ erano un'immagine, e la regola che volevi testare non è mai stata raggiunta.
+
+
+
un parser lo rifiuta prima che venga guardata qualsiasi regola di dimensione
+
un passaggio di miniatura fallisce e l'errore che leggi riguarda la miniatura
+
un antivirus o un controllo del contenuto lo rifiuta per un terzo motivo
+
un visualizzatore non mostra nulla, e nessuno sa dire se sia quello il bug
+
+
+
+
+
L'altra strada
+
Un file reale di quel formato, della dimensione esatta che hai chiesto
+
+ È ciò che fa Testing Files Generator. Il file è un vero file del suo formato - si apre nel programma
+ che gli appartiene - e ha l'esatto numero di byte che hai chiesto, al byte:
+
+ Chiedi una dimensione che un formato non può raggiungere e ottieni un errore che nomina il minimo e
+ il suo motivo, mai un file della dimensione sbagliata. La pagina dei
+ formati elenca ogni formato con il file più piccolo che può produrre.
+
+
E un limite sono tre casi di test anziché uno, quindi lo strumento li costruisce tutti e tre:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Ti dà 10485759, 10485760 e 10485761 byte, e un manifest che dice quali il tuo sistema deve accettare
+ e quali rifiutare. La pagina dei casi d'uso ripercorre questo e
+ altri quattro compiti per cui è pensato.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Quindi, quale usare?
+
+
+
Usa il comando di sistema
+
+ Quando nulla apre il file. Testare un limite di dimensione su un endpoint che controlla prima la
+ dimensione, un trasferimento, una quota, un disco pieno. È una riga ed è già installato.
+
+
+
+
Usa un generatore vero
+
+ Quando qualcosa analizza, renderizza, importa o estrae il file - e quando ti servono le stesse
+ fixture domani, su un'altra macchina, byte per byte.
+
+
+
+
+ Entrambi sono su questa pagina perché entrambi hanno ragione una parte del tempo. L'errore da
+ evitare è usare il primo dove serve il secondo e leggere il test verde come una prova.
+
+
diff --git a/web/content/it/faq.html b/web/content/it/faq.html
new file mode 100644
index 00000000..3fe6fe59
--- /dev/null
+++ b/web/content/it/faq.html
@@ -0,0 +1,20 @@
+
Domande frequenti
+
+ Licenza, privacy, riproducibilità e le cose che le persone controllano prima di mettere un
+ generatore in una pipeline di build. Se la tua domanda non c'è, il
+ tracker delle issue è aperto.
+
{{ .Facts.FormatCount }} formati di file, ognuno generato a una dimensione esatta
+
+ Ognuno è un file reale di quel formato. Si apre nel programma che gli appartiene ed
+ è esattamente il numero di byte che hai chiesto. Nessuno è riempimento di zeri con un'estensione
+ appiccicata.
+
+
+{{ template "formatsTable" . }}
+
+
+
Cosa significano le colonne
+
+
+
File più piccolo
+
+ Il minimo di byte che questo strumento accetta per quel formato, compresa l'etichetta che scrive
+ dentro il file. Chiedi meno e ottieni un errore che nomina il minimo e il suo motivo, mai un
+ file della dimensione sbagliata.
+
+
+
+
Fedeltà
+
+ Quanto è completo il file. full significa che un lettore che analizza davvero il
+ formato lo accetta, non solo che l'estensione corrisponde.
+
+
+
+
Verificato con
+
+ Il lettore indipendente che apre ogni file generato prima che il formato venga rilasciato -
+ un'implementazione separata, non il nostro codice che corregge i propri compiti.
+
+
+
+
+ Ogni formato si ripete anche al byte: la stessa ricetta e lo stesso seed producono file identici su
+ qualsiasi macchina, ed è ciò che rende sicuro committare una ricetta al posto delle fixture
+ stesse.
+
+
+
+
+
Impostazioni che ogni formato accetta
+
+ La maggior parte dei formati ha impostazioni proprie - dimensioni dell'immagine, qualità JPEG,
+ numero di pagine PDF, righe e colonne di un foglio di calcolo, quante voci vanno dentro un
+ archivio. Impostale con --set key=value dalla riga di comando, o sotto
+ properties: in una ricetta.
+
+ Un valore fuori da ciò che un'impostazione accetta viene rifiutato con un messaggio che nomina
+ l'impostazione, l'intervallo consentito e cosa usare al suo posto. Anche un'impostazione
+ sconosciuta è un errore, mai un valore predefinito silenzioso - un refuso accettato in silenzio
+ dà un file con le impostazioni sbagliate e un'ora a chiedersi perché il test passa quando non
+ dovrebbe.
+
+
+ Esegui tfg formats <id> per vedere esattamente cosa accetta un formato nella
+ build che hai.
+
+
+
+
+
Gli archivi contengono file reali
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} e {{ end }}{{ $c.ID }}{{ end }}
+ possono essere riempiti di voci invece di restare un guscio vuoto. Un archivio generato contiene
+ davvero i documenti che dichiara di contenere, quindi qualsiasi cosa lo decomprima durante un
+ test trova file reali al suo interno.
+
+ PDF, PNG, DOCX, ZIP - {{ .Facts.FormatCount }} formati in tutto, e ognuno è un file
+ reale che si apre nel programma che gli appartiene, di esattamente la dimensione che hai
+ chiesto. Ogni esecuzione annota anche cosa la tua applicazione deve fare con ogni file.
+ Riga di comando e finestra desktop, gratuito e open source, interamente sulla tua macchina.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ La finestra desktop, pronta a scrivere un lotto di file. Lo stesso motore gira dietro la riga di comando.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
formati reali, ognuno si apre nel programma che gli appartiene
+
+
+ 1 byte
+
la precisione di ogni dimensione che chiedi, mai arrotondata in silenzio
+
+
+ 0
+
connessioni verso chiunque - nessun account, nessuna telemetria, nessun controllo degli aggiornamenti
+
+
+
+
+
Il problema
+
Fare un file di test è facile. Fare i mille giusti è la parte noiosa
+
Stai testando software che accetta file dalle persone. Prima o poi ti servono:
+
+
un PDF di esattamente 10 MB, per scoprire se il limite di upload è reale
+
i tre file ai due lati di quel limite, per scovare errori di uno in più o in meno
+
10.000 file di log, per vedere cosa fa il job notturno quando la cartella è grande
+
uno ZIP che contiene davvero 200 documenti, non un guscio vuoto con l'estensione giusta
+
un file da 4 GB, senza tenere un file da 4 GB nel tuo repository
+
le stesse fixture sul tuo portatile e sul server di build, byte per byte
+
+
+ È ciò che questo sostituisce. È pensato per ingegneri QA, automazione dei test e chiunque abbia
+ dietro al proprio codice un modulo di upload, una routine di importazione, un parser o una quota
+ di storage.
+
+
+
+
+
Cosa lo rende diverso
+
Gli altri generatori si fermano ai byte. Questo risponde a ciò che il tuo test chiede davvero
+
+ Una cartella di file ti lascia ancora a decidere cosa dovrebbe dimostrare ciascuno. Ogni esecuzione
+ qui scrive un manifest.json accanto ai file - un semplice elenco di tutto ciò che è
+ stato prodotto e, per ogni voce, un'aspettativa dichiarata.
+
+
Poniamo che il tuo endpoint di upload permetta 1 MB. Chiedi i tre file che stanno su quella linea:
Dove la risposta dipende dalla tua politica, il manifest lo dice
+
+ Registra unspecified invece di inventare un'aspettativa. Un generatore che tira a
+ indovinare produce falsi fallimenti, e una suite che grida al lupo finisce spenta.
+
+
+
+
+
+
Preset
+
Scegli la domanda, ottieni l'intero set
+
+ Un preset è un set di file di test progettato attorno a una domanda di test, così non devi capire tu
+ quali file dimostrano cosa. Ognuno ha una pagina che dice cosa trova di solito, cosa c'è nel set
+ e ogni impostazione che accetta.
+
+ Diecimila file di log, ciascuno tra uno e otto kilobyte, con le dimensioni estratte dal seed così
+ domani dà lo stesso set. Dai a ogni esecuzione la sua directory - il
+ manifest è l'unica traccia di ciò che un'esecuzione ha scritto, quindi lo strumento si
+ rifiuta di scriverne un secondo sopra:
+
+ Le dimensioni si contano a 1024, come fa il tuo file manager, quindi 2mb significa
+ 2097152 byte. Funziona anche un semplice numero di byte. La
+ documentazione copre le ricette, il manifest e i codici di
+ uscita.
+
+
+
+
+
Cosa ottieni
+
Costruito per una suite che gira senza supervisione
+
+
+
Dimensione esatta, al byte
+
Chiedi 10485761 byte e ottieni esattamente quelli. Una dimensione che un formato non può raggiungere è un errore con un motivo, mai un file della dimensione sbagliata.
+
+
+
{{ .Facts.FormatCount }} formati reali
+
Non zeri di riempimento con un'estensione. Un PNG generato si apre in un visualizzatore di immagini, un DOCX si apre in Word, uno ZIP si estrae. Ognuno è verificato con lettori indipendenti prima del rilascio.
+
+
+
Un manifest che è un oracolo di test
+
Percorso, dimensione, SHA-256, formato, seed, versione dello strumento - e cosa il tuo sistema deve fare con il file.
+
+
+
Riproducibile
+
Stessa ricetta e stesso seed, stessi byte, su qualsiasi macchina. Committa una piccola ricetta YAML invece di grandi fixture binarie.
+
+
+
Due interfacce, un solo motore
+
Una riga di comando pensata per la CI e una finestra desktop per il test esplorativo. Nessuna è una versione ridotta dell'altra, e un test le confronta capacità per capacità.
+
+
+
Completamente offline
+
Nessun account, nessun cloud, nessuna telemetria, nessun controllo degli aggiornamenti. Il binario della riga di comando non ha alcuno stack di rete compilato al suo interno.
+
+
+
+
+
+
Download
+
Scegli la build per il tuo sistema
+
+ Decomprimi l'archivio ed eseguilo. tfg è la riga di comando e tfg-gui è la
+ finestra desktop. Non c'è un installer e nulla da aggiungere alla tua macchina.
+
+ {{ template "downloadsTable" . }}
+
+
Cosa è firmato e cosa no
+
+ I download per Windows e macOS sono firmati, quindi si avviano senza l'avviso di sviluppatore
+ sconosciuto. Quelli per Linux no, perché Linux desktop non ha un equivalente con cui firmarli.
+ Ogni archivio è elencato in verify-SHA256SUMS.txt nella pagina delle release,
+ così puoi controllare cosa hai scaricato.
+
+ Il preset {{ .ID }} costruisce con un solo comando un intero set di file di test reali
+ per questa domanda, e un manifest.json accanto che dice come il tuo sistema deve
+ reagire a ogni file. Tutto ciò che segue è letto dal programma, ai valori predefiniti di questa
+ versione.
+
+
+{{ if .Catches }}
+
+
Cosa trova di solito?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
Cosa c'è nel set?
+
Ai valori predefiniti, come lo riporta tfg preset show {{ .ID }}:
+
+
+
+
File
{{ .Budget.Files }}
+
Target nella sua ricetta
{{ .Budget.Targets }}
+
Dimensione totale
{{ .Bytes }} B
+
Formati
{{ join .Budget.Formats ", " }}
+
+
+
+
E ciò che il manifest di quel set si aspetta dal tuo sistema:
+
+
+
+
Atteso
Significato
File
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
Cosa puoi cambiare?
+ {{- if .Settings }}
+
+
+
+
Impostazione
Accetta
Predefinito
Cosa fa
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Questo valore predefinito è un nostro segnaposto, non il valore del tuo sistema. Passa il tuo.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
Questo preset non ha impostazioni. Il set è lo stesso ogni volta.
+ {{- end }}
+
+
+
+
Come si esegue?
+
Guarda quanto costerebbe il set, costruiscilo o prendi la sua ricetta da modificare:
Oppure costruiscici sopra in una ricetta tua, accanto ai tuoi test:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/it/presets.html b/web/content/it/presets.html
new file mode 100644
index 00000000..5b07a59e
--- /dev/null
+++ b/web/content/it/presets.html
@@ -0,0 +1,32 @@
+
Preset di file di test, un set per ogni domanda di test
+
+ Un preset è un intero set di file di test progettato attorno a una domanda, con un manifest che dice
+ come il tuo sistema deve reagire a ogni file. Scegli la domanda, lo strumento costruisce il set.
+ Ogni preset ha una pagina tutta sua con cosa trova di solito, cosa c'è nel set e ogni impostazione
+ che accetta.
+
+
+{{ template "presetsList" . }}
+
+
+
In cosa un preset è diverso da una ricetta?
+
+ Sotto il cofano, in niente. Un preset è una ricetta che lo strumento scrive per te a partire da
+ poche impostazioni. tfg preset eject stampa quella ricetta così puoi tenerla
+ accanto ai tuoi test e modificarla, e una ricetta tua può basarsi su un preset con una riga,
+ extends: preset: seguito dal suo id.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Posso fidarmi dei valori predefiniti?
+
+ Per i file, sì. Per un numero che solo il tuo sistema conosce, come il limite di un modulo di
+ upload, un valore predefinito è un nostro segnaposto, e lo strumento lo dice ogni volta che ne
+ usa uno. La pagina di ogni preset marca queste impostazioni, e tfg preset show lo
+ dice prima che venga scritto qualsiasi cosa.
+
+
diff --git a/web/content/it/site.json b/web/content/it/site.json
new file mode 100644
index 00000000..c8ab8ee8
--- /dev/null
+++ b/web/content/it/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "it",
+ "locale": "it_IT",
+ "name": "Italiano",
+ "dir": "it",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Home",
+ "title": "Generatore di file di test - dimensione esatta, {{ .Facts.FormatCount }} formati reali",
+ "description": "Generatore gratuito e open source di file di test per la QA. PDF, DOCX, PNG e ZIP reali della dimensione esatta, con un manifest su come il tuo sistema deve reagire."
+ },
+ {
+ "key": "formats",
+ "slug": "formati",
+ "nav": "Formati",
+ "title": "{{ .Facts.FormatCount }} formati di file supportati - PDF, DOCX, PNG, ZIP e altri",
+ "description": "Tutti i formati che il generatore produce, il file più piccolo possibile per ciascuno e le impostazioni che accetta. Tutti i {{ .Facts.FormatCount }} si aprono nel loro programma."
+ },
+ {
+ "key": "presets",
+ "slug": "preset",
+ "nav": "Preset",
+ "title": "Preset di file di test - set pronti per la QA",
+ "description": "Set pronti di file di test, ognuno risponde a una domanda: limiti di upload, nomi dei file, codifiche, importazione di tabelle, file vuoti e validazione."
+ },
+ {
+ "key": "docs",
+ "slug": "documentazione",
+ "nav": "Documentazione",
+ "title": "Documentazione - comandi, ricette, manifest, codici di uscita",
+ "description": "Come generare file di test dalla riga di comando o con una ricetta YAML, cosa contiene il manifest e cosa significa ogni codice di uscita in CI."
+ },
+ {
+ "key": "use-cases",
+ "slug": "casi-d-uso",
+ "nav": "Casi d'uso",
+ "title": "Casi d'uso - limiti di upload, fixture per la CI, test di massa",
+ "description": "Testare un limite di dimensione dell'upload, costruire fixture riproducibili per la CI, generare diecimila file e riempire archivi con contenuti reali."
+ },
+ {
+ "key": "exact-size",
+ "slug": "creare-file-di-dimensione-esatta",
+ "nav": "Dimensione esatta",
+ "title": "Creare un file di dimensione esatta - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate e mkfile, ciascuno misurato sul proprio sistema, e perché un file fatto così non è un PDF né un PNG quando un test ne richiede uno."
+ },
+ {
+ "key": "faq",
+ "slug": "domande-frequenti",
+ "nav": "FAQ",
+ "title": "FAQ - domande sulla generazione di file di test",
+ "description": "In cosa differisce da dd e fsutil, se i file si possono committare, se le esecuzioni si ripetono byte per byte e cosa succede quando una dimensione è irraggiungibile."
+ },
+ {
+ "key": "damage",
+ "slug": "file-di-test-corrotti",
+ "nav": "File corrotti",
+ "title": "File di test corrotti - file rotti di dimensione esatta",
+ "description": "Un file rotto di proposito, della dimensione esatta, con un manifest che dice che il tuo sistema deve rifiutarlo. Per testare validazione degli upload e parser.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "file-di-test-in-ci",
+ "nav": "File di test in CI",
+ "title": "File di test in CI - GitHub Actions, GitLab CI e PowerShell",
+ "description": "Genera file di test nella pipeline invece di committare binari: workflow GitHub Actions, job GitLab, codici di uscita e la trappola di PowerShell.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "Vai al contenuto",
+ "navLabel": "Principale",
+ "langLabel": "Lingua",
+ "breadcrumbHome": "Home",
+ "imageAlt": "Testing Files Generator - file di test reali della dimensione esatta, con un manifest che dice come il tuo sistema deve reagire a ciascuno",
+ "schemaDescription": "Un generatore gratuito e open source di file di test per la QA. Produce file reali in {{ .Facts.FormatCount }} formati della dimensione esatta e scrive un manifest che dice come il sistema sotto test deve reagire a ciascuno.",
+ "ctaDownload": "Scarica",
+ "ctaSource": "Vedi il codice sorgente",
+ "ctaNote": "Gratuito e open source, GPL-3.0. Nessuna registrazione. I download per Windows e macOS sono firmati e si avviano senza avvisi.",
+ "colFormat": "Formato",
+ "colName": "Nome",
+ "colExtension": "Estensione",
+ "colSmallest": "File più piccolo",
+ "colFidelity": "Fedeltà",
+ "colChecked": "Verificato con",
+ "colSetting": "Impostazione",
+ "colAccepts": "Accetta",
+ "colSystem": "Sistema",
+ "colCli": "Riga di comando",
+ "colWindow": "Finestra desktop",
+ "noBinary": "ancora nessun binario",
+ "colCode": "Codice",
+ "colMeaning": "Significato",
+ "footerBlurb": "File di test per la QA, della dimensione esatta, con un manifest che dice come il tuo sistema deve reagire a ciascuno.",
+ "footerProject": "Progetto",
+ "footerSource": "Codice su GitHub",
+ "footerReleases": "Download",
+ "footerIssues": "Segnala un problema",
+ "footerSupport": "Sostieni il progetto",
+ "footerPages": "Pagine",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. Rilasciato sotto la GNU General Public License, versione 3. I file che generi sono tuoi - la licenza copre lo strumento, non il suo output.",
+ "footerPrivacy": "Questo sito non carica font, script o tracker da nessuna parte. Non imposta cookie.",
+ "notFoundTitle": "Questa pagina non esiste",
+ "notFoundLead": "L'indirizzo che hai seguito non corrisponde a nessuna pagina di questo sito.",
+ "notFoundBack": "Vai alla home",
+ "read.format": "Il formato di ogni file del set. È un'opzione dello strumento stesso, e il preset le dà solo un valore predefinito.",
+ "readTakes.format": "un id di formato dalla pagina dei formati",
+ "colDamage": "Danno",
+ "colEffect": "Cosa fa ai byte",
+ "colSettings": "Impostazioni",
+ "noSettings": "nessuna"
+ },
+ "endings": {
+ "0": "Tutto ha funzionato.",
+ "1": "Un errore imprevisto dentro lo strumento.",
+ "2": "Comando od opzione errati.",
+ "3": "La ricetta non è valida.",
+ "4": "Il formato non può fare ciò che è stato chiesto.",
+ "5": "Una lettura o una scrittura è fallita.",
+ "6": "Spazio su disco insufficiente.",
+ "7": "verify ha trovato una discrepanza.",
+ "8": "L'esecuzione è terminata ma non tutto è stato prodotto.",
+ "130": "Interrotto con Ctrl+C.",
+ "143": "Fermato da un segnale, che è l'aspetto di un timeout della CI."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "Un file valido e piccolo quanto il formato consente passa?",
+ "title": "Vuoto e minimo",
+ "pageTitle": "File di test validi minimi e vuoti in ogni formato",
+ "description": "Il file valido più piccolo che lo strumento scrive in ciascuno dei suoi {{ .Facts.FormatCount }} formati, più un file vuoto dove il formato lo permette, ognuno con la reazione attesa.",
+ "catches": [
+ "un file valido respinto perché troppo piccolo, quando il controllo conta i byte invece di leggerli",
+ "un file vuoto che manda in crash il lettore invece di essere segnalato",
+ "un'immagine larga un pixel che divide per zero lungo la strada verso la miniatura",
+ "uno storage che legge zero byte come un upload fallito e continua a riprovare"
+ ],
+ "details": {
+ "formats": "Da quali formati è composto il set. Lascia all per tutti i formati di questa versione, oppure indica quelli che il tuo sistema accetta."
+ }
+ },
+ "filename-handling": {
+ "question": "Il mio sistema salverà, mostrerà e restituirà un nome di file che non si aspettava?",
+ "title": "Gestione dei nomi di file",
+ "pageTitle": "Nomi di file problematici da testare - Unicode e lunghezza",
+ "description": "File con nomi che mettono in crisi upload e storage: altri alfabeti, emoji, inversione di direzione, caratteri invisibili, sintassi di shell e SQL, lunghezza.",
+ "catches": [
+ "un nome che sembra un altro sullo schermo, in un log o in un elenco",
+ "un nome tagliato, accorciato o riscritto tra l'upload e il salvataggio",
+ "un limite di lunghezza contato in caratteri dove lo storage conta byte"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "Un limite di dimensione viene applicato esattamente dove è dichiarato?",
+ "title": "Limiti di dimensione",
+ "pageTitle": "Testare un limite di dimensione dell'upload - file al limite",
+ "description": "File un byte sotto, esattamente al limite e un byte sopra il limite dichiarato dal tuo sistema, più passi più ampi ai due lati, ognuno marcato se va accettato.",
+ "catches": [
+ "errori di uno in più o in meno al limite",
+ "MB confuso con MiB, che fa il 4,8 per cento e basta a far passare un file che non dovrebbe passare",
+ "un limite applicato nel browser e non sul server"
+ ],
+ "details": {
+ "limit": "Il limite di dimensione dichiarato dal tuo sistema. Tutto il resto si misura a partire da esso.",
+ "spread": "Fin dove spingersi ai due lati del limite, come elenco di dimensioni."
+ }
+ },
+ "tabular-import": {
+ "question": "La mia importazione di tabelle regge a ciò che esportano gli strumenti reali?",
+ "title": "Importazione di tabelle",
+ "pageTitle": "File di test per importare CSV ed Excel - delimitatori",
+ "description": "CSV con altri delimitatori, fine riga CR LF, senza intestazione e con altre virgolette, una tabella molto larga, una cartella Excel e JSON in più layout.",
+ "catches": [
+ "un file con punto e virgola letto come una sola colonna, perché il delimitatore è stato dato per scontato invece di cercarlo",
+ "un file CRLF diviso in righe con una riga vuota dopo ciascuna",
+ "una tabella senza intestazione la cui prima riga di dati viene mangiata come nomi di colonna",
+ "un'importazione che tiene le colonne che sa mostrare e scarta il resto senza dire nulla",
+ "un lettore che prende i record JSON una riga alla volta e si ferma al primo documento indentato"
+ ],
+ "details": {
+ "rows": "Quante righe contiene il foglio di calcolo. Viene scritto esattamente alla dimensione che occupano tante righe, quindi il budget qui sopra si sposta con questo valore.",
+ "columns": "Quante colonne ha ogni riga del foglio di calcolo. Righe per colonne ha un tetto, e chiedere oltre viene rifiutato prima di scrivere qualsiasi cosa."
+ }
+ },
+ "text-encoding": {
+ "question": "Il mio lettore sa in quale codifica è un file, o tira a indovinare?",
+ "title": "Codifica del testo",
+ "pageTitle": "File di test per la codifica del testo - UTF-8, UTF-16, BOM, CRLF",
+ "description": "Lo stesso testo in UTF-8, UTF-16LE e UTF-16BE, con e senza byte order mark, e fine riga CR LF e LF, per testare come un lettore decodifica il testo.",
+ "catches": [
+ "un lettore che presume UTF-8 e mostra un file UTF-16 con un carattere ogni tre, o come file di quadratini",
+ "un byte order mark letto come contenuto, così il primo campo di un'importazione inizia con tre caratteri estranei",
+ "un importatore che indovina la codifica dai primi byte e indovina in modo diverso con un file più lungo",
+ "un file CRLF diviso in righe con una riga vuota dopo ciascuna, o un ritorno a capo rimasto nell'ultimo campo"
+ ],
+ "details": {
+ "sample": "Quanto è grande ogni file del set. UTF-16 memorizza due byte per carattere, quindi un numero dispari viene rifiutato."
+ }
+ },
+ "upload-validation": {
+ "question": "Il mio modulo di upload accetta ciò che deve e respinge il resto?",
+ "title": "Validazione dell'upload",
+ "pageTitle": "File di test per la validazione dell'upload - tipo e nome",
+ "description": "File per testare un modulo di upload: tipi consentiti e negati, contenuto che non corrisponde all'estensione, limite di dimensione, nomi ostili e upload di massa.",
+ "catches": [
+ "un limite applicato nel browser e non sul server",
+ "un SVG o un HTML scambiato per un'immagine o per testo semplice, che è un modo per far passare uno script attraverso un modulo",
+ "un file controllato dall'estensione e mai aperto, così un PDF chiamato .jpg passa",
+ "un modulo che legge l'intero corpo in memoria prima di guardare quanto è grande",
+ "un upload chiamato PHOTO.JPG respinto dove photo.jpg viene accettato, o il contrario",
+ "un nome con spazi, parentesi o caratteri fuori dall'ASCII scritto su disco senza modifiche"
+ ],
+ "details": {
+ "limit": "Il limite di dimensione dichiarato dal tuo modulo di upload. Questo set fa un passo per lato - per un file a ogni distanza, esegui il preset size-boundaries.",
+ "allow": "Quali tipi il tuo modulo deve accettare. Ognuno diventa un file reale di quel tipo, e sono il controllo positivo dell'intero set.",
+ "deny": "Quali estensioni il tuo modulo deve respingere. Un'estensione per cui questa versione non ha un formato riceve comunque un file con quel nome, contenente testo semplice.",
+ "far-over": "Quanto oltre il limite arriva l'unico file grande. Disattivalo dove scrivere diverse volte il limite non vale il disco.",
+ "bulk": "Quanti file contiene l'upload di massa. Zero lascia del tutto fuori dal set quel gruppo."
+ }
+ }
+ },
+ "commands": {
+ "generate": "produrre file, da una ricetta o da opzioni",
+ "validate": "controllare una ricetta senza scrivere nulla",
+ "verify": "controllare una directory rispetto a un manifest",
+ "cleanup": "rimuovere i file elencati da un manifest",
+ "recipe fmt": "stampare una ricetta nella sua forma normalizzata",
+ "preset": "costruire un set di file a partire da una domanda di test con nome",
+ "formats": "elencare i formati supportati da questa versione",
+ "damage": "elencare i modi in cui questa versione può rompere un file di proposito",
+ "tool": "piccole utilità per file che hai già",
+ "version": "stampare la versione dello strumento",
+ "license": "stampare la licenza e cosa significa per i file generati"
+ },
+ "outcomes": {
+ "accept": "Il tuo sistema deve accettare il file.",
+ "reject": "Il tuo sistema deve rifiutare il file.",
+ "sanitize": "Il tuo sistema deve accettare il file e ripulirlo, per esempio rinominandolo.",
+ "unspecified": "Dipende dalle regole del tuo sistema. Decidi tu, poi controlli che ciò che accade sia ciò che intendevi."
+ },
+ "damages": {
+ "zero-head": "Sovrascrive con zeri i primi byte del file, lasciandone intatta la lunghezza. La maggior parte dei lettori guarda prima lì, quindi quasi tutto si accorge di questo danno."
+ },
+ "terms": {
+ "oracleNone": "non applicabile",
+ "int": "qualsiasi numero intero",
+ "choice": "uno di un insieme fisso",
+ "bool": "vero o falso",
+ "size": "una dimensione come 2mb",
+ "text": "testo",
+ "pixels": "pixel",
+ "paragraphs": "paragrafi",
+ "rows": "righe",
+ "columns": "colonne",
+ "slides": "diapositive",
+ "hertz": "hertz",
+ "megapixels": "megapixel",
+ "million cells": "milioni di celle",
+ "entries per second": "voci al secondo",
+ "files": "file",
+ "sizes separated by commas": "dimensioni separate da virgole",
+ "format ids separated by commas": "id di formato separati da virgole",
+ "format ids separated by commas, or all": "id di formato separati da virgole, oppure all",
+ "extensions separated by commas": "estensioni separate da virgole",
+ "the id of a format, as tfg formats lists them": "l'id di un formato, come lo elenca tfg formats",
+ "the password, in plain text": "la password, in chiaro",
+ "any text": "qualsiasi testo",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "una data come 2024-02-29 o 2024-02-29T13:45:00+02:00, oppure none"
+ },
+ "faq": [
+ {
+ "q": "In cosa è diverso da dd, fsutil o truncate?",
+ "a": "Quei comandi ti danno un file della dimensione giusta pieno di niente. Un file da 2 MB chiamato photo.png fatto così non è un PNG, quindi qualsiasi cosa lo analizzi davvero lo rifiuta per il motivo sbagliato, e anche il tuo test passa per il motivo sbagliato. Questo produce un vero PNG di esattamente 2 MB che si apre in un visualizzatore di immagini, e arriva con una dichiarazione su come il tuo sistema deve trattarlo.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "È gratuito, e posso usarlo al lavoro?",
+ "a": "Sì a entrambe. È rilasciato sotto GPL-3.0 e non costa nulla. Non c'è un account, né una chiave di licenza, né un livello a pagamento."
+ },
+ {
+ "q": "Posso usare i file generati in un prodotto closed source?",
+ "a": "Sì. La licenza copre il codice dello strumento, non ciò che lo strumento produce. File, ricette e manifest generati sono output e non opere derivate, quindi puoi committarli e distribuirli senza alcun obbligo."
+ },
+ {
+ "q": "I file generati contengono dati personali reali?",
+ "a": "No. Tutto ciò che contengono è sintetizzato da un seed. Nessun dataset viene letto, nessun servizio viene contattato e nessun contenuto di terzi è incorporato. Considera un indirizzo e-mail generato inutilizzabile anziché inutilizzato, perché qualsiasi stringa casuale può coincidere per caso con uno reale."
+ },
+ {
+ "q": "Otterrò esattamente gli stessi file su un'altra macchina?",
+ "a": "Sì, byte per byte, con la stessa ricetta e lo stesso seed. Il progetto lo verifica a ogni modifica, e romperlo richiede una versione maggiore. È ciò che ti permette di committare una piccola ricetta invece di grandi fixture binarie."
+ },
+ {
+ "q": "Serve una connessione a internet?",
+ "a": "Mai. Non c'è telemetria, né controllo degli aggiornamenti, né client cloud, e il binario della riga di comando non ha alcuno stack di rete compilato al suo interno. Funziona su una macchina senza rete e in un ambiente aziendale chiuso."
+ },
+ {
+ "q": "Cosa succede se chiedo una dimensione che un formato non può raggiungere?",
+ "a": "Ottieni un errore che nomina il formato, il minimo possibile, il motivo di quel limite inferiore e cosa fare invece, e nessun file viene scritto. Lo strumento non arrotonda mai una dimensione in silenzio. Ogni minimo è elencato nella pagina dei formati.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "Posso generare un file deliberatamente rotto?",
+ "a": "Sì. Aggiungi --damage zero-head e il file esce con esattamente la dimensione richiesta, con i primi byte sovrascritti da zeri, così un lettore lo rifiuta, e il manifest dice che il tuo sistema deve rifiutarlo. I dettagli sono nella pagina sui file di test corrotti.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "Quali formati arrivano dopo?",
+ "a": "7z, mp3 e mp4. Oggi {{ .Facts.FormatCount }} formati funzionano da un capo all'altro."
+ },
+ {
+ "q": "Su quali sistemi posso eseguirlo?",
+ "a": "La riga di comando gira su Windows e Linux sia su Intel sia su ARM, e sui Mac con Apple Silicon. La finestra desktop è fornita per Windows su Intel, Linux su Intel e Mac con Apple Silicon. I Mac Intel non sono supportati e non viene compilato nulla per loro."
+ },
+ {
+ "q": "Devo installare qualcosa?",
+ "a": "No. Scarica l'archivio per il tuo sistema, decomprimilo ed esegui il binario. Non c'è un installer, né un runtime da aggiungere, né una dipendenza da risolvere. Se hai Go, funziona anche un solo comando go install.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "Perché un'esecuzione su migliaia di file è più lenta su Windows?",
+ "a": "Perché Windows fa pagare di più ogni percorso che esamina, e un comando che passa su migliaia di file esamina migliaia di percorsi. Misurato su una macchina con 3000 file da 1 kB, verify impiega circa 0,9 secondi su Windows e circa 0,2 secondi su Linux in un container. Un percorso di output più corto abbassa il valore di Windows, perché ogni cartella sopra i file fa parte di ciò che viene esaminato."
+ }
+ ]
+}
diff --git a/web/content/it/use-cases.html b/web/content/it/use-cases.html
new file mode 100644
index 00000000..ed5130de
--- /dev/null
+++ b/web/content/it/use-cases.html
@@ -0,0 +1,134 @@
+
A cosa lo usano le persone
+
+ Cinque compiti che ricorrono in quasi ogni progetto che accetta file dalle persone, e il comando che
+ esegue ciascuno. Ogni esempio qui sotto funziona così com'è scritto.
+
+
+
+
Limiti di upload
+
Testare se un limite di dimensione dei file è applicato dove dice di esserlo
+
+ Un limite sono tre casi di test, non uno: appena sotto, esattamente sul limite e appena sopra.
+ Ottenerli a mano significa calcolare numeri di byte sperando di non sbagliare di uno. Chiedi
+ invece il set:
+
+ Ottieni tre PDF reali da 1048575, 1048576 e 1048577 byte, e un manifest che dice che i primi due
+ vanno accettati e il terzo rifiutato per size_limit. Il tuo test legge
+ l'aspettativa invece che tu scriva tre asserzioni a mano - e quando il limite cambia, cambi un
+ numero e riesegui.
+
+
+ Lo stesso funziona senza preset quando vuoi un singolo set di limiti in linea:
+
Tenere le fixture fuori dal repository senza perderle
+
+ Grandi fixture binarie rendono un repository lento da clonare e scomodo da rivedere, e nessuno sa
+ dire cosa è cambiato quando una viene sostituita. Una ricetta è qualche centinaio di caratteri
+ di YAML che ricostruiscono i file identici - byte per byte, su qualsiasi
+ macchina - perché ogni file deriva dal seed dell'esecuzione.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Ogni conclusione ha il suo codice di uscita, quindi una pipeline distingue una ricetta sbagliata da
+ un disco pieno e da una discrepanza di verifica. Un'esecuzione fallita non stampa nulla sullo
+ standard output, il che evita che un parser di log legga un errore come dato.
+
+
+
+
+
Scala
+
Scoprire cosa succede quando la cartella è grande
+
+ Routine di importazione, job notturni ed elenchi di directory si comportano diversamente con
+ diecimila file che con dieci. Dimensioni estratte da un intervallo fanno sembrare il set
+ traffico reale anziché diecimila file identici, e l'estrazione viene dal seed, quindi il set è
+ lo stesso domani.
+
+ Un'esecuzione più grande dello spazio libero sul disco viene rifiutata prima che sia scritto il
+ primo byte, invece di riempire il disco e fallire a metà.
+
+
+
+
+
Archivi
+
Testare un decompressore con un archivio che contiene davvero dei file
+
+ Un archivio vuoto con l'estensione giusta non dimostra nulla sul codice che lo apre e percorre ciò
+ che c'è dentro. Dichiara il contenuto e l'archivio lo contiene davvero:
+
+ Profondità di annidamento, numero di voci e dimensione di ciò che c'è dentro sono tutte cose su cui
+ una routine di importazione ha opinioni, ed è così che scopri quali sono.
+
+
+
+
+
Parser e visualizzatori
+
Verificare che il tuo codice legga un formato come fa il software reale
+
+ Ogni formato qui è verificato con un lettore indipendente prima del rilascio - un PNG viene aperto e
+ i suoi pixel confrontati, un DOCX viene riletto da librerie separate, un archivio viene
+ estratto. Ciò significa che un file che il tuo parser rifiuta è una scoperta sul tuo parser, non
+ sul generatore.
+
+ La pagina dei formati elenca le impostazioni che ciascuno accetta e il
+ file più piccolo che ciascuno può essere.
+
+
+
+
+
Guide
+
Due di questi più in dettaglio
+
+
+ File di test corrotti - un file rotto di proposito, della
+ dimensione esatta, con nel manifest ciò che deve succedergli.
+
+
+ File di test in CI - un workflow GitHub Actions, un job GitLab
+ e i codici di uscita che fanno fallire una build.
+
+
+
+
+
+
Per chi è
+
+ Ingegneri QA, automazione dei test e chiunque abbia dietro al proprio codice un modulo di upload,
+ una routine di importazione, un parser o una quota di storage. Gira su una macchina senza alcuna
+ rete, il che conta in un ambiente aziendale chiuso dove un generatore basato su browser non è
+ un'opzione.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/ja/ci.html b/web/content/ja/ci.html
new file mode 100644
index 00000000..c27eb1f5
--- /dev/null
+++ b/web/content/ja/ci.html
@@ -0,0 +1,171 @@
+{{ with .Up }}
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }}と{{ end }}{{ $c.ID }}{{ end }}は、空の殻のままではなく、エントリで満たせます。生成されたアーカイブは、含むと言っているドキュメントを実際に含むため、テスト中にそれを展開するものは、中に本物のファイルを見つけます。
+
+ 저장소의 바이너리 픽스처는 기록에 영원히 남고, diff에서 검토할 수 없으며, 파일이 커지면 아예 불가능해집니다. 대신 파이프라인 안에서 레시피로 파일을 생성하세요. 레시피는
+ 텍스트이고, 바이트는 매번 같게 나오며, 마지막 단계가 아무것도 움직이지 않았음을 증명합니다.
+
+
+
+
짧은 답
+
+ tfg를 설치하고, 테스트 전에 tfg generate fixtures.yaml --out ./fixtures를, 테스트 후에
+ tfg verify ./fixtures/manifest.json을 실행하세요. 두 단계 모두 스스로 빌드를 실패시키며, 이유를 알려 주는 종료 코드를
+ 남깁니다.
+
+
+
+
+
커밋하지 않는 이유
+
픽스처가 저장소에 있으면 안 되는 이유
+
+
+ 기록에 남습니다. 바이너리를 나중에 삭제해도 모든 버전이 그대로 있으므로 클론은 작아지지 않습니다.
+
+
+ diff로는 무엇이 바뀌었는지 알 수 없습니다. 검토자는 PDF가 다르다는 것만 볼 뿐 그 이상은 모릅니다. 레시피는 한 줄만 바뀝니다.
+
+
+ 큰 파일은 들어가지 않습니다. GitHub는 100 MB를 넘는 파일이 든 푸시를 거부하므로, 500 MB 업로드 한도를 테스트하려면 커밋할 것이
+ 없습니다.
+
+
+
+ 커밋할 것은 레시피입니다. 같은 레시피와 같은 시드는 어느 머신에서나 같은 바이트를 쓰므로, 파이프라인에서 생성한 파일은 노트북에 있던 바로 그 파일입니다.
+
+
+
+
+
레시피
+
테스트 옆에 두는 레시피
+
+ 이 레시피는 수락되어야 하는 청구서 25건과 한도를 넘어 거부되어야 하는 이미지 2장을 쓰며, 매니페스트는 두 기대 결과를 모두 기록합니다.
+
+ 이것은 PowerShell의 동작이지 이 도구와는 무관합니다. cmd, bash, zsh에는 따로 필요한 것이
+ 없습니다.
+
+
+
+
+
여러 작업
+
작업 사이에서 픽스처 공유하기
+
+ 보통은 업로드할 필요가 없습니다. 같은 레시피가 같은 바이트를 쓰므로 각 작업이 자기 tfg generate를 실행할 수 있고, 이것이 업로드 후
+ 다운로드보다 빠릅니다. 한 작업이 다른 작업에서 파일을 받아야 한다면 전송 후 매니페스트에 tfg verify를 실행하세요. 도착한 것이 기록된 것과
+ 같은지 알려 줍니다.
+
+ 설정은 콜론 뒤에 씁니다. 옵션은 반복할 수 있고, 손상은 쓴 순서대로 적용됩니다. {{ .Facts.FormatCount }}개 형식 모두에서 동작합니다.
+
+
+
+
+
할 수 있는 것
+
어떤 손상이 있나요?
+
+ 이것은 프로그램이 출력하는 목록이며, 이 페이지를 빌드할 때 프로그램에서 읽어 옵니다. tfg damage는 같은 목록을 출력하고, tfg
+ damage <id>는 그중 하나가 받는 설정을 알려 줍니다.
+
+ {{ template "damagesTable" . }}
+
+ zero-head는 파일의 시작 부분을 0으로 덮어씁니다. 대부분의 리더는 파일이 무엇인지 알려 주는 시그니처와 헤더가 있는 그곳을 가장 먼저 봅니다.
+ 그래서 거의 모든 리더가 알아챕니다. 일반 텍스트와 로그에는 시그니처가 없지만 역시 거부됩니다. 0 바이트의 연속은 텍스트가 아니기 때문입니다. 4바이트 미만에서는 어떤
+ 리더도 불평하지 않는 손상이 나오는 형식이 있으며, 설정이 4부터 시작하는 이유가 그것입니다.
+
+
+
+
+
매니페스트가 말하는 것
+
무엇이 일어나야 하는지 말해 주는 매니페스트
+
+ 손상된 파일마다 시스템이 그것을 거부해야 한다는 항목이 붙고, 손상 내용이 그 옆에 기록됩니다.
+
+ 각 타깃에는 size, size-range, boundary, contains 중
+ 정확히 하나가 필요합니다. 둘은 오류이고 하나도 없는 것도 오류입니다. 올바르지 않은 레시피는 파일을 하나도 쓰지 않으며, 첫 번째 문제만이
+ 아니라 모든 문제를 한꺼번에 보고하고 각각 해당 설정의 이름을 알려 줍니다.
+
+
+
+
+
시스템이 파일을 어떻게 처리해야 하는지는 어떻게 선언하나요?
+
결과만 있으면 충분할 때는 짧은 형식을, 이유가 중요할 때는 긴 형식을 씁니다.
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ 결과는 accept, reject, sanitize, unspecified입니다.
+ 이유는 닫힌 목록이라 보고서가 이유별로 묶을 수 있습니다. content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit, size_zero.
+
+
+ 이유가 가리키는 것은 판정이 아니라 문제가 되는 규칙입니다. 그래서 같은 이유가 어느 결과 아래에도 올 수 있습니다. 한도보다 1바이트 작은 파일은
+ accept이지만, 관련된 규칙은 여전히 size_limit입니다.
+
+
+
+
+
매니페스트에는 무엇이 들어 있나요?
+
+ 중단된 실행을 포함해 모든 실행이 끝날 때 파일 옆에 쓰입니다. 파일마다 항목이 하나씩 있습니다.
+
+ 실행이 레시피에서 왔다면 recipe_hash가, 프리셋에서 왔다면 preset과 overrides가
+ 추가되므로, 매니페스트는 항상 그것을 만든 출처까지 추적할 수 있습니다.
+
+
+ 각 항목에는 파일을 만든 레시피 타깃의 id인 target_id도 들어 있고, summary.by_target은 각 타깃이 만든 파일
+ 수를 셉니다. 따라서 타깃이 여러 개인 레시피도 파일 이름을 읽지 않고 타깃별로 확인할 수 있습니다.
+
+
+
+
+
프리셋이란 무엇인가요?
+
+ 흔한 테스트 질문에 답하는 기성 파일 세트로, 세트를 직접 설계할 필요가 없습니다. 프리셋은 내부적으로 평범한 레시피이며, eject가 레시피를 출력하므로
+ 거기서부터 편집할 수 있습니다. 각 프리셋에는 보통 무엇을 찾아내는지, 세트에 무엇이 들어 있는지, 어떤 설정을 받는지 설명하는
+ 전용 페이지가 있습니다.
+
+ 네. 같은 엔진 위에 창을 얹은 것으로, 스크립트로 하지 않는 테스트를 위한 것입니다. 축소판이 아닙니다. 테스트가 두 인터페이스를 기능별로 비교하며, 한쪽만 할 수 있는 것은
+ 조용히 벌어지는 대신 선언하고 이유를 밝혀야 합니다.
+
+
+ 화면은 단일 배치, 프리셋, 여러 배치 동시 실행, 정보입니다. 무엇이든 쓰기 전에 실행 비용을 보여 주고, 실행 중에는 진행 상황을 알려 주며, 쓰다 만 파일을 남기지 않고
+ 도중에 취소할 수 있습니다. 아직 레시피 파일은 열지 못합니다. 지금은 레시피가 명령줄의 몫이고, 창은 양식에서 배치를 구성합니다.
+
+
diff --git a/web/content/ko/exact-size.html b/web/content/ko/exact-size.html
new file mode 100644
index 00000000..313791dd
--- /dev/null
+++ b/web/content/ko/exact-size.html
@@ -0,0 +1,133 @@
+
정확한 크기의 파일을 만드는 방법
+
+ 모든 시스템에 이를 위한 명령이 있으며, 세 가지 모두 아래에 있습니다. 정확한 바이트 수의 파일을 만들어 주며, 많은 테스트에서는 그것만으로 충분합니다. 이
+ 페이지의 모든 명령은 게시하기 전에 해당 시스템에서 실행해 보았습니다.
+
+
+
+
짧은 답
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. 크기는 바이트 단위이며, 파일 관리자가 세는 방식의 10MB는
+ 10485760입니다.
+
+
+
+
+
Windows
+
fsutil, 그리고 추가 도구가 필요 없는 PowerShell 방식
+
+ fsutil은 Windows에 포함되어 있습니다. 크기를 바이트 단위로 받으므로 먼저 숫자를 계산하세요. 10MB는
+ 10485760, 100MB는 104857600, 1GB는 1073741824입니다.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Windows 11에서 측정했습니다. 관리자 권한이 아닌 일반 프롬프트에서도 동작하며, 파일은 정확히 10485760바이트가 됩니다.
+
+
PowerShell은 다른 프로그램을 호출하지 않고도 같은 일을 할 수 있으며 단위를 이해합니다.
+ PowerShell의 10MB는 탐색기가 쓰는 것과 같은 1024 기준 계산으로 10485760바이트를 뜻하므로, 위의 두 명령은 같은 크기를 만듭니다.
+
+
+
+
+
Linux
+
dd, truncate, fallocate, 그리고 사람들이 걸려 넘어지는 차이
+
dd는 누구나 아는 명령입니다. 바이트를 실제로 씁니다.
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate는 즉시 끝나는데, 그것이 함정입니다. Alpine Linux에서 측정해 보면 파일은 10485760바이트로 보고되지만 차지하는 블록은
+ 0개로, 희소 파일입니다. 읽는 쪽은 0으로 채워진 10메가바이트를 받지만, 디스크는 공간을 내준 적이
+ 없습니다.
+
+
truncate -s 10M test10mb.bin
+
+ 업로드 한도를 테스트하기에는 괜찮지만 디스크 할당량을 테스트할 때는 오해를 부릅니다. 공간이 실제여야 할 때는 fallocate를 쓰세요.
+
+
fallocate -l 10M test10mb.bin
+
그리고 압축 프로그램이 다시 줄일 수 없도록 내용이 압축 불가능해야 할 때는:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
희소 파일이 아닌 mkfile, 그리고 이미 아시는 두 가지
+
+ macOS에는 mkfile이 포함되어 있습니다. macOS 26.6.2에서 측정하니 10485760바이트에 20480블록이었으므로, 공간은 약속이 아니라
+ 실제로 할당됩니다.
+
+ 위의 방법은 모두 0으로 된 덩어리를 줍니다. 테스트 대상이 크기만 본다면, 예를 들어 업로드 한도, 할당량, 전송이라면 충분합니다. 하지만 무엇이든 그 파일을
+ 여는 순간 충분하지 않게 됩니다.
+
+
+ 직접 측정했으며, 여러분도 해 볼 만합니다. fsutil로 2MB 파일을 만들고 photo.png라고 이름 붙인 다음 이미지
+ 라이브러리에 넘겨 보세요. Pillow는 cannot identify image file이라고 답합니다. 그것은 PNG가 아닙니다. 처음부터
+ 아니었고, 이름만 그렇게 말했을 뿐입니다.
+
+
+ 이는 들리는 것보다 중요합니다. 테스트가 그다음에 어느 쪽으로 실패하는지가 걸려 있기 때문입니다. 업로드 엔드포인트가 파일을 거부하고, 테스트가
+ 초록색이 되며, 크기 한도가 동작한다고 결론짓게 됩니다. 하지만 크기 때문에 거부한 것이 아닙니다. 바이트가 이미지가 아니어서 거부한 것이며, 테스트하려던 규칙에는 닿지도
+ 않았습니다.
+
+
+
파서가 크기 규칙을 살펴보기도 전에 거부한다
+
썸네일 단계가 실패하고 읽게 되는 오류가 썸네일에 관한 것이다
+
백신이나 콘텐츠 검사가 세 번째 이유로 거부한다
+
뷰어가 아무것도 보여 주지 않고, 그것이 버그인지 아무도 알 수 없다
+
+
+
+
+
다른 방법
+
그 형식의 실제 파일, 요청한 크기 그대로
+
+ 이것이 Testing Files Generator가 하는 일입니다. 파일은 해당 형식의 진짜 파일로, 해당 소프트웨어에서 열리며, 요청한 바이트 수와 정확히 같습니다.
+
+ 설정이 받는 범위를 벗어난 값은 설정, 허용 범위, 대신 쓸 값을 알려 주는 메시지와 함께 거부됩니다. 알 수 없는 설정도 오류이며 조용히 기본값이 되는 일은 없습니다. 조용히
+ 받아들여진 오타는 잘못된 설정의 파일과, 통과하면 안 되는 테스트가 왜 통과하는지 고민하는 한 시간을 낳습니다.
+
+
+ 가지고 있는 빌드에서 한 형식이 정확히 무엇을 받는지 보려면 tfg formats <id>를 실행하세요.
+
+
+
+
+
아카이브에는 실제 파일이 들어 있습니다
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }}와 {{ end }}{{ $c.ID }}{{ end }}는 빈
+ 껍데기로 두지 않고 항목으로 채울 수 있습니다. 생성된 아카이브는 담았다고 하는 문서를 실제로 담고 있으므로, 테스트 중에 이를 푸는 것은 무엇이든 안에서 실제 파일을
+ 찾습니다.
+
+ PDF, PNG, DOCX, ZIP 등 모두 {{ .Facts.FormatCount }}가지 형식이며, 모두 해당 소프트웨어에서 열리는 실제 파일로
+ 요청한 크기와 정확히 같습니다. 매 실행마다 애플리케이션이 각 파일을 어떻게 처리해야 하는지도 함께 기록합니다. 명령줄과 데스크톱 창, 무료
+ 오픈 소스이며, 모두 여러분의 컴퓨터에서 동작합니다.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ 파일 배치를 쓸 준비가 된 데스크톱 창. 명령줄 뒤에서도 같은 엔진이 동작합니다.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
가지 실제 형식, 각각 해당 소프트웨어에서 열립니다
+
+
+ 1바이트
+
요청한 모든 크기의 정확도, 조용히 반올림되는 일은 없습니다
+
+
+ 0
+
어디로도 연결하지 않습니다. 계정도, 텔레메트리도, 업데이트 확인도 없습니다
+
+
+
+
+
문제
+
테스트 파일 하나를 만드는 것은 쉽습니다. 알맞은 천 개를 만드는 것이 번거로운 부분입니다
+
여러분은 사람들에게서 파일을 받는 소프트웨어를 테스트하고 있습니다. 머지않아 다음이 필요해집니다.
+
+
업로드 한도가 실제인지 확인할 정확히 10MB인 PDF
+
하나 차이 오류를 잡기 위한 그 한도 양쪽의 파일 세 개
+
폴더가 클 때 야간 작업이 어떻게 되는지 보기 위한 로그 파일 10,000개
+
확장자만 맞춘 빈 껍데기가 아니라 실제로 문서 200개가 들어 있는 ZIP
+
저장소에 4GB 파일을 두지 않고도 쓸 수 있는 4GB 파일
+
노트북과 빌드 서버에서 바이트 단위로 같은 픽스처
+
+
+ 이것이 바로 이 도구가 대체하는 일입니다. QA 엔지니어, 테스트 자동화, 그리고 코드 뒤에 업로드 양식, 가져오기 루틴, 파서, 저장 용량 할당이 있는 모든 분을 위해
+ 만들었습니다.
+
+
+
+
+
무엇이 다른가
+
다른 생성기는 바이트에서 멈춥니다. 이 도구는 테스트가 실제로 묻는 것에 답합니다
+
+ 파일이 가득한 폴더만으로는 각 파일이 무엇을 증명해야 하는지 여전히 직접 정해야 합니다. 여기서는 실행할 때마다 파일 옆에 manifest.json을
+ 씁니다. 만들어진 모든 것의 단순한 목록이며, 항목마다 선언된 기대값이 있습니다.
+
+
업로드 엔드포인트가 1MB까지 허용한다고 해 봅시다. 그 경계선 위에 놓인 파일 세 개를 요청합니다.
+ 크기는 파일 관리자처럼 1024 단위로 세므로 2mb는 2097152바이트입니다. 바이트 수를 그대로 써도 됩니다.
+ 문서에서 레시피, 매니페스트, 종료 코드를 다룹니다.
+
+
+
+
+
얻는 것
+
무인으로 실행되는 테스트 묶음을 위해 만들었습니다
+
+
+
정확한 크기, 바이트 단위까지
+
10485761바이트를 요청하면 정확히 그 크기가 나옵니다. 형식이 도달할 수 없는 크기는 이유가 붙은 오류가 되며, 크기가 틀린 파일이 되는 일은 없습니다.
+
+
+
실제 형식 {{ .Facts.FormatCount }}가지
+
확장자만 붙인 채운 0이 아닙니다. 생성된 PNG는 이미지 뷰어에서 열리고, DOCX는 Word에서 열리며, ZIP은 풀립니다. 모든 형식은 출시 전에 독립적인 리더로 검증됩니다.
+
+
+
테스트 오라클이 되는 매니페스트
+
경로, 크기, SHA-256, 형식, 시드, 도구 버전, 그리고 시스템이 그 파일을 어떻게 처리해야 하는지.
+
+
+
재현 가능
+
같은 레시피와 같은 시드라면 어느 컴퓨터에서나 바이트까지 같습니다. 큰 바이너리 픽스처 대신 작은 YAML 레시피를 커밋하세요.
+
+
+
두 가지 인터페이스, 하나의 엔진
+
CI를 위해 만든 명령줄과 탐색적 테스트를 위한 데스크톱 창. 어느 쪽도 다른 쪽의 축소판이 아니며, 테스트가 두 인터페이스를 기능별로 비교합니다.
+
+
+
완전한 오프라인
+
계정도, 클라우드도, 텔레메트리도, 업데이트 확인도 없습니다. 명령줄 바이너리에는 네트워크 스택이 아예 컴파일되어 있지 않습니다.
+
+
+
+
+
+
다운로드
+
시스템에 맞는 빌드를 고르세요
+
+ 압축 파일을 풀고 실행하세요. tfg는 명령줄이고 tfg-gui는 데스크톱 창입니다. 설치 프로그램은 없으며 컴퓨터에 추가할 것도
+ 없습니다.
+
+ {{ template "downloadsTable" . }}
+
+
서명된 것과 그렇지 않은 것
+
+ Windows와 macOS 다운로드는 서명되어 있어 확인되지 않은 개발자 경고 없이 실행됩니다. Linux용은 데스크톱 Linux에 서명할 수 있는 대응 수단이 없어 서명되어 있지
+ 않습니다. 모든 압축 파일은 릴리스 페이지의 verify-SHA256SUMS.txt에 나열되어 있으므로 내려받은 것을 확인할 수 있습니다.
+
+ {{ .ID }} 프리셋은 이 질문에 대한 실제 테스트 파일 세트 전체를 명령 하나로 만들고, 그 옆에 시스템이 각 파일에 어떻게 반응해야 하는지 알려 주는
+ manifest.json을 둡니다. 아래의 모든 내용은 이 버전의 기본값으로 프로그램에서 읽어 온 것입니다.
+
+
+{{ if .Catches }}
+
+
보통 무엇을 찾아내나요?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
세트에는 무엇이 들어 있나요?
+
기본값에서 tfg preset show {{ .ID }}가 보고하는 대로입니다.
+
+
+
+
파일 수
{{ .Budget.Files }}
+
레시피의 타깃 수
{{ .Budget.Targets }}
+
총 크기
{{ .Bytes }} B
+
형식
{{ join .Budget.Formats ", " }}
+
+
+
+
그리고 그 세트의 매니페스트가 시스템에 기대하는 것:
+
+
+
+
기대값
의미
파일 수
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
무엇을 바꿀 수 있나요?
+ {{- if .Settings }}
+
+
+
+
설정
값
기본값
동작
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} 이 기본값은 우리 쪽의 임시값이며 여러분 시스템의 값이 아닙니다. 직접 값을 지정하세요.{{ end }}
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/ko/presets.html b/web/content/ko/presets.html
new file mode 100644
index 00000000..bc5d6fed
--- /dev/null
+++ b/web/content/ko/presets.html
@@ -0,0 +1,26 @@
+
테스트 파일 프리셋, 테스트 질문마다 한 세트
+
+ 프리셋은 하나의 질문을 중심으로 설계한 테스트 파일 세트 전체이며, 시스템이 각 파일에 어떻게 반응해야 하는지 알려 주는 매니페스트가 함께 제공됩니다. 질문을 고르면 도구가 세트를
+ 만듭니다. 각 프리셋에는 보통 무엇을 찾아내는지, 세트에 무엇이 들어 있는지, 어떤 설정을 받는지 설명하는 고유한 페이지가 있습니다.
+
+
+{{ template "presetsList" . }}
+
+
+
프리셋과 레시피는 어떻게 다른가요?
+
+ 내부적으로는 다르지 않습니다. 프리셋은 몇 가지 설정으로 도구가 대신 써 주는 레시피입니다. tfg preset eject가 그 레시피를 출력하므로 테스트
+ 옆에 두고 편집할 수 있으며, 직접 만든 레시피는 extends: preset: 뒤에 id를 붙인 한 줄로 프리셋을 바탕으로 할 수 있습니다.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
기본값을 믿어도 되나요?
+
+ 파일에 대해서는 그렇습니다. 업로드 양식의 한도처럼 여러분의 시스템만 아는 숫자라면 기본값은 우리 쪽의 임시값이며, 도구는 임시값을 쓸 때마다 그렇게 알려 줍니다. 각 프리셋의
+ 페이지는 그러한 설정을 표시하고, tfg preset show는 무엇이든 쓰기 전에 그 사실을 알려 줍니다.
+
+
diff --git a/web/content/ko/site.json b/web/content/ko/site.json
new file mode 100644
index 00000000..619bf08c
--- /dev/null
+++ b/web/content/ko/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "ko",
+ "locale": "ko_KR",
+ "name": "한국어",
+ "dir": "ko",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "홈",
+ "title": "테스트 파일 생성기 - 정확한 크기, 실제 형식 {{ .Facts.FormatCount }}종",
+ "description": "QA를 위한 무료 오픈 소스 테스트 파일 생성기. 정확한 크기의 실제 PDF, DOCX, PNG, ZIP 파일과 시스템이 어떻게 반응해야 하는지 알려 주는 매니페스트를 만듭니다."
+ },
+ {
+ "key": "formats",
+ "slug": "formats",
+ "nav": "형식",
+ "title": "지원하는 파일 형식 {{ .Facts.FormatCount }}종 - PDF, DOCX, PNG, ZIP 등",
+ "description": "이 생성기가 만드는 모든 파일 형식, 형식별 가능한 가장 작은 파일, 각 형식이 받는 설정. {{ .Facts.FormatCount }}종 모두 해당 소프트웨어에서 열립니다."
+ },
+ {
+ "key": "presets",
+ "slug": "presets",
+ "nav": "프리셋",
+ "title": "테스트 파일 프리셋 - QA 질문별 기성 세트",
+ "description": "기성 테스트 파일 세트로, 각 세트가 하나의 테스트 질문에 답합니다. 업로드 한도, 파일 이름, 인코딩, 표 가져오기, 빈 파일, 업로드 검증."
+ },
+ {
+ "key": "docs",
+ "slug": "docs",
+ "nav": "문서",
+ "title": "문서 - 명령, 레시피, 매니페스트, 종료 코드",
+ "description": "명령줄이나 YAML 레시피로 테스트 파일을 만드는 방법, 매니페스트의 내용, CI에서 실행할 때 각 종료 코드가 뜻하는 바를 설명합니다."
+ },
+ {
+ "key": "use-cases",
+ "slug": "use-cases",
+ "nav": "활용 사례",
+ "title": "활용 사례 - 업로드 한도, CI 픽스처, 대량 테스트",
+ "description": "업로드 크기 한도 테스트, CI용 재현 가능한 픽스처 구성, 파일 1만 개 생성, 실제 내용으로 아카이브 채우기."
+ },
+ {
+ "key": "exact-size",
+ "slug": "create-file-exact-size",
+ "nav": "정확한 크기",
+ "title": "지정한 크기의 파일 만드는 법 - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate, mkfile을 각 시스템에서 직접 측정했으며, 테스트에 PDF나 PNG가 필요할 때 이렇게 만든 파일로 부족한 이유도 설명합니다."
+ },
+ {
+ "key": "faq",
+ "slug": "faq",
+ "nav": "FAQ",
+ "title": "FAQ - 테스트 파일 생성에 관한 질문",
+ "description": "dd, fsutil과의 차이, 파일을 커밋해도 안전한지, 실행이 바이트 단위로 재현되는지, 크기에 도달할 수 없을 때 어떻게 되는지."
+ },
+ {
+ "key": "damage",
+ "slug": "corrupt-test-files",
+ "nav": "손상 파일",
+ "title": "손상된 테스트 파일 - 크기가 정확한 망가진 파일",
+ "description": "일부러 망가뜨린, 크기가 정확한 파일. 시스템이 거부해야 함을 알리는 매니페스트가 딸려 옵니다. 업로드 검증과 파서 테스트용.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "test-files-in-ci",
+ "nav": "CI의 테스트 파일",
+ "title": "CI의 테스트 파일 - GitHub Actions, GitLab CI, PowerShell",
+ "description": "바이너리를 커밋하는 대신 파이프라인에서 테스트 파일을 생성하세요. GitHub Actions 워크플로, GitLab 작업, 종료 코드, PowerShell의 함정.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "본문으로 건너뛰기",
+ "navLabel": "메인 메뉴",
+ "langLabel": "언어",
+ "breadcrumbHome": "홈",
+ "imageAlt": "Testing Files Generator - 정확한 크기의 실제 테스트 파일과 각 파일에 시스템이 어떻게 반응해야 하는지 알려 주는 매니페스트",
+ "schemaDescription": "QA를 위한 무료 오픈 소스 테스트 파일 생성기입니다. {{ .Facts.FormatCount }}가지 형식의 정확한 크기의 실제 파일을 만들고, 테스트 대상 시스템이 각 파일에 어떻게 반응해야 하는지 알려 주는 매니페스트를 작성합니다.",
+ "ctaDownload": "다운로드",
+ "ctaSource": "소스 코드 보기",
+ "ctaNote": "무료 오픈 소스, GPL-3.0. 가입이 필요 없습니다. Windows와 macOS 다운로드는 서명되어 있어 경고 없이 실행됩니다.",
+ "colFormat": "형식",
+ "colName": "이름",
+ "colExtension": "확장자",
+ "colSmallest": "가장 작은 파일",
+ "colFidelity": "완전성",
+ "colChecked": "검증 도구",
+ "colSetting": "설정",
+ "colAccepts": "허용값",
+ "colSystem": "시스템",
+ "colCli": "명령줄",
+ "colWindow": "데스크톱 창",
+ "noBinary": "아직 바이너리 없음",
+ "colCode": "코드",
+ "colMeaning": "의미",
+ "footerBlurb": "QA를 위한 정확한 크기의 테스트 파일과 각 파일에 시스템이 어떻게 반응해야 하는지 알려 주는 매니페스트.",
+ "footerProject": "프로젝트",
+ "footerSource": "GitHub의 소스 코드",
+ "footerReleases": "다운로드",
+ "footerIssues": "문제 신고",
+ "footerSupport": "프로젝트 후원",
+ "footerPages": "페이지",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. GNU 일반 공중 사용 허가서 버전 3에 따라 배포됩니다. 생성한 파일은 여러분의 것입니다. 라이선스는 도구에 적용되며 도구의 출력물에는 적용되지 않습니다.",
+ "footerPrivacy": "이 사이트는 어디에서도 글꼴, 스크립트, 추적기를 불러오지 않습니다. 쿠키도 설정하지 않습니다.",
+ "notFoundTitle": "이 페이지는 없습니다",
+ "notFoundLead": "따라오신 주소는 이 사이트의 어떤 페이지와도 일치하지 않습니다.",
+ "notFoundBack": "홈으로 이동",
+ "read.format": "세트에 포함된 모든 파일의 형식입니다. 도구 자체의 플래그이며, 프리셋은 기본값만 지정합니다.",
+ "readTakes.format": "형식 페이지의 형식 id",
+ "colDamage": "손상",
+ "colEffect": "바이트에 하는 일",
+ "colSettings": "설정",
+ "noSettings": "없음"
+ },
+ "endings": {
+ "0": "모두 정상적으로 동작했습니다.",
+ "1": "도구 내부에서 예기치 않은 오류가 발생했습니다.",
+ "2": "명령 또는 플래그가 잘못되었습니다.",
+ "3": "레시피가 올바르지 않습니다.",
+ "4": "해당 형식으로는 요청한 작업을 할 수 없습니다.",
+ "5": "읽기 또는 쓰기에 실패했습니다.",
+ "6": "디스크 공간이 부족합니다.",
+ "7": "verify가 불일치를 발견했습니다.",
+ "8": "실행은 끝났지만 모든 것이 만들어지지는 않았습니다.",
+ "130": "Ctrl+C로 중단되었습니다.",
+ "143": "시그널로 중지되었습니다. CI 시간 초과가 이렇게 보입니다."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "형식이 허용하는 가장 작은 크기의 유효한 파일이 통과할까요?",
+ "title": "빈 파일과 최소 파일",
+ "pageTitle": "모든 형식의 가장 작은 유효 파일과 빈 파일",
+ "description": "이 도구가 {{ .Facts.FormatCount }}가지 형식 각각에서 쓰는 가장 작은 유효 파일과, 형식이 허용하는 경우의 빈 파일. 각각 기대되는 반응이 함께 제공됩니다.",
+ "catches": [
+ "검사가 바이트를 읽지 않고 개수만 세기 때문에 너무 작다며 거부되는 유효한 파일",
+ "보고되지 않고 읽는 쪽을 비정상 종료시키는 빈 파일",
+ "썸네일을 만드는 도중 0으로 나누기가 발생하는 너비 1픽셀의 이미지",
+ "0바이트를 업로드 실패로 보고 계속 재시도하는 스토리지"
+ ],
+ "details": {
+ "formats": "세트를 구성하는 형식입니다. 이 빌드의 모든 형식을 쓰려면 all로 두고, 시스템이 받는 형식만 쓰려면 이름을 지정합니다."
+ }
+ },
+ "filename-handling": {
+ "question": "예상하지 못한 파일 이름을 시스템이 저장하고, 보여 주고, 돌려줄 수 있을까요?",
+ "title": "파일 이름 처리",
+ "pageTitle": "테스트용 까다로운 파일 이름 - 유니코드와 길이",
+ "description": "업로드와 저장을 깨뜨리는 이름의 파일. 다른 문자 체계와 이모지, 오른쪽에서 왼쪽 재정의, 보이지 않는 문자, 셸과 SQL 구문, 길이 제한.",
+ "catches": [
+ "화면이나 로그, 목록에서 다른 이름처럼 보이는 이름",
+ "업로드와 저장 사이에 잘리거나 다듬어지거나 다시 쓰이는 이름",
+ "스토리지는 바이트로 세는데 문자로 세는 길이 제한"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "크기 한도가 선언한 바로 그 지점에서 적용되고 있을까요?",
+ "title": "크기 경계",
+ "pageTitle": "업로드 크기 한도 테스트 - 경계 바로 위의 파일",
+ "description": "시스템이 선언한 크기 한도보다 1바이트 작은 파일, 정확히 같은 파일, 1바이트 큰 파일과 양쪽의 더 넓은 간격. 각각 허용해야 하는지 표시합니다.",
+ "catches": [
+ "한도에서 발생하는 하나 차이 오류",
+ "MB와 MiB를 혼동하는 경우로, 4.8퍼센트 차이이며 통과하면 안 되는 파일을 통과시키기에 충분합니다",
+ "서버가 아니라 브라우저에서만 적용되는 한도"
+ ],
+ "details": {
+ "limit": "시스템이 선언한 크기 한도입니다. 다른 모든 값은 이 값을 기준으로 측정됩니다.",
+ "spread": "한도 양쪽으로 얼마나 멀리 갈지를 크기 목록으로 지정합니다."
+ }
+ },
+ "tabular-import": {
+ "question": "실제 도구가 내보내는 표를 제 가져오기 기능이 제대로 처리할까요?",
+ "title": "표 가져오기",
+ "pageTitle": "CSV와 Excel 가져오기 테스트 파일 - 구분자, 머리글",
+ "description": "다른 구분자, CR LF 줄 끝, 머리글 없음, 다른 따옴표를 쓴 CSV, 아주 넓은 표, Excel 통합 문서, 여러 구조의 JSON.",
+ "catches": [
+ "구분자를 찾지 않고 가정했기 때문에 한 열로 읽히는 세미콜론 구분 파일",
+ "각 줄 뒤에 빈 줄이 생기며 행으로 나뉘는 CRLF 파일",
+ "첫 데이터 행이 열 이름으로 처리되어 사라지는 머리글 없는 표",
+ "표시할 수 있는 열만 남기고 나머지는 말없이 버리는 가져오기",
+ "JSON 레코드를 한 줄씩 읽다가 들여쓰기된 첫 문서에서 멈추는 리더"
+ ],
+ "details": {
+ "rows": "스프레드시트에 담길 행 수입니다. 그만큼의 행이 패키징되는 정확한 크기로 파일이 쓰이므로, 위의 예산이 이 값에 따라 움직입니다.",
+ "columns": "스프레드시트의 각 행에 있는 열 수입니다. 행 수와 열 수의 곱에는 상한이 있으며, 이를 넘는 요청은 아무것도 쓰기 전에 거부됩니다."
+ }
+ },
+ "text-encoding": {
+ "question": "제 리더는 파일의 인코딩을 알고 있을까요, 아니면 추측하고 있을까요?",
+ "title": "텍스트 인코딩",
+ "pageTitle": "텍스트 인코딩 테스트 파일 - UTF-8, UTF-16, BOM, CRLF",
+ "description": "같은 텍스트를 UTF-8, UTF-16LE, UTF-16BE로 바이트 순서 표시 유무에 따라, 그리고 CR LF와 LF 줄 끝으로 만들어 리더가 텍스트를 해독하는 방식을 테스트합니다.",
+ "catches": [
+ "UTF-8로 가정하여 UTF-16 파일을 세 글자에 한 글자만, 또는 네모 칸의 행으로 보여 주는 리더",
+ "바이트 순서 표시를 내용으로 읽어서 가져오기의 첫 필드가 낯선 문자 세 개로 시작하는 문제",
+ "앞쪽 바이트로 인코딩을 추측하고 더 긴 파일에서는 다르게 추측하는 임포터",
+ "각 줄 뒤에 빈 줄이 생기며 행으로 나뉘는 CRLF 파일, 또는 마지막 필드에 남는 캐리지 리턴"
+ ],
+ "details": {
+ "sample": "세트에 포함된 각 파일의 크기입니다. UTF-16은 글자당 2바이트를 저장하므로 홀수는 거부됩니다."
+ }
+ },
+ "upload-validation": {
+ "question": "제 업로드 양식은 받아야 할 것을 받고 나머지는 거부할까요?",
+ "title": "업로드 검증",
+ "pageTitle": "업로드 검증 테스트 파일 - 유형, 크기, 이름",
+ "description": "업로드 양식을 테스트하는 파일. 허용과 거부 유형, 확장자와 맞지 않는 내용, 크기 한도 전후, 악의적인 이름, 대량 업로드.",
+ "catches": [
+ "서버가 아니라 브라우저에서만 적용되는 한도",
+ "이미지나 일반 텍스트로 오인되는 SVG 또는 HTML 파일로, 스크립트가 양식 검사를 통과하는 방법이 됩니다",
+ "확장자로만 검사하고 열어 보지 않아서 .jpg라는 이름의 PDF가 통과하는 파일",
+ "크기를 확인하기 전에 본문 전체를 메모리로 읽어 들이는 양식",
+ "photo.jpg는 받으면서 PHOTO.JPG는 거부하거나 그 반대인 업로드",
+ "공백, 괄호, ASCII 이외의 문자가 든 이름이 그대로 디스크에 쓰이는 문제"
+ ],
+ "details": {
+ "limit": "업로드 양식이 선언한 크기 한도입니다. 이 세트는 한도 양쪽으로 한 단계씩 만듭니다. 모든 거리의 파일이 필요하면 size-boundaries 프리셋을 실행하세요.",
+ "allow": "양식이 받아야 할 유형입니다. 각 유형이 해당 유형의 실제 파일이 되며, 세트 전체의 양성 대조군이 됩니다.",
+ "deny": "양식이 거부해야 할 확장자입니다. 이 빌드에 형식이 없는 확장자도 그 이름의 파일이 만들어지며, 내용은 일반 텍스트입니다.",
+ "far-over": "하나뿐인 큰 파일이 한도를 얼마나 넘는지입니다. 한도의 몇 배를 쓰는 것이 디스크 낭비라면 꺼 두세요.",
+ "bulk": "대량 업로드에 포함할 파일 수입니다. 0이면 그 그룹은 세트에서 완전히 빠집니다."
+ }
+ }
+ },
+ "commands": {
+ "generate": "레시피나 플래그로 파일을 만든다",
+ "validate": "레시피를 검사하고 아무것도 쓰지 않는다",
+ "verify": "디렉터리를 매니페스트와 대조해 검사한다",
+ "cleanup": "매니페스트에 나열된 파일을 삭제한다",
+ "recipe fmt": "레시피를 정돈된 형태로 출력한다",
+ "preset": "이름 붙은 테스트 질문으로 파일 세트를 만든다",
+ "formats": "이 빌드가 지원하는 형식을 나열한다",
+ "damage": "이 빌드가 파일을 일부러 망가뜨릴 수 있는 방법을 나열한다",
+ "tool": "이미 가진 파일을 위한 작은 도구",
+ "version": "도구 버전을 출력한다",
+ "license": "라이선스와 생성된 파일에 대한 의미를 출력한다"
+ },
+ "outcomes": {
+ "accept": "시스템은 이 파일을 받아야 합니다.",
+ "reject": "시스템은 이 파일을 거부해야 합니다.",
+ "sanitize": "시스템은 이 파일을 받아서 이름을 바꾸는 등의 방법으로 정리해야 합니다.",
+ "unspecified": "시스템의 규칙에 따라 다릅니다. 직접 결정한 뒤 실제 일어나는 일이 의도한 것인지 확인하세요."
+ },
+ "damages": {
+ "zero-head": "파일의 첫 바이트들을 길이는 그대로 둔 채 0으로 덮어씁니다. 대부분의 리더가 가장 먼저 그곳을 보므로 거의 모든 것이 이 손상을 알아챕니다."
+ },
+ "terms": {
+ "oracleNone": "해당 없음",
+ "int": "임의의 정수",
+ "choice": "정해진 집합 중 하나",
+ "bool": "참 또는 거짓",
+ "size": "2mb와 같은 크기",
+ "text": "텍스트",
+ "pixels": "픽셀",
+ "paragraphs": "단락",
+ "rows": "행",
+ "columns": "열",
+ "slides": "슬라이드",
+ "hertz": "헤르츠",
+ "megapixels": "메가픽셀",
+ "million cells": "백만 셀",
+ "entries per second": "초당 항목 수",
+ "files": "파일",
+ "sizes separated by commas": "쉼표로 구분한 크기",
+ "format ids separated by commas": "쉼표로 구분한 형식 id",
+ "format ids separated by commas, or all": "쉼표로 구분한 형식 id 또는 all",
+ "extensions separated by commas": "쉼표로 구분한 확장자",
+ "the id of a format, as tfg formats lists them": "tfg formats가 나열하는 형식의 id",
+ "the password, in plain text": "암호(평문)",
+ "any text": "임의의 텍스트",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "2024-02-29 또는 2024-02-29T13:45:00+02:00 같은 날짜, 또는 none"
+ },
+ "faq": [
+ {
+ "q": "dd, fsutil, truncate와는 무엇이 다른가요?",
+ "a": "그 명령들은 크기만 맞고 내용이 텅 빈 파일을 줍니다. 그렇게 만든 2MB짜리 photo.png는 PNG가 아니므로, 실제로 파싱하는 것은 모두 엉뚱한 이유로 거부하고, 여러분의 테스트도 엉뚱한 이유로 통과합니다. 이 도구는 정확히 2MB인 실제 PNG를 만듭니다. 이미지 뷰어에서 열리며, 시스템이 이를 어떻게 다루어야 하는지에 대한 선언도 함께 제공됩니다.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "무료인가요? 업무에서 써도 되나요?",
+ "a": "둘 다 가능합니다. GPL-3.0으로 배포되며 비용이 들지 않습니다. 계정도, 라이선스 키도, 유료 요금제도 없습니다."
+ },
+ {
+ "q": "생성한 파일을 클로즈드 소스 제품에 써도 되나요?",
+ "a": "네. 라이선스는 도구의 코드에 적용되며 도구가 만든 것에는 적용되지 않습니다. 생성된 파일, 레시피, 매니페스트는 파생 저작물이 아니라 출력물이므로, 어떤 의무도 없이 커밋하고 배포할 수 있습니다."
+ },
+ {
+ "q": "생성된 파일에 실제 개인 정보가 들어 있나요?",
+ "a": "아니요. 내부의 모든 내용은 시드에서 합성됩니다. 어떤 데이터 세트도 읽지 않고, 어떤 서비스에도 접속하지 않으며, 제3자 콘텐츠도 포함하지 않습니다. 생성된 이메일 주소는 아직 쓰이지 않은 주소가 아니라 쓸 수 없는 주소로 여기세요. 임의의 문자열이 우연히 실제 주소와 같을 수 있기 때문입니다."
+ },
+ {
+ "q": "다른 컴퓨터에서도 완전히 같은 파일이 나오나요?",
+ "a": "네. 같은 레시피와 같은 시드라면 바이트 단위로 같습니다. 프로젝트는 변경할 때마다 이를 테스트하며, 이를 깨려면 메이저 버전을 올려야 합니다. 그래서 큰 바이너리 픽스처 대신 작은 레시피를 커밋할 수 있습니다."
+ },
+ {
+ "q": "인터넷 연결이 필요한가요?",
+ "a": "전혀 필요 없습니다. 텔레메트리도, 업데이트 확인도, 클라우드 클라이언트도 없으며, 명령줄 바이너리에는 네트워크 스택이 아예 컴파일되어 있지 않습니다. 네트워크가 없는 컴퓨터와 폐쇄된 기업 환경에서도 동작합니다."
+ },
+ {
+ "q": "형식이 도달할 수 없는 크기를 요청하면 어떻게 되나요?",
+ "a": "형식, 가능한 가장 작은 크기, 그 하한의 이유, 대신 해야 할 일을 알려 주는 오류가 나오고 파일은 쓰이지 않습니다. 도구는 크기를 조용히 반올림하지 않습니다. 모든 하한은 형식 페이지에 나와 있습니다.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "일부러 망가진 파일도 만들 수 있나요?",
+ "a": "네. --damage zero-head를 추가하면 파일은 요청한 크기 그대로, 첫 바이트가 0으로 덮어쓰인 채 나오므로 리더가 그것을 거부하고, 매니페스트에는 시스템이 그것을 거부해야 한다고 적힙니다. 자세한 내용은 손상된 테스트 파일 페이지에 있습니다.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "다음에는 어떤 형식이 추가되나요?",
+ "a": "7z, mp3, mp4입니다. 현재 {{ .Facts.FormatCount }}가지 형식이 처음부터 끝까지 동작합니다."
+ },
+ {
+ "q": "어떤 시스템에서 실행할 수 있나요?",
+ "a": "명령줄은 Windows와 Linux의 Intel과 ARM, 그리고 Apple Silicon Mac에서 실행됩니다. 데스크톱 창은 Intel의 Windows, Intel의 Linux, Apple Silicon Mac용으로 제공됩니다. Intel Mac은 지원하지 않으며 빌드도 하지 않습니다."
+ },
+ {
+ "q": "설치해야 하는 것이 있나요?",
+ "a": "없습니다. 시스템에 맞는 압축 파일을 내려받아 풀고 바이너리를 실행하면 됩니다. 설치 프로그램도, 추가할 런타임도, 해결할 의존성도 없습니다. Go가 있다면 go install 명령 하나로도 됩니다.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "수천 개의 파일을 처리하는 실행이 Windows에서 더 느린 이유는 무엇인가요?",
+ "a": "Windows는 살펴보는 경로 하나하나에 더 많은 비용을 치르게 하고, 수천 개의 파일을 훑는 명령은 수천 개의 경로를 살펴보기 때문입니다. 1kB 파일 3000개가 있는 한 컴퓨터에서 측정하니 verify는 Windows에서 약 0.9초, 컨테이너 안의 Linux에서 약 0.2초가 걸렸습니다. 출력 경로를 짧게 하면 Windows 수치가 줄어듭니다. 파일 위의 모든 폴더도 살펴보는 대상에 포함되기 때문입니다."
+ }
+ ]
+}
diff --git a/web/content/ko/use-cases.html b/web/content/ko/use-cases.html
new file mode 100644
index 00000000..38882e80
--- /dev/null
+++ b/web/content/ko/use-cases.html
@@ -0,0 +1,116 @@
+
어떤 일에 쓰나요
+
+ 사람들에게서 파일을 받는 거의 모든 프로젝트에 나오는 다섯 가지 작업과, 각각을 처리하는 명령입니다. 아래의 모든 예제는 쓰인 그대로 실행됩니다.
+
+
+
+
업로드 한도
+
파일 크기 한도가 말한 위치에서 적용되는지 테스트하기
+
+ 한도는 하나가 아니라 세 개의 테스트 케이스입니다. 바로 아래, 정확히 그 값, 바로 위입니다. 이를 손으로 만들려면 바이트 수를 계산하고 하나 어긋나지 않았기를 바라야 합니다.
+ 대신 세트를 요청하세요.
+
+ 1048575, 1048576, 1048577바이트의 실제 PDF 세 개와, 처음 두 개는 수락하고 세 번째는 size_limit으로 거부해야 한다고 알려
+ 주는 매니페스트를 얻습니다. 어서션 세 개를 직접 쓰는 대신 테스트가 기대값을 읽으며, 한도가 바뀌면 숫자 하나를 바꾸고 다시 실행하면 됩니다.
+
+
+ 경계 세트 하나를 인라인으로 만들고 싶다면 프리셋 없이도 같은 일을 할 수 있습니다.
+
+ 큰 바이너리 픽스처는 저장소 복제를 느리게 하고 리뷰를 불편하게 하며, 하나가 교체되어도 무엇이 바뀌었는지 아무도 알 수 없습니다. 레시피는 똑같은 파일을 다시 만드는 몇백 자의
+ YAML입니다. 어느 컴퓨터에서나 바이트 단위로 같습니다. 모든 파일이 실행의 시드에서 파생되기 때문입니다.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ 끝나는 방식마다 고유한 종료 코드가 있으므로 파이프라인은 잘못된 레시피, 디스크 가득 참, 검증 불일치를 구별할 수 있습니다. 실패한 실행은 표준 출력에 아무것도 출력하지 않아
+ 로그 파서가 오류를 데이터로 읽지 않습니다.
+
+
+
+
+
규모
+
폴더가 클 때 무슨 일이 일어나는지 알아내기
+
+ 가져오기 루틴, 야간 작업, 디렉터리 목록은 파일이 10개일 때와 1만 개일 때 다르게 동작합니다. 범위에서 뽑은 크기는 똑같은 파일 1만 개가 아니라 실제 트래픽처럼 보이는
+ 세트를 만들며, 추첨은 시드에서 나오므로 세트는 내일도 같습니다.
+
+ Een binaire fixture in een repository blijft voorgoed in de geschiedenis, kan niet in een diff
+ worden beoordeeld en wordt onmogelijk zodra het bestand groot is. Genereer de bestanden in plaats
+ daarvan in de pipeline uit een recept. Het recept is tekst, de bytes komen elke keer hetzelfde uit
+ en een laatste stap bewijst dat er niets is veranderd.
+
+
+
+
Het korte antwoord
+
+ Installeer tfg, voer vóór de tests tfg generate fixtures.yaml --out
+ ./fixtures uit en erna tfg verify ./fixtures/manifest.json. Beide stappen
+ laten de build vanzelf mislukken, met een afsluitcode die zegt waarom.
+
+
+
+
+
Waarom niet committen
+
Waarom een fixture niet in de repository hoort
+
+
+ Het blijft in de geschiedenis. Een binair bestand later verwijderen maakt een kloon
+ niet kleiner, want elke versie ervan staat er nog.
+
+
+ Een diff laat niet zien wat er veranderde. De reviewer ziet dat een PDF anders is
+ en verder niets. Een recept verandert met één regel.
+
+
+ Grote bestanden passen niet. GitHub weigert een push met een bestand van meer dan
+ 100 MB, dus voor een test van een uploadlimiet van 500 MB valt er niets te committen.
+
+
+
+ Het recept is wat je commit. Hetzelfde recept en dezelfde seed schrijven op elke machine dezelfde
+ bytes, dus het bestand dat in de pipeline wordt gegenereerd is het bestand dat je op je laptop
+ had.
+
+
+
+
+
Het recept
+
Een recept dat naast de tests staat
+
+ Dit schrijft vijfentwintig facturen die geaccepteerd moeten worden en twee afbeeldingen boven een
+ limiet die geweigerd moeten worden, en het manifest legt beide verwachtingen vast:
+
+ De regel met de controlesom vergelijkt het archief met verify-SHA256SUMS.txt uit
+ dezelfde release. De versie is vastgezet, dus een nieuwe release verandert nooit een build die
+ je niet hebt aangeraakt.
+
+ Elk einde heeft zijn eigen afsluitcode, dus de stap mislukt vanzelf en het log zegt welke. De codes
+ die een pipeline tegenkomt:
+
+
+
3 - het recept is niet geldig. Er is niets geschreven en elk probleem wordt genoemd
+
4 - het formaat kan niet wat er gevraagd werd, bijvoorbeeld een grootte onder zijn minimum
+
6 - er is niet genoeg schijfruimte
+
7 - tfg verify vond een bestand dat niet bij zijn manifest past
+
8 - de run is klaar, maar niet alles is gemaakt
+
+
+ Een mislukte run drukt niets af op de standaarduitvoer, zodat een logparser een fout nooit voor data
+ aanziet. De hele tabel staat op de documentatiepagina.
+
+
+
+
+
PowerShell
+
Een PowerShell-script heeft nog één regel nodig
+
+ PowerShell neemt de afsluitcode van een programma niet mee uit een .ps1-bestand. Start
+ er een met -File en het script antwoordt 0, ook als de tool erin het
+ werk weigerde, waardoor een build die rood hoort te zijn groen wordt. De laatste regel is de
+ hele oplossing:
+
+ Zo gedraagt PowerShell zich, het ligt niet aan deze tool. cmd, bash en
+ zsh hebben niets extra nodig.
+
+
+
+
+
Meerdere jobs
+
De fixtures delen tussen jobs
+
+ Uploaden is meestal niet nodig. Omdat hetzelfde recept dezelfde bytes schrijft, kan elke job zijn
+ eigen tfg generate uitvoeren, wat sneller is dan uploaden en downloaden. Moet een
+ job bestanden van een andere ontvangen, voer dan na de overdracht tfg verify uit op
+ het manifest, en het zegt of wat aankwam is wat werd geschreven.
+
Hoe maak je een beschadigd bestand om mee te testen
+
+ Een validator aan wie alleen gezonde bestanden zijn getoond, is niet echt getest. Zo krijg je een
+ bestand dat met opzet kapot is, precies de grootte heeft die je vraagt en een
+ manifest meebrengt dat zegt wat je systeem ermee moet doen.
+
+
+
+
Het korte antwoord
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out schrijft een PNG
+ van precies 2097152 bytes waarvan de eerste bytes nullen zijn, en het manifest ernaast legt vast
+ dat je systeem het moet weigeren.
+
+
+
+
+
De gebruikelijke weg
+
Waarom een met de hand beschadigd bestand een slechte test is
+
+ Gebruikelijk zijn een hexeditor, een script dat een paar willekeurige bytes omgooit, of een bestand
+ dat met head of truncate wordt ingekort. Het werkt één keer, en daarna
+ kost het je:
+
+
+
+ Het is elke keer anders. Een willekeurige byte komt bij elke run ergens anders
+ terecht, dus een fout van dinsdag komt woensdag misschien niet terug.
+
+
+ Het verandert de grootte. Een ingekort bestand is kleiner dan de limiet waaronder
+ het hoorde te blijven, dus de groottecontrole antwoordt vóór de inhoudscontrole en de test
+ slaagt om de verkeerde reden.
+
+
+ Het valt vaak niet op. Platte tekst blijft leesbaar met een gewijzigde byte in het
+ midden, en een toegeeflijke afbeeldingslezer tekent het gewoon, waardoor het bestand dat kapot
+ moest zijn wordt geaccepteerd.
+
+
+ Het zegt niets over wat er moet gebeuren. Het bestand is alleen bytes, en wie de
+ test later leest, moet raden of acceptatie of weigering de bedoeling was.
+
+
+
+
+
+
Wat je krijgt
+
Een beschadigd bestand heeft nog steeds de grootte die je vroeg
+
+ Het bestand wordt normaal gegenereerd en daarna kapotgemaakt, op weg naar de schijf. Het houdt de
+ grootte die je vroeg, en hetzelfde commando schrijft opnieuw dezelfde bytes.
+
+ Instellingen komen achter een dubbele punt. De optie mag herhaald worden, en de beschadigingen
+ worden toegepast in de volgorde waarin je ze schrijft. Het werkt met elk van de
+ {{ .Facts.FormatCount }} formaten.
+
+
+
+
+
Wat het kan
+
Welke beschadigingen zijn er?
+
+ Dit is de lijst die het programma afdrukt, uit het programma gelezen op het moment dat deze pagina
+ wordt gebouwd. tfg damage drukt dezelfde af, en tfg damage <id>
+ zegt wat één ervan aanneemt.
+
+ {{ template "damagesTable" . }}
+
+ zero-head schrijft nullen over het begin van het bestand. De meeste lezers kijken daar
+ eerst, naar de handtekening en de kop die zeggen wat het bestand is, dus bijna elke lezer merkt
+ het. Platte tekst en logbestanden hebben geen handtekening en worden ook geweigerd, omdat een
+ reeks nulbytes geen tekst is. Onder vier bytes komen sommige formaten uit met schade waar geen
+ lezer over klaagt, en daarom begint de instelling bij vier.
+
+
+
+
+
Wat het manifest zegt
+
Een manifest dat zegt wat er moet gebeuren
+
+ Elk beschadigd bestand krijgt een regel die zegt dat je systeem het moet weigeren, met de
+ beschadiging ernaast vastgelegd:
+
+ Twee verzoeken worden geweigerd voordat er iets wordt geschreven, omdat elk een bestand op schijf
+ zou laten staan dat het manifest verkeerd beschrijft:
+
+
+
een bestand dat kleiner is dan de beschadiging nodig heeft en ongewijzigd zou uitkomen
+
+ expected: accept naast een beschadiging, omdat niets daaraan kan voldoen. Schrijf
+ sanitize als je systeem het bestand moet repareren, of unspecified
+ als dat juist de vraag is die je stelt
+
+
+
+
+
+
In een recept
+
Gezonde en kapotte bestanden in één run
+
+ Zet beide in één recept, en het manifest draagt de verwachting van elk bestand, zodat de test geen
+ lijst nodig heeft van welk bestand welk is:
+
+ De test leest het manifest en controleert dat wat er gebeurde is wat er werd opgegeven. Hij heeft
+ geen lijst met bestandsnamen nodig:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Een goede weigering is een schone weigering. Een melding die zegt wat er mis was, is het antwoord
+ dat je wilt. Een serverfout, een vastloper of een half opgeslagen bestand is het gebrek dat deze
+ test moet vinden.
+
+
+
+
+
Verder
+
Waar je vandaar heen kunt
+
+
+ De preset upload-validation stelt een formulier de
+ andere twee vragen, die over de grootte en die over het type.
+
+
diff --git a/web/content/nl/docs.html b/web/content/nl/docs.html
new file mode 100644
index 00000000..f6527f34
--- /dev/null
+++ b/web/content/nl/docs.html
@@ -0,0 +1,285 @@
+
Documentatie
+
+ Alles wat de tool doet, geordend als de vragen waarmee mensen echt komen. De
+ README in de repository is de volledige referentie en komt altijd
+ overeen met de build die je hebt gedownload.
+
+
+
+
Welke opdrachten zijn er?
+
Elke doet precies één ding:
+ {{ template "commandList" . }}
+
+
+
+
Hoe genereer ik één bestand van een exacte grootte?
+
+ Noem het formaat, de grootte en waar het naartoe moet. Groottes tellen in 1024-tallen, dus
+ 2mb is 2097152 bytes. Een gewoon aantal bytes werkt ook, dus --size
+ 10485761 vraagt precies zoveel.
+
+
tfg generate --format png --size 2mb --out ./out
+
De nuttige opties van generate:
+
+
+
Optie
Wat het doet
+
+
--format <id>
formaat van de bestanden, bijvoorbeeld txt
+
--size <size>
exacte grootte van elk bestand, zoals 10mb of een gewoon aantal bytes
+
--size-range <a-b>
een grootte die per bestand uit een bereik wordt getrokken, zoals 1kb-8kb. De trekking komt uit de seed
+
--boundary <size>
drie bestanden rond een limiet: één byte eronder, de limiet, één byte erboven
+
--count <n>
hoeveel bestanden te maken. Standaard 1
+
--name <template>
naamsjabloon, bijvoorbeeld invoice_{index:04}.txt
+
--out <dir>
map om naartoe te schrijven
+
--seed <n>
seed van de run. Dezelfde seed geeft dezelfde bytes
+
--set <k>=<v>
een formaatinstelling, herhaalbaar
+
--damage <name>
de bestanden met opzet beschadigen, herhaalbaar en in volgorde toegepast. Draai tfg damage voor de lijst
+
--expected <outcome>
accept, reject, sanitize of unspecified
+
--dry-run
tellen en tonen, helemaal niets schrijven
+
--json
het manifest naar de standaarduitvoer schrijven
+
+
+
+
+
+
+
Hoe maak ik een bestand dat met opzet kapot is?
+
+ Elk ander bestand dat deze tool schrijft is correct per constructie, wat twee van de drie vragen
+ beantwoordt die een uploadvalidator stelt. --damage beantwoordt de derde - gaat het
+ bestand überhaupt open. Het bestand wordt normaal gemaakt en daarna beschadigd, dus het heeft
+ nog steeds de grootte die je vroeg.
+
+ Instellingen komen na een dubbele punt. De optie herhaalt zich, en de volgorde waarin je ze schrijft
+ is de volgorde waarin ze worden toegepast. tfg damage toont wat deze build kan en
+ wat elke variant accepteert.
+
+
In een recept is de sleutel een lijst, van namen of van instellingen:
+ Een beschadigd bestand krijgt expected: reject in het manifest, met de beschadiging
+ ernaast vastgelegd. Twee dingen worden geweigerd voordat er iets wordt geschreven, omdat elk
+ anders een bestand op schijf zou zetten dat het manifest verkeerd beschrijft:
+
+
+
een bestand dat kleiner is dan de beschadiging nodig heeft, omdat het ongewijzigd zou uitkomen
+
+ expected: accept naast een beschadiging, omdat niets daaraan kan voldoen. Schrijf
+ sanitize als het geteste systeem het bestand moet repareren, of
+ unspecified als dat de vraag is die je stelt
+
+
+
+ Een derde is vooraf niet te weten. Als een beschadiging draait en geen enkele byte verschuift, wordt
+ dat bestand weggegooid in plaats van geschreven - de run gaat door, zegt om welk bestand het
+ ging en eindigt met de gedeeltelijke afsluitcode.
+
+ Een recept is een YAML-bestand dat een hele run beschrijft. Commit het naast je tests en de fixtures
+ zijn geen binaries meer in je repository - iedereen kan ze byte voor byte opnieuw opbouwen uit
+ een bestand van een paar honderd tekens.
+
+ Elk target heeft precies één van deze sleutels nodig: size, size-range,
+ boundary of contains. Twee is een fout en geen ook. Een ongeldig
+ recept schrijft helemaal geen bestanden en meldt alle problemen tegelijk in
+ plaats van alleen het eerste, elk met de instelling waar het over gaat.
+
+
+
+
+
Hoe leg ik vast wat mijn systeem met een bestand moet doen?
+
Korte vorm als de uitkomst genoeg is, lange vorm als de reden ertoe doet:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ De uitkomsten zijn accept, reject, sanitize en
+ unspecified. De redenen zijn een gesloten lijst zodat een rapport erop kan
+ groeperen: content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit en
+ size_zero.
+
+
+ Een reden noemt de regel die in het spel is, niet het oordeel. Daarom kan dezelfde
+ reden onder beide uitkomsten staan - een bestand één byte onder een limiet is
+ accept, en de regel waar het om gaat is nog steeds size_limit.
+
+
+
+
+
Wat staat er in het manifest?
+
+ Het wordt aan het einde van elke run naast de bestanden geschreven, ook bij een onderbroken run. Eén
+ item per bestand:
+
+ Er komt een recipe_hash bij als de run uit een recept kwam, en preset met
+ overrides als hij uit een preset kwam, zodat een manifest altijd te herleiden is
+ tot wat het maakte.
+
+
+ Elk item draagt ook target_id, de id van het target in het recept dat het bestand
+ maakte, en summary.by_target telt de bestanden waar elk target op uitkwam. Een
+ recept met meerdere targets kan zo target voor target worden gecontroleerd zonder bestandsnamen
+ te lezen.
+
+
+
+
+
Wat is een preset?
+
+ Een kant-en-klare set bestanden die een veelvoorkomende testvraag beantwoordt, zodat je de set niet
+ zelf hoeft te ontwerpen. Presets zijn gewone recepten onder de motorkap, en eject
+ drukt het recept af zodat je het vanaf daar kunt bewerken. Elke preset heeft
+ een eigen pagina met wat hij meestal vindt, wat er in de set zit en
+ welke instellingen hij kent.
+
+ show zegt je wat de set zou kosten voordat je hem bouwt, en zegt zonder omwegen wanneer
+ een getal een tijdelijke waarde van ons is in plaats van een limiet van jou.
+
+
+
+
+
Wat betekenen de afsluitcodes?
+
+ Elk einde heeft zijn eigen code, machineleesbare uitvoer gaat naar de standaarduitvoer, en een
+ mislukte run drukt daar niets af. De tabel is een bevroren contract - de betekenis van een code
+ wijzigen vereist een major-versie.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Een run die met Ctrl+C is gestopt laat nog steeds een manifest achter en nooit een half geschreven
+ bestand, zodat een afgebroken taak door de volgende nog kan worden opgeruimd.
+
+ Ja, dezelfde engine met een venster erop, voor het testen dat niet geautomatiseerd is. Het is geen
+ uitgeklede versie: een test vergelijkt de twee interfaces mogelijkheid voor mogelijkheid, en
+ alles wat maar één van beide kan moet worden verklaard en gerechtvaardigd in plaats van
+ ongemerkt uit elkaar te drijven.
+
+
+ De schermen zijn één batch, presets, meerdere batches tegelijk en info. Het toont wat een run zou
+ kosten voordat er iets wordt geschreven, meldt de voortgang terwijl het draait en kan halverwege
+ worden afgebroken zonder een half geschreven bestand achter te laten. Het opent nog geen
+ receptbestand - recepten zijn voorlopig iets van de opdrachtregel, en het venster bouwt zijn
+ batches in het formulier.
+
+
diff --git a/web/content/nl/exact-size.html b/web/content/nl/exact-size.html
new file mode 100644
index 00000000..b7e86c8f
--- /dev/null
+++ b/web/content/nl/exact-size.html
@@ -0,0 +1,149 @@
+
Hoe maak je een bestand van een exacte grootte
+
+ Elk systeem heeft er een opdracht voor, en alle drie staan hieronder. Ze geven je een bestand met
+ precies het juiste aantal bytes - en voor veel tests is dat alles wat je nodig hebt. Elke
+ opdracht op deze pagina is uitgevoerd vóór publicatie, op het systeem waartoe hij
+ behoort.
+
+
+
+
Het korte antwoord
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Groottes zijn in bytes, en 10 MB
+ geteld zoals je bestandsbeheer telt is 10485760.
+
+
+
+
+
Windows
+
fsutil, en een PowerShell-versie die niets extra's nodig heeft
+
+ fsutil wordt met Windows meegeleverd. Het neemt de grootte in bytes,
+ reken het getal dus eerst uit - 10 MB is 10485760, 100 MB is 104857600, 1 GB is 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Gemeten op Windows 11: het werkt vanaf een gewone prompt en heeft geen verhoogde nodig, en het
+ bestand komt uit op precies 10485760 bytes.
+
+
PowerShell kan hetzelfde zonder een ander programma aan te roepen, en begrijpt eenheden:
+ 10MB betekent in PowerShell 10485760 bytes, dezelfde telling op basis van 1024 die
+ Verkenner gebruikt, dus de twee opdrachten hierboven geven dezelfde grootte.
+
+
+
+
+
Linux
+
dd, truncate en fallocate, en het verschil dat mensen te pakken neemt
+
dd is degene die iedereen kent. Het schrijft de bytes echt:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate is direct klaar, en dat is de adder onder het gras. Gemeten op Alpine Linux
+ meldt het bestand 10485760 bytes en neemt het nul blokken in beslag - het is
+ een sparse bestand. Alles wat het leest krijgt tien megabyte aan nullen, maar
+ de schijf heeft de ruimte nooit afgestaan:
+
+
truncate -s 10M test10mb.bin
+
+ Dat is prima om een uploadlimiet te testen en misleidend om een schijfquotum te testen.
+ fallocate is degene waar je naar grijpt als de ruimte echt moet zijn:
+
+
fallocate -l 10M test10mb.bin
+
En als de inhoud onsamendrukbaar moet zijn, zodat een archiefprogramma hem niet weer kan verkleinen:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, dat niet sparse is, en de twee die je al kent
+
+ macOS levert mkfile mee. Gemeten op macOS 26.6.2: 10485760 bytes en 20480 blokken, dus
+ de ruimte is echt toegewezen in plaats van beloofd:
+
+
mkfile 10m test10mb.bin
+
dd en truncate zijn er ook en gedragen zich zoals op Linux:
Een bestand van de juiste grootte is geen bestand van het juiste soort
+
+ Alles hierboven geeft je een blok nullen. Dat is genoeg als wat getest wordt alleen naar de grootte
+ kijkt - een uploadlimiet, een quotum, een overdracht. Het is niet meer genoeg zodra iets het
+ bestand opent.
+
+
+ Gemeten, en het is de moeite waard om het zelf te doen: maak een bestand van 2 MB met
+ fsutil, noem het photo.png en geef het aan een afbeeldingsbibliotheek.
+ Pillow antwoordt cannot identify image file. Het is geen PNG. Dat is het ook nooit
+ geweest - alleen de naam zei het.
+
+
+ Dat doet er meer toe dan het klinkt, vanwege de kant waarop de test dan faalt. Je
+ upload-endpoint weigert het bestand, je test wordt groen en je concludeert dat de groottelimiet
+ werkt. Het weigerde het niet vanwege de grootte. Het weigerde het omdat de bytes geen afbeelding
+ waren, en de regel die je wilde testen is nooit bereikt.
+
+
+
een parser weigert het voordat een groottegrens wordt bekeken
+
een miniatuurstap faalt en de fout die je leest gaat over het miniatuur
+
een virusscanner of inhoudscontrole weigert het om een derde reden
+
een viewer toont niets, en niemand kan zeggen of dat de bug is
+
+
+
+
+
De andere weg
+
Een echt bestand van dat formaat, in precies de grootte die je vroeg
+
+ Dit is wat Testing Files Generator doet. Het bestand is een echt bestand van zijn formaat - het
+ opent in het programma waartoe het behoort - en het heeft het exacte aantal bytes dat je vroeg,
+ tot op de byte:
+
+ Vraag een grootte die een formaat niet kan halen en je krijgt een fout die de ondergrens en de reden
+ noemt, nooit een bestand van de verkeerde grootte. De pagina met
+ formaten toont elk formaat met het kleinste bestand dat het kan maken.
+
+
En een limiet is drie testgevallen in plaats van één, dus de tool bouwt ze alle drie:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Dat geeft je 10485759, 10485760 en 10485761 bytes, en een manifest dat zegt welke je systeem moet
+ accepteren en welke het moet weigeren. De pagina met
+ toepassingen loopt dat en vier andere taken door waarvoor het is gebouwd.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Dus wat moet je gebruiken?
+
+
+
Gebruik de systeemopdracht
+
+ Als niets het bestand opent. Een groottelimiet testen op een endpoint dat eerst de grootte
+ controleert, een overdracht, een quotum, een volle schijf. Het is één regel en het is al
+ geïnstalleerd.
+
+
+
+
Gebruik een echte generator
+
+ Als iets het bestand parset, rendert, importeert of uitpakt - en als je morgen op een andere machine
+ dezelfde fixtures nodig hebt, byte voor byte.
+
+
+
+
+ Beide staan op deze pagina omdat beide soms goed zijn. De fout die je moet vermijden is de eerste
+ gebruiken waar de tweede nodig is en de groene test als bewijs lezen.
+
+
diff --git a/web/content/nl/faq.html b/web/content/nl/faq.html
new file mode 100644
index 00000000..901354b5
--- /dev/null
+++ b/web/content/nl/faq.html
@@ -0,0 +1,20 @@
+
Veelgestelde vragen
+
+ Licentie, privacy, reproduceerbaarheid en de dingen die mensen nagaan voordat ze een generator in
+ een buildpipeline zetten. Staat je vraag er niet bij, dan staat de
+ issuetracker open.
+
{{ .Facts.FormatCount }} bestandsformaten, elk gegenereerd in een exacte grootte
+
+ Elk daarvan is een echt bestand van dat formaat. Het opent in het programma waartoe
+ het behoort en is precies het aantal bytes dat je vroeg. Geen enkele is opgevulde nullen met een
+ extensie eraan geplakt.
+
+
+{{ template "formatsTable" . }}
+
+
+
Wat de kolommen betekenen
+
+
+
Kleinste bestand
+
+ Het minste aantal bytes dat deze tool voor dat formaat accepteert, inclusief het label dat hij in
+ het bestand schrijft. Vraag je minder, dan krijg je een fout die de ondergrens en de reden
+ noemt, nooit een bestand van de verkeerde grootte.
+
+
+
+
Volledigheid
+
+ Hoe volledig het bestand is. full betekent dat een lezer die het formaat echt parset
+ het accepteert, niet alleen dat de extensie klopt.
+
+
+
+
Gecontroleerd met
+
+ De onafhankelijke lezer die elk gegenereerd bestand opent voordat het formaat wordt uitgebracht -
+ een aparte implementatie, niet onze eigen code die haar eigen huiswerk nakijkt.
+
+
+
+
+ Elk formaat herhaalt zich ook tot op de byte: hetzelfde recept en dezelfde seed geven op elke
+ machine identieke bestanden, en daardoor is het veilig een recept te committen in plaats van de
+ fixtures zelf.
+
+
+
+
+
Instellingen die elk formaat accepteert
+
+ De meeste formaten hebben eigen instellingen - afbeeldingsafmetingen, JPEG-kwaliteit, aantal
+ PDF-pagina's, rijen en kolommen in een spreadsheet, hoeveel items er in een archief zitten. Stel
+ ze in met --set key=value op de opdrachtregel, of onder properties: in
+ een recept.
+
+ Een waarde buiten wat een instelling accepteert wordt geweigerd met een melding die de instelling,
+ het toegestane bereik en het alternatief noemt. Een onbekende instelling is ook een fout, nooit
+ een stille standaardwaarde - een stilzwijgend geaccepteerde typefout geeft een bestand met de
+ verkeerde instellingen en een uur zoeken waarom de test slaagt terwijl dat niet zou moeten.
+
+
+ Draai tfg formats <id> om precies te zien wat één formaat accepteert in de build
+ die je hebt.
+
+
+
+
+
Archieven bevatten echte bestanden
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} en {{ end }}{{ $c.ID }}{{ end }}
+ kunnen met items worden gevuld in plaats van als lege huls te blijven. Een gegenereerd archief
+ bevat echt de documenten die het zegt te bevatten, dus alles wat het tijdens een test uitpakt
+ vindt er echte bestanden in.
+
Genereer echte testbestanden in elke exacte grootte
+
+ PDF, PNG, DOCX, ZIP - {{ .Facts.FormatCount }} formaten in totaal, en elk is een
+ echt bestand dat opent in het programma waartoe het behoort, in precies de grootte die
+ je vroeg. Elke run schrijft ook op wat je applicatie met elk bestand moet doen.
+ Opdrachtregel en bureaubladvenster, gratis en open source, volledig op je eigen machine.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ Het bureaubladvenster, klaargezet om een reeks bestanden te schrijven. Dezelfde engine draait achter de opdrachtregel.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
echte formaten, elk opent in het programma waartoe het behoort
+
+
+ 1 byte
+
de nauwkeurigheid van elke grootte die je vraagt, nooit stilzwijgend afgerond
+
+
+ 0
+
verbindingen naar wat dan ook - geen account, geen telemetrie, geen updatecontrole
+
+
+
+
+
Het probleem
+
Eén testbestand maken is makkelijk. De juiste duizend maken is het vervelende deel
+
Je test software die bestanden van mensen aanneemt. Vroeg of laat heb je nodig:
+
+
een PDF van precies 10 MB, om uit te zoeken of de uploadlimiet echt is
+
de drie bestanden aan weerszijden van die limiet, om off-by-one-fouten te vangen
+
10.000 logbestanden, om te zien wat de nachtelijke taak doet als de map groot is
+
een ZIP die echt 200 documenten bevat, geen lege huls met de juiste extensie
+
een bestand van 4 GB, zonder een bestand van 4 GB in je repository te bewaren
+
dezelfde fixtures op je laptop en op de buildserver, byte voor byte
+
+
+ Dat is wat dit vervangt. Het is gebouwd voor QA-engineers, testautomatisering en iedereen wiens code
+ een uploadformulier, een importroutine, een parser of een opslagquotum achter zich heeft.
+
+
+
+
+
Wat het anders maakt
+
Andere generatoren stoppen bij de bytes. Deze beantwoordt wat je test werkelijk vraagt
+
+ Een map met bestanden laat je nog steeds beslissen wat elk bestand moet bewijzen. Elke run schrijft
+ hier een manifest.json naast de bestanden - een eenvoudige lijst van alles wat is
+ gemaakt, en bij elk item een gedeclareerde verwachting.
+
+
Stel dat je upload-endpoint 1 MB toestaat. Vraag de drie bestanden die op die lijn zitten:
Drie bestanden, drie verschillende antwoorden, in machineleesbare vorm. Je test leest het manifest in plaats van dat jij de asserties met de hand schrijft:
Waar het antwoord van je eigen beleid afhangt, zegt het manifest dat
+
+ Het legt unspecified vast in plaats van een verwachting te verzinnen. Een generator die
+ gokt levert valse fouten op, en een suite die loos alarm slaat wordt uitgezet.
+
+
+
+
+
+
Presets
+
Kies de vraag, krijg de hele set
+
+ Een preset is een set testbestanden ontworpen rond één testvraag, zodat je zelf niet hoeft uit te
+ zoeken welke bestanden wat bewijzen. Elke heeft een pagina die zegt wat hij meestal vindt, wat
+ er in de set zit en welke instellingen hij kent.
+
+ Tienduizend logbestanden, elk tussen één en acht kilobyte, met groottes getrokken uit de seed zodat
+ morgen dezelfde set oplevert. Geef elke run een eigen map - het manifest is
+ het enige verslag van wat een run schreef, dus de tool weigert er een tweede overheen te
+ schrijven:
+
+ Groottes tellen in 1024-tallen, zoals je bestandsbeheer doet, dus 2mb betekent 2097152
+ bytes. Een gewoon aantal bytes werkt ook. De documentatie
+ behandelt recepten, het manifest en de afsluitcodes.
+
+
+
+
+
Wat je krijgt
+
Gebouwd voor een suite die onbeheerd draait
+
+
+
Exacte grootte, tot op de byte
+
Vraag 10485761 bytes en krijg precies dat. Een grootte die een formaat niet kan halen is een fout met een reden, nooit een bestand van de verkeerde grootte.
+
+
+
{{ .Facts.FormatCount }} echte formaten
+
Geen opgevulde nullen met een extensie. Een gegenereerde PNG opent in een afbeeldingsviewer, een DOCX opent in Word, een ZIP pakt uit. Elk wordt vóór levering gecontroleerd met onafhankelijke lezers.
+
+
+
Een manifest dat een testorakel is
+
Pad, grootte, SHA-256, formaat, seed, toolversie - en wat je systeem met het bestand moet doen.
+
+
+
Reproduceerbaar
+
Hetzelfde recept en dezelfde seed, dezelfde bytes, op elke machine. Commit een klein YAML-recept in plaats van grote binaire fixtures.
+
+
+
Twee interfaces, één engine
+
Een opdrachtregel gebouwd voor CI en een bureaubladvenster voor verkennend testen. Geen van beide is een uitgeklede versie van de ander, en een test vergelijkt ze mogelijkheid voor mogelijkheid.
+
+
+
Volledig offline
+
Geen account, geen cloud, geen telemetrie, geen updatecontrole. In de opdrachtregel-binary is helemaal geen netwerkstack gecompileerd.
+
+
+
+
+
+
Download
+
Kies de build voor je systeem
+
+ Pak het archief uit en start het. tfg is de opdrachtregel en tfg-gui is
+ het bureaubladvenster. Er is geen installatieprogramma en niets om aan je machine toe te voegen.
+
+ {{ template "downloadsTable" . }}
+
+
Wat is ondertekend, en wat niet
+
+ De downloads voor Windows en macOS zijn ondertekend, dus ze starten zonder waarschuwing over een
+ onbekende ontwikkelaar. Die voor Linux niet, omdat desktop-Linux niets vergelijkbaars heeft om
+ ze mee te ondertekenen. Elk archief staat in verify-SHA256SUMS.txt op de
+ releasepagina, zodat je kunt controleren wat je hebt gedownload.
+
+ De preset {{ .ID }} bouwt met één opdracht een hele set echte testbestanden voor deze
+ vraag, en een manifest.json ernaast dat zegt hoe je systeem op elk bestand moet
+ reageren. Alles hieronder wordt uit het programma gelezen, bij de standaardwaarden van deze
+ versie.
+
+
+{{ if .Catches }}
+
+
Wat vindt hij meestal?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
Wat zit er in de set?
+
Bij de standaardwaarden, zoals tfg preset show {{ .ID }} het meldt:
+
+
+
+
Bestanden
{{ .Budget.Files }}
+
Targets in het recept
{{ .Budget.Targets }}
+
Totale grootte
{{ .Bytes }} B
+
Formaten
{{ join .Budget.Formats ", " }}
+
+
+
+
En wat het manifest van die set van je systeem verwacht:
+
+
+
+
Verwacht
Betekenis
Bestanden
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
Wat kun je wijzigen?
+ {{- if .Settings }}
+
+
+
+
Instelling
Accepteert
Standaard
Wat het doet
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Deze standaardwaarde is onze tijdelijke waarde, niet de waarde van je systeem. Geef je eigen op.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
Deze preset heeft geen instellingen. De set is elke keer dezelfde.
+ {{- end }}
+
+
+
+
Hoe draai je hem?
+
Bekijk wat de set zou kosten, bouw hem, of neem zijn recept om te bewerken:
Of bouw erop voort in een eigen recept, naast je tests:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/nl/presets.html b/web/content/nl/presets.html
new file mode 100644
index 00000000..ebfabce3
--- /dev/null
+++ b/web/content/nl/presets.html
@@ -0,0 +1,31 @@
+
Presets voor testbestanden, een set voor elke testvraag
+
+ Een preset is een hele set testbestanden ontworpen rond één vraag, met een manifest dat zegt hoe je
+ systeem op elk bestand moet reageren. Jij kiest de vraag, de tool bouwt de set. Elke preset heeft
+ een eigen pagina met wat hij meestal vindt, wat er in de set zit en welke instellingen hij kent.
+
+
+{{ template "presetsList" . }}
+
+
+
Hoe verschilt een preset van een recept?
+
+ Eronder niet. Een preset is een recept dat de tool voor je schrijft uit een paar instellingen.
+ tfg preset eject drukt dat recept af zodat je het naast je tests kunt bewaren en
+ bewerken, en een eigen recept kan met één regel op een preset voortbouwen, extends:
+ preset: gevolgd door zijn id.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Kan ik de standaardwaarden vertrouwen?
+
+ Voor de bestanden wel. Voor een getal dat alleen je systeem kent, zoals de limiet van een
+ uploadformulier, is een standaardwaarde een tijdelijke waarde van ons, en de tool zegt dat elke
+ keer dat hij er een gebruikt. De pagina van elke preset markeert die instellingen, en tfg
+ preset show zegt het voordat er iets wordt geschreven.
+
+
diff --git a/web/content/nl/site.json b/web/content/nl/site.json
new file mode 100644
index 00000000..93c57e0b
--- /dev/null
+++ b/web/content/nl/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "nl",
+ "locale": "nl_NL",
+ "name": "Nederlands",
+ "dir": "nl",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Home",
+ "title": "Testbestanden genereren - exacte grootte, {{ .Facts.FormatCount }} echte formaten",
+ "description": "Gratis open source generator van testbestanden voor QA. Echte PDF-, DOCX-, PNG- en ZIP-bestanden in exacte grootte, met een manifest over de verwachte reactie."
+ },
+ {
+ "key": "formats",
+ "slug": "formaten",
+ "nav": "Formaten",
+ "title": "{{ .Facts.FormatCount }} ondersteunde bestandsformaten - PDF, DOCX, PNG, ZIP en meer",
+ "description": "Alle bestandsformaten die deze generator maakt, het kleinst mogelijke bestand per formaat en hun instellingen. Alle {{ .Facts.FormatCount }} openen in hun eigen programma."
+ },
+ {
+ "key": "presets",
+ "slug": "presets",
+ "nav": "Presets",
+ "title": "Presets voor testbestanden - kant-en-klare sets voor QA",
+ "description": "Kant-en-klare sets testbestanden, elk beantwoordt een testvraag: uploadlimieten, bestandsnamen, tekencoderingen, tabelimport, lege bestanden en uploadvalidatie."
+ },
+ {
+ "key": "docs",
+ "slug": "documentatie",
+ "nav": "Documentatie",
+ "title": "Documentatie - opdrachten, recepten, manifest, afsluitcodes",
+ "description": "Hoe je testbestanden genereert vanaf de opdrachtregel of met een YAML-recept, wat het manifest bevat en wat elke afsluitcode betekent wanneer de tool in CI draait."
+ },
+ {
+ "key": "use-cases",
+ "slug": "toepassingen",
+ "nav": "Toepassingen",
+ "title": "Toepassingen - uploadlimieten, CI-fixtures, massatests",
+ "description": "Een uploadlimiet testen, reproduceerbare fixtures voor CI bouwen, tienduizend bestanden genereren en archieven vullen met echte inhoud."
+ },
+ {
+ "key": "exact-size",
+ "slug": "bestand-met-exacte-grootte-maken",
+ "nav": "Exacte grootte",
+ "title": "Een bestand van een exacte grootte maken - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate en mkfile, elk gemeten op het systeem waarvoor het bedoeld is, en waarom zo'n bestand geen PDF of PNG is wanneer een test dat nodig heeft."
+ },
+ {
+ "key": "faq",
+ "slug": "veelgestelde-vragen",
+ "nav": "FAQ",
+ "title": "FAQ - vragen over het genereren van testbestanden",
+ "description": "Hoe dit verschilt van dd en fsutil, of je de bestanden kunt committen, of runs byte voor byte herhaalbaar zijn en wat er gebeurt als een grootte onhaalbaar is."
+ },
+ {
+ "key": "damage",
+ "slug": "beschadigde-testbestanden",
+ "nav": "Beschadigde bestanden",
+ "title": "Beschadigde testbestanden - kapotte bestanden op exacte grootte",
+ "description": "Een bestand dat met opzet kapot is, op exacte grootte, met een manifest dat zegt dat je systeem het moet weigeren. Voor het testen van uploadvalidatie en parsers.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "testbestanden-in-ci",
+ "nav": "Testbestanden in CI",
+ "title": "Testbestanden in CI - GitHub Actions, GitLab CI en PowerShell",
+ "description": "Genereer testbestanden in de pipeline in plaats van binaire bestanden te committen: GitHub Actions-workflow, GitLab-job, afsluitcodes en de PowerShell-valkuil.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "Direct naar de inhoud",
+ "navLabel": "Hoofdmenu",
+ "langLabel": "Taal",
+ "breadcrumbHome": "Home",
+ "imageAlt": "Testing Files Generator - echte testbestanden in elke exacte grootte, met een manifest dat zegt hoe je systeem op elk bestand moet reageren",
+ "schemaDescription": "Een gratis open source generator van testbestanden voor QA. Hij maakt echte bestanden in {{ .Facts.FormatCount }} formaten in elke exacte grootte en schrijft een manifest dat zegt hoe het geteste systeem op elk bestand moet reageren.",
+ "ctaDownload": "Downloaden",
+ "ctaSource": "Bekijk de broncode",
+ "ctaNote": "Gratis en open source, GPL-3.0. Geen account nodig. De downloads voor Windows en macOS zijn ondertekend en starten zonder waarschuwing.",
+ "colFormat": "Formaat",
+ "colName": "Naam",
+ "colExtension": "Extensie",
+ "colSmallest": "Kleinste bestand",
+ "colFidelity": "Volledigheid",
+ "colChecked": "Gecontroleerd met",
+ "colSetting": "Instelling",
+ "colAccepts": "Accepteert",
+ "colSystem": "Systeem",
+ "colCli": "Opdrachtregel",
+ "colWindow": "Bureaubladvenster",
+ "noBinary": "nog geen binary",
+ "colCode": "Code",
+ "colMeaning": "Betekenis",
+ "footerBlurb": "Testbestanden voor QA, in elke exacte grootte, met een manifest dat zegt hoe je systeem op elk bestand moet reageren.",
+ "footerProject": "Project",
+ "footerSource": "Broncode op GitHub",
+ "footerReleases": "Downloads",
+ "footerIssues": "Een probleem melden",
+ "footerSupport": "Steun het project",
+ "footerPages": "Pagina's",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. Uitgebracht onder de GNU General Public License, versie 3. De bestanden die je genereert zijn van jou - de licentie geldt voor de tool, niet voor de uitvoer.",
+ "footerPrivacy": "Deze site laadt nergens vandaan lettertypen, scripts of trackers. Hij plaatst geen cookies.",
+ "notFoundTitle": "Die pagina bestaat niet",
+ "notFoundLead": "Het adres dat je volgde komt met geen enkele pagina op deze site overeen.",
+ "notFoundBack": "Naar de startpagina",
+ "read.format": "Het formaat van elk bestand in de set. Het is een optie van de tool zelf, en de preset geeft er alleen een standaardwaarde aan.",
+ "readTakes.format": "een formaat-id van de pagina met formaten",
+ "colDamage": "Beschadiging",
+ "colEffect": "Wat het met de bytes doet",
+ "colSettings": "Instellingen",
+ "noSettings": "geen"
+ },
+ "endings": {
+ "0": "Alles werkte.",
+ "1": "Een onverwachte fout in de tool.",
+ "2": "Verkeerde opdracht of optie.",
+ "3": "Het recept is niet geldig.",
+ "4": "Het formaat kan niet wat er gevraagd werd.",
+ "5": "Een lees- of schrijfactie is mislukt.",
+ "6": "Niet genoeg schijfruimte.",
+ "7": "verify vond een afwijking.",
+ "8": "De run is klaar, maar niet alles is gemaakt.",
+ "130": "Onderbroken met Ctrl+C.",
+ "143": "Gestopt door een signaal, zo ziet een CI-timeout eruit."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "Komt een geldig bestand dat zo klein is als het formaat toestaat door de controle?",
+ "title": "Leeg en minimaal",
+ "pageTitle": "Kleinste geldige en lege testbestanden in elk formaat",
+ "description": "Het kleinste geldige bestand dat deze tool schrijft in elk van zijn {{ .Facts.FormatCount }} formaten, plus een leeg bestand waar het formaat dat toestaat, elk met de verwachte reactie.",
+ "catches": [
+ "een geldig bestand dat als te klein wordt geweigerd, omdat de controle bytes telt in plaats van ze te lezen",
+ "een leeg bestand dat de lezer laat crashen in plaats van gemeld te worden",
+ "een afbeelding van één pixel breed die op weg naar het miniatuur door nul deelt",
+ "opslag die nul bytes als een mislukte upload leest en blijft opnieuw proberen"
+ ],
+ "details": {
+ "formats": "Uit welke formaten de set is opgebouwd. Laat het op all staan voor elk formaat van deze build, of noem de formaten die je systeem accepteert."
+ }
+ },
+ "filename-handling": {
+ "question": "Slaat mijn systeem een bestandsnaam op, toont en geeft het die terug, ook als het die niet verwachtte?",
+ "title": "Omgaan met bestandsnamen",
+ "pageTitle": "Lastige bestandsnamen om te testen - Unicode en lengte",
+ "description": "Testbestanden met namen die uploads en opslag laten haperen: andere schriften, emoji, omgekeerde schrijfrichting, onzichtbare tekens, shell- en SQL-syntaxis.",
+ "catches": [
+ "een naam die er op het scherm, in een log of in een lijst als een andere uitziet",
+ "een naam die tussen upload en opslag wordt afgekapt, ingekort of herschreven",
+ "een lengtelimiet die in tekens wordt geteld waar de opslag bytes telt"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "Wordt een groottelimiet precies afgedwongen waar hij is opgegeven?",
+ "title": "Groottegrenzen",
+ "pageTitle": "Een uploadlimiet testen - bestanden precies op de grens",
+ "description": "Bestanden één byte onder, precies op en één byte boven de limiet van je systeem, plus bredere stappen aan beide kanten, elk gemarkeerd of het geaccepteerd moet worden.",
+ "catches": [
+ "off-by-one-fouten bij de limiet",
+ "MB verward met MiB, wat 4,8 procent is en genoeg om een bestand door te laten dat niet door zou mogen",
+ "een limiet die in de browser wordt afgedwongen en niet op de server"
+ ],
+ "details": {
+ "limit": "De groottelimiet die je systeem opgeeft. Al het andere wordt hiervan afgemeten.",
+ "spread": "Hoe ver aan beide kanten van de limiet te gaan, als een lijst met groottes."
+ }
+ },
+ "tabular-import": {
+ "question": "Overleeft mijn tabelimport wat echte tools exporteren?",
+ "title": "Tabelimport",
+ "pageTitle": "Testbestanden voor CSV- en Excel-import - scheidingstekens",
+ "description": "CSV met andere scheidingstekens, CR LF-regeleinden, zonder koprij en met andere aanhalingstekens, een heel brede tabel, een Excel-werkmap en JSON in meerdere lay-outs.",
+ "catches": [
+ "een bestand met puntkomma's dat als één kolom wordt gelezen, omdat het scheidingsteken is aangenomen in plaats van gezocht",
+ "een CRLF-bestand dat in rijen wordt gesplitst met na elke rij een lege rij",
+ "een tabel zonder koprij waarvan de eerste gegevensrij als kolomnamen wordt opgegeten",
+ "een import die de kolommen houdt die hij kan tonen en de rest zonder een woord weggooit",
+ "een lezer die JSON-records regel voor regel leest en stopt bij het eerste ingesprongen document"
+ ],
+ "details": {
+ "rows": "Hoeveel rijen de spreadsheet bevat. Het bestand wordt precies zo groot geschreven als zoveel rijen verpakt worden, dus het budget hierboven verschuift met deze waarde.",
+ "columns": "Hoeveel kolommen elke rij van de spreadsheet heeft. Rijen maal kolommen heeft een plafond, en erboven vragen wordt geweigerd voordat er iets geschreven wordt."
+ }
+ },
+ "text-encoding": {
+ "question": "Weet mijn lezer in welke codering een bestand staat, of gokt hij?",
+ "title": "Tekencodering",
+ "pageTitle": "Testbestanden voor tekencodering - UTF-8, UTF-16, BOM, CRLF",
+ "description": "Dezelfde tekst in UTF-8, UTF-16LE en UTF-16BE, met en zonder byte order mark, en regeleinden in CR LF en LF, om te testen hoe een lezer tekst decodeert.",
+ "catches": [
+ "een lezer die UTF-8 aanneemt en een UTF-16-bestand toont als één teken op de drie, of als rijen vakjes",
+ "een byte order mark die als inhoud wordt gelezen, zodat het eerste veld van een import met drie vreemde tekens begint",
+ "een importeur die de codering uit de eerste bytes raadt en bij een langer bestand anders raadt",
+ "een CRLF-bestand dat in rijen wordt gesplitst met na elke rij een lege rij, of een regelterugloop die in het laatste veld blijft staan"
+ ],
+ "details": {
+ "sample": "Hoe groot elk bestand van de set is. UTF-16 slaat twee bytes per teken op, dus een oneven getal wordt geweigerd."
+ }
+ },
+ "upload-validation": {
+ "question": "Neemt mijn uploadformulier aan wat het moet en weigert het de rest?",
+ "title": "Uploadvalidatie",
+ "pageTitle": "Testbestanden voor uploadvalidatie - type, grootte en naam",
+ "description": "Bestanden om een uploadformulier te testen: toegestane en geweigerde typen, inhoud die niet bij de extensie past, groottelimiet, vijandige namen en een bulkupload.",
+ "catches": [
+ "een limiet die in de browser wordt afgedwongen en niet op de server",
+ "een SVG- of HTML-bestand dat voor een afbeelding of platte tekst wordt aangezien, een manier om een script langs een formulier te smokkelen",
+ "een bestand dat op extensie wordt gecontroleerd en nooit geopend, zodat een PDF met de naam .jpg erdoor komt",
+ "een formulier dat de hele body in het geheugen leest voordat het kijkt hoe groot hij is",
+ "een upload met de naam PHOTO.JPG die wordt geweigerd terwijl photo.jpg wordt aangenomen, of andersom",
+ "een naam met spaties, haakjes of tekens buiten ASCII die ongewijzigd naar schijf wordt geschreven"
+ ],
+ "details": {
+ "limit": "De groottelimiet die je uploadformulier opgeeft. Deze set zet één stap aan beide kanten - voor een bestand op elke afstand draai je de preset size-boundaries.",
+ "allow": "Welke typen je formulier moet accepteren. Elk wordt een echt bestand van dat type, en ze vormen de positieve controle van de hele set.",
+ "deny": "Welke extensies je formulier moet weigeren. Een extensie waarvoor deze build geen formaat heeft, krijgt toch een bestand met die naam, met platte tekst erin.",
+ "far-over": "Hoe ver boven de limiet het ene grote bestand komt. Zet het uit waar het schrijven van een veelvoud van de limiet de schijfruimte niet waard is.",
+ "bulk": "Hoeveel bestanden de bulkupload bevat. Nul laat die groep helemaal uit de set."
+ }
+ }
+ },
+ "commands": {
+ "generate": "bestanden maken, uit een recept of met opties",
+ "validate": "een recept controleren en niets schrijven",
+ "verify": "een map controleren tegen een manifest",
+ "cleanup": "de bestanden verwijderen die een manifest opsomt",
+ "recipe fmt": "een recept in zijn vaste vorm afdrukken",
+ "preset": "een set bestanden bouwen uit een benoemde testvraag",
+ "formats": "de formaten opsommen die deze build ondersteunt",
+ "damage": "de manieren opsommen waarop deze build een bestand met opzet kan beschadigen",
+ "tool": "kleine hulpmiddelen voor bestanden die je al hebt",
+ "version": "de versie van de tool tonen",
+ "license": "de licentie tonen en wat die betekent voor gegenereerde bestanden"
+ },
+ "outcomes": {
+ "accept": "Je systeem moet het bestand aannemen.",
+ "reject": "Je systeem moet het bestand weigeren.",
+ "sanitize": "Je systeem moet het bestand aannemen en opschonen, bijvoorbeeld door het te hernoemen.",
+ "unspecified": "Het hangt af van de regels van je systeem. Jij beslist, en controleert daarna of wat er gebeurt is wat je bedoelde."
+ },
+ "damages": {
+ "zero-head": "Overschrijft de eerste bytes van het bestand met nullen en laat de lengte ongemoeid. De meeste lezers kijken daar eerst, dus bijna alles merkt deze beschadiging."
+ },
+ "terms": {
+ "oracleNone": "niet van toepassing",
+ "int": "elk geheel getal",
+ "choice": "een uit een vaste verzameling",
+ "bool": "waar of onwaar",
+ "size": "een grootte zoals 2mb",
+ "text": "tekst",
+ "pixels": "pixels",
+ "paragraphs": "alinea's",
+ "rows": "rijen",
+ "columns": "kolommen",
+ "slides": "dia's",
+ "hertz": "hertz",
+ "megapixels": "megapixels",
+ "million cells": "miljoen cellen",
+ "entries per second": "items per seconde",
+ "files": "bestanden",
+ "sizes separated by commas": "groottes gescheiden door komma's",
+ "format ids separated by commas": "formaat-id's gescheiden door komma's",
+ "format ids separated by commas, or all": "formaat-id's gescheiden door komma's, of all",
+ "extensions separated by commas": "extensies gescheiden door komma's",
+ "the id of a format, as tfg formats lists them": "de id van een formaat, zoals tfg formats ze opsomt",
+ "the password, in plain text": "het wachtwoord, als platte tekst",
+ "any text": "willekeurige tekst",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "een datum zoals 2024-02-29 of 2024-02-29T13:45:00+02:00, of none"
+ },
+ "faq": [
+ {
+ "q": "Waarin verschilt dit van dd, fsutil of truncate?",
+ "a": "Die geven je een bestand van de juiste grootte vol met niets. Een bestand van 2 MB met de naam photo.png dat zo is gemaakt is geen PNG, dus alles wat het echt parset weigert het om de verkeerde reden, en je test slaagt dan ook om de verkeerde reden. Dit maakt een echte PNG van precies 2 MB die opent in een afbeeldingsviewer, en komt met een verklaring over hoe je systeem ermee om moet gaan.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "Is het gratis, en mag ik het op het werk gebruiken?",
+ "a": "Ja op beide. Het is uitgebracht onder de GPL-3.0 en kost niets. Er is geen account, geen licentiesleutel en geen betaalde variant."
+ },
+ {
+ "q": "Mag ik de gegenereerde bestanden in een closed source product gebruiken?",
+ "a": "Ja. De licentie geldt voor de code van de tool, niet voor wat de tool produceert. Gegenereerde bestanden, recepten en manifesten zijn uitvoer en geen afgeleide werken, dus je kunt ze committen en verspreiden zonder enige verplichting."
+ },
+ {
+ "q": "Bevatten de gegenereerde bestanden echte persoonsgegevens?",
+ "a": "Nee. Alles erin wordt gesynthetiseerd uit een seed. Er wordt geen dataset gelezen, geen dienst benaderd en geen inhoud van derden ingebed. Behandel een gegenereerd e-mailadres als onbruikbaar in plaats van als ongebruikt, want elke willekeurige tekenreeks kan bij toeval samenvallen met een echte."
+ },
+ {
+ "q": "Krijg ik op een andere machine precies dezelfde bestanden?",
+ "a": "Ja, byte voor byte, bij hetzelfde recept en dezelfde seed. Het project test dat bij elke wijziging, en het breken ervan vereist een major-versie. Daardoor kun je een klein recept committen in plaats van grote binaire fixtures."
+ },
+ {
+ "q": "Heeft het een internetverbinding nodig?",
+ "a": "Nooit. Er is geen telemetrie, geen updatecontrole en geen cloudclient, en in de opdrachtregel-binary is helemaal geen netwerkstack gecompileerd. Het werkt op een machine zonder netwerk en binnen een afgesloten bedrijfsomgeving."
+ },
+ {
+ "q": "Wat gebeurt er als ik een grootte vraag die een formaat niet kan halen?",
+ "a": "Je krijgt een fout die het formaat noemt, de kleinst mogelijke grootte, de reden voor die ondergrens en wat je in plaats daarvan kunt doen, en er wordt geen bestand geschreven. De tool rondt een grootte nooit stilzwijgend af. Elke ondergrens staat op de pagina met formaten.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "Kan ik een bewust kapot bestand genereren?",
+ "a": "Ja. Voeg --damage zero-head toe en het bestand komt uit op precies de gevraagde grootte, met de eerste bytes overschreven door nullen, zodat een lezer het weigert, en het manifest zegt dat je systeem het moet weigeren. De details staan op de pagina over beschadigde testbestanden.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "Welke formaten komen er nog?",
+ "a": "7z, mp3 en mp4. Vandaag werken {{ .Facts.FormatCount }} formaten van begin tot eind."
+ },
+ {
+ "q": "Op welke systemen kan ik het draaien?",
+ "a": "De opdrachtregel draait op Windows en Linux, zowel op Intel als op ARM, en op Macs met Apple Silicon. Het bureaubladvenster wordt geleverd voor Windows op Intel, Linux op Intel en Macs met Apple Silicon. Intel-Macs worden niet ondersteund en daar wordt niets voor gebouwd."
+ },
+ {
+ "q": "Moet ik iets installeren?",
+ "a": "Nee. Download het archief voor je systeem, pak het uit en start de binary. Er is geen installatieprogramma, geen runtime om toe te voegen en geen afhankelijkheid om op te lossen. Als je Go hebt, werkt ook één enkele go install-opdracht.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "Waarom is een run over duizenden bestanden trager op Windows?",
+ "a": "Omdat Windows meer rekent voor elk pad dat het bekijkt, en een opdracht die over duizenden bestanden gaat bekijkt duizenden paden. Gemeten op één machine met 3000 bestanden van 1 kB doet verify er ongeveer 0,9 seconde over op Windows en ongeveer 0,2 seconde op Linux in een container. Een korter uitvoerpad maakt het cijfer voor Windows kleiner, omdat elke map boven de bestanden deel uitmaakt van wat wordt bekeken."
+ }
+ ]
+}
diff --git a/web/content/nl/use-cases.html b/web/content/nl/use-cases.html
new file mode 100644
index 00000000..53be7d02
--- /dev/null
+++ b/web/content/nl/use-cases.html
@@ -0,0 +1,132 @@
+
Waar mensen het voor gebruiken
+
+ Vijf taken die in bijna elk project voorkomen dat bestanden van mensen aanneemt, en de opdracht die
+ elk doet. Elk voorbeeld hieronder werkt zoals het is geschreven.
+
+
+
+
Uploadlimieten
+
Testen of een limiet voor bestandsgrootte wordt afgedwongen waar hij zegt dat hij dat doet
+
+ Een limiet is drie testgevallen, niet één: net eronder, precies erop en net erboven. Die met de hand
+ maken betekent bytetellingen uitrekenen en hopen dat je er niet één naast zit. Vraag in plaats
+ daarvan de set:
+
+ Je krijgt drie echte PDF's van 1048575, 1048576 en 1048577 bytes, en een manifest dat zegt dat de
+ eerste twee geaccepteerd moeten worden en de derde geweigerd wegens size_limit. Je
+ test leest de verwachting in plaats van dat jij drie asserties met de hand schrijft - en als de
+ limiet verandert, wijzig je één getal en draai je opnieuw.
+
+
+ Hetzelfde werkt zonder preset als je één set grenzen inline wilt:
+
Fixtures uit de repository houden zonder ze kwijt te raken
+
+ Grote binaire fixtures maken een repository traag om te klonen en lastig te reviewen, en niemand kan
+ zien wat er veranderde toen er een werd vervangen. Een recept is een paar honderd tekens YAML
+ die de identieke bestanden opnieuw opbouwen - byte voor byte, op elke machine -
+ omdat elk bestand is afgeleid van de seed van de run.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Elk einde heeft zijn eigen afsluitcode, dus een pipeline kan een slecht recept onderscheiden van een
+ volle schijf en van een afwijking bij verificatie. Een mislukte run drukt niets af op de
+ standaarduitvoer, waardoor een logparser een fout niet als gegevens leest.
+
+
+
+
+
Schaal
+
Uitzoeken wat er gebeurt als de map groot is
+
+ Importroutines, nachtelijke taken en maplijsten gedragen zich anders bij tienduizend bestanden dan
+ bij tien. Groottes getrokken uit een bereik laten de set op echt verkeer lijken in plaats van op
+ tienduizend identieke bestanden, en de trekking komt uit de seed, dus de set is morgen dezelfde.
+
+ Een run die groter is dan de vrije ruimte op de schijf wordt geweigerd voordat de eerste byte is
+ geschreven, in plaats van de schijf te vullen en halverwege te falen.
+
+
+
+
+
Archieven
+
Een uitpakprogramma testen met een archief dat echt bestanden bevat
+
+ Een leeg archief met de juiste extensie bewijst niets over code die het opent en doorloopt wat erin
+ zit. Declareer de inhoud en het archief bevat die echt:
+
+ Nestdiepte, aantal items en de grootte van wat erin zit zijn allemaal dingen waar een importroutine
+ een mening over heeft, en zo kom je erachter wat die meningen zijn.
+
+
+
+
+
Parsers en viewers
+
Controleren dat je eigen code een formaat leest zoals echte software dat doet
+
+ Elk formaat hier wordt vóór levering gecontroleerd met een onafhankelijke lezer - een PNG wordt
+ geopend en de pixels worden vergeleken, een DOCX wordt teruggelezen door aparte bibliotheken,
+ een archief wordt uitgepakt. Dat betekent dat een bestand dat je parser weigert een bevinding is
+ over je parser, niet over de generator.
+
+ De pagina met formaten toont de instellingen die elk accepteert en het
+ kleinste bestand dat elk kan zijn.
+
+
+
+
+
Handleidingen
+
Twee hiervan in detail
+
+
+ Beschadigde testbestanden - een bestand dat met opzet
+ kapot is, op exacte grootte, met in het manifest wat ermee moet gebeuren.
+
+
+ Testbestanden in CI - een GitHub Actions-workflow, een
+ GitLab-job en de afsluitcodes die een build laten mislukken.
+
+
+
+
+
+
Voor wie dit is
+
+ QA-engineers, testautomatisering en iedereen wiens code een uploadformulier, een importroutine, een
+ parser of een opslagquotum achter zich heeft. Het draait op een machine zonder enig netwerk, wat
+ telt in een afgesloten bedrijfsomgeving waar een generator in de browser geen optie is.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/pl/ci.html b/web/content/pl/ci.html
new file mode 100644
index 00000000..ccdf7f2c
--- /dev/null
+++ b/web/content/pl/ci.html
@@ -0,0 +1,188 @@
+{{ with .Up }}
+ Binarny plik testowy w repozytorium zostaje w jego historii na zawsze, nie da się go ocenić w
+ różnicach i przestaje być możliwy, gdy plik jest duży. Zamiast tego generuj pliki w potoku z
+ przepisu. Przepis jest tekstem, bajty wychodzą za każdym razem takie same, a ostatni krok dowodzi,
+ że nic się nie ruszyło.
+
+
+
+
Krótka odpowiedź
+
+ Zainstaluj tfg, uruchom tfg generate fixtures.yaml --out ./fixtures przed
+ testami, a tfg verify ./fixtures/manifest.json po nich. Oba kroki same przerywają
+ build, z kodem wyjścia mówiącym dlaczego.
+
+
+
+
+
Dlaczego nie commitować
+
Dlaczego pliku testowego nie powinno być w repozytorium
+
+
+ Zostaje w historii. Usunięcie pliku binarnego później nie zmniejsza klonu, bo każda
+ jego wersja nadal tam jest.
+
+
+ Różnice nie pokażą, co się zmieniło. Recenzent widzi, że PDF jest inny, i nic
+ więcej. Przepis zmienia się o jedną linię.
+
+
+ Duże pliki się nie mieszczą. GitHub odrzuca push z plikiem większym niż 100 MB,
+ więc test limitu uploadu 500 MB nie ma czego commitować.
+
+
+
+ Commitować trzeba przepis. Ten sam przepis i ziarno zapisują te same bajty na każdej maszynie, więc
+ plik wygenerowany w potoku jest tym plikiem, który miałeś na laptopie.
+
+
+
+
+
Przepis
+
Przepis, który leży obok testów
+
+ Ten zapisuje dwadzieścia pięć faktur, które powinny zostać przyjęte, i dwa obrazy ponad limitem,
+ które powinny zostać odrzucone, a manifest zapisuje oba oczekiwania:
+
+ Wiersz z sumą kontrolną porównuje archiwum z verify-SHA256SUMS.txt z tego samego
+ wydania. Wersja jest przypięta, więc nowe wydanie nigdy nie zmieni buildu, którego nie ruszałeś.
+
+ Każde zakończenie ma własny kod wyjścia, więc krok sam się przerywa, a log mówi, który to był. Te,
+ które spotyka potok:
+
+
+
3 - przepis jest niepoprawny. Nic nie zapisano, a każdy problem jest nazwany
+
4 - format nie potrafi tego, o co poproszono, na przykład rozmiaru poniżej swojego najmniejszego
+
6 - brakuje miejsca na dysku
+
7 - tfg verify znalazł plik, który nie zgadza się z manifestem
+
8 - przebieg się skończył, ale nie wszystko powstało
+
+
+ Nieudany przebieg nie wypisuje niczego na standardowe wyjście, więc parser logów nigdy nie weźmie
+ błędu za dane. Cała tabela jest na stronie dokumentacji.
+
+
+
+
+
PowerShell
+
Skrypt PowerShella potrzebuje jeszcze jednej linii
+
+ PowerShell nie wynosi kodu wyjścia programu poza plik .ps1. Uruchom go z
+ -File, a skrypt odpowie 0, nawet gdy narzędzie w środku odmówiło
+ pracy, więc build, który powinien być czerwony, robi się zielony. Ostatnia linia to cała
+ poprawka:
+
+ Tak zachowuje się PowerShell, a nie to narzędzie. cmd, bash i
+ zsh nie potrzebują niczego więcej.
+
+
+
+
+
Kilka zadań
+
Przekazywanie plików testowych między zadaniami
+
+ Zwykle nie trzeba ich wysyłać. Skoro ten sam przepis zapisuje te same bajty, każde zadanie może
+ uruchomić własne tfg generate, co jest szybsze niż wysyłanie i pobieranie. Gdy
+ zadanie musi dostać pliki z innego, uruchom tfg verify na manifeście po przesłaniu,
+ a powie, czy to, co dotarło, jest tym, co zapisano.
+
+ Walidator, któremu pokazywano tylko zdrowe pliki, nie został naprawdę przetestowany. Oto jak dostać
+ plik zepsuty celowo, o dokładnie takim rozmiarze, jaki podasz, z manifestem
+ mówiącym, co system ma z nim zrobić.
+
+
+
+
Krótka odpowiedź
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out zapisuje PNG o
+ dokładnie 2097152 bajtach, którego pierwsze bajty są zerami, a manifest obok zapisuje, że system
+ powinien go odrzucić.
+
+
+
+
+
Zwykła droga
+
Dlaczego plik uszkodzony ręcznie to kiepski test
+
+ Zwykle używa się edytora szesnastkowego, skryptu zmieniającego kilka losowych bajtów albo ucięcia
+ pliku przez head lub truncate. Za pierwszym razem działa, a potem
+ kosztuje:
+
+
+
+ Za każdym razem jest inaczej. Losowy bajt trafia w nowe miejsce przy każdym
+ przebiegu, więc błąd z wtorku może nie wrócić w środę.
+
+
+ Zmienia rozmiar. Plik ucięty jest mniejszy niż limit, pod którym miał się mieścić,
+ więc kontrola rozmiaru odpowiada przed kontrolą zawartości, a test przechodzi z niewłaściwego
+ powodu.
+
+
+ Często nikt tego nie zauważa. Zwykły tekst da się czytać mimo zmienionego bajtu w
+ środku, a pobłażliwy czytnik obrazów po prostu go narysuje, więc plik, który miał być zepsuty,
+ zostaje przyjęty.
+
+
+ Nic nie mówi o tym, co ma się stać. Plik to same bajty, a ten, kto później czyta
+ test, musi zgadywać, czy chodziło o przyjęcie, czy o odrzucenie.
+
+
+
+
+
+
Co dostajesz
+
Uszkodzony plik ma nadal rozmiar, o który prosiłeś
+
+ Plik jest generowany normalnie, a psuty dopiero w drodze na dysk. Zachowuje rozmiar, który podałeś,
+ a to samo polecenie zapisuje znowu te same bajty.
+
+ Ustawienia podaje się po dwukropku. Flagę można powtarzać, a uszkodzenia są stosowane w kolejności,
+ w jakiej je zapiszesz. Działa z każdym z {{ .Facts.FormatCount }} formatów.
+
+
+
+
+
Co potrafi
+
Jakie są uszkodzenia?
+
+ To lista, którą wypisuje program, odczytana z niego w chwili budowania tej strony. tfg
+ damage wypisuje to samo, a tfg damage <id> mówi, co przyjmuje jedno z
+ nich.
+
+ {{ template "damagesTable" . }}
+
+ zero-head zapisuje zera na początku pliku. Większość czytników zagląda tam najpierw, w
+ sygnaturę i nagłówek mówiące, czym jest plik, więc zauważy to prawie każdy czytnik. Zwykły tekst
+ i logi nie mają sygnatury i też są odrzucane, bo ciąg zerowych bajtów nie jest tekstem. Poniżej
+ czterech bajtów niektóre formaty wychodzą z uszkodzeniem, na które nie skarży się żaden czytnik,
+ dlatego ustawienie zaczyna się od czterech.
+
+
+
+
+
Co mówi manifest
+
Manifest, który mówi, co ma się stać
+
+ Każdy uszkodzony plik dostaje wpis mówiący, że system powinien go odrzucić, a obok zapisane jest
+ uszkodzenie:
+
+ Dwie prośby są odrzucane, zanim cokolwiek powstanie, bo każda zostawiłaby na dysku plik, który
+ manifest opisuje błędnie:
+
+
+
plik mniejszy, niż potrzebuje uszkodzenie, bo wyszedłby nietknięty
+
+ expected: accept obok uszkodzenia, bo nic nie mogłoby tego spełnić. Napisz
+ sanitize, jeśli system ma plik naprawić, albo unspecified, jeśli
+ właśnie o to pytasz
+
+
+
+
+
+
W przepisie
+
Zdrowe i zepsute pliki w jednym przebiegu
+
+ Włóż jedno i drugie do jednego przepisu, a manifest niesie oczekiwanie każdego pliku, więc test nie
+ potrzebuje listy, który jest który:
+
+ Test czyta manifest i sprawdza, czy to, co się stało, jest tym, co zadeklarowano. Nie potrzebuje
+ listy nazw plików:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Dobre odrzucenie jest czyste. Komunikat mówiący, co było nie tak, to odpowiedź, o którą chodzi. Błąd
+ serwera, zawieszenie albo plik zapisany do połowy to wada, którą ten test ma znaleźć.
+
jednego bajtu, taki plik zostaje odrzucony zamiast zapisany - przebieg idzie dalej, mówi,
którego pliku to dotyczyło, i kończy się kodem częściowego wyniku.
+
Przebieg zatrzymany przez Ctrl+C i tak zostawia manifest i nigdy nie zostawia pliku zapisanego
w połowie, więc anulowane zadanie da się posprzątać następnym.
+
diff --git a/web/content/pl/site.json b/web/content/pl/site.json
index fbfaebd4..f2310c87 100644
--- a/web/content/pl/site.json
+++ b/web/content/pl/site.json
@@ -1,5 +1,6 @@
{
"code": "pl",
+ "locale": "pl_PL",
"name": "Polski",
"dir": "pl",
"pages": [
@@ -51,11 +52,28 @@
"nav": "FAQ",
"title": "FAQ - pytania o generowanie plików testowych",
"description": "Czym to się różni od dd i fsutil, czy pliki można commitować, czy przebieg powtarza się co do bajta i co się dzieje, gdy rozmiar jest nieosiągalny."
+ },
+ {
+ "key": "damage",
+ "slug": "uszkodzone-pliki-testowe",
+ "nav": "Uszkodzone pliki",
+ "title": "Uszkodzone pliki testowe - zepsute pliki o dokładnym rozmiarze",
+ "description": "Zrób plik zepsuty celowo, o dokładnie takim rozmiarze, jaki podasz, z manifestem mówiącym, że system powinien go odrzucić. Do testów walidacji uploadu i parserów.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "pliki-testowe-w-ci",
+ "nav": "Pliki testowe w CI",
+ "title": "Pliki testowe w CI - GitHub Actions, GitLab CI i PowerShell",
+ "description": "Generuj pliki testowe w potoku zamiast commitować binaria: workflow GitHub Actions, zadanie GitLaba, kody wyjścia przerywające build i pułapka PowerShella.",
+ "parent": "use-cases"
}
],
"words": {
"skip": "Przejdź do treści",
"navLabel": "Główna",
+ "langLabel": "Język",
"breadcrumbHome": "Start",
"imageAlt": "Testing Files Generator - prawdziwe pliki testowe o dokładnym rozmiarze, z manifestem mówiącym, jak system ma na nie zareagować",
"schemaDescription": "Darmowy generator plików testowych dla QA o otwartym kodzie. Tworzy prawdziwe pliki w {{ .Facts.FormatCount }} formatach o dokładnie zadanym rozmiarze i zapisuje manifest mówiący, jak testowany system ma na każdy z nich zareagować.",
@@ -89,7 +107,11 @@
"notFoundLead": "Adres, którym tu trafiłeś, nie pasuje do żadnej strony w tym serwisie.",
"notFoundBack": "Wróć na stronę główną",
"read.format": "Format każdego pliku w zestawie. To flaga samego narzędzia, a preset daje jej tylko wartość domyślną.",
- "readTakes.format": "identyfikator formatu ze strony formatów"
+ "readTakes.format": "identyfikator formatu ze strony formatów",
+ "colDamage": "Uszkodzenie",
+ "colEffect": "Co robi z bajtami",
+ "colSettings": "Ustawienia",
+ "noSettings": "brak"
},
"endings": {
"0": "Wszystko się udało.",
@@ -279,7 +301,8 @@
},
{
"q": "Czy mogę wygenerować plik celowo uszkodzony?",
- "a": "Jeszcze nie. Pliki uszkodzone i niepoprawne są zaplanowaną funkcją. Dziś każdy plik, który narzędzie zapisuje, jest poprawnym plikiem swojego formatu."
+ "a": "Tak. Dodaj --damage zero-head, a plik wyjdzie dokładnie o podanym rozmiarze, z pierwszymi bajtami nadpisanymi zerami, więc czytnik go odrzuci, a manifest powie, że system powinien go odrzucić. Szczegóły są na stronie o uszkodzonych plikach testowych.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
},
{
"q": "Jakie formaty są następne w kolejce?",
@@ -298,5 +321,8 @@
"q": "Dlaczego przebieg po tysiącach plików jest wolniejszy na Windows?",
"a": "Bo Windows liczy sobie więcej za każdą ścieżkę, na którą patrzy, a polecenie chodzące po tysiącach plików patrzy na tysiące ścieżek. Zmierzone na jednej maszynie przy 3000 plików po 1 kB: verify trwa około 0,9 sekundy na Windows i około 0,2 sekundy na Linuksie w kontenerze. Krótsza ścieżka katalogu wyjściowego zmniejsza wynik na Windows, bo każdy katalog nad plikami też jest częścią tego, na co system patrzy."
}
- ]
+ ],
+ "damages": {
+ "zero-head": "Nadpisuje pierwsze bajty pliku zerami, nie zmieniając jego długości. Większość czytników zagląda tam najpierw, więc to uszkodzenie zauważy prawie wszystko."
+ }
}
diff --git a/web/content/pl/use-cases.html b/web/content/pl/use-cases.html
index 9a1baa89..8b652b6e 100644
--- a/web/content/pl/use-cases.html
+++ b/web/content/pl/use-cases.html
@@ -104,6 +104,19 @@
Sprawdzenie, czy Twój kod czyta format tak jak prawdziwe oprogramowanie
+
+
Poradniki
+
Dwa z tych zastosowań dokładniej
+
+
+ Uszkodzone pliki testowe - plik zepsuty celowo, o dokładnym rozmiarze, z zapisanym w manifeście tym, co system ma z nim zrobić.
+
+
+ Pliki testowe w CI - workflow dla GitHub Actions, zadanie GitLaba i kody wyjścia, które przerywają build.
+
+
+
+
Dla kogo to jest
diff --git a/web/content/pt-BR/ci.html b/web/content/pt-BR/ci.html
new file mode 100644
index 00000000..826b511e
--- /dev/null
+++ b/web/content/pt-BR/ci.html
@@ -0,0 +1,191 @@
+{{ with .Up }}
+ Uma fixture binária em um repositório fica para sempre no histórico, não pode ser revisada em um
+ diff e deixa de ser viável quando o arquivo é grande. Gere os arquivos dentro do pipeline a partir
+ de uma receita. A receita é texto, os bytes saem iguais a cada vez e um último passo prova que
+ nada mudou.
+
+
+
+
A resposta curta
+
+ Instale o tfg, rode tfg generate fixtures.yaml --out ./fixtures antes dos
+ testes e tfg verify ./fixtures/manifest.json depois. Os dois passos fazem o build
+ falhar sozinhos, com um código de saída que diz o motivo.
+
+
+
+
+
Por que não commitar
+
Por que uma fixture não deve morar no repositório
+
+
+ Ela fica no histórico. Apagar um binário depois não deixa um clone menor, porque
+ todas as versões dele continuam lá.
+
+
+ Um diff não mostra o que mudou. O revisor vê que um PDF é diferente e nada mais.
+ Uma receita muda em uma linha.
+
+
+ Arquivos grandes não cabem. O GitHub recusa um push que contenha um arquivo acima
+ de 100 MB, então um teste de limite de upload de 500 MB não tem o que commitar.
+
+
+
+ O que se commita é a receita. A mesma receita e a mesma semente gravam os mesmos bytes em qualquer
+ máquina, então o arquivo gerado no pipeline é o arquivo que você tinha no notebook.
+
+
+
+
+
A receita
+
Uma receita que mora junto dos testes
+
+ Esta grava vinte e cinco faturas que devem ser aceitas e duas imagens acima de um limite que devem
+ ser recusadas, e o manifesto registra as duas expectativas:
+
+ A linha da soma de verificação compara o arquivo com verify-SHA256SUMS.txt da mesma
+ versão. A versão está fixada, então uma versão nova nunca altera um build que você não mexeu.
+
+ Cada final tem o seu próprio código de saída, então o passo falha sozinho e o log diz qual foi. Os
+ que um pipeline encontra:
+
+
+
3 - a receita não é válida. Nada foi gravado, e cada problema é nomeado
+
4 - o formato não consegue fazer o que foi pedido, por exemplo um tamanho abaixo do seu mínimo
+
6 - não há espaço em disco suficiente
+
7 - tfg verify achou um arquivo que não bate com o manifesto
+
8 - a execução terminou, mas nem tudo foi produzido
+
+
+ Uma execução que falhou não imprime nada na saída padrão, então um analisador de logs nunca toma um
+ erro por dado. A tabela completa está na página de
+ documentação.
+
+
+
+
+
PowerShell
+
Um script PowerShell precisa de mais uma linha
+
+ O PowerShell não leva o código de saída de um programa para fora de um arquivo .ps1.
+ Rode um com -File e o script responde 0 mesmo quando a ferramenta lá
+ dentro recusou o trabalho, então um build que deveria ficar vermelho fica verde. A última linha
+ é a correção inteira:
+
+ É assim que o PowerShell se comporta, não algo desta ferramenta. cmd, bash
+ e zsh não precisam de mais nada.
+
+
+
+
+
Vários jobs
+
Compartilhando as fixtures entre jobs
+
+ Em geral não é preciso enviá-las. Como a mesma receita grava os mesmos bytes, cada job pode rodar o
+ seu próprio tfg generate, que é mais rápido que um upload e um download. Quando um
+ job precisa receber arquivos de outro, rode tfg verify no manifesto depois da
+ transferência, e ele diz se o que chegou é o que foi gravado.
+
+ Um validador que só viu arquivos saudáveis não foi realmente testado. Veja como obter um arquivo
+ quebrado de propósito, que sai com exatamente o tamanho que você pede e traz um
+ manifesto dizendo o que o seu sistema deve fazer com ele.
+
+
+
+
A resposta curta
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out grava um PNG de
+ exatamente 2097152 bytes cujos primeiros bytes são zeros, e o manifesto ao lado registra que o
+ seu sistema deve rejeitá-lo.
+
+
+
+
+
O jeito de sempre
+
Por que um arquivo corrompido à mão é um teste ruim
+
+ O jeito de sempre é um editor hexadecimal, um script que troca alguns bytes aleatórios ou cortar um
+ arquivo com head ou truncate. Funciona uma vez, e depois sai caro:
+
+
+
+ É diferente a cada vez. Um byte aleatório cai num lugar novo a cada execução, então
+ uma falha de terça pode não voltar na quarta.
+
+
+ Muda o tamanho. Um arquivo cortado fica menor que o limite abaixo do qual deveria
+ ficar, então a checagem de tamanho responde antes da checagem de conteúdo e o teste passa pelo
+ motivo errado.
+
+
+ Muitas vezes passa despercebido. Texto simples continua legível com um byte
+ alterado no meio, e um leitor de imagens tolerante simplesmente o desenha, então o arquivo que
+ deveria estar quebrado é aceito.
+
+
+ Não diz nada sobre o que deve acontecer. O arquivo é só bytes, e quem ler o teste
+ depois precisa adivinhar se a intenção era aceitação ou rejeição.
+
+
+
+
+
+
O que você recebe
+
Um arquivo danificado continua com o tamanho que você pediu
+
+ O arquivo é gerado normalmente e quebrado depois, a caminho do disco. Ele mantém o tamanho pedido, e
+ o mesmo comando grava os mesmos bytes outra vez.
+
+ As configurações vão depois de dois-pontos. A opção pode ser repetida, e os danos são aplicados na
+ ordem em que você os escreve. Funciona com cada um dos {{ .Facts.FormatCount }} formatos.
+
+
+
+
+
O que ele sabe fazer
+
Quais danos existem?
+
+ Esta é a lista que o programa imprime, lida dele quando esta página é construída. tfg
+ damage imprime a mesma, e tfg damage <id> diz o que cada um aceita.
+
+ {{ template "damagesTable" . }}
+
+ zero-head grava zeros sobre o início do arquivo. A maioria dos leitores olha ali
+ primeiro, para a assinatura e o cabeçalho que dizem o que o arquivo é, então quase todo leitor
+ percebe. Texto simples e logs não têm assinatura e também são recusados, porque uma sequência de
+ bytes zero não é texto. Abaixo de quatro bytes, alguns formatos saem com um dano de que nenhum
+ leitor reclama, e por isso a configuração começa em quatro.
+
+
+
+
+
O que o manifesto diz
+
Um manifesto que diz o que deve acontecer
+
+ Cada arquivo danificado recebe uma entrada dizendo que o seu sistema deve rejeitá-lo, com o dano
+ registrado ao lado:
+
+ Dois pedidos são recusados antes de qualquer coisa ser gravada, porque cada um deixaria no disco um
+ arquivo que o manifesto descreve errado:
+
+
+
um arquivo menor do que o dano precisa, que sairia intacto
+
+ expected: accept ao lado de um dano, porque nada poderia cumprir isso. Escreva
+ sanitize se o seu sistema deve consertar o arquivo, ou unspecified
+ se essa é justamente a pergunta que você faz
+
+
+
+
+
+
Em uma receita
+
Arquivos saudáveis e quebrados em uma execução
+
+ Ponha os dois em uma receita, e o manifesto leva a expectativa de cada arquivo, então o teste não
+ precisa de uma lista de qual é qual:
+
+ O teste lê o manifesto e confere se o que aconteceu é o que foi declarado. Não precisa de uma lista
+ de nomes de arquivo:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Uma boa recusa é uma recusa limpa. Uma mensagem que diz o que estava errado é a resposta que você
+ quer. Um erro de servidor, uma trava ou um arquivo salvo pela metade é o defeito que este teste
+ existe para achar.
+
+
+
+
+
A seguir
+
Para onde ir daqui
+
+
+ O preset upload-validation faz a um formulário as
+ outras duas perguntas, a do tamanho e a do tipo.
+
+
diff --git a/web/content/pt-BR/docs.html b/web/content/pt-BR/docs.html
new file mode 100644
index 00000000..f0ddb4d8
--- /dev/null
+++ b/web/content/pt-BR/docs.html
@@ -0,0 +1,280 @@
+
Documentação
+
+ Tudo o que a ferramenta faz, organizado como as perguntas com que as pessoas realmente chegam. O
+ README do repositório é a referência completa e sempre corresponde
+ à versão que você baixou.
+
+
+
+
Quais comandos existem?
+
Cada um faz uma única coisa:
+ {{ template "commandList" . }}
+
+
+
+
Como gero um único arquivo de tamanho exato?
+
+ Informe o formato, o tamanho e o destino. Os tamanhos contam de 1024 em 1024, então 2mb
+ são 2097152 bytes. Uma contagem simples de bytes também funciona, então --size
+ 10485761 pede exatamente essa quantidade.
+
+
tfg generate --format png --size 2mb --out ./out
+
As opções úteis de generate:
+
+
+
Opção
O que faz
+
+
--format <id>
formato dos arquivos, por exemplo txt
+
--size <size>
tamanho exato de cada arquivo, como 10mb ou uma contagem simples de bytes
+
--size-range <a-b>
um tamanho sorteado por arquivo dentro de um intervalo, como 1kb-8kb. O sorteio vem do seed
+
--boundary <size>
três arquivos ao redor de um limite: um byte abaixo, o limite, um byte acima
+
--count <n>
quantos arquivos produzir. Padrão 1
+
--name <template>
modelo de nome, por exemplo invoice_{index:04}.txt
+
--out <dir>
diretório onde escrever
+
--seed <n>
seed da execução. O mesmo seed dá os mesmos bytes
+
--set <k>=<v>
uma configuração de formato, repetível
+
--damage <name>
quebrar os arquivos de propósito, repetível e aplicado em ordem. Rode tfg damage para ver a lista
+
--expected <outcome>
accept, reject, sanitize ou unspecified
+
--dry-run
contar e mostrar, sem escrever absolutamente nada
+
--json
escrever o manifesto na saída padrão
+
+
+
+
+
+
+
Como faço um arquivo quebrado de propósito?
+
+ Todo outro arquivo que esta ferramenta escreve é correto por construção, o que responde a duas das
+ três perguntas que um validador de upload faz. --damage responde à terceira - se o
+ arquivo abre, afinal. O arquivo é produzido normalmente e depois quebrado, então continua com o
+ tamanho que você pediu.
+
+ As configurações vão depois de dois-pontos. A opção se repete, e a ordem em que você as escreve é a
+ ordem em que são aplicadas. tfg damage lista o que esta versão pode fazer e o que
+ cada uma aceita.
+
+
Em uma receita a chave é uma lista, de nomes ou de configurações:
+ Um arquivo danificado recebe expected: reject no manifesto, com o dano registrado ao
+ lado. Duas coisas são recusadas antes de escrever qualquer coisa, porque cada uma deixaria no
+ disco um arquivo que o manifesto descreve errado:
+
+
+
um arquivo menor do que o dano precisa, porque sairia sem alteração
+
+ expected: accept ao lado de um dano, porque nada poderia cumpri-lo. Escreva
+ sanitize se o sistema sob teste deve reparar o arquivo, ou
+ unspecified se essa é a pergunta que você está fazendo
+
+
+
+ Uma terceira não pode ser conhecida de antemão. Se um dano roda e não move nenhum byte, esse arquivo
+ é descartado em vez de escrito - a execução continua, diz qual arquivo foi e termina com o
+ código de saída parcial.
+
+ Uma receita é um arquivo YAML que descreve uma execução inteira. Versione-a ao lado dos seus testes
+ e as fixtures deixam de ser binários no seu repositório - qualquer pessoa pode reconstruí-las,
+ byte a byte, a partir de um arquivo de algumas centenas de caracteres.
+
+ Cada target precisa de exatamente uma destas chaves: size, size-range,
+ boundary ou contains. Duas é um erro e nenhuma também. Uma receita
+ inválida escreve nenhum arquivo e relata todos os problemas de uma vez em vez
+ de só o primeiro, cada um nomeando a configuração a que se refere.
+
+
+
+
+
Como declaro o que meu sistema deve fazer com um arquivo?
+
Forma curta quando o resultado basta, forma longa quando o motivo importa:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Os resultados são accept, reject, sanitize e
+ unspecified. Os motivos são uma lista fechada para que um relatório possa agrupar
+ por eles: content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit e size_zero.
+
+
+ Um motivo nomeia a regra em jogo, não o veredito. Por isso o mesmo motivo pode
+ ficar sob qualquer um dos resultados - um arquivo um byte abaixo de um limite é
+ accept, e a regra de que se trata continua sendo size_limit.
+
+
+
+
+
O que há no manifesto?
+
+ Ele é escrito ao lado dos arquivos no fim de cada execução, inclusive de uma execução interrompida.
+ Uma entrada por arquivo:
+
+ Um recipe_hash é adicionado quando a execução veio de uma receita, e
+ preset com overrides quando veio de um preset, de modo que um
+ manifesto sempre pode ser rastreado até o que o produziu.
+
+
+ Cada entrada também traz target_id, o id do target da receita que produziu o arquivo, e
+ summary.by_target conta os arquivos a que cada target chegou. Uma receita com
+ vários targets pode assim ser verificada target por target sem ler nomes de arquivo.
+
+
+
+
+
O que é um preset?
+
+ Um conjunto de arquivos pronto que responde a uma pergunta de teste comum, para que você não precise
+ desenhar o conjunto. Presets são receitas comuns por baixo, e eject imprime a
+ receita para você editá-la a partir dali. Cada preset tem uma página
+ própria com o que costuma encontrar, o que há no conjunto e cada configuração que aceita.
+
+ show diz quanto o conjunto custaria antes de você montá-lo, e diz abertamente quando um
+ número é um valor provisório nosso, e não um limite seu.
+
+
+
+
+
O que significam os códigos de saída?
+
+ Cada término tem seu próprio código, a saída legível por máquina vai para a saída padrão, e uma
+ execução com falha não imprime nada lá. A tabela é um contrato congelado - mudar o que um código
+ significa exige uma versão maior.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Uma execução parada com Ctrl+C ainda deixa um manifesto e nunca deixa um arquivo pela metade, então
+ um job cancelado ainda pode ser limpo pelo seguinte.
+
+ Sim, o mesmo motor com uma janela por cima, para o teste que não é automatizado. Não é uma versão
+ reduzida: um teste compara as duas interfaces capacidade por capacidade, e tudo que só uma delas
+ pode fazer precisa ser declarado e justificado em vez de divergir em silêncio.
+
+
+ As telas são um lote, presets, vários lotes de uma vez e Sobre. Ela mostra quanto uma execução
+ custaria antes de escrever qualquer coisa, informa o progresso enquanto roda e pode ser
+ cancelada no meio sem deixar um arquivo pela metade. Ainda não abre um arquivo de receita - por
+ enquanto receitas são coisa de linha de comando, e a janela monta seus lotes no formulário.
+
+
diff --git a/web/content/pt-BR/exact-size.html b/web/content/pt-BR/exact-size.html
new file mode 100644
index 00000000..0106f24d
--- /dev/null
+++ b/web/content/pt-BR/exact-size.html
@@ -0,0 +1,145 @@
+
Como criar um arquivo de tamanho exato
+
+ Todo sistema tem um comando para isso, e os três estão abaixo. Eles dão um arquivo com exatamente o
+ número certo de bytes - e para muito teste isso é tudo de que você precisa. Todo comando
+ desta página foi executado antes de ser publicado, no sistema a que pertence.
+
+
+
+
A resposta curta
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Os tamanhos são em bytes, e 10 MB
+ contados como o seu gerenciador de arquivos conta são 10485760.
+
+
+
+
+
Windows
+
fsutil, e uma versão em PowerShell que não precisa de nada extra
+
+ O fsutil vem com o Windows. Ele recebe o tamanho em bytes, então
+ calcule o número antes - 10 MB são 10485760, 100 MB são 104857600, 1 GB é 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Medido no Windows 11: funciona em um prompt comum, sem precisar de um elevado, e o arquivo sai com
+ exatamente 10485760 bytes.
+
+
O PowerShell faz o mesmo sem chamar outro programa, e entende unidades:
+ 10MB no PowerShell significa 10485760 bytes, a mesma contagem em base 1024 que o
+ Explorer usa, então os dois comandos acima produzem o mesmo tamanho.
+
+
+
+
+
Linux
+
dd, truncate e fallocate, e a diferença que pega as pessoas
+
O dd é o que todo mundo conhece. Ele escreve os bytes de verdade:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ O truncate é instantâneo, e essa é a pegadinha. Medido no Alpine Linux, o arquivo
+ informa 10485760 bytes e ocupa zero blocos - é um arquivo
+ esparso. Qualquer coisa que o leia recebe dez megabytes de zeros, mas o disco nunca
+ cedeu o espaço:
+
+
truncate -s 10M test10mb.bin
+
+ Isso serve para testar um limite de upload e engana para testar uma cota de disco. O
+ fallocate é o que se deve usar quando o espaço precisa ser real:
+
+
fallocate -l 10M test10mb.bin
+
E quando o conteúdo precisa ser incompressível, para que um compactador não consiga comprimi-lo de volta:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, que não é esparso, e os dois que você já conhece
+
+ O macOS traz o mkfile. Medido no macOS 26.6.2: 10485760 bytes e 20480 blocos, então o
+ espaço é realmente alocado em vez de prometido:
+
+
mkfile 10m test10mb.bin
+
dd e truncate também estão lá e se comportam como no Linux:
Um arquivo do tamanho certo não é um arquivo do tipo certo
+
+ Tudo acima dá um bloco de zeros. Isso basta quando o que está sob teste olha só o tamanho - um
+ limite de upload, uma cota, uma transferência. Deixa de bastar no momento em que qualquer coisa
+ abre o arquivo.
+
+
+ Medido, e vale a pena fazer você mesmo: crie um arquivo de 2 MB com fsutil, chame-o de
+ photo.png e entregue a uma biblioteca de imagens. O Pillow responde cannot
+ identify image file. Não é um PNG. Nunca foi - só o nome dizia que era.
+
+
+ Isso importa mais do que parece, por causa de o jeito como o teste então falha. Seu
+ endpoint de upload recusa o arquivo, seu teste fica verde e você conclui que o limite de tamanho
+ funciona. Ele não recusou pelo tamanho. Recusou porque os bytes não eram uma imagem, e a regra
+ que você queria testar nunca foi alcançada.
+
+
+
um parser o recusa antes de qualquer regra de tamanho ser olhada
+
uma etapa de miniatura falha e o erro que você lê é sobre a miniatura
+
um antivírus ou uma verificação de conteúdo o recusa por um terceiro motivo
+
um visualizador não mostra nada, e ninguém sabe dizer se esse é o bug
+
+
+
+
+
O outro caminho
+
Um arquivo real desse formato, exatamente no tamanho que você pediu
+
+ É isso que o Testing Files Generator faz. O arquivo é um genuíno do seu formato - abre no programa a
+ que pertence - e tem o número exato de bytes que você pediu, ao byte:
+
+ Peça um tamanho que um formato não alcança e você recebe um erro que nomeia o piso e o motivo, nunca
+ um arquivo de tamanho errado. A página de formatos lista cada
+ formato com o menor arquivo que ele pode produzir.
+
+
E um limite são três casos de teste em vez de um, então a ferramenta monta os três:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Isso dá 10485759, 10485760 e 10485761 bytes, e um manifesto dizendo quais deles seu sistema deve
+ aceitar e quais deve rejeitar. A página de casos de uso
+ percorre isso e outras quatro tarefas para as quais foi feito.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Então qual usar?
+
+
+
Use o comando do sistema
+
+ Quando nada abre o arquivo. Testar um limite de tamanho em um endpoint que checa o tamanho primeiro,
+ uma transferência, uma cota, um disco cheio. É uma linha e já está instalado.
+
+
+
+
Use um gerador de verdade
+
+ Quando qualquer coisa interpreta, renderiza, importa ou extrai o arquivo - e quando você precisa das
+ mesmas fixtures amanhã, em outra máquina, byte a byte.
+
+
+
+
+ Os dois estão nesta página porque os dois estão certos parte do tempo. O erro a evitar é usar o
+ primeiro onde o segundo é necessário e ler o teste verde como prova.
+
+
diff --git a/web/content/pt-BR/faq.html b/web/content/pt-BR/faq.html
new file mode 100644
index 00000000..100b4989
--- /dev/null
+++ b/web/content/pt-BR/faq.html
@@ -0,0 +1,20 @@
+
Perguntas frequentes
+
+ Licença, privacidade, reprodutibilidade e o que as pessoas conferem antes de colocar um gerador em
+ um pipeline de build. Se a sua pergunta não está aqui, o rastreador
+ de issues está aberto.
+
{{ .Facts.FormatCount }} formatos de arquivo, cada um gerado em um tamanho exato
+
+ Cada um é um arquivo real daquele formato. Abre no programa a que pertence e tem
+ exatamente o número de bytes que você pediu. Nenhum é preenchimento de zeros com uma extensão
+ colada.
+
+
+{{ template "formatsTable" . }}
+
+
+
O que as colunas significam
+
+
+
Menor arquivo
+
+ O menor número de bytes que esta ferramenta aceita para aquele formato, incluindo o rótulo que ela
+ escreve dentro do arquivo. Peça menos e você recebe um erro que nomeia o piso e o motivo,
+ nunca um arquivo de tamanho errado.
+
+
+
+
Fidelidade
+
+ Quão completo é o arquivo. full significa que um leitor que realmente interpreta o
+ formato o aceita, e não apenas que a extensão combina.
+
+
+
+
Verificado com
+
+ O leitor independente que abre todo arquivo gerado antes de o formato ser liberado - uma
+ implementação separada, não o nosso próprio código corrigindo o próprio dever de casa.
+
+
+
+
+ Todo formato também se repete ao byte: a mesma receita e o mesmo seed produzem arquivos idênticos em
+ qualquer máquina, o que torna seguro versionar uma receita no lugar das próprias fixtures.
+
+
+
+
+
Configurações que cada formato aceita
+
+ A maioria dos formatos tem configurações próprias - dimensões de imagem, qualidade JPEG, número de
+ páginas do PDF, linhas e colunas de uma planilha, quantas entradas vão dentro de um arquivo
+ compactado. Defina-as com --set key=value na linha de comando, ou em
+ properties: numa receita.
+
+ Um valor fora do que uma configuração aceita é recusado com uma mensagem que nomeia a configuração,
+ o intervalo permitido e o que usar no lugar. Uma configuração desconhecida também é um erro,
+ nunca um padrão silencioso - um erro de digitação aceito em silêncio dá um arquivo com as
+ configurações erradas e uma hora se perguntando por que o teste passa quando não deveria.
+
+
+ Rode tfg formats <id> para ver exatamente o que um formato aceita na versão que
+ você tem.
+
+
+
+
+
Arquivos compactados contêm arquivos reais
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} e {{ end }}{{ $c.ID }}{{ end }}
+ podem ser preenchidos com entradas em vez de ficarem como uma casca vazia. Um arquivo compactado
+ gerado realmente contém os documentos que diz conter, então qualquer coisa que o descompacte
+ durante um teste encontra arquivos reais dentro.
+
+ PDF, PNG, DOCX, ZIP - {{ .Facts.FormatCount }} formatos no total, e cada um é um
+ arquivo real que abre no programa a que pertence, com exatamente o tamanho que você
+ pediu. Cada execução também registra o que sua aplicação deve fazer com cada arquivo.
+ Linha de comando e janela de desktop, gratuito e de código aberto, funcionando inteiramente na
+ sua máquina.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ A janela de desktop, pronta para escrever um lote de arquivos. O mesmo motor roda por trás da linha de comando.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
formatos reais, cada um abre no programa a que pertence
+
+
+ 1 byte
+
a precisão de cada tamanho que você pede, nunca arredondado em silêncio
+
+
+ 0
+
conexões para lugar nenhum - sem conta, sem telemetria, sem verificação de atualizações
+
+
+
+
+
O problema
+
Fazer um arquivo de teste é fácil. Fazer os mil certos é a parte tediosa
+
Você está testando um software que aceita arquivos de pessoas. Mais cedo ou mais tarde, você precisa de:
+
+
um PDF de exatamente 10 MB, para descobrir se o limite de upload é real
+
os três arquivos dos dois lados desse limite, para pegar erros de um a mais ou a menos
+
10.000 arquivos de log, para ver o que o job noturno faz quando a pasta é grande
+
um ZIP que realmente contém 200 documentos, não uma casca com a extensão certa
+
um arquivo de 4 GB, sem guardar um arquivo de 4 GB no seu repositório
+
as mesmas fixtures no seu notebook e no servidor de build, byte a byte
+
+
+ É isso que isto substitui. Foi feito para engenheiros de QA, automação de testes e qualquer pessoa
+ cujo código tenha atrás um formulário de upload, uma rotina de importação, um parser ou uma cota
+ de armazenamento.
+
+
+
+
+
O que o torna diferente
+
Outros geradores param nos bytes. Este responde ao que o seu teste realmente pergunta
+
+ Uma pasta de arquivos ainda deixa você decidindo o que cada um deve provar. Cada execução aqui
+ escreve um manifest.json ao lado dos arquivos - uma lista simples de tudo que foi
+ produzido e, para cada entrada, uma expectativa declarada.
+
+
Digamos que seu endpoint de upload permita 1 MB. Peça os três arquivos que ficam nessa linha:
Onde a resposta depende da sua própria política, o manifesto diz isso
+
+ Ele registra unspecified em vez de inventar uma expectativa. Um gerador que adivinha
+ produz falhas falsas, e uma suíte que dá alarme falso acaba desligada.
+
+
+
+
+
+
Presets
+
Escolha a pergunta, receba o conjunto inteiro
+
+ Um preset é um conjunto de arquivos de teste desenhado em torno de uma pergunta de teste, para que
+ você não precise descobrir quais arquivos provam o quê. Cada um tem uma página dizendo o que
+ costuma encontrar, o que há no conjunto e cada configuração que aceita.
+
+ Dez mil arquivos de log, cada um entre um e oito kilobytes, com os tamanhos sorteados a partir do
+ seed para que amanhã dê o mesmo conjunto. Dê a cada execução o seu próprio
+ diretório - o manifesto é o único registro do que uma execução escreveu, então a
+ ferramenta se recusa a escrever um segundo por cima:
+
+ Os tamanhos contam de 1024 em 1024, como o seu gerenciador de arquivos faz, então 2mb
+ significa 2097152 bytes. Uma contagem simples de bytes também funciona. A
+ documentação cobre receitas, o manifesto e os códigos de
+ saída.
+
+
+
+
+
O que você recebe
+
Feito para uma suíte que roda sem supervisão
+
+
+
Tamanho exato, ao byte
+
Peça 10485761 bytes e receba exatamente isso. Um tamanho que um formato não alcança é um erro com um motivo, nunca um arquivo de tamanho errado.
+
+
+
{{ .Facts.FormatCount }} formatos reais
+
Não são zeros de preenchimento com uma extensão. Um PNG gerado abre em um visualizador de imagens, um DOCX abre no Word, um ZIP extrai. Cada um é verificado com leitores independentes antes de ser liberado.
+
+
+
Um manifesto que é um oráculo de teste
+
Caminho, tamanho, SHA-256, formato, seed, versão da ferramenta - e o que seu sistema deve fazer com o arquivo.
+
+
+
Reproduzível
+
Mesma receita e mesmo seed, mesmos bytes, em qualquer máquina. Versione uma pequena receita YAML em vez de fixtures binárias grandes.
+
+
+
Duas interfaces, um motor
+
Uma linha de comando feita para CI e uma janela de desktop para testes exploratórios. Nenhuma é uma versão reduzida da outra, e um teste compara as duas capacidade por capacidade.
+
+
+
Totalmente offline
+
Sem conta, sem nuvem, sem telemetria, sem verificação de atualizações. O binário da linha de comando não tem nenhuma pilha de rede compilada nele.
+
+
+
+
+
+
Download
+
Escolha a versão para o seu sistema
+
+ Descompacte o arquivo e execute. tfg é a linha de comando e tfg-gui é a
+ janela de desktop. Não há instalador e nada para adicionar à sua máquina.
+
+ {{ template "downloadsTable" . }}
+
+
O que é assinado e o que não é
+
+ Os downloads de Windows e macOS são assinados, então iniciam sem aviso de desenvolvedor
+ desconhecido. Os de Linux não são, porque o Linux de desktop não tem equivalente para
+ assiná-los. Cada arquivo está listado em verify-SHA256SUMS.txt na página de
+ releases, para que você possa conferir o que baixou.
+
+ O preset {{ .ID }} monta com um único comando um conjunto inteiro de arquivos de teste
+ reais para esta pergunta, e um manifest.json ao lado dizendo como seu sistema deve
+ reagir a cada arquivo. Tudo abaixo é lido do programa, com os valores padrão desta versão.
+
+
+{{ if .Catches }}
+
+
O que ele costuma encontrar?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
O que há no conjunto?
+
Com os valores padrão, como o tfg preset show {{ .ID }} informa:
+
+
+
+
Arquivos
{{ .Budget.Files }}
+
Targets na sua receita
{{ .Budget.Targets }}
+
Tamanho total
{{ .Bytes }} B
+
Formatos
{{ join .Budget.Formats ", " }}
+
+
+
+
E o que o manifesto desse conjunto espera do seu sistema:
+
+
+
+
Esperado
Significado
Arquivos
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
O que você pode mudar?
+ {{- if .Settings }}
+
+
+
+
Configuração
Aceita
Padrão
O que faz
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Este valor padrão é o nosso provisório, não o valor do seu sistema. Passe o seu.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
Este preset não tem configurações. O conjunto é o mesmo toda vez.
+ {{- end }}
+
+
+
+
Como executar?
+
Veja quanto o conjunto custaria, monte-o ou pegue a receita dele para editar:
Ou construa sobre ele em uma receita sua, ao lado dos seus testes:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/pt-BR/presets.html b/web/content/pt-BR/presets.html
new file mode 100644
index 00000000..88b48d84
--- /dev/null
+++ b/web/content/pt-BR/presets.html
@@ -0,0 +1,32 @@
+
Presets de arquivos de teste, um conjunto para cada pergunta de teste
+
+ Um preset é um conjunto inteiro de arquivos de teste desenhado em torno de uma pergunta, com um
+ manifesto dizendo como seu sistema deve reagir a cada arquivo. Você escolhe a pergunta, a
+ ferramenta monta o conjunto. Cada preset tem sua própria página com o que costuma encontrar, o que
+ há no conjunto e cada configuração que aceita.
+
+
+{{ template "presetsList" . }}
+
+
+
Como um preset é diferente de uma receita?
+
+ Por baixo, não é. Um preset é uma receita que a ferramenta escreve para você a partir de algumas
+ configurações. tfg preset eject imprime essa receita para você guardá-la ao lado
+ dos seus testes e editá-la, e uma receita sua pode se basear em um preset com uma linha,
+ extends: preset: seguido do id dele.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Posso confiar nos valores padrão?
+
+ Para os arquivos, sim. Para um número que só o seu sistema conhece, como o limite de um formulário
+ de upload, um valor padrão é um provisório nosso, e a ferramenta diz isso toda vez que usa um. A
+ página de cada preset marca essas configurações, e tfg preset show diz isso antes
+ de qualquer coisa ser escrita.
+
+
diff --git a/web/content/pt-BR/site.json b/web/content/pt-BR/site.json
new file mode 100644
index 00000000..1e613f43
--- /dev/null
+++ b/web/content/pt-BR/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "pt-BR",
+ "locale": "pt_BR",
+ "name": "Português (Brasil)",
+ "dir": "pt-br",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Início",
+ "title": "Gerador de arquivos de teste - tamanho exato, {{ .Facts.FormatCount }} formatos reais",
+ "description": "Gerador gratuito e de código aberto de arquivos de teste para QA. PDF, DOCX, PNG e ZIP reais no tamanho exato, com um manifesto de como seu sistema deve reagir."
+ },
+ {
+ "key": "formats",
+ "slug": "formatos",
+ "nav": "Formatos",
+ "title": "{{ .Facts.FormatCount }} formatos de arquivo - PDF, DOCX, PNG, ZIP e mais",
+ "description": "Todos os formatos que o gerador produz, o menor arquivo possível de cada um e as configurações que aceita. Os {{ .Facts.FormatCount }} abrem no programa a que pertencem."
+ },
+ {
+ "key": "presets",
+ "slug": "presets",
+ "nav": "Presets",
+ "title": "Presets de arquivos de teste - conjuntos prontos para QA",
+ "description": "Conjuntos prontos de arquivos de teste, cada um responde a uma pergunta: limites de upload, nomes, codificações, importação, arquivos vazios e validação."
+ },
+ {
+ "key": "docs",
+ "slug": "documentacao",
+ "nav": "Documentação",
+ "title": "Documentação - comandos, receitas, manifesto, códigos de saída",
+ "description": "Como gerar arquivos de teste pela linha de comando ou com uma receita YAML, o que o manifesto contém e o que cada código de saída significa no CI."
+ },
+ {
+ "key": "use-cases",
+ "slug": "casos-de-uso",
+ "nav": "Casos de uso",
+ "title": "Casos de uso - limites de upload, fixtures de CI, testes em massa",
+ "description": "Testar um limite de tamanho de upload, montar fixtures reproduzíveis para o CI, gerar dez mil arquivos e encher arquivos compactados com conteúdo real."
+ },
+ {
+ "key": "exact-size",
+ "slug": "criar-arquivo-de-tamanho-exato",
+ "nav": "Tamanho exato",
+ "title": "Criar um arquivo de tamanho exato - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate e mkfile, cada um medido no seu sistema, e por que um arquivo feito assim não é um PDF nem um PNG quando um teste precisa de um."
+ },
+ {
+ "key": "faq",
+ "slug": "perguntas-frequentes",
+ "nav": "FAQ",
+ "title": "FAQ - perguntas sobre gerar arquivos de teste",
+ "description": "Como isso difere de dd e fsutil, se os arquivos podem ir para o repositório, se as execuções se repetem byte a byte e o que acontece quando um tamanho é inalcançável."
+ },
+ {
+ "key": "damage",
+ "slug": "arquivos-de-teste-corrompidos",
+ "nav": "Arquivos corrompidos",
+ "title": "Arquivos de teste corrompidos - arquivos quebrados, tamanho exato",
+ "description": "Um arquivo quebrado de propósito, com o tamanho exato que você pede e um manifesto dizendo que o seu sistema deve rejeitá-lo. Para testar validação de upload e parsers.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "arquivos-de-teste-no-ci",
+ "nav": "Arquivos de teste no CI",
+ "title": "Arquivos de teste no CI - GitHub Actions, GitLab CI e PowerShell",
+ "description": "Gere arquivos de teste no pipeline em vez de commitar binários: workflow do GitHub Actions, job do GitLab, códigos de saída e a pegadinha do PowerShell.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "Ir para o conteúdo",
+ "navLabel": "Principal",
+ "langLabel": "Idioma",
+ "breadcrumbHome": "Início",
+ "imageAlt": "Testing Files Generator - arquivos de teste reais no tamanho exato, com um manifesto que diz como seu sistema deve reagir a cada um",
+ "schemaDescription": "Um gerador gratuito e de código aberto de arquivos de teste para QA. Produz arquivos reais de {{ .Facts.FormatCount }} formatos no tamanho exato e escreve um manifesto que diz como o sistema sob teste deve reagir a cada um.",
+ "ctaDownload": "Baixar",
+ "ctaSource": "Ver o código-fonte",
+ "ctaNote": "Gratuito e de código aberto, GPL-3.0. Sem cadastro. Os downloads de Windows e macOS são assinados e iniciam sem aviso.",
+ "colFormat": "Formato",
+ "colName": "Nome",
+ "colExtension": "Extensão",
+ "colSmallest": "Menor arquivo",
+ "colFidelity": "Fidelidade",
+ "colChecked": "Verificado com",
+ "colSetting": "Configuração",
+ "colAccepts": "Aceita",
+ "colSystem": "Sistema",
+ "colCli": "Linha de comando",
+ "colWindow": "Janela de desktop",
+ "noBinary": "ainda sem binário",
+ "colCode": "Código",
+ "colMeaning": "Significado",
+ "footerBlurb": "Arquivos de teste para QA, no tamanho exato, com um manifesto que diz como seu sistema deve reagir a cada um.",
+ "footerProject": "Projeto",
+ "footerSource": "Código no GitHub",
+ "footerReleases": "Downloads",
+ "footerIssues": "Relatar um problema",
+ "footerSupport": "Apoiar o projeto",
+ "footerPages": "Páginas",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. Distribuído sob a Licença Pública Geral GNU, versão 3. Os arquivos que você gera são seus - a licença cobre a ferramenta, não a sua saída.",
+ "footerPrivacy": "Este site não carrega fontes, scripts nem rastreadores de lugar nenhum. Não usa cookies.",
+ "notFoundTitle": "Essa página não está aqui",
+ "notFoundLead": "O endereço que você seguiu não corresponde a nenhuma página deste site.",
+ "notFoundBack": "Ir para o início",
+ "read.format": "O formato de cada arquivo do conjunto. É uma opção da própria ferramenta, e o preset apenas dá a ela um valor padrão.",
+ "readTakes.format": "um id de formato da página de formatos",
+ "colDamage": "Dano",
+ "colEffect": "O que faz com os bytes",
+ "colSettings": "Configurações",
+ "noSettings": "nenhuma"
+ },
+ "endings": {
+ "0": "Tudo funcionou.",
+ "1": "Um erro inesperado dentro da ferramenta.",
+ "2": "Comando ou opção incorretos.",
+ "3": "A receita não é válida.",
+ "4": "O formato não consegue fazer o que foi pedido.",
+ "5": "Uma leitura ou escrita falhou.",
+ "6": "Espaço em disco insuficiente.",
+ "7": "verify encontrou uma divergência.",
+ "8": "A execução terminou, mas nem tudo foi produzido.",
+ "130": "Interrompido com Ctrl+C.",
+ "143": "Encerrado por um sinal, que é a cara de um timeout de CI."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "Um arquivo válido e tão pequeno quanto o formato permite passa?",
+ "title": "Vazio e mínimo",
+ "pageTitle": "Menores arquivos de teste válidos e vazios em cada formato",
+ "description": "O menor arquivo válido que a ferramenta escreve em cada um dos seus {{ .Facts.FormatCount }} formatos, mais um arquivo vazio onde o formato permite, cada um com a reação esperada.",
+ "catches": [
+ "um arquivo válido recusado por ser pequeno demais, porque a verificação conta bytes em vez de lê-los",
+ "um arquivo vazio que derruba o leitor em vez de ser reportado",
+ "uma imagem de um pixel de largura que divide por zero a caminho da miniatura",
+ "um armazenamento que lê zero byte como upload com falha e fica tentando de novo"
+ ],
+ "details": {
+ "formats": "De quais formatos o conjunto é feito. Deixe em all para todos os formatos desta versão, ou nomeie os que o seu sistema aceita."
+ }
+ },
+ "filename-handling": {
+ "question": "Meu sistema vai guardar, mostrar e devolver um nome de arquivo que ele não esperava?",
+ "title": "Tratamento de nomes de arquivo",
+ "pageTitle": "Nomes de arquivo problemáticos para testar - Unicode e tamanho",
+ "description": "Arquivos com nomes que quebram uploads e armazenamento: outros alfabetos, emoji, inversão de direção, caracteres invisíveis, sintaxe de shell e SQL, tamanho.",
+ "catches": [
+ "um nome que parece outro na tela, em um log ou em uma lista",
+ "um nome cortado, aparado ou reescrito entre o upload e o armazenamento",
+ "um limite de tamanho contado em caracteres onde o armazenamento conta bytes"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "Um limite de tamanho é aplicado exatamente onde foi declarado?",
+ "title": "Limites de tamanho",
+ "pageTitle": "Testar um limite de tamanho de upload - arquivos no limite exato",
+ "description": "Arquivos um byte abaixo, exatamente no e um byte acima do limite que seu sistema declara, mais degraus maiores dos dois lados, cada um marcado se deve ser aceito.",
+ "catches": [
+ "erros de um a mais ou a menos no limite",
+ "MB confundido com MiB, que dá 4,8 por cento e basta para deixar passar um arquivo que não deveria passar",
+ "um limite aplicado no navegador e não no servidor"
+ ],
+ "details": {
+ "limit": "O limite de tamanho que seu sistema declara. Todo o resto é medido a partir dele.",
+ "spread": "Até onde ir de cada lado do limite, como uma lista de tamanhos."
+ }
+ },
+ "tabular-import": {
+ "question": "A minha importação de tabelas sobrevive ao que ferramentas reais exportam?",
+ "title": "Importação de tabelas",
+ "pageTitle": "Arquivos de teste para importar CSV e Excel - delimitadores",
+ "description": "CSV com outros delimitadores, quebras de linha CR LF, sem cabeçalho e com outras aspas, uma tabela larga demais, uma planilha Excel e JSON em vários formatos.",
+ "catches": [
+ "um arquivo com ponto e vírgula lido como uma coluna só, porque o delimitador foi presumido em vez de procurado",
+ "um arquivo CRLF dividido em linhas com uma linha vazia depois de cada uma",
+ "uma tabela sem cabeçalho cuja primeira linha de dados é engolida como nomes de coluna",
+ "uma importação que mantém as colunas que consegue mostrar e descarta o resto sem dizer nada",
+ "um leitor que lê registros JSON uma linha por vez e para no primeiro documento indentado"
+ ],
+ "details": {
+ "rows": "Quantas linhas a planilha tem. Ela é escrita exatamente no tamanho que essas linhas ocupam, então o orçamento acima muda com este valor.",
+ "columns": "Quantas colunas cada linha da planilha tem. Linhas vezes colunas tem um teto, e pedir além disso é recusado antes de escrever qualquer coisa."
+ }
+ },
+ "text-encoding": {
+ "question": "Meu leitor sabe em que codificação um arquivo está, ou está adivinhando?",
+ "title": "Codificação de texto",
+ "pageTitle": "Arquivos de teste de codificação - UTF-8, UTF-16, BOM, CRLF",
+ "description": "O mesmo texto em UTF-8, UTF-16LE e UTF-16BE, com e sem marca de ordem de bytes, e quebras de linha CR LF e LF, para testar como um leitor decodifica texto.",
+ "catches": [
+ "um leitor que presume UTF-8 e mostra um arquivo UTF-16 com um caractere a cada três, ou como fileiras de quadradinhos",
+ "uma marca de ordem de bytes lida como conteúdo, de modo que o primeiro campo de uma importação começa com três caracteres estranhos",
+ "um importador que adivinha a codificação pelos primeiros bytes e adivinha diferente num arquivo mais longo",
+ "um arquivo CRLF dividido em linhas com uma linha vazia depois de cada uma, ou um retorno de carro que sobra dentro do último campo"
+ ],
+ "details": {
+ "sample": "O tamanho de cada arquivo do conjunto. UTF-16 guarda dois bytes por caractere, então um número ímpar é recusado."
+ }
+ },
+ "upload-validation": {
+ "question": "Meu formulário de upload aceita o que deve e recusa o resto?",
+ "title": "Validação de upload",
+ "pageTitle": "Arquivos de teste de validação de upload - tipo, tamanho e nome",
+ "description": "Arquivos para testar um formulário de upload: tipos permitidos e negados, conteúdo que não bate com a extensão, limite de tamanho, nomes hostis e upload em massa.",
+ "catches": [
+ "um limite aplicado no navegador e não no servidor",
+ "um SVG ou HTML tomado por imagem ou por texto simples, que é um jeito de passar um script por um formulário",
+ "um arquivo verificado pela extensão e nunca aberto, de modo que um PDF chamado .jpg passa",
+ "um formulário que lê o corpo inteiro na memória antes de olhar o tamanho",
+ "um upload chamado PHOTO.JPG recusado onde photo.jpg é aceito, ou o contrário",
+ "um nome com espaços, parênteses ou caracteres fora do ASCII gravado em disco sem alteração"
+ ],
+ "details": {
+ "limit": "O limite de tamanho que seu formulário de upload declara. Este conjunto dá um passo para cada lado - para um arquivo em cada distância, rode o preset size-boundaries.",
+ "allow": "Quais tipos seu formulário deve aceitar. Cada um vira um arquivo real desse tipo, e eles são o controle positivo do conjunto todo.",
+ "deny": "Quais extensões seu formulário deve recusar. Uma extensão para a qual esta versão não tem formato ainda recebe um arquivo com esse nome, com texto simples.",
+ "far-over": "O quanto acima do limite vai o único arquivo grande. Desligue onde escrever várias vezes o limite não vale o disco.",
+ "bulk": "Quantos arquivos o upload em massa contém. Zero deixa esse grupo totalmente fora do conjunto."
+ }
+ }
+ },
+ "commands": {
+ "generate": "produzir arquivos, a partir de uma receita ou de opções",
+ "validate": "verificar uma receita sem escrever nada",
+ "verify": "verificar um diretório contra um manifesto",
+ "cleanup": "remover os arquivos que um manifesto lista",
+ "recipe fmt": "imprimir uma receita na sua forma normalizada",
+ "preset": "montar um conjunto de arquivos a partir de uma pergunta de teste nomeada",
+ "formats": "listar os formatos que esta versão suporta",
+ "damage": "listar as formas como esta versão pode quebrar um arquivo de propósito",
+ "tool": "pequenas utilidades para arquivos que você já tem",
+ "version": "imprimir a versão da ferramenta",
+ "license": "imprimir a licença e o que ela significa para os arquivos gerados"
+ },
+ "outcomes": {
+ "accept": "Seu sistema deve aceitar o arquivo.",
+ "reject": "Seu sistema deve recusar o arquivo.",
+ "sanitize": "Seu sistema deve aceitar o arquivo e limpá-lo, por exemplo renomeando-o.",
+ "unspecified": "Depende das regras do seu sistema. Você decide e depois confere se o que acontece é o que você queria."
+ },
+ "damages": {
+ "zero-head": "Sobrescreve os primeiros bytes do arquivo com zeros, sem mexer no comprimento. A maioria dos leitores olha ali primeiro, então quase tudo percebe este dano."
+ },
+ "terms": {
+ "oracleNone": "não se aplica",
+ "int": "qualquer número inteiro",
+ "choice": "um de um conjunto fixo",
+ "bool": "verdadeiro ou falso",
+ "size": "um tamanho como 2mb",
+ "text": "texto",
+ "pixels": "pixels",
+ "paragraphs": "parágrafos",
+ "rows": "linhas",
+ "columns": "colunas",
+ "slides": "slides",
+ "hertz": "hertz",
+ "megapixels": "megapixels",
+ "million cells": "milhões de células",
+ "entries per second": "entradas por segundo",
+ "files": "arquivos",
+ "sizes separated by commas": "tamanhos separados por vírgulas",
+ "format ids separated by commas": "ids de formato separados por vírgulas",
+ "format ids separated by commas, or all": "ids de formato separados por vírgulas, ou all",
+ "extensions separated by commas": "extensões separadas por vírgulas",
+ "the id of a format, as tfg formats lists them": "o id de um formato, como o tfg formats lista",
+ "the password, in plain text": "a senha, em texto simples",
+ "any text": "qualquer texto",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "uma data como 2024-02-29 ou 2024-02-29T13:45:00+02:00, ou none"
+ },
+ "faq": [
+ {
+ "q": "Como isso é diferente de dd, fsutil ou truncate?",
+ "a": "Esses comandos dão um arquivo do tamanho certo cheio de nada. Um arquivo de 2 MB chamado photo.png feito assim não é um PNG, então qualquer coisa que realmente o interprete o recusa pelo motivo errado, e o seu teste também passa pelo motivo errado. Isto produz um PNG real de exatamente 2 MB que abre em um visualizador de imagens e vem com uma declaração de como o seu sistema deve tratá-lo.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "É gratuito, e posso usar no trabalho?",
+ "a": "Sim para os dois. É distribuído sob a GPL-3.0 e não custa nada. Não há conta, chave de licença nem plano pago."
+ },
+ {
+ "q": "Posso usar os arquivos gerados em um produto de código fechado?",
+ "a": "Sim. A licença cobre o código da ferramenta, não o que ela produz. Arquivos, receitas e manifestos gerados são saída e não obras derivadas, então você pode versioná-los e distribuí-los sem nenhuma obrigação."
+ },
+ {
+ "q": "Os arquivos gerados contêm dados pessoais reais?",
+ "a": "Não. Tudo dentro deles é sintetizado a partir de um seed. Nenhum conjunto de dados é lido, nenhum serviço é contatado e nenhum conteúdo de terceiros é embutido. Trate um endereço de e-mail gerado como inutilizável em vez de não usado, porque qualquer texto aleatório pode coincidir por acaso com um real."
+ },
+ {
+ "q": "Vou obter exatamente os mesmos arquivos em outra máquina?",
+ "a": "Sim, byte a byte, com a mesma receita e o mesmo seed. O projeto testa isso a cada mudança, e quebrá-lo exige uma versão maior. É isso que permite versionar uma receita pequena em vez de fixtures binárias grandes."
+ },
+ {
+ "q": "Precisa de conexão com a internet?",
+ "a": "Nunca. Não há telemetria, verificação de atualizações nem cliente de nuvem, e o binário da linha de comando não tem pilha de rede compilada nele. Funciona em uma máquina sem rede e dentro de um ambiente corporativo fechado."
+ },
+ {
+ "q": "O que acontece se eu pedir um tamanho que um formato não consegue alcançar?",
+ "a": "Você recebe um erro que nomeia o formato, o menor tamanho possível, o motivo desse piso e o que fazer em vez disso, e nenhum arquivo é escrito. A ferramenta nunca arredonda um tamanho em silêncio. Cada piso está listado na página de formatos.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "Posso gerar um arquivo deliberadamente quebrado?",
+ "a": "Sim. Adicione --damage zero-head e o arquivo sai com exatamente o tamanho pedido, com os primeiros bytes sobrescritos por zeros, de modo que um leitor o recusa, e o manifesto diz que o seu sistema deve rejeitá-lo. A página sobre arquivos de teste corrompidos traz os detalhes.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "Quais formatos vêm a seguir?",
+ "a": "7z, mp3 e mp4. Hoje {{ .Facts.FormatCount }} formatos funcionam de ponta a ponta."
+ },
+ {
+ "q": "Em quais sistemas posso rodar?",
+ "a": "A linha de comando roda em Windows e Linux, tanto em Intel quanto em ARM, e em Macs com Apple Silicon. A janela de desktop é distribuída para Windows em Intel, Linux em Intel e Macs com Apple Silicon. Macs Intel não são suportados e nada é compilado para eles."
+ },
+ {
+ "q": "Preciso instalar alguma coisa?",
+ "a": "Não. Baixe o arquivo do seu sistema, descompacte e execute o binário. Não há instalador, runtime para adicionar nem dependência para resolver. Se você tem Go, um único comando go install também funciona.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "Por que uma execução sobre milhares de arquivos é mais lenta no Windows?",
+ "a": "Porque o Windows cobra mais por cada caminho que examina, e um comando que percorre milhares de arquivos examina milhares de caminhos. Medido em uma máquina com 3000 arquivos de 1 kB, o verify leva cerca de 0,9 segundo no Windows e cerca de 0,2 segundo no Linux em um contêiner. Um caminho de saída mais curto reduz o valor do Windows, porque cada pasta acima dos arquivos faz parte do que é examinado."
+ }
+ ]
+}
diff --git a/web/content/pt-BR/use-cases.html b/web/content/pt-BR/use-cases.html
new file mode 100644
index 00000000..620c8413
--- /dev/null
+++ b/web/content/pt-BR/use-cases.html
@@ -0,0 +1,135 @@
+
Para que as pessoas usam
+
+ Cinco tarefas que aparecem em quase todo projeto que aceita arquivos de pessoas, e o comando que faz
+ cada uma. Todo exemplo abaixo roda como está escrito.
+
+
+
+
Limites de upload
+
Testar se um limite de tamanho de arquivo é aplicado onde diz que é
+
+ Um limite são três casos de teste, não um: logo abaixo, exatamente nele e logo acima. Conseguir
+ esses à mão significa calcular contagens de bytes e torcer para não ter errado por um. Peça o
+ conjunto no lugar:
+
+ Você recebe três PDFs reais com 1048575, 1048576 e 1048577 bytes, e um manifesto dizendo que os dois
+ primeiros devem ser aceitos e o terceiro rejeitado por size_limit. Seu teste lê a
+ expectativa em vez de você escrever três asserções à mão - e quando o limite muda, você muda um
+ número e roda de novo.
+
+
+ O mesmo funciona sem preset quando você quer um único conjunto de limites embutido:
+
+ Fixtures binárias grandes deixam um repositório lento de clonar e chato de revisar, e ninguém sabe
+ dizer o que mudou quando uma é substituída. Uma receita são algumas centenas de caracteres de
+ YAML que reconstroem os arquivos idênticos - byte a byte, em qualquer máquina -
+ porque cada arquivo é derivado do seed da execução.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Cada término tem seu próprio código de saída, então um pipeline consegue distinguir uma receita ruim
+ de um disco cheio e de uma divergência de verificação. Uma execução com falha não imprime nada
+ na saída padrão, o que impede um parser de logs de ler um erro como dado.
+
+
+
+
+
Escala
+
Descobrir o que acontece quando a pasta é grande
+
+ Rotinas de importação, jobs noturnos e listagens de diretório se comportam diferente com dez mil
+ arquivos do que com dez. Tamanhos sorteados de um intervalo fazem o conjunto parecer tráfego
+ real em vez de dez mil arquivos idênticos, e o sorteio vem do seed, então o conjunto é o mesmo
+ amanhã.
+
+ Uma execução maior que o espaço livre no disco é recusada antes de o primeiro byte ser escrito, em
+ vez de encher o disco e falhar no meio.
+
+
+
+
+
Arquivos compactados
+
Testar um descompactador com um arquivo compactado que realmente contém arquivos
+
+ Um arquivo compactado vazio com a extensão certa não prova nada sobre o código que o abre e percorre
+ o que há dentro. Declare o conteúdo e o arquivo compactado realmente o contém:
+
+ Profundidade de aninhamento, contagem de entradas e tamanho do que há dentro são coisas sobre as
+ quais uma rotina de importação tem opinião, e é assim que você descobre quais são.
+
+
+
+
+
Parsers e visualizadores
+
Conferir se o seu próprio código lê um formato como o software real
+
+ Todo formato aqui é verificado com um leitor independente antes de ser liberado - um PNG é aberto e
+ seus pixels comparados, um DOCX é relido por bibliotecas separadas, um arquivo compactado é
+ extraído. Isso significa que um arquivo que o seu parser recusa é uma descoberta sobre o seu
+ parser, não sobre o gerador.
+
+ A página de formatos lista as configurações que cada um aceita e o
+ menor arquivo que cada um pode ser.
+
+
+
+
+
Guias
+
Dois deles em detalhe
+
+
+ Arquivos de teste corrompidos - um arquivo
+ quebrado de propósito, com o tamanho exato e com o que deve acontecer com ele escrito no
+ manifesto.
+
+
+ Arquivos de teste no CI - um workflow do GitHub
+ Actions, um job do GitLab e os códigos de saída que fazem um build falhar.
+
+
+
+
+
+
Para quem é
+
+ Engenheiros de QA, automação de testes e qualquer pessoa cujo código tenha atrás um formulário de
+ upload, uma rotina de importação, um parser ou uma cota de armazenamento. Roda em uma máquina
+ sem rede nenhuma, o que importa em um ambiente corporativo fechado onde um gerador baseado em
+ navegador não é opção.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/ro/ci.html b/web/content/ro/ci.html
new file mode 100644
index 00000000..1a52e87b
--- /dev/null
+++ b/web/content/ro/ci.html
@@ -0,0 +1,192 @@
+{{ with .Up }}
+ Un fixture binar într-un repository rămâne pentru totdeauna în istoricul lui, nu poate fi revizuit
+ într-un diff și devine imposibil când fișierul este mare. Generează în schimb fișierele în
+ pipeline, dintr-o rețetă. Rețeta este text, octeții ies la fel de fiecare dată, iar un ultim pas
+ dovedește că nimic nu s-a mișcat.
+
+
+
+
Răspunsul scurt
+
+ Instalează tfg, rulează tfg generate fixtures.yaml --out ./fixtures
+ înaintea testelor și tfg verify ./fixtures/manifest.json după ele. Ambii pași fac
+ singuri build-ul să eșueze, cu un cod de ieșire care spune de ce.
+
+
+
+
+
De ce să nu le comiți
+
De ce un fixture nu trebuie să stea în repository
+
+
+ Rămâne în istoric. Ștergerea ulterioară a unui binar nu face un clon mai mic,
+ pentru că fiecare versiune a lui este încă acolo.
+
+
+ Un diff nu arată ce s-a schimbat. Cel care revizuiește vede că un PDF este diferit
+ și nimic altceva. O rețetă se schimbă cu o linie.
+
+
+ Fișierele mari nu încap. GitHub refuză un push care conține un fișier de peste 100
+ MB, așa că un test al unei limite de încărcare de 500 MB nu are ce comite.
+
+
+
+ Ce trebuie comis este rețeta. Aceeași rețetă și același seed scriu aceiași octeți pe orice mașină,
+ deci fișierul generat în pipeline este fișierul pe care l-ai avut pe laptop.
+
+
+
+
+
Rețeta
+
O rețetă care stă lângă teste
+
+ Aceasta scrie douăzeci și cinci de facturi care trebuie acceptate și două imagini peste o limită
+ care trebuie respinse, iar manifestul notează ambele așteptări:
+
+ Linia cu suma de control compară arhiva cu verify-SHA256SUMS.txt din aceeași versiune.
+ Versiunea este fixată, așa că o versiune nouă nu schimbă niciodată un build pe care nu l-ai
+ atins.
+
+ Fiecare final are propriul cod de ieșire, deci pasul eșuează singur, iar jurnalul spune care a fost.
+ Cele pe care le întâlnește un pipeline:
+
+
+
3 - rețeta nu este validă. Nu s-a scris nimic, iar fiecare problemă este numită
+
4 - formatul nu poate face ce s-a cerut, de exemplu o mărime sub minimul lui
+
6 - nu este destul spațiu pe disc
+
7 - tfg verify a găsit un fișier care nu se potrivește cu manifestul lui
+
8 - rularea s-a încheiat, dar nu s-a produs totul
+
+
+ O rulare eșuată nu afișează nimic la ieșirea standard, așa că un parser de jurnale nu ia niciodată o
+ eroare drept date. Tabelul complet este pe pagina de
+ documentație.
+
+
+
+
+
PowerShell
+
Un script PowerShell mai are nevoie de o linie
+
+ PowerShell nu scoate codul de ieșire al unui program dintr-un fișier .ps1. Rulează unul
+ cu -File și scriptul răspunde 0 chiar și când instrumentul dinăuntru a
+ refuzat lucrul, așa că un build care ar trebui să fie roșu devine verde. Ultima linie este toată
+ soluția:
+
+ Așa se comportă PowerShell, nu este ceva legat de acest instrument. cmd,
+ bash și zsh nu au nevoie de nimic în plus.
+
+
+
+
+
Mai multe joburi
+
Împărțirea fixture-urilor între joburi
+
+ De obicei nu e nevoie să le încarci. Fiindcă aceeași rețetă scrie aceiași octeți, fiecare job își
+ poate rula propriul tfg generate, ceea ce e mai rapid decât o încărcare și o
+ descărcare. Când un job trebuie să primească fișiere de la altul, rulează tfg
+ verify pe manifest după transfer, și îți spune dacă ce a ajuns este ce s-a scris.
+
+ Un validator căruia i s-au arătat doar fișiere sănătoase nu a fost cu adevărat testat. Iată cum
+ obții un fișier stricat intenționat, care iese cu exact mărimea pe care o ceri și
+ vine cu un manifest care spune ce trebuie să facă sistemul tău cu el.
+
+
+
+
Răspunsul scurt
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out scrie un PNG de
+ exact 2097152 de octeți ai cărui primi octeți sunt zerouri, iar manifestul de lângă el notează
+ că sistemul tău trebuie să îl respingă.
+
+
+
+
+
Calea obișnuită
+
De ce un fișier corupt de mână face un test prost
+
+ Căile obișnuite sunt un editor hexazecimal, un script care schimbă câțiva octeți la întâmplare sau
+ un fișier scurtat cu head ori truncate. Merg o dată, apoi te costă:
+
+
+
+ Este altfel de fiecare dată. Un octet ales la întâmplare cade în alt loc la fiecare
+ rulare, deci o eroare de marți poate să nu se mai întoarcă miercuri.
+
+
+ Schimbă mărimea. Un fișier tăiat este mai mic decât limita sub care trebuia să
+ stea, deci verificarea mărimii răspunde înaintea celei a conținutului, iar testul trece din
+ motivul greșit.
+
+
+ Adesea trece neobservat. Textul simplu se citește în continuare cu un octet
+ schimbat la mijloc, iar un cititor de imagini îngăduitor îl desenează pur și simplu, așa că
+ fișierul care trebuia să fie stricat este acceptat.
+
+
+ Nu spune nimic despre ce trebuie să se întâmple. Fișierul este doar octeți, iar
+ cine citește testul mai târziu trebuie să ghicească dacă s-a urmărit acceptarea sau
+ respingerea.
+
+
+
+
+
+
Ce primești
+
Un fișier deteriorat are în continuare mărimea cerută
+
+ Fișierul este generat normal și stricat după aceea, pe drumul spre disc. Păstrează mărimea cerută,
+ iar aceeași comandă scrie din nou aceiași octeți.
+
+ Setările se scriu după două puncte. Opțiunea poate fi repetată, iar deteriorările se aplică în
+ ordinea în care le scrii. Funcționează cu fiecare dintre cele {{ .Facts.FormatCount }} formate.
+
+
+
+
+
Ce poate face
+
Ce deteriorări există?
+
+ Aceasta este lista pe care o afișează programul, citită din el când se construiește pagina.
+ tfg damage o afișează pe aceeași, iar tfg damage <id> spune ce
+ primește una dintre ele.
+
+ {{ template "damagesTable" . }}
+
+ zero-head scrie zerouri peste începutul fișierului. Majoritatea cititorilor se uită
+ întâi acolo, la semnătura și antetul care spun ce este fișierul, așa că aproape orice cititor
+ observă. Textul simplu și jurnalele nu au semnătură și sunt respinse și ele, pentru că un șir de
+ octeți nuli nu este text. Sub patru octeți, unele formate ies cu o deteriorare de care nu se
+ plânge niciun cititor, de aceea setarea începe de la patru.
+
+
+
+
+
Ce spune manifestul
+
Un manifest care spune ce trebuie să se întâmple
+
+ Fiecare fișier deteriorat primește o intrare care spune că sistemul tău trebuie să îl respingă, cu
+ deteriorarea notată alături:
+
+ Două cereri sunt refuzate înainte să se scrie ceva, pentru că fiecare ar lăsa pe disc un fișier pe
+ care manifestul îl descrie greșit:
+
+
+
un fișier mai mic decât are nevoie deteriorarea, care ar ieși neschimbat
+
+ expected: accept lângă o deteriorare, pentru că nimic nu ar putea îndeplini asta. Scrie
+ sanitize dacă sistemul tău trebuie să repare fișierul sau
+ unspecified dacă tocmai asta este întrebarea pe care o pui
+
+
+
+
+
+
Într-o rețetă
+
Fișiere sănătoase și stricate într-o singură rulare
+
+ Pune-le pe amândouă într-o rețetă, iar manifestul poartă așteptarea fiecărui fișier, deci testul nu
+ are nevoie de o listă cu care este care:
+
+ Testul citește manifestul și verifică dacă ce s-a întâmplat este ce s-a declarat. Nu are nevoie de o
+ listă de nume de fișiere:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ O respingere bună este una curată. Un mesaj care spune ce a fost greșit este răspunsul pe care îl
+ vrei. O eroare de server, o blocare sau un fișier salvat pe jumătate este defectul pe care acest
+ test există ca să îl găsească.
+
+
+
+
+
Mai departe
+
Unde să mergi de aici
+
+
+ Presetarea upload-validation pune unui formular
+ celelalte două întrebări, cea despre mărime și cea despre tip.
+
+ Documentația cuprinde fiecare opțiune a lui tfg
+ generate.
+
+
+
diff --git a/web/content/ro/docs.html b/web/content/ro/docs.html
new file mode 100644
index 00000000..b7e04504
--- /dev/null
+++ b/web/content/ro/docs.html
@@ -0,0 +1,281 @@
+
Documentație
+
+ Tot ce face instrumentul, aranjat ca întrebările cu care vin oamenii de fapt.
+ README-ul din repository este referința completă și se potrivește
+ mereu cu versiunea pe care ai descărcat-o.
+
+
+
+
Ce comenzi există?
+
Fiecare face un singur lucru:
+ {{ template "commandList" . }}
+
+
+
+
Cum generez un singur fișier de dimensiune exactă?
+
+ Spune formatul, dimensiunea și unde merge. Dimensiunile se numără din 1024 în 1024, deci
+ 2mb sunt 2097152 octeți. Merge și un simplu număr de octeți, deci --size
+ 10485761 cere exact atât.
+
+
tfg generate --format png --size 2mb --out ./out
+
Opțiunile utile ale comenzii generate:
+
+
+
Opțiune
Ce face
+
+
--format <id>
formatul fișierelor, de exemplu txt
+
--size <size>
dimensiunea exactă a fiecărui fișier, precum 10mb sau un simplu număr de octeți
+
--size-range <a-b>
o dimensiune extrasă pentru fiecare fișier dintr-un interval, precum 1kb-8kb. Extragerea vine din seed
+
--boundary <size>
trei fișiere în jurul unei limite: un octet sub, limita, un octet peste
+
--count <n>
câte fișiere să producă. Implicit 1
+
--name <template>
șablon de nume, de exemplu invoice_{index:04}.txt
+
--out <dir>
directorul în care se scrie
+
--seed <n>
seed-ul rulării. Același seed dă aceiași octeți
+
--set <k>=<v>
o setare de format, repetabilă
+
--damage <name>
strică fișierele intenționat, repetabil și aplicat în ordine. Rulează tfg damage pentru listă
+
--expected <outcome>
accept, reject, sanitize sau unspecified
+
--dry-run
numără și arată, nu scrie absolut nimic
+
--json
scrie manifestul la ieșirea standard
+
+
+
+
+
+
+
Cum fac un fișier stricat intenționat?
+
+ Orice alt fișier scris de acest instrument este corect prin construcție, ceea ce răspunde la două
+ din cele trei întrebări pe care le pune un validator de încărcare. --damage
+ răspunde la a treia - se deschide oare fișierul. Fișierul este produs normal și apoi stricat,
+ deci are în continuare dimensiunea cerută.
+
+ Setările se pun după două puncte. Opțiunea se repetă, iar ordinea în care le scrii este ordinea în
+ care se aplică. tfg damage listează ce poate face această versiune și ce acceptă
+ fiecare.
+
+
Într-o rețetă cheia este o listă, de nume sau de setări:
+ Un fișier deteriorat primește expected: reject în manifest, cu deteriorarea consemnată
+ alături. Două lucruri sunt refuzate înainte de a se scrie ceva, pentru că fiecare ar pune pe
+ disc un fișier pe care manifestul îl descrie greșit:
+
+
+
un fișier mai mic decât are nevoie deteriorarea, pentru că ar ieși neschimbat
+
+ expected: accept alături de o deteriorare, pentru că nimic nu l-ar putea îndeplini.
+ Scrie sanitize dacă sistemul testat trebuie să repare fișierul sau
+ unspecified dacă exact asta e întrebarea pe care o pui
+
+
+
+ O a treia nu se poate ști dinainte. Dacă o deteriorare rulează și nu mută niciun octet, fișierul
+ respectiv este abandonat în loc să fie scris - rularea continuă, spune care a fost fișierul și
+ se termină cu codul de ieșire parțial.
+
+ O rețetă este un fișier YAML care descrie o rulare întreagă. Comite-o lângă testele tale și
+ fixture-urile nu mai sunt binare în repository - oricine le poate reconstrui, octet cu octet,
+ dintr-un fișier de câteva sute de caractere.
+
+ Fiecare target are nevoie de exact una dintre cheile size, size-range,
+ boundary sau contains. Două este o eroare și la fel niciuna. O rețetă
+ invalidă nu scrie niciun fișier și raportează toate problemele deodată, nu doar
+ prima, fiecare numind setarea la care se referă.
+
+
+
+
+
Cum declar ce trebuie să facă sistemul meu cu un fișier?
+
Formă scurtă când rezultatul e de ajuns, formă lungă când contează motivul:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Rezultatele sunt accept, reject, sanitize și
+ unspecified. Motivele sunt o listă închisă ca un raport să poată grupa după ele:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit și size_zero.
+
+
+ Un motiv numește regula în joc, nu verdictul. De aceea același motiv poate sta sub
+ oricare dintre rezultate - un fișier cu un octet sub o limită este accept, iar
+ regula la care se referă rămâne size_limit.
+
+
+
+
+
Ce conține manifestul?
+
+ Se scrie lângă fișiere la sfârșitul fiecărei rulări, inclusiv a uneia întrerupte. O intrare pentru
+ fiecare fișier:
+
+ Se adaugă un recipe_hash când rularea a venit dintr-o rețetă și preset cu
+ overrides când a venit dintr-o presetare, astfel încât un manifest poate fi mereu
+ urmărit până la ce l-a produs.
+
+
+ Fiecare intrare poartă și target_id, id-ul targetului din rețeta care a produs
+ fișierul, iar summary.by_target numără fișierele la care a ajuns fiecare target. O
+ rețetă cu mai multe targeturi poate fi verificată astfel target cu target, fără a citi nume de
+ fișiere.
+
+
+
+
+
Ce este o presetare?
+
+ Un set de fișiere gata făcut care răspunde unei întrebări de test obișnuite, ca să nu trebuiască să
+ proiectezi tu setul. Presetările sunt rețete obișnuite pe dedesubt, iar eject
+ afișează rețeta ca s-o poți edita de acolo. Fiecare presetare are o
+ pagină proprie cu ce găsește de obicei, ce este în set și fiecare setare pe care o acceptă.
+
+ show îți spune cât ar costa setul înainte să-l construiești și spune pe față când un
+ număr este o valoare provizorie de-a noastră, nu o limită de-a ta.
+
+
+
+
+
Ce înseamnă codurile de ieșire?
+
+ Fiecare final are propriul cod, ieșirea citibilă de mașină merge la ieșirea standard, iar o rulare
+ eșuată nu tipărește nimic acolo. Tabelul este un contract înghețat - schimbarea sensului unui
+ cod cere o versiune majoră.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ O rulare oprită cu Ctrl+C lasă totuși un manifest și nu lasă niciodată un fișier scris pe jumătate,
+ așa că un job anulat poate fi curățat de următorul.
+
+ Da, același motor cu o fereastră deasupra, pentru testarea care nu e automatizată. Nu e o versiune
+ redusă: un test compară cele două interfețe capacitate cu capacitate, iar tot ce poate face doar
+ una dintre ele trebuie declarat și justificat, nu lăsat să divergă pe tăcute.
+
+
+ Ecranele sunt un lot, presetări, mai multe loturi deodată și Despre. Arată cât ar costa o rulare
+ înainte să scrie ceva, raportează progresul cât rulează și poate fi anulată pe la jumătate fără
+ să lase un fișier scris pe jumătate. Nu deschide încă un fișier de rețetă - rețetele sunt
+ deocamdată treaba liniei de comandă, iar fereastra își construiește loturile în formular.
+
+
diff --git a/web/content/ro/exact-size.html b/web/content/ro/exact-size.html
new file mode 100644
index 00000000..aca2dbb7
--- /dev/null
+++ b/web/content/ro/exact-size.html
@@ -0,0 +1,145 @@
+
Cum creezi un fișier de dimensiune exactă
+
+ Fiecare sistem are o comandă pentru asta, iar toate trei sunt mai jos. Îți dau un fișier cu exact
+ numărul potrivit de octeți - și pentru multe teste atât îți trebuie. Fiecare comandă de pe
+ această pagină a fost rulată înainte de publicare, pe sistemul căruia îi aparține.
+
+
+
+
Răspunsul scurt
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Dimensiunile sunt în octeți, iar 10
+ MB numărați cum numără managerul tău de fișiere sunt 10485760.
+
+
+
+
+
Windows
+
fsutil și o variantă PowerShell care nu are nevoie de nimic în plus
+
+ fsutil vine cu Windows. Primește dimensiunea în octeți, așa că
+ calculează mai întâi numărul - 10 MB sunt 10485760, 100 MB sunt 104857600, 1 GB este 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Măsurat pe Windows 11: merge dintr-un prompt obișnuit, fără să ceară unul cu privilegii ridicate,
+ iar fișierul iese de exact 10485760 de octeți.
+
+
PowerShell poate face același lucru fără să cheme alt program și înțelege unitățile:
+ 10MB în PowerShell înseamnă 10485760 de octeți, aceeași numărare în baza 1024 pe care o
+ folosește Explorer, deci cele două comenzi de mai sus produc aceeași dimensiune.
+
+
+
+
+
Linux
+
dd, truncate și fallocate, și diferența care îi prinde pe oameni
+
dd este cel pe care îl știe toată lumea. Scrie într-adevăr octeții:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate e instantaneu și asta e capcana. Măsurat pe Alpine Linux, fișierul raportează
+ 10485760 de octeți și ocupă zero blocuri - este un fișier rar
+ (sparse). Tot ce îl citește primește zece megaocteți de zerouri, dar discul nu a cedat niciodată
+ spațiul:
+
+
truncate -s 10M test10mb.bin
+
+ E bine pentru a testa o limită de încărcare și înșelător pentru a testa o cotă de disc.
+ fallocate este cel de folosit când spațiul trebuie să fie real:
+
+
fallocate -l 10M test10mb.bin
+
Și când conținutul trebuie să fie incompresibil, ca un arhivator să nu-l poată strânge la loc:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, care nu e rar, și cele două pe care le știi deja
+
+ macOS vine cu mkfile. Măsurat pe macOS 26.6.2: 10485760 de octeți și 20480 de blocuri,
+ deci spațiul este alocat cu adevărat, nu doar promis:
+
+
mkfile 10m test10mb.bin
+
dd și truncate sunt și ele acolo și se comportă ca pe Linux:
Un fișier de dimensiunea potrivită nu este un fișier de tipul potrivit
+
+ Tot ce e mai sus îți dă un bloc de zerouri. Asta ajunge când ce se testează se uită doar la
+ dimensiune - o limită de încărcare, o cotă, un transfer. Nu mai ajunge din clipa în care ceva
+ deschide fișierul.
+
+
+ Măsurat, și merită să încerci singur: fă un fișier de 2 MB cu fsutil, numește-l
+ photo.png și dă-l unei biblioteci de imagini. Pillow răspunde cannot identify
+ image file. Nu e un PNG. N-a fost niciodată - doar numele o spunea.
+
+
+ Contează mai mult decât pare, din cauza direcției în care eșuează testul.
+ Endpointul tău de încărcare respinge fișierul, testul tău devine verde și tragi concluzia că
+ limita de dimensiune funcționează. Nu l-a respins pentru dimensiune. L-a respins pentru că
+ octeții nu erau o imagine, iar regula pe care voiai s-o testezi n-a fost niciodată atinsă.
+
+
+
un parser îl respinge înainte să se uite vreo regulă de dimensiune
+
un pas de miniatură eșuează și eroarea pe care o citești e despre miniatură
+
un antivirus sau o verificare de conținut îl refuză dintr-un al treilea motiv
+
un vizualizator nu arată nimic și nimeni nu poate spune dacă asta e bug-ul
+
+
+
+
+
Cealaltă cale
+
Un fișier real de acel format, la exact dimensiunea cerută
+
+ Asta face Testing Files Generator. Fișierul este unul autentic al formatului său - se deschide în
+ programul căruia îi aparține - și are numărul exact de octeți pe care l-ai cerut, la octet:
+
+ Cere o dimensiune pe care un format nu o poate atinge și primești o eroare care numește pragul și
+ motivul lui, niciodată un fișier de dimensiune greșită. Pagina de
+ formate listează fiecare format cu cel mai mic fișier pe care îl poate produce.
+
+
Iar o limită înseamnă trei cazuri de test, nu unul, așa că instrumentul le construiește pe toate trei:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Asta îți dă 10485759, 10485760 și 10485761 de octeți și un manifest care spune pe care sistemul tău
+ trebuie să le accepte și pe care să le respingă. Pagina de
+ cazuri de utilizare parcurge asta și alte patru sarcini pentru care a fost făcut.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Deci pe care să-l folosești?
+
+
+
Folosește comanda sistemului
+
+ Când nimic nu deschide fișierul. Testarea unei limite de dimensiune pe un endpoint care verifică
+ întâi dimensiunea, un transfer, o cotă, un disc plin. E o singură linie și e deja instalat.
+
+
+
+
Folosește un generator adevărat
+
+ Când ceva analizează, randează, importă sau extrage fișierul - și când ai nevoie de aceleași
+ fixture-uri mâine, pe altă mașină, octet cu octet.
+
+
+
+
+ Ambele sunt pe această pagină pentru că ambele au dreptate o parte din timp. Greșeala de evitat este
+ să-l folosești pe primul unde îl trebuie pe al doilea și să citești testul verde drept dovadă.
+
+
diff --git a/web/content/ro/faq.html b/web/content/ro/faq.html
new file mode 100644
index 00000000..d1dcf5d8
--- /dev/null
+++ b/web/content/ro/faq.html
@@ -0,0 +1,20 @@
+
Întrebări frecvente
+
+ Licență, confidențialitate, reproductibilitate și lucrurile pe care oamenii le verifică înainte să
+ pună un generator într-un pipeline de build. Dacă întrebarea ta nu e aici,
+ sistemul de issue-uri este deschis.
+
{{ .Facts.FormatCount }} formate de fișiere, fiecare generat la o dimensiune exactă
+
+ Fiecare este un fișier real al acelui format. Se deschide în programul căruia îi
+ aparține și are exact numărul de octeți pe care l-ai cerut. Niciunul nu e umplutură de zerouri cu
+ o extensie lipită.
+
+
+{{ template "formatsTable" . }}
+
+
+
Ce înseamnă coloanele
+
+
+
Cel mai mic fișier
+
+ Cel mai mic număr de octeți pe care instrumentul îl acceptă pentru acel format, inclusiv eticheta pe
+ care o scrie în fișier. Cere mai puțin și primești o eroare care numește pragul și motivul
+ lui, niciodată un fișier de dimensiune greșită.
+
+
+
+
Fidelitate
+
+ Cât de complet este fișierul. full înseamnă că un cititor care analizează cu adevărat
+ formatul îl acceptă, nu doar că extensia se potrivește.
+
+
+
+
Verificat cu
+
+ Cititorul independent care deschide fiecare fișier generat înainte ca formatul să fie livrat - o
+ implementare separată, nu propriul nostru cod care își corectează singur temele.
+
+
+
+
+ Fiecare format se și repetă la octet: aceeași rețetă și același seed produc fișiere identice pe
+ orice mașină, ceea ce face sigur să comiți o rețetă în locul fixture-urilor înseși.
+
+
+
+
+
Setările pe care le acceptă fiecare format
+
+ Majoritatea formatelor au setări proprii - dimensiunile imaginii, calitatea JPEG, numărul de pagini
+ PDF, rândurile și coloanele dintr-o foaie de calcul, câte intrări intră într-o arhivă.
+ Setează-le cu --set key=value în linia de comandă sau sub properties:
+ într-o rețetă.
+
+ O valoare în afara a ce acceptă o setare este refuzată cu un mesaj care numește setarea, intervalul
+ permis și ce să folosești în loc. O setare necunoscută este și ea o eroare, niciodată o valoare
+ implicită tăcută - o greșeală de scriere acceptată pe tăcute dă un fișier cu setările greșite și
+ o oră de întrebări de ce trece testul când n-ar trebui.
+
+
+ Rulează tfg formats <id> ca să vezi exact ce acceptă un format în versiunea pe
+ care o ai.
+
+
+
+
+
Arhivele conțin fișiere reale
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} și {{ end }}{{ $c.ID }}{{ end }} pot
+ fi umplute cu intrări, nu lăsate ca o carcasă goală. O arhivă generată conține cu adevărat
+ documentele pe care spune că le conține, așa că tot ce o dezarhivează în timpul unui test
+ găsește înăuntru fișiere reale.
+
Generează fișiere de test reale la dimensiunea exactă
+
+ PDF, PNG, DOCX, ZIP - {{ .Facts.FormatCount }} formate în total, și fiecare este un
+ fișier real care se deschide în programul căruia îi aparține, la exact dimensiunea pe
+ care ai cerut-o. Fiecare rulare notează și ce trebuie să facă aplicația ta cu fiecare
+ fișier. Linie de comandă și fereastră desktop, gratuit și open source, funcționând în întregime
+ pe mașina ta.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ Fereastra desktop, pregătită să scrie un lot de fișiere. Același motor rulează în spatele liniei de comandă.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
formate reale, fiecare se deschide în programul căruia îi aparține
+
+
+ 1 octet
+
precizia fiecărei dimensiuni cerute, niciodată rotunjită pe tăcute
+
+
+ 0
+
conexiuni către orice loc - fără cont, fără telemetrie, fără verificare de actualizări
+
+
+
+
+
Problema
+
Să faci un fișier de test e ușor. Să faci cele o mie potrivite e partea plictisitoare
+
Testezi software care primește fișiere de la oameni. Mai devreme sau mai târziu ai nevoie de:
+
+
un PDF de exact 10 MB, ca să afli dacă limita de încărcare e reală
+
cele trei fișiere de o parte și de alta a acelei limite, ca să prinzi erorile de unu
+
10.000 de fișiere de jurnal, ca să vezi ce face jobul de noapte când folderul e mare
+
un ZIP care chiar conține 200 de documente, nu o carcasă goală cu extensia potrivită
+
un fișier de 4 GB, fără să ții un fișier de 4 GB în repository
+
aceleași fixture-uri pe laptopul tău și pe serverul de build, octet cu octet
+
+
+ Asta înlocuiește acesta. Este construit pentru ingineri QA, automatizarea testelor și oricine are în
+ spatele codului un formular de încărcare, o rutină de import, un parser sau o cotă de stocare.
+
+
+
+
+
Ce îl face diferit
+
Alte generatoare se opresc la octeți. Acesta răspunde la ce întreabă de fapt testul tău
+
+ Un folder de fișiere te lasă tot pe tine să hotărăști ce trebuie să demonstreze fiecare. Fiecare
+ rulare scrie aici un manifest.json lângă fișiere - o listă simplă a tot ce s-a
+ produs și, pentru fiecare intrare, o așteptare declarată.
+
+
Să zicem că endpointul tău de încărcare permite 1 MB. Cere cele trei fișiere de pe acea linie:
Acolo unde răspunsul depinde de propria ta politică, manifestul spune asta
+
+ Înregistrează unspecified în loc să inventeze o așteptare. Un generator care ghicește
+ produce eșecuri false, iar o suită care dă alarme false ajunge oprită.
+
+
+
+
+
+
Presetări
+
Alege întrebarea, primești setul întreg
+
+ O presetare este un set de fișiere de test conceput în jurul unei întrebări de test, ca să nu fie
+ nevoie să afli tu ce fișiere dovedesc ce. Fiecare are o pagină care spune ce găsește de obicei,
+ ce este în set și fiecare setare pe care o acceptă.
+
+ Zece mii de fișiere de jurnal, fiecare între unu și opt kiloocteți, cu dimensiunile extrase din seed
+ ca mâine să dea același set. Dă fiecărei rulări propriul director -
+ manifestul este singura evidență a ce a scris o rulare, așa că instrumentul refuză să scrie
+ un al doilea peste el:
+
+ Dimensiunile se numără din 1024 în 1024, cum o face managerul tău de fișiere, deci 2mb
+ înseamnă 2097152 octeți. Merge și un simplu număr de octeți.
+ Documentația acoperă rețetele, manifestul și codurile de ieșire.
+
+
+
+
+
Ce primești
+
Construit pentru o suită care rulează nesupravegheată
+
+
+
Dimensiune exactă, la octet
+
Cere 10485761 de octeți și primești exact atât. O dimensiune pe care un format nu o poate atinge este o eroare cu un motiv, niciodată un fișier de dimensiune greșită.
+
+
+
{{ .Facts.FormatCount }} formate reale
+
Nu zerouri de umplutură cu o extensie. Un PNG generat se deschide într-un vizualizator de imagini, un DOCX se deschide în Word, un ZIP se extrage. Fiecare este verificat cu cititori independenți înainte de livrare.
+
+
+
Un manifest care este un oracol de test
+
Cale, dimensiune, SHA-256, format, seed, versiunea instrumentului - și ce trebuie să facă sistemul tău cu fișierul.
+
+
+
Reproductibil
+
Aceeași rețetă și același seed, aceiași octeți, pe orice mașină. Comite o rețetă YAML mică în loc de fixture-uri binare mari.
+
+
+
Două interfețe, un singur motor
+
O linie de comandă făcută pentru CI și o fereastră desktop pentru testarea exploratorie. Niciuna nu e o versiune redusă a celeilalte, iar un test le compară capacitate cu capacitate.
+
+
+
Complet offline
+
Fără cont, fără cloud, fără telemetrie, fără verificare de actualizări. Binarul liniei de comandă nu are compilat în el niciun stack de rețea.
+
+
+
+
+
+
Descărcare
+
Alege versiunea pentru sistemul tău
+
+ Dezarhivează arhiva și rulează-o. tfg este linia de comandă și tfg-gui
+ este fereastra desktop. Nu există instalator și nimic de adăugat pe mașina ta.
+
+ {{ template "downloadsTable" . }}
+
+
Ce este semnat și ce nu
+
+ Descărcările pentru Windows și macOS sunt semnate, așa că pornesc fără avertisment despre un
+ dezvoltator necunoscut. Cele pentru Linux nu sunt, pentru că Linux pe desktop nu are un
+ echivalent cu care să le semnezi. Fiecare arhivă este listată în
+ verify-SHA256SUMS.txt pe pagina de versiuni, ca să poți verifica ce ai descărcat.
+
+ Presetarea {{ .ID }} construiește cu o singură comandă un set întreg de fișiere de test
+ reale pentru această întrebare, și un manifest.json alături care spune cum trebuie să
+ reacționeze sistemul tău la fiecare fișier. Tot ce urmează este citit din program, la valorile
+ implicite ale acestei versiuni.
+
+
+{{ if .Catches }}
+
+
Ce găsește de obicei?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
Ce este în set?
+
La valorile implicite, așa cum le raportează tfg preset show {{ .ID }}:
+
+
+
+
Fișiere
{{ .Budget.Files }}
+
Targeturi în rețeta lui
{{ .Budget.Targets }}
+
Dimensiune totală
{{ .Bytes }} B
+
Formate
{{ join .Budget.Formats ", " }}
+
+
+
+
Și ce așteaptă manifestul acelui set de la sistemul tău:
+
+
+
+
Așteptat
Semnificație
Fișiere
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
Ce poți schimba?
+ {{- if .Settings }}
+
+
+
+
Setare
Primește
Implicit
Ce face
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Această valoare implicită este valoarea noastră provizorie, nu valoarea sistemului tău. Dă-o pe a ta.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
Această presetare nu are setări. Setul este același de fiecare dată.
+ {{- end }}
+
+
+
+
Cum o rulezi?
+
Vezi cât ar costa setul, construiește-l sau ia-i rețeta ca s-o editezi:
Sau construiește peste ea într-o rețetă proprie, lângă testele tale:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/ro/presets.html b/web/content/ro/presets.html
new file mode 100644
index 00000000..017f703b
--- /dev/null
+++ b/web/content/ro/presets.html
@@ -0,0 +1,32 @@
+
Presetări de fișiere de test, câte un set pentru fiecare întrebare de test
+
+ O presetare este un set întreg de fișiere de test conceput în jurul unei întrebări, cu un manifest
+ care spune cum trebuie să reacționeze sistemul tău la fiecare fișier. Tu alegi întrebarea,
+ instrumentul construiește setul. Fiecare presetare are propria pagină cu ce găsește de obicei, ce
+ este în set și fiecare setare pe care o acceptă.
+
+
+{{ template "presetsList" . }}
+
+
+
Prin ce diferă o presetare de o rețetă?
+
+ Pe dedesubt, prin nimic. O presetare este o rețetă pe care instrumentul o scrie pentru tine din
+ câteva setări. tfg preset eject afișează acea rețetă ca s-o poți păstra lângă
+ testele tale și s-o editezi, iar o rețetă proprie se poate sprijini pe o presetare cu o singură
+ linie, extends: preset: urmat de id-ul ei.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Pot avea încredere în valorile implicite?
+
+ Pentru fișiere, da. Pentru un număr pe care îl știe doar sistemul tău, precum limita unui formular
+ de încărcare, o valoare implicită este o valoare provizorie de-a noastră, iar instrumentul o
+ spune de fiecare dată când folosește una. Pagina fiecărei presetări marchează acele setări, iar
+ tfg preset show o spune înainte să se scrie ceva.
+
+
diff --git a/web/content/ro/site.json b/web/content/ro/site.json
new file mode 100644
index 00000000..8b011671
--- /dev/null
+++ b/web/content/ro/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "ro",
+ "locale": "ro_RO",
+ "name": "Română",
+ "dir": "ro",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Acasă",
+ "title": "Generator de fișiere de test - dimensiune exactă, {{ .Facts.FormatCount }} formate reale",
+ "description": "Generator gratuit și open source de fișiere de test pentru QA. PDF, DOCX, PNG și ZIP reale, la dimensiunea exactă, cu un manifest despre reacția așteptată."
+ },
+ {
+ "key": "formats",
+ "slug": "formate",
+ "nav": "Formate",
+ "title": "{{ .Facts.FormatCount }} formate de fișiere - PDF, DOCX, PNG, ZIP și altele",
+ "description": "Toate formatele generate, cel mai mic fișier posibil pentru fiecare și setările acceptate. Toate cele {{ .Facts.FormatCount }} se deschid în programul căruia îi aparțin."
+ },
+ {
+ "key": "presets",
+ "slug": "presetari",
+ "nav": "Presetări",
+ "title": "Presetări de fișiere de test - seturi gata făcute pentru QA",
+ "description": "Seturi gata făcute de fișiere de test, fiecare răspunde unei întrebări: limite de încărcare, nume de fișiere, codări, import de tabele, fișiere goale și validare."
+ },
+ {
+ "key": "docs",
+ "slug": "documentatie",
+ "nav": "Documentație",
+ "title": "Documentație - comenzi, rețete, manifest, coduri de ieșire",
+ "description": "Cum generezi fișiere de test din linia de comandă sau dintr-o rețetă YAML, ce conține manifestul și ce înseamnă fiecare cod de ieșire în CI."
+ },
+ {
+ "key": "use-cases",
+ "slug": "cazuri-de-utilizare",
+ "nav": "Cazuri de utilizare",
+ "title": "Cazuri de utilizare - limite de încărcare, fixture-uri, teste",
+ "description": "Testarea unei limite de dimensiune la încărcare, fixture-uri reproductibile pentru CI, zece mii de fișiere generate și arhive umplute cu conținut real."
+ },
+ {
+ "key": "exact-size",
+ "slug": "creare-fisier-de-dimensiune-exacta",
+ "nav": "Dimensiune exactă",
+ "title": "Cum creezi un fișier de dimensiune exactă - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate și mkfile, fiecare măsurat pe sistemul lui, și de ce un fișier făcut așa nu e un PDF sau un PNG când un test are nevoie de unul."
+ },
+ {
+ "key": "faq",
+ "slug": "intrebari-frecvente",
+ "nav": "FAQ",
+ "title": "FAQ - întrebări despre generarea fișierelor de test",
+ "description": "Prin ce diferă de dd și fsutil, dacă fișierele pot fi comise, dacă rulările se repetă octet cu octet și ce se întâmplă când o dimensiune nu poate fi atinsă."
+ },
+ {
+ "key": "damage",
+ "slug": "fisiere-de-test-corupte",
+ "nav": "Fișiere corupte",
+ "title": "Fișiere de test corupte - fișiere stricate de mărime exactă",
+ "description": "Un fișier stricat intenționat, de mărime exactă, cu un manifest care spune că sistemul tău trebuie să îl respingă. Pentru validarea încărcărilor și parsere.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "fisiere-de-test-in-ci",
+ "nav": "Fișiere de test în CI",
+ "title": "Fișiere de test în CI - GitHub Actions, GitLab CI și PowerShell",
+ "description": "Generează fișiere de test în pipeline în loc să comiți binare: workflow GitHub Actions, job GitLab, coduri de ieșire și capcana PowerShell.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "Sari la conținut",
+ "navLabel": "Principal",
+ "langLabel": "Limba",
+ "breadcrumbHome": "Acasă",
+ "imageAlt": "Testing Files Generator - fișiere de test reale la dimensiunea exactă, cu un manifest care spune cum trebuie să reacționeze sistemul tău la fiecare",
+ "schemaDescription": "Un generator gratuit și open source de fișiere de test pentru QA. Produce fișiere reale în {{ .Facts.FormatCount }} formate, la dimensiunea exactă, și scrie un manifest care spune cum trebuie să reacționeze sistemul testat la fiecare.",
+ "ctaDownload": "Descarcă",
+ "ctaSource": "Vezi codul sursă",
+ "ctaNote": "Gratuit și open source, GPL-3.0. Fără cont. Descărcările pentru Windows și macOS sunt semnate și pornesc fără avertisment.",
+ "colFormat": "Format",
+ "colName": "Nume",
+ "colExtension": "Extensie",
+ "colSmallest": "Cel mai mic fișier",
+ "colFidelity": "Fidelitate",
+ "colChecked": "Verificat cu",
+ "colSetting": "Setare",
+ "colAccepts": "Acceptă",
+ "colSystem": "Sistem",
+ "colCli": "Linie de comandă",
+ "colWindow": "Fereastră desktop",
+ "noBinary": "încă fără binar",
+ "colCode": "Cod",
+ "colMeaning": "Semnificație",
+ "footerBlurb": "Fișiere de test pentru QA, la dimensiunea exactă, cu un manifest care spune cum trebuie să reacționeze sistemul tău la fiecare.",
+ "footerProject": "Proiect",
+ "footerSource": "Cod sursă pe GitHub",
+ "footerReleases": "Descărcări",
+ "footerIssues": "Raportează o problemă",
+ "footerSupport": "Susține proiectul",
+ "footerPages": "Pagini",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. Publicat sub Licența Publică Generală GNU, versiunea 3. Fișierele pe care le generezi sunt ale tale - licența acoperă instrumentul, nu rezultatul lui.",
+ "footerPrivacy": "Acest site nu încarcă fonturi, scripturi sau trackere de nicăieri. Nu setează cookie-uri.",
+ "notFoundTitle": "Pagina aceasta nu există",
+ "notFoundLead": "Adresa pe care ai urmat-o nu corespunde niciunei pagini de pe acest site.",
+ "notFoundBack": "Mergi la pagina principală",
+ "read.format": "Formatul fiecărui fișier din set. Este o opțiune a instrumentului însuși, iar presetarea îi dă doar o valoare implicită.",
+ "readTakes.format": "un id de format din pagina de formate",
+ "colDamage": "Deteriorare",
+ "colEffect": "Ce face cu octeții",
+ "colSettings": "Setări",
+ "noSettings": "niciuna"
+ },
+ "endings": {
+ "0": "Totul a mers.",
+ "1": "O eroare neașteptată în interiorul instrumentului.",
+ "2": "Comandă sau opțiune greșită.",
+ "3": "Rețeta nu este validă.",
+ "4": "Formatul nu poate face ce s-a cerut.",
+ "5": "O citire sau o scriere a eșuat.",
+ "6": "Nu este destul spațiu pe disc.",
+ "7": "verify a găsit o nepotrivire.",
+ "8": "Rularea s-a terminat, dar nu s-a produs totul.",
+ "130": "Întreruptă cu Ctrl+C.",
+ "143": "Oprită de un semnal, așa arată o depășire de timp în CI."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "Trece un fișier valid, cât de mic permite formatul?",
+ "title": "Gol și minimal",
+ "pageTitle": "Cele mai mici fișiere de test valide și goale, în fiecare format",
+ "description": "Cel mai mic fișier valid scris în fiecare dintre cele {{ .Facts.FormatCount }} formate, plus un fișier gol acolo unde formatul permite, fiecare cu reacția așteptată.",
+ "catches": [
+ "un fișier valid respins pentru că e prea mic, când verificarea numără octeți în loc să îi citească",
+ "un fișier gol care prăbușește cititorul în loc să fie raportat",
+ "o imagine lată de un pixel care împarte la zero pe drumul spre miniatură",
+ "un depozit care citește zero octeți ca pe o încărcare eșuată și tot reîncearcă"
+ ],
+ "details": {
+ "formats": "Din ce formate este alcătuit setul. Lasă all pentru toate formatele acestei versiuni sau numește-le pe cele pe care le acceptă sistemul tău."
+ }
+ },
+ "filename-handling": {
+ "question": "Va stoca, va afișa și va returna sistemul meu un nume de fișier la care nu se aștepta?",
+ "title": "Gestionarea numelor de fișiere",
+ "pageTitle": "Nume de fișiere problematice pentru teste - Unicode și lungime",
+ "description": "Fișiere cu nume care strică încărcarea și stocarea: alte alfabete și emoji, inversarea direcției, caractere invizibile, sintaxă shell și SQL, limite de lungime.",
+ "catches": [
+ "un nume care arată ca altul pe ecran, într-un jurnal sau într-o listă",
+ "un nume tăiat, scurtat sau rescris între încărcare și stocare",
+ "o limită de lungime numărată în caractere acolo unde depozitul numără octeți"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "Este o limită de dimensiune aplicată exact acolo unde este declarată?",
+ "title": "Limite de dimensiune",
+ "pageTitle": "Testarea unei limite de încărcare - fișiere exact la limită",
+ "description": "Fișiere cu un octet sub, exact la și cu un octet peste limita declarată de sistemul tău, plus trepte mai largi de ambele părți, fiecare marcat dacă trebuie acceptat.",
+ "catches": [
+ "erori de unu în plus sau în minus la limită",
+ "MB confundat cu MiB, adică 4,8 la sută, suficient cât să treacă un fișier care n-ar trebui să treacă",
+ "o limită aplicată în browser și nu pe server"
+ ],
+ "details": {
+ "limit": "Limita de dimensiune declarată de sistemul tău. Tot restul se măsoară pornind de la ea.",
+ "spread": "Cât de departe să se meargă de ambele părți ale limitei, ca listă de dimensiuni."
+ }
+ },
+ "tabular-import": {
+ "question": "Supraviețuiește importul meu de tabele la ce exportă instrumentele reale?",
+ "title": "Import de tabele",
+ "pageTitle": "Fișiere de test pentru import CSV și Excel - delimitatori",
+ "description": "CSV cu alți delimitatori, sfârșituri de linie CR LF, fără antet și cu alte ghilimele, un tabel foarte lat, un registru Excel și JSON în mai multe forme.",
+ "catches": [
+ "un fișier cu punct și virgulă citit ca o singură coloană, pentru că delimitatorul a fost presupus în loc să fie căutat",
+ "un fișier CRLF împărțit în rânduri cu un rând gol după fiecare",
+ "un tabel fără antet al cărui prim rând de date este înghițit drept nume de coloane",
+ "un import care păstrează coloanele pe care le poate arăta și aruncă restul fără o vorbă",
+ "un cititor care ia înregistrările JSON câte o linie și se oprește la primul document indentat"
+ ],
+ "details": {
+ "rows": "Câte rânduri are foaia de calcul. Se scrie exact la dimensiunea pe care o ocupă atâtea rânduri, așa că bugetul de mai sus se mută odată cu această valoare.",
+ "columns": "Câte coloane are fiecare rând al foii de calcul. Rânduri înmulțit cu coloane are un plafon, iar cererea peste el este refuzată înainte de a se scrie ceva."
+ }
+ },
+ "text-encoding": {
+ "question": "Știe cititorul meu în ce codare este un fișier sau doar ghicește?",
+ "title": "Codarea textului",
+ "pageTitle": "Fișiere de test pentru codarea textului - UTF-8, UTF-16, BOM, CRLF",
+ "description": "Același text în UTF-8, UTF-16LE și UTF-16BE, cu și fără marcă de ordine a octeților, și sfârșituri de linie CR LF și LF, pentru a testa cum decodează un cititor textul.",
+ "catches": [
+ "un cititor care presupune UTF-8 și arată un fișier UTF-16 cu un caracter din trei sau ca rânduri de pătrățele",
+ "o marcă de ordine a octeților citită ca și conținut, astfel încât primul câmp al unui import începe cu trei caractere străine",
+ "un importator care ghicește codarea din primii octeți și ghicește altfel pentru un fișier mai lung",
+ "un fișier CRLF împărțit în rânduri cu un rând gol după fiecare sau un retur de car rămas în ultimul câmp"
+ ],
+ "details": {
+ "sample": "Cât de mare este fiecare fișier din set. UTF-16 stochează doi octeți pentru fiecare caracter, așa că un număr impar este refuzat."
+ }
+ },
+ "upload-validation": {
+ "question": "Acceptă formularul meu de încărcare ce trebuie și respinge restul?",
+ "title": "Validarea încărcării",
+ "pageTitle": "Fișiere de test pentru validarea încărcării - tip și nume",
+ "description": "Fișiere pentru testarea unui formular de încărcare: tipuri permise și interzise, conținut ce nu se potrivește cu extensia, limită de dimensiune, nume ostile.",
+ "catches": [
+ "o limită aplicată în browser și nu pe server",
+ "un SVG sau un HTML luat drept imagine sau text simplu, o cale de a strecura un script printr-un formular",
+ "un fișier verificat după extensie și niciodată deschis, așa că un PDF numit .jpg trece",
+ "un formular care citește tot corpul în memorie înainte să vadă cât de mare e",
+ "o încărcare numită PHOTO.JPG respinsă acolo unde photo.jpg e acceptată, sau invers",
+ "un nume cu spații, paranteze sau caractere în afara ASCII scris pe disc neschimbat"
+ ],
+ "details": {
+ "limit": "Limita de dimensiune declarată de formularul tău de încărcare. Acest set face câte un pas de fiecare parte - pentru un fișier la orice distanță rulează presetarea size-boundaries.",
+ "allow": "Ce tipuri trebuie să accepte formularul tău. Fiecare devine un fișier real de acel tip și ele formează controlul pozitiv al întregului set.",
+ "deny": "Ce extensii trebuie să respingă formularul tău. O extensie pentru care această versiune nu are format primește totuși un fișier cu acel nume, conținând text simplu.",
+ "far-over": "Cât de mult peste limită ajunge singurul fișier mare. Oprește-l unde scrierea de mai multe ori limita nu merită discul.",
+ "bulk": "Câte fișiere conține încărcarea în masă. Zero scoate acel grup complet din set."
+ }
+ }
+ },
+ "commands": {
+ "generate": "produce fișiere, dintr-o rețetă sau din opțiuni",
+ "validate": "verifică o rețetă fără a scrie nimic",
+ "verify": "verifică un director față de un manifest",
+ "cleanup": "șterge fișierele pe care le listează un manifest",
+ "recipe fmt": "afișează o rețetă în forma ei normalizată",
+ "preset": "construiește un set de fișiere dintr-o întrebare de test cu nume",
+ "formats": "listează formatele acceptate de această versiune",
+ "damage": "listează modurile în care această versiune poate strica un fișier intenționat",
+ "tool": "mici unelte pentru fișiere pe care le ai deja",
+ "version": "afișează versiunea instrumentului",
+ "license": "afișează licența și ce înseamnă ea pentru fișierele generate"
+ },
+ "outcomes": {
+ "accept": "Sistemul tău trebuie să accepte fișierul.",
+ "reject": "Sistemul tău trebuie să respingă fișierul.",
+ "sanitize": "Sistemul tău trebuie să accepte fișierul și să îl curețe, de exemplu redenumindu-l.",
+ "unspecified": "Depinde de regulile sistemului tău. Tu decizi, apoi verifici că ce se întâmplă este ce ai vrut."
+ },
+ "damages": {
+ "zero-head": "Suprascrie cu zerouri primii octeți ai fișierului, fără să îi schimbe lungimea. Majoritatea cititorilor se uită întâi acolo, deci aproape orice observă această deteriorare."
+ },
+ "terms": {
+ "oracleNone": "nu se aplică",
+ "int": "orice număr întreg",
+ "choice": "unul dintr-un set fix",
+ "bool": "adevărat sau fals",
+ "size": "o dimensiune precum 2mb",
+ "text": "text",
+ "pixels": "pixeli",
+ "paragraphs": "paragrafe",
+ "rows": "rânduri",
+ "columns": "coloane",
+ "slides": "diapozitive",
+ "hertz": "herți",
+ "megapixels": "megapixeli",
+ "million cells": "milioane de celule",
+ "entries per second": "intrări pe secundă",
+ "files": "fișiere",
+ "sizes separated by commas": "dimensiuni separate prin virgule",
+ "format ids separated by commas": "id-uri de format separate prin virgule",
+ "format ids separated by commas, or all": "id-uri de format separate prin virgule, sau all",
+ "extensions separated by commas": "extensii separate prin virgule",
+ "the id of a format, as tfg formats lists them": "id-ul unui format, așa cum îl listează tfg formats",
+ "the password, in plain text": "parola, în text simplu",
+ "any text": "orice text",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "o dată precum 2024-02-29 sau 2024-02-29T13:45:00+02:00, sau none"
+ },
+ "faq": [
+ {
+ "q": "Prin ce diferă de dd, fsutil sau truncate?",
+ "a": "Acelea îți dau un fișier de dimensiunea potrivită, plin de nimic. Un fișier de 2 MB numit photo.png făcut așa nu este un PNG, deci tot ce îl analizează cu adevărat îl respinge din motivul greșit, iar testul tău trece apoi tot din motivul greșit. Acesta produce un PNG real de exact 2 MB care se deschide într-un vizualizator de imagini și vine cu o declarație despre cum trebuie să îl trateze sistemul tău.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "Este gratuit și îl pot folosi la serviciu?",
+ "a": "Da la amândouă. Este publicat sub GPL-3.0 și nu costă nimic. Nu există cont, cheie de licență sau nivel plătit."
+ },
+ {
+ "q": "Pot folosi fișierele generate într-un produs cu cod închis?",
+ "a": "Da. Licența acoperă codul instrumentului, nu ce produce el. Fișierele, rețetele și manifestele generate sunt rezultat și nu lucrări derivate, deci le poți comite și distribui fără nicio obligație."
+ },
+ {
+ "q": "Conțin fișierele generate date personale reale?",
+ "a": "Nu. Tot ce se află în ele este sintetizat dintr-un seed. Nu se citește niciun set de date, nu se contactează niciun serviciu și nu se încorporează conținut de la terți. Tratează o adresă de e-mail generată ca inutilizabilă, nu ca neutilizată, pentru că orice șir aleatoriu poate coincide din întâmplare cu una reală."
+ },
+ {
+ "q": "Voi obține exact aceleași fișiere pe altă mașină?",
+ "a": "Da, octet cu octet, cu aceeași rețetă și același seed. Proiectul testează asta la fiecare modificare, iar încălcarea ei cere o versiune majoră. Asta îți permite să comiți o rețetă mică în loc de fixture-uri binare mari."
+ },
+ {
+ "q": "Are nevoie de conexiune la internet?",
+ "a": "Niciodată. Nu există telemetrie, verificare de actualizări sau client cloud, iar binarul liniei de comandă nu are compilat în el niciun stack de rețea. Funcționează pe o mașină fără rețea și într-un mediu corporativ închis."
+ },
+ {
+ "q": "Ce se întâmplă dacă cer o dimensiune pe care un format nu o poate atinge?",
+ "a": "Primești o eroare care numește formatul, cea mai mică dimensiune posibilă, motivul acelui prag și ce să faci în loc, și nu se scrie niciun fișier. Instrumentul nu rotunjește niciodată o dimensiune pe tăcute. Fiecare prag este listat în pagina de formate.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "Pot genera un fișier stricat în mod deliberat?",
+ "a": "Da. Adaugă --damage zero-head și fișierul iese cu exact mărimea cerută, cu primii octeți suprascriși cu zerouri, așa că un cititor îl respinge, iar manifestul spune că sistemul tău trebuie să îl respingă. Detaliile sunt pe pagina despre fișierele de test corupte.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "Ce formate urmează?",
+ "a": "7z, mp3 și mp4. Azi funcționează de la un capăt la altul {{ .Facts.FormatCount }} formate."
+ },
+ {
+ "q": "Pe ce sisteme îl pot rula?",
+ "a": "Linia de comandă rulează pe Windows și Linux, atât pe Intel, cât și pe ARM, și pe Mac-uri cu Apple Silicon. Fereastra desktop este livrată pentru Windows pe Intel, Linux pe Intel și Mac-uri cu Apple Silicon. Mac-urile Intel nu sunt acceptate și nu se construiește nimic pentru ele."
+ },
+ {
+ "q": "Trebuie să instalez ceva?",
+ "a": "Nu. Descarcă arhiva pentru sistemul tău, dezarhiveaz-o și rulează binarul. Nu există instalator, mediu de execuție de adăugat sau dependență de rezolvat. Dacă ai Go, funcționează și o singură comandă go install.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "De ce o rulare peste mii de fișiere este mai lentă pe Windows?",
+ "a": "Pentru că Windows cere mai mult pentru fiecare cale pe care o examinează, iar o comandă care parcurge mii de fișiere examinează mii de căi. Măsurat pe o mașină cu 3000 de fișiere de 1 kB, verify durează aproximativ 0,9 secunde pe Windows și aproximativ 0,2 secunde pe Linux într-un container. O cale de ieșire mai scurtă micșorează cifra de pe Windows, pentru că fiecare folder de deasupra fișierelor face parte din ce se examinează."
+ }
+ ]
+}
diff --git a/web/content/ro/use-cases.html b/web/content/ro/use-cases.html
new file mode 100644
index 00000000..196dfb85
--- /dev/null
+++ b/web/content/ro/use-cases.html
@@ -0,0 +1,133 @@
+
Pentru ce îl folosesc oamenii
+
+ Cinci sarcini care apar în aproape orice proiect care primește fișiere de la oameni și comanda care
+ face fiecare. Fiecare exemplu de mai jos rulează așa cum e scris.
+
+
+
+
Limite de încărcare
+
Testarea dacă o limită de dimensiune a fișierelor este aplicată acolo unde spune că este
+
+ O limită înseamnă trei cazuri de test, nu unul: puțin sub, exact pe ea și puțin peste. Să le faci de
+ mână înseamnă să calculezi numere de octeți și să speri că n-ai greșit cu unu. Cere în schimb
+ setul:
+
+ Primești trei PDF-uri reale de 1048575, 1048576 și 1048577 de octeți și un manifest care spune că
+ primele două trebuie acceptate, iar al treilea respins pentru size_limit. Testul
+ tău citește așteptarea în loc să scrii tu trei asertări de mână - iar când limita se schimbă,
+ schimbi un număr și rulezi din nou.
+
+
+ La fel merge fără presetare când vrei un singur set de limite inline:
+
Ținerea fixture-urilor în afara repository-ului fără a le pierde
+
+ Fixture-urile binare mari fac un repository lent la clonare și incomod la revizuire, și nimeni nu
+ poate spune ce s-a schimbat când una e înlocuită. O rețetă este câteva sute de caractere de YAML
+ care reconstruiesc fișierele identice - octet cu octet, pe orice mașină -
+ pentru că fiecare fișier derivă din seed-ul rulării.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Fiecare final are propriul cod de ieșire, așa că un pipeline poate deosebi o rețetă proastă de un
+ disc plin și de o nepotrivire la verificare. O rulare eșuată nu tipărește nimic la ieșirea
+ standard, ceea ce împiedică un parser de jurnale să citească o eroare drept date.
+
+
+
+
+
Scară
+
Aflarea a ce se întâmplă când folderul e mare
+
+ Rutinele de import, joburile de noapte și listările de directoare se comportă altfel la zece mii de
+ fișiere decât la zece. Dimensiunile extrase dintr-un interval fac setul să semene cu trafic
+ real, nu cu zece mii de fișiere identice, iar extragerea vine din seed, deci setul e același
+ mâine.
+
+ O rulare mai mare decât spațiul liber de pe disc este refuzată înainte de a se scrie primul octet,
+ în loc să umple discul și să eșueze pe la jumătate.
+
+
+
+
+
Arhive
+
Testarea unui dezarhivator cu o arhivă care conține cu adevărat fișiere
+
+ O arhivă goală cu extensia potrivită nu dovedește nimic despre codul care o deschide și parcurge ce
+ e înăuntru. Declară conținutul și arhiva îl conține cu adevărat:
+
+ Adâncimea de imbricare, numărul de intrări și dimensiunea a ce e înăuntru sunt toate lucruri despre
+ care o rutină de import are păreri, iar așa afli care sunt acele păreri.
+
+
+
+
+
Parsere și vizualizatoare
+
Verificarea că propriul tău cod citește un format cum o face software-ul real
+
+ Fiecare format de aici este verificat cu un cititor independent înainte de livrare - un PNG este
+ deschis și pixelii lui comparați, un DOCX este recitit de biblioteci separate, o arhivă este
+ extrasă. Asta înseamnă că un fișier pe care parserul tău îl respinge este o constatare despre
+ parserul tău, nu despre generator.
+
+ Pagina de formate listează setările pe care le acceptă fiecare format și
+ cel mai mic fișier posibil pentru fiecare.
+
+
+
+
+
Ghiduri
+
Două dintre ele mai în detaliu
+
+
+ Fișiere de test corupte - un fișier stricat intenționat,
+ de mărime exactă, cu ce trebuie să se întâmple cu el scris în manifest.
+
+
+ Fișiere de test în CI - un workflow GitHub Actions, un job
+ GitLab și codurile de ieșire care fac un build să eșueze.
+
+
+
+
+
+
Pentru cine este
+
+ Ingineri QA, automatizarea testelor și oricine are în spatele codului un formular de încărcare, o
+ rutină de import, un parser sau o cotă de stocare. Rulează pe o mașină fără nicio rețea, ceea ce
+ contează într-un mediu corporativ închis unde un generator din browser nu e o opțiune.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/ru/ci.html b/web/content/ru/ci.html
new file mode 100644
index 00000000..1983c0bc
--- /dev/null
+++ b/web/content/ru/ci.html
@@ -0,0 +1,190 @@
+{{ with .Up }}
+ Двоичная фикстура в репозитории остаётся в его истории навсегда, её нельзя проверить в диффе, и она
+ перестаёт быть возможной, когда файл велик. Генерируйте файлы внутри конвейера из рецепта. Рецепт
+ - это текст, байты каждый раз выходят одинаковыми, а последний шаг доказывает, что ничего не
+ сдвинулось.
+
+
+
+
Короткий ответ
+
+ Установите tfg, запустите tfg generate fixtures.yaml --out ./fixtures
+ перед тестами и tfg verify ./fixtures/manifest.json после них. Оба шага сами роняют
+ сборку, с кодом завершения, который говорит почему.
+
+
+
+
+
Почему не коммитить
+
Почему фикстуре не место в репозитории
+
+
+ Она остаётся в истории. Удаление двоичного файла позже не делает клон меньше,
+ потому что каждая его версия всё ещё там.
+
+
+ Дифф не показывает, что изменилось. Рецензент видит, что PDF другой, и ничего
+ больше. Рецепт меняется на одну строку.
+
+
+ Большие файлы не помещаются. GitHub отклоняет push, в котором есть файл больше 100
+ МБ, поэтому тесту лимита загрузки в 500 МБ нечего коммитить.
+
+
+
+ Коммитить нужно рецепт. Один и тот же рецепт с тем же зерном записывает одни и те же байты на любой
+ машине, поэтому файл, созданный в конвейере, - это файл, который был у вас на ноутбуке.
+
+
+
+
+
Рецепт
+
Рецепт, который лежит рядом с тестами
+
+ Этот записывает двадцать пять счетов, которые должны быть приняты, и два изображения сверх лимита,
+ которые должны быть отклонены, а манифест фиксирует оба ожидания:
+
+ Строка с контрольной суммой сверяет архив с verify-SHA256SUMS.txt из того же выпуска.
+ Версия зафиксирована, так что новый выпуск никогда не изменит сборку, которой вы не касались.
+
+ У каждого завершения свой код, так что шаг падает сам, а журнал говорит, какой именно. Те, что
+ встречает конвейер:
+
+
+
3 - рецепт недопустим. Ничего не записано, и названа каждая проблема
+
4 - формат не умеет того, что попросили, например размера меньше своего минимума
+
6 - не хватает места на диске
+
7 - tfg verify нашёл файл, не совпадающий со своим манифестом
+
8 - запуск закончился, но создано не всё
+
+
+ Неудачный запуск ничего не печатает в стандартный вывод, поэтому разборщик журналов никогда не
+ примет ошибку за данные. Вся таблица на странице документации.
+
+
+
+
+
PowerShell
+
Скрипту PowerShell нужна ещё одна строка
+
+ PowerShell не выносит код завершения программы из файла .ps1. Запустите такой файл с
+ -File, и скрипт ответит 0, даже когда инструмент внутри отказался
+ работать, так что сборка, которая должна быть красной, становится зелёной. Последняя строка -
+ это всё исправление:
+
+ Так ведёт себя PowerShell, а не этот инструмент. cmd, bash и
+ zsh ничего лишнего не требуют.
+
+
+
+
+
Несколько заданий
+
Как делиться фикстурами между заданиями
+
+ Обычно загружать их не нужно. Поскольку один и тот же рецепт записывает одни и те же байты, каждое
+ задание может запустить собственный tfg generate, что быстрее загрузки и
+ скачивания. Когда задание должно получить файлы от другого, запустите после передачи tfg
+ verify на манифесте, и он скажет, совпадает ли полученное с записанным.
+
+ Валидатор, которому показывали только здоровые файлы, на самом деле не проверен. Вот как получить
+ файл, намеренно испорченный, выходящий точно того размера, который вы просите, и
+ несущий манифест с указанием, что ваша система должна с ним сделать.
+
+
+
+
Короткий ответ
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out записывает PNG
+ ровно в 2097152 байта, первые байты которого нули, а манифест рядом фиксирует, что ваша система
+ должна его отклонить.
+
+
+
+
+
Обычный путь
+
Почему файл, испорченный вручную, - плохой тест
+
+ Обычно берут шестнадцатеричный редактор, скрипт, переворачивающий несколько случайных байтов, или
+ укорачивают файл через head либо truncate. Один раз это работает, а
+ потом обходится дорого:
+
+
+
+ Каждый раз по-разному. Случайный байт при каждом запуске попадает в новое место,
+ поэтому сбой во вторник в среду может не повториться.
+
+
+ Меняется размер. Обрезанный файл меньше лимита, под которым он должен был
+ оставаться, поэтому проверка размера отвечает раньше проверки содержимого, и тест проходит по
+ неверной причине.
+
+
+ Это часто остаётся незамеченным. Простой текст читается и с изменённым байтом
+ посередине, а снисходительная программа чтения изображений просто рисует его, так что файл,
+ который должен быть испорчен, принимается.
+
+
+ Не сказано, что должно произойти. Файл - это просто байты, и тому, кто будет читать
+ тест позже, придётся гадать, имелось в виду принятие или отклонение.
+
+
+
+
+
+
Что вы получаете
+
Повреждённый файл остаётся нужного размера
+
+ Файл создаётся как обычно и портится потом, по пути на диск. Он сохраняет заданный размер, а та же
+ команда снова записывает те же байты.
+
+ Настройки пишутся после двоеточия. Параметр можно повторять, а повреждения применяются в том
+ порядке, в каком вы их записали. Это работает с каждым из {{ .Facts.FormatCount }} форматов.
+
+
+
+
+
Что он умеет
+
Какие бывают повреждения?
+
+ Это список, который печатает программа, прочитанный из неё при сборке этой страницы. tfg
+ damage печатает тот же список, а tfg damage <id> говорит, что
+ принимает одно из них.
+
+ {{ template "damagesTable" . }}
+
+ zero-head записывает нули поверх начала файла. Большинство программ чтения смотрят
+ сначала туда, на сигнатуру и заголовок, которые говорят, что это за файл, поэтому замечает почти
+ любая. У простого текста и журналов сигнатуры нет, и их тоже отклоняют, потому что
+ последовательность нулевых байтов не является текстом. Меньше четырёх байтов у некоторых
+ форматов получается повреждение, на которое не жалуется ни одна программа чтения, поэтому
+ настройка начинается с четырёх.
+
+
+
+
+
Что говорит манифест
+
Манифест, который говорит, что должно произойти
+
+ Каждый повреждённый файл получает запись о том, что ваша система должна его отклонить, а рядом
+ записано повреждение:
+
+ Два запроса отклоняются до того, как что-либо записано, потому что каждый оставил бы на диске файл,
+ который манифест описывает неверно:
+
+
+
файл меньше, чем нужно повреждению, который вышел бы нетронутым
+
+ expected: accept рядом с повреждением, потому что ничто не могло бы этого выполнить.
+ Напишите sanitize, если ваша система должна починить файл, или
+ unspecified, если именно это вы и проверяете
+
+
+
+
+
+
В рецепте
+
Здоровые и сломанные файлы за один запуск
+
+ Положите оба вида в один рецепт, и манифест несёт ожидание для каждого файла, так что тесту не нужен
+ список, какой файл какой:
+
+ Тест читает манифест и проверяет, что произошедшее совпадает с заявленным. Список имён файлов ему не
+ нужен:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Хороший отказ - это чистый отказ. Сообщение, говорящее, что было не так, - тот ответ, который вам
+ нужен. Ошибка сервера, зависание или наполовину сохранённый файл - тот дефект, ради которого
+ этот тест и существует.
+
+ Документация содержит каждый параметр tfg generate.
+
+
+
diff --git a/web/content/ru/docs.html b/web/content/ru/docs.html
new file mode 100644
index 00000000..371ed003
--- /dev/null
+++ b/web/content/ru/docs.html
@@ -0,0 +1,281 @@
+
Документация
+
+ Всё, что делает инструмент, разложено по вопросам, с которыми люди действительно приходят.
+ README в репозитории - полный справочник, и он всегда
+ соответствует скачанной вами сборке.
+
+
+
+
Какие есть команды?
+
Каждая делает одно дело:
+ {{ template "commandList" . }}
+
+
+
+
Как создать один файл точного размера?
+
+ Укажите формат, размер и место назначения. Размеры считаются по 1024, поэтому 2mb - это
+ 2097152 байта. Подойдёт и простое число байт, так что --size 10485761 запрашивает
+ ровно столько.
+
+
tfg generate --format png --size 2mb --out ./out
+
Полезные флаги команды generate:
+
+
+
Флаг
Что делает
+
+
--format <id>
формат файлов, например txt
+
--size <size>
точный размер каждого файла, например 10mb или простое число байт
+
--size-range <a-b>
размер, выбираемый для каждого файла из диапазона, например 1kb-8kb. Выбор идёт от seed
+
--boundary <size>
три файла вокруг лимита: на байт меньше, сам лимит, на байт больше
+
--count <n>
сколько файлов создать. По умолчанию 1
+
--name <template>
шаблон имени, например invoice_{index:04}.txt
+
--out <dir>
каталог, в который записывать
+
--seed <n>
seed запуска. Один и тот же seed даёт те же байты
+
--set <k>=<v>
настройка формата, можно повторять
+
--damage <name>
намеренно испортить файлы, можно повторять, применяется по порядку. Список выводит tfg damage
+
--expected <outcome>
accept, reject, sanitize или unspecified
+
--dry-run
посчитать и показать, ничего не записывая
+
--json
записать манифест в стандартный вывод
+
+
+
+
+
+
+
Как сделать намеренно сломанный файл?
+
+ Любой другой файл, который записывает этот инструмент, корректен по построению, и это отвечает на
+ два из трёх вопросов, которые задаёт проверка загрузки. --damage отвечает на третий
+ - открывается ли файл вообще. Файл создаётся как обычно, а затем портится, поэтому у него
+ остаётся запрошенный размер.
+
+ Настройки указываются после двоеточия. Флаг можно повторять, и порядок записи - это порядок
+ применения. tfg damage перечисляет, что умеет эта сборка и что принимает каждый вид
+ повреждения.
+
+ Повреждённый файл получает в манифесте expected: reject с записанным рядом
+ повреждением. Две вещи отклоняются до записи чего-либо, потому что каждая оставила бы на диске
+ файл, неверно описанный манифестом:
+
+
+
файл меньше, чем нужно повреждению, потому что он вышел бы без изменений
+
+ expected: accept рядом с повреждением, потому что этому не мог бы соответствовать ни
+ один файл. Пишите sanitize, если тестируемая система должна починить файл, или
+ unspecified, если именно этот вопрос вы и задаёте
+
+
+
+ Третье заранее узнать нельзя. Если повреждение выполняется и не меняет ни одного байта, такой файл
+ отбрасывается, а не записывается - запуск продолжается, сообщает, что это был за файл, и
+ завершается кодом частичного завершения.
+
+ Рецепт - это файл YAML, описывающий целый запуск. Закоммитьте его рядом с тестами, и фикстуры
+ перестанут быть бинарными файлами в вашем репозитории - любой сможет пересоздать их байт в байт
+ из файла в несколько сотен символов.
+
+ Каждой цели нужен ровно один из ключей size, size-range,
+ boundary или contains. Два - это ошибка, и ни одного - тоже.
+ Недопустимый рецепт записывает ни одного файла и сообщает обо всех проблемах
+ сразу, а не только о первой, называя каждый раз настройку, к которой она относится.
+
+
+
+
+
Как объявить, что моя система должна делать с файлом?
+
Краткая форма, когда достаточно исхода, и длинная, когда важна причина:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Исходы - accept, reject, sanitize и unspecified.
+ Причины образуют закрытый список, чтобы отчёт мог по ним группировать:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit и size_zero.
+
+
+ Причина называет действующее правило, а не вердикт. Поэтому одна и та же причина
+ может стоять под любым исходом - файл на байт меньше лимита получает accept, а
+ правило, о котором речь, всё равно size_limit.
+
+
+
+
+
Что в манифесте?
+
+ Он записывается рядом с файлами в конце каждого запуска, в том числе прерванного. Одна запись на
+ файл:
+
+ recipe_hash добавляется, если запуск был по рецепту, а preset с
+ overrides - если по пресету, так что манифест всегда можно отследить до того, что
+ его создало.
+
+
+ Каждая запись также содержит target_id - id цели рецепта, которая создала файл, а
+ summary.by_target считает файлы каждой цели. Рецепт с несколькими целями можно
+ поэтому проверить цель за целью, не читая имена файлов.
+
+
+
+
+
Что такое пресет?
+
+ Готовый набор файлов, отвечающий на распространённый тестовый вопрос, чтобы вам не приходилось
+ проектировать набор самостоятельно. Пресеты - обычные рецепты внутри, а eject
+ выводит рецепт, чтобы вы могли отредактировать его. У каждого пресета есть
+ отдельная страница о том, что он обычно находит, что входит в набор и
+ какие настройки принимает.
+
+ show сообщает, чего стоил бы набор, прежде чем вы его соберёте, и прямо говорит, когда
+ число - наша временная подстановка, а не ваш лимит.
+
+
+
+
+
Что означают коды завершения?
+
+ У каждого исхода свой код, машиночитаемый вывод идёт в стандартный вывод, а неудачный запуск ничего
+ туда не печатает. Таблица - замороженный контракт: смена значения кода требует повышения
+ мажорной версии.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Запуск, остановленный с помощью Ctrl+C, всё равно оставляет манифест и никогда не оставляет
+ наполовину записанный файл, поэтому отменённое задание может быть убрано следующим.
+
+ Да, тот же движок с окном сверху, для тестирования, которое не автоматизируется. Это не урезанная
+ версия: тест сравнивает два интерфейса возможность за возможностью, и всё, что умеет только один
+ из них, должно быть объявлено и обосновано, а не тихо расходиться.
+
+
+ Экраны: одна партия, пресеты, несколько партий одновременно и о программе. Окно показывает, чего
+ стоил бы запуск, прежде чем что-либо записать, отображает ход работы и может быть отменено на
+ полпути без наполовину записанного файла. Файл рецепта оно пока не открывает - рецепты пока дело
+ командной строки, а окно собирает свои партии в форме.
+
+
diff --git a/web/content/ru/exact-size.html b/web/content/ru/exact-size.html
new file mode 100644
index 00000000..2ac130c5
--- /dev/null
+++ b/web/content/ru/exact-size.html
@@ -0,0 +1,145 @@
+
Как создать файл точного размера
+
+ В каждой системе для этого есть команда, и все три приведены ниже. Они дают файл с точным числом
+ байт, а для многих тестов этого достаточно. Каждая команда на этой странице была выполнена
+ до публикации в той системе, к которой она относится.
+
+
+
+
Короткий ответ
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Размеры указываются в байтах, а 10
+ МБ, посчитанные так, как считает ваш файловый менеджер, - это 10485760.
+
+
+
+
+
Windows
+
fsutil и вариант на PowerShell, которому ничего дополнительного не нужно
+
+ fsutil входит в Windows. Он принимает размер в байтах, поэтому сначала
+ посчитайте число: 10 МБ - это 10485760, 100 МБ - 104857600, 1 ГБ - 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Измерено в Windows 11: работает из обычной командной строки без повышенных прав, и файл получается
+ ровно в 10485760 байт.
+
+
PowerShell может сделать то же самое, не вызывая другую программу, и понимает единицы:
+ 10MB в PowerShell означает 10485760 байт, тот же счёт по основанию 1024, что использует
+ Проводник, поэтому две команды выше дают один и тот же размер.
+
+
+
+
+
Linux
+
dd, truncate и fallocate, и разница, которая ловит людей
+
dd знают все. Он действительно записывает байты:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate срабатывает мгновенно, и в этом подвох. Измерено в Alpine Linux: файл сообщает
+ 10485760 байт и занимает ноль блоков - это разреженный файл.
+ Всё, что его читает, получает десять мегабайт нулей, но диск место так и не отдал:
+
+
truncate -s 10M test10mb.bin
+
+ Для проверки лимита загрузки это нормально, а для проверки дисковой квоты вводит в заблуждение.
+ fallocate - то, к чему стоит обратиться, когда место должно быть настоящим:
+
+
fallocate -l 10M test10mb.bin
+
А когда содержимое должно быть несжимаемым, чтобы архиватор не мог снова его ужать:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, который не разреженный, и две команды, которые вы уже знаете
+
+ В macOS есть mkfile. Измерено в macOS 26.6.2: 10485760 байт и 20480 блоков, то есть
+ место действительно выделено, а не обещано:
+
Файл правильного размера - не файл правильного вида
+
+ Всё сказанное выше даёт блок нулей. Этого достаточно, когда тестируемое смотрит только на размер:
+ лимит загрузки, квота, передача. Этого перестаёт хватать, как только что-либо
+ открывает файл.
+
+
+ Измерено, и стоит проверить самому: сделайте файл на 2 МБ командой fsutil, назовите его
+ photo.png и передайте библиотеке работы с изображениями. Pillow ответит
+ cannot identify image file. Это не PNG. Он им никогда и не был, так говорило лишь
+ имя.
+
+
+ Это важнее, чем кажется, из-за того, в какую сторону тест тогда проваливается. Ваша
+ точка загрузки отклоняет файл, ваш тест зеленеет, и вы заключаете, что лимит размера работает.
+ Она отклонила его не из-за размера. Она отклонила его потому, что байты не были изображением, и
+ правило, которое вы хотели проверить, так и не было достигнуто.
+
+
+
парсер отклоняет его, не дойдя до каких-либо правил размера
+
шаг создания миниатюры падает, и ошибка, которую вы читаете, относится к миниатюре
+
антивирус или проверка содержимого отклоняет его по третьей причине
+
просмотрщик ничего не показывает, и никто не может сказать, в этом ли ошибка
+
+
+
+
+
Другой путь
+
Настоящий файл этого формата точно того размера, который вы запросили
+
+ Именно это делает Testing Files Generator. Файл - настоящий файл своего формата, он открывается в
+ своей программе, и в нём ровно то число байт, которое вы запросили, с точностью до байта:
+
+ Запросите размер, которого формат не может достичь, и вы получите ошибку с названием минимума и
+ причиной, а не файл неверного размера. Страница форматов перечисляет
+ каждый формат с наименьшим файлом, который он может создать.
+
+
А лимит - это три тестовых случая, а не один, поэтому инструмент собирает все три:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Вы получите 10485759, 10485760 и 10485761 байт и манифест, который говорит, какие из них ваша
+ система должна принять, а какие отклонить. Страница сценариев
+ разбирает это и ещё четыре задачи, для которых инструмент создан.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Так что же использовать?
+
+
+
Используйте системную команду
+
+ Когда ничто не открывает файл. Проверка лимита размера на точке, которая сначала смотрит размер,
+ передача, квота, переполнение диска. Это одна строка, и она уже установлена.
+
+
+
+
Используйте настоящий генератор
+
+ Когда что-либо разбирает, отображает, импортирует или распаковывает файл - и когда завтра на другой
+ машине нужны те же фикстуры, байт в байт.
+
+
+
+
+ Обе есть на этой странице, потому что обе бывают правы. Ошибка, которой стоит избегать, -
+ использовать первую там, где нужна вторая, и принимать зелёный тест за доказательство.
+
+
diff --git a/web/content/ru/faq.html b/web/content/ru/faq.html
new file mode 100644
index 00000000..ae0de5c2
--- /dev/null
+++ b/web/content/ru/faq.html
@@ -0,0 +1,20 @@
+
Часто задаваемые вопросы
+
+ Лицензия, приватность, воспроизводимость и то, что люди проверяют, прежде чем включать генератор в
+ конвейер сборки. Если вашего вопроса здесь нет, трекер задач
+ открыт.
+
{{ .Facts.FormatCount }} форматов файлов, каждый создаётся точного размера
+
+ Каждый из них - настоящий файл этого формата. Он открывается в своей программе и
+ имеет ровно то число байт, которое вы запросили. Ни один не является нулями-заполнителями с
+ приклеенным расширением.
+
+
+{{ template "formatsTable" . }}
+
+
+
Что означают столбцы
+
+
+
Наименьший файл
+
+ Наименьшее число байт, которое этот инструмент принимает для формата, включая метку, которую он
+ пишет внутри файла. Запросите меньше, и вы получите ошибку с названием минимума и причиной,
+ а не файл неверного размера.
+
+
+
+
Полнота
+
+ Насколько полон файл. full означает, что его принимает читатель, который по-настоящему
+ разбирает формат, а не просто совпадает расширение.
+
+
+
+
Проверяется с помощью
+
+ Независимый читатель, который открывает каждый созданный файл до выпуска формата, - отдельная
+ реализация, а не наш собственный код, проверяющий собственные домашние задания.
+
+
+
+
+ Каждый формат к тому же повторяется до байта: тот же рецепт и тот же seed дают одинаковые файлы на
+ любой машине, и именно это делает безопасным коммит рецепта вместо самих фикстур.
+
+
+
+
+
Настройки, которые принимает каждый формат
+
+ У большинства форматов есть свои настройки - размеры изображения, качество JPEG, число страниц PDF,
+ строки и столбцы в таблице, сколько записей входит в архив. Задайте их через --set
+ key=value в командной строке или в разделе properties: рецепта.
+
+ Значение вне допустимого для настройки отклоняется сообщением с названием настройки, допустимым
+ диапазоном и тем, что использовать вместо этого. Неизвестная настройка тоже ошибка, а не
+ молчаливое значение по умолчанию - опечатка, принятая молча, даёт файл с неверными настройками и
+ час раздумий, почему тест проходит, хотя не должен.
+
+
+ Выполните tfg formats <id>, чтобы увидеть, что именно принимает один формат в
+ вашей сборке.
+
+
+
+
+
Архивы содержат настоящие файлы
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} и {{ end }}{{ $c.ID }}{{ end }}
+ можно наполнить записями, а не оставлять пустой оболочкой. Созданный архив действительно
+ содержит документы, которые заявляет, поэтому всё, что распаковывает его во время теста, находит
+ внутри настоящие файлы.
+
+ PDF, PNG, DOCX, ZIP - всего {{ .Facts.FormatCount }} форматов, и каждый из них
+ настоящий файл, который открывается в своей программе, точно того размера, который вы
+ запросили. Каждый запуск ещё и записывает, что ваше приложение должно делать с каждым
+ файлом. Командная строка и десктопное окно, бесплатно и с открытым кодом, всё работает на вашей
+ машине.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ Десктопное окно, подготовленное к записи партии файлов. За командной строкой работает тот же движок.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
настоящих форматов, каждый открывается в своей программе
+
+
+ 1 байт
+
точность каждого запрошенного размера, никогда не округляется молча
+
+
+ 0
+
соединений куда бы то ни было - без учётной записи, без телеметрии, без проверки обновлений
+
+
+
+
+
Проблема
+
Сделать один тестовый файл легко. Сделать нужную тысячу - вот утомительная часть
+
Вы тестируете программу, принимающую файлы от людей. Рано или поздно вам понадобятся:
+
+
PDF ровно на 10 МБ, чтобы выяснить, реален ли лимит загрузки
+
три файла по обе стороны этого лимита, чтобы поймать ошибки на единицу
+
10 000 файлов журнала, чтобы увидеть, что делает ночное задание, когда папка велика
+
ZIP, который действительно содержит 200 документов, а не пустышку с правильным расширением
+
файл на 4 ГБ без хранения файла на 4 ГБ в вашем репозитории
+
одинаковые фикстуры на ноутбуке и на сервере сборки, байт в байт
+
+
+ Именно это он заменяет. Он создан для QA-инженеров, автоматизации тестирования и всех, за чьим кодом
+ стоит форма загрузки, процедура импорта, парсер или квота хранилища.
+
+
+
+
+
Чем он отличается
+
Другие генераторы останавливаются на байтах. Этот отвечает на то, о чём на самом деле спрашивает ваш тест
+
+ Папка с файлами всё равно оставляет вам решать, что должен доказывать каждый из них. Каждый запуск
+ здесь записывает рядом с файлами manifest.json - простой список всего созданного и
+ для каждой записи заявленное ожидание.
+
+
Допустим, ваша точка загрузки допускает 1 МБ. Запросите три файла, лежащие на этой границе:
Там, где ответ зависит от вашей собственной политики, манифест так и говорит
+
+ Он записывает unspecified, а не придумывает ожидание. Генератор, который гадает, даёт
+ ложные сбои, а набор тестов, который кричит «волки», в итоге отключают.
+
+
+
+
+
+
Пресеты
+
Выберите вопрос, получите весь набор
+
+ Пресет - это набор тестовых файлов, продуманный вокруг одного тестового вопроса, чтобы вам не
+ пришлось выяснять, какие файлы что доказывают. У каждого есть страница о том, что он обычно
+ находит, что входит в набор и какие настройки принимает.
+
+ Десять тысяч файлов журнала, каждый от одного до восьми килобайт, с размерами из seed, чтобы завтра
+ получился тот же набор. Давайте каждому запуску свой каталог - манифест
+ остаётся единственной записью о том, что записал запуск, поэтому инструмент отказывается
+ записывать второй поверх него:
+
+ Размеры считаются по 1024, как в вашем файловом менеджере, поэтому 2mb означает 2097152
+ байта. Подойдёт и простое число байт. Документация охватывает рецепты,
+ манифест и коды завершения.
+
+
+
+
+
Что вы получаете
+
Создан для набора тестов, работающего без присмотра
+
+
+
Точный размер, до байта
+
Запросите 10485761 байт и получите ровно столько. Размер, которого формат не может достичь, - это ошибка с причиной, а не файл неверного размера.
+
+
+
{{ .Facts.FormatCount }} настоящих форматов
+
Не нули-заполнители с расширением. Созданный PNG открывается в просмотрщике изображений, DOCX - в Word, ZIP распаковывается. Каждый формат проверяется независимыми читателями до выпуска.
+
+
+
Манифест, который служит тестовым оракулом
+
Путь, размер, SHA-256, формат, seed, версия инструмента - и то, что ваша система должна сделать с файлом.
+
+
+
Воспроизводимость
+
Тот же рецепт и тот же seed, те же байты на любой машине. Коммитьте небольшой рецепт YAML вместо больших бинарных фикстур.
+
+
+
Два интерфейса, один движок
+
Командная строка, созданная для CI, и десктопное окно для исследовательского тестирования. Ни один не урезанная версия другого, и тест сравнивает их возможность за возможностью.
+
+
+
Полностью офлайн
+
Нет учётной записи, облака, телеметрии и проверки обновлений. В бинарный файл командной строки вообще не скомпилирован сетевой стек.
+
+
+
+
+
+
Скачать
+
Выберите сборку для вашей системы
+
+ Распакуйте архив и запустите. tfg - это командная строка, а tfg-gui -
+ десктопное окно. Нет установщика и ничего, что нужно добавлять на вашу машину.
+
+ {{ template "downloadsTable" . }}
+
+
Что подписано, а что нет
+
+ Сборки для Windows и macOS подписаны, поэтому запускаются без предупреждения о неизвестном
+ разработчике. Сборки для Linux не подписаны, потому что у десктопного Linux нет эквивалента,
+ которым их можно подписать. Каждый архив указан в verify-SHA256SUMS.txt на
+ странице релиза, так что вы можете проверить, что скачали.
+
+ Пресет {{ .ID }} одной командой собирает целый набор настоящих тестовых файлов для
+ этого вопроса и рядом manifest.json с ожидаемой реакцией вашей системы на каждый
+ файл. Всё ниже прочитано из программы со значениями по умолчанию этой версии.
+
+
+{{ if .Catches }}
+
+
Что он обычно находит?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
Что входит в набор?
+
Со значениями по умолчанию, как сообщает tfg preset show {{ .ID }}:
+
+
+
+
Файлов
{{ .Budget.Files }}
+
Целей в его рецепте
{{ .Budget.Targets }}
+
Общий размер
{{ .Bytes }} B
+
Форматы
{{ join .Budget.Formats ", " }}
+
+
+
+
И чего манифест этого набора ожидает от вашей системы:
+
+
+
+
Ожидается
Значение
Файлов
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
Что можно изменить?
+ {{- if .Settings }}
+
+
+
+
Настройка
Принимает
По умолчанию
Что делает
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Это значение по умолчанию - наша временная подстановка, а не значение вашей системы. Передайте своё.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
У этого пресета нет настроек. Набор каждый раз одинаков.
+ {{- end }}
+
+
+
+
Как его запустить?
+
Посмотрите, чего стоил бы набор, соберите его или возьмите его рецепт для правки:
Или стройте на нём в собственном рецепте рядом с тестами:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/ru/presets.html b/web/content/ru/presets.html
new file mode 100644
index 00000000..b5c1bae0
--- /dev/null
+++ b/web/content/ru/presets.html
@@ -0,0 +1,32 @@
+
Пресеты тестовых файлов, по набору на каждый тестовый вопрос
+
+ Пресет - это целый набор тестовых файлов, продуманный вокруг одного вопроса, с манифестом об
+ ожидаемой реакции вашей системы на каждый файл. Вы выбираете вопрос, инструмент собирает набор. У
+ каждого пресета своя страница о том, что он обычно находит, что входит в набор и какие настройки
+ принимает.
+
+
+{{ template "presetsList" . }}
+
+
+
Чем пресет отличается от рецепта?
+
+ По сути ничем. Пресет - это рецепт, который инструмент пишет для вас из нескольких настроек.
+ tfg preset eject выводит этот рецепт, чтобы вы могли хранить его рядом с тестами и
+ править, а ваш собственный рецепт может опираться на пресет одной строкой: extends:
+ preset: и его id.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Можно ли доверять значениям по умолчанию?
+
+ Для файлов - да. Для числа, которое знает только ваша система, например лимита формы загрузки,
+ значение по умолчанию - наша временная подстановка, и инструмент говорит об этом каждый раз,
+ когда её использует. Страница каждого пресета отмечает такие настройки, а tfg preset
+ show сообщает об этом до записи чего-либо.
+
+
diff --git a/web/content/ru/site.json b/web/content/ru/site.json
new file mode 100644
index 00000000..e898c8fe
--- /dev/null
+++ b/web/content/ru/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "ru",
+ "locale": "ru_RU",
+ "name": "Русский",
+ "dir": "ru",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Главная",
+ "title": "Генератор тестовых файлов для QA - точный размер, {{ .Facts.FormatCount }} форматов",
+ "description": "Бесплатный генератор тестовых файлов для QA с открытым кодом. Настоящие PDF, DOCX, PNG и ZIP точного размера и манифест с ожидаемой реакцией вашей системы."
+ },
+ {
+ "key": "formats",
+ "slug": "formats",
+ "nav": "Форматы",
+ "title": "{{ .Facts.FormatCount }} форматов файлов - PDF, DOCX, PNG, ZIP и другие",
+ "description": "Все форматы, которые создаёт генератор, самый маленький возможный файл каждого и допустимые настройки. Все {{ .Facts.FormatCount }} открываются в своих программах."
+ },
+ {
+ "key": "presets",
+ "slug": "presets",
+ "nav": "Пресеты",
+ "title": "Пресеты тестовых файлов - готовые наборы для QA",
+ "description": "Готовые наборы тестовых файлов, каждый отвечает на один вопрос: лимиты загрузки, имена файлов, кодировки, импорт таблиц, пустые файлы и проверка загрузки."
+ },
+ {
+ "key": "docs",
+ "slug": "docs",
+ "nav": "Документация",
+ "title": "Документация - команды, рецепты, манифест, коды завершения",
+ "description": "Как создавать тестовые файлы из командной строки или рецепта YAML, что содержит манифест и что означает каждый код завершения при запуске в CI."
+ },
+ {
+ "key": "use-cases",
+ "slug": "use-cases",
+ "nav": "Сценарии",
+ "title": "Сценарии - лимиты загрузки, фикстуры для CI, массовые тесты",
+ "description": "Проверка лимита размера загрузки, воспроизводимые фикстуры для CI, десять тысяч файлов за один запуск и архивы с настоящим содержимым."
+ },
+ {
+ "key": "exact-size",
+ "slug": "create-file-exact-size",
+ "nav": "Точный размер",
+ "title": "Как создать файл точного размера - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate и mkfile, каждая команда измерена в своей системе, и почему такой файл не является PDF или PNG, когда тесту нужен настоящий."
+ },
+ {
+ "key": "faq",
+ "slug": "faq",
+ "nav": "FAQ",
+ "title": "FAQ - вопросы о создании тестовых файлов",
+ "description": "Чем это отличается от dd и fsutil, можно ли коммитить файлы, повторяются ли запуски байт в байт и что будет, если размер недостижим."
+ },
+ {
+ "key": "damage",
+ "slug": "corrupt-test-files",
+ "nav": "Повреждённые файлы",
+ "title": "Повреждённые тестовые файлы - сломанные файлы точного размера",
+ "description": "Намеренно испорченный файл точного размера с манифестом, который говорит, что ваша система должна его отклонить. Для проверки валидации загрузки и парсеров.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "test-files-in-ci",
+ "nav": "Тестовые файлы в CI",
+ "title": "Тестовые файлы в CI - GitHub Actions, GitLab CI и PowerShell",
+ "description": "Генерируйте тестовые файлы в конвейере, а не коммитьте бинарники: workflow GitHub Actions, задание GitLab, коды завершения и ловушка PowerShell.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "Перейти к содержимому",
+ "navLabel": "Основное",
+ "langLabel": "Язык",
+ "breadcrumbHome": "Главная",
+ "imageAlt": "Testing Files Generator - настоящие тестовые файлы точного размера и манифест с ожидаемой реакцией вашей системы на каждый из них",
+ "schemaDescription": "Бесплатный генератор тестовых файлов для QA с открытым кодом. Создаёт настоящие файлы в {{ .Facts.FormatCount }} форматах точного размера и записывает манифест с ожидаемой реакцией тестируемой системы на каждый из них.",
+ "ctaDownload": "Скачать",
+ "ctaSource": "Исходный код",
+ "ctaNote": "Бесплатно, открытый код, GPL-3.0. Без регистрации. Сборки для Windows и macOS подписаны и запускаются без предупреждений.",
+ "colFormat": "Формат",
+ "colName": "Название",
+ "colExtension": "Расширение",
+ "colSmallest": "Наименьший файл",
+ "colFidelity": "Полнота",
+ "colChecked": "Проверяется с помощью",
+ "colSetting": "Настройка",
+ "colAccepts": "Допускает",
+ "colSystem": "Система",
+ "colCli": "Командная строка",
+ "colWindow": "Десктопное окно",
+ "noBinary": "пока без сборки",
+ "colCode": "Код",
+ "colMeaning": "Значение",
+ "footerBlurb": "Тестовые файлы для QA точного размера и манифест с ожидаемой реакцией вашей системы на каждый из них.",
+ "footerProject": "Проект",
+ "footerSource": "Исходный код на GitHub",
+ "footerReleases": "Загрузки",
+ "footerIssues": "Сообщить о проблеме",
+ "footerSupport": "Поддержать проект",
+ "footerPages": "Страницы",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. Распространяется по лицензии GNU General Public License версии 3. Файлы, которые вы создаёте, принадлежат вам - лицензия охватывает инструмент, а не его результат.",
+ "footerPrivacy": "Этот сайт не загружает шрифты, скрипты и трекеры ниоткуда. Он не устанавливает куки.",
+ "notFoundTitle": "Такой страницы нет",
+ "notFoundLead": "Адрес, по которому вы перешли, не соответствует ни одной странице этого сайта.",
+ "notFoundBack": "На главную",
+ "read.format": "Формат каждого файла набора. Это флаг самого инструмента, а пресет лишь задаёт ему значение по умолчанию.",
+ "readTakes.format": "id формата со страницы форматов",
+ "colDamage": "Повреждение",
+ "colEffect": "Что оно делает с байтами",
+ "colSettings": "Настройки",
+ "noSettings": "нет"
+ },
+ "endings": {
+ "0": "Всё сработало.",
+ "1": "Непредвиденная ошибка внутри инструмента.",
+ "2": "Неверная команда или флаг.",
+ "3": "Рецепт недопустим.",
+ "4": "Формат не может сделать то, что запрошено.",
+ "5": "Не удалось прочитать или записать.",
+ "6": "Недостаточно места на диске.",
+ "7": "verify обнаружил расхождение.",
+ "8": "Запуск завершён, но создано не всё.",
+ "130": "Прерван с помощью Ctrl+C.",
+ "143": "Остановлен сигналом, так выглядит тайм-аут в CI."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "Пройдёт ли корректный файл, настолько маленький, насколько позволяет формат?",
+ "title": "Пустые и минимальные",
+ "pageTitle": "Минимальные корректные и пустые тестовые файлы в каждом формате",
+ "description": "Самый маленький корректный файл, который инструмент записывает в каждом из {{ .Facts.FormatCount }} форматов, и пустой файл там, где формат это допускает, с ожидаемой реакцией для каждого.",
+ "catches": [
+ "корректный файл, отклонённый как слишком маленький, потому что проверка считает байты, а не читает их",
+ "пустой файл, который роняет читающий код вместо того, чтобы быть замеченным",
+ "картинка шириной в один пиксель, которая делит на ноль на пути к миниатюре",
+ "хранилище, которое воспринимает ноль байт как неудачную загрузку и бесконечно повторяет попытки"
+ ],
+ "details": {
+ "formats": "Из каких форматов состоит набор. Оставьте all для всех форматов этой сборки или перечислите те, которые принимает ваша система."
+ }
+ },
+ "filename-handling": {
+ "question": "Сохранит, покажет и вернёт ли моя система имя файла, которого не ожидала?",
+ "title": "Обработка имён файлов",
+ "pageTitle": "Проблемные имена файлов для тестов - Unicode и длина",
+ "description": "Файлы с именами, ломающими загрузку и хранение: другие письменности и эмодзи, смена направления письма, невидимые символы, синтаксис shell и SQL, лимиты длины.",
+ "catches": [
+ "имя, которое на экране, в журнале или в списке выглядит как другое",
+ "имя, обрезанное, укороченное или переписанное между загрузкой и хранением",
+ "лимит длины, который считается в символах там, где хранилище считает байты"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "Применяется ли лимит размера ровно там, где он объявлен?",
+ "title": "Границы размера",
+ "pageTitle": "Проверка лимита размера загрузки - файлы на самой границе",
+ "description": "Файлы на байт меньше, ровно по лимиту и на байт больше лимита вашей системы, плюс более широкие шаги в обе стороны, с пометкой, нужно ли принять каждый.",
+ "catches": [
+ "ошибки на единицу на границе лимита",
+ "МБ, перепутанные с МиБ, то есть 4,8 процента, чего достаточно, чтобы пропустить файл, который не должен проходить",
+ "лимит, который применяется в браузере, а не на сервере"
+ ],
+ "details": {
+ "limit": "Лимит размера, который объявляет ваша система. Всё остальное отмеряется от него.",
+ "spread": "Как далеко отходить от лимита в обе стороны, списком размеров."
+ }
+ },
+ "tabular-import": {
+ "question": "Переживёт ли мой импорт таблиц то, что экспортируют настоящие инструменты?",
+ "title": "Импорт таблиц",
+ "pageTitle": "Тестовые файлы для импорта CSV и Excel - разделители и заголовки",
+ "description": "CSV с другими разделителями, концами строк CR LF, без заголовка и с иными кавычками, очень широкая таблица, книга Excel и JSON в нескольких видах.",
+ "catches": [
+ "файл с точкой с запятой, прочитанный как один столбец, потому что разделитель предположили, а не искали",
+ "файл CRLF, разбитый на строки с пустой строкой после каждой",
+ "таблица без заголовка, первая строка данных которой съедается как имена столбцов",
+ "импорт, который оставляет столбцы, что может показать, и молча отбрасывает остальные",
+ "читатель, который берёт записи JSON по одной строке и останавливается на первом документе с отступами"
+ ],
+ "details": {
+ "rows": "Сколько строк в таблице. Файл записывается ровно того размера, в который упаковывается столько строк, поэтому бюджет выше меняется вместе с этим значением.",
+ "columns": "Сколько столбцов в каждой строке таблицы. У произведения строк на столбцы есть потолок, и запрос сверх него отклоняется до записи чего-либо."
+ }
+ },
+ "text-encoding": {
+ "question": "Знает ли мой читатель, в какой кодировке файл, или угадывает?",
+ "title": "Кодировка текста",
+ "pageTitle": "Тестовые файлы кодировки текста - UTF-8, UTF-16, BOM, CRLF",
+ "description": "Один и тот же текст в UTF-8, UTF-16LE и UTF-16BE, с меткой порядка байтов и без неё, и концы строк CR LF и LF, чтобы проверить, как читатель декодирует текст.",
+ "catches": [
+ "читатель, который предполагает UTF-8 и показывает файл UTF-16 с одним символом из трёх или рядами квадратиков",
+ "метка порядка байтов, прочитанная как содержимое, из-за чего первое поле импорта начинается с трёх лишних символов",
+ "импортёр, который угадывает кодировку по первым байтам и угадывает иначе для более длинного файла",
+ "файл CRLF, разбитый на строки с пустой строкой после каждой, или возврат каретки, оставшийся в последнем поле"
+ ],
+ "details": {
+ "sample": "Размер каждого файла набора. UTF-16 хранит по два байта на символ, поэтому нечётное число отклоняется."
+ }
+ },
+ "upload-validation": {
+ "question": "Принимает ли моя форма загрузки то, что должна, и отклоняет ли остальное?",
+ "title": "Проверка загрузки",
+ "pageTitle": "Тестовые файлы проверки загрузки - тип, размер и имя",
+ "description": "Файлы для проверки формы загрузки: разрешённые и запрещённые типы, содержимое не по расширению, лимит размера, враждебные имена и массовая загрузка.",
+ "catches": [
+ "лимит, который применяется в браузере, а не на сервере",
+ "SVG или HTML, принятый за картинку или простой текст, что позволяет провести скрипт через форму",
+ "файл, проверенный по расширению и ни разу не открытый, так что PDF с именем .jpg проходит",
+ "форма, которая читает всё тело в память, прежде чем посмотреть, насколько оно велико",
+ "загрузка с именем PHOTO.JPG отклонена там, где photo.jpg принимается, или наоборот",
+ "имя с пробелами, скобками или символами вне ASCII, записанное на диск без изменений"
+ ],
+ "details": {
+ "limit": "Лимит размера, который объявляет ваша форма загрузки. Этот набор делает по одному шагу в обе стороны - для файла на любом расстоянии запустите пресет size-boundaries.",
+ "allow": "Какие типы должна принимать ваша форма. Каждый становится настоящим файлом этого типа, и вместе они служат положительным контролем всего набора.",
+ "deny": "Какие расширения должна отклонять ваша форма. Расширение, для которого в этой сборке нет формата, всё равно получает файл с таким именем и простым текстом внутри.",
+ "far-over": "Насколько далеко за лимит заходит единственный большой файл. Отключите, если запись нескольких лимитов не стоит места на диске.",
+ "bulk": "Сколько файлов в массовой загрузке. Ноль полностью убирает эту группу из набора."
+ }
+ }
+ },
+ "commands": {
+ "generate": "создать файлы по рецепту или по флагам",
+ "validate": "проверить рецепт, ничего не записывая",
+ "verify": "сверить каталог с манифестом",
+ "cleanup": "удалить файлы, перечисленные в манифесте",
+ "recipe fmt": "вывести рецепт в устоявшемся виде",
+ "preset": "собрать набор файлов по именованному тестовому вопросу",
+ "formats": "перечислить форматы этой сборки",
+ "damage": "перечислить способы, которыми эта сборка может намеренно испортить файл",
+ "tool": "небольшие инструменты для уже имеющихся файлов",
+ "version": "вывести версию инструмента",
+ "license": "вывести лицензию и что она означает для созданных файлов"
+ },
+ "outcomes": {
+ "accept": "Ваша система должна принять файл.",
+ "reject": "Ваша система должна отклонить файл.",
+ "sanitize": "Ваша система должна принять файл и очистить его, например переименовав.",
+ "unspecified": "Зависит от правил вашей системы. Вы решаете, а затем проверяете, что происходит именно то, что вы имели в виду."
+ },
+ "damages": {
+ "zero-head": "Перезаписывает первые байты файла нулями, не меняя его длину. Большинство программ чтения смотрят сначала туда, поэтому это повреждение замечает почти всё."
+ },
+ "terms": {
+ "oracleNone": "не применимо",
+ "int": "любое целое число",
+ "choice": "одно значение из фиксированного набора",
+ "bool": "истина или ложь",
+ "size": "размер, например 2mb",
+ "text": "текст",
+ "pixels": "пикселей",
+ "paragraphs": "абзацев",
+ "rows": "строк",
+ "columns": "столбцов",
+ "slides": "слайдов",
+ "hertz": "герц",
+ "megapixels": "мегапикселей",
+ "million cells": "миллионов ячеек",
+ "entries per second": "записей в секунду",
+ "files": "файлов",
+ "sizes separated by commas": "размеры через запятую",
+ "format ids separated by commas": "id форматов через запятую",
+ "format ids separated by commas, or all": "id форматов через запятую или all",
+ "extensions separated by commas": "расширения через запятую",
+ "the id of a format, as tfg formats lists them": "id формата в том виде, как его выводит tfg formats",
+ "the password, in plain text": "пароль открытым текстом",
+ "any text": "любой текст",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "дата вида 2024-02-29 или 2024-02-29T13:45:00+02:00, либо none"
+ },
+ "faq": [
+ {
+ "q": "Чем это отличается от dd, fsutil или truncate?",
+ "a": "Они дают файл нужного размера, набитый пустотой. Файл photo.png на 2 МБ, сделанный так, не является PNG, поэтому всё, что действительно его разбирает, отклоняет его по неверной причине, и ваш тест тоже проходит по неверной причине. Этот инструмент создаёт настоящий PNG ровно на 2 МБ, который открывается в просмотрщике изображений, и сопровождает его заявлением о том, как ваша система должна с ним поступать.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "Это бесплатно, и можно ли использовать на работе?",
+ "a": "Да в обоих случаях. Инструмент выпущен под GPL-3.0 и ничего не стоит. Нет ни учётной записи, ни лицензионного ключа, ни платного тарифа."
+ },
+ {
+ "q": "Можно ли использовать созданные файлы в продукте с закрытым кодом?",
+ "a": "Да. Лицензия охватывает код инструмента, а не то, что он создаёт. Созданные файлы, рецепты и манифесты являются результатом, а не производными произведениями, поэтому их можно коммитить и поставлять без каких-либо обязательств."
+ },
+ {
+ "q": "Содержат ли созданные файлы настоящие персональные данные?",
+ "a": "Нет. Всё внутри синтезируется из seed. Никакой набор данных не читается, ни к какому сервису не обращаются и никакое стороннее содержимое не встраивается. Считайте созданный адрес электронной почты непригодным, а не неиспользованным, потому что любая случайная строка может случайно совпасть с настоящим адресом."
+ },
+ {
+ "q": "Получу ли я точно такие же файлы на другой машине?",
+ "a": "Да, байт в байт, при том же рецепте и том же seed. Проект проверяет это при каждом изменении, а нарушить это можно только повышением мажорной версии. Именно поэтому вы можете коммитить небольшой рецепт вместо больших бинарных фикстур."
+ },
+ {
+ "q": "Нужно ли подключение к интернету?",
+ "a": "Никогда. Нет ни телеметрии, ни проверки обновлений, ни облачного клиента, а в бинарный файл командной строки вообще не скомпилирован сетевой стек. Он работает на машине без сети и в закрытой корпоративной среде."
+ },
+ {
+ "q": "Что будет, если запросить размер, которого формат не может достичь?",
+ "a": "Вы получите ошибку с названием формата, наименьшим возможным размером, причиной этого минимума и тем, что делать вместо этого, а файл записан не будет. Инструмент никогда не округляет размер молча. Каждый минимум указан на странице форматов.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "Можно ли создать намеренно сломанный файл?",
+ "a": "Да. Добавьте --damage zero-head, и файл выйдет точно заданного размера, с первыми байтами, перезаписанными нулями, так что программа чтения его отклонит, а манифест скажет, что ваша система должна его отклонить. Подробности на странице о повреждённых тестовых файлах.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "Какие форматы появятся дальше?",
+ "a": "7z, mp3 и mp4. Сегодня полностью работают {{ .Facts.FormatCount }} форматов."
+ },
+ {
+ "q": "На каких системах это можно запускать?",
+ "a": "Командная строка работает в Windows и Linux на Intel и ARM, а также на Mac с Apple Silicon. Десктопное окно поставляется для Windows на Intel, Linux на Intel и Mac с Apple Silicon. Mac на Intel не поддерживаются, и для них ничего не собирается."
+ },
+ {
+ "q": "Нужно ли что-нибудь устанавливать?",
+ "a": "Нет. Скачайте архив для своей системы, распакуйте и запустите бинарный файл. Нет установщика, среды выполнения, которую нужно добавлять, и зависимостей, которые нужно разрешать. Если у вас есть Go, подойдёт и одна команда go install.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "Почему запуск на тысячах файлов в Windows медленнее?",
+ "a": "Потому что Windows берёт больше за каждый просматриваемый путь, а команда, обходящая тысячи файлов, просматривает тысячи путей. Измерено на одной машине с 3000 файлов по 1 КБ: verify занимает около 0,9 секунды в Windows и около 0,2 секунды в Linux в контейнере. Более короткий путь вывода уменьшает цифру для Windows, потому что каждая папка над файлами входит в то, что просматривается."
+ }
+ ]
+}
diff --git a/web/content/ru/use-cases.html b/web/content/ru/use-cases.html
new file mode 100644
index 00000000..3f9d79d0
--- /dev/null
+++ b/web/content/ru/use-cases.html
@@ -0,0 +1,131 @@
+
Для чего это используют
+
+ Пять задач, которые возникают почти в каждом проекте, принимающем файлы от людей, и команда,
+ решающая каждую. Каждый пример ниже запускается как написано.
+
+
+
+
Лимиты загрузки
+
Проверка того, что лимит размера файла применяется там, где заявлено
+
+ Лимит - это три тестовых случая, а не один: чуть ниже, ровно по лимиту и чуть выше. Получить их
+ вручную значит считать числа байт и надеяться, что вы не ошиблись на единицу. Запросите вместо
+ этого набор:
+
+ Вы получите три настоящих PDF по 1048575, 1048576 и 1048577 байт и манифест, который говорит, что
+ первые два нужно принять, а третий отклонить по size_limit. Ваш тест читает
+ ожидание, вместо того чтобы вы писали три проверки вручную, а когда лимит меняется, вы меняете
+ одно число и запускаете заново.
+
+
+ То же работает и без пресета, когда нужен один набор границ прямо в команде:
+
+ Большие бинарные фикстуры замедляют клонирование репозитория и мешают ревью, а при замене никто не
+ может сказать, что изменилось. Рецепт - это несколько сотен символов YAML, которые пересоздают
+ те же файлы - байт в байт, на любой машине - потому что каждый файл выводится
+ из seed запуска.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ У каждого исхода свой код завершения, поэтому конвейер отличает плохой рецепт от полного диска и от
+ расхождения при проверке. Неудачный запуск ничего не печатает в стандартный вывод, и разборщик
+ журналов не принимает ошибку за данные.
+
+
+
+
+
Масштаб
+
Выяснить, что происходит, когда папка велика
+
+ Процедуры импорта, ночные задания и списки каталогов ведут себя иначе при десяти тысячах файлов, чем
+ при десяти. Размеры, выбранные из диапазона, делают набор похожим на настоящий трафик, а не на
+ десять тысяч одинаковых файлов, и выбор идёт от seed, так что завтра набор будет тем же.
+
+ Запуск больше свободного места на диске отклоняется до записи первого байта, а не заполняет диск и
+ не падает на полпути.
+
+
+
+
+
Архивы
+
Проверка распаковщика на архиве, который действительно содержит файлы
+
+ Пустой архив с правильным расширением ничего не доказывает о коде, который его открывает и обходит
+ содержимое. Объявите содержимое, и архив действительно его содержит:
+
+ Глубина вложенности, число записей и размер содержимого - это то, о чём у процедуры импорта есть
+ своё мнение, и так вы узнаёте, каково оно.
+
+
+
+
+
Парсеры и просмотрщики
+
Проверка того, что ваш собственный код читает формат так же, как настоящее ПО
+
+ Каждый формат здесь проверяется независимым читателем до выпуска: PNG открывается и сравниваются его
+ пиксели, DOCX перечитывается отдельными библиотеками, архив распаковывается. Это значит, что
+ файл, который отклоняет ваш парсер, - находка о вашем парсере, а не о генераторе.
+
+ Страница форматов перечисляет настройки каждого формата и наименьший
+ файл, каким он может быть.
+
+
+
+
+
Руководства
+
Два из них подробнее
+
+
+ Повреждённые тестовые файлы - файл, намеренно испорченный,
+ точного размера, с записанным в манифесте тем, что с ним должно произойти.
+
+
+ Тестовые файлы в CI - workflow для GitHub Actions, задание
+ GitLab и коды завершения, которые роняют сборку.
+
+
+
+
+
+
Для кого это
+
+ QA-инженеры, автоматизация тестирования и все, за чьим кодом стоит форма загрузки, процедура
+ импорта, парсер или квота хранилища. Работает на машине вообще без сети, что важно в закрытой
+ корпоративной среде, где генератор в браузере - не вариант.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/th/ci.html b/web/content/th/ci.html
new file mode 100644
index 00000000..48ae49f1
--- /dev/null
+++ b/web/content/th/ci.html
@@ -0,0 +1,185 @@
+{{ with .Up }}
บรรทัดคำสั่งที่สร้างมาสำหรับ CI และหน้าต่างเดสก์ท็อปสำหรับการทดสอบเชิงสำรวจ ไม่มีอันใดเป็นฉบับตัดทอนของอีกอัน และมีการทดสอบเปรียบเทียบทั้งสองทีละความสามารถ
+ Bir depodaki ikili fixture sonsuza dek geçmişinde kalır, bir diff'te incelenemez ve dosya
+ büyüdüğünde olanaksız hale gelir. Bunun yerine dosyaları hat içinde bir tariften üretin. Tarif
+ metindir, baytlar her seferinde aynı çıkar ve son bir adım hiçbir şeyin kaymadığını kanıtlar.
+
+
+
+
Kısa yanıt
+
+ tfg'yi kurun, testlerden önce tfg generate fixtures.yaml --out ./fixtures,
+ sonra tfg verify ./fixtures/manifest.json çalıştırın. Her iki adım da derlemeyi
+ kendiliğinden başarısız kılar ve nedenini söyleyen bir çıkış koduyla bunu yapar.
+
+
+
+
+
Neden commit edilmez
+
Bir fixture neden depoda durmamalı
+
+
+ Geçmişte kalır. Bir ikili dosyayı sonradan silmek klonu küçültmez, çünkü onun her
+ sürümü hâlâ oradadır.
+
+
+ Diff neyin değiştiğini göstermez. İnceleyen kişi bir PDF'nin farklı olduğunu görür,
+ başka bir şey değil. Bir tarif ise bir satırla değişir.
+
+
+ Büyük dosyalar sığmaz. GitHub, 100 MB'ın üzerinde bir dosya içeren bir push'u
+ reddeder. Bu yüzden 500 MB'lık bir yükleme sınırı testinin commit edecek bir şeyi olmaz.
+
+
+
+ Commit edilecek olan tariftir. Aynı tarif ve aynı tohum her makinede aynı baytları yazar, bu yüzden
+ hatta üretilen dosya dizüstünüzde sahip olduğunuz dosyadır.
+
+
+
+
+
Tarif
+
Testlerin yanında duran bir tarif
+
+ Bu tarif, kabul edilmesi gereken yirmi beş fatura ile bir sınırın üzerinde olup reddedilmesi gereken
+ iki görüntü yazar ve bildirim iki beklentiyi de kaydeder:
+
+ Sağlama toplamı satırı arşivi aynı sürümdeki verify-SHA256SUMS.txt ile karşılaştırır.
+ Sürüm sabitlenmiştir, bu yüzden yeni bir sürüm dokunmadığınız bir derlemeyi asla değiştirmez.
+
+ Her sonun kendi çıkış kodu vardır, bu yüzden adım kendiliğinden başarısız olur ve günlük hangisi
+ olduğunu söyler. Bir hattın karşılaştıkları:
+
+
+
3 - tarif geçerli değil. Hiçbir şey yazılmadı ve her sorun adlandırıldı
+
4 - biçim istenileni yapamıyor, örneğin kendi en küçüğünün altında bir boyut
+
6 - yeterli disk alanı yok
+
7 - tfg verify bildirimiyle uyuşmayan bir dosya buldu
+
8 - çalıştırma bitti ama her şey üretilmedi
+
+
+ Başarısız bir çalıştırma standart çıktıya hiçbir şey yazmaz, bu yüzden bir günlük ayrıştırıcısı
+ hatayı asla veri sanmaz. Tablonun tamamı belgeler
+ sayfasında.
+
+
+
+
+
PowerShell
+
Bir PowerShell betiği bir satır daha ister
+
+ PowerShell, bir programın çıkış kodunu bir .ps1 dosyasının dışına taşımaz. Birini
+ -File ile çalıştırın. İçindeki araç işi reddetse bile betik 0 yanıtı
+ verir ve kırmızı olması gereken bir derleme yeşile döner. Son satır düzeltmenin tamamıdır:
+
+ PowerShell böyle davranır, bu aracla ilgili bir şey değildir. cmd, bash ve
+ zsh fazladan hiçbir şeye gerek duymaz.
+
+
+
+
+
Birkaç iş
+
Fixture'ları işler arasında paylaşmak
+
+ Genellikle yüklemeye gerek yoktur. Aynı tarif aynı baytları yazdığı için her iş kendi tfg
+ generate komutunu çalıştırabilir ve bu, yükleyip indirmekten daha hızlıdır. Bir işin
+ başka bir işten dosya alması gerekiyorsa, aktarımdan sonra bildirim üzerinde tfg
+ verify çalıştırın. Gelenin yazılanla aynı olup olmadığını söyler.
+
+ Yalnızca sağlam dosyalar gösterilmiş bir doğrulayıcı gerçekten sınanmış sayılmaz. İşte kasıtlı
+ bozulmuş, tam istediğiniz boyutta çıkan ve sisteminizin onunla ne yapması
+ gerektiğini söyleyen bir bildirimle gelen bir dosyayı nasıl elde edeceğiniz.
+
+
+
+
Kısa yanıt
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out tam 2097152 bayt
+ boyutunda, ilk baytları sıfır olan bir PNG yazar ve yanındaki bildirim sisteminizin onu
+ reddetmesi gerektiğini kaydeder.
+
+
+
+
+
Olağan yol
+
Elle bozulmuş bir dosya neden kötü bir testtir
+
+ Olağan yollar bir onaltılık düzenleyici, birkaç rastgele baytı çeviren bir betik ya da bir dosyayı
+ head veya truncate ile kısaltmaktır. Bir kez işe yarar, sonra size
+ pahalıya mal olur:
+
+
+
+ Her seferinde farklıdır. Rastgele bir bayt her çalıştırmada başka bir yere düşer,
+ bu yüzden salı günkü bir hata çarşamba dönmeyebilir.
+
+
+ Boyutu değiştirir. Kesilmiş bir dosya, altında kalması gereken sınırdan küçüktür.
+ Böylece boyut denetimi içerik denetiminden önce yanıt verir ve test yanlış nedenle geçer.
+
+
+ Çoğu zaman fark edilmez. Düz metin ortasında değişmiş bir baytla da okunur,
+ hoşgörülü bir görüntü okuyucusu ise onu olduğu gibi çizer. Böylece bozuk olması gereken dosya
+ kabul edilir.
+
+
+ Ne olması gerektiğini söylemez. Dosya yalnızca bayttır ve testi sonradan okuyan,
+ kabulün mü reddin mi amaçlandığını tahmin etmek zorunda kalır.
+
+
+
+
+
+
Ne elde edersiniz
+
Hasarlı bir dosya yine istediğiniz boyuttadır
+
+ Dosya normal üretilir, sonra diske giderken bozulur. İstediğiniz boyutu korur ve aynı komut yine
+ aynı baytları yazar.
+
+ Ayarlar iki noktadan sonra yazılır. Seçenek tekrarlanabilir ve hasarlar yazdığınız sırayla
+ uygulanır. {{ .Facts.FormatCount }} biçimin her biriyle çalışır.
+
+
+
+
+
Neler yapabilir
+
Hangi hasarlar var?
+
+ Bu, programın yazdırdığı listedir ve bu sayfa oluşturulurken programdan okunur. tfg
+ damage aynısını yazdırır, tfg damage <id> ise birinin neyi kabul
+ ettiğini söyler.
+
+ {{ template "damagesTable" . }}
+
+ zero-head dosyanın başına sıfırlar yazar. Okuyucuların çoğu önce oraya bakar, dosyanın
+ ne olduğunu söyleyen imzaya ve başlığa, bu yüzden hemen her okuyucu fark eder. Düz metin ve
+ günlüklerin imzası yoktur ve onlar da reddedilir, çünkü bir sıfır baytı dizisi metin değildir.
+ Dört baytın altında bazı biçimler hiçbir okuyucunun şikâyet etmediği bir hasarla çıkar, ayarın
+ dörtten başlamasının nedeni budur.
+
+
+
+
+
Bildirim ne söyler
+
Ne olması gerektiğini söyleyen bir bildirim
+
+ Hasarlı her dosya, sisteminizin onu reddetmesi gerektiğini söyleyen bir kayıt alır ve hasar yanına
+ yazılır:
+
+ İki istek, bir şey yazılmadan önce reddedilir, çünkü her biri diskte bildirimin yanlış tarif ettiği
+ bir dosya bırakırdı:
+
+
+
hasarın gerektirdiğinden küçük bir dosya, ki değişmeden çıkardı
+
+ Bir hasarın yanında expected: accept, çünkü hiçbir şey bunu karşılayamaz. Sisteminiz
+ dosyayı onarmalıysa sanitize, tam da bunu soruyorsanız unspecified
+ yazın
+
+
+
+
+
+
Bir tarifte
+
Tek çalıştırmada sağlam ve bozuk dosyalar
+
+ İkisini de tek bir tarife koyun, bildirim her dosyanın beklentisini taşır. Böylece testin hangisinin
+ hangisi olduğuna dair bir listeye ihtiyacı kalmaz:
+
+ Test bildirimi okur ve olanın bildirilenle aynı olup olmadığına bakar. Dosya adı listesine ihtiyacı
+ yoktur:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ İyi bir ret temiz bir rettir. Neyin yanlış olduğunu söyleyen bir ileti istediğiniz yanıttır. Sunucu
+ hatası, takılma ya da yarım kaydedilmiş dosya, bu testin bulmak için var olduğu kusurdur.
+
+ Belgelertfg generate için her seçeneği içerir.
+
+
+
diff --git a/web/content/tr/docs.html b/web/content/tr/docs.html
new file mode 100644
index 00000000..1e299277
--- /dev/null
+++ b/web/content/tr/docs.html
@@ -0,0 +1,278 @@
+
Dokümantasyon
+
+ Aracın yaptığı her şey, insanların gerçekten geldiği sorular şeklinde düzenlendi.
+ Depodaki README tam başvurudur ve her zaman indirdiğiniz sürümle
+ eşleşir.
+
+
+
+
Hangi komutlar var?
+
Her biri tek bir iş yapar:
+ {{ template "commandList" . }}
+
+
+
+
Tam boyutta tek bir dosyayı nasıl üretirim?
+
+ Biçimi, boyutu ve nereye gideceğini söyleyin. Boyutlar 1024'lerle sayılır, yani 2mb
+ 2097152 bayttır. Düz bir bayt sayısı da olur, yani --size 10485761 tam o kadarını
+ ister.
+
+
tfg generate --format png --size 2mb --out ./out
+
generate için işe yarar bayraklar:
+
+
+
Bayrak
Ne yapar
+
+
--format <id>
dosyaların biçimi, örneğin txt
+
--size <size>
her dosyanın tam boyutu, 10mb gibi veya düz bir bayt sayısı
+
--size-range <a-b>
bir aralıktan dosya başına çekilen boyut, 1kb-8kb gibi. Çekiliş seed'den gelir
+
--boundary <size>
bir sınırın çevresinde üç dosya: bir bayt altı, sınırın kendisi, bir bayt üstü
+
--count <n>
kaç dosya üretileceği. Varsayılan 1
+
--name <template>
ad şablonu, örneğin invoice_{index:04}.txt
+
--out <dir>
yazılacak dizin
+
--seed <n>
çalıştırmanın seed'i. Aynı seed aynı baytları verir
+
--set <k>=<v>
bir biçim ayarı, tekrarlanabilir
+
--damage <name>
dosyaları kasıtlı bozar, tekrarlanabilir ve sırayla uygulanır. Liste için tfg damage çalıştırın
+
--expected <outcome>
accept, reject, sanitize veya unspecified
+
--dry-run
say ve göster, hiçbir şey yazma
+
--json
manifesti standart çıktıya yaz
+
+
+
+
+
+
+
Kasıtlı bozuk bir dosyayı nasıl yaparım?
+
+ Bu aracın yazdığı diğer her dosya yapısı gereği doğrudur ve bu, bir yükleme doğrulayıcısının sorduğu
+ üç sorudan ikisini yanıtlar. --damage üçüncüsünü yanıtlar - dosya hiç açılıyor mu.
+ Dosya normal üretilir, sonra bozulur, böylece hâlâ istediğiniz boyuttadır.
+
+ Ayarlar iki noktadan sonra gelir. Bayrak tekrarlanır ve yazdığınız sıra uygulanma sırasıdır.
+ tfg damage bu sürümün neler yapabildiğini ve her birinin ne aldığını listeler.
+
+
Bir tarifte anahtar, adlardan veya ayarlardan oluşan bir listedir:
+ Hasarlı bir dosya manifestte expected: reject alır, hasar yanında kaydedilir. İki şey
+ bir şey yazılmadan önce reddedilir, çünkü her biri aksi hâlde diske manifestin yanlış tarif
+ ettiği bir dosya koyardı:
+
+
+
hasarın gerektirdiğinden küçük bir dosya, çünkü değişmeden çıkardı
+
+ bir hasarın yanında expected: accept, çünkü hiçbir şey bunu karşılayamaz. Test edilen
+ sistemin dosyayı onarması amaçlanıyorsa sanitize, sorduğunuz soru buysa
+ unspecified yazın
+
+
+
+ Üçüncüsü önceden bilinemez. Bir hasar çalışıp hiçbir baytı oynatmazsa o dosya yazılmak yerine atılır
+ - çalıştırma sürer, hangi dosya olduğunu söyler ve kısmi çıkış koduyla biter.
+
+ Tarif, tüm bir çalıştırmayı anlatan bir YAML dosyasıdır. Testlerinizin yanına commit edin,
+ fixture'lar deponuzda ikili dosya olmaktan çıkar - herkes onları birkaç yüz karakterlik bir
+ dosyadan bayt bayt yeniden kurabilir.
+
+ Her target, size, size-range, boundary veya
+ contains anahtarlarından tam birine ihtiyaç duyar. İkisi hatadır, hiçbiri de öyle.
+ Geçersiz bir tarif hiç dosya yazmaz ve yalnızca ilkini değil tüm sorunları bir
+ seferde bildirir, her biri ilgili ayarı adlandırır.
+
+
+
+
+
Sistemimin bir dosyayla ne yapması gerektiğini nasıl bildiririm?
+
Sonuç yeterliyse kısa biçim, neden önemliyse uzun biçim:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Sonuçlar accept, reject, sanitize ve
+ unspecified. Nedenler, bir rapor onlara göre gruplayabilsin diye kapalı bir
+ listedir: content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit ve
+ size_zero.
+
+
+ Bir neden söz konusu kuralı adlandırır, hükmü değil. Bu yüzden aynı neden iki
+ sonucun altında da durabilir - sınırın bir bayt altındaki dosya accept olur ve söz
+ konusu kural yine size_limit kalır.
+
+
+
+
+
Manifestte ne var?
+
+ Her çalıştırmanın sonunda, kesilen çalıştırma dahil, dosyaların yanına yazılır. Dosya başına bir
+ girdi:
+
+ Çalıştırma bir tariften geldiyse bir recipe_hash, bir hazır ayardan geldiyse
+ overrides ile birlikte preset eklenir, böylece bir manifest her zaman
+ onu üreten şeye kadar izlenebilir.
+
+
+ Her girdi ayrıca dosyayı üreten tarifteki hedefin kimliği olan target_id taşır ve
+ summary.by_target her hedefin kaç dosyaya vardığını sayar. Birkaç hedefli bir tarif
+ böylece dosya adlarını okumadan hedef hedef denetlenebilir.
+
+
+
+
+
Hazır ayar nedir?
+
+ Yaygın bir test sorusunu yanıtlayan hazır bir dosya seti, böylece seti kendiniz tasarlamanız
+ gerekmez. Hazır ayarlar altta sıradan tariflerdir ve eject tarifi yazdırır, oradan
+ düzenleyebilirsiniz. Her hazır ayarın genelde ne bulduğunu, sette ne olduğunu ve kabul ettiği
+ her ayarı anlatan kendi sayfası vardır.
+
+ show, seti kurmadan önce neye mal olacağını söyler ve bir sayının sizin sınırınız değil
+ bizim geçici değerimiz olduğunu açıkça belirtir.
+
+
+
+
+
Çıkış kodları ne anlama gelir?
+
+ Her sonun kendi kodu vardır, makine tarafından okunabilir çıktı standart çıktıya gider ve başarısız
+ bir çalıştırma orada hiçbir şey yazdırmaz. Tablo dondurulmuş bir sözleşmedir - bir kodun
+ anlamını değiştirmek büyük sürüm artışı gerektirir.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Ctrl+C ile durdurulan bir çalıştırma yine bir manifest bırakır ve asla yarım yazılmış bir dosya
+ bırakmaz, böylece iptal edilen bir işi bir sonraki temizleyebilir.
+
+ Evet, betiklenmeyen test için üzerine bir pencere konmuş aynı motor. Kırpılmış bir sürüm değildir:
+ bir test iki arayüzü yetenek yetenek karşılaştırır ve yalnızca birinin yapabildiği her şey
+ sessizce ayrışmak yerine bildirilip gerekçelendirilmelidir.
+
+
+ Ekranlar tek bir grup, hazır ayarlar, aynı anda birkaç grup ve hakkında. Bir çalıştırmanın neye mal
+ olacağını bir şey yazmadan önce gösterir, çalışırken ilerlemeyi bildirir ve yarım yazılmış dosya
+ bırakmadan yarıda iptal edilebilir. Henüz bir tarif dosyası açmaz - tarifler şimdilik komut
+ satırının işidir ve pencere gruplarını formda kurar.
+
+
diff --git a/web/content/tr/exact-size.html b/web/content/tr/exact-size.html
new file mode 100644
index 00000000..5548df50
--- /dev/null
+++ b/web/content/tr/exact-size.html
@@ -0,0 +1,144 @@
+
Tam boyutta dosya nasıl oluşturulur
+
+ Her sistemin bunun için bir komutu var ve üçü de aşağıda. Size tam doğru bayt sayısında bir dosya
+ verirler - ve birçok test için gereken tek şey budur. Bu sayfadaki her komut,
+ yayımlanmadan önce ait olduğu sistemde çalıştırıldı.
+
+ PowerShell'de 10MB, Gezgin'in kullandığı aynı 1024 tabanlı sayımla 10485760 bayt
+ demektir, yani yukarıdaki iki komut aynı boyutu üretir.
+
+
+
+
+
Linux
+
dd, truncate ve fallocate ve insanları yakalayan fark
+
dd herkesin bildiğidir. Baytları gerçekten yazar:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate anlıktır ve tuzak da budur. Alpine Linux'ta ölçüldü: dosya 10485760 bayt
+ bildirir ve sıfır blok kaplar - bir seyrek dosyadır. Onu
+ okuyan her şey on megabayt sıfır alır ama disk alanı hiç vermemiştir:
+
+
truncate -s 10M test10mb.bin
+
+ Bu, yükleme sınırını sınamak için iyidir ve disk kotasını sınamak için yanıltıcıdır. Alan gerçek
+ olmalıysa başvurulacak olan fallocate'tir:
+
+
fallocate -l 10M test10mb.bin
+
Ve içerik, bir arşivleyici onu yeniden sıkıştıramasın diye sıkıştırılamaz olmalıysa:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
seyrek olmayan mkfile ve zaten bildiğiniz iki komut
+
+ macOS mkfile ile gelir. macOS 26.6.2'de ölçüldü: 10485760 bayt ve 20480 blok, yani alan
+ söz verilmek yerine gerçekten ayrılır:
+
+
mkfile 10m test10mb.bin
+
dd ve truncate da var ve Linux'taki gibi davranır:
Doğru boyutta bir dosya doğru türde bir dosya değildir
+
+ Yukarıdakilerin hepsi size bir sıfır bloğu verir. Test edilen şey yalnızca boyuta bakıyorsa -
+ yükleme sınırı, kota, aktarım - bu yeterlidir. Bir şey dosyayı açtığı anda
+ yeterli olmaktan çıkar.
+
+
+ Ölçüldü ve kendiniz yapmaya değer: fsutil ile 2 MB'lık bir dosya yapın, adını
+ photo.png koyun ve bir görüntü kitaplığına verin. Pillow cannot identify
+ image file yanıtını verir. PNG değil. Hiç de olmadı - yalnızca adı öyle diyordu.
+
+
+ Bu, göründüğünden daha önemlidir, çünkü testin bundan sonra hangi yönde başarısız
+ olduğu belirleyicidir. Yükleme endpoint'iniz dosyayı reddeder, testiniz yeşile döner ve
+ boyut sınırının çalıştığı sonucuna varırsınız. Onu boyut yüzünden reddetmedi. Baytlar resim
+ olmadığı için reddetti ve sınamak istediğiniz kurala hiç ulaşılmadı.
+
+
+
bir ayrıştırıcı herhangi bir boyut kuralına bakılmadan önce onu reddeder
+
küçük resim adımı başarısız olur ve okuduğunuz hata küçük resimle ilgilidir
+
bir antivirüs veya içerik denetimi onu üçüncü bir nedenle reddeder
+
bir görüntüleyici hiçbir şey göstermez ve bunun hata olup olmadığını kimse söyleyemez
+
+
+
+
+
Öbür yol
+
O biçimden gerçek bir dosya, tam istediğiniz boyutta
+
+ Testing Files Generator'ın yaptığı budur. Dosya biçiminin gerçek bir örneğidir - ait olduğu
+ programda açılır - ve istediğiniz tam bayt sayısındadır, bayta kadar:
+
+ Bir biçimin ulaşamayacağı bir boyut isteyin, alt sınırı ve nedenini adlandıran bir hata alırsınız,
+ asla yanlış boyutta bir dosya değil. Biçimler sayfası her biçimi
+ üretebildiği en küçük dosyayla listeler.
+
+
Ve bir sınır bir değil üç test durumudur, bu yüzden araç üçünü de kurar:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Bu size 10485759, 10485760 ve 10485761 bayt ile hangilerini sisteminizin kabul etmesi, hangilerini
+ reddetmesi gerektiğini söyleyen bir manifest verir. Kullanım
+ senaryoları sayfası bunu ve aracın yapıldığı dört işi daha anlatır.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Peki hangisini kullanmalı?
+
+
+
Sistem komutunu kullanın
+
+ Hiçbir şey dosyayı açmıyorsa. Önce boyuta bakan bir endpoint'te boyut sınırını sınamak, bir aktarım,
+ bir kota, disk dolu durumu. Tek satırdır ve zaten kuruludur.
+
+
+
+
Gerçek bir üretici kullanın
+
+ Bir şey dosyayı ayrıştırıyor, işliyor, içe aktarıyor veya çıkarıyorsa - ve yarın başka bir makinede
+ aynı fixture'lara bayt bayt ihtiyacınız varsa.
+
+
+
+
+ İkisi de bu sayfada çünkü ikisi de zamanın bir kısmında haklı. Kaçınılması gereken hata, ikincisinin
+ gerektiği yerde birincisini kullanmak ve yeşil testi kanıt saymaktır.
+
+
diff --git a/web/content/tr/faq.html b/web/content/tr/faq.html
new file mode 100644
index 00000000..4f268e89
--- /dev/null
+++ b/web/content/tr/faq.html
@@ -0,0 +1,18 @@
+
Sık sorulan sorular
+
+ Lisans, gizlilik, tekrarlanabilirlik ve insanların bir üreticiyi derleme hattına koymadan önce
+ denetlediği şeyler. Sorunuz burada yoksa sorun takipçisi açık.
+
{{ .Facts.FormatCount }} dosya biçimi, her biri tam boyutta üretilir
+
+ Bunların her biri o biçimde gerçek bir dosyadır. Ait olduğu programda açılır ve tam
+ istediğiniz bayt sayısındadır. Hiçbiri yapıştırılmış uzantılı dolgu sıfırları değildir.
+
+
+{{ template "formatsTable" . }}
+
+
+
Sütunların anlamı
+
+
+
En küçük dosya
+
+ Bu aracın o biçim için kabul edeceği en az bayt sayısı, dosyanın içine yazdığı etiket dahil. Daha
+ azını isterseniz alt sınırı ve nedenini adlandıran bir hata alırsınız, asla yanlış boyutta
+ bir dosya değil.
+
+
+
+
Bütünlük
+
+ Dosyanın ne kadar tam olduğu. full, biçimi gerçekten ayrıştıran bir okuyucunun onu
+ kabul ettiği anlamına gelir, yalnızca uzantının uyduğu anlamına değil.
+
+
+
+
Doğrulayan
+
+ Biçim yayımlanmadan önce üretilen her dosyayı açan bağımsız okuyucu - ayrı bir uygulama, kendi
+ ödevini kendi notlayan bizim kodumuz değil.
+
+
+
+
+ Her biçim ayrıca bayta kadar tekrarlanır: aynı tarif ve aynı seed her makinede özdeş dosyalar üretir
+ ve bir tarifi fixture'ların kendisi yerine commit etmeyi güvenli kılan budur.
+
+
+
+
+
Her biçimin kabul ettiği ayarlar
+
+ Çoğu biçimin kendi ayarları vardır - görüntü boyutları, JPEG kalitesi, PDF sayfa sayısı, bir
+ elektronik tablodaki satır ve sütunlar, bir arşivin içine kaç girdi gireceği. Bunları komut
+ satırında --set key=value ile veya bir tarifte properties: altında
+ ayarlayın.
+
+ Bir ayarın kabul ettiğinin dışındaki değer, ayarı, izin verilen aralığı ve onun yerine ne
+ kullanılacağını söyleyen bir iletiyle reddedilir. Bilinmeyen bir ayar da hatadır, asla sessiz
+ bir varsayılan değil - sessizce kabul edilen bir yazım hatası yanlış ayarlı bir dosya ve testin
+ geçmemesi gerekirken neden geçtiğini merak ederek geçen bir saat verir.
+
+
+ Elinizdeki sürümde bir biçimin tam olarak ne kabul ettiğini görmek için tfg formats
+ <id> çalıştırın.
+
+
+
+
+
Arşivler gerçek dosyalar içerir
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} ve {{ end }}{{ $c.ID }}{{ end }} boş
+ bir kabuk olarak bırakılmak yerine girdilerle doldurulabilir. Üretilmiş bir arşiv, içerdiğini
+ söylediği belgeleri gerçekten içerir, bu yüzden bir test sırasında onu açan her şey içinde
+ gerçek dosyalar bulur.
+
+ PDF, PNG, DOCX, ZIP - toplam {{ .Facts.FormatCount }} biçim ve her biri ait olduğu
+ programda açılan, tam istediğiniz boyutta gerçek bir dosya. Her çalıştırma
+ ayrıca uygulamanızın her dosyayla ne yapması gerektiğini de yazar. Komut satırı ve masaüstü
+ penceresi, ücretsiz ve açık kaynak, tamamen makinenizde çalışır.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ Bir dosya grubu yazmaya hazırlanmış masaüstü penceresi. Aynı motor komut satırının arkasında çalışır.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
gerçek biçim, her biri ait olduğu programda açılır
+
+
+ 1 bayt
+
istediğiniz her boyutun doğruluğu, asla sessizce yuvarlanmaz
+
+
+ 0
+
hiçbir yere bağlantı - hesap yok, telemetri yok, güncelleme denetimi yok
+
+
+
+
+
Sorun
+
Bir test dosyası yapmak kolay. Doğru bini yapmak sıkıcı kısım
+
İnsanlardan dosya kabul eden bir yazılımı test ediyorsunuz. Er ya da geç şunlara ihtiyacınız olur:
+
+
yükleme sınırının gerçek olup olmadığını anlamak için tam 10 MB'lık bir PDF
+
bir eksik veya fazla hatalarını yakalamak için o sınırın iki yanındaki üç dosya
+
klasör büyükken gece işinin ne yaptığını görmek için 10.000 günlük dosyası
+
doğru uzantılı boş bir kabuk değil, gerçekten 200 belge içeren bir ZIP
+
deponuzda 4 GB'lık bir dosya tutmadan 4 GB'lık bir dosya
+
dizüstü bilgisayarınızda ve derleme sunucusunda aynı fixture'lar, bayt bayt
+
+
+ Bunun yerini alan şey bu. QA mühendisleri, test otomasyonu ve kodunun arkasında bir yükleme formu,
+ içe aktarma rutini, ayrıştırıcı veya depolama kotası olan herkes için yapıldı.
+
+
+
+
+
Onu farklı kılan
+
Diğer üreticiler baytlarda durur. Bu, testinizin gerçekte ne sorduğunu yanıtlar
+
+ Bir dosya klasörü, her birinin neyi kanıtlaması gerektiğine yine sizin karar vermenize bırakır.
+ Burada her çalıştırma dosyaların yanına bir manifest.json yazar - üretilen her
+ şeyin düz bir listesi ve her girdi için bir bildirilmiş beklenti.
+
+
Yükleme endpoint'inizin 1 MB'a izin verdiğini varsayalım. O çizgideki üç dosyayı isteyin:
Yanıt kendi politikanıza bağlıysa manifest bunu söyler
+
+ Bir beklenti uydurmak yerine unspecified kaydeder. Tahmin yürüten bir üretici yanlış
+ hatalar üretir ve sürekli yalancı alarm veren bir test takımı kapatılır.
+
+
+
+
+
+
Hazır ayarlar
+
Soruyu seçin, setin tamamını alın
+
+ Hazır ayar, hangi dosyanın neyi kanıtladığını sizin çözmeniz gerekmesin diye tek bir test sorusu
+ etrafında tasarlanmış bir test dosyası setidir. Her birinin, genelde ne bulduğunu, sette ne
+ olduğunu ve kabul ettiği her ayarı anlatan bir sayfası vardır.
+
+ Her biri bir ile sekiz kilobayt arasında on bin günlük dosyası, boyutlar seed'den çekilir ki yarın
+ aynı seti versin. Her çalıştırmaya kendi dizinini verin - manifest bir
+ çalıştırmanın ne yazdığının tek kaydıdır, bu yüzden araç üzerine ikincisini yazmayı
+ reddeder:
+
+ Boyutlar, dosya yöneticinizin yaptığı gibi 1024'lerle sayılır, yani 2mb 2097152 bayt
+ demektir. Düz bir bayt sayısı da olur. Dokümantasyon tarifleri,
+ manifesti ve çıkış kodlarını kapsar.
+
+
+
+
+
Neler elde edersiniz
+
Gözetimsiz çalışan bir test takımı için yapıldı
+
+
+
Tam boyut, bayta kadar
+
10485761 bayt isteyin ve tam olarak onu alın. Bir biçimin ulaşamayacağı boyut nedeni olan bir hatadır, asla yanlış boyutta bir dosya değil.
+
+
+
{{ .Facts.FormatCount }} gerçek biçim
+
Uzantılı dolgu sıfırları değil. Üretilmiş bir PNG resim görüntüleyicide, bir DOCX Word'de açılır, bir ZIP çıkarılır. Her biri yayımlanmadan önce bağımsız okuyucularla doğrulanır.
+
+
+
Test oracle'ı olan bir manifest
+
Yol, boyut, SHA-256, biçim, seed, araç sürümü - ve sisteminizin dosyayla ne yapması gerektiği.
+
+
+
Tekrarlanabilir
+
Aynı tarif ve aynı seed, aynı baytlar, her makinede. Büyük ikili fixture'lar yerine küçük bir YAML tarifini commit edin.
+
+
+
İki arayüz, tek motor
+
CI için yapılmış bir komut satırı ve keşif amaçlı testler için bir masaüstü penceresi. Hiçbiri diğerinin kırpılmış sürümü değildir ve bir test ikisini yetenek yetenek karşılaştırır.
+
+
+
Tamamen çevrimdışı
+
Hesap yok, bulut yok, telemetri yok, güncelleme denetimi yok. Komut satırı ikilisinin içine hiç ağ yığını derlenmemiştir.
+
+
+
+
+
+
İndirme
+
Sisteminiz için derlemeyi seçin
+
+ Arşivi açın ve çalıştırın. tfg komut satırı, tfg-gui masaüstü
+ penceresidir. Yükleyici yok ve makinenize eklenecek hiçbir şey yok.
+
+ {{ template "downloadsTable" . }}
+
+
Neler imzalı, neler değil
+
+ Windows ve macOS indirmeleri imzalıdır, bu yüzden bilinmeyen geliştirici uyarısı olmadan başlar.
+ Linux olanlar değildir, çünkü masaüstü Linux'ta onları imzalayacak bir karşılık yoktur. Her
+ arşiv sürüm sayfasındaki verify-SHA256SUMS.txt içinde listelenir, böylece
+ indirdiğinizi doğrulayabilirsiniz.
+
+ {{ .ID }} hazır ayarı, bu soru için tek komutla gerçek test dosyalarından oluşan bütün
+ bir set ve yanında sisteminizin her dosyaya nasıl tepki vermesi gerektiğini söyleyen bir
+ manifest.json kurar. Aşağıdaki her şey programdan, bu sürümün varsayılanlarıyla
+ okunur.
+
+
+{{ if .Catches }}
+
+
Genelde ne bulur?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
Sette ne var?
+
Varsayılanlarda, tfg preset show {{ .ID }} çıktısının bildirdiği gibi:
+
+
+
+
Dosya
{{ .Budget.Files }}
+
Tarifindeki hedefler
{{ .Budget.Targets }}
+
Toplam boyut
{{ .Bytes }} B
+
Biçimler
{{ join .Budget.Formats ", " }}
+
+
+
+
Ve o setin manifestinin sisteminizden beklediği:
+
+
+
+
Beklenen
Anlamı
Dosya
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
Neyi değiştirebilirsiniz?
+ {{- if .Settings }}
+
+
+
+
Ayar
Aldığı
Varsayılan
Ne yapar
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Bu varsayılan sizin sisteminizin değeri değil, bizim geçici değerimizdir. Kendinizinkini verin.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
Bu hazır ayarın ayarı yok. Set her seferinde aynıdır.
+ {{- end }}
+
+
+
+
Nasıl çalıştırılır?
+
Setin neye mal olacağına bakın, kurun veya düzenlemek için tarifini alın:
Ya da testlerinizin yanında kendi tarifinizde onun üzerine kurun:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/tr/presets.html b/web/content/tr/presets.html
new file mode 100644
index 00000000..c1fae63e
--- /dev/null
+++ b/web/content/tr/presets.html
@@ -0,0 +1,32 @@
+
Test dosyası hazır ayarları, her test sorusu için bir set
+
+ Hazır ayar, tek bir soru etrafında tasarlanmış, sisteminizin her dosyaya nasıl tepki vermesi
+ gerektiğini söyleyen bir manifestle gelen bütün bir test dosyası setidir. Soruyu siz seçersiniz,
+ aracın seti kurar. Her hazır ayarın genelde ne bulduğunu, sette ne olduğunu ve kabul ettiği her
+ ayarı anlatan kendi sayfası vardır.
+
+
+{{ template "presetsList" . }}
+
+
+
Hazır ayar bir tariften nasıl farklıdır?
+
+ Altta, hiç farklı değildir. Hazır ayar, aracın sizin için birkaç ayardan yazdığı bir tariftir.
+ tfg preset eject o tarifi yazdırır, böylece testlerinizin yanında tutup
+ düzenleyebilirsiniz ve kendi tarifiniz tek satırla bir hazır ayarın üzerine kurulabilir:
+ extends: preset: ve ardından kimliği.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Varsayılanlara güvenebilir miyim?
+
+ Dosyalar için evet. Yükleme formunun sınırı gibi yalnızca sisteminizin bildiği bir sayı için
+ varsayılan bizim geçici değerimizdir ve araç birini kullandığı her seferde bunu söyler. Her
+ hazır ayarın sayfası bu ayarları işaretler ve tfg preset show bir şey yazılmadan
+ önce söyler.
+
+
diff --git a/web/content/tr/site.json b/web/content/tr/site.json
new file mode 100644
index 00000000..1bc477e0
--- /dev/null
+++ b/web/content/tr/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "tr",
+ "locale": "tr_TR",
+ "name": "Türkçe",
+ "dir": "tr",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Ana sayfa",
+ "title": "QA için test dosyası oluşturucu - tam boyut, {{ .Facts.FormatCount }} gerçek biçim",
+ "description": "QA için ücretsiz, açık kaynaklı test dosyası oluşturucu. Tam boyutta gerçek PDF, DOCX, PNG ve ZIP dosyaları ve sisteminizin tepkisini söyleyen bir manifest."
+ },
+ {
+ "key": "formats",
+ "slug": "bicimler",
+ "nav": "Biçimler",
+ "title": "{{ .Facts.FormatCount }} desteklenen dosya biçimi - PDF, DOCX, PNG, ZIP ve daha fazlası",
+ "description": "Üretilen tüm biçimler, her birinin mümkün olan en küçük dosyası ve kabul ettiği ayarlar. {{ .Facts.FormatCount }} biçimin hepsi kendi programında açılır."
+ },
+ {
+ "key": "presets",
+ "slug": "hazir-ayarlar",
+ "nav": "Hazır ayarlar",
+ "title": "Test dosyası hazır ayarları - QA için hazır setler",
+ "description": "Hazır test dosyası setleri, her biri tek bir test sorusunu yanıtlar: yükleme sınırları, dosya adları, kodlamalar, tablo içe aktarma, boş dosyalar ve doğrulama."
+ },
+ {
+ "key": "docs",
+ "slug": "dokumantasyon",
+ "nav": "Dokümantasyon",
+ "title": "Dokümantasyon - komutlar, tarifler, manifest, çıkış kodları",
+ "description": "Komut satırından veya bir YAML tarifinden test dosyası nasıl üretilir, manifestin içeriği ve araç CI içinde çalışırken her çıkış kodunun anlamı."
+ },
+ {
+ "key": "use-cases",
+ "slug": "kullanim-senaryolari",
+ "nav": "Kullanım senaryoları",
+ "title": "Kullanım senaryoları - yükleme sınırları, CI fixture'ları, testler",
+ "description": "Yükleme boyut sınırını test etmek, CI için tekrarlanabilir fixture'lar kurmak, on bin dosya üretmek ve arşivleri gerçek içerikle doldurmak."
+ },
+ {
+ "key": "exact-size",
+ "slug": "tam-boyutta-dosya-olusturma",
+ "nav": "Tam boyut",
+ "title": "Belirli boyutta dosya oluşturma - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate ve mkfile, her biri kendi sisteminde ölçüldü, ve bir test PDF veya PNG gerektirdiğinde bu yolla yapılan dosyanın neden onlar olmadığı."
+ },
+ {
+ "key": "faq",
+ "slug": "sss",
+ "nav": "SSS",
+ "title": "SSS - test dosyası üretimi hakkında sorular",
+ "description": "dd ve fsutil'den farkı, dosyaların commit edilip edilemeyeceği, çalıştırmaların bayt bayt tekrar edip etmediği ve bir boyuta ulaşılamadığında ne olduğu."
+ },
+ {
+ "key": "damage",
+ "slug": "bozuk-test-dosyalari",
+ "nav": "Bozuk dosyalar",
+ "title": "Bozuk test dosyaları - tam boyutta bozuk dosyalar",
+ "description": "Kasıtlı bozulmuş, tam boyutta bir dosya ve sisteminizin onu reddetmesi gerektiğini söyleyen bir bildirim. Yükleme doğrulaması ve ayrıştırıcıları sınamak için.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "ci-icinde-test-dosyalari",
+ "nav": "CI'da test dosyaları",
+ "title": "CI'da test dosyaları - GitHub Actions, GitLab CI ve PowerShell",
+ "description": "İkili dosya commit etmek yerine test dosyalarını hat içinde üretin: GitHub Actions iş akışı, GitLab işi, çıkış kodları ve PowerShell tuzağı.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "İçeriğe geç",
+ "navLabel": "Ana",
+ "langLabel": "Dil",
+ "breadcrumbHome": "Ana sayfa",
+ "imageAlt": "Testing Files Generator - tam boyutta gerçek test dosyaları ve sisteminizin her birine nasıl tepki vermesi gerektiğini söyleyen bir manifest",
+ "schemaDescription": "QA için ücretsiz ve açık kaynaklı bir test dosyası oluşturucu. {{ .Facts.FormatCount }} biçimde tam boyutta gerçek dosyalar üretir ve test edilen sistemin her birine nasıl tepki vermesi gerektiğini söyleyen bir manifest yazar.",
+ "ctaDownload": "İndir",
+ "ctaSource": "Kaynak kodu görüntüle",
+ "ctaNote": "Ücretsiz ve açık kaynak, GPL-3.0. Kayıt gerekmez. Windows ve macOS indirmeleri imzalıdır ve uyarı vermeden başlar.",
+ "colFormat": "Biçim",
+ "colName": "Ad",
+ "colExtension": "Uzantı",
+ "colSmallest": "En küçük dosya",
+ "colFidelity": "Bütünlük",
+ "colChecked": "Doğrulayan",
+ "colSetting": "Ayar",
+ "colAccepts": "Kabul eder",
+ "colSystem": "Sistem",
+ "colCli": "Komut satırı",
+ "colWindow": "Masaüstü penceresi",
+ "noBinary": "henüz ikili dosya yok",
+ "colCode": "Kod",
+ "colMeaning": "Anlamı",
+ "footerBlurb": "QA için tam boyutta test dosyaları ve sisteminizin her birine nasıl tepki vermesi gerektiğini söyleyen bir manifest.",
+ "footerProject": "Proje",
+ "footerSource": "GitHub'da kaynak kod",
+ "footerReleases": "İndirmeler",
+ "footerIssues": "Sorun bildir",
+ "footerSupport": "Projeyi destekle",
+ "footerPages": "Sayfalar",
+ "footerLicence": "Telif (C) 2026 DonislawDev. GNU Genel Kamu Lisansı sürüm 3 altında yayımlanmıştır. Ürettiğiniz dosyalar sizindir - lisans aracı kapsar, çıktısını değil.",
+ "footerPrivacy": "Bu site hiçbir yerden yazı tipi, betik veya izleyici yüklemez. Çerez bırakmaz.",
+ "notFoundTitle": "Bu sayfa burada yok",
+ "notFoundLead": "Takip ettiğiniz adres bu sitedeki hiçbir sayfayla eşleşmiyor.",
+ "notFoundBack": "Ana sayfaya git",
+ "read.format": "Setteki her dosyanın biçimi. Aracın kendi bayrağıdır ve hazır ayar yalnızca ona bir varsayılan verir.",
+ "readTakes.format": "biçimler sayfasındaki bir biçim kimliği",
+ "colDamage": "Hasar",
+ "colEffect": "Baytlara ne yapar",
+ "colSettings": "Ayarlar",
+ "noSettings": "yok"
+ },
+ "endings": {
+ "0": "Her şey çalıştı.",
+ "1": "Araç içinde beklenmeyen bir hata.",
+ "2": "Yanlış komut veya bayrak.",
+ "3": "Tarif geçerli değil.",
+ "4": "Biçim istenen şeyi yapamıyor.",
+ "5": "Bir okuma veya yazma başarısız oldu.",
+ "6": "Yeterli disk alanı yok.",
+ "7": "verify bir uyuşmazlık buldu.",
+ "8": "Çalıştırma bitti ama her şey üretilmedi.",
+ "130": "Ctrl+C ile kesildi.",
+ "143": "Bir sinyalle durduruldu, CI zaman aşımı böyle görünür."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "Biçimin izin verdiği kadar küçük, geçerli bir dosya geçer mi?",
+ "title": "Boş ve asgari",
+ "pageTitle": "Her biçimde en küçük geçerli ve boş test dosyaları",
+ "description": "Aracın {{ .Facts.FormatCount }} biçiminin her birinde yazdığı en küçük geçerli dosya, biçim izin veriyorsa bir de boş dosya, her biri beklenen tepkiyle.",
+ "catches": [
+ "kontrol baytları okumak yerine saydığı için çok küçük diye reddedilen geçerli bir dosya",
+ "bildirilmek yerine okuyucuyu çökerten boş bir dosya",
+ "küçük resme giderken sıfıra bölen bir piksel genişliğinde görüntü",
+ "sıfır baytı başarısız yükleme sayıp durmadan yeniden deneyen depolama"
+ ],
+ "details": {
+ "formats": "Setin hangi biçimlerden oluştuğu. Bu sürümdeki tüm biçimler için all bırakın veya sisteminizin kabul ettiklerini yazın."
+ }
+ },
+ "filename-handling": {
+ "question": "Sistemim beklemediği bir dosya adını saklayıp gösterecek ve geri verecek mi?",
+ "title": "Dosya adı işleme",
+ "pageTitle": "Test için sorunlu dosya adları - Unicode ve uzunluk",
+ "description": "Yüklemeleri ve depolamayı bozan adlara sahip dosyalar: başka yazılar ve emoji, yön geçersiz kılma, görünmez karakterler, kabuk ve SQL sözdizimi, uzunluk sınırları.",
+ "catches": [
+ "ekranda, bir günlükte veya bir listede başka bir ad gibi görünen bir ad",
+ "yükleme ile depolama arasında kesilen, kırpılan veya yeniden yazılan bir ad",
+ "depolama bayt sayarken karakterle sayılan bir uzunluk sınırı"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "Bir boyut sınırı tam bildirildiği yerde uygulanıyor mu?",
+ "title": "Boyut sınırları",
+ "pageTitle": "Yükleme boyut sınırını test etme - tam sınırdaki dosyalar",
+ "description": "Sisteminizin bildirdiği sınırın bir bayt altında, tam üzerinde ve bir bayt üstünde dosyalar, iki yanda daha geniş adımlar, her biri kabul bilgisiyle işaretli.",
+ "catches": [
+ "sınırda bir eksik veya fazla hataları",
+ "MB ile MiB'in karıştırılması, yani yüzde 4,8, geçmemesi gereken bir dosyayı geçirmeye yeter",
+ "tarayıcıda uygulanan ama sunucuda uygulanmayan bir sınır"
+ ],
+ "details": {
+ "limit": "Sisteminizin bildirdiği boyut sınırı. Geri kalan her şey buradan ölçülür.",
+ "spread": "Sınırın iki yanında ne kadar uzağa gidileceği, boyutlar listesi olarak."
+ }
+ },
+ "tabular-import": {
+ "question": "Tablo içe aktarmam gerçek araçların dışa aktardıklarına dayanıyor mu?",
+ "title": "Tablo içe aktarma",
+ "pageTitle": "CSV ve Excel içe aktarma test dosyaları - ayırıcılar, başlıklar",
+ "description": "Başka ayırıcılı, CR LF satır sonlu, başlıksız ve başka tırnaklı CSV, çok geniş bir tablo, bir Excel çalışma kitabı ve birkaç düzende JSON.",
+ "catches": [
+ "ayırıcı aranmak yerine varsayıldığı için tek sütun olarak okunan noktalı virgüllü dosya",
+ "her satırdan sonra boş bir satırla satırlara bölünen CRLF dosyası",
+ "ilk veri satırı sütun adı diye yutulan başlıksız bir tablo",
+ "gösterebildiği sütunları tutup geri kalanını tek söz etmeden atan bir içe aktarma",
+ "JSON kayıtlarını satır satır alıp ilk girintili belgede duran bir okuyucu"
+ ],
+ "details": {
+ "rows": "Elektronik tablonun kaç satır içerdiği. O kadar satırın paketlendiği tam boyutta yazılır, bu yüzden yukarıdaki bütçe bu değerle kayar.",
+ "columns": "Elektronik tablonun her satırında kaç sütun olduğu. Satır çarpı sütunun bir tavanı vardır ve aşılması bir şey yazılmadan önce reddedilir."
+ }
+ },
+ "text-encoding": {
+ "question": "Okuyucum bir dosyanın hangi kodlamada olduğunu biliyor mu, yoksa tahmin mi ediyor?",
+ "title": "Metin kodlaması",
+ "pageTitle": "Metin kodlaması test dosyaları - UTF-8, UTF-16, BOM, CRLF",
+ "description": "Aynı metin UTF-8, UTF-16LE ve UTF-16BE olarak, bayt sırası işaretiyle ve işaretsiz, ayrıca CR LF ve LF satır sonlarıyla, okuyucunun metni nasıl çözdüğünü sınamak için.",
+ "catches": [
+ "UTF-8 varsayıp bir UTF-16 dosyasını üç karakterde bir karakter olarak veya kutu sıraları olarak gösteren okuyucu",
+ "içerik olarak okunan bir bayt sırası işareti, böylece bir içe aktarmanın ilk alanı üç yabancı karakterle başlar",
+ "kodlamayı ilk baytlardan tahmin edip daha uzun bir dosyada farklı tahmin eden bir içe aktarıcı",
+ "her satırdan sonra boş bir satırla satırlara bölünen CRLF dosyası veya son alanda kalan bir satır başı karakteri"
+ ],
+ "details": {
+ "sample": "Setteki her dosyanın büyüklüğü. UTF-16 her karakter için iki bayt saklar, bu yüzden tek sayı reddedilir."
+ }
+ },
+ "upload-validation": {
+ "question": "Yükleme formum alması gerekeni alıp geri kalanı reddediyor mu?",
+ "title": "Yükleme doğrulama",
+ "pageTitle": "Yükleme doğrulama test dosyaları - tür, boyut ve ad",
+ "description": "Yükleme formunu test etmek için dosyalar: izinli ve yasaklı türler, uzantıyla uyuşmayan içerik, boyut sınırı, düşmanca adlar ve toplu yükleme.",
+ "catches": [
+ "tarayıcıda uygulanan ama sunucuda uygulanmayan bir sınır",
+ "resim veya düz metin sanılan bir SVG ya da HTML dosyası, yani bir betiği formdan geçirmenin yolu",
+ "uzantısına bakılıp hiç açılmayan bir dosya, böylece .jpg adlı bir PDF geçer",
+ "ne kadar büyük olduğuna bakmadan önce tüm gövdeyi belleğe okuyan bir form",
+ "photo.jpg kabul edilirken reddedilen PHOTO.JPG adlı bir yükleme veya tersi",
+ "boşluk, parantez veya ASCII dışı karakter içeren bir adın diske değişmeden yazılması"
+ ],
+ "details": {
+ "limit": "Yükleme formunuzun bildirdiği boyut sınırı. Bu set her iki yanda birer adım atar - her uzaklıktaki dosya için size-boundaries hazır ayarını çalıştırın.",
+ "allow": "Formunuzun hangi türleri kabul etmesi gerektiği. Her biri o türden gerçek bir dosya olur ve tüm setin pozitif kontrolünü oluşturur.",
+ "deny": "Formunuzun hangi uzantıları reddetmesi gerektiği. Bu sürümde biçimi olmayan bir uzantı yine de o adla, düz metin içeren bir dosya alır.",
+ "far-over": "Tek büyük dosyanın sınırın ne kadar ötesine geçtiği. Sınırın birkaç katını yazmak diske değmiyorsa kapatın.",
+ "bulk": "Toplu yüklemenin kaç dosya içerdiği. Sıfır, bu grubu setten tamamen çıkarır."
+ }
+ }
+ },
+ "commands": {
+ "generate": "tariften veya bayraklardan dosya üret",
+ "validate": "bir tarifi denetle, hiçbir şey yazma",
+ "verify": "bir dizini bir manifeste göre denetle",
+ "cleanup": "bir manifestin listelediği dosyaları sil",
+ "recipe fmt": "bir tarifi oturmuş biçiminde yazdır",
+ "preset": "adlandırılmış bir test sorusundan dosya seti oluştur",
+ "formats": "bu sürümün desteklediği biçimleri listele",
+ "damage": "bu sürümün bir dosyayı kasıtlı bozma yollarını listele",
+ "tool": "elinizdeki dosyalar için küçük araçlar",
+ "version": "araç sürümünü yazdır",
+ "license": "lisansı ve üretilen dosyalar için anlamını yazdır"
+ },
+ "outcomes": {
+ "accept": "Sisteminiz dosyayı kabul etmeli.",
+ "reject": "Sisteminiz dosyayı reddetmeli.",
+ "sanitize": "Sisteminiz dosyayı kabul edip temizlemeli, örneğin yeniden adlandırarak.",
+ "unspecified": "Sisteminizin kurallarına bağlı. Siz karar verirsiniz, sonra olanın amaçladığınız şey olduğunu doğrularsınız."
+ },
+ "damages": {
+ "zero-head": "Dosyanın ilk baytlarını uzunluğuna dokunmadan sıfırlarla ezer. Okuyucuların çoğu önce oraya bakar, bu yüzden hemen her şey bu hasarı fark eder."
+ },
+ "terms": {
+ "oracleNone": "uygulanamaz",
+ "int": "herhangi bir tam sayı",
+ "choice": "sabit bir kümeden biri",
+ "bool": "doğru veya yanlış",
+ "size": "2mb gibi bir boyut",
+ "text": "metin",
+ "pixels": "piksel",
+ "paragraphs": "paragraf",
+ "rows": "satır",
+ "columns": "sütun",
+ "slides": "slayt",
+ "hertz": "hertz",
+ "megapixels": "megapiksel",
+ "million cells": "milyon hücre",
+ "entries per second": "saniyedeki girdi",
+ "files": "dosya",
+ "sizes separated by commas": "virgülle ayrılmış boyutlar",
+ "format ids separated by commas": "virgülle ayrılmış biçim kimlikleri",
+ "format ids separated by commas, or all": "virgülle ayrılmış biçim kimlikleri veya all",
+ "extensions separated by commas": "virgülle ayrılmış uzantılar",
+ "the id of a format, as tfg formats lists them": "tfg formats'ın listelediği gibi bir biçimin kimliği",
+ "the password, in plain text": "parola, düz metin olarak",
+ "any text": "herhangi bir metin",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "2024-02-29 veya 2024-02-29T13:45:00+02:00 gibi bir tarih, veya none"
+ },
+ "faq": [
+ {
+ "q": "dd, fsutil veya truncate'ten farkı nedir?",
+ "a": "Onlar size doğru boyutta, içi bomboş bir dosya verir. Bu şekilde yapılmış photo.png adlı 2 MB'lık bir dosya PNG değildir, bu yüzden onu gerçekten ayrıştıran her şey yanlış nedenle reddeder ve testiniz de yanlış nedenle geçer. Bu araç tam 2 MB'lık gerçek bir PNG üretir, resim görüntüleyicide açılır ve sisteminizin onu nasıl ele alması gerektiğine dair bir bildirimle gelir.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "Ücretsiz mi, ve işte kullanabilir miyim?",
+ "a": "İkisi de evet. GPL-3.0 altında yayımlanır ve hiçbir şeye mal olmaz. Hesap, lisans anahtarı veya ücretli katman yoktur."
+ },
+ {
+ "q": "Üretilen dosyaları kapalı kaynaklı bir üründe kullanabilir miyim?",
+ "a": "Evet. Lisans aracın kodunu kapsar, aracın ürettiğini değil. Üretilen dosyalar, tarifler ve manifestler türev eser değil çıktıdır, bu yüzden hiçbir yükümlülük olmadan commit edip dağıtabilirsiniz."
+ },
+ {
+ "q": "Üretilen dosyalar gerçek kişisel veri içeriyor mu?",
+ "a": "Hayır. İçindeki her şey bir seed'den sentezlenir. Hiçbir veri kümesi okunmaz, hiçbir servise bağlanılmaz ve üçüncü taraf içeriği gömülmez. Üretilmiş bir e-posta adresini kullanılmamış değil kullanılamaz sayın, çünkü rastgele bir dize tesadüfen gerçek biriyle çakışabilir."
+ },
+ {
+ "q": "Başka bir makinede tam olarak aynı dosyaları alır mıyım?",
+ "a": "Evet, aynı tarif ve aynı seed ile bayt bayt. Proje bunu her değişiklikte test eder ve bozmak büyük sürüm artışı gerektirir. Büyük ikili fixture'lar yerine küçük bir tarifi commit etmenizi sağlayan da budur."
+ },
+ {
+ "q": "İnternet bağlantısı gerekiyor mu?",
+ "a": "Asla. Telemetri, güncelleme denetimi veya bulut istemcisi yoktur ve komut satırı ikilisinin içine hiç ağ yığını derlenmemiştir. Ağı olmayan bir makinede ve kapalı bir kurumsal ortamda çalışır."
+ },
+ {
+ "q": "Bir biçimin ulaşamayacağı bir boyut istersem ne olur?",
+ "a": "Biçimi, olabilecek en küçük boyutu, bu alt sınırın nedenini ve bunun yerine ne yapılacağını söyleyen bir hata alırsınız ve hiçbir dosya yazılmaz. Araç bir boyutu asla sessizce yuvarlamaz. Her alt sınır biçimler sayfasında listelenir.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "Kasıtlı olarak bozuk bir dosya üretebilir miyim?",
+ "a": "Evet. --damage zero-head ekleyin, dosya tam istediğiniz boyutta ve ilk baytları sıfırlarla ezilmiş olarak çıkar. Böylece bir okuyucu onu reddeder ve bildirim sisteminizin onu reddetmesi gerektiğini söyler. Ayrıntılar bozuk test dosyaları sayfasındadır.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "Sırada hangi biçimler var?",
+ "a": "7z, mp3 ve mp4. Bugün {{ .Facts.FormatCount }} biçim uçtan uca çalışıyor."
+ },
+ {
+ "q": "Hangi sistemlerde çalıştırabilirim?",
+ "a": "Komut satırı Windows ve Linux'ta hem Intel hem ARM üzerinde, ayrıca Apple Silicon Mac'lerde çalışır. Masaüstü penceresi Intel üzerinde Windows, Intel üzerinde Linux ve Apple Silicon Mac'ler için sunulur. Intel Mac'ler desteklenmez ve onlar için hiçbir şey derlenmez."
+ },
+ {
+ "q": "Bir şey kurmam gerekiyor mu?",
+ "a": "Hayır. Sisteminiz için arşivi indirin, açın ve ikiliyi çalıştırın. Yükleyici, eklenecek bir çalışma zamanı veya çözülecek bir bağımlılık yoktur. Go'nuz varsa tek bir go install komutu da işe yarar.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "Binlerce dosya üzerindeki çalıştırma Windows'ta neden daha yavaş?",
+ "a": "Çünkü Windows baktığı her yol için daha fazla bedel ister ve binlerce dosyayı dolaşan bir komut binlerce yola bakar. Her biri 1 kB'lık 3000 dosyalı bir makinede ölçüldü: verify Windows'ta yaklaşık 0,9 saniye, bir konteynerdeki Linux'ta yaklaşık 0,2 saniye sürer. Daha kısa bir çıktı yolu Windows rakamını küçültür, çünkü dosyaların üstündeki her klasör bakılanın parçasıdır."
+ }
+ ]
+}
diff --git a/web/content/tr/use-cases.html b/web/content/tr/use-cases.html
new file mode 100644
index 00000000..8ca45544
--- /dev/null
+++ b/web/content/tr/use-cases.html
@@ -0,0 +1,131 @@
+
İnsanlar bunu ne için kullanıyor
+
+ İnsanlardan dosya kabul eden hemen her projede çıkan beş iş ve her birini yapan komut. Aşağıdaki her
+ örnek yazıldığı gibi çalışır.
+
+
+
+
Yükleme sınırları
+
Bir dosya boyutu sınırının söylediği yerde uygulanıp uygulanmadığını test etmek
+
+ Bir sınır bir değil üç test durumudur: hemen altı, tam üstü ve hemen üzeri. Bunları elle yapmak bayt
+ sayıları hesaplamak ve bir kayma yapmadığınızı ummak demektir. Bunun yerine seti isteyin:
+
+ 1048575, 1048576 ve 1048577 baytlık üç gerçek PDF ve ilk ikisinin kabul edilmesi, üçüncünün
+ size_limit nedeniyle reddedilmesi gerektiğini söyleyen bir manifest alırsınız.
+ Testiniz üç assertion'ı elle yazmanız yerine beklentiyi okur - sınır değiştiğinde bir sayıyı
+ değiştirip yeniden çalıştırırsınız.
+
+
+ Satır içi tek bir sınır seti istediğinizde aynısı hazır ayar olmadan da çalışır:
+
+ Büyük ikili fixture'lar bir depoyu klonlamada yavaş, incelemede zahmetli yapar ve biri
+ değiştirildiğinde neyin değiştiğini kimse söyleyemez. Tarif, özdeş dosyaları yeniden kuran
+ birkaç yüz karakterlik YAML'dir - bayt bayt, her makinede - çünkü her dosya
+ çalıştırmanın seed'inden türetilir.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Her sonun kendi çıkış kodu vardır, bu yüzden bir hat kötü bir tarifi dolu bir diskten ve bir
+ doğrulama uyuşmazlığından ayırt edebilir. Başarısız bir çalıştırma standart çıktıya hiçbir şey
+ yazdırmaz, bu da bir günlük ayrıştırıcısının hatayı veri sanmasını önler.
+
+
+
+
+
Ölçek
+
Klasör büyükken ne olduğunu öğrenmek
+
+ İçe aktarma rutinleri, gece işleri ve dizin listeleri on bin dosyada ona göre farklı davranır. Bir
+ aralıktan çekilen boyutlar seti on bin özdeş dosya yerine gerçek trafiğe benzetir ve çekiliş
+ seed'den gelir, yani set yarın da aynıdır.
+
+ İç içe geçme derinliği, girdi sayıları ve içindekilerin boyutu, bir içe aktarma rutininin görüş
+ sahibi olduğu şeylerdir ve bu görüşlerin ne olduğunu böyle öğrenirsiniz.
+
+
+
+
+
Ayrıştırıcılar ve görüntüleyiciler
+
Kendi kodunuzun bir biçimi gerçek yazılım gibi okuduğunu denetlemek
+
+ Buradaki her biçim yayımlanmadan önce bağımsız bir okuyucuyla doğrulanır - bir PNG açılır ve
+ pikselleri karşılaştırılır, bir DOCX ayrı kitaplıklarca geri okunur, bir arşiv çıkarılır. Bu,
+ ayrıştırıcınızın reddettiği bir dosyanın üretici hakkında değil ayrıştırıcınız hakkında bir
+ bulgu olduğu anlamına gelir.
+
+ Biçimler sayfası her birinin kabul ettiği ayarları ve her birinin
+ olabileceği en küçük dosyayı listeler.
+
+
+
+
+
Rehberler
+
Bunlardan ikisi daha ayrıntılı
+
+
+ Bozuk test dosyaları - kasıtlı bozulmuş, tam boyutta bir
+ dosya ve ona ne olması gerektiği bildirimde yazılı.
+
+
+ CI'da test dosyaları - bir GitHub Actions iş akışı, bir
+ GitLab işi ve derlemeyi başarısız kılan çıkış kodları.
+
+
+
+
+
+
Kimler için
+
+ QA mühendisleri, test otomasyonu ve kodunun arkasında bir yükleme formu, içe aktarma rutini,
+ ayrıştırıcı veya depolama kotası olan herkes. Hiç ağı olmayan bir makinede çalışır, bu da
+ tarayıcı tabanlı bir üreticinin seçenek olmadığı kapalı bir kurumsal ortamda önem taşır.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/uk/ci.html b/web/content/uk/ci.html
new file mode 100644
index 00000000..55b6b25d
--- /dev/null
+++ b/web/content/uk/ci.html
@@ -0,0 +1,190 @@
+{{ with .Up }}
+ Двійкова фікстура в репозиторії лишається в його історії назавжди, її не можна перевірити в діфі, і
+ вона перестає бути можливою, коли файл великий. Генеруйте файли всередині конвеєра з рецепта.
+ Рецепт - це текст, байти щоразу виходять однакові, а останній крок доводить, що нічого не
+ зсунулося.
+
+
+
+
Коротка відповідь
+
+ Установіть tfg, запустіть tfg generate fixtures.yaml --out ./fixtures
+ перед тестами і tfg verify ./fixtures/manifest.json після них. Обидва кроки самі
+ валять збірку, з кодом завершення, який каже чому.
+
+
+
+
+
Чому не комітити
+
Чому фікстурі не місце в репозиторії
+
+
+ Вона лишається в історії. Видалення двійкового файлу пізніше не робить клон меншим,
+ бо кожна його версія все ще там.
+
+
+ Діф не показує, що змінилося. Рецензент бачить, що PDF інший, і нічого більше.
+ Рецепт змінюється на один рядок.
+
+
+ Великі файли не вміщаються. GitHub відхиляє push, у якому є файл більший за 100 МБ,
+ тож тесту ліміту завантаження в 500 МБ нічого комітити.
+
+
+
+ Комітити потрібно рецепт. Той самий рецепт із тим самим зерном записує ті самі байти на будь-якій
+ машині, тож файл, створений у конвеєрі, - це файл, який був у вас на ноутбуці.
+
+
+
+
+
Рецепт
+
Рецепт, що лежить поруч із тестами
+
+ Цей записує двадцять п'ять рахунків, які мають бути прийняті, і два зображення понад ліміт, які
+ мають бути відхилені, а маніфест фіксує обидва очікування:
+
+ Рядок із контрольною сумою звіряє архів із verify-SHA256SUMS.txt з того самого випуску.
+ Версію закріплено, тож новий випуск ніколи не змінить збірку, якої ви не торкалися.
+
+ У кожного завершення свій код, тож крок падає сам, а журнал каже, який саме. Ті, що трапляються
+ конвеєру:
+
+
+
3 - рецепт недопустимий. Нічого не записано, і названо кожну проблему
+
4 - формат не вміє того, про що попросили, наприклад розміру менше за свій мінімум
+
6 - не вистачає місця на диску
+
7 - tfg verify знайшов файл, що не збігається зі своїм маніфестом
+
8 - запуск закінчився, але створено не все
+
+
+ Невдалий запуск нічого не друкує у стандартний вивід, тож розбирач журналів ніколи не сприйме
+ помилку за дані. Уся таблиця на сторінці документації.
+
+
+
+
+
PowerShell
+
Скрипту PowerShell потрібен ще один рядок
+
+ PowerShell не виносить код завершення програми з файлу .ps1. Запустіть такий файл із
+ -File, і скрипт відповість 0, навіть коли інструмент усередині
+ відмовився працювати, тож збірка, яка мала б бути червоною, стає зеленою. Останній рядок - це
+ все виправлення:
+
+ Так поводиться PowerShell, а не цей інструмент. cmd, bash і
+ zsh нічого зайвого не потребують.
+
+
+
+
+
Кілька завдань
+
Як ділитися фікстурами між завданнями
+
+ Зазвичай завантажувати їх не треба. Оскільки той самий рецепт записує ті самі байти, кожне завдання
+ може запустити власний tfg generate, що швидше за завантаження й скачування. Коли
+ завдання має отримати файли від іншого, запустіть після передачі tfg verify на
+ маніфесті, і він скаже, чи збігається отримане із записаним.
+
+ Валідатор, якому показували лише здорові файли, насправді не перевірений. Ось як отримати файл,
+ навмисно зіпсований, що виходить точно такого розміру, який ви просите, і несе
+ маніфест із вказівкою, що ваша система має з ним зробити.
+
+
+
+
Коротка відповідь
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out записує PNG рівно в
+ 2097152 байти, перші байти якого нулі, а маніфест поруч фіксує, що ваша система має його
+ відхилити.
+
+
+
+
+
Звичайний шлях
+
Чому файл, зіпсований вручну, - поганий тест
+
+ Зазвичай беруть шістнадцятковий редактор, скрипт, що перевертає кілька випадкових байтів, або
+ вкорочують файл через head чи truncate. Один раз це працює, а потім
+ коштує дорого:
+
+
+
+ Щоразу по-різному. Випадковий байт при кожному запуску потрапляє в нове місце, тому
+ збій у вівторок у середу може не повторитися.
+
+
+ Змінюється розмір. Обрізаний файл менший за ліміт, під яким він мав залишатися,
+ тому перевірка розміру відповідає раніше за перевірку вмісту, і тест проходить із неправильної
+ причини.
+
+
+ Це часто лишається непоміченим. Простий текст читається і зі зміненим байтом
+ посередині, а поблажлива програма читання зображень просто малює його, тож файл, який мав бути
+ зіпсований, приймається.
+
+
+ Не сказано, що має статися. Файл - це лише байти, і тому, хто читатиме тест
+ пізніше, доведеться гадати, чи йшлося про прийняття, чи про відхилення.
+
+
+
+
+
+
Що ви отримуєте
+
Пошкоджений файл лишається потрібного розміру
+
+ Файл створюється як зазвичай і псується потім, дорогою на диск. Він зберігає заданий розмір, а та
+ сама команда знову записує ті самі байти.
+
+ Налаштування пишуться після двокрапки. Параметр можна повторювати, а пошкодження застосовуються в
+ тому порядку, в якому ви їх записали. Це працює з кожним із {{ .Facts.FormatCount }} форматів.
+
+
+
+
+
Що він уміє
+
Які бувають пошкодження?
+
+ Це список, який друкує програма, прочитаний із неї під час збирання цієї сторінки. tfg
+ damage друкує той самий список, а tfg damage <id> каже, що приймає
+ одне з них.
+
+ {{ template "damagesTable" . }}
+
+ zero-head записує нулі поверх початку файлу. Більшість програм читання дивляться
+ спочатку туди, на сигнатуру й заголовок, які кажуть, що це за файл, тому помічає майже будь-яка.
+ У простого тексту та журналів сигнатури немає, і їх теж відхиляють, бо послідовність нульових
+ байтів не є текстом. Менше ніж чотири байти - і в деяких форматів виходить пошкодження, на яке
+ не скаржиться жодна програма читання, тому налаштування починається з чотирьох.
+
+
+
+
+
Що каже маніфест
+
Маніфест, який каже, що має статися
+
+ Кожен пошкоджений файл отримує запис про те, що ваша система має його відхилити, а поруч записано
+ пошкодження:
+
+ Два запити відхиляються, перш ніж щось буде записано, бо кожен залишив би на диску файл, який
+ маніфест описує хибно:
+
+
+
файл менший, ніж потрібно пошкодженню, який вийшов би недоторканим
+
+ expected: accept поруч із пошкодженням, бо ніщо не могло б цього виконати. Напишіть
+ sanitize, якщо ваша система має полагодити файл, або unspecified,
+ якщо саме це ви й перевіряєте
+
+
+
+
+
+
У рецепті
+
Здорові й зламані файли за один запуск
+
+ Покладіть обидва види в один рецепт, і маніфест несе очікування для кожного файлу, тож тесту не
+ потрібен список, який файл який:
+
+ Тест читає маніфест і перевіряє, що сталося те, що було заявлено. Список імен файлів йому не
+ потрібен:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Гарна відмова - це чиста відмова. Повідомлення, що каже, що було не так, - та відповідь, яка вам
+ потрібна. Помилка сервера, зависання або наполовину збережений файл - той дефект, заради якого
+ цей тест і існує.
+
+ Документація містить кожен параметр tfg generate.
+
+
+
diff --git a/web/content/uk/docs.html b/web/content/uk/docs.html
new file mode 100644
index 00000000..f4ca7b7b
--- /dev/null
+++ b/web/content/uk/docs.html
@@ -0,0 +1,280 @@
+
Документація
+
+ Усе, що робить інструмент, розкладено за питаннями, з якими люди справді приходять.
+ README у репозиторії - повний довідник, і він завжди відповідає
+ завантаженій вами збірці.
+
+
+
+
Які є команди?
+
Кожна робить одну справу:
+ {{ template "commandList" . }}
+
+
+
+
Як створити один файл точного розміру?
+
+ Укажіть формат, розмір і місце призначення. Розміри рахуються по 1024, тому 2mb - це
+ 2097152 байти. Підійде й просте число байтів, тож --size 10485761 запитує рівно
+ стільки.
+
+
tfg generate --format png --size 2mb --out ./out
+
Корисні прапорці команди generate:
+
+
+
Прапорець
Що робить
+
+
--format <id>
формат файлів, наприклад txt
+
--size <size>
точний розмір кожного файлу, наприклад 10mb або просте число байтів
+
--size-range <a-b>
розмір, що вибирається для кожного файлу з діапазону, наприклад 1kb-8kb. Вибір іде від seed
+
--boundary <size>
три файли навколо ліміту: на байт менше, сам ліміт, на байт більше
+
--count <n>
скільки файлів створити. За замовчуванням 1
+
--name <template>
шаблон імені, наприклад invoice_{index:04}.txt
+
--out <dir>
каталог, у який записувати
+
--seed <n>
seed запуску. Той самий seed дає ті самі байти
+
--set <k>=<v>
налаштування формату, можна повторювати
+
--damage <name>
навмисно зіпсувати файли, можна повторювати, застосовується по порядку. Список виводить tfg damage
+
--expected <outcome>
accept, reject, sanitize або unspecified
+
--dry-run
порахувати й показати, нічого не записуючи
+
--json
записати маніфест у стандартний вивід
+
+
+
+
+
+
+
Як зробити навмисно зламаний файл?
+
+ Будь-який інший файл, що його записує цей інструмент, коректний за побудовою, і це відповідає на два
+ з трьох питань, які ставить перевірка завантаження. --damage відповідає на третє -
+ чи відкривається файл узагалі. Файл створюється як зазвичай, а потім псується, тому в нього
+ лишається запитаний розмір.
+
+ Налаштування вказуються після двокрапки. Прапорець можна повторювати, і порядок запису - це порядок
+ застосування. tfg damage перелічує, що вміє ця збірка та що приймає кожен вид
+ пошкодження.
+
+ Пошкоджений файл отримує в маніфесті expected: reject із записаним поруч пошкодженням.
+ Дві речі відхиляються до запису чого-небудь, бо кожна залишила б на диску файл, неправильно
+ описаний маніфестом:
+
+
+
файл менший, ніж потрібно пошкодженню, бо він вийшов би без змін
+
+ expected: accept поруч із пошкодженням, бо цьому не міг би відповідати жоден файл.
+ Пишіть sanitize, якщо тестована система має полагодити файл, або
+ unspecified, якщо саме це питання ви й ставите
+
+
+
+ Третє наперед дізнатися не можна. Якщо пошкодження виконується й не змінює жодного байта, такий файл
+ відкидається, а не записується - запуск триває, повідомляє, що це був за файл, і завершується
+ кодом часткового завершення.
+
+ Рецепт - це файл YAML, що описує цілий запуск. Закомітьте його поряд із тестами, і фікстури
+ перестануть бути бінарними файлами у вашому репозиторії - будь-хто зможе відтворити їх байт у
+ байт із файлу в кілька сотень символів.
+
+ Кожній цілі потрібен рівно один із ключів size, size-range,
+ boundary або contains. Два - це помилка, і жодного - теж. Недійсний
+ рецепт записує жодного файлу і повідомляє про всі проблеми одразу, а не лише
+ про першу, щоразу називаючи налаштування, якого вона стосується.
+
+
+
+
+
Як оголосити, що моя система має робити з файлом?
+
Коротка форма, коли досить результату, і довга, коли важлива причина:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Результати - accept, reject, sanitize і
+ unspecified. Причини утворюють закритий список, щоб звіт міг за ними групувати:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit і size_zero.
+
+
+ Причина називає чинне правило, а не вердикт. Тому та сама причина може стояти під
+ будь-яким результатом - файл на байт менший за ліміт отримує accept, а правило, про
+ яке йдеться, усе одно size_limit.
+
+
+
+
+
Що в маніфесті?
+
+ Він записується поряд із файлами наприкінці кожного запуску, зокрема й перерваного. Один запис на
+ файл:
+
+ recipe_hash додається, якщо запуск був за рецептом, а preset з
+ overrides - якщо за пресетом, тож маніфест завжди можна простежити до того, що його
+ створило.
+
+
+ Кожен запис також містить target_id - id цілі рецепта, що створила файл, а
+ summary.by_target рахує файли кожної цілі. Рецепт із кількома цілями можна тому
+ перевірити ціль за ціллю, не читаючи імена файлів.
+
+
+
+
+
Що таке пресет?
+
+ Готовий набір файлів, що відповідає на поширене тестове питання, щоб вам не доводилося проєктувати
+ набір самостійно. Пресети - звичайні рецепти всередині, а eject виводить рецепт,
+ щоб ви могли його відредагувати. Кожен пресет має окрему сторінку про
+ те, що він зазвичай знаходить, що входить у набір і які налаштування приймає.
+
+ show повідомляє, скільки коштував би набір, перш ніж ви його зберете, і прямо каже,
+ коли число - наша тимчасова підстановка, а не ваш ліміт.
+
+
+
+
+
Що означають коди завершення?
+
+ Кожен кінець має власний код, машиночитний вивід іде в стандартний вивід, а невдалий запуск нічого
+ туди не друкує. Таблиця - заморожений контракт: зміна значення коду вимагає підвищення мажорної
+ версії.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Запуск, зупинений за допомогою Ctrl+C, усе одно залишає маніфест і ніколи не залишає наполовину
+ записаного файлу, тож скасоване завдання може бути прибране наступним.
+
+ Так, той самий рушій із вікном згори, для тестування, яке не автоматизується. Це не урізана версія:
+ тест порівнює два інтерфейси можливість за можливістю, і все, що вміє лише один із них, має бути
+ оголошене й обґрунтоване, а не тихо розходитися.
+
+
+ Екрани: одна партія, пресети, кілька партій одночасно та про програму. Вікно показує, скільки
+ коштував би запуск, перш ніж щось записати, відображає перебіг роботи й може бути скасоване на
+ півдорозі без наполовину записаного файлу. Файл рецепта воно поки не відкриває - рецепти поки
+ справа командного рядка, а вікно збирає свої партії у формі.
+
+
diff --git a/web/content/uk/exact-size.html b/web/content/uk/exact-size.html
new file mode 100644
index 00000000..aaba5286
--- /dev/null
+++ b/web/content/uk/exact-size.html
@@ -0,0 +1,146 @@
+
Як створити файл точного розміру
+
+ У кожній системі для цього є команда, і всі три наведено нижче. Вони дають файл із точною кількістю
+ байтів, а для багатьох тестів цього досить. Кожну команду на цій сторінці було виконано до
+ публікації у тій системі, до якої вона належить.
+
+
+
+
Коротка відповідь
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Розміри вказуються в байтах, а 10
+ МБ, пораховані так, як рахує ваш файловий менеджер, - це 10485760.
+
+
+
+
+
Windows
+
fsutil і варіант на PowerShell, якому не потрібно нічого додаткового
+
+ fsutil входить до Windows. Він приймає розмір у байтах, тому спершу
+ порахуйте число: 10 МБ - це 10485760, 100 МБ - 104857600, 1 ГБ - 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Виміряно у Windows 11: працює зі звичайного командного рядка без підвищених прав, і файл виходить
+ рівно в 10485760 байт.
+
+
PowerShell може зробити те саме, не викликаючи іншу програму, і розуміє одиниці:
+ 10MB у PowerShell означає 10485760 байт, той самий рахунок за основою 1024, що його
+ використовує Провідник, тому дві команди вище дають той самий розмір.
+
+
+
+
+
Linux
+
dd, truncate і fallocate, і різниця, що ловить людей
+
dd знають усі. Він справді записує байти:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate спрацьовує миттєво, і в цьому підступ. Виміряно в Alpine Linux: файл
+ повідомляє 10485760 байт і займає нуль блоків - це розріджений
+ файл. Усе, що його читає, отримує десять мегабайт нулів, але диск місця так і не
+ віддав:
+
+
truncate -s 10M test10mb.bin
+
+ Для перевірки ліміту завантаження це нормально, а для перевірки дискової квоти вводить в оману.
+ fallocate - те, до чого варто вдатися, коли місце має бути справжнім:
+
+
fallocate -l 10M test10mb.bin
+
А коли вміст має бути нестисливим, щоб архіватор не міг знову його стиснути:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, що не є розрідженим, і дві команди, які ви вже знаєте
+
+ У macOS є mkfile. Виміряно в macOS 26.6.2: 10485760 байт і 20480 блоків, тобто місце
+ справді виділено, а не обіцяно:
+
Файл правильного розміру - не файл правильного виду
+
+ Усе сказане вище дає блок нулів. Цього досить, коли тестоване дивиться лише на розмір: ліміт
+ завантаження, квота, передача. Цього перестає вистачати, щойно щось відкриває
+ файл.
+
+
+ Виміряно, і варто перевірити самому: зробіть файл на 2 МБ командою fsutil, назвіть його
+ photo.png і передайте бібліотеці роботи із зображеннями. Pillow відповість
+ cannot identify image file. Це не PNG. Він ним ніколи й не був, так казало лише
+ ім'я.
+
+
+ Це важливіше, ніж здається, через те, в який бік тест тоді провалюється. Ваша точка
+ завантаження відхиляє файл, ваш тест зеленіє, і ви робите висновок, що ліміт розміру працює.
+ Вона відхилила його не через розмір. Вона відхилила його тому, що байти не були зображенням, і
+ правило, яке ви хотіли перевірити, так і не було досягнуте.
+
+
+
парсер відхиляє його, не дійшовши до жодних правил розміру
+
крок створення мініатюри падає, і помилка, яку ви читаєте, стосується мініатюри
+
антивірус чи перевірка вмісту відхиляє його з третьої причини
+
переглядач нічого не показує, і ніхто не може сказати, чи в цьому помилка
+
+
+
+
+
Інший шлях
+
Справжній файл цього формату точно того розміру, який ви запросили
+
+ Саме це робить Testing Files Generator. Файл - справжній файл свого формату, він відкривається у
+ своїй програмі, і в ньому рівно стільки байтів, скільки ви запросили, з точністю до байта:
+
+ Запросіть розмір, якого формат не може досягти, і ви отримаєте помилку з назвою мінімуму та
+ причиною, а не файл неправильного розміру. Сторінка форматів
+ перелічує кожен формат з найменшим файлом, який він може створити.
+
+
А ліміт - це три тестові випадки, а не один, тому інструмент збирає всі три:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Ви отримаєте 10485759, 10485760 і 10485761 байт та маніфест, що каже, які з них ваша система має
+ прийняти, а які відхилити. Сторінка сценаріїв розбирає це та ще
+ чотири завдання, для яких інструмент створений.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Тож що використовувати?
+
+
+
Використовуйте системну команду
+
+ Коли ніщо не відкриває файл. Перевірка ліміту розміру на точці, що спершу дивиться розмір, передача,
+ квота, переповнення диска. Це один рядок, і він уже встановлений.
+
+
+
+
Використовуйте справжній генератор
+
+ Коли будь-що розбирає, відображає, імпортує чи розпаковує файл - і коли завтра на іншій машині
+ потрібні ті самі фікстури, байт у байт.
+
+
+
+
+ Обидві є на цій сторінці, бо обидві бувають слушними. Помилка, якої слід уникати, - використати
+ першу там, де потрібна друга, і сприйняти зелений тест за доказ.
+
+
diff --git a/web/content/uk/faq.html b/web/content/uk/faq.html
new file mode 100644
index 00000000..4cfe81f6
--- /dev/null
+++ b/web/content/uk/faq.html
@@ -0,0 +1,19 @@
+
Часті запитання
+
+ Ліцензія, приватність, відтворюваність і те, що люди перевіряють, перш ніж додавати генератор до
+ конвеєра збірки. Якщо вашого питання тут немає, трекер задач
+ відкритий.
+
{{ .Facts.FormatCount }} форматів файлів, кожен створюється точного розміру
+
+ Кожен із них - справжній файл цього формату. Він відкривається у своїй програмі та
+ має рівно стільки байтів, скільки ви запросили. Жоден не є нулями-заповнювачами з приклеєним
+ розширенням.
+
+
+{{ template "formatsTable" . }}
+
+
+
Що означають стовпці
+
+
+
Найменший файл
+
+ Найменша кількість байтів, яку цей інструмент приймає для формату, разом із позначкою, яку він пише
+ всередині файлу. Запросіть менше, і ви отримаєте помилку з назвою мінімуму та причиною, а не
+ файл неправильного розміру.
+
+
+
+
Повнота
+
+ Наскільки повний файл. full означає, що його приймає читач, який по-справжньому
+ розбирає формат, а не просто збігається розширення.
+
+
+
+
Перевіряється за допомогою
+
+ Незалежний читач, що відкриває кожен створений файл до випуску формату, - окрема реалізація, а не
+ наш власний код, що перевіряє власні домашні завдання.
+
+
+
+
+ Кожен формат до того ж повторюється до байта: той самий рецепт і той самий seed дають однакові файли
+ на будь-якій машині, і саме це робить безпечним коміт рецепта замість самих фікстур.
+
+
+
+
+
Налаштування, які приймає кожен формат
+
+ Більшість форматів мають власні налаштування - розміри зображення, якість JPEG, кількість сторінок
+ PDF, рядки й стовпці в таблиці, скільки записів входить в архів. Задайте їх через --set
+ key=value у командному рядку або в розділі properties: рецепта.
+
+ Значення поза допустимим для налаштування відхиляється повідомленням із назвою налаштування,
+ допустимим діапазоном і тим, що використати натомість. Невідоме налаштування теж помилка, а не
+ мовчазне значення за замовчуванням - друкарська помилка, прийнята мовчки, дає файл із хибними
+ налаштуваннями та годину роздумів, чому тест проходить, хоча не мав би.
+
+
+ Виконайте tfg formats <id>, щоб побачити, що саме приймає один формат у вашій
+ збірці.
+
+
+
+
+
Архіви містять справжні файли
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} і {{ end }}{{ $c.ID }}{{ end }}
+ можна наповнити записами, а не лишати порожньою оболонкою. Створений архів справді містить
+ документи, які заявляє, тому все, що розпаковує його під час тесту, знаходить усередині справжні
+ файли.
+
+ PDF, PNG, DOCX, ZIP - усього {{ .Facts.FormatCount }} форматів, і кожен із них -
+ справжній файл, що відкривається у своїй програмі, точно того розміру, який ви
+ запросили. Кожен запуск ще й записує, що ваш застосунок має робити з кожним файлом.
+ Командний рядок і десктопне вікно, безкоштовно та з відкритим кодом, усе працює на вашій машині.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ Десктопне вікно, підготовлене до запису партії файлів. За командним рядком працює той самий рушій.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
справжніх форматів, кожен відкривається у своїй програмі
+
+
+ 1 байт
+
точність кожного запитаного розміру, ніколи не округлюється мовчки
+
+
+ 0
+
з'єднань будь-куди - без облікового запису, без телеметрії, без перевірки оновлень
+
+
+
+
+
Проблема
+
Зробити один тестовий файл легко. Зробити потрібну тисячу - ось виснажлива частина
+
Ви тестуєте програму, що приймає файли від людей. Рано чи пізно вам знадобляться:
+
+
PDF рівно на 10 МБ, щоб з'ясувати, чи реальний ліміт завантаження
+
три файли по обидва боки цього ліміту, щоб упіймати помилки на одиницю
+
10 000 файлів журналу, щоб побачити, що робить нічне завдання, коли тека велика
+
ZIP, який справді містить 200 документів, а не порожню оболонку з правильним розширенням
+
файл на 4 ГБ без зберігання файлу на 4 ГБ у вашому репозиторії
+
однакові фікстури на ноутбуці та на сервері збірки, байт у байт
+
+
+ Саме це він замінює. Він створений для QA-інженерів, автоматизації тестування та всіх, за чиїм кодом
+ стоїть форма завантаження, процедура імпорту, парсер чи квота сховища.
+
+
+
+
+
Чим він відрізняється
+
Інші генератори зупиняються на байтах. Цей відповідає на те, про що насправді питає ваш тест
+
+ Тека з файлами все одно залишає вам вирішувати, що має доводити кожен із них. Кожен запуск тут
+ записує поряд із файлами manifest.json - простий перелік усього створеного та для
+ кожного запису заявлене очікування.
+
+
Припустімо, ваша точка завантаження допускає 1 МБ. Запросіть три файли, що лежать на цій межі:
Там, де відповідь залежить від вашої власної політики, маніфест так і каже
+
+ Він записує unspecified, а не вигадує очікування. Генератор, що вгадує, дає хибні збої,
+ а набір тестів, що кричить «вовки», зрештою вимикають.
+
+
+
+
+
+
Пресети
+
Виберіть питання, отримайте весь набір
+
+ Пресет - це набір тестових файлів, продуманий навколо одного тестового питання, щоб вам не довелося
+ з'ясовувати, які файли що доводять. Кожен має сторінку про те, що він зазвичай знаходить, що
+ входить у набір і які налаштування приймає.
+
+ Десять тисяч файлів журналу, кожен від одного до восьми кілобайтів, з розмірами з seed, щоб завтра
+ вийшов той самий набір. Давайте кожному запуску власний каталог - маніфест
+ лишається єдиним записом про те, що записав запуск, тому інструмент відмовляється записувати
+ другий поверх нього:
+
+ Розміри рахуються по 1024, як у вашому файловому менеджері, тому 2mb означає 2097152
+ байти. Підійде й просте число байтів. Документація охоплює рецепти,
+ маніфест і коди завершення.
+
+
+
+
+
Що ви отримуєте
+
Створений для набору тестів, що працює без нагляду
+
+
+
Точний розмір, до байта
+
Запросіть 10485761 байт і отримайте рівно стільки. Розмір, якого формат не може досягти, - це помилка з причиною, а не файл неправильного розміру.
+
+
+
{{ .Facts.FormatCount }} справжніх форматів
+
Не нулі-заповнювачі з розширенням. Створений PNG відкривається в переглядачі зображень, DOCX - у Word, ZIP розпаковується. Кожен формат перевіряється незалежними читачами до випуску.
+
+
+
Маніфест, що править за тестовий оракул
+
Шлях, розмір, SHA-256, формат, seed, версія інструмента - і те, що ваша система має зробити з файлом.
+
+
+
Відтворюваність
+
Той самий рецепт і той самий seed, ті самі байти на будь-якій машині. Комітьте невеликий рецепт YAML замість великих бінарних фікстур.
+
+
+
Два інтерфейси, один рушій
+
Командний рядок, створений для CI, і десктопне вікно для дослідницького тестування. Жоден не є урізаною версією іншого, і тест порівнює їх можливість за можливістю.
+
+
+
Повністю офлайн
+
Немає облікового запису, хмари, телеметрії та перевірки оновлень. У бінарний файл командного рядка взагалі не скомпільовано мережевий стек.
+
+
+
+
+
+
Завантаження
+
Виберіть збірку для вашої системи
+
+ Розпакуйте архів і запустіть. tfg - це командний рядок, а tfg-gui -
+ десктопне вікно. Немає інсталятора й нічого, що треба додавати на вашу машину.
+
+ {{ template "downloadsTable" . }}
+
+
Що підписано, а що ні
+
+ Збірки для Windows і macOS підписані, тому запускаються без попередження про невідомого розробника.
+ Збірки для Linux не підписані, бо в десктопного Linux немає еквівалента, яким їх можна
+ підписати. Кожен архів указано в verify-SHA256SUMS.txt на сторінці релізу, тож ви
+ можете перевірити, що завантажили.
+
+ Пресет {{ .ID }} однією командою збирає цілий набір справжніх тестових файлів для цього
+ питання та поруч manifest.json з очікуваною реакцією вашої системи на кожен файл. Усе
+ нижче прочитано з програми зі значеннями за замовчуванням цієї версії.
+
+
+{{ if .Catches }}
+
+
Що він зазвичай знаходить?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
Що входить у набір?
+
Зі значеннями за замовчуванням, як повідомляє tfg preset show {{ .ID }}:
+
+
+
+
Файлів
{{ .Budget.Files }}
+
Цілей у його рецепті
{{ .Budget.Targets }}
+
Загальний розмір
{{ .Bytes }} B
+
Формати
{{ join .Budget.Formats ", " }}
+
+
+
+
І чого маніфест цього набору очікує від вашої системи:
+
+
+
+
Очікується
Значення
Файлів
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
Що можна змінити?
+ {{- if .Settings }}
+
+
+
+
Налаштування
Приймає
За замовчуванням
Що робить
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Це значення за замовчуванням - наша тимчасова підстановка, а не значення вашої системи. Передайте своє.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
Цей пресет не має налаштувань. Набір щоразу однаковий.
+ {{- end }}
+
+
+
+
Як його запустити?
+
Подивіться, скільки коштував би набір, зберіть його або візьміть його рецепт для правки:
Або будуйте на ньому у власному рецепті поряд із тестами:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/uk/presets.html b/web/content/uk/presets.html
new file mode 100644
index 00000000..d34cc763
--- /dev/null
+++ b/web/content/uk/presets.html
@@ -0,0 +1,32 @@
+
Пресети тестових файлів, по набору на кожне тестове питання
+
+ Пресет - це цілий набір тестових файлів, продуманий навколо одного питання, з маніфестом про
+ очікувану реакцію вашої системи на кожен файл. Ви вибираєте питання, інструмент збирає набір.
+ Кожен пресет має власну сторінку про те, що він зазвичай знаходить, що входить у набір і які
+ налаштування приймає.
+
+
+{{ template "presetsList" . }}
+
+
+
Чим пресет відрізняється від рецепта?
+
+ По суті нічим. Пресет - це рецепт, який інструмент пише для вас із кількох налаштувань. tfg
+ preset eject виводить цей рецепт, щоб ви могли зберігати його поряд із тестами й
+ редагувати, а ваш власний рецепт може спиратися на пресет одним рядком: extends:
+ preset: і його id.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Чи можна довіряти значенням за замовчуванням?
+
+ Для файлів - так. Для числа, яке знає лише ваша система, як-от ліміту форми завантаження, значення
+ за замовчуванням - наша тимчасова підстановка, і інструмент каже про це щоразу, коли її
+ використовує. Сторінка кожного пресета позначає такі налаштування, а tfg preset
+ show повідомляє про це до запису чого-небудь.
+
+
diff --git a/web/content/uk/site.json b/web/content/uk/site.json
new file mode 100644
index 00000000..b3752144
--- /dev/null
+++ b/web/content/uk/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "uk",
+ "locale": "uk_UA",
+ "name": "Українська",
+ "dir": "uk",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Головна",
+ "title": "Генератор тестових файлів для QA - точний розмір, {{ .Facts.FormatCount }} форматів",
+ "description": "Безкоштовний генератор тестових файлів для QA з відкритим кодом. Справжні PDF, DOCX, PNG і ZIP точного розміру та маніфест з очікуваною реакцією вашої системи."
+ },
+ {
+ "key": "formats",
+ "slug": "formats",
+ "nav": "Формати",
+ "title": "{{ .Facts.FormatCount }} форматів файлів - PDF, DOCX, PNG, ZIP та інші",
+ "description": "Усі формати, які створює генератор, найменший можливий файл кожного та допустимі налаштування. Усі {{ .Facts.FormatCount }} відкриваються у своїх програмах."
+ },
+ {
+ "key": "presets",
+ "slug": "presets",
+ "nav": "Пресети",
+ "title": "Пресети тестових файлів - готові набори для QA",
+ "description": "Готові набори тестових файлів, кожен відповідає на одне питання: ліміти завантаження, імена файлів, кодування, імпорт таблиць, порожні файли та перевірка завантаження."
+ },
+ {
+ "key": "docs",
+ "slug": "docs",
+ "nav": "Документація",
+ "title": "Документація - команди, рецепти, маніфест, коди завершення",
+ "description": "Як створювати тестові файли з командного рядка чи рецепта YAML, що містить маніфест і що означає кожен код завершення під час запуску в CI."
+ },
+ {
+ "key": "use-cases",
+ "slug": "use-cases",
+ "nav": "Сценарії",
+ "title": "Сценарії - ліміти завантаження, фікстури для CI, масові тести",
+ "description": "Перевірка ліміту розміру завантаження, відтворювані фікстури для CI, десять тисяч файлів за один запуск і архіви зі справжнім вмістом."
+ },
+ {
+ "key": "exact-size",
+ "slug": "create-file-exact-size",
+ "nav": "Точний розмір",
+ "title": "Як створити файл точного розміру - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate і mkfile, кожну команду виміряно у своїй системі, і чому такий файл не є PDF чи PNG, коли тесту потрібен справжній."
+ },
+ {
+ "key": "faq",
+ "slug": "faq",
+ "nav": "FAQ",
+ "title": "FAQ - питання про створення тестових файлів",
+ "description": "Чим це відрізняється від dd і fsutil, чи можна комітити файли, чи повторюються запуски байт у байт і що буде, якщо розмір недосяжний."
+ },
+ {
+ "key": "damage",
+ "slug": "corrupt-test-files",
+ "nav": "Пошкоджені файли",
+ "title": "Пошкоджені тестові файли - зламані файли точного розміру",
+ "description": "Навмисно зіпсований файл точного розміру з маніфестом, який каже, що ваша система має його відхилити. Для перевірки валідації завантаження та парсерів.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "test-files-in-ci",
+ "nav": "Тестові файли в CI",
+ "title": "Тестові файли в CI - GitHub Actions, GitLab CI і PowerShell",
+ "description": "Генеруйте тестові файли в конвеєрі, а не комітьте бінарники: workflow GitHub Actions, завдання GitLab, коди завершення та пастка PowerShell.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "Перейти до вмісту",
+ "navLabel": "Основне",
+ "langLabel": "Мова",
+ "breadcrumbHome": "Головна",
+ "imageAlt": "Testing Files Generator - справжні тестові файли точного розміру та маніфест з очікуваною реакцією вашої системи на кожен із них",
+ "schemaDescription": "Безкоштовний генератор тестових файлів для QA з відкритим кодом. Створює справжні файли у {{ .Facts.FormatCount }} форматах точного розміру й записує маніфест з очікуваною реакцією тестованої системи на кожен із них.",
+ "ctaDownload": "Завантажити",
+ "ctaSource": "Вихідний код",
+ "ctaNote": "Безкоштовно, відкритий код, GPL-3.0. Без реєстрації. Збірки для Windows і macOS підписані та запускаються без попереджень.",
+ "colFormat": "Формат",
+ "colName": "Назва",
+ "colExtension": "Розширення",
+ "colSmallest": "Найменший файл",
+ "colFidelity": "Повнота",
+ "colChecked": "Перевіряється за допомогою",
+ "colSetting": "Налаштування",
+ "colAccepts": "Допускає",
+ "colSystem": "Система",
+ "colCli": "Командний рядок",
+ "colWindow": "Десктопне вікно",
+ "noBinary": "поки без збірки",
+ "colCode": "Код",
+ "colMeaning": "Значення",
+ "footerBlurb": "Тестові файли для QA точного розміру та маніфест з очікуваною реакцією вашої системи на кожен із них.",
+ "footerProject": "Проєкт",
+ "footerSource": "Вихідний код на GitHub",
+ "footerReleases": "Завантаження",
+ "footerIssues": "Повідомити про проблему",
+ "footerSupport": "Підтримати проєкт",
+ "footerPages": "Сторінки",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. Поширюється за ліцензією GNU General Public License версії 3. Файли, які ви створюєте, належать вам - ліцензія охоплює інструмент, а не його результат.",
+ "footerPrivacy": "Цей сайт не завантажує шрифти, скрипти чи трекери звідки б то не було. Він не встановлює куки.",
+ "notFoundTitle": "Такої сторінки немає",
+ "notFoundLead": "Адреса, за якою ви перейшли, не відповідає жодній сторінці цього сайту.",
+ "notFoundBack": "На головну",
+ "read.format": "Формат кожного файлу набору. Це прапорець самого інструмента, а пресет лише задає йому значення за замовчуванням.",
+ "readTakes.format": "id формату зі сторінки форматів",
+ "colDamage": "Пошкодження",
+ "colEffect": "Що воно робить із байтами",
+ "colSettings": "Налаштування",
+ "noSettings": "немає"
+ },
+ "endings": {
+ "0": "Усе спрацювало.",
+ "1": "Непередбачена помилка всередині інструмента.",
+ "2": "Неправильна команда або прапорець.",
+ "3": "Рецепт недійсний.",
+ "4": "Формат не може зробити те, що просили.",
+ "5": "Не вдалося прочитати або записати.",
+ "6": "Недостатньо місця на диску.",
+ "7": "verify виявив розбіжність.",
+ "8": "Запуск завершено, але створено не все.",
+ "130": "Перервано за допомогою Ctrl+C.",
+ "143": "Зупинено сигналом, так виглядає тайм-аут у CI."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "Чи пройде коректний файл, настільки малий, наскільки дозволяє формат?",
+ "title": "Порожні та мінімальні",
+ "pageTitle": "Мінімальні коректні та порожні тестові файли в кожному форматі",
+ "description": "Найменший коректний файл, який інструмент записує в кожному з {{ .Facts.FormatCount }} форматів, і порожній файл там, де формат це допускає, з очікуваною реакцією для кожного.",
+ "catches": [
+ "коректний файл, відхилений як надто малий, бо перевірка рахує байти, а не читає їх",
+ "порожній файл, який валить читальний код замість того, щоб бути поміченим",
+ "картинка завширшки один піксель, яка ділить на нуль дорогою до мініатюри",
+ "сховище, яке сприймає нуль байтів як невдале завантаження й безкінечно повторює спроби"
+ ],
+ "details": {
+ "formats": "З яких форматів складається набір. Залиште all для всіх форматів цієї збірки або перелічіть ті, які приймає ваша система."
+ }
+ },
+ "filename-handling": {
+ "question": "Чи збереже, покаже та поверне моя система ім'я файлу, якого не очікувала?",
+ "title": "Обробка імен файлів",
+ "pageTitle": "Проблемні імена файлів для тестів - Unicode і довжина",
+ "description": "Файли з іменами, що ламають завантаження та зберігання: інші писемності й емодзі, зміна напряму письма, невидимі символи, синтаксис shell і SQL, ліміти довжини.",
+ "catches": [
+ "ім'я, що на екрані, в журналі чи в списку виглядає як інше",
+ "ім'я, обрізане, скорочене або переписане між завантаженням і зберіганням",
+ "ліміт довжини, що рахується в символах там, де сховище рахує байти"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "Чи застосовується ліміт розміру саме там, де його оголошено?",
+ "title": "Межі розміру",
+ "pageTitle": "Перевірка ліміту розміру завантаження - файли на самій межі",
+ "description": "Файли на байт менші, рівно за лімітом і на байт більші за ліміт вашої системи, плюс ширші кроки в обидва боки, з позначкою, чи треба приймати кожен.",
+ "catches": [
+ "помилки на одиницю на межі ліміту",
+ "МБ, сплутані з МіБ, тобто 4,8 відсотка, чого досить, щоб пропустити файл, який не мав би пройти",
+ "ліміт, що застосовується в браузері, а не на сервері"
+ ],
+ "details": {
+ "limit": "Ліміт розміру, який оголошує ваша система. Усе інше відмірюється від нього.",
+ "spread": "Як далеко відходити від ліміту в обидва боки, списком розмірів."
+ }
+ },
+ "tabular-import": {
+ "question": "Чи переживе мій імпорт таблиць те, що експортують справжні інструменти?",
+ "title": "Імпорт таблиць",
+ "pageTitle": "Тестові файли для імпорту CSV та Excel - роздільники й заголовки",
+ "description": "CSV з іншими роздільниками, кінцями рядків CR LF, без заголовка й з іншими лапками, дуже широка таблиця, книга Excel та JSON у кількох виглядах.",
+ "catches": [
+ "файл із крапкою з комою, прочитаний як один стовпець, бо роздільник припустили, а не шукали",
+ "файл CRLF, розбитий на рядки з порожнім рядком після кожного",
+ "таблиця без заголовка, перший рядок даних якої з'їдається як імена стовпців",
+ "імпорт, що залишає стовпці, які може показати, і мовчки відкидає решту",
+ "читач, що бере записи JSON по одному рядку й зупиняється на першому документі з відступами"
+ ],
+ "details": {
+ "rows": "Скільки рядків у таблиці. Файл записується рівно того розміру, у який пакується стільки рядків, тому бюджет вище змінюється разом із цим значенням.",
+ "columns": "Скільки стовпців у кожному рядку таблиці. Добуток рядків на стовпці має стелю, і запит понад неї відхиляється до запису чого-небудь."
+ }
+ },
+ "text-encoding": {
+ "question": "Чи знає мій читач, у якому кодуванні файл, чи вгадує?",
+ "title": "Кодування тексту",
+ "pageTitle": "Тестові файли кодування тексту - UTF-8, UTF-16, BOM, CRLF",
+ "description": "Той самий текст в UTF-8, UTF-16LE та UTF-16BE, з позначкою порядку байтів і без неї, та кінці рядків CR LF і LF, щоб перевірити, як читач декодує текст.",
+ "catches": [
+ "читач, що припускає UTF-8 і показує файл UTF-16 з одним символом із трьох або рядами квадратиків",
+ "позначка порядку байтів, прочитана як вміст, через що перше поле імпорту починається з трьох зайвих символів",
+ "імпортер, що вгадує кодування за першими байтами й вгадує інакше для довшого файлу",
+ "файл CRLF, розбитий на рядки з порожнім рядком після кожного, або повернення каретки, що залишилося в останньому полі"
+ ],
+ "details": {
+ "sample": "Розмір кожного файлу набору. UTF-16 зберігає по два байти на символ, тому непарне число відхиляється."
+ }
+ },
+ "upload-validation": {
+ "question": "Чи приймає моя форма завантаження те, що має, і відхиляє решту?",
+ "title": "Перевірка завантаження",
+ "pageTitle": "Тестові файли перевірки завантаження - тип, розмір та ім'я",
+ "description": "Файли для перевірки форми завантаження: дозволені й заборонені типи, вміст не за розширенням, ліміт розміру, ворожі імена та масове завантаження.",
+ "catches": [
+ "ліміт, що застосовується в браузері, а не на сервері",
+ "SVG або HTML, прийнятий за картинку чи простий текст, що дає змогу провести скрипт крізь форму",
+ "файл, перевірений за розширенням і жодного разу не відкритий, тож PDF з ім'ям .jpg проходить",
+ "форма, що читає все тіло в пам'ять, перш ніж подивитися, наскільки воно велике",
+ "завантаження з ім'ям PHOTO.JPG відхилене там, де photo.jpg приймається, або навпаки",
+ "ім'я з пробілами, дужками чи символами поза ASCII, записане на диск без змін"
+ ],
+ "details": {
+ "limit": "Ліміт розміру, який оголошує ваша форма завантаження. Цей набір робить по одному кроку в обидва боки - для файлу на кожній відстані запустіть пресет size-boundaries.",
+ "allow": "Які типи має приймати ваша форма. Кожен стає справжнім файлом цього типу, і разом вони є позитивним контролем усього набору.",
+ "deny": "Які розширення має відхиляти ваша форма. Розширення, для якого в цій збірці немає формату, усе одно отримує файл із таким ім'ям і простим текстом усередині.",
+ "far-over": "Наскільки далеко за ліміт заходить єдиний великий файл. Вимкніть, якщо запис кількох лімітів не вартий місця на диску.",
+ "bulk": "Скільки файлів у масовому завантаженні. Нуль повністю прибирає цю групу з набору."
+ }
+ }
+ },
+ "commands": {
+ "generate": "створити файли за рецептом або за прапорцями",
+ "validate": "перевірити рецепт, нічого не записуючи",
+ "verify": "звірити каталог із маніфестом",
+ "cleanup": "видалити файли, перелічені в маніфесті",
+ "recipe fmt": "вивести рецепт у усталеному вигляді",
+ "preset": "зібрати набір файлів за іменованим тестовим питанням",
+ "formats": "перелічити формати цієї збірки",
+ "damage": "перелічити способи, якими ця збірка може навмисно зіпсувати файл",
+ "tool": "невеликі інструменти для вже наявних файлів",
+ "version": "вивести версію інструмента",
+ "license": "вивести ліцензію та що вона означає для створених файлів"
+ },
+ "outcomes": {
+ "accept": "Ваша система має прийняти файл.",
+ "reject": "Ваша система має відхилити файл.",
+ "sanitize": "Ваша система має прийняти файл і очистити його, наприклад перейменувавши.",
+ "unspecified": "Залежить від правил вашої системи. Ви вирішуєте, а потім перевіряєте, що відбувається саме те, що ви мали на увазі."
+ },
+ "damages": {
+ "zero-head": "Перезаписує перші байти файлу нулями, не змінюючи його довжину. Більшість програм читання дивляться спочатку туди, тому це пошкодження помічає майже все."
+ },
+ "terms": {
+ "oracleNone": "не застосовується",
+ "int": "будь-яке ціле число",
+ "choice": "одне зі значень фіксованого набору",
+ "bool": "істина або хибність",
+ "size": "розмір, наприклад 2mb",
+ "text": "текст",
+ "pixels": "пікселів",
+ "paragraphs": "абзаців",
+ "rows": "рядків",
+ "columns": "стовпців",
+ "slides": "слайдів",
+ "hertz": "герців",
+ "megapixels": "мегапікселів",
+ "million cells": "мільйонів комірок",
+ "entries per second": "записів на секунду",
+ "files": "файлів",
+ "sizes separated by commas": "розміри через кому",
+ "format ids separated by commas": "id форматів через кому",
+ "format ids separated by commas, or all": "id форматів через кому або all",
+ "extensions separated by commas": "розширення через кому",
+ "the id of a format, as tfg formats lists them": "id формату в тому вигляді, як його виводить tfg formats",
+ "the password, in plain text": "пароль відкритим текстом",
+ "any text": "будь-який текст",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "дата на кшталт 2024-02-29 або 2024-02-29T13:45:00+02:00, або none"
+ },
+ "faq": [
+ {
+ "q": "Чим це відрізняється від dd, fsutil чи truncate?",
+ "a": "Вони дають файл потрібного розміру, набитий порожнечею. Файл photo.png на 2 МБ, зроблений так, не є PNG, тому все, що справді його розбирає, відхиляє його з хибної причини, і ваш тест теж проходить із хибної причини. Цей інструмент створює справжній PNG рівно на 2 МБ, який відкривається в переглядачі зображень, і супроводжує його заявою про те, як ваша система має з ним вчинити.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "Це безкоштовно, і чи можна використовувати на роботі?",
+ "a": "Так в обох випадках. Інструмент випущено під GPL-3.0, і він нічого не коштує. Немає ні облікового запису, ні ліцензійного ключа, ні платного тарифу."
+ },
+ {
+ "q": "Чи можна використовувати створені файли в продукті із закритим кодом?",
+ "a": "Так. Ліцензія охоплює код інструмента, а не те, що він створює. Створені файли, рецепти й маніфести є результатом, а не похідними творами, тож їх можна комітити та постачати без жодних зобов'язань."
+ },
+ {
+ "q": "Чи містять створені файли справжні персональні дані?",
+ "a": "Ні. Усе всередині синтезується з seed. Жоден набір даних не читається, до жодного сервісу не звертаються і жоден сторонній вміст не вбудовується. Вважайте створену адресу електронної пошти непридатною, а не невикористаною, бо будь-який випадковий рядок може випадково збігтися зі справжнім."
+ },
+ {
+ "q": "Чи отримаю я точно такі самі файли на іншій машині?",
+ "a": "Так, байт у байт, за того самого рецепта й того самого seed. Проєкт перевіряє це при кожній зміні, а порушити це можна лише підвищенням мажорної версії. Саме тому ви можете комітити невеликий рецепт замість великих бінарних фікстур."
+ },
+ {
+ "q": "Чи потрібне підключення до інтернету?",
+ "a": "Ніколи. Немає ні телеметрії, ні перевірки оновлень, ні хмарного клієнта, а в бінарний файл командного рядка взагалі не скомпільовано мережевий стек. Він працює на машині без мережі й у закритому корпоративному середовищі."
+ },
+ {
+ "q": "Що буде, якщо запросити розмір, якого формат не може досягти?",
+ "a": "Ви отримаєте помилку з назвою формату, найменшим можливим розміром, причиною цього мінімуму та тим, що робити натомість, а файл записано не буде. Інструмент ніколи не округлює розмір мовчки. Кожен мінімум указано на сторінці форматів.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "Чи можна створити навмисно зламаний файл?",
+ "a": "Так. Додайте --damage zero-head, і файл вийде точно заданого розміру, з першими байтами, перезаписаними нулями, тож програма читання його відхилить, а маніфест скаже, що ваша система має його відхилити. Подробиці на сторінці про пошкоджені тестові файли.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "Які формати з'являться далі?",
+ "a": "7z, mp3 і mp4. Сьогодні повністю працюють {{ .Facts.FormatCount }} форматів."
+ },
+ {
+ "q": "У яких системах це можна запускати?",
+ "a": "Командний рядок працює у Windows і Linux на Intel та ARM, а також на Mac з Apple Silicon. Десктопне вікно постачається для Windows на Intel, Linux на Intel і Mac з Apple Silicon. Mac на Intel не підтримуються, і для них нічого не збирається."
+ },
+ {
+ "q": "Чи потрібно щось установлювати?",
+ "a": "Ні. Завантажте архів для своєї системи, розпакуйте й запустіть бінарний файл. Немає інсталятора, середовища виконання, яке треба додавати, і залежностей, які треба розв'язувати. Якщо у вас є Go, підійде й одна команда go install.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "Чому запуск на тисячах файлів у Windows повільніший?",
+ "a": "Бо Windows бере більше за кожен шлях, який переглядає, а команда, що обходить тисячі файлів, переглядає тисячі шляхів. Виміряно на одній машині з 3000 файлів по 1 КБ: verify займає близько 0,9 секунди у Windows і близько 0,2 секунди в Linux у контейнері. Коротший шлях виводу зменшує цифру для Windows, бо кожна тека над файлами входить у те, що переглядається."
+ }
+ ]
+}
diff --git a/web/content/uk/use-cases.html b/web/content/uk/use-cases.html
new file mode 100644
index 00000000..5799f125
--- /dev/null
+++ b/web/content/uk/use-cases.html
@@ -0,0 +1,131 @@
+
Для чого це використовують
+
+ П'ять завдань, що виникають майже в кожному проєкті, який приймає файли від людей, і команда, що
+ розв'язує кожне. Кожен приклад нижче запускається як написано.
+
+
+
+
Ліміти завантаження
+
Перевірка того, що ліміт розміру файлу застосовується там, де заявлено
+
+ Ліміт - це три тестові випадки, а не один: трохи нижче, рівно за лімітом і трохи вище. Отримати їх
+ вручну означає рахувати числа байтів і сподіватися, що ви не помилилися на одиницю. Запросіть
+ натомість набір:
+
+ Ви отримаєте три справжні PDF по 1048575, 1048576 і 1048577 байт та маніфест, що каже: перші два
+ слід прийняти, а третій відхилити за size_limit. Ваш тест читає очікування, замість
+ того щоб ви писали три перевірки вручну, а коли ліміт змінюється, ви змінюєте одне число й
+ запускаєте знову.
+
+
+ Те саме працює й без пресета, коли потрібен один набір меж просто в команді:
+
Тримати фікстури поза репозиторієм, не втрачаючи їх
+
+ Великі бінарні фікстури сповільнюють клонування репозиторію й заважають рев'ю, а при заміні ніхто не
+ може сказати, що змінилося. Рецепт - це кілька сотень символів YAML, що відтворюють ті самі
+ файли - байт у байт, на будь-якій машині - бо кожен файл виводиться з seed
+ запуску.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Кожен кінець має власний код завершення, тому конвеєр відрізняє поганий рецепт від повного диска й
+ від розбіжності під час перевірки. Невдалий запуск нічого не друкує в стандартний вивід, і
+ розбірник журналів не сприймає помилку за дані.
+
+
+
+
+
Масштаб
+
З'ясувати, що відбувається, коли тека велика
+
+ Процедури імпорту, нічні завдання та списки каталогів поводяться інакше за десяти тисяч файлів, ніж
+ за десяти. Розміри, вибрані з діапазону, роблять набір схожим на справжній трафік, а не на
+ десять тисяч однакових файлів, і вибір іде від seed, тож завтра набір буде той самий.
+
+ Запуск, більший за вільне місце на диску, відхиляється до запису першого байта, а не заповнює диск і
+ не падає на півдорозі.
+
+
+
+
+
Архіви
+
Перевірка розпакувальника на архіві, що справді містить файли
+
+ Порожній архів із правильним розширенням нічого не доводить про код, який його відкриває й обходить
+ вміст. Оголосіть вміст, і архів справді його містить:
+
+ Глибина вкладеності, кількість записів і розмір вмісту - це те, про що в процедури імпорту є власна
+ думка, і так ви дізнаєтеся, яка вона.
+
+
+
+
+
Парсери та переглядачі
+
Перевірка того, що ваш власний код читає формат так само, як справжнє ПЗ
+
+ Кожен формат тут перевіряється незалежним читачем до випуску: PNG відкривається й порівнюються його
+ пікселі, DOCX перечитується окремими бібліотеками, архів розпаковується. Це означає, що файл,
+ який відхиляє ваш парсер, - знахідка про ваш парсер, а не про генератор.
+
+ Сторінка форматів перелічує налаштування кожного формату та найменший
+ файл, яким він може бути.
+
+
+
+
+
Посібники
+
Два з них докладніше
+
+
+ Пошкоджені тестові файли - файл, навмисно зіпсований, точного
+ розміру, із записаним у маніфесті тим, що з ним має статися.
+
+
+ Тестові файли в CI - workflow для GitHub Actions, завдання
+ GitLab і коди завершення, що валять збірку.
+
+
+
+
+
+
Для кого це
+
+ QA-інженери, автоматизація тестування та всі, за чиїм кодом стоїть форма завантаження, процедура
+ імпорту, парсер чи квота сховища. Працює на машині взагалі без мережі, що важливо в закритому
+ корпоративному середовищі, де генератор у браузері - не варіант.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/vi/ci.html b/web/content/vi/ci.html
new file mode 100644
index 00000000..a12a45dc
--- /dev/null
+++ b/web/content/vi/ci.html
@@ -0,0 +1,187 @@
+{{ with .Up }}
+ Một fixture nhị phân trong kho mã nằm lại mãi trong lịch sử của nó, không thể review trong diff và
+ trở nên bất khả thi khi tệp lớn. Hãy tạo tệp ngay trong pipeline từ một công thức. Công thức là
+ văn bản, các byte ra giống hệt mỗi lần, và một bước cuối chứng minh không có gì xê dịch.
+
+
+
+
Câu trả lời ngắn
+
+ Cài tfg, chạy tfg generate fixtures.yaml --out ./fixtures trước các bài
+ kiểm thử và tfg verify ./fixtures/manifest.json sau đó. Cả hai bước tự làm bản dựng
+ thất bại, với một mã thoát nói lý do.
+
+
+
+
+
Vì sao không commit
+
Vì sao fixture không nên nằm trong kho mã
+
+
+ Nó ở lại trong lịch sử. Xóa một tệp nhị phân sau này không làm bản clone nhỏ đi, vì
+ mọi phiên bản của nó vẫn còn đó.
+
+
+ Diff không cho thấy cái gì đã đổi. Người review thấy một tệp PDF khác đi và không
+ biết gì thêm. Công thức thì đổi một dòng.
+
+
+ Tệp lớn không vừa. GitHub từ chối một lần push có tệp lớn hơn 100 MB, nên bài kiểm
+ thử giới hạn tải lên 500 MB không có gì để commit.
+
+
+
+ Thứ cần commit là công thức. Cùng công thức và cùng seed ghi ra cùng các byte trên mọi máy, nên tệp
+ tạo trong pipeline chính là tệp bạn có trên laptop.
+
+
+
+
+
Công thức
+
Một công thức nằm cạnh các bài kiểm thử
+
+ Công thức này ghi hai mươi lăm hóa đơn phải được chấp nhận và hai ảnh vượt giới hạn phải bị từ chối,
+ và manifest ghi cả hai kỳ vọng:
+
+ Dòng checksum so sánh tệp lưu trữ với verify-SHA256SUMS.txt của cùng bản phát hành.
+ Phiên bản được ghim cố định, nên một bản phát hành mới không bao giờ đổi một bản dựng bạn chưa
+ đụng tới.
+
+ Mỗi kết cục có mã thoát riêng, nên bước tự thất bại và nhật ký nói là mã nào. Những mã một pipeline
+ gặp:
+
+
+
3 - công thức không hợp lệ. Không có gì được ghi, và mọi vấn đề đều được nêu
+
4 - định dạng không làm được điều được yêu cầu, ví dụ kích thước dưới mức nhỏ nhất của nó
+
6 - không đủ dung lượng đĩa
+
7 - tfg verify tìm thấy một tệp không khớp với manifest của nó
+
8 - lần chạy đã xong, nhưng không phải mọi thứ đều được tạo ra
+
+
+ Lần chạy thất bại không in gì ra đầu ra chuẩn, nên trình phân tích nhật ký không bao giờ nhầm một
+ lỗi là dữ liệu. Cả bảng nằm ở trang tài liệu.
+
+
+
+
+
PowerShell
+
Script PowerShell cần thêm một dòng
+
+ PowerShell không mang mã thoát của một chương trình ra khỏi tệp .ps1. Chạy một script
+ với -File và script trả lời 0 ngay cả khi công cụ bên trong đã từ chối
+ công việc, nên một bản dựng lẽ ra phải đỏ lại thành xanh. Dòng cuối là toàn bộ cách sửa:
+
+ PowerShell hành xử như vậy, không phải điều gì của công cụ này. cmd, bash
+ và zsh không cần thêm gì.
+
+
+
+
+
Nhiều job
+
Chia sẻ fixture giữa các job
+
+ Thường không cần tải chúng lên. Vì cùng công thức ghi cùng các byte, mỗi job có thể chạy tfg
+ generate của riêng nó, nhanh hơn một lần tải lên rồi tải xuống. Khi một job phải nhận tệp
+ từ job khác, hãy chạy tfg verify trên manifest sau khi chuyển, và nó cho biết thứ
+ đến nơi có đúng là thứ đã được ghi không.
+
+ Một trình kiểm tra chỉ từng được cho xem tệp lành thì chưa thực sự được kiểm thử. Đây là cách có
+ được một tệp cố ý làm hỏng, ra đúng kích thước bạn yêu cầu và mang theo manifest
+ nói hệ thống của bạn phải làm gì với nó.
+
+
+
+
Câu trả lời ngắn
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out ghi một tệp PNG
+ đúng 2097152 byte với các byte đầu là số không, và manifest bên cạnh ghi rằng hệ thống của bạn
+ phải từ chối nó.
+
+
+
+
+
Cách thường dùng
+
Vì sao tệp làm hỏng bằng tay là một bài kiểm thử tồi
+
+ Cách thường dùng là trình soạn thảo hex, một script đảo vài byte ngẫu nhiên, hoặc cắt ngắn tệp bằng
+ head hay truncate. Dùng được một lần, rồi nó làm bạn tốn công:
+
+
+
+ Mỗi lần một khác. Byte ngẫu nhiên rơi vào chỗ mới ở mỗi lần chạy, nên lỗi hôm thứ
+ Ba có thể không quay lại vào thứ Tư.
+
+
+ Nó đổi kích thước. Tệp bị cắt ngắn nhỏ hơn giới hạn mà nó phải nằm dưới, nên bước
+ kiểm tra kích thước trả lời trước bước kiểm tra nội dung và bài kiểm thử đạt vì lý do sai.
+
+
+ Nó thường không ai nhận ra. Văn bản thuần vẫn đọc được khi đổi một byte ở giữa, và
+ một trình đọc ảnh dễ tính chỉ việc vẽ nó ra, nên tệp lẽ ra phải hỏng lại được chấp nhận.
+
+
+ Nó không nói gì về điều phải xảy ra. Tệp chỉ là các byte, và ai đọc bài kiểm thử
+ sau đó phải đoán xem ý định là chấp nhận hay từ chối.
+
+
+
+
+
+
Bạn nhận được gì
+
Tệp bị hỏng vẫn có kích thước bạn đã yêu cầu
+
+ Tệp được tạo bình thường rồi mới bị làm hỏng, trên đường ghi xuống đĩa. Nó giữ kích thước bạn yêu
+ cầu, và cùng một lệnh ghi lại đúng các byte đó.
+
+ Cài đặt viết sau dấu hai chấm. Tùy chọn có thể lặp lại, và các hỏng hóc được áp dụng theo thứ tự bạn
+ viết. Nó dùng được với từng định dạng trong {{ .Facts.FormatCount }} định dạng.
+
+
+
+
+
Nó làm được gì
+
Có những kiểu hỏng nào?
+
+ Đây là danh sách chương trình in ra, được đọc từ chính nó khi trang này được dựng. tfg
+ damage in ra cùng danh sách đó, và tfg damage <id> cho biết một kiểu
+ nhận những gì.
+
+ {{ template "damagesTable" . }}
+
+ zero-head ghi số không đè lên phần đầu tệp. Hầu hết trình đọc nhìn vào đó trước, vào
+ chữ ký và phần đầu cho biết tệp là gì, nên gần như trình đọc nào cũng nhận ra. Văn bản thuần và
+ nhật ký không có chữ ký và cũng bị từ chối, vì một chuỗi byte không không phải là văn bản. Dưới
+ bốn byte, một số định dạng ra với hỏng hóc mà không trình đọc nào phàn nàn, đó là lý do cài đặt
+ bắt đầu từ bốn.
+
+
+
+
+
Manifest nói gì
+
Một manifest nói điều phải xảy ra
+
+ Mỗi tệp bị hỏng nhận một mục nói rằng hệ thống của bạn phải từ chối nó, với hỏng hóc được ghi bên
+ cạnh:
+
+ Hai yêu cầu bị từ chối trước khi có gì được ghi, vì mỗi yêu cầu sẽ để lại trên đĩa một tệp mà
+ manifest mô tả sai:
+
+
+
một tệp nhỏ hơn mức hỏng hóc cần, sẽ ra mà không bị đổi
+
+ expected: accept cạnh một hỏng hóc, vì không gì có thể đáp ứng được. Viết
+ sanitize nếu hệ thống của bạn phải sửa tệp, hoặc unspecified nếu đó
+ chính là câu hỏi bạn đang đặt ra
+
+
+
+
+
+
Trong một công thức
+
Tệp lành và tệp hỏng trong một lần chạy
+
+ Đặt cả hai vào một công thức, và manifest mang kỳ vọng của từng tệp, nên bài kiểm thử không cần danh
+ sách tệp nào là tệp nào:
+
+ Bài kiểm thử đọc manifest và kiểm tra điều đã xảy ra có đúng như điều đã khai báo. Nó không cần danh
+ sách tên tệp:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Một lần từ chối tốt là một lần từ chối gọn. Một thông báo nói điều gì sai là câu trả lời bạn muốn.
+ Lỗi máy chủ, treo máy hoặc một tệp lưu dở là khiếm khuyết mà bài kiểm thử này sinh ra để tìm.
+
+
+
+
+
Tiếp theo
+
Đi đâu từ đây
+
+
+ Preset upload-validation hỏi một biểu mẫu hai câu hỏi
+ còn lại, về kích thước và về loại tệp.
+
+
diff --git a/web/content/vi/docs.html b/web/content/vi/docs.html
new file mode 100644
index 00000000..847a13f6
--- /dev/null
+++ b/web/content/vi/docs.html
@@ -0,0 +1,274 @@
+
Tài liệu
+
+ Mọi thứ công cụ làm, sắp xếp theo những câu hỏi mà mọi người thật sự mang đến.
+ README trong kho mã là tài liệu tham chiếu đầy đủ và luôn khớp với
+ bản dựng bạn đã tải.
+
+
+
+
Có những lệnh nào?
+
Mỗi lệnh làm đúng một việc:
+ {{ template "commandList" . }}
+
+
+
+
Làm sao tạo một tệp đơn có kích thước chính xác?
+
+ Nêu định dạng, kích thước và nơi đặt. Kích thước đếm theo 1024, nên 2mb là 2097152
+ byte. Số byte thuần cũng được, nên --size 10485761 yêu cầu đúng chừng đó.
+
+
tfg generate --format png --size 2mb --out ./out
+
Các cờ hữu ích của generate:
+
+
+
Cờ
Tác dụng
+
+
--format <id>
định dạng của các tệp, ví dụ txt
+
--size <size>
kích thước chính xác của mỗi tệp, như 10mb hoặc số byte thuần
+
--size-range <a-b>
kích thước rút cho từng tệp từ một khoảng, như 1kb-8kb. Lần rút lấy từ seed
+
--boundary <size>
ba tệp quanh một giới hạn: thấp hơn một byte, đúng giới hạn, cao hơn một byte
+
--count <n>
tạo bao nhiêu tệp. Mặc định 1
+
--name <template>
mẫu tên, ví dụ invoice_{index:04}.txt
+
--out <dir>
thư mục để ghi vào
+
--seed <n>
seed của lần chạy. Cùng seed cho cùng các byte
+
--set <k>=<v>
một thiết lập định dạng, lặp lại được
+
--damage <name>
cố ý làm hỏng tệp, lặp lại được và áp dụng theo thứ tự. Chạy tfg damage để xem danh sách
+
--expected <outcome>
accept, reject, sanitize hoặc unspecified
+
--dry-run
đếm và hiển thị, hoàn toàn không ghi gì
+
--json
ghi manifest ra đầu ra chuẩn
+
+
+
+
+
+
+
Làm sao tạo một tệp cố ý bị hỏng?
+
+ Mọi tệp khác mà công cụ này ghi đều đúng theo cách xây dựng, điều đó trả lời hai trong ba câu hỏi mà
+ trình kiểm tra tải lên đặt ra. --damage trả lời câu thứ ba - tệp có mở được không.
+ Tệp được tạo bình thường rồi bị làm hỏng, nên nó vẫn có kích thước bạn đã yêu cầu.
+
+ Các thiết lập đặt sau dấu hai chấm. Cờ lặp lại được, và thứ tự bạn viết là thứ tự chúng được áp
+ dụng. tfg damage liệt kê những gì bản dựng này làm được và mỗi kiểu nhận gì.
+
+
Trong công thức, khóa là một danh sách, gồm tên hoặc thiết lập:
+ Tệp bị làm hỏng nhận expected: reject trong manifest, kèm kiểu hỏng được ghi bên cạnh.
+ Hai thứ bị từ chối trước khi ghi bất cứ gì, vì mỗi thứ sẽ đặt lên đĩa một tệp mà manifest mô tả
+ sai:
+
+
+
tệp nhỏ hơn mức kiểu hỏng cần, vì nó sẽ ra mà không thay đổi
+
+ expected: accept bên cạnh một kiểu hỏng, vì không gì có thể đáp ứng. Hãy viết
+ sanitize nếu hệ thống được kiểm thử phải sửa tệp, hoặc unspecified
+ nếu đó chính là câu hỏi bạn đang đặt
+
+
+
+ Thứ ba không thể biết trước. Nếu một kiểu hỏng chạy mà không đổi byte nào, tệp đó bị bỏ thay vì được
+ ghi - lần chạy tiếp tục, nói đó là tệp nào và kết thúc bằng mã thoát một phần.
+
+ Công thức là một tệp YAML mô tả cả một lần chạy. Hãy commit nó bên cạnh các bài kiểm thử và fixture
+ thôi là tệp nhị phân trong kho mã - ai cũng có thể dựng lại chúng, từng byte, từ một tệp vài
+ trăm ký tự.
+
+ Mỗi target cần đúng một trong size, size-range, boundary hoặc
+ contains. Hai cái là lỗi và không cái nào cũng là lỗi. Công thức không hợp lệ ghi
+ không tệp nào và báo mọi vấn đề cùng lúc thay vì chỉ cái đầu, mỗi cái nêu thiết
+ lập mà nó nói đến.
+
+
+
+
+
Làm sao khai báo hệ thống của tôi cần làm gì với một tệp?
+
Dạng ngắn khi kết quả là đủ, dạng dài khi lý do quan trọng:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Các kết quả là accept, reject, sanitize và
+ unspecified. Các lý do là một danh sách đóng để báo cáo có thể nhóm theo chúng:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit và size_zero.
+
+
+ Một lý do nêu quy tắc đang áp dụng, không phải phán quyết. Vì vậy cùng một lý do có
+ thể nằm dưới cả hai kết quả - tệp thấp hơn giới hạn một byte là accept, và quy tắc
+ liên quan vẫn là size_limit.
+
+
+
+
+
Manifest chứa gì?
+
+ Nó được ghi bên cạnh các tệp ở cuối mỗi lần chạy, kể cả lần chạy bị ngắt. Một mục cho mỗi tệp:
+
+ recipe_hash được thêm khi lần chạy đến từ một công thức, và preset cùng
+ overrides khi nó đến từ một preset, nên manifest luôn truy ngược được về thứ đã tạo
+ ra nó.
+
+
+ Mỗi mục còn mang target_id, id của target trong công thức đã tạo tệp, và
+ summary.by_target đếm số tệp mà mỗi target tạo ra. Một công thức có nhiều target
+ nhờ vậy kiểm tra được từng target mà không cần đọc tên tệp.
+
+
+
+
+
Preset là gì?
+
+ Một bộ tệp dựng sẵn trả lời một câu hỏi kiểm thử thường gặp, để bạn không phải tự thiết kế bộ.
+ Preset thực chất là công thức bình thường, và eject in công thức ra để bạn chỉnh
+ sửa từ đó. Mỗi preset có trang riêng nói nó thường tìm thấy gì, trong
+ bộ có gì và mọi thiết lập nó nhận.
+
+ show cho bạn biết bộ sẽ tốn bao nhiêu trước khi dựng, và nói thẳng khi một con số là
+ giá trị tạm của chúng tôi chứ không phải giới hạn của bạn.
+
+
+
+
+
Các mã thoát có nghĩa gì?
+
+ Mỗi kết cục có mã riêng, đầu ra máy đọc được đi ra đầu ra chuẩn, và lần chạy thất bại không in gì ở
+ đó. Bảng này là một hợp đồng đóng băng - đổi nghĩa của một mã đòi hỏi tăng phiên bản chính.
+
+ {{ template "exitCodesTable" . }}
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Lần chạy bị dừng bằng Ctrl+C vẫn để lại manifest và không bao giờ để lại tệp ghi dở, nên tác vụ bị
+ hủy vẫn có thể được dọn bởi tác vụ sau.
+
+ Có, cùng một động cơ với một cửa sổ phủ lên, cho kiểu kiểm thử không viết kịch bản. Nó không phải
+ bản cắt giảm: một bài kiểm thử so sánh hai giao diện từng khả năng một, và bất cứ điều gì chỉ
+ một bên làm được đều phải được khai báo và biện minh thay vì lặng lẽ lệch nhau.
+
+
+ Các màn hình là một lô, preset, nhiều lô cùng lúc và giới thiệu. Nó cho biết một lần chạy sẽ tốn bao
+ nhiêu trước khi ghi gì, báo tiến độ khi đang chạy và có thể hủy giữa chừng mà không để lại tệp
+ ghi dở. Nó chưa mở được tệp công thức - hiện công thức là việc của dòng lệnh, còn cửa sổ dựng
+ các lô trong biểu mẫu.
+
+
diff --git a/web/content/vi/exact-size.html b/web/content/vi/exact-size.html
new file mode 100644
index 00000000..4e4dcb1b
--- /dev/null
+++ b/web/content/vi/exact-size.html
@@ -0,0 +1,144 @@
+
Cách tạo tệp có kích thước chính xác
+
+ Hệ thống nào cũng có một lệnh cho việc này, và cả ba nằm bên dưới. Chúng cho bạn một tệp có đúng số
+ byte cần thiết - và với nhiều bài kiểm thử, thế là đủ. Mọi lệnh trên trang này đã được
+ chạy trước khi đăng, trên hệ thống mà nó thuộc về.
+
+
+
+
Câu trả lời ngắn
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Kích thước tính bằng byte, và 10 MB
+ đếm theo cách trình quản lý tệp của bạn đếm là 10485760.
+
+
+
+
+
Windows
+
fsutil, và một bản PowerShell không cần thêm gì
+
+ fsutil có sẵn trong Windows. Nó nhận kích thước bằng byte, nên hãy
+ tính số trước - 10 MB là 10485760, 100 MB là 104857600, 1 GB là 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Đo trên Windows 11: nó chạy từ một dấu nhắc thường mà không cần quyền nâng cao, và tệp ra đúng
+ 10485760 byte.
+
+
PowerShell làm được điều tương tự mà không gọi chương trình khác, và hiểu đơn vị:
+ 10MB trong PowerShell nghĩa là 10485760 byte, cùng cách đếm cơ số 1024 mà Explorer
+ dùng, nên hai lệnh ở trên cho cùng một kích thước.
+
+
+
+
+
Linux
+
dd, truncate và fallocate, và sự khác biệt làm người ta vấp
+
dd là lệnh ai cũng biết. Nó thật sự ghi các byte:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate chạy tức thì, và đó là cái bẫy. Đo trên Alpine Linux, tệp báo 10485760 byte và
+ chiếm không khối nào - nó là một tệp thưa. Bất cứ thứ gì đọc
+ nó nhận mười megabyte số không, nhưng đĩa chưa bao giờ nhường chỗ:
+
+
truncate -s 10M test10mb.bin
+
+ Điều đó ổn để kiểm thử giới hạn tải lên và gây hiểu lầm khi kiểm thử hạn ngạch đĩa.
+ fallocate là lệnh nên dùng khi dung lượng phải là thật:
+
+
fallocate -l 10M test10mb.bin
+
Và khi nội dung phải không nén được, để trình nén không thể ép nó nhỏ lại:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, không phải tệp thưa, và hai lệnh bạn đã biết
+
+ macOS có sẵn mkfile. Đo trên macOS 26.6.2: 10485760 byte và 20480 khối, nên dung lượng
+ thật sự được cấp phát chứ không chỉ hứa hẹn:
+
+
mkfile 10m test10mb.bin
+
dd và truncate cũng có và hoạt động như trên Linux:
+ Mọi thứ ở trên cho bạn một khối số không. Điều đó đủ khi thứ được kiểm thử chỉ nhìn kích thước -
+ giới hạn tải lên, hạn ngạch, một lần truyền. Nó thôi đủ ngay khi có thứ gì mở
+ tệp.
+
+
+ Đã đo, và đáng để tự làm: tạo tệp 2 MB bằng fsutil, đặt tên photo.png rồi
+ đưa cho một thư viện ảnh. Pillow trả lời cannot identify image file. Nó không phải
+ PNG. Nó chưa bao giờ là - chỉ cái tên nói vậy.
+
+
+ Điều đó quan trọng hơn vẻ ngoài, vì bài kiểm thử sau đó hỏng theo hướng nào.
+ Endpoint tải lên từ chối tệp, bài kiểm thử của bạn xanh và bạn kết luận giới hạn kích thước hoạt
+ động. Nó không từ chối vì kích thước. Nó từ chối vì các byte không phải ảnh, và quy tắc bạn định
+ kiểm thử chưa bao giờ được chạm tới.
+
+
+
bộ phân tích từ chối nó trước khi xét bất kỳ quy tắc kích thước nào
+
bước tạo ảnh thu nhỏ hỏng và lỗi bạn đọc là về ảnh thu nhỏ
+
phần mềm diệt virus hoặc bước kiểm tra nội dung từ chối nó vì lý do thứ ba
+
trình xem không hiện gì, và không ai biết đó có phải lỗi hay không
+
+
+
+
+
Con đường còn lại
+
Một tệp thật của định dạng đó, đúng kích thước bạn đã yêu cầu
+
+ Đây là việc Testing Files Generator làm. Tệp là tệp thật của định dạng - mở được bằng phần mềm của
+ nó - và có đúng số byte bạn đã yêu cầu, chính xác đến từng byte:
+
+ Yêu cầu kích thước mà định dạng không thể đạt và bạn nhận một lỗi nêu mức sàn cùng lý do, không bao
+ giờ là tệp sai kích thước. Trang định dạng liệt kê mỗi định dạng
+ cùng tệp nhỏ nhất nó có thể tạo.
+
+
Và một giới hạn là ba trường hợp kiểm thử chứ không phải một, nên công cụ dựng cả ba:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Điều đó cho bạn 10485759, 10485760 và 10485761 byte, cùng manifest nói tệp nào hệ thống của bạn nên
+ chấp nhận và tệp nào nên từ chối. Trang trường hợp sử dụng
+ đi qua việc đó và bốn việc khác mà nó được làm ra để giải quyết.
+
+ {{ template "downloadCta" . }}
+
+
+
+
Vậy nên dùng cái nào?
+
+
+
Dùng lệnh của hệ thống
+
+ Khi không có gì mở tệp. Kiểm thử giới hạn kích thước trên endpoint kiểm tra kích thước trước, một
+ lần truyền, một hạn ngạch, tình trạng đầy đĩa. Chỉ một dòng và đã được cài sẵn.
+
+
+
+
Dùng một trình tạo thật
+
+ Khi có thứ gì phân tích, kết xuất, nhập hoặc giải nén tệp - và khi ngày mai bạn cần cùng các fixture
+ đó, trên máy khác, từng byte.
+
+
+
+
+ Cả hai đều có trên trang này vì cả hai đúng trong một phần thời gian. Sai lầm cần tránh là dùng cái
+ đầu ở nơi cần cái sau và coi bài kiểm thử xanh là bằng chứng.
+
+
diff --git a/web/content/vi/faq.html b/web/content/vi/faq.html
new file mode 100644
index 00000000..cabcb701
--- /dev/null
+++ b/web/content/vi/faq.html
@@ -0,0 +1,20 @@
+
Câu hỏi thường gặp
+
+ Giấy phép, quyền riêng tư, khả năng tái lập và những điều mọi người kiểm tra trước khi đưa một trình
+ tạo vào pipeline build. Nếu câu hỏi của bạn chưa có ở đây, trình
+ theo dõi issue luôn mở.
+
{{ .Facts.FormatCount }} định dạng tệp, mỗi định dạng được tạo ở kích thước chính xác
+
+ Mỗi cái là một tệp thật của định dạng đó. Nó mở được bằng phần mềm của nó và có
+ đúng số byte bạn đã yêu cầu. Không cái nào là số không độn với phần mở rộng dán vào.
+
+
+{{ template "formatsTable" . }}
+
+
+
Ý nghĩa các cột
+
+
+
Tệp nhỏ nhất
+
+ Số byte ít nhất mà công cụ này chấp nhận cho định dạng đó, gồm cả nhãn nó ghi vào trong tệp. Yêu cầu
+ ít hơn và bạn nhận một lỗi nêu mức sàn cùng lý do, không bao giờ là tệp sai kích thước.
+
+
+
+
Độ đầy đủ
+
+ Tệp đầy đủ đến đâu. full nghĩa là một trình đọc thật sự phân tích định dạng sẽ chấp
+ nhận nó, chứ không chỉ là phần mở rộng khớp.
+
+
+
+
Kiểm tra bằng
+
+ Trình đọc độc lập mở mọi tệp được tạo trước khi định dạng được phát hành - một bản cài đặt riêng,
+ không phải mã của chính chúng tôi tự chấm bài tập của mình.
+
+
+
+
+ Mỗi định dạng cũng lặp lại đến từng byte: cùng công thức và cùng seed cho các tệp giống hệt trên mọi
+ máy, điều làm cho việc commit một công thức thay cho chính các fixture trở nên an toàn.
+
+
+
+
+
Các thiết lập mỗi định dạng nhận
+
+ Hầu hết định dạng có thiết lập riêng - kích thước ảnh, chất lượng JPEG, số trang PDF, số dòng và cột
+ trong bảng tính, số mục nằm trong một tệp nén. Đặt chúng bằng --set key=value trên
+ dòng lệnh, hoặc dưới properties: trong công thức.
+
+ Giá trị nằm ngoài thứ một thiết lập chấp nhận bị từ chối bằng thông báo nêu thiết lập, khoảng cho
+ phép và nên dùng gì thay thế. Thiết lập lạ cũng là lỗi, không bao giờ là mặc định im lặng - lỗi
+ gõ được chấp nhận trong im lặng cho ra tệp sai thiết lập và một giờ tự hỏi vì sao bài kiểm thử
+ qua khi lẽ ra không.
+
+
+ Chạy tfg formats <id> để xem chính xác một định dạng nhận gì trong bản dựng bạn
+ có.
+
+
+
+
+
Tệp nén chứa tệp thật
+
+ {{ range $i, $c := .Facts.Containers }}{{ if $i }} và {{ end }}{{ $c.ID }}{{ end }} có
+ thể được nhồi các mục thay vì để thành cái vỏ rỗng. Tệp nén được tạo thật sự chứa các tài liệu
+ nó tuyên bố chứa, nên bất cứ thứ gì giải nén nó trong lúc kiểm thử đều thấy tệp thật bên trong.
+
+ PDF, PNG, DOCX, ZIP - tổng cộng {{ .Facts.FormatCount }} định dạng, và mỗi tệp là
+ tệp thật mở được bằng phần mềm của nó, ở đúng kích thước bạn yêu cầu. Mỗi lần
+ chạy còn ghi lại ứng dụng của bạn cần làm gì với từng tệp. Dòng lệnh và cửa sổ desktop, miễn
+ phí, mã nguồn mở, chạy hoàn toàn trên máy của bạn.
+
+
+ {{ template "downloadCta" . }}
+
+
+
+
+ Cửa sổ desktop, sẵn sàng ghi một lô tệp. Cùng một động cơ chạy phía sau dòng lệnh.
+
+
+
+
+
+ {{ .Facts.FormatCount }}
+
định dạng thật, mỗi định dạng mở được bằng phần mềm của nó
+
+
+ 1 byte
+
độ chính xác của mọi kích thước bạn yêu cầu, không bao giờ bị làm tròn lặng lẽ
+
+
+ 0
+
kết nối đến bất cứ đâu - không tài khoản, không telemetry, không kiểm tra cập nhật
+
+
+
+
+
Vấn đề
+
Làm một tệp kiểm thử thì dễ. Làm đúng một nghìn tệp mới là phần mệt mỏi
+
Bạn đang kiểm thử phần mềm nhận tệp từ con người. Sớm hay muộn bạn sẽ cần:
+
+
một PDF đúng 10 MB, để biết giới hạn tải lên có thật không
+
ba tệp nằm hai bên giới hạn đó, để bắt lỗi lệch một
+
10.000 tệp nhật ký, để xem tác vụ ban đêm làm gì khi thư mục lớn
+
một ZIP thật sự chứa 200 tài liệu, không phải cái vỏ rỗng với đuôi đúng
+
một tệp 4 GB, mà không phải giữ tệp 4 GB trong kho mã của bạn
+
các fixture giống hệt trên laptop và trên máy chủ build, từng byte
+
+
+ Đó là thứ nó thay thế. Nó được làm cho kỹ sư QA, tự động hóa kiểm thử và bất kỳ ai có mã đứng sau là
+ biểu mẫu tải lên, quy trình nhập, bộ phân tích cú pháp hoặc hạn ngạch lưu trữ.
+
+
+
+
+
Điều làm nó khác biệt
+
Các trình tạo khác dừng ở các byte. Cái này trả lời điều bài kiểm thử của bạn thật sự hỏi
+
+ Một thư mục tệp vẫn để bạn tự quyết định mỗi tệp chứng minh điều gì. Mỗi lần chạy ở đây ghi một
+ manifest.json bên cạnh các tệp - danh sách đơn giản mọi thứ đã tạo, và với mỗi mục
+ là một kỳ vọng được khai báo.
+
+
Giả sử endpoint tải lên của bạn cho phép 1 MB. Hãy yêu cầu ba tệp nằm trên ranh giới đó:
Khi câu trả lời phụ thuộc chính sách của riêng bạn, manifest sẽ nói rõ
+
+ Nó ghi unspecified thay vì bịa ra kỳ vọng. Một trình tạo đoán mò tạo ra thất bại giả,
+ và bộ kiểm thử cứ báo động giả sẽ bị tắt.
+
+
+
+
+
+
Preset
+
Chọn câu hỏi, nhận cả bộ
+
+ Preset là một bộ tệp kiểm thử được thiết kế quanh một câu hỏi kiểm thử, để bạn không phải tự tìm ra
+ tệp nào chứng minh điều gì. Mỗi preset có một trang nói nó thường tìm thấy gì, trong bộ có gì và
+ mọi thiết lập nó nhận.
+
+ Mười nghìn tệp nhật ký, mỗi tệp từ một đến tám kilobyte, với kích thước rút từ seed để ngày mai ra
+ cùng một bộ. Cho mỗi lần chạy một thư mục riêng - manifest là bản ghi duy
+ nhất về những gì một lần chạy đã ghi, nên công cụ từ chối ghi cái thứ hai đè lên:
+
+ Kích thước đếm theo 1024, như trình quản lý tệp của bạn, nên 2mb nghĩa là 2097152 byte.
+ Số byte thuần cũng được. Tài liệu bao gồm công thức, manifest và các
+ mã thoát.
+
+
+
+
+
Bạn nhận được gì
+
Làm cho bộ kiểm thử chạy không cần người trông
+
+
+
Kích thước chính xác, đến từng byte
+
Yêu cầu 10485761 byte và nhận đúng như vậy. Kích thước mà định dạng không thể đạt là một lỗi có lý do, không bao giờ là tệp sai kích thước.
+
+
+
{{ .Facts.FormatCount }} định dạng thật
+
Không phải số không độn kèm một phần mở rộng. PNG được tạo mở trong trình xem ảnh, DOCX mở trong Word, ZIP giải nén được. Mỗi định dạng được kiểm tra bằng các trình đọc độc lập trước khi phát hành.
+
+
+
Một manifest là một oracle kiểm thử
+
Đường dẫn, kích thước, SHA-256, định dạng, seed, phiên bản công cụ - và việc hệ thống của bạn cần làm với tệp.
+
+
+
Tái lập được
+
Cùng công thức và cùng seed, cùng các byte, trên mọi máy. Hãy commit một công thức YAML nhỏ thay vì các fixture nhị phân lớn.
+
+
+
Hai giao diện, một động cơ
+
Một dòng lệnh làm cho CI và một cửa sổ desktop cho kiểm thử khám phá. Cái nào cũng không phải bản cắt giảm của cái kia, và một bài kiểm thử so sánh chúng từng khả năng một.
+
+
+
Hoàn toàn ngoại tuyến
+
Không tài khoản, không đám mây, không telemetry, không kiểm tra cập nhật. Bản nhị phân dòng lệnh hoàn toàn không biên dịch sẵn ngăn xếp mạng.
+
+
+
+
+
+
Tải xuống
+
Chọn bản dựng cho hệ thống của bạn
+
+ Giải nén kho lưu trữ rồi chạy. tfg là dòng lệnh và tfg-gui là cửa sổ
+ desktop. Không có trình cài đặt và không có gì phải thêm vào máy của bạn.
+
+ {{ template "downloadsTable" . }}
+
+
Cái nào được ký, cái nào không
+
+ Bản tải cho Windows và macOS đã được ký, nên khởi động mà không có cảnh báo nhà phát triển không xác
+ định. Bản Linux thì không, vì Linux desktop không có gì tương đương để ký. Mỗi kho lưu trữ
+ được liệt kê trong verify-SHA256SUMS.txt trên trang phát hành, để bạn kiểm tra
+ thứ mình đã tải.
+
+ Preset {{ .ID }} dựng bằng một lệnh cả một bộ tệp kiểm thử thật cho câu hỏi này, kèm
+ một manifest.json bên cạnh nêu cách hệ thống của bạn cần phản ứng với từng tệp. Mọi
+ thứ bên dưới được đọc từ chương trình, ở các giá trị mặc định của phiên bản này.
+
+
+{{ if .Catches }}
+
+
Nó thường tìm thấy gì?
+
+ {{- range .Catches }}
+
{{ . }}
+ {{- end }}
+
+
+{{ end }}
+
+
+
Trong bộ có gì?
+
Ở các giá trị mặc định, như tfg preset show {{ .ID }} báo cáo:
+
+
+
+
Tệp
{{ .Budget.Files }}
+
Target trong công thức của nó
{{ .Budget.Targets }}
+
Tổng kích thước
{{ .Bytes }} B
+
Định dạng
{{ join .Budget.Formats ", " }}
+
+
+
+
Và điều manifest của bộ đó mong đợi từ hệ thống của bạn:
+
+
+
+
Mong đợi
Ý nghĩa
Tệp
+
+
+ {{- range .Outcomes }}
+
{{ .Name }}
{{ .Meaning }}
{{ .Count }}
+ {{- end }}
+
+
+
+
+
+
+
Bạn có thể đổi gì?
+ {{- if .Settings }}
+
+
+
+
Thiết lập
Nhận
Mặc định
Tác dụng
+
+
+ {{- range .Settings }}
+
+
--{{ .Flag }}
+
{{ .Takes }}
+
{{ .Default }}
+
{{ .Detail }}{{ if .Placeholder }} Giá trị mặc định này là giá trị tạm của chúng tôi, không phải giá trị của hệ thống bạn. Hãy truyền giá trị của riêng bạn.{{ end }}
+
+ {{- end }}
+
+
+
+ {{- else }}
+
Preset này không có thiết lập. Bộ luôn giống nhau mỗi lần.
+ {{- end }}
+
+
+
+
Chạy nó thế nào?
+
Xem bộ sẽ tốn bao nhiêu, dựng nó, hoặc lấy công thức của nó để chỉnh sửa:
Hoặc xây trên nó trong công thức của riêng bạn, bên cạnh các bài kiểm thử:
+
version: 1
+extends: preset:{{ .ID }}
+{{- with .Placeholders }}
+with:
+{{- range . }}
+ {{ .Flag }}: {{ .Default }}
+{{- end }}
+{{- end }}
+
+{{ end }}
diff --git a/web/content/vi/presets.html b/web/content/vi/presets.html
new file mode 100644
index 00000000..20d1127c
--- /dev/null
+++ b/web/content/vi/presets.html
@@ -0,0 +1,31 @@
+
Preset tệp kiểm thử, một bộ cho mỗi câu hỏi kiểm thử
+
+ Preset là cả một bộ tệp kiểm thử được thiết kế quanh một câu hỏi, kèm manifest nêu cách hệ thống của
+ bạn cần phản ứng với từng tệp. Bạn chọn câu hỏi, công cụ dựng bộ. Mỗi preset có trang riêng nói nó
+ thường tìm thấy gì, trong bộ có gì và mọi thiết lập nó nhận.
+
+
+{{ template "presetsList" . }}
+
+
+
Preset khác công thức thế nào?
+
+ Về bản chất thì không khác. Preset là công thức mà công cụ viết cho bạn từ vài thiết lập. tfg
+ preset eject in công thức đó ra để bạn giữ cạnh các bài kiểm thử và chỉnh sửa, và công
+ thức của riêng bạn có thể xây trên một preset bằng một dòng, extends: preset: theo
+ sau là id của nó.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Tôi có thể tin các giá trị mặc định không?
+
+ Với các tệp thì có. Với con số chỉ hệ thống của bạn biết, như giới hạn của một biểu mẫu tải lên, giá
+ trị mặc định là giá trị tạm của chúng tôi, và công cụ nói vậy mỗi lần dùng một giá trị như thế.
+ Trang của mỗi preset đánh dấu các thiết lập đó, và tfg preset show nói điều đó
+ trước khi ghi bất cứ gì.
+
+
diff --git a/web/content/vi/site.json b/web/content/vi/site.json
new file mode 100644
index 00000000..f6f73567
--- /dev/null
+++ b/web/content/vi/site.json
@@ -0,0 +1,328 @@
+{
+ "code": "vi",
+ "locale": "vi_VN",
+ "name": "Tiếng Việt",
+ "dir": "vi",
+ "pages": [
+ {
+ "key": "index",
+ "slug": "",
+ "nav": "Trang chủ",
+ "title": "Trình tạo tệp kiểm thử cho QA - kích thước chính xác, {{ .Facts.FormatCount }} định dạng",
+ "description": "Trình tạo tệp kiểm thử miễn phí, mã nguồn mở cho QA. Tệp PDF, DOCX, PNG, ZIP thật đúng kích thước, kèm manifest nêu cách hệ thống của bạn cần phản ứng."
+ },
+ {
+ "key": "formats",
+ "slug": "dinh-dang",
+ "nav": "Định dạng",
+ "title": "{{ .Facts.FormatCount }} định dạng tệp được hỗ trợ - PDF, DOCX, PNG, ZIP và hơn nữa",
+ "description": "Mọi định dạng tệp mà trình tạo này tạo ra, tệp nhỏ nhất có thể của mỗi định dạng và các thiết lập nó nhận. Cả {{ .Facts.FormatCount }} đều mở được bằng phần mềm của chúng."
+ },
+ {
+ "key": "presets",
+ "slug": "preset",
+ "nav": "Preset",
+ "title": "Preset tệp kiểm thử - bộ tệp dựng sẵn cho câu hỏi QA",
+ "description": "Các bộ tệp kiểm thử dựng sẵn, mỗi bộ trả lời một câu hỏi kiểm thử: giới hạn tải lên, tên tệp, mã hóa, nhập bảng, tệp rỗng và kiểm tra hợp lệ."
+ },
+ {
+ "key": "docs",
+ "slug": "tai-lieu",
+ "nav": "Tài liệu",
+ "title": "Tài liệu - lệnh, công thức, manifest, mã thoát",
+ "description": "Cách tạo tệp kiểm thử từ dòng lệnh hoặc công thức YAML, manifest chứa gì và mỗi mã thoát có nghĩa gì khi công cụ chạy trong CI."
+ },
+ {
+ "key": "use-cases",
+ "slug": "truong-hop-su-dung",
+ "nav": "Trường hợp sử dụng",
+ "title": "Trường hợp sử dụng - giới hạn tải lên, fixture CI, kiểm thử",
+ "description": "Kiểm thử giới hạn kích thước tải lên, dựng fixture tái lập được cho CI, tạo mười nghìn tệp và nhồi nội dung thật vào tệp nén."
+ },
+ {
+ "key": "exact-size",
+ "slug": "tao-tep-kich-thuoc-chinh-xac",
+ "nav": "Kích thước chính xác",
+ "title": "Cách tạo tệp có kích thước chính xác - Windows, Linux, macOS",
+ "description": "fsutil, dd, truncate và mkfile, mỗi lệnh được đo trên hệ thống của nó, và vì sao tệp tạo kiểu đó không phải PDF hay PNG khi bài kiểm thử cần."
+ },
+ {
+ "key": "faq",
+ "slug": "faq",
+ "nav": "FAQ",
+ "title": "FAQ - câu hỏi về việc tạo tệp kiểm thử",
+ "description": "Khác gì dd và fsutil, tệp có commit an toàn không, các lần chạy có giống từng byte không và chuyện gì xảy ra khi không đạt được kích thước."
+ },
+ {
+ "key": "damage",
+ "slug": "tep-kiem-thu-bi-hong",
+ "nav": "Tệp bị hỏng",
+ "title": "Tệp kiểm thử bị hỏng - tệp hỏng đúng kích thước",
+ "description": "Một tệp cố ý làm hỏng, đúng kích thước, với manifest nói hệ thống của bạn phải từ chối nó. Để kiểm thử xác thực tải lên và trình phân tích cú pháp.",
+ "parent": "use-cases"
+ },
+ {
+ "key": "ci",
+ "slug": "tep-kiem-thu-trong-ci",
+ "nav": "Tệp kiểm thử trong CI",
+ "title": "Tệp kiểm thử trong CI - GitHub Actions, GitLab CI và PowerShell",
+ "description": "Tạo tệp kiểm thử trong pipeline thay vì commit tệp nhị phân: workflow GitHub Actions, job GitLab, mã thoát và cái bẫy của PowerShell.",
+ "parent": "use-cases"
+ }
+ ],
+ "words": {
+ "skip": "Chuyển đến nội dung",
+ "navLabel": "Chính",
+ "langLabel": "Ngôn ngữ",
+ "breadcrumbHome": "Trang chủ",
+ "imageAlt": "Testing Files Generator - tệp kiểm thử thật đúng kích thước, kèm manifest nêu cách hệ thống của bạn cần phản ứng với từng tệp",
+ "schemaDescription": "Trình tạo tệp kiểm thử miễn phí, mã nguồn mở cho QA. Nó tạo tệp thật ở {{ .Facts.FormatCount }} định dạng, đúng kích thước, và ghi manifest nêu cách hệ thống được kiểm thử cần phản ứng với từng tệp.",
+ "ctaDownload": "Tải xuống",
+ "ctaSource": "Xem mã nguồn",
+ "ctaNote": "Miễn phí, mã nguồn mở, GPL-3.0. Không cần đăng ký. Bản tải cho Windows và macOS đã được ký nên khởi động không cảnh báo.",
+ "colFormat": "Định dạng",
+ "colName": "Tên",
+ "colExtension": "Phần mở rộng",
+ "colSmallest": "Tệp nhỏ nhất",
+ "colFidelity": "Độ đầy đủ",
+ "colChecked": "Kiểm tra bằng",
+ "colSetting": "Thiết lập",
+ "colAccepts": "Chấp nhận",
+ "colSystem": "Hệ thống",
+ "colCli": "Dòng lệnh",
+ "colWindow": "Cửa sổ desktop",
+ "noBinary": "chưa có bản nhị phân",
+ "colCode": "Mã",
+ "colMeaning": "Ý nghĩa",
+ "footerBlurb": "Tệp kiểm thử cho QA, đúng kích thước, kèm manifest nêu cách hệ thống của bạn cần phản ứng với từng tệp.",
+ "footerProject": "Dự án",
+ "footerSource": "Mã nguồn trên GitHub",
+ "footerReleases": "Tải xuống",
+ "footerIssues": "Báo lỗi",
+ "footerSupport": "Ủng hộ dự án",
+ "footerPages": "Trang",
+ "footerLicence": "Copyright (C) 2026 DonislawDev. Phát hành theo Giấy phép Công cộng GNU, phiên bản 3. Tệp bạn tạo ra là của bạn - giấy phép áp dụng cho công cụ, không áp dụng cho kết quả của nó.",
+ "footerPrivacy": "Trang này không tải phông chữ, tập lệnh hay công cụ theo dõi từ bất kỳ đâu. Nó không đặt cookie.",
+ "notFoundTitle": "Trang này không có ở đây",
+ "notFoundLead": "Địa chỉ bạn vừa theo không khớp với trang nào trên trang web này.",
+ "notFoundBack": "Về trang chủ",
+ "read.format": "Định dạng của mọi tệp trong bộ. Đây là một cờ của chính công cụ, và preset chỉ cho nó một giá trị mặc định.",
+ "readTakes.format": "id định dạng từ trang định dạng",
+ "colDamage": "Hỏng hóc",
+ "colEffect": "Nó làm gì với các byte",
+ "colSettings": "Cài đặt",
+ "noSettings": "không có"
+ },
+ "endings": {
+ "0": "Mọi thứ đều chạy tốt.",
+ "1": "Lỗi bất ngờ bên trong công cụ.",
+ "2": "Lệnh hoặc cờ sai.",
+ "3": "Công thức không hợp lệ.",
+ "4": "Định dạng không làm được điều được yêu cầu.",
+ "5": "Đọc hoặc ghi thất bại.",
+ "6": "Không đủ dung lượng đĩa.",
+ "7": "verify phát hiện sai lệch.",
+ "8": "Lần chạy đã xong nhưng không phải mọi thứ đều được tạo.",
+ "130": "Bị ngắt bằng Ctrl+C.",
+ "143": "Bị dừng bởi một tín hiệu, đó là hình dạng của việc CI hết thời gian."
+ },
+ "presets": {
+ "empty-and-minimal": {
+ "question": "Một tệp hợp lệ và nhỏ nhất mà định dạng cho phép có qua được không?",
+ "title": "Rỗng và tối thiểu",
+ "pageTitle": "Tệp kiểm thử hợp lệ nhỏ nhất và tệp rỗng ở mọi định dạng",
+ "description": "Tệp hợp lệ nhỏ nhất mà công cụ ghi ở mỗi trong {{ .Facts.FormatCount }} định dạng, cộng tệp rỗng nơi định dạng cho phép, mỗi tệp kèm phản ứng cần có.",
+ "catches": [
+ "tệp hợp lệ bị từ chối vì quá nhỏ, khi bước kiểm tra đếm byte thay vì đọc chúng",
+ "tệp rỗng làm trình đọc sập thay vì được báo cáo",
+ "ảnh rộng một pixel chia cho không trên đường tạo ảnh thu nhỏ",
+ "bộ lưu trữ đọc không byte như một lần tải lên thất bại và cứ thử lại mãi"
+ ],
+ "details": {
+ "formats": "Bộ được dựng từ những định dạng nào. Để all cho mọi định dạng của bản dựng này, hoặc nêu những định dạng hệ thống của bạn chấp nhận."
+ }
+ },
+ "filename-handling": {
+ "question": "Hệ thống của tôi có lưu, hiển thị và trả lại một tên tệp mà nó không ngờ tới không?",
+ "title": "Xử lý tên tệp",
+ "pageTitle": "Tên tệp gây rắc rối để kiểm thử - Unicode và độ dài",
+ "description": "Tệp có tên làm hỏng việc tải lên và lưu trữ: chữ viết khác và emoji, đảo chiều văn bản, ký tự vô hình, cú pháp shell và SQL, giới hạn độ dài.",
+ "catches": [
+ "một tên trông như tên khác trên màn hình, trong nhật ký hoặc trong danh sách",
+ "một tên bị cắt, xén hoặc viết lại giữa lúc tải lên và lưu trữ",
+ "giới hạn độ dài tính bằng ký tự trong khi bộ lưu trữ tính bằng byte"
+ ],
+ "details": {}
+ },
+ "size-boundaries": {
+ "question": "Giới hạn kích thước có được áp dụng đúng nơi nó được khai báo không?",
+ "title": "Ranh giới kích thước",
+ "pageTitle": "Kiểm thử giới hạn kích thước tải lên - tệp đúng ranh giới",
+ "description": "Tệp thấp hơn một byte, đúng bằng và cao hơn một byte so với giới hạn hệ thống bạn khai báo, cùng các bước rộng hơn hai phía, mỗi tệp đánh dấu có nên được chấp nhận.",
+ "catches": [
+ "lỗi lệch một ở giới hạn",
+ "nhầm MB với MiB, tức 4,8 phần trăm và đủ để lọt một tệp lẽ ra không được qua",
+ "giới hạn được áp dụng ở trình duyệt chứ không phải ở máy chủ"
+ ],
+ "details": {
+ "limit": "Giới hạn kích thước mà hệ thống của bạn khai báo. Mọi thứ khác được đo từ đó.",
+ "spread": "Vươn ra xa bao nhiêu về hai phía của giới hạn, dưới dạng danh sách kích thước."
+ }
+ },
+ "tabular-import": {
+ "question": "Việc nhập bảng của tôi có chịu được những gì công cụ thật xuất ra không?",
+ "title": "Nhập bảng",
+ "pageTitle": "Tệp kiểm thử nhập CSV và Excel - dấu phân cách, tiêu đề",
+ "description": "CSV với dấu phân cách khác, kết thúc dòng CR LF, không tiêu đề và dấu trích dẫn khác, bảng rất rộng, sổ làm việc Excel và JSON ở vài bố cục.",
+ "catches": [
+ "tệp dùng dấu chấm phẩy bị đọc thành một cột, vì dấu phân cách được giả định thay vì được dò tìm",
+ "tệp CRLF bị tách thành các dòng với một dòng trống sau mỗi dòng",
+ "bảng không có tiêu đề mà dòng dữ liệu đầu bị nuốt làm tên cột",
+ "lần nhập giữ các cột nó hiển thị được và lặng lẽ bỏ phần còn lại",
+ "trình đọc lấy bản ghi JSON từng dòng một và dừng ở tài liệu thụt lề đầu tiên"
+ ],
+ "details": {
+ "rows": "Bảng tính có bao nhiêu dòng. Tệp được ghi đúng bằng kích thước mà chừng đó dòng đóng gói thành, nên ngân sách ở trên dịch chuyển theo giá trị này.",
+ "columns": "Mỗi dòng của bảng tính có bao nhiêu cột. Số dòng nhân số cột có trần, và yêu cầu vượt trần sẽ bị từ chối trước khi ghi bất cứ thứ gì."
+ }
+ },
+ "text-encoding": {
+ "question": "Trình đọc của tôi có biết tệp ở mã hóa nào, hay chỉ đoán?",
+ "title": "Mã hóa văn bản",
+ "pageTitle": "Tệp kiểm thử mã hóa văn bản - UTF-8, UTF-16, BOM, CRLF",
+ "description": "Cùng một văn bản ở UTF-8, UTF-16LE và UTF-16BE, có và không có dấu thứ tự byte, cùng kết thúc dòng CR LF và LF, để kiểm thử cách trình đọc giải mã.",
+ "catches": [
+ "trình đọc giả định UTF-8 và hiện tệp UTF-16 thành cứ ba ký tự mới có một, hoặc thành hàng ô vuông",
+ "dấu thứ tự byte bị đọc như nội dung, nên trường đầu tiên của lần nhập bắt đầu bằng ba ký tự lạ",
+ "trình nhập đoán mã hóa từ các byte đầu và đoán khác đi với tệp dài hơn",
+ "tệp CRLF bị tách thành các dòng với một dòng trống sau mỗi dòng, hoặc ký tự xuống dòng còn sót trong trường cuối"
+ ],
+ "details": {
+ "sample": "Mỗi tệp trong bộ lớn bao nhiêu. UTF-16 lưu hai byte cho mỗi ký tự, nên số lẻ bị từ chối."
+ }
+ },
+ "upload-validation": {
+ "question": "Biểu mẫu tải lên của tôi có nhận đúng thứ nó cần và từ chối phần còn lại không?",
+ "title": "Kiểm tra tải lên",
+ "pageTitle": "Tệp kiểm thử kiểm tra tải lên - loại, kích thước và tên",
+ "description": "Tệp để kiểm thử biểu mẫu tải lên: loại được phép và bị cấm, nội dung không khớp phần mở rộng, giới hạn kích thước, tên độc hại và tải lên hàng loạt.",
+ "catches": [
+ "giới hạn được áp dụng ở trình duyệt chứ không phải ở máy chủ",
+ "tệp SVG hoặc HTML bị tưởng là ảnh hay văn bản thuần, một cách để lách tập lệnh qua biểu mẫu",
+ "tệp chỉ được kiểm bằng phần mở rộng mà không bao giờ mở, nên PDF đặt tên .jpg vẫn qua",
+ "biểu mẫu đọc cả phần thân vào bộ nhớ trước khi xem nó lớn đến đâu",
+ "lần tải lên tên PHOTO.JPG bị từ chối trong khi photo.jpg được nhận, hoặc ngược lại",
+ "tên có dấu cách, ngoặc hoặc ký tự ngoài ASCII được ghi xuống đĩa không thay đổi"
+ ],
+ "details": {
+ "limit": "Giới hạn kích thước mà biểu mẫu tải lên của bạn khai báo. Bộ này đi một bước về mỗi phía - muốn tệp ở mọi khoảng cách, hãy chạy preset size-boundaries.",
+ "allow": "Biểu mẫu của bạn nên chấp nhận những loại nào. Mỗi loại trở thành một tệp thật thuộc loại đó, và chúng là đối chứng dương của cả bộ.",
+ "deny": "Biểu mẫu của bạn nên từ chối những phần mở rộng nào. Phần mở rộng mà bản dựng này không có định dạng vẫn nhận một tệp mang tên đó, chứa văn bản thuần.",
+ "far-over": "Tệp lớn duy nhất vượt giới hạn bao xa. Tắt đi nếu ghi gấp nhiều lần giới hạn không đáng với dung lượng đĩa.",
+ "bulk": "Số tệp trong lần tải lên hàng loạt. Bằng không thì bỏ hẳn nhóm đó khỏi bộ."
+ }
+ }
+ },
+ "commands": {
+ "generate": "tạo tệp, từ công thức hoặc từ các cờ",
+ "validate": "kiểm tra công thức và không ghi gì cả",
+ "verify": "kiểm tra một thư mục đối chiếu với manifest",
+ "cleanup": "xóa các tệp mà manifest liệt kê",
+ "recipe fmt": "in công thức ở dạng chuẩn hóa",
+ "preset": "dựng một bộ tệp từ một câu hỏi kiểm thử có tên",
+ "formats": "liệt kê các định dạng bản dựng này hỗ trợ",
+ "damage": "liệt kê các cách bản dựng này có thể cố ý làm hỏng một tệp",
+ "tool": "các tiện ích nhỏ cho tệp bạn đã có",
+ "version": "in phiên bản công cụ",
+ "license": "in giấy phép và ý nghĩa của nó với tệp được tạo"
+ },
+ "outcomes": {
+ "accept": "Hệ thống của bạn nên nhận tệp.",
+ "reject": "Hệ thống của bạn nên từ chối tệp.",
+ "sanitize": "Hệ thống của bạn nên nhận tệp và làm sạch nó, ví dụ bằng cách đổi tên.",
+ "unspecified": "Tùy vào quy tắc của hệ thống bạn. Bạn quyết định, rồi kiểm tra điều xảy ra có đúng ý bạn không."
+ },
+ "damages": {
+ "zero-head": "Ghi đè các byte đầu của tệp bằng số không, giữ nguyên độ dài. Hầu hết trình đọc nhìn vào đó trước, nên gần như mọi thứ đều nhận ra hỏng hóc này."
+ },
+ "terms": {
+ "oracleNone": "không áp dụng",
+ "int": "số nguyên bất kỳ",
+ "choice": "một trong một tập cố định",
+ "bool": "đúng hoặc sai",
+ "size": "kích thước như 2mb",
+ "text": "văn bản",
+ "pixels": "pixel",
+ "paragraphs": "đoạn văn",
+ "rows": "dòng",
+ "columns": "cột",
+ "slides": "trang chiếu",
+ "hertz": "hertz",
+ "megapixels": "megapixel",
+ "million cells": "triệu ô",
+ "entries per second": "mục mỗi giây",
+ "files": "tệp",
+ "sizes separated by commas": "các kích thước cách nhau bằng dấu phẩy",
+ "format ids separated by commas": "các id định dạng cách nhau bằng dấu phẩy",
+ "format ids separated by commas, or all": "các id định dạng cách nhau bằng dấu phẩy, hoặc all",
+ "extensions separated by commas": "các phần mở rộng cách nhau bằng dấu phẩy",
+ "the id of a format, as tfg formats lists them": "id của một định dạng, như tfg formats liệt kê",
+ "the password, in plain text": "mật khẩu, ở dạng văn bản thuần",
+ "any text": "văn bản bất kỳ",
+ "a date such as 2024-02-29 or 2024-02-29T13:45:00+02:00, or none": "ngày như 2024-02-29 hoặc 2024-02-29T13:45:00+02:00, hoặc none"
+ },
+ "faq": [
+ {
+ "q": "Điều này khác gì dd, fsutil hay truncate?",
+ "a": "Chúng cho bạn một tệp đúng kích thước nhưng đầy sự trống rỗng. Tệp 2 MB tên photo.png tạo kiểu đó không phải PNG, nên bất cứ thứ gì thực sự phân tích nó sẽ từ chối vì lý do sai, và bài kiểm thử của bạn cũng qua vì lý do sai. Công cụ này tạo ra một PNG thật đúng 2 MB, mở được trong trình xem ảnh, và đi kèm lời khai về cách hệ thống của bạn cần xử lý nó.",
+ "code": "tfg generate --format png --size 2mb --out ./fixtures"
+ },
+ {
+ "q": "Nó có miễn phí không, và tôi dùng ở chỗ làm được không?",
+ "a": "Có cho cả hai. Nó phát hành theo GPL-3.0 và không tốn gì. Không có tài khoản, khóa giấy phép hay gói trả phí."
+ },
+ {
+ "q": "Tôi có dùng tệp được tạo trong sản phẩm mã nguồn đóng được không?",
+ "a": "Được. Giấy phép áp dụng cho mã của công cụ, không áp dụng cho thứ công cụ tạo ra. Tệp, công thức và manifest được tạo là đầu ra chứ không phải tác phẩm phái sinh, nên bạn có thể commit và phân phối mà không có nghĩa vụ nào."
+ },
+ {
+ "q": "Tệp được tạo có chứa dữ liệu cá nhân thật không?",
+ "a": "Không. Mọi thứ bên trong đều được tổng hợp từ một seed. Không có tập dữ liệu nào được đọc, không dịch vụ nào được liên hệ và không nội dung bên thứ ba nào được nhúng. Hãy coi địa chỉ e-mail được tạo là không dùng được thay vì chưa dùng, vì chuỗi ngẫu nhiên nào cũng có thể ngẫu nhiên trùng với địa chỉ thật."
+ },
+ {
+ "q": "Tôi có nhận đúng các tệp giống hệt trên máy khác không?",
+ "a": "Có, từng byte, với cùng công thức và cùng seed. Dự án kiểm thử điều đó ở mỗi thay đổi, và phá vỡ nó đòi hỏi tăng phiên bản chính. Đó là điều cho phép bạn commit một công thức nhỏ thay vì các fixture nhị phân lớn."
+ },
+ {
+ "q": "Nó có cần kết nối internet không?",
+ "a": "Không bao giờ. Không có telemetry, không kiểm tra cập nhật và không có máy khách đám mây, và bản nhị phân dòng lệnh hoàn toàn không biên dịch sẵn ngăn xếp mạng. Nó chạy trên máy không có mạng và trong môi trường doanh nghiệp đóng."
+ },
+ {
+ "q": "Chuyện gì xảy ra nếu tôi yêu cầu kích thước mà một định dạng không thể đạt tới?",
+ "a": "Bạn nhận một lỗi nêu định dạng, kích thước nhỏ nhất có thể, lý do của mức sàn đó và việc nên làm thay thế, và không có tệp nào được ghi. Công cụ không bao giờ làm tròn kích thước một cách lặng lẽ. Mỗi mức sàn đều được liệt kê trên trang định dạng.",
+ "code": "tfg formats png"
+ },
+ {
+ "q": "Tôi có thể tạo một tệp cố ý bị hỏng không?",
+ "a": "Có. Thêm --damage zero-head và tệp ra đúng kích thước bạn yêu cầu, với các byte đầu bị ghi đè bằng số không, nên trình đọc từ chối nó, và manifest nói hệ thống của bạn phải từ chối nó. Chi tiết nằm ở trang về tệp kiểm thử bị hỏng.",
+ "code": "tfg generate --format png --size 2mb --damage zero-head --out ./out"
+ },
+ {
+ "q": "Những định dạng nào sắp có?",
+ "a": "7z, mp3 và mp4. Hôm nay có {{ .Facts.FormatCount }} định dạng hoạt động trọn vẹn từ đầu đến cuối."
+ },
+ {
+ "q": "Tôi chạy nó trên những hệ thống nào?",
+ "a": "Dòng lệnh chạy trên Windows và Linux cả Intel lẫn ARM, và trên Mac Apple Silicon. Cửa sổ desktop được cung cấp cho Windows trên Intel, Linux trên Intel và Mac Apple Silicon. Mac Intel không được hỗ trợ và không có gì được dựng cho chúng."
+ },
+ {
+ "q": "Tôi có phải cài gì không?",
+ "a": "Không. Tải kho lưu trữ cho hệ thống của bạn, giải nén và chạy bản nhị phân. Không có trình cài đặt, không có runtime cần thêm và không có phụ thuộc cần giải quyết. Nếu bạn có Go, một lệnh go install duy nhất cũng được.",
+ "code": "go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest"
+ },
+ {
+ "q": "Vì sao chạy trên hàng nghìn tệp chậm hơn trên Windows?",
+ "a": "Vì Windows tính phí nhiều hơn cho mỗi đường dẫn nó xem, và một lệnh duyệt hàng nghìn tệp xem hàng nghìn đường dẫn. Đo trên một máy với 3000 tệp 1 kB, verify mất khoảng 0,9 giây trên Windows và khoảng 0,2 giây trên Linux trong container. Đường dẫn đầu ra ngắn hơn làm con số Windows nhỏ đi, vì mỗi thư mục phía trên các tệp đều nằm trong thứ được xem."
+ }
+ ]
+}
diff --git a/web/content/vi/use-cases.html b/web/content/vi/use-cases.html
new file mode 100644
index 00000000..3c1cc6aa
--- /dev/null
+++ b/web/content/vi/use-cases.html
@@ -0,0 +1,129 @@
+
Mọi người dùng nó để làm gì
+
+ Năm việc xuất hiện trong gần như mọi dự án nhận tệp từ con người, và lệnh làm từng việc. Mỗi ví dụ
+ bên dưới chạy đúng như được viết.
+
+
+
+
Giới hạn tải lên
+
Kiểm thử xem giới hạn kích thước tệp có được áp dụng đúng nơi nó nói không
+
+ Một giới hạn là ba trường hợp kiểm thử chứ không phải một: ngay dưới, đúng bằng và ngay trên. Làm
+ tay thì phải tính số byte và hy vọng không lệch một. Hãy yêu cầu cả bộ:
+
+ Bạn nhận ba PDF thật có 1048575, 1048576 và 1048577 byte, cùng manifest nói hai tệp đầu nên được
+ chấp nhận và tệp thứ ba bị từ chối vì size_limit. Bài kiểm thử của bạn đọc kỳ vọng
+ thay vì bạn viết tay ba câu khẳng định - và khi giới hạn đổi, bạn đổi một con số rồi chạy lại.
+
+
+ Điều tương tự dùng được không cần preset khi bạn muốn một bộ ranh giới đơn ngay trong lệnh:
+
+ Fixture nhị phân lớn làm kho mã clone chậm và khó review, và không ai biết cái gì đã đổi khi thay
+ một tệp. Công thức là vài trăm ký tự YAML dựng lại các tệp giống hệt - từng byte, trên
+ mọi máy - vì mọi tệp đều suy ra từ seed của lần chạy.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Mỗi kết cục có mã thoát riêng, nên pipeline phân biệt được công thức xấu, đĩa đầy và sai lệch khi
+ xác minh. Lần chạy thất bại không in gì ra đầu ra chuẩn, nhờ vậy trình phân tích nhật ký không
+ đọc lỗi thành dữ liệu.
+
+
+
+
+
Quy mô
+
Tìm hiểu chuyện gì xảy ra khi thư mục lớn
+
+ Quy trình nhập, tác vụ ban đêm và danh sách thư mục hoạt động khác nhau ở mười nghìn tệp so với mười
+ tệp. Kích thước rút từ một khoảng làm bộ trông như lưu lượng thật thay vì mười nghìn tệp giống
+ hệt, và lần rút lấy từ seed, nên bộ ngày mai vẫn như cũ.
+
+ Độ sâu lồng nhau, số mục và kích thước phần bên trong đều là những thứ mà quy trình nhập có ý kiến
+ riêng, và đây là cách bạn biết ý kiến đó là gì.
+
+
+
+
+
Bộ phân tích và trình xem
+
Kiểm tra mã của chính bạn đọc một định dạng như phần mềm thật
+
+ Mỗi định dạng ở đây được kiểm tra bằng trình đọc độc lập trước khi phát hành - PNG được mở và so
+ sánh pixel, DOCX được các thư viện riêng đọc lại, tệp nén được giải nén. Nghĩa là tệp mà bộ phân
+ tích của bạn từ chối là một phát hiện về bộ phân tích của bạn, không phải về trình tạo.
+
+ Trang định dạng liệt kê các thiết lập mỗi định dạng nhận và tệp nhỏ
+ nhất mà mỗi định dạng có thể có.
+
+
+
+
+
Hướng dẫn
+
Hai trong số đó, chi tiết hơn
+
+
+ Tệp kiểm thử bị hỏng - một tệp cố ý làm hỏng, đúng kích
+ thước, với điều phải xảy ra với nó được ghi trong manifest.
+
+
+ Tệp kiểm thử trong CI - một workflow GitHub Actions, một
+ job GitLab và các mã thoát làm bản dựng thất bại.
+
+
+
+
+
+
Dành cho ai
+
+ Kỹ sư QA, tự động hóa kiểm thử và bất kỳ ai có mã đứng sau là biểu mẫu tải lên, quy trình nhập, bộ
+ phân tích cú pháp hoặc hạn ngạch lưu trữ. Nó chạy trên máy hoàn toàn không có mạng, điều quan
+ trọng trong môi trường doanh nghiệp đóng nơi trình tạo chạy trên trình duyệt không phải một lựa
+ chọn.
+
+ {{ template "downloadCta" . }}
+
diff --git a/web/content/zh-Hans/ci.html b/web/content/zh-Hans/ci.html
new file mode 100644
index 00000000..7cb9c3dd
--- /dev/null
+++ b/web/content/zh-Hans/ci.html
@@ -0,0 +1,170 @@
+{{ with .Up }}
+ المدقق الذي لم يُعرض عليه إلا ملفات سليمة لم يُختبر حقًّا. إليك طريقة الحصول على ملف أُتلف عمدًا،
+ ويخرج بالحجم الذي تطلبه تمامًا، ويحمل بيانًا يقول ما الذي ينبغي أن يفعله نظامك
+ به.
+
+
+
+
الجواب المختصر
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out يكتب ملف PNG حجمه
+ 2097152 بايتًا بالضبط، وبايتاته الأولى أصفار، ويسجّل البيان المجاور له أن نظامك ينبغي أن يرفضه.
+
+
+
+
+
الطريقة المعتادة
+
لماذا يُعدّ الملف المتلف يدويًا اختبارًا رديئًا
+
+ الطرق المعتادة هي محرر سداسي عشري، أو سكربت يقلب بضع بايتات عشوائية، أو قصّ الملف بـ
+ head أو truncate. تنجح مرة واحدة، ثم تكلّفك:
+
+
+
+ يختلف في كل مرة. البايت العشوائي يقع في مكان جديد عند كل تشغيل، فقد لا يعود فشل يوم
+ الثلاثاء يوم الأربعاء.
+
+
+ يغيّر الحجم. الملف المقصوص أصغر من الحد الذي كان ينبغي أن يبقى تحته، فيجيب فحص
+ الحجم قبل فحص المحتوى، ويمرّ الاختبار لسبب خاطئ.
+
+
+ كثيرًا ما يمرّ دون أن يلاحظه أحد. النص العادي يبقى مقروءًا مع تغيير بايت في الوسط،
+ وقارئ الصور المتسامح يرسمه ببساطة، فيُقبل الملف الذي كان يُفترض أن يكون تالفًا.
+
+
+ لا يقول شيئًا عمّا ينبغي أن يحدث. الملف مجرد بايتات، ومن يقرأ الاختبار لاحقًا عليه
+ أن يخمّن هل كان المقصود القبول أم الرفض.
+
+
+
+
+
+
ما تحصل عليه
+
الملف التالف يبقى بالحجم الذي طلبته
+
+ يُولَّد الملف كالمعتاد ثم يُتلَف في طريقه إلى القرص. يحتفظ بالحجم الذي طلبته، ويكتب الأمر نفسه
+ البايتات نفسها مرة أخرى.
+
+ تُكتب الإعدادات بعد النقطتين. يمكن تكرار الخيار، وتُطبَّق أنواع التلف بالترتيب الذي تكتبه. ويعمل مع
+ كل واحدة من 26 صيغة.
+
+
+
+
+
ما الذي يستطيعه
+
ما أنواع التلف المتاحة؟
+
+ هذه هي القائمة التي يطبعها البرنامج، وتُقرأ منه عند بناء هذه الصفحة. يطبع tfg damage
+ القائمة نفسها، ويبيّن tfg damage <id> ما يقبله واحد منها.
+
+
+
+
+
+
التلف
+
ما يفعله بالبايتات
+
أصغر ملف
+
الإعدادات
+
+
+
+
+
zero-head
+
يكتب أصفارًا فوق أول بايتات الملف دون المساس بطوله. معظم القارئات تنظر إلى هناك أولًا، فيلاحظ هذا التلف كل شيء تقريبًا.
+
8
+
bytes
+
+
+
+
+
+ يكتب zero-head أصفارًا فوق بداية الملف. معظم القارئات تنظر إلى هناك أولًا، إلى التوقيع
+ والترويسة اللذين يقولان ما هو الملف، فتلاحظ ذلك أي قارئة تقريبًا. والنص العادي والسجلات لا توقيع
+ لها وتُرفض أيضًا، لأن سلسلة من البايتات الصفرية ليست نصًّا. وتحت أربعة بايتات تخرج بعض الصيغ
+ بتلف لا تشتكي منه أي قارئة، ولهذا يبدأ الإعداد من أربعة.
+
+
+
+
+
ما يقوله البيان
+
بيان يقول ما ينبغي أن يحدث
+
+ كل ملف تالف يحصل على مدخل يقول إن نظامك ينبغي أن يرفضه، ويُسجَّل التلف بجانبه:
+
+ يُرفض طلبان قبل أن يُكتب أي شيء، لأن كلًّا منهما سيترك على القرص ملفًا يصفه البيان وصفًا خاطئًا:
+
+
+
ملف أصغر مما يحتاجه التلف، وكان سيخرج دون تغيير
+
+ expected: accept بجانب تلف، لأن لا شيء يمكنه تحقيق ذلك. اكتب sanitize إن
+ كان نظامك مقصودًا به إصلاح الملف، أو unspecified إن كان هذا هو السؤال الذي تطرحه
+
+
+
+
+
+
في وصفة
+
ملفات سليمة وتالفة في تشغيل واحد
+
+ ضع الاثنين في وصفة واحدة، فيحمل البيان المتوقَّع لكل ملف، ولا يحتاج الاختبار إلى قائمة تقول أيها
+ أيّ:
+
+ يقرأ الاختبار البيان ويتحقق من أن ما حدث هو ما أُعلن. لا يحتاج إلى قائمة بأسماء الملفات:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ الرفض الجيد هو الرفض النظيف. رسالة تقول ما الخطأ هي الجواب الذي تريده. أما خطأ الخادم أو التعليق أو
+ ملف حُفظ نصفه فهو العيب الذي وُجد هذا الاختبار لاكتشافه.
+
+ لكل نظام أمر لذلك، والثلاثة كلها أدناه. تعطيك ملفًا بعدد البايتات الصحيح تمامًا، وفي كثير من
+ الاختبارات هذا كل ما تحتاجه. كل أمر في هذه الصفحة جُرِّب قبل النشر على النظام
+ الذي ينتمي إليه.
+
+ تعني 10MB في PowerShell ما قدره 10485760 بايتًا، وهو العدّ نفسه بأساس 1024 الذي يستخدمه
+ مستكشف الملفات، فيُنتج الأمران أعلاه الحجم نفسه.
+
+
+
+
+
لينكس
+
dd وtruncate وfallocate، والفرق الذي يوقع الناس
+
dd هو الأمر الذي يعرفه الجميع. يكتب البايتات فعلًا:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate فوري، وهنا الفخ. قيس على Alpine Linux، فأبلغ الملف عن 10485760 بايتًا وشغل
+ صفر كتل، فهو ملف متناثر. كل ما يقرؤه يحصل على عشرة ميغابايت من
+ الأصفار، لكن القرص لم يتنازل عن المساحة قط:
+
+
truncate -s 10M test10mb.bin
+
+ هذا مناسب لاختبار حد الرفع، ومضلل لاختبار حصة القرص. أما fallocate فهو ما تلجأ إليه حين
+ يجب أن تكون المساحة حقيقية:
+
+
fallocate -l 10M test10mb.bin
+
وحين يجب أن يكون المحتوى غير قابل للضغط، حتى لا يستطيع أداة الأرشفة تصغيره من جديد:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
ماك
+
mkfile، وهو غير متناثر، والأمران اللذان تعرفهما بالفعل
+
+ يأتي ماك مع mkfile. قيس على macOS 26.6.2: 10485760 بايتًا و20480 كتلة، فالمساحة مخصصة
+ فعلًا لا موعودة فقط:
+
+ كل ما سبق يعطيك كتلة من الأصفار. وهذا يكفي حين لا ينظر الشيء المختبَر إلا إلى الحجم، كحد الرفع أو
+ الحصة أو النقل. ويتوقف عن الكفاية لحظة أن يفتح أي شيء الملف.
+
+
+ قيس، وهو يستحق أن تجرّبه بنفسك: أنشئ ملفًا بحجم 2 MB بـ fsutil، وسمّه
+ photo.png، وسلّمه إلى مكتبة صور. تجيب Pillow بـ cannot identify image
+ file. إنه ليس PNG. ولم يكن كذلك قط، فالاسم وحده قال ذلك.
+
+
+ هذا أهم مما يبدو، بسبب الاتجاه الذي يفشل فيه الاختبار بعد ذلك. ترفض نقطة الرفع عندك
+ الملف، فيصبح اختبارك أخضر، وتستنتج أن حد الحجم يعمل. لم ترفضه بسبب الحجم. رفضته لأن البايتات لم
+ تكن صورة، ولم تُبلَغ القاعدة التي أردت اختبارها قط.
+
+
+
محلل يرفضه قبل النظر في أي قاعدة للحجم
+
تفشل خطوة الصورة المصغرة، والخطأ الذي تقرؤه عن الصورة المصغرة
+
يرفضه برنامج مكافحة فيروسات أو فحص محتوى لسبب ثالث
+
عارض لا يظهر شيئًا، ولا أحد يستطيع الجزم إن كان هذا هو الخطأ
+
+
+
+
+
الطريق الآخر
+
ملف حقيقي من تلك الصيغة، بالحجم الذي طلبته تمامًا
+
+ هذا ما يفعله Testing Files Generator. الملف ملف أصيل من صيغته، يُفتح في البرنامج الذي يملكه، وعدد
+ بايتاته هو ما طلبته بالضبط، حتى البايت:
+
+ اطلب حجمًا لا تستطيع الصيغة بلوغه فتحصل على خطأ يذكر الحد الأدنى وسببه، لا ملفًا بحجم خاطئ أبدًا.
+ تسرد صفحة الصيغ كل صيغة مع أصغر ملف تستطيع إنتاجه.
+
+
والحد حالات اختبار ثلاث لا حالة واحدة، لذا تبني الأداة الثلاث كلها:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ وهذا يعطيك 10485759 و10485760 و10485761 بايتًا، وبيانًا يقول أيها يجب أن يقبله نظامك وأيها يجب أن
+ يرفضه. تستعرض صفحة حالات الاستخدام هذا وأربع مهام أخرى بُنيت الأداة
+ لها.
+
+ كل ما تفعله الأداة، مرتبًا على هيئة الأسئلة التي يأتي بها الناس فعلًا. ملف
+ README في المستودع هو المرجع الكامل ويطابق دائمًا الإصدار الذي
+ نزّلته.
+
+
+
+
ما الأوامر المتاحة؟
+
كل أمر يؤدي مهمة واحدة:
+
tfg generate توليد ملفات، من وصفة أو من خيارات
+tfg validate فحص وصفة دون كتابة شيء
+tfg verify فحص مجلد مقابل بيان
+tfg cleanup حذف الملفات التي يسردها بيان
+tfg recipe fmt طباعة وصفة بشكلها المستقر
+tfg preset بناء مجموعة ملفات من سؤال اختبار مُسمّى
+tfg formats سرد الصيغ التي يدعمها هذا الإصدار
+tfg damage سرد الطرق التي يستطيع بها هذا الإصدار إتلاف ملف عمدًا
+tfg tool أدوات صغيرة للملفات التي لديك بالفعل
+tfg version طباعة إصدار الأداة
+tfg license طباعة الرخصة ومعناها للملفات المولَّدة
+
+
+
+
كيف أولّد ملفًا واحدًا بحجم دقيق؟
+
+ حدد الصيغة والحجم ووجهة الملف. تُعدّ الأحجام بالمضاعفات 1024، فـ2mb تساوي 2097152
+ بايتًا. وعدد البايتات المجرد يصلح أيضًا، فـ--size 10485761 يطلب هذا العدد بالضبط.
+
+
tfg generate --format png --size 2mb --out ./out
+
الخيارات المفيدة في generate:
+
+
+
الخيار
ما يفعله
+
+
--format <id>
صيغة الملفات، مثل txt
+
--size <size>
الحجم الدقيق لكل ملف، مثل 10mb أو عدد بايتات مجرد
+
--size-range <a-b>
حجم يُسحب لكل ملف من نطاق، مثل 1kb-8kb. يأتي السحب من البذرة
+
--boundary <size>
ثلاثة ملفات حول حد: أقل بايتًا واحدًا، والحد نفسه، وأكثر بايتًا واحدًا
+
--count <n>
عدد الملفات المراد إنتاجها. الافتراضي 1
+
--name <template>
قالب الاسم، مثل invoice_{index:04}.txt
+
--out <dir>
المجلد الذي يُكتب فيه
+
--seed <n>
بذرة التشغيل. البذرة نفسها تعطي البايتات نفسها
+
--set <k>=<v>
إعداد صيغة، يمكن تكراره
+
--damage <name>
إتلاف الملفات عمدًا، يمكن تكراره ويُطبَّق بالترتيب. شغّل tfg damage للاطلاع على القائمة
+
--expected <outcome>
accept أو reject أو sanitize أو unspecified
+
--dry-run
عدّ وأظهر، ولا تكتب شيئًا إطلاقًا
+
--json
اكتب البيان إلى المخرج القياسي
+
+
+
+
+
+
+
كيف أصنع ملفًا تالفًا عمدًا؟
+
+ كل ملف آخر تكتبه هذه الأداة صحيح بحكم بنائه، وهذا يجيب عن اثنين من ثلاثة أسئلة يطرحها مدقق الرفع.
+ أما --damage فيجيب عن الثالث: هل يُفتح الملف أصلًا. يُنتَج الملف بشكل طبيعي ثم
+ يُتلف، فيبقى بالحجم الذي طلبته.
+
+ يحصل الملف التالف على expected: reject في البيان، مع تسجيل الإتلاف بجانبه. يُرفض أمران
+ قبل كتابة أي شيء، لأن كلًّا منهما كان سيضع على القرص ملفًا يصفه البيان وصفًا خاطئًا:
+
+
+
ملف أصغر مما يحتاجه الإتلاف، لأنه كان سيخرج دون تغيير
+
+ expected: accept بجانب إتلاف، لأن لا شيء يمكن أن يحققه. اكتب sanitize إن
+ كان المقصود أن يصلح النظام قيد الاختبار الملف، أو unspecified إن كان هذا هو
+ السؤال الذي تطرحه
+
+
+
+ أما الثالث فلا يمكن معرفته مسبقًا. إذا نُفّذ إتلاف ولم يحرّك أي بايت، يُسقَط ذلك الملف بدل كتابته،
+ ويستمر التشغيل ويذكر أي ملف كان، وينتهي برمز الخروج الجزئي.
+
+ الوصفة ملف YAML يصف تشغيلًا كاملًا. أودعها بجانب اختباراتك فتتوقف بيانات الاختبار عن كونها ملفات
+ ثنائية في مستودعك، ويستطيع أي شخص إعادة بنائها، بايتًا ببايت، من ملف بضع مئات من الأحرف.
+
+ يحتاج كل هدف إلى واحد فقط من size أو size-range أو boundary
+ أو contains. اثنان خطأ، وعدم وجود أي منها خطأ كذلك. الوصفة غير الصالحة لا
+ تكتب أي ملف وتبلّغ عن كل المشكلات دفعة واحدة لا عن أولها فقط، وتسمّي كل مشكلة الإعداد
+ الذي تخصه.
+
+
+
+
+
كيف أصرّح بما يجب أن يفعله نظامي بملف ما؟
+
الصيغة القصيرة حين تكفي النتيجة، والطويلة حين يهم السبب:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ النتائج هي accept وreject وsanitize
+ وunspecified. الأسباب قائمة مغلقة ليتمكن التقرير من التجميع بحسبها:
+ content_malformed وcount_limit وdimensions_limit
+ وduplicate وencoding_invalid وextension_rule
+ وfilename_invalid وfilename_too_long وfilename_traversal
+ وmalware_signature وmime_mismatch وnesting_depth
+ وnone وsize_limit وsize_zero.
+
+
+ يسمّي السبب القاعدة المعنية لا الحكم. ولهذا يمكن أن يقع السبب نفسه تحت أي من
+ النتيجتين: ملف أقل من الحد بايتًا واحدًا نتيجته accept، والقاعدة المعنية تبقى
+ size_limit.
+
+
+
+
+
ماذا يوجد في البيان؟
+
+ يُكتب بجانب الملفات في نهاية كل تشغيل، بما في ذلك التشغيل الذي أُوقف. عنصر واحد لكل ملف:
+
+ يُضاف recipe_hash حين يأتي التشغيل من وصفة، ويُضاف preset مع
+ overrides حين يأتي من إعداد مسبق، فيمكن دائمًا تتبّع البيان إلى ما أنتجه.
+
+
+ يحمل كل عنصر أيضًا target_id، وهو معرّف الهدف في الوصفة الذي أنتج الملف، ويحصي
+ summary.by_target الملفات التي انتهى إليها كل هدف. وهكذا يمكن فحص وصفة متعددة
+ الأهداف هدفًا هدفًا دون قراءة أسماء الملفات.
+
+
+
+
+
ما الإعداد المسبق؟
+
+ مجموعة ملفات جاهزة تجيب عن سؤال اختبار شائع، فلا تحتاج إلى تصميم المجموعة بنفسك. الإعدادات المسبقة
+ وصفات عادية في جوهرها، ويطبع eject الوصفة لتعدّلها من هناك. لكل إعداد مسبق
+ صفحة خاصة تذكر ما يكتشفه عادةً، وما في المجموعة، وكل إعداد يقبله.
+
+ يخبرك show بكلفة المجموعة قبل أن تبنيها، ويقول صراحةً حين يكون رقم ما قيمة مؤقتة منا لا
+ حدًّا منك.
+
+
+
+
+
ما معنى رموز الخروج؟
+
+ لكل نهاية رمزها الخاص، وتذهب المخرجات المقروءة آليًا إلى المخرج القياسي، ولا يطبع التشغيل الفاشل
+ شيئًا هناك. الجدول عقد مجمّد، وتغيير معنى رمز يتطلب رفع الإصدار الرئيسي.
+
+
+
+
+
+
الرمز
+
المعنى
+
+
+
+
+
0
+
عمل كل شيء.
+
+
+
1
+
خطأ غير متوقع داخل الأداة.
+
+
+
2
+
أمر أو خيار خاطئ.
+
+
+
3
+
الوصفة غير صالحة.
+
+
+
4
+
لا تستطيع الصيغة فعل ما طُلب منها.
+
+
+
5
+
فشلت قراءة أو كتابة.
+
+
+
6
+
لا توجد مساحة كافية على القرص.
+
+
+
7
+
وجد verify عدم تطابق.
+
+
+
8
+
انتهى التشغيل لكن لم يُنتَج كل شيء.
+
+
+
130
+
أُوقف بواسطة Ctrl+C.
+
+
+
143
+
أوقفته إشارة، وهذا ما يبدو عليه انتهاء مهلة CI.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ التشغيل الموقوف بـ Ctrl+C يترك بيانًا ولا يترك أبدًا ملفًا مكتوبًا نصفه، لذا يمكن للمهمة التالية أن
+ تنظّف مهمة أُلغيت.
+
+ نعم، المحرك نفسه بنافذة فوقه، للاختبار الذي لا يُكتب له سكربت. وهي ليست نسخة مبتورة: يقارن اختبار
+ الواجهتين ميزةً ميزة، وكل ما تستطيع إحداهما فعله دون الأخرى يجب أن يُعلَن ويُبرَّر بدل أن
+ يتباعدا بصمت.
+
+
+ الشاشات هي دفعة واحدة، والإعدادات المسبقة، وعدة دفعات معًا، وحول. تُظهر كلفة التشغيل قبل كتابة أي
+ شيء، وتبلّغ عن التقدم أثناء العمل، ويمكن إلغاؤها في منتصف الطريق دون ترك ملف مكتوب نصفه. لا تفتح
+ ملف وصفة بعد، فالوصفات شأن سطر الأوامر حاليًا، وتبني النافذة دفعاتها في النموذج.
+
+ الترخيص والخصوصية وقابلية إعادة الإنتاج وما يتحقق منه الناس قبل إدخال مولّد في خط بناء. إذا لم يكن
+ سؤالك هنا، فإن متتبع المشكلات مفتوح.
+
+
+
+
+
بماذا يختلف عن dd أو fsutil أو truncate؟
+
+
تلك الأوامر تعطيك ملفًا بالحجم الصحيح مملوءًا بلا شيء. ملف بحجم 2 MB باسم photo.png صُنع بهذه الطريقة ليس PNG، فكل ما يحلله فعلًا يرفضه لسبب خاطئ، ويمر اختبارك أيضًا لسبب خاطئ. هذه الأداة تنتج ملف PNG حقيقيًا بحجم 2 MB تمامًا يُفتح في عارض الصور، ويصل مع بيان عن كيفية معاملة نظامك له.
نعم في الحالتين. صدر بموجب GPL-3.0 ولا يكلّف شيئًا. لا يوجد حساب ولا مفتاح ترخيص ولا مستوى مدفوع.
+
+
+
+
هل يمكنني استخدام الملفات المولَّدة في منتج مغلق المصدر؟
+
+
نعم. الرخصة تشمل شيفرة الأداة لا ما تنتجه. الملفات والوصفات والبيانات المولَّدة مخرجات لا أعمال مشتقة، فيمكنك إيداعها وتوزيعها دون أي التزام.
+
+
+
+
هل تحتوي الملفات المولَّدة على بيانات شخصية حقيقية؟
+
+
لا. كل ما بداخلها يُركَّب من بذرة. لا تُقرأ أي مجموعة بيانات، ولا يُتصل بأي خدمة، ولا يُضمَّن أي محتوى من طرف ثالث. عامل عنوان البريد الإلكتروني المولَّد على أنه غير صالح للاستخدام لا على أنه غير مستخدم، لأن أي سلسلة عشوائية قد تتطابق مصادفة مع سلسلة حقيقية.
+
+
+
+
هل سأحصل على الملفات نفسها تمامًا على جهاز آخر؟
+
+
نعم، بايتًا ببايت، مع الوصفة نفسها والبذرة نفسها. يختبر المشروع ذلك مع كل تغيير، وكسره يتطلب رفع الإصدار الرئيسي. وهذا ما يتيح لك إيداع وصفة صغيرة بدل بيانات اختبار ثنائية كبيرة.
+
+
+
+
هل يحتاج إلى اتصال بالإنترنت؟
+
+
أبدًا. لا توجد قياسات عن بُعد ولا فحص للتحديثات ولا عميل سحابي، والملف التنفيذي لسطر الأوامر لا تُترجَم فيه حزمة شبكة أصلًا. يعمل على جهاز بلا شبكة وداخل بيئة مؤسسية مغلقة.
+
+
+
+
ماذا يحدث إذا طلبت حجمًا لا تستطيع الصيغة بلوغه؟
+
+
تحصل على خطأ يذكر الصيغة وأصغر حجم ممكن وسبب هذا الحد الأدنى وما يجب فعله بدلًا من ذلك، ولا يُكتب أي ملف. الأداة لا تقرّب الحجم بصمت أبدًا. وكل حد أدنى مذكور في صفحة الصيغ.
+
tfg formats png
+
+
+
+
هل يمكنني توليد ملف تالف عمدًا؟
+
+
نعم. أضف --damage zero-head فيخرج الملف بالحجم الذي طلبته تمامًا، وأول بايتاته مكتوب فوقها أصفار، فترفضه القارئة، ويقول البيان إن نظامك ينبغي أن يرفضه. التفاصيل في صفحة ملفات الاختبار التالفة.
7z وmp3 وmp4. تعمل اليوم 26 صيغة من البداية إلى النهاية.
+
+
+
+
على أي أنظمة يمكنني تشغيله؟
+
+
يعمل سطر الأوامر على ويندوز ولينكس على معالجات Intel وARM، وعلى أجهزة ماك بمعالجات Apple Silicon. تُقدَّم نافذة سطح المكتب لويندوز على Intel، ولينكس على Intel، وأجهزة ماك بمعالجات Apple Silicon. أجهزة ماك بمعالجات Intel غير مدعومة ولا يُبنى لها شيء.
+
+
+
+
هل أحتاج إلى تثبيت شيء؟
+
+
لا. نزّل الأرشيف الخاص بنظامك وفك ضغطه وشغّل الملف التنفيذي. لا يوجد مثبّت ولا بيئة تشغيل تُضاف ولا اعتماديات تُحل. وإذا كان لديك Go فيكفي أمر go install واحد أيضًا.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
لماذا يكون التشغيل على آلاف الملفات أبطأ على ويندوز؟
+
+
لأن ويندوز يتقاضى أكثر عن كل مسار ينظر فيه، والأمر الذي يمر على آلاف الملفات ينظر في آلاف المسارات. قيس على جهاز واحد فيه 3000 ملف بحجم 1 kB، فاستغرق verify نحو 0.9 ثانية على ويندوز ونحو 0.2 ثانية على لينكس داخل حاوية. ويصغّر مسار الإخراج الأقصر رقم ويندوز، لأن كل مجلد فوق الملفات جزء مما يُنظر فيه.
+ كلٌّ منها ملف حقيقي من تلك الصيغة. يُفتح في البرنامج الذي يملكه، وعدد بايتاته هو ما
+ طلبته بالضبط. ولا واحد منها أصفار حشوية أُلصق بها امتداد.
+
+
+
+
+
+
+
الصيغة
+
الاسم
+
الامتداد
+
أصغر ملف
+
الاكتمال
+
يُتحقق منه بواسطة
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
غير منطبق
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
غير منطبق
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
غير منطبق
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
معنى الأعمدة
+
+
+
أصغر ملف
+
+ أقل عدد من البايتات تقبله هذه الأداة لتلك الصيغة، شاملًا الوسم الذي تكتبه داخل الملف. اطلب أقل فتحصل
+ على خطأ يذكر الحد الأدنى وسببه، لا ملفًا بحجم خاطئ أبدًا.
+
+
+
+
الاكتمال
+
+ مدى اكتمال الملف. تعني full أن قارئًا يحلل الصيغة فعلًا يقبله، لا أن الامتداد يطابق
+ فحسب.
+
+
+
+
يُتحقق منه بواسطة
+
+ القارئ المستقل الذي يفتح كل ملف مولَّد قبل إصدار الصيغة، وهو تنفيذ منفصل، لا شيفرتنا نحن تصحّح
+ واجباتها بنفسها.
+
+
+
+
+ وتتكرر كل صيغة حتى البايت أيضًا: الوصفة نفسها والبذرة نفسها تنتجان ملفات متطابقة على أي جهاز، وهذا
+ ما يجعل إيداع وصفة بدل بيانات الاختبار نفسها أمرًا آمنًا.
+
+
+
+
+
الإعدادات التي تقبلها كل صيغة
+
+ لمعظم الصيغ إعدادات خاصة بها: أبعاد الصورة، وجودة JPEG، وعدد صفحات PDF، والصفوف والأعمدة في جدول
+ بيانات، وعدد العناصر داخل الأرشيف. اضبطها بـ --set key=value في سطر الأوامر أو تحت
+ properties: في وصفة.
+
تاريخ مثل 2024-02-29 أو 2024-02-29T13:45:00+02:00، أو none
+
+
+
+
modified
+
تاريخ مثل 2024-02-29 أو 2024-02-29T13:45:00+02:00، أو none
+
+
+
png
+
width
+
1 - 20000 بكسل
+
+
+
+
height
+
1 - 20000 بكسل
+
+
+
pptx
+
slides
+
1 - 500 شرائح
+
+
+
svg
+
width
+
1 - 20000 بكسل
+
+
+
+
height
+
1 - 20000 بكسل
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
معرّف صيغة، كما يسردها tfg formats
+
+
+
+
entry_size
+
حجم مثل 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
صحيح أو خاطئ
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 بكسل
+
+
+
+
height
+
1 - 20000 بكسل
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
صحيح أو خاطئ
+
+
+
wav
+
sample_rate
+
8000 - 192000 هرتز
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 بكسل
+
+
+
+
height
+
1 - 16383 بكسل
+
+
+
xlsx
+
rows
+
1 - 200000 صفوف
+
+
+
+
columns
+
1 - 32768 أعمدة
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
صحيح أو خاطئ
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
معرّف صيغة، كما يسردها tfg formats
+
+
+
+
entry_size
+
حجم مثل 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
صحيح أو خاطئ
+
+
+
+
password
+
كلمة المرور، كنص عادي
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ القيمة الواقعة خارج ما يقبله الإعداد تُرفض برسالة تسمّي الإعداد والنطاق المسموح وما يُستخدم بدلًا
+ منه. والإعداد المجهول خطأ أيضًا، وليس قيمة افتراضية صامتة أبدًا، فخطأ مطبعي يُقبل بصمت يعطي
+ ملفًا بإعدادات خاطئة وساعة من التساؤل عن سبب نجاح اختبار كان ينبغي ألا ينجح.
+
+
+ شغّل tfg formats <id> لترى بالضبط ما تقبله صيغة واحدة في الإصدار الذي لديك.
+
+
+
+
+
الأرشيفات تحتوي ملفات حقيقية
+
+ targz وzip يمكن
+ ملؤها بعناصر بدل تركها قشرة فارغة. الأرشيف المولَّد يحتوي فعلًا على المستندات التي يدّعي
+ احتواءها، فكل ما يفكّه أثناء اختبار يجد بداخله ملفات حقيقية.
+
+ PDF وPNG وDOCX وZIP، 26 صيغة في المجمل، وكلٌّ منها ملف حقيقي
+ يُفتح في البرنامج الذي يملكه، وبـالحجم الذي طلبته تمامًا. كما يدوّن كل تشغيل ما
+ يجب أن يفعله تطبيقك بكل ملف. سطر أوامر ونافذة سطح مكتب، مجاني ومفتوح المصدر، ويعمل بالكامل على
+ جهازك.
+
مجاني ومفتوح المصدر، GPL-3.0. لا حاجة إلى التسجيل. تنزيلات ويندوز وماك موقّعة وتعمل دون تحذير.
+
+
+
+
+ نافذة سطح المكتب، مجهّزة لكتابة دفعة من الملفات. المحرك نفسه يعمل خلف سطر الأوامر.
+
+
+
+
+
+ 26
+
صيغة حقيقية، وكلٌّ منها يُفتح في البرنامج الذي يملكه
+
+
+ 1 بايت
+
دقة كل حجم تطلبه، دون تقريب صامت أبدًا
+
+
+ 0
+
اتصالات إلى أي مكان - لا حساب ولا قياسات عن بُعد ولا فحص للتحديثات
+
+
+
+
+
المشكلة
+
صنع ملف اختبار واحد سهل. صنع الألف الصحيحة هو الجزء المرهق
+
أنت تختبر برنامجًا يقبل ملفات من الناس. عاجلًا أم آجلًا ستحتاج إلى:
+
+
ملف PDF بحجم 10 MB تمامًا، لتعرف إن كان حد الرفع حقيقيًا
+
الملفات الثلاثة على جانبي هذا الحد، لاصطياد أخطاء الفرق بواحد
+
10,000 ملف سجل، لترى ماذا تفعل المهمة الليلية حين يكون المجلد كبيرًا
+
ملف ZIP يحتوي فعلًا على 200 مستند، لا قشرة فارغة بالامتداد الصحيح
+
ملف بحجم 4 GB دون الاحتفاظ بملف 4 GB في مستودعك
+
بيانات الاختبار نفسها على حاسوبك المحمول وعلى خادم البناء، بايتًا ببايت
+
+
+ هذا ما يحل محله هذا المولّد. صُمم لمهندسي ضمان الجودة وأتمتة الاختبار، ولكل من خلف شيفرته نموذج رفع
+ أو روتين استيراد أو محلل أو حصة تخزين.
+
+
+
+
+
ما الذي يميّزه
+
المولّدات الأخرى تتوقف عند البايتات. هذا المولّد يجيب عما يسأله اختبارك فعلًا
+
+ مجلد من الملفات يتركك تقرر بنفسك ما يُفترض أن يثبته كل ملف. يكتب كل تشغيل هنا ملف
+ manifest.json بجانب الملفات، وهو قائمة بسيطة بكل ما أُنتج، ولكل عنصر توقّع
+ معلن.
+
+
لنفترض أن نقطة الرفع عندك تسمح بـ 1 MB. اطلب الملفات الثلاثة الواقعة على هذا الخط:
+ يسجّل unspecified بدل اختلاق توقّع. المولّد الذي يخمّن يصنع إخفاقات زائفة، ومجموعة
+ الاختبارات التي تطلق إنذارات كاذبة يُوقف العمل بها.
+
+
+
+
+
+
الإعدادات المسبقة
+
اختر السؤال، واحصل على المجموعة كاملة
+
+ الإعداد المسبق مجموعة ملفات اختبار مصممة حول سؤال اختبار واحد، فلا تحتاج إلى معرفة أي الملفات يثبت
+ ماذا. لكل منها صفحة تذكر ما يكتشفه عادةً، وما في المجموعة، وكل إعداد يقبله.
+
+ عشرة آلاف ملف سجل، حجم كل منها بين واحد وثمانية كيلوبايت، تُسحب الأحجام من البذرة ليعطي الغد
+ المجموعة نفسها. امنح كل تشغيل مجلده الخاص، فالبيان هو السجل الوحيد لما كتبه
+ التشغيل، لذا ترفض الأداة كتابة بيان ثانٍ فوقه:
+
+ تُعدّ الأحجام بالمضاعفات 1024 كما يفعل مدير الملفات لديك، فـ2mb تعني 2097152 بايتًا.
+ وعدد البايتات المجرد يصلح أيضًا. يغطي التوثيق الوصفات والبيان ورموز
+ الخروج.
+
+
+
+
+
ما تحصل عليه
+
مبني لمجموعة اختبارات تعمل دون إشراف
+
+
+
حجم دقيق، حتى البايت
+
اطلب 10485761 بايتًا واحصل على هذا العدد بالضبط. الحجم الذي لا تستطيع الصيغة بلوغه خطأ مع سبب، وليس ملفًا بحجم خاطئ أبدًا.
+
+
+
26 صيغة حقيقية
+
ليست أصفارًا حشوية بامتداد. يُفتح ملف PNG المولَّد في عارض الصور، ويُفتح DOCX في Word، ويُفك ضغط ZIP. وتُفحص كل صيغة بقرّاء مستقلين قبل إصدارها.
+
+
+
بيان هو مرجع للاختبار
+
المسار والحجم وSHA-256 والصيغة والبذرة وإصدار الأداة، وما يجب أن يفعله نظامك بالملف.
+
+
+
قابل لإعادة الإنتاج
+
الوصفة نفسها والبذرة نفسها تعطيان البايتات نفسها على أي جهاز. أودع وصفة YAML صغيرة بدل بيانات اختبار ثنائية كبيرة.
+
+
+
واجهتان ومحرك واحد
+
سطر أوامر مبني للتكامل المستمر، ونافذة سطح مكتب للاختبار الاستكشافي. ليست أيٌّ منهما نسخة مبتورة من الأخرى، ويقارنهما اختبار ميزةً ميزة.
+
+
+
دون اتصال بالكامل
+
لا حساب ولا سحابة ولا قياسات عن بُعد ولا فحص للتحديثات. والملف التنفيذي لسطر الأوامر لا تُترجَم فيه حزمة شبكة أصلًا.
+
+
+
+
+
+
التنزيل
+
اختر الإصدار المناسب لنظامك
+
+ فك ضغط الأرشيف وشغّل الملف. tfg هو سطر الأوامر وtfg-gui هو نافذة سطح
+ المكتب. لا يوجد مثبّت ولا شيء يُضاف إلى جهازك.
+
+
+
+
+
+
النظام
+
سطر الأوامر
+
نافذة سطح المكتب
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
ما الموقَّع وما غير الموقَّع
+
+ تنزيلات ويندوز وماك موقّعة، لذا تبدأ دون تحذير من مطوّر غير معروف. أما تنزيلات لينكس فغير موقّعة،
+ لأن لينكس المكتبي لا يملك ما يوقَّع به. وكل أرشيف مدرج في verify-SHA256SUMS.txt
+ على صفحة الإصدارات، لتتحقق مما نزّلته.
+
+ يبني الإعداد المسبق empty-and-minimal بأمر واحد مجموعة كاملة من ملفات الاختبار الحقيقية لهذا
+ السؤال، وبجانبها manifest.json يحدد كيف يجب أن يتفاعل نظامك مع كل ملف. كل ما يلي
+ مقروء من البرنامج، عند القيم الافتراضية لهذا الإصدار.
+
+
+
+
+
ماذا يكتشف عادةً؟
+
+
ملف صالح يُرفض لأنه صغير جدًا، لأن الفحص يعدّ البايتات بدل قراءتها
+
ملف فارغ يُسقط القارئ بدل أن يُبلَّغ عنه
+
صورة بعرض بكسل واحد تقسم على صفر في طريقها إلى الصورة المصغرة
+
تخزين يقرأ صفر بايت على أنه رفع فاشل ويواصل إعادة المحاولة
+
+
+
+
+
+
ماذا في المجموعة؟
+
عند القيم الافتراضية، كما يبلّغ tfg preset show empty-and-minimal:
+ يبني الإعداد المسبق filename-handling بأمر واحد مجموعة كاملة من ملفات الاختبار الحقيقية لهذا
+ السؤال، وبجانبها manifest.json يحدد كيف يجب أن يتفاعل نظامك مع كل ملف. كل ما يلي
+ مقروء من البرنامج، عند القيم الافتراضية لهذا الإصدار.
+
+
+
+
+
ماذا يكتشف عادةً؟
+
+
اسم يبدو كاسم آخر على الشاشة أو في السجل أو في قائمة
+
اسم يُقطع أو يُقص أو يُعاد كتابته بين الرفع والتخزين
+
حد للطول يُحسب بالأحرف بينما يحسب التخزين بالبايتات
+
+
+
+
+
+
ماذا في المجموعة؟
+
عند القيم الافتراضية، كما يبلّغ tfg preset show filename-handling:
+
+
+
+
الملفات
50
+
الأهداف في وصفته
50
+
الحجم الإجمالي
51 200 B
+
الصيغ
txt
+
+
+
+
وما يتوقعه بيان تلك المجموعة من نظامك:
+
+
+
+
المتوقع
المعنى
الملفات
+
+
+
accept
ينبغي أن يقبل نظامك الملف.
4
+
unspecified
يعتمد على قواعد نظامك. أنت من يقرر، ثم تتحقق من أن ما يحدث هو ما قصدته.
46
+
+
+
+
+
+
+
ما الذي يمكنك تغييره؟
+
+
+
+
الإعداد
يقبل
الافتراضي
ما يفعله
+
+
+
+
--format
+
معرّف صيغة من صفحة الصيغ
+
txt
+
صيغة كل ملف في المجموعة. إنه خيار في الأداة نفسها، والإعداد المسبق يمنحه قيمة افتراضية فقط.
+
+
+
+
+
+
+
+
كيف تشغّله؟
+
اطّلع على كلفة المجموعة، أو ابنِها، أو خذ وصفتها لتعدّلها:
إعدادات مسبقة لملفات الاختبار، مجموعة لكل سؤال اختبار
+
+ الإعداد المسبق مجموعة كاملة من ملفات الاختبار مصممة حول سؤال واحد، مع بيان يحدد كيف يجب أن يتفاعل
+ نظامك مع كل ملف. أنت تختار السؤال، والأداة تبني المجموعة. لكل إعداد مسبق صفحته الخاصة التي تذكر ما
+ يكتشفه عادةً، وما في المجموعة، وكل إعداد يقبله.
+
هل يقبل نموذج الرفع عندي ما يجب قبوله ويرفض الباقي؟
+
upload-validation
+
+
+
+
+
بماذا يختلف الإعداد المسبق عن الوصفة؟
+
+ في جوهره، لا يختلف. الإعداد المسبق وصفة تكتبها الأداة لك من بضعة إعدادات. يطبع tfg preset
+ eject تلك الوصفة لتحتفظ بها بجانب اختباراتك وتعدّلها، ويمكن لوصفة خاصة بك أن تبني على
+ إعداد مسبق بسطر واحد: extends: preset: يليه معرّفه.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
هل يمكنني الوثوق بالقيم الافتراضية؟
+
+ بالنسبة إلى الملفات، نعم. أما الرقم الذي لا يعرفه إلا نظامك، مثل حد نموذج الرفع، فالقيمة الافتراضية
+ قيمة مؤقتة منا، وتقول الأداة ذلك في كل مرة تستخدم فيها واحدة. وتعلّم صفحة كل إعداد مسبق تلك
+ الإعدادات، ويقول tfg preset show ذلك قبل كتابة أي شيء.
+
+ يبني الإعداد المسبق size-boundaries بأمر واحد مجموعة كاملة من ملفات الاختبار الحقيقية لهذا
+ السؤال، وبجانبها manifest.json يحدد كيف يجب أن يتفاعل نظامك مع كل ملف. كل ما يلي
+ مقروء من البرنامج، عند القيم الافتراضية لهذا الإصدار.
+
+
+
+
+
ماذا يكتشف عادةً؟
+
+
أخطاء الفرق بواحد عند الحد
+
خلط MB مع MiB، أي 4.8 بالمئة، وهذا كافٍ لتمرير ملف لا ينبغي أن يمر
+
حد يُطبَّق في المتصفح لا على الخادم
+
+
+
+
+
+
ماذا في المجموعة؟
+
عند القيم الافتراضية، كما يبلّغ tfg preset show size-boundaries:
+
+
+
+
الملفات
7
+
الأهداف في وصفته
7
+
الحجم الإجمالي
73 400 320 B
+
الصيغ
pdf
+
+
+
+
وما يتوقعه بيان تلك المجموعة من نظامك:
+
+
+
+
المتوقع
المعنى
الملفات
+
+
+
accept
ينبغي أن يقبل نظامك الملف.
4
+
reject
ينبغي أن يرفض نظامك الملف.
3
+
+
+
+
+
+
+
ما الذي يمكنك تغييره؟
+
+
+
+
الإعداد
يقبل
الافتراضي
ما يفعله
+
+
+
+
--limit
+
حجم مثل 2mb
+
10mb
+
حد الحجم الذي يعلنه نظامك. كل شيء آخر يُقاس منه. هذه القيمة الافتراضية مؤقتة منا، وليست قيمة نظامك. مرّر قيمتك أنت.
+
+
+
--spread
+
أحجام مفصولة بفواصل
+
1B,1kb,1mb
+
إلى أي مدى يمتد على جانبي الحد، كقائمة أحجام.
+
+
+
--format
+
معرّف صيغة من صفحة الصيغ
+
pdf
+
صيغة كل ملف في المجموعة. إنه خيار في الأداة نفسها، والإعداد المسبق يمنحه قيمة افتراضية فقط.
+
+
+
+
+
+
+
+
كيف تشغّله؟
+
اطّلع على كلفة المجموعة، أو ابنِها، أو خذ وصفتها لتعدّلها:
هل يصمد استيراد الجداول عندي أمام ما تصدّره الأدوات الحقيقية؟
+
+ يبني الإعداد المسبق tabular-import بأمر واحد مجموعة كاملة من ملفات الاختبار الحقيقية لهذا
+ السؤال، وبجانبها manifest.json يحدد كيف يجب أن يتفاعل نظامك مع كل ملف. كل ما يلي
+ مقروء من البرنامج، عند القيم الافتراضية لهذا الإصدار.
+
+
+
+
+
ماذا يكتشف عادةً؟
+
+
ملف بفاصلة منقوطة يُقرأ كعمود واحد، لأن الفاصل افتُرض بدل أن يُبحث عنه
+
ملف CRLF يُقسَّم إلى صفوف مع صف فارغ بعد كل صف
+
جدول بلا ترويسة يُبتلع صف بياناته الأول كأسماء أعمدة
+
استيراد يحتفظ بالأعمدة التي يستطيع عرضها ويُسقط الباقي دون كلمة
+
قارئ يأخذ سجلات JSON سطرًا سطرًا ويتوقف عند أول مستند بمسافة بادئة
+
+
+
+
+
+
ماذا في المجموعة؟
+
عند القيم الافتراضية، كما يبلّغ tfg preset show tabular-import:
+
+
+
+
الملفات
13
+
الأهداف في وصفته
13
+
الحجم الإجمالي
3 080 060 B
+
الصيغ
csv, json, xlsx
+
+
+
+
وما يتوقعه بيان تلك المجموعة من نظامك:
+
+
+
+
المتوقع
المعنى
الملفات
+
+
+
accept
ينبغي أن يقبل نظامك الملف.
8
+
unspecified
يعتمد على قواعد نظامك. أنت من يقرر، ثم تتحقق من أن ما يحدث هو ما قصدته.
5
+
+
+
+
+
+
+
ما الذي يمكنك تغييره؟
+
+
+
+
الإعداد
يقبل
الافتراضي
ما يفعله
+
+
+
+
--rows
+
1 - 200000 صفوف
+
1000
+
عدد الصفوف في الجدول. يُكتب الملف بالحجم الذي تُعبَّأ إليه هذه الصفوف تمامًا، لذا تتحرك الميزانية أعلاه مع هذه القيمة.
+
+
+
--columns
+
1 - 32768 أعمدة
+
10
+
عدد الأعمدة في كل صف من الجدول. لحاصل ضرب الصفوف في الأعمدة سقف، وأي طلب يتجاوزه يُرفض قبل أن يُكتب أي شيء.
+
+
+
+
+
+
+
+
كيف تشغّله؟
+
اطّلع على كلفة المجموعة، أو ابنِها، أو خذ وصفتها لتعدّلها:
+ يبني الإعداد المسبق text-encoding بأمر واحد مجموعة كاملة من ملفات الاختبار الحقيقية لهذا
+ السؤال، وبجانبها manifest.json يحدد كيف يجب أن يتفاعل نظامك مع كل ملف. كل ما يلي
+ مقروء من البرنامج، عند القيم الافتراضية لهذا الإصدار.
+
+
+
+
+
ماذا يكتشف عادةً؟
+
+
قارئ يفترض UTF-8 فيعرض ملف UTF-16 بحرف واحد من كل ثلاثة أو كصفوف من المربعات
+
علامة ترتيب بايتات تُقرأ كمحتوى، فيبدأ أول حقل في الاستيراد بثلاثة أحرف غريبة
+
مستورد يخمّن الترميز من البايتات الأولى ويخمّن بشكل مختلف مع ملف أطول
+
ملف CRLF يُقسَّم إلى صفوف مع صف فارغ بعد كل صف، أو حرف إرجاع الحامل يبقى داخل الحقل الأخير
+
+
+
+
+
+
ماذا في المجموعة؟
+
عند القيم الافتراضية، كما يبلّغ tfg preset show text-encoding:
+
+
+
+
الملفات
20
+
الأهداف في وصفته
20
+
الحجم الإجمالي
81 920 B
+
الصيغ
csv, log, md, txt, xml
+
+
+
+
وما يتوقعه بيان تلك المجموعة من نظامك:
+
+
+
+
المتوقع
المعنى
الملفات
+
+
+
accept
ينبغي أن يقبل نظامك الملف.
10
+
unspecified
يعتمد على قواعد نظامك. أنت من يقرر، ثم تتحقق من أن ما يحدث هو ما قصدته.
10
+
+
+
+
+
+
+
ما الذي يمكنك تغييره؟
+
+
+
+
الإعداد
يقبل
الافتراضي
ما يفعله
+
+
+
+
--sample
+
حجم مثل 2mb
+
4kb
+
حجم كل ملف في المجموعة. يخزّن UTF-16 بايتين لكل حرف، لذا يُرفض العدد الفردي.
+
+
+
+
+
+
+
+
كيف تشغّله؟
+
اطّلع على كلفة المجموعة، أو ابنِها، أو خذ وصفتها لتعدّلها:
هل يقبل نموذج الرفع عندي ما يجب قبوله ويرفض الباقي؟
+
+ يبني الإعداد المسبق upload-validation بأمر واحد مجموعة كاملة من ملفات الاختبار الحقيقية لهذا
+ السؤال، وبجانبها manifest.json يحدد كيف يجب أن يتفاعل نظامك مع كل ملف. كل ما يلي
+ مقروء من البرنامج، عند القيم الافتراضية لهذا الإصدار.
+
+
+
+
+
ماذا يكتشف عادةً؟
+
+
حد يُطبَّق في المتصفح لا على الخادم
+
ملف SVG أو HTML يُؤخذ على أنه صورة أو نص عادي، وهي طريقة لتمرير سكربت عبر نموذج
+
ملف يُفحص بامتداده ولا يُفتح أبدًا، فيمر ملف PDF اسمه .jpg
+
نموذج يقرأ الجسم كله في الذاكرة قبل أن ينظر كم حجمه
+
رفع باسم PHOTO.JPG يُرفض بينما يُقبل photo.jpg، أو العكس
+
اسم فيه مسافات أو أقواس أو أحرف خارج ASCII يُكتب على القرص دون تغيير
+
+
+
+
+
+
ماذا في المجموعة؟
+
عند القيم الافتراضية، كما يبلّغ tfg preset show upload-validation:
+
+
+
+
الملفات
71
+
الأهداف في وصفته
22
+
الحجم الإجمالي
120 639 488 B
+
الصيغ
html, jpg, pdf, png, svg, txt
+
+
+
+
وما يتوقعه بيان تلك المجموعة من نظامك:
+
+
+
+
المتوقع
المعنى
الملفات
+
+
+
accept
ينبغي أن يقبل نظامك الملف.
56
+
reject
ينبغي أن يرفض نظامك الملف.
10
+
unspecified
يعتمد على قواعد نظامك. أنت من يقرر، ثم تتحقق من أن ما يحدث هو ما قصدته.
5
+
+
+
+
+
+
+
ما الذي يمكنك تغييره؟
+
+
+
+
الإعداد
يقبل
الافتراضي
ما يفعله
+
+
+
+
--limit
+
حجم مثل 2mb
+
10mb
+
حد الحجم الذي يعلنه نموذج الرفع عندك. تأخذ هذه المجموعة خطوة واحدة على كل جانب منه، ولملف عند كل مسافة شغّل الإعداد المسبق size-boundaries. هذه القيمة الافتراضية مؤقتة منا، وليست قيمة نظامك. مرّر قيمتك أنت.
+
+
+
--allow
+
معرّفات صيغ مفصولة بفواصل
+
jpg,png,pdf
+
الأنواع التي يجب أن يقبلها نموذجك. يصير كل نوع ملفًا حقيقيًا من ذلك النوع، وتشكّل الشاهد الإيجابي للمجموعة كلها.
+
+
+
--deny
+
امتدادات مفصولة بفواصل
+
svg,html,exe,sh
+
الامتدادات التي يجب أن يرفضها نموذجك. الامتداد الذي لا صيغة له في هذا الإصدار يحصل مع ذلك على ملف بهذا الاسم يحتوي نصًا عاديًا.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
إلى أي مدى يتجاوز الملف الكبير الوحيد الحد. أوقفه حيث لا يستحق كتابة أضعاف الحد مساحة القرص.
+
+
+
--bulk
+
0 - 10000 ملفات
+
50
+
عدد الملفات في الرفع الجماعي. الصفر يُخرج هذه المجموعة من المجموعة كليًا.
+
+
+
+
+
+
+
+
كيف تشغّله؟
+
اطّلع على كلفة المجموعة، أو ابنِها، أو خذ وصفتها لتعدّلها:
+ الملف الثنائي الثابت في المستودع يبقى في سجله إلى الأبد، ولا يمكن مراجعته في diff، ويصبح مستحيلًا
+ حين يكبر الملف. ولِّد الملفات بدلًا من ذلك داخل الخط من وصفة. الوصفة نص، والبايتات تخرج متطابقة في
+ كل مرة، وخطوة أخيرة تثبت أن شيئًا لم يتحرك.
+
+
+
+
الجواب المختصر
+
+ ثبّت tfg، وشغّل tfg generate fixtures.yaml --out ./fixtures قبل
+ الاختبارات، وtfg verify ./fixtures/manifest.json بعدها. كلتا الخطوتين تُفشلان
+ البناء من تلقاء نفسيهما، برمز خروج يقول السبب.
+
+
+
+
+
لماذا لا نودعها
+
لماذا لا ينبغي أن يعيش الملف الثابت في المستودع
+
+
+ يبقى في السجل. حذف ملف ثنائي لاحقًا لا يصغّر النسخة المستنسخة، لأن كل إصدار منه ما
+ زال هناك.
+
+
+ الـ diff لا يُظهر ما تغيّر. يرى المراجع أن ملف PDF مختلف ولا شيء غير ذلك. أما
+ الوصفة فتتغيّر بسطر واحد.
+
+
+ الملفات الكبيرة لا تتسع. يرفض GitHub دفعة تحتوي ملفًا أكبر من 100 ميغابايت، فلا يجد
+ اختبار حد رفع 500 ميغابايت ما يودعه.
+
+
+
+ الذي يُودَع هو الوصفة. الوصفة نفسها مع البذرة نفسها تكتب البايتات نفسها على أي جهاز، فالملف المولَّد
+ في الخط هو الملف الذي كان عندك على حاسوبك المحمول.
+
+
+
+
+
الوصفة
+
وصفة تعيش بجانب الاختبارات
+
+ تكتب هذه خمسًا وعشرين فاتورة ينبغي قبولها وصورتين فوق الحد ينبغي رفضهما، ويسجّل البيان التوقعين
+ معًا:
+
+ لكل نهاية رمز خروج خاص بها، فتفشل الخطوة من تلقاء نفسها ويقول السجل أيّها كان. هذه هي التي يصادفها
+ الخط:
+
+
+
3 - الوصفة غير صالحة. لم يُكتب شيء، ويُسمّى كل خلل
+
4 - الصيغة لا تستطيع ما طُلب منها، مثل حجم أقل من أصغر حجم لها
+
6 - لا توجد مساحة كافية على القرص
+
7 - وجد tfg verify ملفًا لا يطابق بيانه
+
8 - انتهى التشغيل لكن لم يُنتَج كل شيء
+
+
+ التشغيل الفاشل لا يطبع شيئًا على الخرج القياسي، فلا يحسب محلل السجلات خطأً بيانات أبدًا. الجدول
+ الكامل في صفحة التوثيق.
+
+
+
+
+
PowerShell
+
سكربت PowerShell يحتاج سطرًا إضافيًا
+
+ لا ينقل PowerShell رمز خروج برنامج إلى خارج ملف .ps1. شغّل واحدًا بـ -File
+ فيجيب السكربت 0 حتى حين رفضت الأداة داخله العمل، فيتحول بناء كان ينبغي أن يكون أحمر
+ إلى أخضر. السطر الأخير هو الإصلاح كله:
+
+ هكذا يتصرف PowerShell، وليس في الأمر شيء يخص هذه الأداة. أما cmd وbash
+ وzsh فلا تحتاج إلى شيء إضافي.
+
+
+
+
+
عدة مهام
+
مشاركة الملفات الثابتة بين المهام
+
+ لا حاجة عادةً إلى رفعها. لأن الوصفة نفسها تكتب البايتات نفسها، تستطيع كل مهمة تشغيل tfg
+ generate الخاص بها، وهذا أسرع من الرفع ثم التنزيل. وحين تحتاج مهمة إلى استلام ملفات من
+ أخرى، شغّل tfg verify على البيان بعد النقل، فيخبرك هل ما وصل هو ما كُتب.
+
+ خمس مهام تظهر في كل مشروع تقريبًا يقبل ملفات من الناس، والأمر الذي ينفذ كلًّا منها. كل مثال أدناه
+ يعمل كما هو مكتوب.
+
+
+
+
حدود الرفع
+
اختبار ما إذا كان حد حجم الملف يُطبَّق حيث يقول إنه يُطبَّق
+
+ الحد ثلاث حالات اختبار لا حالة واحدة: أقل منه بقليل، وعنده تمامًا، وأعلى منه بقليل. الحصول عليها
+ يدويًا يعني حساب أعداد البايتات والأمل في ألا تخطئ بواحد. اطلب المجموعة بدلًا من ذلك:
+
+ تحصل على ثلاثة ملفات PDF حقيقية بحجم 1048575 و1048576 و1048577 بايتًا، وبيان يقول إن الأولين يجب
+ قبولهما والثالث يُرفض بسبب size_limit. يقرأ اختبارك التوقّع بدل أن تكتب ثلاثة
+ تأكيدات يدويًا، وحين يتغير الحد تغيّر رقمًا واحدًا وتعيد التشغيل.
+
+
+ ويعمل الأمر نفسه دون إعداد مسبق حين تريد مجموعة حدود واحدة داخل الأمر:
+
+ بيانات الاختبار الثنائية الكبيرة تُبطئ استنساخ المستودع وتُصعّب مراجعته، ولا أحد يعرف ما الذي تغيّر
+ حين تُستبدل واحدة. الوصفة بضع مئات من أحرف YAML تعيد بناء الملفات المطابقة، بايتًا ببايت
+ وعلى أي جهاز، لأن كل ملف مشتق من بذرة التشغيل.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ لكل نهاية رمز خروج خاص بها، فيستطيع خط البناء التمييز بين وصفة سيئة وقرص ممتلئ وعدم تطابق في التحقق.
+ والتشغيل الفاشل لا يطبع شيئًا على المخرج القياسي، فلا يقرأ محلل السجلات خطأً على أنه بيانات.
+
+
+
+
+
الحجم الكبير
+
معرفة ما يحدث حين يكون المجلد كبيرًا
+
+ تتصرف روتينات الاستيراد والمهام الليلية وقوائم المجلدات بشكل مختلف عند عشرة آلاف ملف عنه عند عشرة.
+ الأحجام المسحوبة من نطاق تجعل المجموعة تبدو كحركة حقيقية لا كعشرة آلاف ملف متطابق، ويأتي السحب
+ من البذرة، فتكون المجموعة نفسها غدًا.
+
+ عمق التداخل وعدد العناصر وحجم ما بالداخل كلها أمور لروتين الاستيراد رأي فيها، وهكذا تعرف ما هي تلك
+ الآراء.
+
+
+
+
+
المحللات والعارضات
+
التحقق من أن شيفرتك تقرأ الصيغة كما يفعل البرنامج الحقيقي
+
+ كل صيغة هنا تُفحص بقارئ مستقل قبل إصدارها: يُفتح PNG وتُقارَن بكسلاته، ويُقرأ DOCX من جديد بمكتبات
+ منفصلة، ويُفك أرشيف. وهذا يعني أن ملفًا يرفضه محللك هو نتيجة عن محللك، لا عن المولّد.
+
+ تسرد صفحة الصيغ الإعدادات التي تقبلها كل صيغة وأصغر ملف يمكن أن تكونه.
+
+
+
+
+
أدلة
+
اثنان منها بتفصيل أكبر
+
+
+ ملفات اختبار تالفة - ملف أُتلف عمدًا بحجم دقيق، وما ينبغي أن
+ يحدث له مكتوب في البيان.
+
+
+ ملفات الاختبار في CI - سير عمل لـ GitHub Actions ومهمة في GitLab
+ ورموز الخروج التي تُفشل البناء.
+
+
+
+
+
+
لمن هذا
+
+ لمهندسي ضمان الجودة وأتمتة الاختبار، ولكل من خلف شيفرته نموذج رفع أو روتين استيراد أو محلل أو حصة
+ تخزين. يعمل على جهاز بلا شبكة إطلاقًا، وهذا مهم في بيئة مؤسسية مغلقة لا يكون فيها المولّد القائم
+ على المتصفح خيارًا.
+
+ A validator that has only ever been shown healthy files has not really been tested. Here is how to
+ get a file that is broken on purpose, comes out at exactly the size you ask for,
+ and carries a manifest saying what your system should do with it.
+
+
+
+
The short answer
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out writes a PNG of
+ exactly 2097152 bytes whose first bytes are zeros, and the manifest beside it records that your
+ system should reject it.
+
+
+
+
+
The usual way
+
Why a file corrupted by hand makes a poor test
+
+ The usual ways are a hex editor, a script that flips a few random bytes, or cutting a file short
+ with head or truncate. They work once, and then they cost you:
+
+
+
+ It is different every time. A random byte lands somewhere new on each run, so a
+ failure on Tuesday may not come back on Wednesday.
+
+
+ It changes the size. A file cut short is smaller than the limit it was meant to
+ sit under, so the size check answers before the content check and the test passes for the wrong
+ reason.
+
+
+ It often goes unnoticed. Plain text still reads with a byte changed in the
+ middle, and a forgiving image reader just draws it, so the file you meant to be broken is
+ accepted.
+
+
+ It says nothing about what should happen. The file is only bytes, and whoever
+ reads the test next has to guess whether acceptance or rejection was intended.
+
+
+
+
+
+
What you get
+
A damaged file is still the size you asked for
+
+ The file is generated normally and broken afterwards, on its way to the disk. It keeps the size
+ you asked for, and the same command writes the same bytes again.
+
+ Settings go after a colon. The flag can be repeated, and the damages are applied in the order you
+ write them. It works with every one of the 26 formats.
+
+
+
+
+
What it can do
+
Which damages are there?
+
+ This is the list the program prints, read from it when this page is built. tfg damage
+ prints the same, and tfg damage <id> says what one of them takes.
+
+
+
+
+
+
Damage
+
What it does to the bytes
+
Smallest file
+
Settings
+
+
+
+
+
zero-head
+
Overwrites the first bytes of the file with zeros, leaving its length alone. Most readers look there first, so this is the damage almost anything notices.
+
8
+
bytes
+
+
+
+
+
+ zero-head writes zeros over the start of the file. Most readers look there first, at
+ the signature and the header that say what the file is, so almost any reader notices. Plain text
+ and logs have no signature and are turned away as well, because a run of zero bytes is not text.
+ Below four bytes some formats come out with damage that no reader complains about, which is why
+ the setting starts at four.
+
+
+
+
+
What the manifest says
+
A manifest that says what should happen
+
+ Every damaged file gets an entry saying your system should reject it, with the damage recorded
+ beside it:
+
+ Two requests are refused before anything is written, because each would leave a file on disk that
+ the manifest describes wrongly:
+
+
+
a file smaller than the damage needs, which would come out unchanged
+
+ expected: accept beside a damage, because nothing could meet it. Write
+ sanitize if your system is meant to repair the file, or unspecified if
+ that is the question you are asking
+
+
+
+
+
+
In a recipe
+
Healthy and broken files in one run
+
+ Put both in one recipe, and the manifest carries the expectation of every file, so the test does
+ not need a list of which is which:
+
+ The test reads the manifest and checks that what happened is what was declared. It needs no list
+ of file names:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ A good refusal is a clean one. A message that says what was wrong is the answer you want. A server
+ error, a hang or a half stored file is the defect this test exists to find.
+
+ Vše, co nástroj dělá, uspořádané podle otázek, se kterými lidé skutečně přicházejí.
+ README v repozitáři je úplná reference a vždy odpovídá verzi,
+ kterou jste stáhli.
+
+
+
+
Jaké příkazy existují?
+
Každý dělá jednu věc:
+
tfg generate vytvořit soubory z receptu nebo z přepínačů
+tfg validate zkontrolovat recept a nic nezapisovat
+tfg verify zkontrolovat adresář proti manifestu
+tfg cleanup odstranit soubory, které manifest uvádí
+tfg recipe fmt vypsat recept v ustáleném tvaru
+tfg preset sestavit sadu souborů z pojmenované testovací otázky
+tfg formats vypsat formáty, které tato verze podporuje
+tfg damage vypsat způsoby, jak tato verze umí soubor schválně poškodit
+tfg tool drobné pomůcky pro soubory, které už máte
+tfg version vypsat verzi nástroje
+tfg license vypsat licenci a co znamená pro generované soubory
+
+
+
+
Jak vygeneruji jeden soubor přesné velikosti?
+
+ Uveďte formát, velikost a kam soubor půjde. Velikosti se počítají po 1024, takže 2mb je
+ 2097152 bajtů. Funguje i prostý počet bajtů, takže --size 10485761 žádá přesně
+ tolik.
+
+
tfg generate --format png --size 2mb --out ./out
+
Užitečné přepínače příkazu generate:
+
+
+
Přepínač
Co dělá
+
+
--format <id>
formát souborů, například txt
+
--size <size>
přesná velikost každého souboru, například 10mb nebo prostý počet bajtů
+
--size-range <a-b>
velikost losovaná pro každý soubor z rozsahu, například 1kb-8kb. Losování vychází ze seedu
+
--boundary <size>
tři soubory kolem limitu: o bajt pod, limit, o bajt nad
+
--count <n>
kolik souborů vytvořit. Výchozí 1
+
--name <template>
šablona názvu, například invoice_{index:04}.txt
+
--out <dir>
adresář, do kterého se zapisuje
+
--seed <n>
seed běhu. Stejný seed dává stejné bajty
+
--set <k>=<v>
nastavení formátu, lze opakovat
+
--damage <name>
záměrně soubory poškodit, lze opakovat a uplatňuje se v pořadí. Seznam získáte příkazem tfg damage
+
--expected <outcome>
accept, reject, sanitize nebo unspecified
+
--dry-run
spočítat a ukázat, nic nezapisovat
+
--json
zapsat manifest na standardní výstup
+
+
+
+
+
+
+
Jak vytvořím soubor, který je záměrně rozbitý?
+
+ Každý jiný soubor, který tento nástroj zapíše, je správný z konstrukce, což odpovídá na dvě ze tří
+ otázek, které klade validátor nahrávání. --damage odpovídá na třetí - zda se soubor
+ vůbec otevře. Soubor se vytvoří normálně a pak se rozbije, takže má stále velikost, o kterou
+ jste požádali.
+
+ Nastavení se zadávají za dvojtečku. Přepínač se opakuje a pořadí, v jakém je napíšete, je pořadí, v
+ jakém se uplatní. tfg damage vypíše, co tato verze umí a co která varianta přijímá.
+
+
V receptu je klíč seznam, a to názvů nebo nastavení:
+ Poškozený soubor dostane v manifestu expected: reject a vedle toho zaznamenané
+ poškození. Dvě věci jsou odmítnuty dříve, než se cokoli zapíše, protože každá by jinak dala na
+ disk soubor, který manifest popisuje špatně:
+
+
+
soubor menší, než poškození potřebuje, protože by vyšel beze změny
+
+ expected: accept vedle poškození, protože nic by to nemohlo splnit. Napište
+ sanitize, pokud má testovaný systém soubor opravit, nebo
+ unspecified, pokud je to právě ta otázka, kterou kladete
+
+
+
+ Třetí se předem zjistit nedá. Pokud se poškození provede a nepohne žádným bajtem, soubor se zahodí
+ místo zapsání - běh pokračuje, řekne, o který soubor šlo, a skončí s částečným návratovým kódem.
+
+ Recept je soubor YAML popisující celý běh. Commitujte ho vedle testů a fixtures přestanou být
+ binárkami ve vašem repozitáři - kdokoli je může bajt po bajtu znovu sestavit ze souboru o
+ několika stovkách znaků.
+
+ Každý target potřebuje přesně jeden z klíčů size, size-range,
+ boundary nebo contains. Dva jsou chyba a žádný také. Neplatný recept
+ nezapíše žádné soubory a nahlásí všechny problémy najednou, ne jen první, každý
+ s názvem nastavení, kterého se týká.
+
+
+
+
+
Jak deklaruji, co má můj systém se souborem udělat?
+
Krátká forma, když stačí výsledek, dlouhá forma, když záleží na důvodu:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Výsledky jsou accept, reject, sanitize a
+ unspecified. Důvody tvoří uzavřený seznam, aby podle nich mohl report seskupovat:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit a size_zero.
+
+
+ Důvod pojmenovává pravidlo, o které jde, ne verdikt. Proto může stejný důvod stát
+ pod oběma výsledky - soubor o bajt pod limitem je accept a pravidlo, o které jde,
+ je stále size_limit.
+
+
+
+
+
Co obsahuje manifest?
+
+ Zapisuje se vedle souborů na konci každého běhu, včetně přerušeného. Jedna položka na soubor:
+
+ recipe_hash se přidá, když běh pochází z receptu, a preset s
+ overrides, když pochází z předvolby, takže manifest lze vždy dohledat k tomu, co ho
+ vytvořilo.
+
+
+ Každá položka nese také target_id, id targetu v receptu, který soubor vytvořil, a
+ summary.by_target počítá soubory, ke kterým každý target dospěl. Recept s více
+ targety lze tak kontrolovat target po targetu, aniž by se četly názvy souborů.
+
+
+
+
+
Co je předvolba?
+
+ Hotová sada souborů, která odpovídá na běžnou testovací otázku, abyste sadu nemuseli navrhovat sami.
+ Předvolby jsou pod povrchem obyčejné recepty a eject recept vypíše, takže ho můžete
+ odtud upravit. Každá předvolba má vlastní stránku s tím, co obvykle
+ najde, co je v sadě a jaké nastavení přijímá.
+
+ show vám řekne, kolik by sada stála, než ji sestavíte, a otevřeně řekne, když je číslo
+ naším zástupným údajem, a ne vaším limitem.
+
+
+
+
+
Co znamenají návratové kódy?
+
+ Každý konec má svůj kód, strojově čitelný výstup jde na standardní výstup a neúspěšný běh tam
+ nevypíše nic. Tabulka je zmrazená smlouva - změna významu kódu vyžaduje novou hlavní verzi.
+
+
+
+
+
+
Kód
+
Význam
+
+
+
+
+
0
+
Vše fungovalo.
+
+
+
1
+
Neočekávaná chyba uvnitř nástroje.
+
+
+
2
+
Špatný příkaz nebo přepínač.
+
+
+
3
+
Recept není platný.
+
+
+
4
+
Formát neumí to, co bylo požadováno.
+
+
+
5
+
Čtení nebo zápis selhal.
+
+
+
6
+
Nedostatek místa na disku.
+
+
+
7
+
verify našel nesrovnalost.
+
+
+
8
+
Běh skončil, ale nebylo vytvořeno všechno.
+
+
+
130
+
Přerušeno pomocí Ctrl+C.
+
+
+
143
+
Zastaveno signálem, tak vypadá vypršení času v CI.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Běh zastavený pomocí Ctrl+C po sobě stále zanechá manifest a nikdy nenechá napůl zapsaný soubor,
+ takže zrušenou úlohu může následující stále uklidit.
+
+ Ano, stejný motor s oknem navrch, pro testování, které se neskriptuje. Není to osekaná verze: test
+ porovnává obě rozhraní schopnost po schopnosti a cokoli, co umí jen jedno z nich, musí být
+ deklarováno a zdůvodněno, ne tiše se rozcházet.
+
+
+ Obrazovky jsou jedna dávka, předvolby, více dávek najednou a O aplikaci. Ukáže, kolik by běh stál,
+ než cokoli zapíše, hlásí průběh a lze ho zrušit uprostřed, aniž by zanechal napůl zapsaný
+ soubor. Soubor receptu zatím neotevře - recepty jsou zatím záležitostí příkazového řádku a okno
+ sestavuje své dávky ve formuláři.
+
+ Licence, soukromí, opakovatelnost a věci, které lidé ověřují, než generátor zařadí do build
+ pipeline. Pokud tu vaše otázka není, sledování issues je
+ otevřené.
+
+
+
+
+
Čím se to liší od dd, fsutil nebo truncate?
+
+
Ty vám dají soubor správné velikosti plný ničeho. Soubor o 2 MB pojmenovaný photo.png vytvořený takto není PNG, takže ho cokoli, co ho skutečně zpracovává, odmítne z nesprávného důvodu a váš test pak projde také z nesprávného důvodu. Tohle vytvoří skutečné PNG o přesně 2 MB, které se otevře v prohlížeči obrázků, a přichází s prohlášením, jak s ním má váš systém naložit.
Ano k obojímu. Je vydáno pod GPL-3.0 a nestojí nic. Není tu účet, licenční klíč ani placená úroveň.
+
+
+
+
Mohu generované soubory použít v produktu s uzavřeným zdrojovým kódem?
+
+
Ano. Licence se vztahuje na kód nástroje, ne na to, co nástroj vytváří. Generované soubory, recepty a manifesty jsou výstup, nikoli odvozená díla, takže je můžete commitovat a dodávat bez jakékoli povinnosti.
+
+
+
+
Obsahují generované soubory skutečné osobní údaje?
+
+
Ne. Vše uvnitř je syntetizováno ze seedu. Nečte se žádný datový soubor, nekontaktuje se žádná služba a nevkládá se obsah třetích stran. Vygenerovanou e-mailovou adresu považujte za nepoužitelnou, ne za nepoužitou, protože libovolný náhodný řetězec se může shodou okolností shodovat se skutečným.
+
+
+
+
Dostanu na jiném počítači přesně stejné soubory?
+
+
Ano, bajt po bajtu, při stejném receptu a stejném seedu. Projekt to testuje při každé změně a porušit to vyžaduje novou hlavní verzi. Díky tomu můžete commitovat malý recept místo velkých binárních fixtures.
+
+
+
+
Potřebuje připojení k internetu?
+
+
Nikdy. Není tu telemetrie, kontrola aktualizací ani cloudový klient a do binárky příkazového řádku není zkompilován žádný síťový zásobník. Funguje na počítači bez sítě i v uzavřeném firemním prostředí.
+
+
+
+
Co se stane, když požádám o velikost, které formát nedosáhne?
+
+
Dostanete chybu, která pojmenuje formát, nejmenší možnou velikost, důvod tohoto minima a co dělat místo toho, a nezapíše se žádný soubor. Nástroj nikdy velikost mlčky nezaokrouhlí. Každé minimum je uvedeno na stránce formátů.
+
tfg formats png
+
+
+
+
Mohu vygenerovat soubor, který je záměrně rozbitý?
+
+
Ano. Přidejte --damage zero-head a soubor vyjde v přesně požadované velikosti, s prvními bajty přepsanými nulami, takže ho čtečka odmítne, a manifest říká, že ho má váš systém odmítnout. Podrobnosti jsou na stránce o poškozených testovacích souborech.
7z, mp3 a mp4. Dnes funguje od začátku do konce 26 formátů.
+
+
+
+
Na kterých systémech to mohu spustit?
+
+
Příkazový řádek běží na Windows a Linuxu na Intelu i ARM a na Macích s Apple Silicon. Desktopové okno se dodává pro Windows na Intelu, Linux na Intelu a Macy s Apple Silicon. Intel Macy nejsou podporovány a nic se pro ně nesestavuje.
+
+
+
+
Musím něco instalovat?
+
+
Ne. Stáhněte archiv pro svůj systém, rozbalte ho a spusťte binárku. Není tu instalátor, běhové prostředí k doplnění ani závislost k vyřešení. Pokud máte Go, funguje i jediný příkaz go install.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
Proč je běh nad tisíci soubory na Windows pomalejší?
+
+
Protože Windows si účtuje víc za každou cestu, na kterou se podívá, a příkaz, který prochází tisíce souborů, se dívá na tisíce cest. Změřeno na jednom počítači s 3000 soubory po 1 kB: verify trvá na Windows asi 0,9 sekundy a na Linuxu v kontejneru asi 0,2 sekundy. Kratší výstupní cesta číslo na Windows zmenší, protože každá složka nad soubory je součástí toho, na co se dívá.
26 formátů souborů, každý generovaný v přesné velikosti
+
+ Každý z nich je skutečný soubor toho formátu. Otevře se v programu, kam patří, a má
+ přesně tolik bajtů, kolik jste požádali. Žádný není vycpávka z nul s přilepenou příponou.
+
+
+
+
+
+
+
Formát
+
Název
+
Přípona
+
Nejmenší soubor
+
Úplnost
+
Ověřeno pomocí
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
nelze použít
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
nelze použít
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
nelze použít
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
Co znamenají sloupce
+
+
+
Nejmenší soubor
+
+ Nejméně bajtů, které tento nástroj pro daný formát přijme, včetně štítku, který zapisuje do souboru.
+ Požádejte o méně a dostanete chybu, která pojmenuje minimum a jeho důvod, nikdy soubor
+ špatné velikosti.
+
+
+
+
Úplnost
+
+ Jak úplný soubor je. full znamená, že ho přijme čtečka, která formát skutečně
+ zpracovává, ne jen že přípona souhlasí.
+
+
+
+
Ověřeno pomocí
+
+ Nezávislá čtečka, která otevře každý vygenerovaný soubor, než se formát vydá - samostatná
+ implementace, ne náš vlastní kód, který opravuje své vlastní úkoly.
+
+
+
+
+ Každý formát se také opakuje na bajt: stejný recept a stejný seed vytvoří na jakémkoli počítači
+ identické soubory, a to dělá z receptu bezpečnou věc k commitování místo samotných fixtures.
+
+
+
+
+
Nastavení, která každý formát přijímá
+
+ Většina formátů má vlastní nastavení - rozměry obrázku, kvalitu JPEG, počet stránek PDF, řádky a
+ sloupce v tabulce, kolik položek jde do archivu. Nastavte je pomocí --set key=value
+ v příkazovém řádku nebo pod properties: v receptu.
+
datum, například 2024-02-29 nebo 2024-02-29T13:45:00+02:00, nebo none
+
+
+
+
modified
+
datum, například 2024-02-29 nebo 2024-02-29T13:45:00+02:00, nebo none
+
+
+
png
+
width
+
1 - 20000 pixelů
+
+
+
+
height
+
1 - 20000 pixelů
+
+
+
pptx
+
slides
+
1 - 500 snímků
+
+
+
svg
+
width
+
1 - 20000 pixelů
+
+
+
+
height
+
1 - 20000 pixelů
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
id formátu tak, jak je vypisuje tfg formats
+
+
+
+
entry_size
+
velikost, například 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
pravda nebo nepravda
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 pixelů
+
+
+
+
height
+
1 - 20000 pixelů
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
pravda nebo nepravda
+
+
+
wav
+
sample_rate
+
8000 - 192000 hertzů
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 pixelů
+
+
+
+
height
+
1 - 16383 pixelů
+
+
+
xlsx
+
rows
+
1 - 200000 řádků
+
+
+
+
columns
+
1 - 32768 sloupců
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
pravda nebo nepravda
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
id formátu tak, jak je vypisuje tfg formats
+
+
+
+
entry_size
+
velikost, například 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
pravda nebo nepravda
+
+
+
+
password
+
heslo ve formě prostého textu
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ Hodnota mimo to, co nastavení přijímá, je odmítnuta zprávou, která pojmenuje nastavení, povolený
+ rozsah a co použít místo toho. Neznámé nastavení je také chyba, nikdy tichá výchozí hodnota -
+ tiše přijatý překlep dá soubor se špatným nastavením a hodinu přemýšlení, proč test prochází,
+ když neměl.
+
+
+ Spusťte tfg formats <id> a uvidíte přesně, co jeden formát v dané verzi přijímá.
+
+
+
+
+
Archivy obsahují skutečné soubory
+
+ targz a zip lze
+ naplnit položkami, místo aby zůstaly prázdnou skořápkou. Vygenerovaný archiv skutečně obsahuje
+ dokumenty, které tvrdí, že obsahuje, takže cokoli ho během testu rozbalí, uvnitř najde skutečné
+ soubory.
+
Generujte skutečné testovací soubory v přesné velikosti
+
+ PDF, PNG, DOCX, ZIP - celkem 26 formátů a každý je skutečný
+ soubor, který se otevře v programu, kam patří, v přesně té velikosti, o kterou jste
+ požádali. Každý běh také zapisuje, co má vaše aplikace s každým souborem udělat.
+ Příkazový řádek a desktopové okno, zdarma a open source, celé na vašem počítači.
+
Zdarma a open source, GPL-3.0. Žádná registrace. Stažené soubory pro Windows a macOS jsou podepsané a spustí se bez varování.
+
+
+
+
+ Desktopové okno připravené zapsat dávku souborů. Za příkazovým řádkem běží stejný motor.
+
+
+
+
+
+ 26
+
skutečných formátů, každý se otevře v programu, kam patří
+
+
+ 1 bajt
+
přesnost každé požadované velikosti, nikdy mlčky nezaokrouhlená
+
+
+ 0
+
spojení kamkoli - žádný účet, žádná telemetrie, žádná kontrola aktualizací
+
+
+
+
+
Problém
+
Vytvořit jeden testovací soubor je snadné. Vytvořit těch správných tisíc je ta únavná část
+
Testujete software, který přijímá soubory od lidí. Dříve nebo později budete potřebovat:
+
+
PDF o přesně 10 MB, abyste zjistili, zda je limit nahrávání skutečný
+
tři soubory po obou stranách tohoto limitu, abyste zachytili chyby o jedna
+
10 000 souborů logu, abyste viděli, co udělá noční úloha, když je složka velká
+
ZIP, který skutečně obsahuje 200 dokumentů, ne prázdnou skořápku se správnou příponou
+
soubor o 4 GB, aniž byste ve svém repozitáři drželi soubor o 4 GB
+
stejné fixtures na notebooku i na build serveru, bajt po bajtu
+
+
+ To je to, co toto nahrazuje. Je určeno pro QA inženýry, automatizaci testů a každého, za jehož kódem
+ stojí formulář pro nahrávání, importní rutina, parser nebo kvóta úložiště.
+
+
+
+
+
Čím se liší
+
Jiné generátory končí u bajtů. Tento odpovídá na to, na co se váš test skutečně ptá
+
+ Složka souborů vás stále nechává rozhodovat, co má který dokazovat. Každý běh tady zapíše vedle
+ souborů manifest.json - prostý seznam všeho vytvořeného a u každé položky
+ deklarované očekávání.
+
+
Řekněme, že váš endpoint pro nahrávání povoluje 1 MB. Požádejte o tři soubory, které leží na té hranici:
Kde odpověď závisí na vaší vlastní politice, manifest to říká
+
+ Zapíše unspecified, místo aby vymýšlel očekávání. Generátor, který hádá, vytváří
+ falešná selhání a sada testů, která křičí vlk, bude vypnuta.
+
+
+
+
+
+
Předvolby
+
Vyberte otázku, získejte celou sadu
+
+ Předvolba je sada testovacích souborů navržená kolem jedné testovací otázky, abyste nemuseli
+ vymýšlet, které soubory co dokazují. Každá má stránku, která říká, co obvykle najde, co je v
+ sadě a jaké nastavení přijímá.
+
+ Deset tisíc souborů logu, každý mezi jedním a osmi kilobajty, s velikostmi losovanými ze seedu, aby
+ zítra vyšla stejná sada. Dejte každému běhu vlastní adresář - manifest je
+ jediný záznam o tom, co běh zapsal, takže nástroj odmítne zapsat druhý přes něj:
+
+ Velikosti se počítají po 1024, jak to dělá váš správce souborů, takže 2mb znamená
+ 2097152 bajtů. Funguje i prostý počet bajtů. Dokumentace pokrývá
+ recepty, manifest a návratové kódy.
+
+
+
+
+
Co získáte
+
Vytvořeno pro sadu testů, která běží bez dozoru
+
+
+
Přesná velikost, na bajt
+
Požádejte o 10485761 bajtů a dostanete přesně tolik. Velikost, které formát nedosáhne, je chyba s důvodem, nikdy soubor špatné velikosti.
+
+
+
26 skutečných formátů
+
Ne vycpávkové nuly s příponou. Vygenerované PNG se otevře v prohlížeči obrázků, DOCX ve Wordu, ZIP se rozbalí. Každý formát je před vydáním ověřen nezávislými čtečkami.
+
+
+
Manifest, který je testovací orákulum
+
Cesta, velikost, SHA-256, formát, seed, verze nástroje - a co má váš systém se souborem udělat.
+
+
+
Opakovatelné
+
Stejný recept a stejný seed, stejné bajty, na jakémkoli počítači. Commitujte malý recept YAML místo velkých binárních fixtures.
+
+
+
Dvě rozhraní, jeden motor
+
Příkazový řádek vytvořený pro CI a desktopové okno pro průzkumné testování. Ani jedno není osekanou verzí druhého a test je porovnává schopnost po schopnosti.
+
+
+
Zcela offline
+
Žádný účet, žádný cloud, žádná telemetrie, žádná kontrola aktualizací. V binárce příkazového řádku není zkompilován vůbec žádný síťový zásobník.
+
+
+
+
+
+
Stažení
+
Vyberte verzi pro svůj systém
+
+ Rozbalte archiv a spusťte ho. tfg je příkazový řádek a tfg-gui je
+ desktopové okno. Není tu instalátor a nic, co by se do vašeho počítače přidávalo.
+
+
+
+
+
+
Systém
+
Příkazový řádek
+
Desktopové okno
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
Co je podepsáno a co ne
+
+ Soubory ke stažení pro Windows a macOS jsou podepsané, takže se spustí bez varování o neznámém
+ vývojáři. Ty pro Linux ne, protože desktopový Linux nemá ekvivalent, kterým by je šlo
+ podepsat. Každý archiv je uveden v verify-SHA256SUMS.txt na stránce vydání, takže
+ můžete ověřit, co jste stáhli.
+
+ Validátor, kterému se ukazovaly jen zdravé soubory, nebyl opravdu otestován. Tady je postup, jak
+ získat soubor záměrně rozbitý, který vyjde přesně v požadované velikosti a nese
+ manifest říkající, co s ním má váš systém udělat.
+
+
+
+
Stručná odpověď
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out zapíše PNG o přesně
+ 2097152 bajtech, jehož první bajty jsou nuly, a manifest vedle něj zaznamená, že ho má váš
+ systém odmítnout.
+
+
+
+
+
Obvyklý způsob
+
Proč je ručně poškozený soubor špatný test
+
+ Obvykle se sáhne po hexadecimálním editoru, skriptu, který převrátí pár náhodných bajtů, nebo po
+ zkrácení souboru pomocí head či truncate. Jednou to funguje a pak to
+ stojí:
+
+
+
+ Pokaždé je to jiné. Náhodný bajt padne při každém spuštění jinam, takže chyba z
+ úterý se ve středu nemusí vrátit.
+
+
+ Mění to velikost. Zkrácený soubor je menší než limit, pod kterým měl zůstat, takže
+ kontrola velikosti odpoví dřív než kontrola obsahu a test projde z nesprávného důvodu.
+
+
+ Často si toho nikdo nevšimne. Prostý text se dá číst i se změněným bajtem uprostřed
+ a shovívavá čtečka obrázků ho prostě vykreslí, takže soubor, který měl být rozbitý, se přijme.
+
+
+ Neříká, co se má stát. Soubor jsou jen bajty a ten, kdo test čte později, musí
+ hádat, zda se mělo přijmout, nebo odmítnout.
+
+
+
+
+
+
Co dostanete
+
Poškozený soubor má stále velikost, kterou jste chtěli
+
+ Soubor se vygeneruje normálně a poškodí se až potom, cestou na disk. Zachová velikost, kterou jste
+ chtěli, a stejný příkaz zapíše znovu stejné bajty.
+
+ Nastavení se píše za dvojtečku. Přepínač lze opakovat a poškození se použijí v pořadí, v jakém je
+ zapíšete. Funguje s každým z 26 formátů.
+
+
+
+
+
Co umí
+
Jaká poškození existují?
+
+ Toto je seznam, který program vypisuje, načtený z něj při sestavení této stránky. tfg
+ damage vypíše totéž a tfg damage <id> řekne, co které z nich přijímá.
+
+
+
+
+
+
Poškození
+
Co dělá s bajty
+
Nejmenší soubor
+
Nastavení
+
+
+
+
+
zero-head
+
Přepíše prvních několik bajtů souboru nulami a jeho délku nechá být. Většina čteček se dívá nejdřív tam, takže si tohoto poškození všimne téměř cokoli.
+
8
+
bytes
+
+
+
+
+
+ zero-head zapíše nuly přes začátek souboru. Většina čteček se dívá nejdřív tam, na
+ signaturu a hlavičku, které říkají, co soubor je, takže si toho všimne téměř každá. Prostý text
+ a logy signaturu nemají a odmítnou se také, protože řada nulových bajtů není text. Pod čtyřmi
+ bajty některé formáty vyjdou s poškozením, na které si žádná čtečka nestěžuje, proto nastavení
+ začíná na čtyřech.
+
+
+
+
+
Co říká manifest
+
Manifest, který říká, co se má stát
+
+ Každý poškozený soubor dostane záznam, že ho má váš systém odmítnout, s poškozením zapsaným vedle:
+
+ Dva požadavky se odmítnou dřív, než se cokoli zapíše, protože každý by na disku nechal soubor, který
+ manifest popisuje špatně:
+
+
+
soubor menší, než poškození potřebuje, který by vyšel nezměněný
+
+ expected: accept vedle poškození, protože by to nic nemohlo splnit. Napište
+ sanitize, pokud má váš systém soubor opravit, nebo unspecified,
+ pokud je právě to vaše otázka
+
+
+
+
+
+
V receptu
+
Zdravé a rozbité soubory v jednom běhu
+
+ Dejte obojí do jednoho receptu a manifest ponese očekávání každého souboru, takže test nepotřebuje
+ seznam, který je který:
+
+ Test přečte manifest a ověří, že to, co se stalo, je to, co bylo uvedeno. Nepotřebuje seznam názvů
+ souborů:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Dobré odmítnutí je čisté. Zpráva, která říká, co bylo špatně, je odpověď, kterou chcete. Chyba
+ serveru, zaseknutí nebo napůl uložený soubor je vada, kterou má tento test najít.
+
+ Předvolba empty-and-minimal sestaví jediným příkazem celou sadu skutečných testovacích souborů
+ pro tuto otázku a vedle nich manifest.json, který říká, jak má váš systém na každý
+ soubor reagovat. Vše níže se čte z programu při výchozích hodnotách této verze.
+
+
+
+
+
Co obvykle najde?
+
+
platný soubor odmítnutý jako příliš malý, protože kontrola počítá bajty místo toho, aby je četla
+
prázdný soubor, který shodí čtečku, místo aby byl nahlášen
+
obrázek široký jeden pixel, který cestou k náhledu dělí nulou
+
úložiště, které čte nula bajtů jako selhané nahrání a stále to opakuje
+
+
+
+
+
+
Co je v sadě?
+
Při výchozích hodnotách, jak je hlásí tfg preset show empty-and-minimal:
Uloží, zobrazí a vrátí můj systém název souboru, který nečekal?
+
+ Předvolba filename-handling sestaví jediným příkazem celou sadu skutečných testovacích souborů
+ pro tuto otázku a vedle nich manifest.json, který říká, jak má váš systém na každý
+ soubor reagovat. Vše níže se čte z programu při výchozích hodnotách této verze.
+
+
+
+
+
Co obvykle najde?
+
+
název, který na obrazovce, v logu nebo v seznamu vypadá jako jiný
+
název oříznutý, zkrácený nebo přepsaný mezi nahráním a uložením
+
limit délky počítaný ve znacích tam, kde úložiště počítá bajty
+
+
+
+
+
+
Co je v sadě?
+
Při výchozích hodnotách, jak je hlásí tfg preset show filename-handling:
+
+
+
+
Soubory
50
+
Targety v receptu
50
+
Celková velikost
51 200 B
+
Formáty
txt
+
+
+
+
A co od vašeho systému očekává manifest té sady:
+
+
+
+
Očekáváno
Význam
Soubory
+
+
+
accept
Váš systém má soubor přijmout.
4
+
unspecified
Záleží na pravidlech vašeho systému. Rozhodnete vy, a pak ověříte, že to, co se stane, je to, co jste chtěli.
46
+
+
+
+
+
+
+
Co můžete změnit?
+
+
+
+
Nastavení
Přijímá
Výchozí
Co dělá
+
+
+
+
--format
+
id formátu ze stránky formátů
+
txt
+
Formát každého souboru v sadě. Je to přepínač samotného nástroje a předvolba mu jen dává výchozí hodnotu.
+
+
+
+
+
+
+
+
Jak ji spustit?
+
Podívejte se, kolik by sada stála, sestavte ji, nebo si vezměte její recept k úpravě:
Předvolby testovacích souborů, jedna sada pro každou testovací otázku
+
+ Předvolba je celá sada testovacích souborů navržená kolem jedné otázky, s manifestem, který říká,
+ jak má váš systém na každý soubor reagovat. Vy vyberete otázku, nástroj sestaví sadu. Každá
+ předvolba má vlastní stránku s tím, co obvykle najde, co je v sadě a jaké nastavení přijímá.
+
Přijme můj formulář pro nahrávání to, co má, a zbytek odmítne?
+
upload-validation
+
+
+
+
+
Čím se předvolba liší od receptu?
+
+ Pod povrchem ničím. Předvolba je recept, který za vás nástroj napíše z několika nastavení. tfg
+ preset eject tento recept vypíše, abyste si ho mohli ponechat vedle testů a upravovat, a
+ váš vlastní recept může na předvolbě stavět jedním řádkem, extends: preset:
+ následovaným jejím id.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Mohu výchozím hodnotám věřit?
+
+ U souborů ano. U čísla, které zná jen váš systém, například limitu formuláře pro nahrávání, je
+ výchozí hodnota naším zástupným údajem a nástroj to řekne pokaždé, když nějaký použije. Stránka
+ každé předvolby tato nastavení označuje a tfg preset show to řekne dřív, než se
+ cokoli zapíše.
+
Je limit velikosti vynucován přesně tam, kde je deklarován?
+
+ Předvolba size-boundaries sestaví jediným příkazem celou sadu skutečných testovacích souborů
+ pro tuto otázku a vedle nich manifest.json, který říká, jak má váš systém na každý
+ soubor reagovat. Vše níže se čte z programu při výchozích hodnotách této verze.
+
+
+
+
+
Co obvykle najde?
+
+
chyby o jedna na hranici limitu
+
MB zaměněné za MiB, což je 4,8 procenta a stačí to k propuštění souboru, který projít neměl
+
limit vynucovaný v prohlížeči a ne na serveru
+
+
+
+
+
+
Co je v sadě?
+
Při výchozích hodnotách, jak je hlásí tfg preset show size-boundaries:
+
+
+
+
Soubory
7
+
Targety v receptu
7
+
Celková velikost
73 400 320 B
+
Formáty
pdf
+
+
+
+
A co od vašeho systému očekává manifest té sady:
+
+
+
+
Očekáváno
Význam
Soubory
+
+
+
accept
Váš systém má soubor přijmout.
4
+
reject
Váš systém má soubor odmítnout.
3
+
+
+
+
+
+
+
Co můžete změnit?
+
+
+
+
Nastavení
Přijímá
Výchozí
Co dělá
+
+
+
+
--limit
+
velikost, například 2mb
+
10mb
+
Limit velikosti, který váš systém deklaruje. Vše ostatní se měří od něj. Tato výchozí hodnota je náš zástupný údaj, ne hodnota vašeho systému. Zadejte vlastní.
+
+
+
--spread
+
velikosti oddělené čárkami
+
1B,1kb,1mb
+
Jak daleko na obě strany od limitu zajít, jako seznam velikostí.
+
+
+
--format
+
id formátu ze stránky formátů
+
pdf
+
Formát každého souboru v sadě. Je to přepínač samotného nástroje a předvolba mu jen dává výchozí hodnotu.
+
+
+
+
+
+
+
+
Jak ji spustit?
+
Podívejte se, kolik by sada stála, sestavte ji, nebo si vezměte její recept k úpravě:
Přežije můj import tabulek to, co exportují skutečné nástroje?
+
+ Předvolba tabular-import sestaví jediným příkazem celou sadu skutečných testovacích souborů
+ pro tuto otázku a vedle nich manifest.json, který říká, jak má váš systém na každý
+ soubor reagovat. Vše níže se čte z programu při výchozích hodnotách této verze.
+
+
+
+
+
Co obvykle najde?
+
+
soubor se středníky přečtený jako jediný sloupec, protože oddělovač se předpokládal, místo aby se hledal
+
soubor CRLF rozdělený na řádky s prázdným řádkem za každým
+
tabulka bez hlavičky, jejíž první datový řádek se spolkne jako názvy sloupců
+
import, který ponechá sloupce, které umí zobrazit, a zbytek beze slova zahodí
+
čtečka, která bere záznamy JSON po jednom řádku a zastaví se u prvního odsazeného dokumentu
+
+
+
+
+
+
Co je v sadě?
+
Při výchozích hodnotách, jak je hlásí tfg preset show tabular-import:
+
+
+
+
Soubory
13
+
Targety v receptu
13
+
Celková velikost
3 080 060 B
+
Formáty
csv, json, xlsx
+
+
+
+
A co od vašeho systému očekává manifest té sady:
+
+
+
+
Očekáváno
Význam
Soubory
+
+
+
accept
Váš systém má soubor přijmout.
8
+
unspecified
Záleží na pravidlech vašeho systému. Rozhodnete vy, a pak ověříte, že to, co se stane, je to, co jste chtěli.
5
+
+
+
+
+
+
+
Co můžete změnit?
+
+
+
+
Nastavení
Přijímá
Výchozí
Co dělá
+
+
+
+
--rows
+
1 - 200000 řádků
+
1000
+
Kolik řádků tabulka obsahuje. Zapisuje se přesně v takové velikosti, jakou tolik řádků zabere, takže rozpočet výše se s touto hodnotou posouvá.
+
+
+
--columns
+
1 - 32768 sloupců
+
10
+
Kolik sloupců má každý řádek tabulky. Řádky krát sloupce mají strop a požadavek nad ním je odmítnut dříve, než se cokoli zapíše.
+
+
+
+
+
+
+
+
Jak ji spustit?
+
Podívejte se, kolik by sada stála, sestavte ji, nebo si vezměte její recept k úpravě:
Ví moje čtečka, v jakém kódování soubor je, nebo hádá?
+
+ Předvolba text-encoding sestaví jediným příkazem celou sadu skutečných testovacích souborů
+ pro tuto otázku a vedle nich manifest.json, který říká, jak má váš systém na každý
+ soubor reagovat. Vše níže se čte z programu při výchozích hodnotách této verze.
+
+
+
+
+
Co obvykle najde?
+
+
čtečka, která předpokládá UTF-8 a zobrazí soubor UTF-16 jako každý třetí znak nebo jako řady čtverečků
+
označení pořadí bajtů přečtené jako obsah, takže první pole importu začíná třemi cizími znaky
+
importér, který hádá kódování z prvních bajtů a u delšího souboru hádá jinak
+
soubor CRLF rozdělený na řádky s prázdným řádkem za každým, nebo návrat vozíku zůstávající v posledním poli
+
+
+
+
+
+
Co je v sadě?
+
Při výchozích hodnotách, jak je hlásí tfg preset show text-encoding:
+
+
+
+
Soubory
20
+
Targety v receptu
20
+
Celková velikost
81 920 B
+
Formáty
csv, log, md, txt, xml
+
+
+
+
A co od vašeho systému očekává manifest té sady:
+
+
+
+
Očekáváno
Význam
Soubory
+
+
+
accept
Váš systém má soubor přijmout.
10
+
unspecified
Záleží na pravidlech vašeho systému. Rozhodnete vy, a pak ověříte, že to, co se stane, je to, co jste chtěli.
10
+
+
+
+
+
+
+
Co můžete změnit?
+
+
+
+
Nastavení
Přijímá
Výchozí
Co dělá
+
+
+
+
--sample
+
velikost, například 2mb
+
4kb
+
Jak velký je každý soubor sady. UTF-16 ukládá dva bajty na znak, takže lichý počet je odmítnut.
+
+
+
+
+
+
+
+
Jak ji spustit?
+
Podívejte se, kolik by sada stála, sestavte ji, nebo si vezměte její recept k úpravě:
Přijme můj formulář pro nahrávání to, co má, a zbytek odmítne?
+
+ Předvolba upload-validation sestaví jediným příkazem celou sadu skutečných testovacích souborů
+ pro tuto otázku a vedle nich manifest.json, který říká, jak má váš systém na každý
+ soubor reagovat. Vše níže se čte z programu při výchozích hodnotách této verze.
+
+
+
+
+
Co obvykle najde?
+
+
limit vynucovaný v prohlížeči a ne na serveru
+
SVG nebo HTML považované za obrázek či prostý text, což je způsob, jak protlačit skript formulářem
+
soubor kontrolovaný podle přípony a nikdy neotevřený, takže PDF s názvem .jpg projde
+
formulář, který načte celé tělo do paměti, než se podívá, jak je velké
+
nahrání s názvem PHOTO.JPG odmítnuté tam, kde se photo.jpg přijme, nebo naopak
+
název s mezerami, závorkami nebo znaky mimo ASCII zapsaný na disk beze změny
+
+
+
+
+
+
Co je v sadě?
+
Při výchozích hodnotách, jak je hlásí tfg preset show upload-validation:
+
+
+
+
Soubory
71
+
Targety v receptu
22
+
Celková velikost
120 639 488 B
+
Formáty
html, jpg, pdf, png, svg, txt
+
+
+
+
A co od vašeho systému očekává manifest té sady:
+
+
+
+
Očekáváno
Význam
Soubory
+
+
+
accept
Váš systém má soubor přijmout.
56
+
reject
Váš systém má soubor odmítnout.
10
+
unspecified
Záleží na pravidlech vašeho systému. Rozhodnete vy, a pak ověříte, že to, co se stane, je to, co jste chtěli.
5
+
+
+
+
+
+
+
Co můžete změnit?
+
+
+
+
Nastavení
Přijímá
Výchozí
Co dělá
+
+
+
+
--limit
+
velikost, například 2mb
+
10mb
+
Limit velikosti, který váš formulář pro nahrávání deklaruje. Tato sada udělá jeden krok na každou stranu - pro soubor v každé vzdálenosti spusťte předvolbu size-boundaries. Tato výchozí hodnota je náš zástupný údaj, ne hodnota vašeho systému. Zadejte vlastní.
+
+
+
--allow
+
id formátů oddělená čárkami
+
jpg,png,pdf
+
Které typy má váš formulář přijímat. Každý se stane skutečným souborem toho typu a tvoří pozitivní kontrolu celé sady.
+
+
+
--deny
+
přípony oddělené čárkami
+
svg,html,exe,sh
+
Které přípony má váš formulář odmítat. Přípona, pro kterou tato verze nemá formát, přesto dostane soubor s tímto názvem, obsahující prostý text.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
Jak daleko za limit sahá jediný velký soubor. Vypněte, kde zapsání několikanásobku limitu nestojí za místo na disku.
+
+
+
--bulk
+
0 - 10000 souborů
+
50
+
Kolik souborů obsahuje hromadné nahrání. Nula tuto skupinu ze sady úplně vynechá.
+
+
+
+
+
+
+
+
Jak ji spustit?
+
Podívejte se, kolik by sada stála, sestavte ji, nebo si vezměte její recept k úpravě:
+ Pět úloh, které se objevují téměř v každém projektu přijímajícím soubory od lidí, a příkaz, který
+ každou provede. Každý příklad níže běží tak, jak je napsán.
+
+
+
+
Limity nahrávání
+
Test, zda je limit velikosti souboru vynucován tam, kde se tvrdí
+
+ Limit jsou tři testovací případy, ne jeden: těsně pod, přesně na něm a těsně nad. Získat je ručně
+ znamená počítat počty bajtů a doufat, že jste se nespletli o jedna. Požádejte raději o sadu:
+
+ Dostanete tři skutečná PDF o 1048575, 1048576 a 1048577 bajtech a manifest, který říká, že první dvě
+ mají být přijata a třetí odmítnuto pro size_limit. Váš test čte očekávání místo
+ toho, abyste ručně psali tři aserce - a když se limit změní, změníte jedno číslo a spustíte
+ znovu.
+
+
+ Totéž funguje bez předvolby, když chcete jedinou sadu hranic přímo v příkazu:
+
Držet fixtures mimo repozitář, aniž byste o ně přišli
+
+ Velké binární fixtures zpomalují klonování repozitáře a znepříjemňují revizi a nikdo nepozná, co se
+ změnilo, když se jeden vymění. Recept je pár set znaků YAML, které znovu sestaví totožné soubory
+ - bajt po bajtu, na jakémkoli počítači - protože každý soubor je odvozen ze
+ seedu běhu.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Každý konec má svůj vlastní návratový kód, takže pipeline rozliší špatný recept od plného disku a od
+ nesrovnalosti při ověření. Neúspěšný běh nevypíše na standardní výstup nic, takže parser logu
+ nečte chybu jako data.
+
+
+
+
+
Rozsah
+
Zjistit, co se stane, když je složka velká
+
+ Importní rutiny, noční úlohy a výpisy adresářů se chovají při deseti tisících souborů jinak než při
+ deseti. Velikosti losované z rozsahu dělají ze sady něco, co vypadá jako skutečný provoz, a ne
+ deset tisíc stejných souborů, a losování vychází ze seedu, takže sada je zítra stejná.
+
+ Běh větší než volné místo na disku je odmítnut dřív, než se zapíše první bajt, místo aby zaplnil
+ disk a selhal v půlce.
+
+
+
+
+
Archivy
+
Test rozbalovače s archivem, který skutečně obsahuje soubory
+
+ Prázdný archiv se správnou příponou nic nedokazuje o kódu, který ho otevírá a prochází, co je
+ uvnitř. Deklarujte obsah a archiv ho skutečně obsahuje:
+
+ Hloubka vnoření, počet položek a velikost toho, co je uvnitř, jsou věci, o kterých má importní
+ rutina názor, a takto zjistíte, jaké ty názory jsou.
+
+
+
+
+
Parsery a prohlížeče
+
Ověření, že váš vlastní kód čte formát tak, jak to dělá skutečný software
+
+ Každý formát zde je před vydáním ověřen nezávislou čtečkou - PNG se otevře a porovnají se jeho
+ pixely, DOCX čtou zpět samostatné knihovny, archiv se rozbalí. To znamená, že soubor, který váš
+ parser odmítne, je zjištění o vašem parseru, ne o generátoru.
+
+ Stránka formátů uvádí nastavení, která každý formát přijímá, a nejmenší
+ soubor, jakým každý může být.
+
+
+
+
+
Návody
+
Dva z nich podrobněji
+
+
+ Poškozené testovací soubory - soubor záměrně rozbitý,
+ přesné velikosti, s tím, co se s ním má stát, zapsaným v manifestu.
+
+
+ Testovací soubory v CI - workflow pro GitHub Actions, job
+ v GitLabu a návratové kódy, které shodí build.
+
+
+
+
+
+
Pro koho to je
+
+ QA inženýry, automatizaci testů a každého, za jehož kódem stojí formulář pro nahrávání, importní
+ rutina, parser nebo kvóta úložiště. Běží na počítači bez jakékoli sítě, na čem záleží v
+ uzavřeném firemním prostředí, kde generátor v prohlížeči není možnost.
+
+ Binární fixture v repozitáři zůstává navždy v jeho historii, nedá se posoudit v diffu a při velkém
+ souboru přestává být možný. Generujte soubory raději v pipeline z receptu. Recept je text, bajty
+ vycházejí pokaždé stejné a poslední krok dokáže, že se nic nepohnulo.
+
+
+
+
Stručná odpověď
+
+ Nainstalujte tfg, před testy spusťte tfg generate fixtures.yaml --out
+ ./fixtures a po nich tfg verify ./fixtures/manifest.json. Oba kroky shodí
+ build samy, s návratovým kódem, který říká proč.
+
+
+
+
+
Proč je necommitovat
+
Proč fixture nepatří do repozitáře
+
+
+ Zůstává v historii. Pozdější smazání binárního souboru klon nezmenší, protože každá
+ jeho verze je tam pořád.
+
+
+ Diff neukáže, co se změnilo. Recenzent vidí, že PDF je jiné, a nic víc. Recept se
+ změní o jeden řádek.
+
+
+ Velké soubory se nevejdou. GitHub odmítne push, který obsahuje soubor větší než 100
+ MB, takže test limitu nahrávání 500 MB nemá co commitovat.
+
+
+
+ Commitovat je třeba recept. Stejný recept a stejný seed zapíší na každém počítači stejné bajty,
+ takže soubor vygenerovaný v pipeline je soubor, který jste měli na notebooku.
+
+
+
+
+
Recept
+
Recept, který leží vedle testů
+
+ Tento zapíše pětadvacet faktur, které se mají přijmout, a dva obrázky nad limitem, které se mají
+ odmítnout, a manifest zaznamená obě očekávání:
+
+ Řádek s kontrolním součtem porovná archiv se souborem verify-SHA256SUMS.txt ze stejného
+ vydání. Verze je pevně daná, takže nové vydání nikdy nezmění build, na který jste nesáhli.
+
+ Každý konec má vlastní návratový kód, takže krok selže sám a log řekne který. Ty, které pipeline
+ potká:
+
+
+
3 - recept není platný. Nic se nezapsalo a každý problém je pojmenován
+
4 - formát neumí, co se chtělo, například velikost pod svým minimem
+
6 - na disku není dost místa
+
7 - tfg verify našel soubor, který nesedí s manifestem
+
8 - běh skončil, ale ne všechno se vytvořilo
+
+
+ Neúspěšný běh nevypíše nic na standardní výstup, takže parser logů nikdy nevezme chybu za data. Celá
+ tabulka je na stránce dokumentace.
+
+
+
+
+
PowerShell
+
Skript PowerShellu potřebuje ještě jeden řádek
+
+ PowerShell nevynese návratový kód programu ze souboru .ps1. Spusťte ho s
+ -File a skript odpoví 0, i když nástroj uvnitř práci odmítl, takže
+ build, který měl být červený, zezelená. Poslední řádek je celá oprava:
+
+ Tak se PowerShell chová, nejde o vlastnost tohoto nástroje. cmd, bash a
+ zsh nepotřebují nic navíc.
+
+
+
+
+
Více jobů
+
Sdílení fixtures mezi joby
+
+ Nahrávat je obvykle není třeba. Protože stejný recept zapisuje stejné bajty, může každý job spustit
+ vlastní tfg generate, což je rychlejší než nahrání a stažení. Když má job přijmout
+ soubory od jiného, spusťte po přenosu tfg verify nad manifestem a řekne vám, zda
+ to, co dorazilo, je to, co bylo zapsáno.
+
+ Každý systém na to má příkaz a všechny tři jsou níže. Dají vám soubor s přesně správným počtem bajtů
+ - a pro mnoho testů je to vše, co potřebujete. Každý příkaz na této stránce byl před
+ zveřejněním spuštěn na systému, kam patří.
+
+
+
+
Krátká odpověď
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Velikosti jsou v bajtech a 10 MB
+ počítané tak, jak je počítá váš správce souborů, je 10485760.
+
+
+
+
+
Windows
+
fsutil a verze v PowerShellu, která nepotřebuje nic navíc
+
+ fsutil je součástí Windows. Bere velikost v bajtech, takže si číslo
+ nejdřív spočítejte - 10 MB je 10485760, 100 MB je 104857600, 1 GB je 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Změřeno na Windows 11: funguje z běžného příkazového řádku a nepotřebuje zvýšená oprávnění a soubor
+ vyjde přesně na 10485760 bajtů.
+
+
PowerShell umí totéž bez volání jiného programu a rozumí jednotkám:
+ 10MB v PowerShellu znamená 10485760 bajtů, tedy stejné počítání po 1024 jako
+ Průzkumník, takže oba příkazy výše vytvoří stejnou velikost.
+
+
+
+
+
Linux
+
dd, truncate a fallocate a rozdíl, který lidi chytí
+
dd zná každý. Bajty skutečně zapisuje:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate je okamžitý, a to je ten háček. Změřeno na Alpine Linuxu: soubor hlásí
+ 10485760 bajtů a zabírá nula bloků - je to řídký soubor.
+ Cokoli, co ho čte, dostane deset megabajtů nul, ale disk místo nikdy neuvolnil:
+
+
truncate -s 10M test10mb.bin
+
+ To stačí k testu limitu nahrávání a klame to při testu diskové kvóty. fallocate je ten
+ správný, když musí být místo skutečné:
+
+
fallocate -l 10M test10mb.bin
+
A když musí být obsah nestlačitelný, aby ho archivátor nemohl znovu zmenšit:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, který není řídký, a dva, které už znáte
+
+ macOS dodává mkfile. Změřeno na macOS 26.6.2: 10485760 bajtů a 20480 bloků, takže místo
+ je skutečně přiděleno, ne jen slíbeno:
+
+
mkfile 10m test10mb.bin
+
dd a truncate tam jsou také a chovají se jako na Linuxu:
Soubor správné velikosti není soubor správného druhu
+
+ Vše výše vám dá blok nul. To stačí, když testovaná věc hledí jen na velikost - limit nahrávání,
+ kvótu, přenos. Přestane to stačit ve chvíli, kdy soubor cokoli otevře.
+
+
+ Změřeno a stojí za to to zkusit samostatně: vytvořte pomocí fsutil soubor o 2 MB,
+ pojmenujte ho photo.png a předejte ho knihovně pro obrázky. Pillow odpoví
+ cannot identify image file. Není to PNG. Nikdy nebylo - tvrdil to jen název.
+
+
+ To je důležitější, než to zní, kvůli tomu, jakým směrem test pak selže. Váš
+ endpoint pro nahrávání soubor odmítne, váš test zezelená a vy usoudíte, že limit velikosti
+ funguje. Neodmítl ho kvůli velikosti. Odmítl ho proto, že bajty nebyly obrázek, a pravidlo,
+ které jste chtěli otestovat, nebylo nikdy dosaženo.
+
+
+
parser ho odmítne dřív, než se podívá na jakékoli pravidlo velikosti
+
selže krok náhledu a chyba, kterou čtete, je o náhledu
+
antivirus nebo kontrola obsahu ho odmítne z třetího důvodu
+
prohlížeč nezobrazí nic a nikdo nepozná, zda je to ta chyba
+
+
+
+
+
Druhá cesta
+
Skutečný soubor toho formátu, v přesně té velikosti, o kterou jste požádali
+
+ To je to, co dělá Testing Files Generator. Soubor je pravý soubor svého formátu - otevře se v
+ programu, kam patří - a má přesný počet bajtů, o který jste požádali, na bajt:
+
+ Požádejte o velikost, které formát nedosáhne, a dostanete chybu, která pojmenuje minimum a jeho
+ důvod, nikdy soubor špatné velikosti. Stránka formátů uvádí každý
+ formát s nejmenším souborem, který umí vytvořit.
+
+
A limit jsou tři testovací případy, ne jeden, takže nástroj sestaví všechny tři:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ To vám dá 10485759, 10485760 a 10485761 bajtů a manifest, který říká, které má váš systém přijmout a
+ které odmítnout. Stránka případů použití to probírá spolu se
+ čtyřmi dalšími úlohami, pro které je určen.
+
Zdarma a open source, GPL-3.0. Žádná registrace. Stažené soubory pro Windows a macOS jsou podepsané a spustí se bez varování.
+
+
+
+
Tak který použít?
+
+
+
Použijte příkaz systému
+
+ Když soubor nic neotevírá. Test limitu velikosti na endpointu, který kontroluje velikost jako první,
+ přenos, kvóta, plný disk. Je to jeden řádek a už je nainstalovaný.
+
+
+
+
Použijte skutečný generátor
+
+ Když soubor cokoli zpracovává, vykresluje, importuje nebo rozbaluje - a když zítra na jiném počítači
+ potřebujete stejné fixtures, bajt po bajtu.
+
+
+
+
+ Oba jsou na této stránce, protože oba mají část času pravdu. Chybou, které je třeba se vyhnout, je
+ použít první tam, kde je třeba druhý, a číst zelený test jako důkaz.
+
+ Fünf Aufgaben, die in fast jedem Projekt vorkommen, das Dateien von Menschen annimmt, und der
+ Befehl, der jede erledigt. Jedes Beispiel unten läuft so, wie es geschrieben steht.
+
+
+
+
Upload-Limits
+
Testen, ob ein Dateigrößenlimit dort durchgesetzt wird, wo es angegeben ist
+
+ Ein Limit sind drei Testfälle, nicht einer: knapp darunter, genau darauf und knapp darüber. Die von
+ Hand zu bekommen heißt, Byte-Zahlen auszurechnen und zu hoffen, dass man sich nicht um eins
+ verzählt hat. Fordere stattdessen das Set an:
+
+ Du bekommst drei echte PDFs mit 1048575, 1048576 und 1048577 Bytes und ein Manifest, das sagt, dass
+ die ersten beiden akzeptiert und die dritte wegen size_limit abgelehnt werden soll.
+ Dein Test liest die Erwartung, statt dass du drei Assertions von Hand schreibst - und wenn sich
+ das Limit ändert, änderst du eine Zahl und startest neu.
+
+
+ Dasselbe geht ohne Preset, wenn du ein einzelnes Grenzen-Set inline willst:
+
Fixtures aus dem Repository heraushalten, ohne sie zu verlieren
+
+ Große binäre Fixtures machen ein Repository langsam beim Klonen und mühsam beim Review, und niemand
+ sieht, was sich geändert hat, wenn eine ersetzt wird. Ein Rezept sind ein paar hundert Zeichen
+ YAML, die die identischen Dateien neu erzeugen - Byte für Byte, auf jedem
+ Rechner - weil jede Datei aus dem Seed des Laufs abgeleitet wird.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Jedes Ende hat einen eigenen Exit-Code, sodass eine Pipeline ein schlechtes Rezept von einem vollen
+ Datenträger und von einer Abweichung bei der Prüfung unterscheiden kann. Ein fehlgeschlagener
+ Lauf gibt nichts auf der Standardausgabe aus, wodurch ein Log-Parser einen Fehler nicht als
+ Daten liest.
+
+
+
+
+
Skalierung
+
Herausfinden, was passiert, wenn der Ordner groß ist
+
+ Importroutinen, nächtliche Jobs und Verzeichnislisten verhalten sich bei zehntausend Dateien anders
+ als bei zehn. Aus einem Bereich gezogene Größen lassen das Set wie echten Datenverkehr aussehen
+ statt wie zehntausend identische Dateien, und die Ziehung kommt aus dem Seed, das Set ist also
+ morgen dasselbe.
+
+ Ein Lauf, der größer ist als der freie Platz auf dem Datenträger, wird vor dem ersten geschriebenen
+ Byte abgelehnt, statt den Datenträger zu füllen und auf halbem Weg zu scheitern.
+
+
+
+
+
Archive
+
Einen Entpacker mit einem Archiv testen, das wirklich Dateien enthält
+
+ Ein leeres Archiv mit der richtigen Endung beweist nichts über Code, der es öffnet und durchläuft,
+ was darin ist. Deklariere den Inhalt, und das Archiv enthält ihn wirklich:
+
+ Verschachtelungstiefe, Eintragszahlen und die Größe dessen, was darin liegt, sind alles Dinge, zu
+ denen eine Importroutine Meinungen hat, und so findest du heraus, welche das sind.
+
+
+
+
+
Parser und Viewer
+
Prüfen, dass dein eigener Code ein Format so liest wie echte Software
+
+ Jedes Format hier wird vor der Auslieferung mit einem unabhängigen Leser geprüft - ein PNG wird
+ geöffnet und seine Pixel verglichen, ein DOCX von separaten Bibliotheken zurückgelesen, ein
+ Archiv entpackt. Das heißt, eine Datei, die dein Parser abweist, ist ein Befund über deinen
+ Parser, nicht über den Generator.
+
+ Die Formate-Seite listet die Einstellungen jedes Formats und die kleinste
+ Datei auf, die es sein kann.
+
+
+
+
+
Anleitungen
+
Zwei davon im Detail
+
+
+ Beschädigte Testdateien - eine absichtlich kaputte Datei
+ in exakter Größe, mit dem Manifest als Angabe, was mit ihr geschehen soll.
+
+
+ Testdateien in CI - ein GitHub-Actions-Workflow, ein GitLab-Job
+ und die Exit-Codes, die einen Build scheitern lassen.
+
+
+
+
+
+
Für wen das gedacht ist
+
+ QA-Engineers, Testautomatisierung und alle, deren Code ein Upload-Formular, eine Importroutine,
+ einen Parser oder ein Speicherkontingent hinter sich hat. Es läuft auf einem Rechner ganz ohne
+ Netz, was in einer abgeschotteten Unternehmensumgebung zählt, wo ein browserbasierter Generator
+ keine Option ist.
+
+ Ein Validator, dem man nur gesunde Dateien gezeigt hat, ist nicht wirklich getestet. So bekommen Sie
+ eine Datei, die absichtlich kaputt ist, genau die Größe hat, die Sie verlangen,
+ und ein Manifest mitbringt, das sagt, was Ihr System damit tun soll.
+
+
+
+
Die kurze Antwort
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out schreibt ein PNG
+ von genau 2097152 Byte, dessen erste Bytes Nullen sind, und das Manifest daneben hält fest, dass
+ Ihr System es ablehnen soll.
+
+
+
+
+
Der übliche Weg
+
Warum eine von Hand beschädigte Datei ein schlechter Test ist
+
+ Üblich sind ein Hex-Editor, ein Skript, das ein paar zufällige Bytes kippt, oder eine Datei, die mit
+ head oder truncate gekürzt wird. Das funktioniert einmal, und dann
+ kostet es Sie:
+
+
+
+ Es ist jedes Mal anders. Ein zufälliges Byte landet bei jedem Lauf woanders, ein
+ Fehler vom Dienstag kommt am Mittwoch womöglich nicht wieder.
+
+
+ Es verändert die Größe. Eine gekürzte Datei ist kleiner als das Limit, unter dem
+ sie liegen sollte, also antwortet die Größenprüfung vor der Inhaltsprüfung, und der Test
+ besteht aus dem falschen Grund.
+
+
+ Es fällt oft nicht auf. Reiner Text lässt sich mit einem geänderten Byte in der
+ Mitte weiterlesen, und ein nachsichtiger Bildleser zeichnet es einfach, sodass die Datei, die
+ kaputt sein sollte, angenommen wird.
+
+
+ Es sagt nichts darüber, was geschehen soll. Die Datei besteht nur aus Bytes, und
+ wer den Test später liest, muss raten, ob Annahme oder Ablehnung gemeint war.
+
+
+
+
+
+
Was Sie bekommen
+
Eine beschädigte Datei hat trotzdem die verlangte Größe
+
+ Die Datei wird normal erzeugt und erst danach auf dem Weg zur Festplatte beschädigt. Sie behält die
+ verlangte Größe, und derselbe Befehl schreibt wieder dieselben Bytes.
+
+ Einstellungen stehen nach einem Doppelpunkt. Die Option lässt sich wiederholen, und die
+ Beschädigungen werden in der Reihenfolge angewendet, in der Sie sie schreiben. Es funktioniert
+ mit allen 26 Formaten.
+
+
+
+
+
Was möglich ist
+
Welche Beschädigungen gibt es?
+
+ Das ist die Liste, die das Programm ausgibt, beim Erstellen dieser Seite aus ihm gelesen. tfg
+ damage gibt dieselbe aus, und tfg damage <id> sagt, was eine davon
+ annimmt.
+
+
+
+
+
+
Beschädigung
+
Was sie mit den Bytes macht
+
Kleinste Datei
+
Einstellungen
+
+
+
+
+
zero-head
+
Überschreibt die ersten Bytes der Datei mit Nullen und lässt ihre Länge unverändert. Die meisten Leser schauen zuerst dorthin, deshalb bemerkt fast alles diese Beschädigung.
+
8
+
bytes
+
+
+
+
+
+ zero-head schreibt Nullen über den Anfang der Datei. Die meisten Leser schauen zuerst
+ dorthin, auf die Signatur und den Header, die sagen, was die Datei ist, deshalb bemerkt es fast
+ jeder Leser. Reiner Text und Logs haben keine Signatur und werden ebenfalls abgewiesen, weil
+ eine Folge von Nullbytes kein Text ist. Unter vier Bytes entstehen bei manchen Formaten Schäden,
+ über die sich kein Leser beschwert, deshalb beginnt die Einstellung bei vier.
+
+
+
+
+
Was das Manifest sagt
+
Ein Manifest, das sagt, was geschehen soll
+
+ Jede beschädigte Datei bekommt einen Eintrag, der besagt, dass Ihr System sie ablehnen soll, mit der
+ Beschädigung daneben:
+
+ Zwei Anfragen werden abgelehnt, bevor etwas geschrieben wird, denn jede würde eine Datei
+ hinterlassen, die das Manifest falsch beschreibt:
+
+
+
eine Datei, die kleiner ist, als die Beschädigung braucht, und unverändert herauskäme
+
+ expected: accept neben einer Beschädigung, weil nichts es erfüllen könnte. Schreiben
+ Sie sanitize, wenn Ihr System die Datei reparieren soll, oder
+ unspecified, wenn genau das Ihre Frage ist
+
+
+
+
+
+
In einem Rezept
+
Gesunde und kaputte Dateien in einem Lauf
+
+ Legen Sie beides in ein Rezept, dann trägt das Manifest die Erwartung jeder Datei, und der Test
+ braucht keine Liste, welche welche ist:
+
+ Der Test liest das Manifest und prüft, ob das, was geschah, dem Erklärten entspricht. Er braucht
+ keine Liste von Dateinamen:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Eine gute Ablehnung ist eine saubere. Eine Meldung, die sagt, was falsch war, ist die gewünschte
+ Antwort. Ein Serverfehler, ein Hänger oder eine halb gespeicherte Datei ist der Fehler, den
+ dieser Test finden soll.
+
+
+
+
+
Weiter
+
Wohin es von hier geht
+
+
+ Das Preset upload-validation stellt einem Formular die
+ beiden anderen Fragen, die nach Größe und die nach Typ.
+
+
+ Testdateien in CI führt ein Rezept wie dieses in einer Pipeline
+ aus.
+
+ Jedes System hat dafür einen Befehl, alle drei stehen unten. Sie liefern dir eine Datei mit genau
+ der richtigen Byte-Zahl - und für viele Tests ist das alles, was du brauchst. Jeder Befehl
+ auf dieser Seite wurde vor der Veröffentlichung ausgeführt, auf dem System, zu dem er
+ gehört.
+
+
+
+
Die kurze Antwort
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Größen werden in Bytes angegeben,
+ und 10 MB, so gezählt wie dein Dateimanager zählt, sind 10485760 davon.
+
+
+
+
+
Windows
+
fsutil und eine PowerShell-Variante, die nichts Zusätzliches braucht
+
+ fsutil gehört zu Windows. Es nimmt die Größe in Bytes, rechne die Zahl
+ also vorher aus - 10 MB sind 10485760, 100 MB sind 104857600, 1 GB ist 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Gemessen unter Windows 11: Es funktioniert in einer normalen Eingabeaufforderung und braucht keine
+ erhöhten Rechte, und die Datei hat genau 10485760 Bytes.
+
+
PowerShell kann dasselbe, ohne ein anderes Programm aufzurufen, und versteht Einheiten:
+ 10MB bedeutet in PowerShell 10485760 Bytes, dieselbe Zählung auf 1024er-Basis, die der
+ Explorer verwendet, die beiden Befehle oben erzeugen also dieselbe Größe.
+
+
+
+
+
Linux
+
dd, truncate und fallocate und der Unterschied, der Leute erwischt
+
dd kennt jeder. Es schreibt die Bytes wirklich:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate ist sofort fertig, und genau das ist der Haken. Gemessen unter Alpine Linux
+ meldet die Datei 10485760 Bytes und belegt null Blöcke - sie ist eine
+ Sparse-Datei. Wer sie liest, bekommt zehn Megabyte Nullen, aber der Datenträger
+ hat den Platz nie hergegeben:
+
+
truncate -s 10M test10mb.bin
+
+ Das ist für den Test eines Upload-Limits in Ordnung und für den Test einer Datenträgerquote
+ irreführend. fallocate ist das Mittel der Wahl, wenn der Platz wirklich belegt sein
+ muss:
+
+
fallocate -l 10M test10mb.bin
+
Und wenn der Inhalt inkompressibel sein muss, damit ein Archivierer ihn nicht wieder zusammendrücken kann:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, das nicht sparse ist, und die beiden, die du schon kennst
+
+ macOS liefert mkfile mit. Gemessen unter macOS 26.6.2: 10485760 Bytes und 20480 Blöcke,
+ der Platz ist also wirklich belegt statt nur versprochen:
+
+
mkfile 10m test10mb.bin
+
dd und truncate gibt es ebenfalls, und sie verhalten sich wie unter Linux:
Eine Datei in der richtigen Größe ist keine Datei der richtigen Art
+
+ Alles oben Genannte liefert dir einen Block aus Nullen. Das reicht, wenn das Getestete nur auf die
+ Größe schaut - ein Upload-Limit, eine Quote, eine Übertragung. Es reicht nicht mehr, sobald
+ irgendetwas die Datei öffnet.
+
+
+ Gemessen, und es lohnt sich, das selbst zu probieren: Erzeuge mit fsutil eine
+ 2-MB-Datei, nenne sie photo.png und gib sie einer Bildbibliothek. Pillow antwortet
+ cannot identify image file. Es ist kein PNG. Es war nie eines - nur der Name
+ behauptete es.
+
+
+ Das ist wichtiger, als es klingt, wegen der Richtung, in der der Test dann
+ fehlschlägt. Dein Upload-Endpunkt weist die Datei ab, dein Test wird grün, und du
+ schließt, dass das Größenlimit funktioniert. Er hat sie nicht wegen der Größe abgewiesen. Er hat
+ sie abgewiesen, weil die Bytes kein Bild waren, und die Regel, die du testen wolltest, wurde nie
+ erreicht.
+
+
+
ein Parser weist sie ab, bevor eine Größenregel angesehen wird
+
ein Vorschauschritt schlägt fehl, und der Fehler, den du liest, betrifft die Vorschau
+
ein Virenscanner oder eine Inhaltsprüfung lehnt sie aus einem dritten Grund ab
+
ein Viewer zeigt nichts an, und niemand kann sagen, ob das der Fehler ist
+
+
+
+
+
Der andere Weg
+
Eine echte Datei dieses Formats, in genau der Größe, die du verlangt hast
+
+ Das ist es, was Testing Files Generator tut. Die Datei ist eine echte ihres Formats - sie öffnet
+ sich in der Software, zu der sie gehört - und hat die exakte Byte-Zahl, die du verlangt hast,
+ auf das Byte genau:
+
+ Verlange eine Größe, die ein Format nicht erreichen kann, und du bekommst einen Fehler, der die
+ Untergrenze und ihren Grund nennt, nie eine Datei in der falschen Größe. Die
+ Formate-Seite listet jedes Format mit der kleinsten Datei auf, die es
+ erzeugen kann.
+
+
Und ein Limit sind drei Testfälle statt einem, deshalb baut das Tool alle drei:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Das ergibt 10485759, 10485760 und 10485761 Bytes und ein Manifest, das sagt, welche davon dein
+ System akzeptieren und welche es ablehnen soll. Die
+ Anwendungsfälle-Seite geht das und vier weitere Aufgaben
+ durch, für die es gebaut ist.
+
Kostenlos und Open Source, GPL-3.0. Keine Anmeldung nötig. Die Downloads für Windows und macOS sind signiert und starten ohne Warnung.
+
+
+
+
Was solltest du also verwenden?
+
+
+
Den Systembefehl verwenden
+
+ Wenn nichts die Datei öffnet. Ein Größenlimit an einem Endpunkt testen, der zuerst die Größe prüft,
+ eine Übertragung, eine Quote, ein voller Datenträger. Es ist eine Zeile, und es ist schon
+ installiert.
+
+
+
+
Einen echten Generator verwenden
+
+ Wenn irgendetwas die Datei parst, rendert, importiert oder entpackt - und wenn du morgen auf einem
+ anderen Rechner dieselben Fixtures brauchst, Byte für Byte.
+
+
+
+
+ Beides steht auf dieser Seite, weil beides manchmal richtig ist. Der Fehler, den es zu vermeiden
+ gilt, ist, das Erste zu verwenden, wo das Zweite nötig ist, und den grünen Test als Beweis zu
+ lesen.
+
+ Alles, was das Tool kann, geordnet nach den Fragen, mit denen die Leute tatsächlich kommen. Die
+ README im Repository ist die vollständige Referenz und passt immer
+ zu dem Build, den du heruntergeladen hast.
+
+
+
+
Welche Befehle gibt es?
+
Jeder tut genau eine Sache:
+
tfg generate Dateien erzeugen, aus einem Rezept oder über Flags
+tfg validate ein Rezept prüfen und nichts schreiben
+tfg verify ein Verzeichnis gegen ein Manifest prüfen
+tfg cleanup die Dateien entfernen, die ein Manifest auflistet
+tfg recipe fmt ein Rezept in seiner festen Form ausgeben
+tfg preset ein Set von Dateien aus einer benannten Testfrage erzeugen
+tfg formats die Formate dieses Builds auflisten
+tfg damage die Arten auflisten, wie dieser Build eine Datei absichtlich beschädigen kann
+tfg tool kleine Helfer für Dateien, die du schon hast
+tfg version die Version des Tools ausgeben
+tfg license die Lizenz ausgeben und was sie für erzeugte Dateien bedeutet
+
+
+
+
Wie erzeuge ich eine einzelne Datei in exakter Größe?
+
+ Nenne das Format, die Größe und das Ziel. Größen zählen in 1024ern, 2mb sind also
+ 2097152 Bytes. Eine einfache Byte-Zahl funktioniert auch, --size 10485761 verlangt
+ also genau so viele.
+
+
tfg generate --format png --size 2mb --out ./out
+
Die nützlichen Flags von generate:
+
+
+
Flag
Was es tut
+
+
--format <id>
Format der Dateien, zum Beispiel txt
+
--size <size>
exakte Größe jeder Datei, etwa 10mb oder eine einfache Byte-Zahl
+
--size-range <a-b>
eine Größe, die pro Datei aus einem Bereich gezogen wird, etwa 1kb-8kb. Die Ziehung kommt aus dem Seed
+
--boundary <size>
drei Dateien rund um ein Limit: ein Byte darunter, das Limit, ein Byte darüber
+
--count <n>
wie viele Dateien erzeugt werden. Standard 1
+
--name <template>
Namensvorlage, zum Beispiel invoice_{index:04}.txt
+
--out <dir>
Verzeichnis, in das geschrieben wird
+
--seed <n>
Seed des Laufs. Derselbe Seed ergibt dieselben Bytes
+
--set <k>=<v>
eine Formateinstellung, wiederholbar
+
--damage <name>
Dateien absichtlich beschädigen, wiederholbar und der Reihe nach angewendet. Mit tfg damage bekommst du die Liste
+
--expected <outcome>
accept, reject, sanitize oder unspecified
+
--dry-run
zählen und anzeigen, überhaupt nichts schreiben
+
--json
das Manifest auf die Standardausgabe schreiben
+
+
+
+
+
+
+
Wie erzeuge ich eine absichtlich kaputte Datei?
+
+ Jede andere Datei, die dieses Tool schreibt, ist per Konstruktion korrekt, was zwei der drei Fragen
+ beantwortet, die ein Upload-Validator stellt. --damage beantwortet die dritte -
+ lässt sich die Datei überhaupt öffnen. Die Datei wird normal erzeugt und dann beschädigt, sie
+ hat also weiterhin die verlangte Größe.
+
+ Einstellungen stehen hinter einem Doppelpunkt. Das Flag lässt sich wiederholen, und die Reihenfolge,
+ in der du sie schreibst, ist die Reihenfolge, in der sie angewendet werden. tfg
+ damage listet auf, was dieser Build kann und was jede Variante annimmt.
+
+
In einem Rezept ist der Schlüssel eine Liste, aus Namen oder aus Einstellungen:
+ Eine beschädigte Datei bekommt im Manifest expected: reject, mit der daneben
+ festgehaltenen Beschädigung. Zwei Dinge werden abgelehnt, bevor etwas geschrieben wird, weil
+ sonst jeweils eine Datei auf die Platte käme, die das Manifest falsch beschreibt:
+
+
+
eine Datei, die kleiner ist, als die Beschädigung braucht, weil sie unverändert herauskäme
+
+ expected: accept neben einer Beschädigung, weil es keine Datei geben kann, die das
+ erfüllt. Schreibe sanitize, wenn das getestete System die Datei reparieren soll,
+ oder unspecified, wenn genau das die Frage ist, die du stellst
+
+
+
+ Eine dritte lässt sich nicht im Voraus wissen. Wenn eine Beschädigung läuft und kein Byte verändert,
+ wird diese Datei verworfen statt geschrieben - der Lauf macht weiter, sagt, um welche Datei es
+ ging, und endet mit dem Exit-Code für teilweise erfolgreiche Läufe.
+
+ Ein Rezept ist eine YAML-Datei, die einen ganzen Lauf beschreibt. Checke sie neben deinen Tests ein,
+ und die Fixtures sind keine Binärdateien mehr in deinem Repository - jeder kann sie Byte für
+ Byte aus einer Datei von wenigen hundert Zeichen neu erzeugen.
+
+ Jedes Target braucht genau eines von size, size-range,
+ boundary oder contains. Zwei davon sind ein Fehler, und keines
+ ebenfalls. Ein ungültiges Rezept schreibt überhaupt keine Dateien und meldet
+ alle Probleme auf einmal statt nur das erste, jedes mit der Einstellung, um die es geht.
+
+
+
+
+
Wie lege ich fest, was mein System mit einer Datei tun soll?
+
Kurzform, wenn das Ergebnis reicht, Langform, wenn der Grund zählt:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Die Ergebnisse sind accept, reject, sanitize und
+ unspecified. Die Gründe sind eine geschlossene Liste, damit ein Report danach
+ gruppieren kann: content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit und
+ size_zero.
+
+
+ Ein Grund benennt die Regel, um die es geht, nicht das Urteil. Deshalb kann
+ derselbe Grund unter beiden Ergebnissen stehen - eine Datei ein Byte unter einem Limit ist
+ accept, und die Regel, um die es geht, ist trotzdem size_limit.
+
+
+
+
+
Was steht im Manifest?
+
+ Es wird am Ende jedes Laufs neben die Dateien geschrieben, auch bei einem unterbrochenen Lauf. Ein
+ Eintrag pro Datei:
+
+ Ein recipe_hash kommt hinzu, wenn der Lauf aus einem Rezept stammt, und
+ preset mit overrides, wenn er aus einem Preset stammt, sodass sich ein
+ Manifest immer auf das zurückführen lässt, was es erzeugt hat.
+
+
+ Jeder Eintrag trägt außerdem target_id, die ID des Targets im Rezept, das die Datei
+ erzeugt hat, und summary.by_target zählt, auf wie viele Dateien jedes Target kam.
+ Ein Rezept mit mehreren Targets lässt sich so Target für Target prüfen, ohne Dateinamen zu
+ lesen.
+
+
+
+
+
Was ist ein Preset?
+
+ Ein fertiges Set aus Dateien, das eine gängige Testfrage beantwortet, damit du das Set nicht selbst
+ entwerfen musst. Presets sind darunter ganz normale Rezepte, und eject gibt das
+ Rezept aus, damit du es von dort aus bearbeiten kannst. Jedes Preset hat
+ eine eigene Seite mit dem, was es meist findet, was im Set steckt und
+ welche Einstellungen es kennt.
+
+ show sagt dir, was das Set kosten würde, bevor du es baust, und sagt
+ unmissverständlich, wenn eine Zahl ein Platzhalter von uns statt ein Limit von dir ist.
+
+
+
+
+
Was bedeuten die Exit-Codes?
+
+ Jedes Ende hat einen eigenen Code, maschinenlesbare Ausgabe geht auf die Standardausgabe, und ein
+ fehlgeschlagener Lauf gibt dort nichts aus. Die Tabelle ist ein eingefrorener Vertrag - die
+ Bedeutung eines Codes zu ändern erfordert einen Major-Versionssprung.
+
+
+
+
+
+
Code
+
Bedeutung
+
+
+
+
+
0
+
Alles hat funktioniert.
+
+
+
1
+
Ein unerwarteter Fehler im Tool.
+
+
+
2
+
Falscher Befehl oder falsches Flag.
+
+
+
3
+
Das Rezept ist ungültig.
+
+
+
4
+
Das Format kann nicht, was verlangt wurde.
+
+
+
5
+
Lesen oder Schreiben ist fehlgeschlagen.
+
+
+
6
+
Nicht genug Speicherplatz.
+
+
+
7
+
verify hat eine Abweichung gefunden.
+
+
+
8
+
Der Lauf ist beendet, aber nicht alles wurde erzeugt.
+
+
+
130
+
Mit Strg+C abgebrochen.
+
+
+
143
+
Durch ein Signal beendet, so sieht ein CI-Timeout aus.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Ein mit Strg+C gestoppter Lauf hinterlässt trotzdem ein Manifest und nie eine halb geschriebene
+ Datei, sodass ein abgebrochener Job vom nächsten noch aufgeräumt werden kann.
+
+ Ja, dieselbe Engine mit einem Fenster davor, für das Testen, das nicht skriptbar ist. Es ist keine
+ abgespeckte Version: Ein Test vergleicht die beiden Oberflächen Fähigkeit für Fähigkeit, und
+ alles, was nur eine von beiden kann, muss deklariert und begründet werden, statt unbemerkt
+ auseinanderzudriften.
+
+
+ Die Bildschirme sind ein Stapel, Presets, mehrere Stapel gleichzeitig und Info. Es zeigt, was ein
+ Lauf kosten würde, bevor etwas geschrieben wird, meldet den Fortschritt während des Laufs und
+ lässt sich mittendrin abbrechen, ohne eine halb geschriebene Datei zu hinterlassen. Eine
+ Rezeptdatei öffnet es noch nicht - Rezepte gibt es vorerst nur auf der Kommandozeile, und das
+ Fenster baut seine Stapel im Formular.
+
+ Lizenz, Datenschutz, Reproduzierbarkeit und das, was Leute prüfen, bevor sie einen Generator in eine
+ Build-Pipeline einbauen. Wenn deine Frage hier fehlt, ist der
+ Issue-Tracker offen.
+
+
+
+
+
Worin unterscheidet sich das von dd, fsutil oder truncate?
+
+
Diese Befehle liefern dir eine Datei in der richtigen Größe, gefüllt mit nichts. Eine 2 MB große Datei namens photo.png, die so entstanden ist, ist kein PNG. Alles, was sie wirklich parst, weist sie aus dem falschen Grund ab, und dein Test besteht dann ebenfalls aus dem falschen Grund. Dieses Tool erzeugt ein echtes PNG von genau 2 MB, das sich in einem Bildbetrachter öffnet und mit einer Aussage darüber geliefert wird, wie dein System damit umgehen soll.
Ist es kostenlos, und darf ich es bei der Arbeit einsetzen?
+
+
Ja, beides. Es steht unter der GPL-3.0 und kostet nichts. Es gibt kein Konto, keinen Lizenzschlüssel und keine kostenpflichtige Stufe.
+
+
+
+
Darf ich die erzeugten Dateien in einem Closed-Source-Produkt verwenden?
+
+
Ja. Die Lizenz gilt für den Code des Tools, nicht für das, was das Tool erzeugt. Erzeugte Dateien, Rezepte und Manifeste sind Ausgabe und keine abgeleiteten Werke, du kannst sie also einchecken und ohne jede Verpflichtung weitergeben.
+
+
+
+
Enthalten die erzeugten Dateien echte personenbezogene Daten?
+
+
Nein. Alles darin wird aus einem Seed synthetisch erzeugt. Es wird kein Datensatz gelesen, kein Dienst kontaktiert und kein Inhalt Dritter eingebettet. Behandle eine erzeugte E-Mail-Adresse als unbrauchbar statt als unbenutzt, denn jede Zufallszeichenfolge kann zufällig mit einer echten übereinstimmen.
+
+
+
+
Bekomme ich auf einem anderen Rechner genau dieselben Dateien?
+
+
Ja, Byte für Byte, bei gleichem Rezept und gleichem Seed. Das Projekt testet das bei jeder Änderung, und es zu brechen erfordert einen Major-Versionssprung. Genau deshalb kannst du ein kleines Rezept einchecken statt großer binärer Fixtures.
+
+
+
+
Braucht es eine Internetverbindung?
+
+
Nie. Es gibt keine Telemetrie, keine Update-Prüfung und keinen Cloud-Client, und die Kommandozeilen-Binärdatei hat gar keinen Netzwerkstack einkompiliert. Sie läuft auf einem Rechner ohne Netz und in einer abgeschotteten Unternehmensumgebung.
+
+
+
+
Was passiert, wenn ich eine Größe verlange, die ein Format nicht erreichen kann?
+
+
Du bekommst einen Fehler, der das Format nennt, die kleinstmögliche Größe, den Grund für diese Untergrenze und was du stattdessen tun kannst, und es wird keine Datei geschrieben. Das Tool rundet eine Größe nie stillschweigend. Jede Untergrenze steht auf der Formate-Seite.
+
tfg formats png
+
+
+
+
Kann ich eine absichtlich kaputte Datei erzeugen?
+
+
Ja. Fügen Sie --damage zero-head hinzu, und die Datei kommt in genau der verlangten Größe heraus, mit Nullen über den ersten Bytes, sodass ein Leser sie abweist, und das Manifest sagt, dass Ihr System sie ablehnen soll. Die Einzelheiten stehen auf der Seite über beschädigte Testdateien.
7z, mp3 und mp4. 26 Formate funktionieren heute durchgängig.
+
+
+
+
Auf welchen Systemen läuft es?
+
+
Die Kommandozeile läuft unter Windows und Linux auf Intel und ARM sowie auf Macs mit Apple Silicon. Das Desktop-Fenster gibt es für Windows auf Intel, Linux auf Intel und Macs mit Apple Silicon. Intel-Macs werden nicht unterstützt, und für sie wird nichts gebaut.
+
+
+
+
Muss ich etwas installieren?
+
+
Nein. Lade das Archiv für dein System herunter, entpacke es und starte die Binärdatei. Es gibt keinen Installer, keine Laufzeitumgebung zum Nachrüsten und keine Abhängigkeit, die aufgelöst werden müsste. Wenn du Go hast, funktioniert auch ein einziger go-install-Befehl.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
Warum ist ein Lauf über Tausende Dateien unter Windows langsamer?
+
+
Weil Windows für jeden Pfad, den es ansieht, mehr verlangt, und ein Befehl über Tausende Dateien sieht sich Tausende Pfade an. Gemessen auf einem Rechner mit 3000 Dateien zu je 1 kB braucht verify unter Windows etwa 0,9 Sekunden und unter Linux in einem Container etwa 0,2 Sekunden. Ein kürzerer Ausgabepfad verkleinert den Windows-Wert, denn jeder Ordner über den Dateien gehört zu dem, was angesehen wird.
+
+
+
+
+
+
+
Noch unentschlossen?
+
+ Die Anwendungsfälle-Seite zeigt die Aufgaben, für die es gebaut
+ ist, und die Formate-Seite listet jedes Format mit der kleinsten
+ Datei auf, die es erzeugen kann. Die README im Repository ist
+ die vollständige Referenz.
+
+ Jedes davon ist eine echte Datei dieses Formats. Sie öffnet sich in der Software,
+ zu der sie gehört, und hat genau die Byte-Zahl, die du verlangt hast. Keines davon besteht aus
+ aufgefüllten Nullen mit einer angeklebten Endung.
+
+
+
+
+
+
+
Format
+
Name
+
Endung
+
Kleinste Datei
+
Vollständigkeit
+
Geprüft mit
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
nicht zutreffend
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
nicht zutreffend
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
nicht zutreffend
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
Was die Spalten bedeuten
+
+
+
Kleinste Datei
+
+ Die wenigsten Bytes, die dieses Tool für das Format akzeptiert, einschließlich des Labels, das es in
+ die Datei schreibt. Verlangst du weniger, bekommst du einen Fehler, der die Untergrenze und
+ ihren Grund nennt, nie eine Datei in der falschen Größe.
+
+
+
+
Vollständigkeit
+
+ Wie vollständig die Datei ist. full heißt, dass ein Leser, der das Format wirklich
+ parst, sie akzeptiert, nicht nur, dass die Endung passt.
+
+
+
+
Geprüft mit
+
+ Der unabhängige Leser, der jede erzeugte Datei öffnet, bevor das Format ausgeliefert wird - eine
+ eigene Implementierung, nicht unser eigener Code, der seine Hausaufgaben selbst korrigiert.
+
+
+
+
+ Jedes Format wiederholt sich außerdem bis aufs Byte: Dasselbe Rezept und derselbe Seed erzeugen auf
+ jedem Rechner identische Dateien, und genau das macht ein Rezept sicher einzuchecken statt der
+ Fixtures selbst.
+
+
+
+
+
Einstellungen, die jedes Format kennt
+
+ Die meisten Formate haben eigene Einstellungen - Bildmaße, JPEG-Qualität, PDF-Seitenzahl, Zeilen und
+ Spalten in einer Tabelle, wie viele Einträge in ein Archiv kommen. Setze sie mit --set
+ key=value auf der Kommandozeile oder unter properties: in einem Rezept.
+
ein Datum wie 2024-02-29 oder 2024-02-29T13:45:00+02:00, oder none
+
+
+
+
modified
+
ein Datum wie 2024-02-29 oder 2024-02-29T13:45:00+02:00, oder none
+
+
+
png
+
width
+
1 - 20000 Pixel
+
+
+
+
height
+
1 - 20000 Pixel
+
+
+
pptx
+
slides
+
1 - 500 Folien
+
+
+
svg
+
width
+
1 - 20000 Pixel
+
+
+
+
height
+
1 - 20000 Pixel
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
die ID eines Formats, wie tfg formats sie auflistet
+
+
+
+
entry_size
+
eine Größe wie 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
wahr oder falsch
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 Pixel
+
+
+
+
height
+
1 - 20000 Pixel
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
wahr oder falsch
+
+
+
wav
+
sample_rate
+
8000 - 192000 Hertz
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 Pixel
+
+
+
+
height
+
1 - 16383 Pixel
+
+
+
xlsx
+
rows
+
1 - 200000 Zeilen
+
+
+
+
columns
+
1 - 32768 Spalten
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
wahr oder falsch
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
die ID eines Formats, wie tfg formats sie auflistet
+
+
+
+
entry_size
+
eine Größe wie 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
wahr oder falsch
+
+
+
+
password
+
das Passwort im Klartext
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ Ein Wert außerhalb dessen, was eine Einstellung zulässt, wird mit einer Meldung abgewiesen, die die
+ Einstellung, den erlaubten Bereich und eine Alternative nennt. Eine unbekannte Einstellung ist
+ ebenfalls ein Fehler, nie ein stiller Standardwert - ein stillschweigend akzeptierter Tippfehler
+ ergibt eine Datei mit den falschen Einstellungen und eine Stunde Rätselraten, warum der Test
+ besteht, obwohl er es nicht sollte.
+
+
+ Mit tfg formats <id> siehst du genau, was ein Format in dem Build akzeptiert, den
+ du hast.
+
+
+
+
+
Archive enthalten echte Dateien
+
+ targz und zip
+ lassen sich mit Einträgen füllen, statt als leere Hülle zu bleiben. Ein erzeugtes Archiv enthält
+ wirklich die Dokumente, die es zu enthalten vorgibt, sodass alles, was es während eines Tests
+ entpackt, echte Dateien darin findet.
+
+ PDF, PNG, DOCX, ZIP - insgesamt 26 Formate, und jedes ist
+ eine echte Datei, die sich in der Software öffnet, zu der sie gehört, in genau der
+ Größe, die du verlangt hast. Jeder Lauf hält außerdem fest, was deine Anwendung mit
+ jeder Datei tun soll. Kommandozeile und Desktop-Fenster, kostenlos und Open Source, vollständig
+ auf deinem Rechner.
+
Kostenlos und Open Source, GPL-3.0. Keine Anmeldung nötig. Die Downloads für Windows und macOS sind signiert und starten ohne Warnung.
+
+
+
+
+ Das Desktop-Fenster, eingerichtet für einen Stapel Dateien. Dieselbe Engine läuft hinter der Kommandozeile.
+
+
+
+
+
+ 26
+
echte Formate, jedes öffnet sich in der Software, zu der es gehört
+
+
+ 1 Byte
+
die Genauigkeit jeder verlangten Größe, nie stillschweigend gerundet
+
+
+ 0
+
Verbindungen irgendwohin - kein Konto, keine Telemetrie, keine Update-Prüfung
+
+
+
+
+
Das Problem
+
Eine Testdatei zu machen ist einfach. Die richtigen tausend zu machen ist das Mühsame
+
Du testest Software, die Dateien von Menschen annimmt. Früher oder später brauchst du:
+
+
ein PDF von exakt 10 MB, um herauszufinden, ob das Upload-Limit echt ist
+
die drei Dateien beidseits dieses Limits, um Off-by-one-Fehler zu fangen
+
10.000 Logdateien, um zu sehen, was der nächtliche Job tut, wenn der Ordner groß ist
+
ein ZIP, das wirklich 200 Dokumente enthält, keine Attrappe mit der richtigen Endung
+
eine 4-GB-Datei, ohne eine 4-GB-Datei in deinem Repository zu halten
+
die gleichen Fixtures auf deinem Laptop und auf dem Build-Server, Byte für Byte
+
+
+ Genau das ersetzt dieses Tool. Es ist gebaut für QA-Engineers, Testautomatisierung und alle, deren
+ Code ein Upload-Formular, eine Importroutine, einen Parser oder ein Speicherkontingent hinter
+ sich hat.
+
+
+
+
+
Was es anders macht
+
Andere Generatoren hören bei den Bytes auf. Dieser beantwortet, was dein Test wirklich fragt
+
+ Ein Ordner voller Dateien lässt dich weiter entscheiden, was jede davon belegen soll. Jeder Lauf
+ schreibt hier ein manifest.json neben die Dateien - eine einfache Liste von allem,
+ was erzeugt wurde, und zu jedem Eintrag eine deklarierte Erwartung.
+
+
Angenommen, dein Upload-Endpunkt erlaubt 1 MB. Fordere die drei Dateien an, die auf dieser Linie liegen:
Wo die Antwort von deiner eigenen Richtlinie abhängt, sagt das Manifest das
+
+ Es hält unspecified fest, statt eine Erwartung zu erfinden. Ein Generator, der rät,
+ erzeugt falsche Fehlschläge, und eine Testsuite, die ständig Alarm schlägt, wird abgeschaltet.
+
+
+
+
+
+
Presets
+
Wähle die Frage, bekomme das ganze Set
+
+ Ein Preset ist ein Set aus Testdateien, das um eine Testfrage herum entworfen wurde, damit du nicht
+ selbst herausfinden musst, welche Dateien was belegen. Jedes hat eine eigene Seite mit dem, was
+ es meist findet, was im Set steckt und welche Einstellungen es kennt.
+
+ Zehntausend Logdateien, jede zwischen einem und acht Kilobyte, die Größen werden aus dem Seed
+ gezogen, sodass morgen dasselbe Set herauskommt. Gib jedem Lauf ein eigenes
+ Verzeichnis - das Manifest ist die einzige Aufzeichnung dessen, was ein Lauf
+ geschrieben hat, deshalb weigert sich das Tool, ein zweites darüber zu schreiben:
+
+ Größen zählen in 1024ern, wie es dein Dateimanager tut, 2mb bedeutet also 2097152
+ Bytes. Eine einfache Byte-Zahl funktioniert auch. Die
+ Dokumentation behandelt Rezepte, das Manifest und die
+ Exit-Codes.
+
+
+
+
+
Was du bekommst
+
Gebaut für eine Testsuite, die unbeaufsichtigt läuft
+
+
+
Exakte Größe, auf das Byte genau
+
Verlange 10485761 Bytes und bekomme genau das. Eine Größe, die ein Format nicht erreichen kann, ist ein Fehler mit Begründung, nie eine Datei in der falschen Größe.
+
+
+
26 echte Formate
+
Keine aufgefüllten Nullen mit einer Endung. Ein erzeugtes PNG öffnet sich im Bildbetrachter, ein DOCX in Word, ein ZIP lässt sich entpacken. Jedes wird vor der Auslieferung mit unabhängigen Readern geprüft.
+
+
+
Ein Manifest, das ein Testorakel ist
+
Pfad, Größe, SHA-256, Format, Seed, Tool-Version - und was dein System mit der Datei tun soll.
+
+
+
Reproduzierbar
+
Gleiches Rezept und gleicher Seed, gleiche Bytes, auf jedem Rechner. Checke ein kleines YAML-Rezept ein statt großer binärer Fixtures.
+
+
+
Zwei Oberflächen, eine Engine
+
Eine Kommandozeile für die CI und ein Desktop-Fenster für exploratives Testen. Keine ist eine abgespeckte Version der anderen, und ein Test vergleicht sie Fähigkeit für Fähigkeit.
+
+
+
Komplett offline
+
Kein Konto, keine Cloud, keine Telemetrie, keine Update-Prüfung. In die Kommandozeilen-Binärdatei ist gar kein Netzwerkstack einkompiliert.
+
+
+
+
+
+
Download
+
Wähle den Build für dein System
+
+ Entpacke das Archiv und starte es. tfg ist die Kommandozeile und tfg-gui
+ das Desktop-Fenster. Es gibt keinen Installer und nichts, was auf deinem Rechner hinzugefügt
+ werden müsste.
+
+
+
+
+
+
System
+
Kommandozeile
+
Desktop-Fenster
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
Was signiert ist und was nicht
+
+ Die Downloads für Windows und macOS sind signiert und starten daher ohne Warnung vor einem
+ unbekannten Entwickler. Die für Linux nicht, weil es unter Desktop-Linux nichts Vergleichbares
+ zum Signieren gibt. Jedes Archiv steht auf der Release-Seite in
+ verify-SHA256SUMS.txt, sodass du prüfen kannst, was du heruntergeladen hast.
+
Kommt eine gültige Datei durch, die so klein ist, wie das Format es erlaubt?
+
+ Das Preset empty-and-minimal baut mit einem Befehl ein ganzes Set echter Testdateien für diese
+ Frage und ein manifest.json daneben, das beschreibt, wie dein System auf jede Datei
+ reagieren soll. Alles unten wird aus dem Programm gelesen, mit den Standardwerten dieser Version.
+
+
+
+
+
Was findet es meistens?
+
+
eine gültige Datei, die als zu klein abgewiesen wird, weil die Prüfung Bytes zählt, statt sie zu lesen
+
eine leere Datei, die den Leser zum Absturz bringt, statt gemeldet zu werden
+
ein Bild mit einem Pixel Breite, das auf dem Weg zur Vorschau durch null teilt
+
ein Speicher, der null Bytes als fehlgeschlagenen Upload liest und immer wieder neu versucht
+
+
+
+
+
+
Was steckt im Set?
+
Mit den Standardwerten, wie es tfg preset show empty-and-minimal ausgibt:
Speichert, zeigt und liefert mein System einen Dateinamen korrekt, mit dem es nicht gerechnet hat?
+
+ Das Preset filename-handling baut mit einem Befehl ein ganzes Set echter Testdateien für diese
+ Frage und ein manifest.json daneben, das beschreibt, wie dein System auf jede Datei
+ reagieren soll. Alles unten wird aus dem Programm gelesen, mit den Standardwerten dieser Version.
+
+
+
+
+
Was findet es meistens?
+
+
ein Name, der auf dem Bildschirm, in einem Log oder in einer Liste wie ein anderer aussieht
+
ein Name, der zwischen Upload und Speicherung abgeschnitten, gekürzt oder umgeschrieben wird
+
ein Längenlimit, das in Zeichen gezählt wird, obwohl der Speicher Bytes zählt
+
+
+
+
+
+
Was steckt im Set?
+
Mit den Standardwerten, wie es tfg preset show filename-handling ausgibt:
+
+
+
+
Dateien
50
+
Targets in seinem Rezept
50
+
Gesamtgröße
51 200 B
+
Formate
txt
+
+
+
+
Und was das Manifest dieses Sets von deinem System erwartet:
+
+
+
+
Erwartet
Bedeutung
Dateien
+
+
+
accept
Dein System soll die Datei annehmen.
4
+
unspecified
Das hängt von den Regeln deines Systems ab. Du entscheidest, dann prüfst du, ob das Ergebnis dem entspricht, was du gemeint hast.
46
+
+
+
+
+
+
+
Was kannst du ändern?
+
+
+
+
Einstellung
Nimmt
Standard
Was es tut
+
+
+
+
--format
+
eine Format-ID von der Formate-Seite
+
txt
+
Das Format jeder Datei im Set. Es ist ein Flag des Tools selbst, das Preset gibt ihm nur einen Standardwert.
+
+
+
+
+
+
+
+
Wie führst du es aus?
+
Sieh nach, was das Set kosten würde, baue es oder nimm sein Rezept zum Bearbeiten:
+ Ein Preset ist ein ganzes Set aus Testdateien, das um eine Frage herum entworfen wurde, mit einem
+ Manifest, das beschreibt, wie dein System auf jede Datei reagieren soll. Du wählst die Frage, das
+ Tool baut das Set. Jedes Preset hat eine eigene Seite mit dem, was es meist findet, was im Set
+ steckt und welche Einstellungen es kennt.
+
Nimmt mein Upload-Formular an, was es soll, und weist den Rest ab?
+
upload-validation
+
+
+
+
+
Worin unterscheidet sich ein Preset von einem Rezept?
+
+ Darunter gar nicht. Ein Preset ist ein Rezept, das das Tool aus ein paar Einstellungen für dich
+ schreibt. tfg preset eject gibt dieses Rezept aus, damit du es neben deinen Tests
+ aufbewahren und bearbeiten kannst, und ein eigenes Rezept kann mit einer Zeile auf einem Preset
+ aufbauen, extends: preset: gefolgt von seiner ID.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Kann ich den Standardwerten trauen?
+
+ Bei den Dateien ja. Bei einer Zahl, die nur dein System kennt, etwa dem Limit eines
+ Upload-Formulars, ist ein Standardwert ein Platzhalter von uns, und das Tool sagt es jedes Mal,
+ wenn es einen verwendet. Die Seite jedes Presets markiert diese Einstellungen, und tfg
+ preset show sagt es, bevor etwas geschrieben wird.
+
Wird ein Größenlimit genau dort durchgesetzt, wo es angegeben ist?
+
+ Das Preset size-boundaries baut mit einem Befehl ein ganzes Set echter Testdateien für diese
+ Frage und ein manifest.json daneben, das beschreibt, wie dein System auf jede Datei
+ reagieren soll. Alles unten wird aus dem Programm gelesen, mit den Standardwerten dieser Version.
+
+
+
+
+
Was findet es meistens?
+
+
Off-by-one-Fehler am Limit
+
MB mit MiB verwechselt, was 4,8 Prozent ausmacht und reicht, um eine Datei durchzulassen, die nicht durchkommen dürfte
+
ein Limit, das im Browser durchgesetzt wird und nicht auf dem Server
+
+
+
+
+
+
Was steckt im Set?
+
Mit den Standardwerten, wie es tfg preset show size-boundaries ausgibt:
+
+
+
+
Dateien
7
+
Targets in seinem Rezept
7
+
Gesamtgröße
73 400 320 B
+
Formate
pdf
+
+
+
+
Und was das Manifest dieses Sets von deinem System erwartet:
+
+
+
+
Erwartet
Bedeutung
Dateien
+
+
+
accept
Dein System soll die Datei annehmen.
4
+
reject
Dein System soll die Datei abweisen.
3
+
+
+
+
+
+
+
Was kannst du ändern?
+
+
+
+
Einstellung
Nimmt
Standard
Was es tut
+
+
+
+
--limit
+
eine Größe wie 2mb
+
10mb
+
Das Größenlimit, das dein System angibt. Alles andere wird von hier aus gemessen. Dieser Standardwert ist unser Platzhalter, nicht der Wert deines Systems. Gib deinen eigenen an.
+
+
+
--spread
+
Größen, durch Kommas getrennt
+
1B,1kb,1mb
+
Wie weit auf beiden Seiten des Limits gegangen wird, als Liste von Größen.
+
+
+
--format
+
eine Format-ID von der Formate-Seite
+
pdf
+
Das Format jeder Datei im Set. Es ist ein Flag des Tools selbst, das Preset gibt ihm nur einen Standardwert.
+
+
+
+
+
+
+
+
Wie führst du es aus?
+
Sieh nach, was das Set kosten würde, baue es oder nimm sein Rezept zum Bearbeiten:
Übersteht mein Tabellenimport das, was echte Tools exportieren?
+
+ Das Preset tabular-import baut mit einem Befehl ein ganzes Set echter Testdateien für diese
+ Frage und ein manifest.json daneben, das beschreibt, wie dein System auf jede Datei
+ reagieren soll. Alles unten wird aus dem Programm gelesen, mit den Standardwerten dieser Version.
+
+
+
+
+
Was findet es meistens?
+
+
eine CSV-Datei mit Semikolon, die als eine Spalte gelesen wird, weil das Trennzeichen angenommen statt gesucht wurde
+
eine CRLF-Datei, die in Zeilen mit einer leeren Zeile nach jeder zerlegt wird
+
eine Tabelle ohne Kopfzeile, deren erste Datenzeile als Spaltennamen verschluckt wird
+
ein Import, der die Spalten behält, die er anzeigen kann, und den Rest kommentarlos verwirft
+
ein Leser, der JSON-Datensätze Zeile für Zeile liest und beim ersten eingerückten Dokument aufgibt
+
+
+
+
+
+
Was steckt im Set?
+
Mit den Standardwerten, wie es tfg preset show tabular-import ausgibt:
+
+
+
+
Dateien
13
+
Targets in seinem Rezept
13
+
Gesamtgröße
3 080 060 B
+
Formate
csv, json, xlsx
+
+
+
+
Und was das Manifest dieses Sets von deinem System erwartet:
+
+
+
+
Erwartet
Bedeutung
Dateien
+
+
+
accept
Dein System soll die Datei annehmen.
8
+
unspecified
Das hängt von den Regeln deines Systems ab. Du entscheidest, dann prüfst du, ob das Ergebnis dem entspricht, was du gemeint hast.
5
+
+
+
+
+
+
+
Was kannst du ändern?
+
+
+
+
Einstellung
Nimmt
Standard
Was es tut
+
+
+
+
--rows
+
1 - 200000 Zeilen
+
1000
+
Wie viele Zeilen die Tabelle enthält. Die Datei wird in genau der Größe geschrieben, auf die sich so viele Zeilen verpacken lassen, daher verschiebt sich das Budget oben mit diesem Wert.
+
+
+
--columns
+
1 - 32768 Spalten
+
10
+
Wie viele Spalten jede Zeile der Tabelle hat. Zeilen mal Spalten hat eine Obergrenze, und wer darüber hinausgeht, wird abgewiesen, bevor etwas geschrieben wird.
+
+
+
+
+
+
+
+
Wie führst du es aus?
+
Sieh nach, was das Set kosten würde, baue es oder nimm sein Rezept zum Bearbeiten:
Weiß mein Leser, in welcher Kodierung eine Datei vorliegt, oder rät er?
+
+ Das Preset text-encoding baut mit einem Befehl ein ganzes Set echter Testdateien für diese
+ Frage und ein manifest.json daneben, das beschreibt, wie dein System auf jede Datei
+ reagieren soll. Alles unten wird aus dem Programm gelesen, mit den Standardwerten dieser Version.
+
+
+
+
+
Was findet es meistens?
+
+
ein Leser, der UTF-8 annimmt und eine UTF-16-Datei als jedes dritte Zeichen oder als Reihen von Kästchen anzeigt
+
eine Byte Order Mark, die als Inhalt gelesen wird, sodass das erste Feld eines Imports mit drei fremden Zeichen beginnt
+
ein Importer, der die Kodierung aus den ersten Bytes errät und bei einer längeren Datei anders rät
+
eine CRLF-Datei, die in Zeilen mit einer leeren Zeile nach jeder zerlegt wird, oder ein Wagenrücklauf, der im letzten Feld stehen bleibt
+
+
+
+
+
+
Was steckt im Set?
+
Mit den Standardwerten, wie es tfg preset show text-encoding ausgibt:
+
+
+
+
Dateien
20
+
Targets in seinem Rezept
20
+
Gesamtgröße
81 920 B
+
Formate
csv, log, md, txt, xml
+
+
+
+
Und was das Manifest dieses Sets von deinem System erwartet:
+
+
+
+
Erwartet
Bedeutung
Dateien
+
+
+
accept
Dein System soll die Datei annehmen.
10
+
unspecified
Das hängt von den Regeln deines Systems ab. Du entscheidest, dann prüfst du, ob das Ergebnis dem entspricht, was du gemeint hast.
10
+
+
+
+
+
+
+
Was kannst du ändern?
+
+
+
+
Einstellung
Nimmt
Standard
Was es tut
+
+
+
+
--sample
+
eine Größe wie 2mb
+
4kb
+
Wie groß jede Datei des Sets ist. UTF-16 speichert zwei Bytes pro Zeichen, daher wird eine ungerade Zahl abgewiesen.
+
+
+
+
+
+
+
+
Wie führst du es aus?
+
Sieh nach, was das Set kosten würde, baue es oder nimm sein Rezept zum Bearbeiten:
Nimmt mein Upload-Formular an, was es soll, und weist den Rest ab?
+
+ Das Preset upload-validation baut mit einem Befehl ein ganzes Set echter Testdateien für diese
+ Frage und ein manifest.json daneben, das beschreibt, wie dein System auf jede Datei
+ reagieren soll. Alles unten wird aus dem Programm gelesen, mit den Standardwerten dieser Version.
+
+
+
+
+
Was findet es meistens?
+
+
ein Limit, das im Browser durchgesetzt wird und nicht auf dem Server
+
eine SVG- oder HTML-Datei, die für ein Bild oder für einfachen Text gehalten wird, womit sich ein Skript an einem Formular vorbeischleusen lässt
+
eine Datei, die nur an der Endung geprüft und nie geöffnet wird, sodass ein PDF namens .jpg durchgeht
+
ein Formular, das den ganzen Body in den Speicher liest, bevor es nachsieht, wie groß er ist
+
ein Upload namens PHOTO.JPG, der abgewiesen wird, während photo.jpg durchkommt, oder umgekehrt
+
ein Name mit Leerzeichen, Klammern oder Zeichen außerhalb von ASCII, der unverändert auf die Platte geschrieben wird
+
+
+
+
+
+
Was steckt im Set?
+
Mit den Standardwerten, wie es tfg preset show upload-validation ausgibt:
+
+
+
+
Dateien
71
+
Targets in seinem Rezept
22
+
Gesamtgröße
120 639 488 B
+
Formate
html, jpg, pdf, png, svg, txt
+
+
+
+
Und was das Manifest dieses Sets von deinem System erwartet:
+
+
+
+
Erwartet
Bedeutung
Dateien
+
+
+
accept
Dein System soll die Datei annehmen.
56
+
reject
Dein System soll die Datei abweisen.
10
+
unspecified
Das hängt von den Regeln deines Systems ab. Du entscheidest, dann prüfst du, ob das Ergebnis dem entspricht, was du gemeint hast.
5
+
+
+
+
+
+
+
Was kannst du ändern?
+
+
+
+
Einstellung
Nimmt
Standard
Was es tut
+
+
+
+
--limit
+
eine Größe wie 2mb
+
10mb
+
Das Größenlimit, das dein Upload-Formular angibt. Dieses Set geht je einen Schritt auf beiden Seiten davon - für eine Datei in jedem Abstand führe das Preset size-boundaries aus. Dieser Standardwert ist unser Platzhalter, nicht der Wert deines Systems. Gib deinen eigenen an.
+
+
+
--allow
+
Format-IDs, durch Kommas getrennt
+
jpg,png,pdf
+
Welche Typen dein Formular akzeptieren soll. Jeder wird zu einer echten Datei dieses Typs, und sie sind die positive Kontrolle des ganzen Sets.
+
+
+
--deny
+
Endungen, durch Kommas getrennt
+
svg,html,exe,sh
+
Welche Endungen dein Formular abweisen soll. Für eine Endung, zu der dieser Build kein Format hat, wird trotzdem eine Datei mit diesem Namen geschrieben, die einfachen Text enthält.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
Wie weit über dem Limit die eine große Datei liegt. Schalte sie ab, wo es das Vielfache des Limits auf der Platte nicht wert ist.
+
+
+
--bulk
+
0 - 10000 Dateien
+
50
+
Wie viele Dateien der Massen-Upload enthält. Bei null fällt diese Gruppe ganz aus dem Set.
+
+
+
+
+
+
+
+
Wie führst du es aus?
+
Sieh nach, was das Set kosten würde, baue es oder nimm sein Rezept zum Bearbeiten:
+ Ein binäres Fixture in einem Repository bleibt für immer in dessen Verlauf, lässt sich in einem Diff
+ nicht prüfen und geht bei großen Dateien gar nicht mehr. Erzeugen Sie die Dateien stattdessen in
+ der Pipeline aus einem Rezept. Das Rezept ist Text, die Bytes sind jedes Mal dieselben, und ein
+ letzter Schritt beweist, dass sich nichts verändert hat.
+
+
+
+
Die kurze Antwort
+
+ Installieren Sie tfg, führen Sie vor den Tests tfg generate fixtures.yaml --out
+ ./fixtures aus und danach tfg verify ./fixtures/manifest.json. Beide
+ Schritte lassen den Build von selbst scheitern, mit einem Exit-Code, der sagt, warum.
+
+
+
+
+
Warum nicht einchecken
+
Warum ein Fixture nicht im Repository liegen sollte
+
+
+ Es bleibt im Verlauf. Eine Binärdatei später zu löschen macht einen Klon nicht
+ kleiner, denn jede ihrer Versionen ist weiterhin da.
+
+
+ Ein Diff zeigt nicht, was sich geändert hat. Der Reviewer sieht, dass eine PDF
+ anders ist, und sonst nichts. Ein Rezept ändert sich um eine Zeile.
+
+
+ Große Dateien passen nicht. GitHub lehnt einen Push mit einer Datei über 100 MB ab,
+ also gibt es für den Test eines Upload-Limits von 500 MB nichts einzuchecken.
+
+
+
+ Einzuchecken ist das Rezept. Dasselbe Rezept mit demselben Seed schreibt auf jeder Maschine
+ dieselben Bytes, die in der Pipeline erzeugte Datei ist also die Datei, die Sie auf dem Laptop
+ hatten.
+
+
+
+
+
Das Rezept
+
Ein Rezept, das neben den Tests liegt
+
+ Dieses schreibt fünfundzwanzig Rechnungen, die angenommen werden sollen, und zwei Bilder über einem
+ Limit, die abgewiesen werden sollen, und das Manifest hält beide Erwartungen fest:
+
+ Die Prüfsummenzeile vergleicht das Archiv mit verify-SHA256SUMS.txt aus demselben
+ Release. Die Version ist festgelegt, ein neues Release ändert also nie einen Build, den Sie
+ nicht angefasst haben.
+
+ Jedes Ende hat seinen eigenen Exit-Code, der Schritt scheitert also von selbst, und das Log sagt,
+ welcher es war. Die, denen eine Pipeline begegnet:
+
+
+
3 - das Rezept ist ungültig. Es wurde nichts geschrieben, und jedes Problem wird genannt
+
4 - das Format kann nicht, was verlangt wurde, zum Beispiel eine Größe unter seinem Minimum
+
6 - es ist nicht genug Speicherplatz da
+
7 - tfg verify hat eine Datei gefunden, die nicht zu ihrem Manifest passt
+
8 - der Lauf ist fertig, aber nicht alles wurde erzeugt
+
+
+ Ein fehlgeschlagener Lauf gibt nichts auf der Standardausgabe aus, sodass ein Log-Parser nie einen
+ Fehler für Daten hält. Die ganze Tabelle steht auf der
+ Dokumentationsseite.
+
+
+
+
+
PowerShell
+
Ein PowerShell-Skript braucht eine Zeile mehr
+
+ PowerShell trägt den Exit-Code eines Programms nicht aus einer .ps1-Datei heraus.
+ Starten Sie eine mit -File, und das Skript antwortet 0, auch wenn das
+ Tool darin die Arbeit verweigert hat, sodass ein Build, der rot sein sollte, grün wird. Die
+ letzte Zeile ist die ganze Lösung:
+
+ So verhält sich PowerShell, es liegt nicht an diesem Tool. cmd, bash und
+ zsh brauchen nichts zusätzlich.
+
+
+
+
+
Mehrere Jobs
+
Fixtures zwischen Jobs teilen
+
+ Hochladen ist meist nicht nötig. Weil dasselbe Rezept dieselben Bytes schreibt, kann jeder Job sein
+ eigenes tfg generate ausführen, und das geht schneller als Hoch- und Herunterladen.
+ Muss ein Job Dateien von einem anderen erhalten, führen Sie nach der Übertragung tfg
+ verify auf dem Manifest aus, und es sagt, ob das Angekommene dem Geschriebenen
+ entspricht.
+
A run stopped with Ctrl+C still leaves a manifest and never leaves a half written file behind, so
a cancelled job can still be cleaned up by the next one.
+
+ Un validador al que solo se le han mostrado archivos sanos no está realmente probado. Así se
+ consigue un archivo roto a propósito, que sale con exactamente el tamaño que
+ pides y trae un manifiesto que dice qué debe hacer tu sistema con él.
+
+
+
+
La respuesta corta
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out escribe un PNG de
+ exactamente 2097152 bytes cuyos primeros bytes son ceros, y el manifiesto que lo acompaña
+ registra que tu sistema debe rechazarlo.
+
+
+
+
+
La forma habitual
+
Por qué un archivo corrompido a mano es una mala prueba
+
+ Lo habitual es un editor hexadecimal, un script que cambia unos cuantos bytes al azar o cortar un
+ archivo con head o truncate. Funciona una vez y después sale caro:
+
+
+
+ Es distinto cada vez. Un byte al azar cae en un sitio nuevo en cada ejecución, así
+ que un fallo del martes puede no volver el miércoles.
+
+
+ Cambia el tamaño. Un archivo cortado es más pequeño que el límite bajo el que debía
+ quedar, de modo que la comprobación de tamaño responde antes que la del contenido y la prueba
+ pasa por el motivo equivocado.
+
+
+ A menudo pasa inadvertido. El texto plano se sigue leyendo con un byte cambiado en
+ medio, y un lector de imágenes indulgente simplemente lo dibuja, así que el archivo que debía
+ estar roto se acepta.
+
+
+ No dice nada de lo que debe ocurrir. El archivo son solo bytes, y quien lea la
+ prueba después tiene que adivinar si se quería la aceptación o el rechazo.
+
+
+
+
+
+
Lo que obtienes
+
Un archivo dañado conserva el tamaño que pediste
+
+ El archivo se genera con normalidad y se rompe después, de camino al disco. Conserva el tamaño que
+ pediste, y el mismo comando vuelve a escribir los mismos bytes.
+
+ Los ajustes van después de dos puntos. La opción se puede repetir, y los daños se aplican en el
+ orden en que los escribes. Funciona con cada uno de los 26 formatos.
+
+
+
+
+
Lo que puede hacer
+
¿Qué daños hay?
+
+ Esta es la lista que imprime el programa, leída de él al construir esta página. tfg
+ damage imprime la misma, y tfg damage <id> dice qué admite cada uno.
+
+
+
+
+
+
Daño
+
Qué hace con los bytes
+
Archivo más pequeño
+
Ajustes
+
+
+
+
+
zero-head
+
Sobrescribe los primeros bytes del archivo con ceros sin tocar su longitud. La mayoría de los lectores miran ahí primero, así que casi todo nota este daño.
+
8
+
bytes
+
+
+
+
+
+ zero-head escribe ceros sobre el comienzo del archivo. La mayoría de los lectores miran
+ ahí primero, la firma y la cabecera que dicen qué es el archivo, así que casi cualquier lector
+ lo nota. El texto plano y los registros no tienen firma y también se rechazan, porque una serie
+ de bytes nulos no es texto. Por debajo de cuatro bytes algunos formatos salen con un daño del
+ que ningún lector se queja, por eso el ajuste empieza en cuatro.
+
+
+
+
+
Lo que dice el manifiesto
+
Un manifiesto que dice lo que debe ocurrir
+
+ Cada archivo dañado recibe una entrada que dice que tu sistema debe rechazarlo, con el daño anotado
+ al lado:
+
+ Se rechazan dos peticiones antes de escribir nada, porque cada una dejaría en el disco un archivo
+ que el manifiesto describe mal:
+
+
+
un archivo más pequeño de lo que el daño necesita, que saldría intacto
+
+ expected: accept junto a un daño, porque nada podría cumplirlo. Escribe
+ sanitize si tu sistema debe reparar el archivo, o unspecified si esa
+ es justo la pregunta que haces
+
+
+
+
+
+
En una receta
+
Archivos sanos y rotos en una sola ejecución
+
+ Pon ambos en una receta y el manifiesto lleva lo esperado de cada archivo, así que la prueba no
+ necesita una lista de cuál es cuál:
+
+ La prueba lee el manifiesto y comprueba que lo ocurrido es lo declarado. No necesita una lista de
+ nombres de archivo:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Un buen rechazo es un rechazo limpio. Un mensaje que dice qué estaba mal es la respuesta que
+ quieres. Un error de servidor, un bloqueo o un archivo guardado a medias es el defecto que esta
+ prueba existe para encontrar.
+
+
+
+
+
Siguiente
+
A dónde ir desde aquí
+
+
+ El preset upload-validation hace a un formulario las
+ otras dos preguntas, la del tamaño y la del tipo.
+
Cómo generar archivos de prueba en un pipeline de CI
+
+ Un fixture binario en un repositorio se queda para siempre en su historial, no se puede revisar en
+ un diff y deja de ser posible cuando el archivo es grande. Genera los archivos dentro del pipeline
+ a partir de una receta. La receta es texto, los bytes salen iguales cada vez y un último paso
+ demuestra que nada se movió.
+
+
+
+
La respuesta corta
+
+ Instala tfg, ejecuta tfg generate fixtures.yaml --out ./fixtures antes de
+ las pruebas y tfg verify ./fixtures/manifest.json después. Los dos pasos hacen
+ fallar la compilación por sí solos, con un código de salida que dice por qué.
+
+
+
+
+
Por qué no subirlos
+
Por qué un fixture no debe vivir en el repositorio
+
+
+ Se queda en el historial. Borrar un binario más tarde no hace más pequeño un clon,
+ porque todas sus versiones siguen ahí.
+
+
+ Un diff no muestra qué cambió. El revisor ve que un PDF es distinto y nada más. Una
+ receta cambia en una línea.
+
+
+ Los archivos grandes no caben. GitHub rechaza un push que contenga un archivo de
+ más de 100 MB, así que una prueba de un límite de subida de 500 MB no tiene nada que subir.
+
+
+
+ Lo que hay que subir es la receta. La misma receta y la misma semilla escriben los mismos bytes en
+ cualquier máquina, así que el archivo generado en el pipeline es el que tenías en tu portátil.
+
+
+
+
+
La receta
+
Una receta que vive junto a las pruebas
+
+ Esta escribe veinticinco facturas que deben aceptarse y dos imágenes por encima de un límite que
+ deben rechazarse, y el manifiesto registra las dos expectativas:
+
+ La línea de la suma de comprobación compara el archivo con verify-SHA256SUMS.txt de la
+ misma versión. La versión está fijada, así que una versión nueva nunca cambia una compilación
+ que no tocaste.
+
+ Cada final tiene su propio código de salida, así que el paso falla por sí solo y el registro dice
+ cuál fue. Los que encuentra un pipeline:
+
+
+
3 - la receta no es válida. No se escribió nada y se nombra cada problema
+
4 - el formato no puede hacer lo pedido, por ejemplo un tamaño por debajo de su mínimo
+
6 - no hay suficiente espacio en disco
+
7 - tfg verify encontró un archivo que no coincide con su manifiesto
+
8 - la ejecución terminó, pero no se produjo todo
+
+
+ Una ejecución fallida no imprime nada en la salida estándar, así que un analizador de registros
+ nunca toma un error por datos. La tabla completa está en la
+ página de documentación.
+
+
+
+
+
PowerShell
+
Un script de PowerShell necesita una línea más
+
+ PowerShell no saca el código de salida de un programa fuera de un archivo .ps1. Ejecuta
+ uno con -File y el script responde 0 incluso cuando la herramienta de
+ dentro rechazó el trabajo, así que una compilación que debería estar en rojo pasa a verde. La
+ última línea es toda la solución:
+
+ Así se comporta PowerShell, no es algo de esta herramienta. cmd, bash y
+ zsh no necesitan nada más.
+
+
+
+
+
Varios jobs
+
Compartir los fixtures entre jobs
+
+ Normalmente no hace falta subirlos. Como la misma receta escribe los mismos bytes, cada job puede
+ ejecutar su propio tfg generate, que es más rápido que subir y bajar. Cuando un job
+ tiene que recibir archivos de otro, ejecuta tfg verify sobre el manifiesto tras la
+ transferencia y te dice si lo que llegó es lo que se escribió.
+
+ Cinco tareas que aparecen en casi todos los proyectos que aceptan archivos de personas, y el comando
+ que hace cada una. Cada ejemplo de abajo se ejecuta tal como está escrito.
+
+
+
+
Límites de subida
+
Probar si un límite de tamaño de archivo se aplica donde dice que se aplica
+
+ Un límite son tres casos de prueba, no uno: justo por debajo, exactamente en él y justo por encima.
+ Conseguirlos a mano significa calcular números de bytes y esperar no haberte equivocado en uno.
+ Pide el conjunto en su lugar:
+
+ Obtienes tres PDF reales de 1048575, 1048576 y 1048577 bytes, y un manifiesto que dice que los dos
+ primeros deben aceptarse y el tercero rechazarse por size_limit. Tu prueba lee la
+ expectativa en lugar de que escribas tres aserciones a mano - y cuando cambia el límite, cambias
+ un número y vuelves a ejecutar.
+
+
+ Lo mismo funciona sin preset cuando quieres un único conjunto de límites en línea:
+
Mantener los fixtures fuera del repositorio sin perderlos
+
+ Los fixtures binarios grandes hacen lento clonar un repositorio y incómodo revisarlo, y nadie puede
+ decir qué cambió cuando se sustituye uno. Una receta son unos cientos de caracteres de YAML que
+ reconstruyen los archivos idénticos - byte a byte, en cualquier máquina -
+ porque cada archivo se deriva de la semilla de la ejecución.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Cada final tiene su propio código de salida, así que una canalización puede distinguir una receta
+ mala de un disco lleno y de una discrepancia de verificación. Una ejecución fallida no imprime
+ nada en la salida estándar, lo que evita que un analizador de registros lea un error como datos.
+
+
+
+
+
Escala
+
Descubrir qué pasa cuando la carpeta es grande
+
+ Las rutinas de importación, los trabajos nocturnos y los listados de directorios se comportan
+ distinto con diez mil archivos que con diez. Los tamaños sacados de un intervalo hacen que el
+ conjunto parezca tráfico real en lugar de diez mil archivos idénticos, y el sorteo viene de la
+ semilla, así que el conjunto es el mismo mañana.
+
+ Una ejecución mayor que el espacio libre del disco se rechaza antes de escribir el primer byte, en
+ lugar de llenar el disco y fallar a medias.
+
+
+
+
+
Archivos comprimidos
+
Probar un descompresor con un archivo comprimido que de verdad contiene archivos
+
+ Un archivo comprimido vacío con la extensión correcta no demuestra nada sobre el código que lo abre
+ y recorre lo que hay dentro. Declara el contenido y el archivo comprimido lo contiene de verdad:
+
+ La profundidad de anidamiento, el número de entradas y el tamaño de lo que hay dentro son cosas
+ sobre las que una rutina de importación tiene opiniones, y así descubres cuáles son.
+
+
+
+
+
Analizadores y visores
+
Comprobar que tu propio código lee un formato como lo hace el software real
+
+ Cada formato de aquí se comprueba con un lector independiente antes de publicarse - un PNG se abre y
+ se comparan sus píxeles, un DOCX lo vuelven a leer bibliotecas distintas, un archivo comprimido
+ se extrae. Eso significa que un archivo que tu analizador rechaza es un hallazgo sobre tu
+ analizador, no sobre el generador.
+
+ La página de formatos lista los ajustes que admite cada uno y el archivo
+ más pequeño que puede ser cada uno.
+
+
+
+
+
Guías
+
Dos de ellos con más detalle
+
+
+ Archivos de prueba corruptos - un archivo roto a
+ propósito, con el tamaño exacto y con lo que debe ocurrirle escrito en el manifiesto.
+
+
+ Archivos de prueba en CI - un workflow de GitHub
+ Actions, un job de GitLab y los códigos de salida que hacen fallar una compilación.
+
+
+
+
+
+
Para quién es
+
+ Ingenieros de QA, automatización de pruebas y cualquiera cuyo código tenga detrás un formulario de
+ subida, una rutina de importación, un analizador o una cuota de almacenamiento. Funciona en una
+ máquina sin red alguna, lo que importa en un entorno corporativo cerrado donde un generador
+ basado en navegador no es una opción.
+
+ Cada sistema tiene un comando para ello, y los tres están abajo. Te dan un archivo con exactamente
+ el número correcto de bytes - y para muchas pruebas eso es todo lo que necesitas. Cada
+ comando de esta página se ejecutó antes de publicarse, en el sistema al que pertenece.
+
+
+
+
La respuesta corta
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Los tamaños son en bytes, y 10 MB
+ contados como los cuenta tu gestor de archivos son 10485760.
+
+
+
+
+
Windows
+
fsutil, y una versión de PowerShell que no necesita nada extra
+
+ fsutil viene con Windows. Toma el tamaño en bytes, así que calcula
+ antes el número - 10 MB son 10485760, 100 MB son 104857600, 1 GB es 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Medido en Windows 11: funciona desde un símbolo del sistema normal sin necesitar uno elevado, y el
+ archivo sale con exactamente 10485760 bytes.
+
+
PowerShell puede hacer lo mismo sin llamar a otro programa, y entiende unidades:
+ 10MB en PowerShell significa 10485760 bytes, el mismo recuento en base 1024 que usa el
+ Explorador, así que los dos comandos anteriores producen el mismo tamaño.
+
+
+
+
+
Linux
+
dd, truncate y fallocate, y la diferencia que pilla a la gente
+
dd es el que todo el mundo conoce. Escribe los bytes de verdad:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate es instantáneo, y esa es la trampa. Medido en Alpine Linux, el archivo informa
+ de 10485760 bytes y ocupa cero bloques - es un archivo
+ disperso. Cualquier cosa que lo lea obtiene diez megabytes de ceros, pero el disco
+ nunca cedió el espacio:
+
+
truncate -s 10M test10mb.bin
+
+ Eso sirve para probar un límite de subida y engaña para probar una cuota de disco.
+ fallocate es el que hay que usar cuando el espacio tiene que ser real:
+
+
fallocate -l 10M test10mb.bin
+
Y cuando el contenido tiene que ser incompresible, para que un compresor no pueda volver a reducirlo:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, que no es disperso, y los dos que ya conoces
+
+ macOS incluye mkfile. Medido en macOS 26.6.2: 10485760 bytes y 20480 bloques, así que
+ el espacio está realmente asignado en lugar de prometido:
+
+
mkfile 10m test10mb.bin
+
dd y truncate también están y se comportan como en Linux:
Un archivo del tamaño correcto no es un archivo del tipo correcto
+
+ Todo lo anterior te da un bloque de ceros. Eso basta cuando lo que se prueba solo mira el tamaño -
+ un límite de subida, una cuota, una transferencia. Deja de bastar en cuanto algo
+ abre el archivo.
+
+
+ Medido, y merece la pena que lo hagas tú: crea un archivo de 2 MB con fsutil, llámalo
+ photo.png y pásaselo a una biblioteca de imágenes. Pillow responde cannot
+ identify image file. No es un PNG. Nunca lo fue - solo lo decía el nombre.
+
+
+ Eso importa más de lo que parece, por la forma en que la prueba falla entonces. Tu
+ endpoint de subida rechaza el archivo, tu prueba se pone en verde y concluyes que el límite de
+ tamaño funciona. No lo rechazó por el tamaño. Lo rechazó porque los bytes no eran una imagen, y
+ la regla que querías probar nunca se alcanzó.
+
+
+
un analizador lo rechaza antes de mirar ninguna regla de tamaño
+
falla un paso de miniaturas y el error que lees trata de la miniatura
+
un antivirus o una comprobación de contenido lo rechaza por un tercer motivo
+
un visor no muestra nada, y nadie puede saber si ese es el fallo
+
+
+
+
+
La otra vía
+
Un archivo real de ese formato, con exactamente el tamaño que pediste
+
+ Esto es lo que hace Testing Files Generator. El archivo es uno genuino de su formato - se abre en el
+ programa que le corresponde - y tiene el número exacto de bytes que pediste, al byte:
+
+ Pide un tamaño que un formato no puede alcanzar y obtienes un error que nombra el suelo y su motivo,
+ nunca un archivo del tamaño equivocado. La página de formatos lista
+ cada formato con el archivo más pequeño que puede producir.
+
+
Y un límite son tres casos de prueba y no uno, así que la herramienta construye los tres:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Eso te da 10485759, 10485760 y 10485761 bytes, y un manifiesto que dice cuáles debe aceptar tu
+ sistema y cuáles rechazar. La página de casos de uso repasa eso
+ y otras cuatro tareas para las que está pensada.
+
Gratuito y de código abierto, GPL-3.0. Sin registro. Las descargas de Windows y macOS están firmadas y se inician sin advertencias.
+
+
+
+
Entonces, ¿cuál debes usar?
+
+
+
Usa el comando del sistema
+
+ Cuando nada abre el archivo. Probar un límite de tamaño en un endpoint que comprueba antes el
+ tamaño, una transferencia, una cuota, un disco lleno. Es una línea y ya está instalado.
+
+
+
+
Usa un generador real
+
+ Cuando algo analiza, renderiza, importa o extrae el archivo - y cuando necesitas los mismos fixtures
+ mañana, en otra máquina, byte a byte.
+
+
+
+
+ Ambos están en esta página porque ambos aciertan parte del tiempo. El error que conviene evitar es
+ usar el primero donde hace falta el segundo y leer la prueba en verde como una demostración.
+
+ Todo lo que hace la herramienta, ordenado según las preguntas con las que la gente llega de verdad.
+ El README del repositorio es la referencia completa y siempre
+ coincide con la versión que descargaste.
+
+
+
+
¿Qué comandos hay?
+
Cada uno hace una sola cosa:
+
tfg generate producir archivos, desde una receta o desde opciones
+tfg validate comprobar una receta sin escribir nada
+tfg verify comprobar un directorio contra un manifiesto
+tfg cleanup eliminar los archivos que lista un manifiesto
+tfg recipe fmt imprimir una receta en su forma normalizada
+tfg preset construir un conjunto de archivos a partir de una pregunta de prueba con nombre
+tfg formats listar los formatos que admite esta versión
+tfg damage listar las formas en que esta versión puede romper un archivo a propósito
+tfg tool pequeñas utilidades para archivos que ya tienes
+tfg version imprimir la versión de la herramienta
+tfg license imprimir la licencia y qué significa para los archivos generados
+
+
+
+
¿Cómo genero un único archivo de tamaño exacto?
+
+ Indica el formato, el tamaño y dónde va. Los tamaños cuentan de 1024 en 1024, así que
+ 2mb son 2097152 bytes. Un número de bytes simple también sirve, de modo que
+ --size 10485761 pide exactamente esa cantidad.
+
+
tfg generate --format png --size 2mb --out ./out
+
Las opciones útiles de generate:
+
+
+
Opción
Qué hace
+
+
--format <id>
formato de los archivos, por ejemplo txt
+
--size <size>
tamaño exacto de cada archivo, como 10mb o un número de bytes simple
+
--size-range <a-b>
un tamaño sacado por archivo de un intervalo, como 1kb-8kb. El sorteo viene de la semilla
+
--boundary <size>
tres archivos alrededor de un límite: un byte por debajo, el límite, un byte por encima
+
--count <n>
cuántos archivos producir. Por defecto 1
+
--name <template>
plantilla de nombre, por ejemplo invoice_{index:04}.txt
+
--out <dir>
directorio donde escribir
+
--seed <n>
semilla de la ejecución. La misma semilla da los mismos bytes
+
--set <k>=<v>
un ajuste de formato, repetible
+
--damage <name>
romper los archivos a propósito, repetible y aplicado en orden. Ejecuta tfg damage para ver la lista
+
--expected <outcome>
accept, reject, sanitize o unspecified
+
--dry-run
contar y mostrar, sin escribir absolutamente nada
+
--json
escribir el manifiesto en la salida estándar
+
+
+
+
+
+
+
¿Cómo hago un archivo roto a propósito?
+
+ Todos los demás archivos que escribe esta herramienta son correctos por construcción, lo que
+ responde a dos de las tres preguntas que hace un validador de subidas. --damage
+ responde a la tercera - si el archivo se abre siquiera. El archivo se produce con normalidad y
+ luego se rompe, así que conserva el tamaño que pediste.
+
+ Los ajustes van después de dos puntos. La opción se repite, y el orden en que las escribes es el
+ orden en que se aplican. tfg damage lista lo que puede hacer esta versión y qué
+ admite cada una.
+
+
En una receta la clave es una lista, de nombres o de ajustes:
+ Un archivo dañado recibe expected: reject en el manifiesto, con el daño registrado a su
+ lado. Dos cosas se rechazan antes de escribir nada, porque cada una dejaría en disco un archivo
+ que el manifiesto describe mal:
+
+
+
un archivo más pequeño de lo que necesita el daño, porque saldría sin cambios
+
+ expected: accept junto a un daño, porque nada podría cumplirlo. Escribe
+ sanitize si el sistema bajo prueba debe reparar el archivo, o
+ unspecified si esa es la pregunta que haces
+
+
+
+ Una tercera no se puede saber de antemano. Si un daño se ejecuta y no mueve ningún byte, ese archivo
+ se descarta en lugar de escribirse - la ejecución continúa, dice de qué archivo se trató y
+ termina con el código de salida parcial.
+
+ Una receta es un archivo YAML que describe una ejecución completa. Súbela al repositorio junto a tus
+ pruebas y los fixtures dejan de ser binarios en tu repositorio - cualquiera puede
+ reconstruirlos, byte a byte, a partir de un archivo de unos cientos de caracteres.
+
+ Cada target necesita exactamente una de estas claves: size, size-range,
+ boundary o contains. Dos es un error y ninguna también. Una receta
+ inválida escribe ningún archivo e informa de todos los problemas a la vez en
+ lugar de solo del primero, cada uno nombrando el ajuste al que se refiere.
+
+
+
+
+
¿Cómo declaro qué debe hacer mi sistema con un archivo?
+
Forma corta cuando basta con el resultado, forma larga cuando importa el motivo:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Los resultados son accept, reject, sanitize y
+ unspecified. Los motivos son una lista cerrada para que un informe pueda
+ agruparlos: content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit y size_zero.
+
+
+ Un motivo nombra la regla en juego, no el veredicto. Por eso el mismo motivo puede
+ estar bajo cualquiera de los dos resultados - un archivo un byte por debajo de un límite es
+ accept, y la regla de la que trata sigue siendo size_limit.
+
+
+
+
+
¿Qué hay en el manifiesto?
+
+ Se escribe junto a los archivos al final de cada ejecución, incluida una ejecución interrumpida. Una
+ entrada por archivo:
+
+ Se añade un recipe_hash cuando la ejecución viene de una receta, y preset
+ con overrides cuando viene de un preset, de modo que un manifiesto siempre se puede
+ rastrear hasta lo que lo produjo.
+
+
+ Cada entrada lleva también target_id, el id del target de la receta que produjo el
+ archivo, y summary.by_target cuenta los archivos a los que llegó cada target. Una
+ receta con varios targets se puede comprobar así target por target sin leer nombres de archivo.
+
+
+
+
+
¿Qué es un preset?
+
+ Un conjunto de archivos listo que responde a una pregunta de prueba habitual, para que no tengas que
+ diseñar el conjunto tú. Los presets son recetas normales por debajo, y eject
+ imprime la receta para que la edites desde ahí. Cada preset tiene una
+ página propia con lo que suele encontrar, qué hay en el conjunto y cada ajuste que admite.
+
+ show te dice cuánto costaría el conjunto antes de construirlo, y dice sin rodeos cuándo
+ un número es un marcador nuestro en lugar de un límite tuyo.
+
+
+
+
+
¿Qué significan los códigos de salida?
+
+ Cada final tiene su propio código, la salida legible por máquina va a la salida estándar, y una
+ ejecución fallida no imprime nada allí. La tabla es un contrato congelado - cambiar lo que
+ significa un código exige una versión mayor.
+
+
+
+
+
+
Código
+
Significado
+
+
+
+
+
0
+
Todo ha funcionado.
+
+
+
1
+
Un error inesperado dentro de la herramienta.
+
+
+
2
+
Comando u opción incorrectos.
+
+
+
3
+
La receta no es válida.
+
+
+
4
+
El formato no puede hacer lo que se pidió.
+
+
+
5
+
Ha fallado una lectura o una escritura.
+
+
+
6
+
No hay espacio suficiente en disco.
+
+
+
7
+
verify ha encontrado una discrepancia.
+
+
+
8
+
La ejecución terminó, pero no se produjo todo.
+
+
+
130
+
Interrumpido con Ctrl+C.
+
+
+
143
+
Detenido por una señal, que es el aspecto de un tiempo de espera agotado en CI.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Una ejecución detenida con Ctrl+C sigue dejando un manifiesto y nunca deja un archivo a medio
+ escribir, así que un trabajo cancelado aún puede limpiarlo el siguiente.
+
+ Sí, el mismo motor con una ventana encima, para las pruebas que no se automatizan. No es una versión
+ recortada: una prueba compara las dos interfaces capacidad por capacidad, y todo lo que solo una
+ de ellas puede hacer debe declararse y justificarse en lugar de divergir en silencio.
+
+
+ Las pantallas son un lote, presets, varios lotes a la vez y Acerca de. Muestra lo que costaría una
+ ejecución antes de escribir nada, informa del progreso mientras corre y se puede cancelar a
+ medias sin dejar un archivo a medio escribir. Todavía no abre un archivo de receta - por ahora
+ las recetas son cosa de la línea de comandos, y la ventana construye sus lotes en el formulario.
+
26 formatos de archivo, cada uno generado a un tamaño exacto
+
+ Cada uno es un archivo real de ese formato. Se abre en el programa que le
+ corresponde y tiene exactamente el número de bytes que pediste. Ninguno es relleno de ceros con
+ una extensión pegada.
+
+
+
+
+
+
+
Formato
+
Nombre
+
Extensión
+
Archivo más pequeño
+
Fidelidad
+
Comprobado con
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
no aplicable
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
no aplicable
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
no aplicable
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
Qué significan las columnas
+
+
+
Archivo más pequeño
+
+ Los menos bytes que esta herramienta aceptará para ese formato, incluida la etiqueta que escribe
+ dentro del archivo. Pide menos y obtienes un error que nombra el suelo y su motivo, nunca un
+ archivo del tamaño equivocado.
+
+
+
+
Fidelidad
+
+ Cuán completo es el archivo. full significa que lo acepta un lector que analiza de
+ verdad el formato, no solo que la extensión coincida.
+
+
+
+
Comprobado con
+
+ El lector independiente que abre cada archivo generado antes de que el formato se publique - una
+ implementación aparte, no nuestro propio código corrigiendo sus propios deberes.
+
+
+
+
+ Cada formato también se repite byte a byte: la misma receta y la misma semilla producen archivos
+ idénticos en cualquier máquina, y eso es lo que hace seguro subir al repositorio una receta en
+ lugar de los fixtures mismos.
+
+
+
+
+
Ajustes que admite cada formato
+
+ La mayoría de los formatos tienen ajustes propios - dimensiones de imagen, calidad JPEG, número de
+ páginas de PDF, filas y columnas de una hoja de cálculo, cuántas entradas van dentro de un
+ archivo comprimido. Defínelos con --set key=value en la línea de comandos, o bajo
+ properties: en una receta.
+
una fecha como 2024-02-29 o 2024-02-29T13:45:00+02:00, o none
+
+
+
+
modified
+
una fecha como 2024-02-29 o 2024-02-29T13:45:00+02:00, o none
+
+
+
png
+
width
+
1 - 20000 píxeles
+
+
+
+
height
+
1 - 20000 píxeles
+
+
+
pptx
+
slides
+
1 - 500 diapositivas
+
+
+
svg
+
width
+
1 - 20000 píxeles
+
+
+
+
height
+
1 - 20000 píxeles
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
el id de un formato, tal como lo lista tfg formats
+
+
+
+
entry_size
+
un tamaño como 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
verdadero o falso
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 píxeles
+
+
+
+
height
+
1 - 20000 píxeles
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
verdadero o falso
+
+
+
wav
+
sample_rate
+
8000 - 192000 hercios
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 píxeles
+
+
+
+
height
+
1 - 16383 píxeles
+
+
+
xlsx
+
rows
+
1 - 200000 filas
+
+
+
+
columns
+
1 - 32768 columnas
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
verdadero o falso
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
el id de un formato, tal como lo lista tfg formats
+
+
+
+
entry_size
+
un tamaño como 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
verdadero o falso
+
+
+
+
password
+
la contraseña, en texto plano
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ Un valor fuera de lo que admite un ajuste se rechaza con un mensaje que nombra el ajuste, el
+ intervalo permitido y qué usar en su lugar. Un ajuste desconocido también es un error, nunca un
+ valor por defecto silencioso - una errata aceptada en silencio da un archivo con los ajustes
+ equivocados y una hora preguntándote por qué la prueba pasa cuando no debería.
+
+
+ Ejecuta tfg formats <id> para ver exactamente qué admite un formato en la versión
+ que tienes.
+
+
+
+
+
Los archivos comprimidos contienen archivos reales
+
+ targz y zip se
+ pueden llenar de entradas en lugar de quedar como un cascarón vacío. Un archivo comprimido
+ generado contiene de verdad los documentos que dice contener, así que todo lo que lo descomprima
+ durante una prueba encuentra archivos reales dentro.
+
+ PDF, PNG, DOCX, ZIP - 26 formatos en total, y cada uno es un
+ archivo real que se abre en el programa que le corresponde, con exactamente el tamaño
+ que pediste. Cada ejecución también anota qué debe hacer tu aplicación con cada
+ archivo. Línea de comandos y ventana de escritorio, gratis y de código abierto, funcionando por
+ completo en tu máquina.
+
Gratuito y de código abierto, GPL-3.0. Sin registro. Las descargas de Windows y macOS están firmadas y se inician sin advertencias.
+
+
+
+
+ La ventana de escritorio, lista para escribir un lote de archivos. El mismo motor funciona detrás de la línea de comandos.
+
+
+
+
+
+ 26
+
formatos reales, cada uno se abre en el programa que le corresponde
+
+
+ 1 byte
+
la precisión de cada tamaño que pides, nunca redondeado en silencio
+
+
+ 0
+
conexiones a ningún sitio - sin cuenta, sin telemetría, sin comprobación de actualizaciones
+
+
+
+
+
El problema
+
Hacer un archivo de prueba es fácil. Hacer los mil correctos es la parte tediosa
+
Estás probando software que acepta archivos de personas. Tarde o temprano necesitas:
+
+
un PDF de exactamente 10 MB, para saber si el límite de subida es real
+
los tres archivos a ambos lados de ese límite, para cazar errores de uno
+
10 000 archivos de registro, para ver qué hace el trabajo nocturno cuando la carpeta es grande
+
un ZIP que de verdad contiene 200 documentos, no un cascarón con la extensión correcta
+
un archivo de 4 GB, sin guardar un archivo de 4 GB en tu repositorio
+
los mismos fixtures en tu portátil y en el servidor de compilación, byte a byte
+
+
+ Eso es lo que esto sustituye. Está pensado para ingenieros de QA, automatización de pruebas y
+ cualquiera cuyo código tenga detrás un formulario de subida, una rutina de importación, un
+ analizador o una cuota de almacenamiento.
+
+
+
+
+
Qué lo hace distinto
+
Otros generadores se quedan en los bytes. Este responde a lo que tu prueba realmente pregunta
+
+ Una carpeta de archivos te deja aún decidiendo qué se supone que demuestra cada uno. Cada ejecución
+ escribe aquí un manifest.json junto a los archivos - una lista simple de todo lo
+ producido y, para cada entrada, una expectativa declarada.
+
+
Supón que tu endpoint de subida permite 1 MB. Pide los tres archivos que están sobre esa línea:
Donde la respuesta depende de tu propia política, el manifiesto lo dice
+
+ Registra unspecified en lugar de inventar una expectativa. Un generador que adivina
+ produce falsos fallos, y un conjunto de pruebas que da falsas alarmas acaba apagado.
+
+
+
+
+
+
Presets
+
Elige la pregunta, obtén el conjunto entero
+
+ Un preset es un conjunto de archivos de prueba diseñado en torno a una pregunta de prueba, para que
+ no tengas que averiguar qué archivos demuestran qué. Cada uno tiene una página que dice qué
+ suele encontrar, qué hay en el conjunto y cada ajuste que admite.
+
+ Diez mil archivos de registro, cada uno de entre uno y ocho kilobytes, con los tamaños sacados de la
+ semilla para que mañana dé el mismo conjunto. Dale a cada ejecución su propio
+ directorio - el manifiesto es el único registro de lo que escribió una ejecución,
+ así que la herramienta se niega a escribir un segundo encima:
+
+ Los tamaños cuentan de 1024 en 1024, como hace tu gestor de archivos, así que 2mb
+ significa 2097152 bytes. Un número de bytes simple también sirve. La
+ documentación cubre las recetas, el manifiesto y los códigos de
+ salida.
+
+
+
+
+
Qué obtienes
+
Pensado para un conjunto de pruebas que corre sin supervisión
+
+
+
Tamaño exacto, al byte
+
Pide 10485761 bytes y obtén exactamente eso. Un tamaño que un formato no puede alcanzar es un error con un motivo, nunca un archivo del tamaño equivocado.
+
+
+
26 formatos reales
+
No ceros de relleno con una extensión. Un PNG generado se abre en un visor de imágenes, un DOCX se abre en Word, un ZIP se extrae. Cada uno se comprueba con lectores independientes antes de publicarse.
+
+
+
Un manifiesto que es un oráculo de pruebas
+
Ruta, tamaño, SHA-256, formato, semilla, versión de la herramienta - y qué debe hacer tu sistema con el archivo.
+
+
+
Reproducible
+
Misma receta y misma semilla, mismos bytes, en cualquier máquina. Sube al repositorio una receta YAML pequeña en lugar de fixtures binarios grandes.
+
+
+
Dos interfaces, un motor
+
Una línea de comandos pensada para CI y una ventana de escritorio para pruebas exploratorias. Ninguna es una versión recortada de la otra, y una prueba las compara capacidad por capacidad.
+
+
+
Completamente sin conexión
+
Sin cuenta, sin nube, sin telemetría, sin comprobación de actualizaciones. El binario de la línea de comandos no lleva compilada ninguna pila de red.
+
+
+
+
+
+
Descarga
+
Elige la versión para tu sistema
+
+ Descomprime el archivo y ejecútalo. tfg es la línea de comandos y tfg-gui
+ es la ventana de escritorio. No hay instalador ni nada que añadir a tu máquina.
+
+
+
+
+
+
Sistema
+
Línea de comandos
+
Ventana de escritorio
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
Qué está firmado y qué no
+
+ Las descargas de Windows y macOS están firmadas, así que se inician sin advertencia de desarrollador
+ desconocido. Las de Linux no, porque Linux de escritorio no tiene un equivalente con el que
+ firmarlas. Cada archivo aparece en verify-SHA256SUMS.txt en la página de
+ versiones, para que puedas comprobar lo que descargaste.
+
+ Licencia, privacidad, reproducibilidad y lo que la gente comprueba antes de poner un generador en
+ una canalización de compilación. Si tu pregunta no está aquí, el
+ gestor de incidencias está abierto.
+
+
+
+
+
¿En qué se diferencia de dd, fsutil o truncate?
+
+
Esos comandos te dan un archivo del tamaño correcto lleno de nada. Un archivo de 2 MB llamado photo.png hecho así no es un PNG, de modo que cualquier cosa que lo analice de verdad lo rechaza por el motivo equivocado, y tu prueba también pasa por el motivo equivocado. Esto produce un PNG real de exactamente 2 MB que se abre en un visor de imágenes, y llega con una declaración de cómo debe tratarlo tu sistema.
Sí a ambas. Se publica bajo GPL-3.0 y no cuesta nada. No hay cuenta, ni clave de licencia, ni nivel de pago.
+
+
+
+
¿Puedo usar los archivos generados en un producto de código cerrado?
+
+
Sí. La licencia cubre el código de la herramienta, no lo que la herramienta produce. Los archivos, recetas y manifiestos generados son una salida y no obras derivadas, así que puedes subirlos al repositorio y distribuirlos sin ninguna obligación.
+
+
+
+
¿Contienen los archivos generados datos personales reales?
+
+
No. Todo lo que hay dentro se sintetiza a partir de una semilla. No se lee ningún conjunto de datos, no se contacta con ningún servicio y no se incrusta contenido de terceros. Trata una dirección de correo generada como inutilizable en lugar de como no usada, porque cualquier cadena aleatoria puede coincidir por casualidad con una real.
+
+
+
+
¿Obtendré exactamente los mismos archivos en otra máquina?
+
+
Sí, byte a byte, con la misma receta y la misma semilla. El proyecto lo prueba en cada cambio, y romperlo exige una versión mayor. Eso es lo que te permite subir al repositorio una receta pequeña en lugar de fixtures binarios grandes.
+
+
+
+
¿Necesita conexión a internet?
+
+
Nunca. No hay telemetría, ni comprobación de actualizaciones, ni cliente en la nube, y el binario de la línea de comandos no lleva compilada ninguna pila de red. Funciona en una máquina sin red y dentro de un entorno corporativo cerrado.
+
+
+
+
¿Qué pasa si pido un tamaño que un formato no puede alcanzar?
+
+
Obtienes un error que nombra el formato, lo más pequeño que puede ser, el motivo de ese suelo y qué hacer en su lugar, y no se escribe ningún archivo. La herramienta nunca redondea un tamaño en silencio. Cada suelo aparece en la página de formatos.
+
tfg formats png
+
+
+
+
¿Puedo generar un archivo deliberadamente roto?
+
+
Sí. Añade --damage zero-head y el archivo sale con exactamente el tamaño pedido, con sus primeros bytes sobrescritos por ceros, de modo que un lector lo rechaza, y el manifiesto dice que tu sistema debe rechazarlo. La página sobre archivos de prueba corruptos tiene los detalles.
7z, mp3 y mp4. Hoy funcionan de principio a fin 26 formatos.
+
+
+
+
¿En qué sistemas puedo ejecutarlo?
+
+
La línea de comandos funciona en Windows y Linux, tanto en Intel como en ARM, y en Mac con Apple Silicon. La ventana de escritorio se entrega para Windows en Intel, Linux en Intel y Mac con Apple Silicon. Los Mac Intel no son compatibles y no se compila nada para ellos.
+
+
+
+
¿Tengo que instalar algo?
+
+
No. Descarga el archivo de tu sistema, descomprímelo y ejecuta el binario. No hay instalador, ni entorno de ejecución que añadir, ni dependencia que resolver. Si tienes Go, también sirve un único comando go install.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
¿Por qué una ejecución sobre miles de archivos es más lenta en Windows?
+
+
Porque Windows cobra más por cada ruta que mira, y un comando que recorre miles de archivos mira miles de rutas. Medido en una máquina con 3000 archivos de 1 kB, verify tarda unos 0,9 segundos en Windows y unos 0,2 segundos en Linux dentro de un contenedor. Una ruta de salida más corta reduce la cifra de Windows, porque cada carpeta por encima de los archivos forma parte de lo que se mira.
¿Pasa un archivo válido y tan pequeño como permite el formato?
+
+ El preset empty-and-minimal construye con un solo comando un conjunto entero de archivos de
+ prueba reales para esta pregunta, y un manifest.json a su lado que dice cómo debe
+ reaccionar tu sistema a cada archivo. Todo lo de abajo se lee del programa, con los valores por
+ defecto de esta versión.
+
+
+
+
+
¿Qué suele encontrar?
+
+
un archivo válido rechazado por ser demasiado pequeño, porque la comprobación cuenta bytes en lugar de leerlos
+
un archivo vacío que hace caer al lector en vez de ser notificado
+
una imagen de un píxel de ancho que divide entre cero de camino a la miniatura
+
un almacenamiento que lee cero bytes como una subida fallida y sigue reintentando
+
+
+
+
+
+
¿Qué hay en el conjunto?
+
Con sus valores por defecto, tal como lo informa tfg preset show empty-and-minimal:
¿Mi sistema guardará, mostrará y devolverá un nombre de archivo que no esperaba?
+
+ El preset filename-handling construye con un solo comando un conjunto entero de archivos de
+ prueba reales para esta pregunta, y un manifest.json a su lado que dice cómo debe
+ reaccionar tu sistema a cada archivo. Todo lo de abajo se lee del programa, con los valores por
+ defecto de esta versión.
+
+
+
+
+
¿Qué suele encontrar?
+
+
un nombre que parece otro en pantalla, en un registro o en una lista
+
un nombre cortado, recortado o reescrito entre la subida y el almacenamiento
+
un límite de longitud contado en caracteres donde el almacenamiento cuenta bytes
+
+
+
+
+
+
¿Qué hay en el conjunto?
+
Con sus valores por defecto, tal como lo informa tfg preset show filename-handling:
+
+
+
+
Archivos
50
+
Targets en su receta
50
+
Tamaño total
51 200 B
+
Formatos
txt
+
+
+
+
Y lo que el manifiesto de ese conjunto espera de tu sistema:
+
+
+
+
Esperado
Significado
Archivos
+
+
+
accept
Tu sistema debe aceptar el archivo.
4
+
unspecified
Depende de las reglas de tu sistema. Tú decides y después compruebas que lo que ocurre es lo que querías.
46
+
+
+
+
+
+
+
¿Qué puedes cambiar?
+
+
+
+
Ajuste
Admite
Por defecto
Qué hace
+
+
+
+
--format
+
un id de formato de la página de formatos
+
txt
+
El formato de cada archivo del conjunto. Es una opción de la propia herramienta, y el preset solo le da un valor por defecto.
+
+
+
+
+
+
+
+
¿Cómo se ejecuta?
+
Mira cuánto costaría el conjunto, constrúyelo o toma su receta para editarla:
Presets de archivos de prueba, un conjunto para cada pregunta de prueba
+
+ Un preset es un conjunto entero de archivos de prueba diseñado en torno a una pregunta, con un
+ manifiesto que dice cómo debe reaccionar tu sistema a cada archivo. Tú eliges la pregunta, la
+ herramienta construye el conjunto. Cada preset tiene su propia página con lo que suele encontrar,
+ qué hay en el conjunto y cada ajuste que admite.
+
¿Mi formulario de subida acepta lo que debe y rechaza el resto?
+
upload-validation
+
+
+
+
+
¿En qué se diferencia un preset de una receta?
+
+ Por debajo, en nada. Un preset es una receta que la herramienta escribe por ti a partir de unos
+ pocos ajustes. tfg preset eject imprime esa receta para que la guardes junto a tus
+ pruebas y la edites, y una receta tuya puede basarse en un preset con una línea, extends:
+ preset: seguido de su id.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
¿Puedo fiarme de los valores por defecto?
+
+ Para los archivos, sí. Para un número que solo conoce tu sistema, como el límite de un formulario de
+ subida, un valor por defecto es un marcador nuestro, y la herramienta lo dice cada vez que usa
+ uno. La página de cada preset marca esos ajustes, y tfg preset show lo dice antes
+ de escribir nada.
+
¿Se aplica un límite de tamaño exactamente donde se declara?
+
+ El preset size-boundaries construye con un solo comando un conjunto entero de archivos de
+ prueba reales para esta pregunta, y un manifest.json a su lado que dice cómo debe
+ reaccionar tu sistema a cada archivo. Todo lo de abajo se lee del programa, con los valores por
+ defecto de esta versión.
+
+
+
+
+
¿Qué suele encontrar?
+
+
errores de uno en el límite
+
MB confundido con MiB, que son un 4,8 por ciento y bastan para dejar pasar un archivo que no debería pasar
+
un límite aplicado en el navegador y no en el servidor
+
+
+
+
+
+
¿Qué hay en el conjunto?
+
Con sus valores por defecto, tal como lo informa tfg preset show size-boundaries:
+
+
+
+
Archivos
7
+
Targets en su receta
7
+
Tamaño total
73 400 320 B
+
Formatos
pdf
+
+
+
+
Y lo que el manifiesto de ese conjunto espera de tu sistema:
+
+
+
+
Esperado
Significado
Archivos
+
+
+
accept
Tu sistema debe aceptar el archivo.
4
+
reject
Tu sistema debe rechazar el archivo.
3
+
+
+
+
+
+
+
¿Qué puedes cambiar?
+
+
+
+
Ajuste
Admite
Por defecto
Qué hace
+
+
+
+
--limit
+
un tamaño como 2mb
+
10mb
+
El límite de tamaño que declara tu sistema. Todo lo demás se mide a partir de él. Este valor por defecto es nuestro marcador, no el valor de tu sistema. Pasa el tuyo.
+
+
+
--spread
+
tamaños separados por comas
+
1B,1kb,1mb
+
Hasta dónde llegar a cada lado del límite, como una lista de tamaños.
+
+
+
--format
+
un id de formato de la página de formatos
+
pdf
+
El formato de cada archivo del conjunto. Es una opción de la propia herramienta, y el preset solo le da un valor por defecto.
+
+
+
+
+
+
+
+
¿Cómo se ejecuta?
+
Mira cuánto costaría el conjunto, constrúyelo o toma su receta para editarla:
¿Sobrevive mi importación de tablas a lo que exportan las herramientas reales?
+
+ El preset tabular-import construye con un solo comando un conjunto entero de archivos de
+ prueba reales para esta pregunta, y un manifest.json a su lado que dice cómo debe
+ reaccionar tu sistema a cada archivo. Todo lo de abajo se lee del programa, con los valores por
+ defecto de esta versión.
+
+
+
+
+
¿Qué suele encontrar?
+
+
un archivo con punto y coma leído como una sola columna, porque el delimitador se supuso en lugar de buscarse
+
un archivo CRLF partido en filas con una fila vacía después de cada una
+
una tabla sin cabecera cuya primera fila de datos se come como nombres de columna
+
una importación que conserva las columnas que puede mostrar y descarta el resto sin decir nada
+
un lector que toma los registros JSON de uno en uno por línea y se detiene en el primer documento con sangría
+
+
+
+
+
+
¿Qué hay en el conjunto?
+
Con sus valores por defecto, tal como lo informa tfg preset show tabular-import:
+
+
+
+
Archivos
13
+
Targets en su receta
13
+
Tamaño total
3 080 060 B
+
Formatos
csv, json, xlsx
+
+
+
+
Y lo que el manifiesto de ese conjunto espera de tu sistema:
+
+
+
+
Esperado
Significado
Archivos
+
+
+
accept
Tu sistema debe aceptar el archivo.
8
+
unspecified
Depende de las reglas de tu sistema. Tú decides y después compruebas que lo que ocurre es lo que querías.
5
+
+
+
+
+
+
+
¿Qué puedes cambiar?
+
+
+
+
Ajuste
Admite
Por defecto
Qué hace
+
+
+
+
--rows
+
1 - 200000 filas
+
1000
+
Cuántas filas contiene la hoja de cálculo. Se escribe exactamente con el tamaño que ocupan tantas filas, así que el presupuesto de arriba se mueve con este valor.
+
+
+
--columns
+
1 - 32768 columnas
+
10
+
Cuántas columnas tiene cada fila de la hoja de cálculo. Filas por columnas tiene un techo, y pedir más se rechaza antes de escribir nada.
+
+
+
+
+
+
+
+
¿Cómo se ejecuta?
+
Mira cuánto costaría el conjunto, constrúyelo o toma su receta para editarla:
¿Sabe mi lector en qué codificación está un archivo, o lo adivina?
+
+ El preset text-encoding construye con un solo comando un conjunto entero de archivos de
+ prueba reales para esta pregunta, y un manifest.json a su lado que dice cómo debe
+ reaccionar tu sistema a cada archivo. Todo lo de abajo se lee del programa, con los valores por
+ defecto de esta versión.
+
+
+
+
+
¿Qué suele encontrar?
+
+
un lector que supone UTF-8 y muestra un archivo UTF-16 con un carácter de cada tres, o como filas de cuadros
+
una marca de orden de bytes leída como contenido, de modo que el primer campo de una importación empieza con tres caracteres extraños
+
un importador que adivina la codificación por los primeros bytes y adivina distinto con un archivo más largo
+
un archivo CRLF partido en filas con una fila vacía después de cada una, o un retorno de carro que queda dentro del último campo
+
+
+
+
+
+
¿Qué hay en el conjunto?
+
Con sus valores por defecto, tal como lo informa tfg preset show text-encoding:
+
+
+
+
Archivos
20
+
Targets en su receta
20
+
Tamaño total
81 920 B
+
Formatos
csv, log, md, txt, xml
+
+
+
+
Y lo que el manifiesto de ese conjunto espera de tu sistema:
+
+
+
+
Esperado
Significado
Archivos
+
+
+
accept
Tu sistema debe aceptar el archivo.
10
+
unspecified
Depende de las reglas de tu sistema. Tú decides y después compruebas que lo que ocurre es lo que querías.
10
+
+
+
+
+
+
+
¿Qué puedes cambiar?
+
+
+
+
Ajuste
Admite
Por defecto
Qué hace
+
+
+
+
--sample
+
un tamaño como 2mb
+
4kb
+
El tamaño de cada archivo del conjunto. UTF-16 guarda dos bytes por carácter, así que un número impar se rechaza.
+
+
+
+
+
+
+
+
¿Cómo se ejecuta?
+
Mira cuánto costaría el conjunto, constrúyelo o toma su receta para editarla:
¿Mi formulario de subida acepta lo que debe y rechaza el resto?
+
+ El preset upload-validation construye con un solo comando un conjunto entero de archivos de
+ prueba reales para esta pregunta, y un manifest.json a su lado que dice cómo debe
+ reaccionar tu sistema a cada archivo. Todo lo de abajo se lee del programa, con los valores por
+ defecto de esta versión.
+
+
+
+
+
¿Qué suele encontrar?
+
+
un límite aplicado en el navegador y no en el servidor
+
un SVG o un HTML tomado por una imagen o por texto plano, que es una forma de colar un script por un formulario
+
un archivo comprobado por su extensión y nunca abierto, de modo que un PDF llamado .jpg pasa
+
un formulario que lee todo el cuerpo en memoria antes de mirar su tamaño
+
una subida llamada PHOTO.JPG rechazada donde photo.jpg se acepta, o al revés
+
un nombre con espacios, paréntesis o caracteres fuera de ASCII escrito en disco sin cambios
+
+
+
+
+
+
¿Qué hay en el conjunto?
+
Con sus valores por defecto, tal como lo informa tfg preset show upload-validation:
+
+
+
+
Archivos
71
+
Targets en su receta
22
+
Tamaño total
120 639 488 B
+
Formatos
html, jpg, pdf, png, svg, txt
+
+
+
+
Y lo que el manifiesto de ese conjunto espera de tu sistema:
+
+
+
+
Esperado
Significado
Archivos
+
+
+
accept
Tu sistema debe aceptar el archivo.
56
+
reject
Tu sistema debe rechazar el archivo.
10
+
unspecified
Depende de las reglas de tu sistema. Tú decides y después compruebas que lo que ocurre es lo que querías.
5
+
+
+
+
+
+
+
¿Qué puedes cambiar?
+
+
+
+
Ajuste
Admite
Por defecto
Qué hace
+
+
+
+
--limit
+
un tamaño como 2mb
+
10mb
+
El límite de tamaño que declara tu formulario de subida. Este conjunto da un paso a cada lado - para un archivo a cada distancia, ejecuta el preset size-boundaries. Este valor por defecto es nuestro marcador, no el valor de tu sistema. Pasa el tuyo.
+
+
+
--allow
+
ids de formato separados por comas
+
jpg,png,pdf
+
Qué tipos debe aceptar tu formulario. Cada uno se convierte en un archivo real de ese tipo, y son el control positivo de todo el conjunto.
+
+
+
--deny
+
extensiones separadas por comas
+
svg,html,exe,sh
+
Qué extensiones debe rechazar tu formulario. Una extensión para la que esta versión no tiene formato recibe igualmente un archivo con ese nombre, con texto plano.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
Cuánto se pasa del límite el único archivo grande. Desactívalo donde escribir varias veces el límite no compense el disco.
+
+
+
--bulk
+
0 - 10000 archivos
+
50
+
Cuántos archivos contiene la subida masiva. Cero deja ese grupo fuera del conjunto por completo.
+
+
+
+
+
+
+
+
¿Cómo se ejecuta?
+
Mira cuánto costaría el conjunto, constrúyelo o toma su receta para editarla:
Can I generate a file that is deliberately broken?
-
Not yet. Damaged and malformed files are a planned feature. Today every file the tool writes is a valid one of its format.
+
Yes. Add --damage zero-head and the file comes out at exactly the size you asked for with its first bytes overwritten by zeros, so a reader turns it away, and the manifest says your system should reject it. The page about corrupt test files has the details.
{
"@type": "Question",
"name": "Can I generate a file that is deliberately broken?",
- "acceptedAnswer": { "@type": "Answer", "text": "Not yet. Damaged and malformed files are a planned feature. Today every file the tool writes is a valid one of its format." }
+ "acceptedAnswer": { "@type": "Answer", "text": "Yes. Add --damage zero-head and the file comes out at exactly the size you asked for with its first bytes overwritten by zeros, so a reader turns it away, and the manifest says your system should reject it. The page about corrupt test files has the details." }
},
{
"@type": "Question",
diff --git a/web/public/formats/index.html b/web/public/formats/index.html
index 5f467709..dc6cfb55 100644
--- a/web/public/formats/index.html
+++ b/web/public/formats/index.html
@@ -3,15 +3,36 @@
+
26 Supported File Formats - PDF, DOCX, PNG, ZIP and More
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -19,7 +40,27 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -68,9 +109,35 @@
Exact sizeFAQ
-
+ Cinq tâches qui reviennent dans presque tous les projets qui reçoivent des fichiers de la part de
+ personnes, et la commande qui fait chacune. Chaque exemple ci-dessous s'exécute tel qu'il est
+ écrit.
+
+
+
+
Limites d'envoi
+
Tester si une limite de taille de fichier est appliquée là où elle le dit
+
+ Une limite, ce sont trois cas de test, pas un : juste en dessous, pile dessus et juste
+ au-dessus. Les obtenir à la main revient à calculer des nombres d'octets en espérant ne pas
+ s'être trompé d'un. Demandez plutôt le jeu :
+
+ Vous obtenez trois vrais PDF de 1048575, 1048576 et 1048577 octets, et un manifeste qui dit que les
+ deux premiers doivent être acceptés et le troisième refusé pour size_limit. Votre
+ test lit l'attente au lieu que vous écriviez trois assertions à la main - et quand la limite
+ change, vous changez un nombre et relancez.
+
+
+ La même chose fonctionne sans préréglage quand vous voulez un seul jeu de limites en ligne :
+
+ De gros fixtures binaires rendent un dépôt lent à cloner et pénible à relire, et personne ne peut
+ dire ce qui a changé quand l'un est remplacé. Une recette, ce sont quelques centaines de
+ caractères de YAML qui reconstruisent les fichiers identiques - à l'octet près, sur
+ n'importe quelle machine - parce que chaque fichier est dérivé de la graine de
+ l'exécution.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Chaque fin a son propre code de sortie, si bien qu'un pipeline peut distinguer une mauvaise recette
+ d'un disque plein et d'une différence de vérification. Une exécution échouée n'écrit rien sur la
+ sortie standard, ce qui évite qu'un analyseur de journaux lise une erreur comme une donnée.
+
+
+
+
+
Volume
+
Découvrir ce qui se passe quand le dossier est gros
+
+ Les routines d'import, les tâches de nuit et les listages de répertoires se comportent autrement à
+ dix mille fichiers qu'à dix. Des tailles tirées dans une plage donnent au jeu l'allure d'un vrai
+ trafic plutôt que de dix mille fichiers identiques, et le tirage vient de la graine, donc le jeu
+ est le même demain.
+
+ Une exécution plus grande que l'espace libre du disque est refusée avant que le premier octet soit
+ écrit, au lieu de remplir le disque et d'échouer à mi-chemin.
+
+
+
+
+
Archives
+
Tester un décompresseur avec une archive qui contient vraiment des fichiers
+
+ Une archive vide avec la bonne extension ne prouve rien sur le code qui l'ouvre et parcourt ce
+ qu'elle contient. Déclarez le contenu et l'archive le contient vraiment :
+
+ La profondeur d'imbrication, le nombre d'entrées et la taille de ce qu'il y a dedans sont autant de
+ choses sur lesquelles une routine d'import a des opinions, et c'est ainsi que vous découvrez
+ lesquelles.
+
+
+
+
+
Analyseurs et visionneuses
+
Vérifier que votre propre code lit un format comme le fait un vrai logiciel
+
+ Chaque format ici est vérifié avec un lecteur indépendant avant la livraison - un PNG est ouvert et
+ ses pixels comparés, un DOCX est relu par des bibliothèques distinctes, une archive est
+ extraite. Cela signifie qu'un fichier que votre analyseur refuse est une trouvaille sur votre
+ analyseur, pas sur le générateur.
+
+ La page des formats liste les réglages que chacun accepte et le plus
+ petit fichier que chacun peut être.
+
+
+
+
+
Guides
+
Deux d'entre eux en détail
+
+
+ Fichiers de test corrompus - un fichier cassé
+ volontairement, à la taille exacte, avec dans le manifeste ce qui doit lui arriver.
+
+
+ Fichiers de test en CI - un workflow GitHub Actions, un
+ job GitLab et les codes de sortie qui font échouer un build.
+
+
+
+
+
+
À qui cela s'adresse
+
+ Les ingénieurs QA, l'automatisation de tests et tous ceux dont le code a derrière lui un formulaire
+ d'envoi, une routine d'import, un analyseur ou un quota de stockage. Il fonctionne sur une
+ machine sans aucun réseau, ce qui compte dans un environnement d'entreprise fermé où un
+ générateur dans le navigateur n'est pas une option.
+
+ Chaque système a une commande pour cela, et les trois sont ci-dessous. Elles donnent un fichier du
+ nombre d'octets exact - et pour beaucoup de tests, c'est tout ce qu'il faut. Chaque
+ commande de cette page a été exécutée avant publication, sur le système auquel elle
+ appartient.
+
+
+
+
La réponse courte
+
+ Windows : fsutil file createnew name 10485760. Linux : dd if=/dev/zero
+ of=name bs=1M count=10. macOS : mkfile 10m name. Les tailles sont en
+ octets, et 10 Mo comptés comme les compte votre gestionnaire de fichiers font 10485760 octets.
+
+
+
+
+
Windows
+
fsutil, et une version PowerShell qui n'a besoin de rien de plus
+
+ fsutil est fourni avec Windows. Il prend la taille en octets, calculez
+ donc le nombre d'abord - 10 Mo font 10485760, 100 Mo font 104857600, 1 Go fait 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Mesuré sous Windows 11 : cela fonctionne depuis une invite ordinaire sans exiger de droits
+ élevés, et le fichier fait exactement 10485760 octets.
+
+
PowerShell sait faire la même chose sans appeler un autre programme, et il comprend les unités :
+ 10MB en PowerShell signifie 10485760 octets, le même comptage par 1024 qu'utilise
+ l'Explorateur, donc les deux commandes ci-dessus produisent la même taille.
+
+
+
+
+
Linux
+
dd, truncate et fallocate, et la différence qui piège les gens
+
dd est celle que tout le monde connaît. Elle écrit vraiment les octets :
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate est instantané, et c'est là le piège. Mesuré sous Alpine Linux, le fichier
+ annonce 10485760 octets et occupe zéro bloc - c'est un fichier
+ creux. Tout ce qui le lit obtient dix mégaoctets de zéros, mais le disque n'a jamais
+ cédé la place :
+
+
truncate -s 10M test10mb.bin
+
+ C'est correct pour tester une limite d'envoi et trompeur pour tester un quota de disque.
+ fallocate est celui à choisir quand l'espace doit être réel :
+
+
fallocate -l 10M test10mb.bin
+
Et quand le contenu doit être incompressible, pour qu'un archiveur ne puisse pas le réduire à nouveau :
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, qui n'est pas creux, et les deux que vous connaissez déjà
+
+ macOS fournit mkfile. Mesuré sous macOS 26.6.2 : 10485760 octets et 20480 blocs,
+ donc l'espace est réellement alloué plutôt que promis :
+
+
mkfile 10m test10mb.bin
+
dd et truncate sont là aussi et se comportent comme sous Linux :
Un fichier de la bonne taille n'est pas un fichier du bon type
+
+ Tout ce qui précède donne un bloc de zéros. C'est suffisant quand ce qui est testé ne regarde que la
+ taille - une limite d'envoi, un quota, un transfert. Cela cesse de l'être dès que quelque chose
+ ouvre le fichier.
+
+
+ Mesuré, et cela vaut la peine de le faire vous-même : créez un fichier de 2 Mo avec
+ fsutil, appelez-le photo.png et donnez-le à une bibliothèque d'images.
+ Pillow répond cannot identify image file. Ce n'est pas un PNG. Cela n'en a jamais
+ été un - seul le nom le prétendait.
+
+
+ Cela compte plus qu'il n'y paraît, à cause de la façon dont le test échoue ensuite.
+ Votre point d'envoi refuse le fichier, votre test passe au vert et vous concluez que la limite
+ de taille fonctionne. Il ne l'a pas refusé pour sa taille. Il l'a refusé parce que les octets
+ n'étaient pas une image, et la règle que vous vouliez tester n'a jamais été atteinte.
+
+
+
un analyseur le refuse avant qu'aucune règle de taille ne soit examinée
+
une étape de miniature échoue et l'erreur que vous lisez concerne la miniature
+
un antivirus ou un contrôle de contenu le refuse pour une troisième raison
+
une visionneuse n'affiche rien, et personne ne peut dire si c'est le bogue
+
+
+
+
+
L'autre voie
+
Un vrai fichier de ce format, à la taille exacte que vous avez demandée
+
+ C'est ce que fait Testing Files Generator. Le fichier est un vrai fichier de son format - il s'ouvre
+ dans le logiciel qui lui correspond - et il fait le nombre d'octets exact que vous avez demandé,
+ à l'octet près :
+
+ Demandez une taille qu'un format ne peut pas atteindre et vous obtenez une erreur qui nomme le
+ plancher et sa raison, jamais un fichier de mauvaise taille. La page des
+ formats liste chaque format avec le plus petit fichier qu'il peut produire.
+
+
Et une limite, ce sont trois cas de test et non un, donc l'outil construit les trois :
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Cela donne 10485759, 10485760 et 10485761 octets, et un manifeste qui dit lesquels votre système
+ doit accepter et lesquels il doit refuser. La page des cas
+ d'usage passe en revue cela et quatre autres tâches pour lesquelles il est conçu.
+
Gratuit et open source, GPL-3.0. Aucune inscription. Les téléchargements Windows et macOS sont signés et démarrent sans avertissement.
+
+
+
+
Alors lequel utiliser ?
+
+
+
Utiliser la commande du système
+
+ Quand rien n'ouvre le fichier. Tester une limite de taille sur un point d'entrée qui vérifie d'abord
+ la taille, un transfert, un quota, un disque plein. C'est une ligne et c'est déjà installé.
+
+
+
+
Utiliser un vrai générateur
+
+ Quand quoi que ce soit analyse, affiche, importe ou extrait le fichier - et quand vous avez besoin
+ des mêmes fixtures demain, sur une autre machine, à l'octet près.
+
+
+
+
+ Les deux sont sur cette page parce que les deux sont justes une partie du temps. L'erreur à éviter
+ est d'utiliser la première là où il faut la seconde et de lire le test vert comme une preuve.
+
+ Tout ce que fait l'outil, rangé selon les questions avec lesquelles les gens arrivent vraiment. Le
+ README du dépôt est la référence complète et correspond toujours à
+ la version que vous avez téléchargée.
+
+
+
+
Quelles commandes existe-t-il ?
+
Chacune fait une seule chose :
+
tfg generate produire des fichiers, depuis une recette ou des options
+tfg validate vérifier une recette sans rien écrire
+tfg verify comparer un répertoire à un manifeste
+tfg cleanup supprimer les fichiers qu'un manifeste liste
+tfg recipe fmt afficher une recette sous sa forme normalisée
+tfg preset construire un jeu de fichiers à partir d'une question de test nommée
+tfg formats lister les formats pris en charge par cette version
+tfg damage lister les façons dont cette version peut abîmer un fichier exprès
+tfg tool de petits outils pour des fichiers que vous avez déjà
+tfg version afficher la version de l'outil
+tfg license afficher la licence et ce qu'elle implique pour les fichiers générés
+
+
+
+
Comment générer un seul fichier de taille exacte ?
+
+ Nommez le format, la taille et la destination. Les tailles se comptent par 1024, donc
+ 2mb font 2097152 octets. Un nombre d'octets brut fonctionne aussi, donc
+ --size 10485761 demande exactement ce nombre.
+
+
tfg generate --format png --size 2mb --out ./out
+
Les options utiles de generate :
+
+
+
Option
Ce qu'elle fait
+
+
--format <id>
format des fichiers, par exemple txt
+
--size <size>
taille exacte de chaque fichier, comme 10mb ou un nombre d'octets brut
+
--size-range <a-b>
une taille tirée par fichier dans une plage, comme 1kb-8kb. Le tirage vient de la graine
+
--boundary <size>
trois fichiers autour d'une limite : un octet en dessous, la limite, un octet au-dessus
+
--count <n>
combien de fichiers produire. Par défaut 1
+
--name <template>
modèle de nom, par exemple invoice_{index:04}.txt
+
--out <dir>
répertoire où écrire
+
--seed <n>
graine de l'exécution. La même graine donne les mêmes octets
+
--set <k>=<v>
un réglage de format, répétable
+
--damage <name>
abîmer les fichiers exprès, répétable et appliqué dans l'ordre. Lancez tfg damage pour la liste
+
--expected <outcome>
accept, reject, sanitize ou unspecified
+
--dry-run
compter et montrer, sans rien écrire du tout
+
--json
écrire le manifeste sur la sortie standard
+
+
+
+
+
+
+
Comment fabriquer un fichier volontairement cassé ?
+
+ Tout autre fichier écrit par cet outil est correct par construction, ce qui répond à deux des trois
+ questions que pose un validateur d'envoi. --damage répond à la troisième - le
+ fichier s'ouvre-t-il seulement. Le fichier est produit normalement puis abîmé, il garde donc la
+ taille demandée.
+
+ Les réglages se placent après deux-points. L'option se répète, et l'ordre dans lequel vous les
+ écrivez est l'ordre dans lequel ils sont appliqués. tfg damage liste ce que cette
+ version sait faire et ce que chacun accepte.
+
+
Dans une recette, la clé est une liste, de noms ou de réglages :
+ Un fichier abîmé reçoit expected: reject dans le manifeste, avec l'altération notée à
+ côté. Deux choses sont refusées avant que rien ne soit écrit, car chacune mettrait sinon sur le
+ disque un fichier que le manifeste décrit à tort :
+
+
+
un fichier plus petit que ce dont l'altération a besoin, car il ressortirait inchangé
+
+ expected: accept à côté d'une altération, car rien ne pourrait y répondre. Écrivez
+ sanitize si le système testé doit réparer le fichier, ou unspecified
+ si c'est justement la question que vous posez
+
+
+
+ Une troisième ne peut pas être connue à l'avance. Si une altération s'exécute sans déplacer un seul
+ octet, ce fichier est abandonné plutôt qu'écrit - l'exécution continue, dit de quel fichier il
+ s'agissait et se termine avec le code de sortie partiel.
+
+ Une recette est un fichier YAML qui décrit toute une exécution. Commitez-la à côté de vos tests et
+ les fixtures cessent d'être des binaires dans votre dépôt - n'importe qui peut les reconstruire,
+ à l'octet près, à partir d'un fichier de quelques centaines de caractères.
+
+ Chaque cible exige exactement une de ces clés : size, size-range,
+ boundary ou contains. Deux est une erreur, et aucune aussi. Une
+ recette invalide n'écrit aucun fichier et signale tous les problèmes d'un coup
+ plutôt que le premier seulement, chacun nommant le réglage concerné.
+
+
+
+
+
Comment déclarer ce que mon système doit faire d'un fichier ?
+
Forme courte quand le résultat suffit, forme longue quand la raison compte :
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Les résultats sont accept, reject, sanitize et
+ unspecified. Les raisons forment une liste fermée pour qu'un rapport puisse les
+ regrouper : content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit et
+ size_zero.
+
+
+ Une raison nomme la règle en jeu, pas le verdict. C'est pourquoi la même raison
+ peut se trouver sous l'un ou l'autre résultat - un fichier un octet sous une limite est
+ accept, et la règle concernée reste size_limit.
+
+
+
+
+
Que contient le manifeste ?
+
+ Il est écrit à côté des fichiers à la fin de chaque exécution, y compris d'une exécution
+ interrompue. Une entrée par fichier :
+
+ Un recipe_hash est ajouté quand l'exécution vient d'une recette, et preset
+ avec overrides quand elle vient d'un préréglage, de sorte qu'un manifeste peut
+ toujours être rattaché à ce qui l'a produit.
+
+
+ Chaque entrée porte aussi target_id, l'identifiant de la cible de la recette qui a
+ produit le fichier, et summary.by_target compte les fichiers de chaque cible. Une
+ recette à plusieurs cibles peut donc être vérifiée cible par cible sans lire les noms de
+ fichiers.
+
+
+
+
+
Qu'est-ce qu'un préréglage ?
+
+ Un jeu de fichiers prêt à l'emploi qui répond à une question de test courante, pour que vous n'ayez
+ pas à concevoir le jeu vous-même. Les préréglages sont des recettes ordinaires en dessous, et
+ eject affiche la recette pour que vous puissiez la modifier. Chaque préréglage a
+ sa propre page qui dit ce qu'il trouve d'habitude, ce que
+ contient le jeu et chaque réglage qu'il accepte.
+
+ show vous dit ce que coûterait le jeu avant que vous ne le construisiez, et dit
+ franchement quand un nombre est un substitut de notre part plutôt qu'une limite de la vôtre.
+
+
+
+
+
Que signifient les codes de sortie ?
+
+ Chaque fin a son propre code, la sortie lisible par machine va sur la sortie standard, et une
+ exécution échouée n'y écrit rien. Le tableau est un contrat figé - changer le sens d'un code
+ exige une version majeure.
+
+
+
+
+
+
Code
+
Signification
+
+
+
+
+
0
+
Tout a fonctionné.
+
+
+
1
+
Une erreur inattendue dans l'outil.
+
+
+
2
+
Commande ou option incorrecte.
+
+
+
3
+
La recette n'est pas valide.
+
+
+
4
+
Le format ne peut pas faire ce qui était demandé.
+
+
+
5
+
Une lecture ou une écriture a échoué.
+
+
+
6
+
Espace disque insuffisant.
+
+
+
7
+
verify a trouvé une différence.
+
+
+
8
+
L'exécution s'est terminée mais tout n'a pas été produit.
+
+
+
130
+
Interrompu avec Ctrl+C.
+
+
+
143
+
Arrêté par un signal, ce qui ressemble à un délai dépassé en CI.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Une exécution arrêtée avec Ctrl+C laisse quand même un manifeste et ne laisse jamais de fichier à
+ moitié écrit, si bien qu'une tâche annulée peut encore être nettoyée par la suivante.
+
+ Oui, le même moteur avec une fenêtre, pour les tests qui ne sont pas scriptés. Ce n'est pas une
+ version amputée : un test compare les deux interfaces fonctionnalité par fonctionnalité, et
+ tout ce que seule l'une peut faire doit être déclaré et justifié au lieu de diverger
+ discrètement.
+
+
+ Les écrans sont un lot, les préréglages, plusieurs lots à la fois et À propos. Elle montre ce que
+ coûterait une exécution avant d'écrire quoi que ce soit, indique la progression pendant
+ l'exécution et peut être annulée en cours de route sans laisser de fichier à moitié écrit. Elle
+ n'ouvre pas encore de fichier de recette - les recettes sont pour l'instant une affaire de ligne
+ de commande, et la fenêtre construit ses lots dans le formulaire.
+
+ Licence, vie privée, reproductibilité et ce que les gens vérifient avant de mettre un générateur
+ dans un pipeline de build. Si votre question n'est pas ici, le suivi
+ des tickets est ouvert.
+
+
+
+
+
En quoi est-ce différent de dd, fsutil ou truncate ?
+
+
Ces commandes donnent un fichier de la bonne taille rempli de rien. Un fichier de 2 Mo nommé photo.png fabriqué ainsi n'est pas un PNG, donc tout ce qui l'analyse vraiment le refuse pour la mauvaise raison, et votre test réussit alors lui aussi pour la mauvaise raison. Cet outil produit un vrai PNG d'exactement 2 Mo, qui s'ouvre dans une visionneuse d'images, accompagné d'une déclaration sur la façon dont votre système doit le traiter.
Est-ce gratuit, et puis-je l'utiliser au travail ?
+
+
Oui aux deux. Il est publié sous GPL-3.0 et ne coûte rien. Il n'y a ni compte, ni clé de licence, ni offre payante.
+
+
+
+
Puis-je utiliser les fichiers générés dans un produit propriétaire ?
+
+
Oui. La licence couvre le code de l'outil, pas ce qu'il produit. Les fichiers, recettes et manifestes générés sont une sortie et non des œuvres dérivées, vous pouvez donc les commiter et les livrer sans aucune obligation.
+
+
+
+
Les fichiers générés contiennent-ils de vraies données personnelles ?
+
+
Non. Tout ce qu'ils contiennent est synthétisé à partir d'une graine. Aucun jeu de données n'est lu, aucun service n'est contacté et aucun contenu tiers n'est intégré. Considérez une adresse e-mail générée comme inutilisable plutôt que comme inutilisée, car n'importe quelle chaîne aléatoire peut coïncider par hasard avec une vraie.
+
+
+
+
Obtiendrai-je exactement les mêmes fichiers sur une autre machine ?
+
+
Oui, à l'octet près, avec la même recette et la même graine. Le projet le teste à chaque modification, et le casser exige un changement de version majeure. C'est ce qui vous permet de commiter une petite recette plutôt que de gros fixtures binaires.
+
+
+
+
Faut-il une connexion internet ?
+
+
Jamais. Il n'y a ni télémétrie, ni vérification de mises à jour, ni client cloud, et le binaire en ligne de commande n'a aucune pile réseau compilée dedans. Il fonctionne sur une machine sans réseau et dans un environnement d'entreprise fermé.
+
+
+
+
Que se passe-t-il si je demande une taille qu'un format ne peut pas atteindre ?
+
+
Vous obtenez une erreur qui nomme le format, la taille minimale possible, la raison de ce plancher et ce qu'il faut faire à la place, et aucun fichier n'est écrit. L'outil n'arrondit jamais une taille en silence. Chaque plancher est listé sur la page des formats.
+
tfg formats png
+
+
+
+
Puis-je générer un fichier volontairement cassé ?
+
+
Oui. Ajoutez --damage zero-head et le fichier sort à la taille exacte demandée, avec ses premiers octets écrasés par des zéros, si bien qu'un lecteur le refuse, et le manifeste dit que votre système doit le rejeter. La page sur les fichiers de test corrompus donne le détail.
7z, mp3 et mp4. 26 formats fonctionnent de bout en bout aujourd'hui.
+
+
+
+
Sur quels systèmes puis-je l'exécuter ?
+
+
La ligne de commande fonctionne sous Windows et Linux, sur Intel comme sur ARM, et sur les Mac Apple silicon. La fenêtre de bureau est fournie pour Windows sur Intel, Linux sur Intel et les Mac Apple silicon. Les Mac Intel ne sont pas pris en charge et rien n'est construit pour eux.
+
+
+
+
Dois-je installer quelque chose ?
+
+
Non. Téléchargez l'archive de votre système, décompressez-la et lancez le binaire. Il n'y a pas d'installateur, pas d'environnement d'exécution à ajouter et pas de dépendance à résoudre. Si vous avez Go, une seule commande go install fonctionne aussi.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
Pourquoi une exécution sur des milliers de fichiers est-elle plus lente sous Windows ?
+
+
Parce que Windows facture plus cher chaque chemin qu'il examine, et une commande qui parcourt des milliers de fichiers examine des milliers de chemins. Mesuré sur une machine avec 3000 fichiers de 1 ko, verify prend environ 0,9 seconde sous Windows et environ 0,2 seconde sous Linux dans un conteneur. Un chemin de sortie plus court réduit le chiffre de Windows, car chaque dossier au-dessus des fichiers fait partie de ce qui est examiné.
+
+
+
+
+
+
+
Encore indécis ?
+
+ La page des cas d'usage montre les tâches pour lesquelles il est
+ conçu, et la page des formats liste chaque format avec le plus petit
+ fichier qu'il peut produire. Le README du dépôt est la référence
+ complète.
+
Comment fabriquer un fichier corrompu pour les tests
+
+ Un validateur à qui l'on n'a jamais montré que des fichiers sains n'a pas vraiment été testé. Voici
+ comment obtenir un fichier cassé volontairement, qui sort à exactement la taille
+ demandée et qui porte un manifeste disant ce que votre système doit en faire.
+
+
+
+
La réponse courte
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out écrit un PNG
+ d'exactement 2097152 octets dont les premiers octets sont des zéros, et le manifeste à côté note
+ que votre système doit le rejeter.
+
+
+
+
+
La méthode habituelle
+
Pourquoi un fichier corrompu à la main fait un mauvais test
+
+ Les moyens habituels sont un éditeur hexadécimal, un script qui inverse quelques octets au hasard,
+ ou un fichier raccourci avec head ou truncate. Ça marche une fois,
+ puis ça coûte :
+
+
+
+ C'est différent à chaque fois. Un octet tiré au hasard tombe ailleurs à chaque
+ exécution, donc un échec du mardi peut ne pas revenir le mercredi.
+
+
+ Ça change la taille. Un fichier coupé est plus petit que la limite sous laquelle il
+ devait se trouver, si bien que le contrôle de taille répond avant le contrôle du contenu et
+ que le test passe pour la mauvaise raison.
+
+
+ Ça passe souvent inaperçu. Un texte brut reste lisible avec un octet modifié au
+ milieu, et un lecteur d'images indulgent le dessine simplement, de sorte que le fichier censé
+ être cassé est accepté.
+
+
+ Ça ne dit rien de ce qui doit se passer. Le fichier n'est que des octets, et celui
+ qui lira le test ensuite doit deviner si l'acceptation ou le rejet était voulu.
+
+
+
+
+
+
Ce que vous obtenez
+
Un fichier abîmé garde la taille demandée
+
+ Le fichier est généré normalement puis cassé, en route vers le disque. Il garde la taille demandée,
+ et la même commande écrit de nouveau les mêmes octets.
+
+ Les réglages se placent après deux-points. L'option peut être répétée, et les dommages s'appliquent
+ dans l'ordre où vous les écrivez. Ça marche avec chacun des 26 formats.
+
+
+
+
+
Ce qu'il sait faire
+
Quels dommages existe-t-il ?
+
+ Voici la liste que le programme affiche, lue dans le programme au moment de construire cette page.
+ tfg damage affiche la même, et tfg damage <id> dit ce que prend
+ l'un d'eux.
+
+
+
+
+
+
Dommage
+
Ce qu'il fait aux octets
+
Plus petit fichier
+
Réglages
+
+
+
+
+
zero-head
+
Écrase les premiers octets du fichier avec des zéros, sans toucher à sa longueur. La plupart des lecteurs regardent d'abord là, donc presque tout remarque ce dommage.
+
8
+
bytes
+
+
+
+
+
+ zero-head écrit des zéros sur le début du fichier. La plupart des lecteurs regardent
+ d'abord là, la signature et l'en-tête qui disent ce qu'est le fichier, donc presque tout lecteur
+ le remarque. Le texte brut et les journaux n'ont pas de signature et sont refusés eux aussi, car
+ une suite d'octets nuls n'est pas du texte. En dessous de quatre octets, certains formats
+ sortent avec un dommage dont aucun lecteur ne se plaint, c'est pourquoi le réglage commence à
+ quatre.
+
+
+
+
+
Ce que dit le manifeste
+
Un manifeste qui dit ce qui doit se passer
+
+ Chaque fichier abîmé reçoit une entrée disant que votre système doit le rejeter, avec le dommage
+ noté à côté :
+
+ Deux demandes sont refusées avant que rien ne soit écrit, car chacune laisserait sur le disque un
+ fichier que le manifeste décrit mal :
+
+
+
un fichier plus petit que ce dont le dommage a besoin, qui sortirait intact
+
+ expected: accept à côté d'un dommage, car rien ne pourrait le satisfaire. Écrivez
+ sanitize si votre système doit réparer le fichier, ou unspecified si
+ c'est justement la question que vous posez
+
+
+
+
+
+
Dans une recette
+
Fichiers sains et cassés dans une même exécution
+
+ Mettez les deux dans une seule recette, et le manifeste porte l'attente de chaque fichier, de sorte
+ que le test n'a pas besoin d'une liste disant lequel est lequel :
+
+ Le test lit le manifeste et vérifie que ce qui s'est passé est ce qui a été déclaré. Il n'a pas
+ besoin d'une liste de noms de fichiers :
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Un bon refus est un refus net. Un message qui dit ce qui n'allait pas est la réponse voulue. Une
+ erreur serveur, un blocage ou un fichier à moitié enregistré est le défaut que ce test existe
+ pour trouver.
+
+
+
+
+
Suite
+
Où aller ensuite
+
+
+ Le preset upload-validation pose à un formulaire
+ les deux autres questions, celle de la taille et celle du type.
+
Comment générer des fichiers de test dans un pipeline CI
+
+ Une fixture binaire dans un dépôt reste à jamais dans son historique, ne se relit pas dans un diff
+ et devient impossible dès que le fichier est gros. Générez plutôt les fichiers dans le pipeline à
+ partir d'une recette. La recette est du texte, les octets sortent identiques à chaque fois, et une
+ dernière étape prouve que rien n'a bougé.
+
+
+
+
La réponse courte
+
+ Installez tfg, lancez tfg generate fixtures.yaml --out ./fixtures avant
+ les tests et tfg verify ./fixtures/manifest.json après. Les deux étapes font
+ échouer le build d'elles-mêmes, avec un code de sortie qui dit pourquoi.
+
+
+
+
+
Pourquoi ne pas les commiter
+
Pourquoi une fixture ne doit pas vivre dans le dépôt
+
+
+ Elle reste dans l'historique. Supprimer un binaire plus tard ne rend pas un clone
+ plus petit, car chacune de ses versions est toujours là.
+
+
+ Un diff ne montre pas ce qui a changé. Le relecteur voit qu'un PDF est différent,
+ et rien de plus. Une recette change d'une ligne.
+
+
+ Les gros fichiers ne tiennent pas. GitHub refuse un push qui contient un fichier de
+ plus de 100 Mo, donc un test d'une limite d'envoi de 500 Mo n'a rien à commiter.
+
+
+
+ C'est la recette qu'il faut commiter. La même recette et la même graine écrivent les mêmes octets
+ sur toute machine, donc le fichier généré dans le pipeline est celui que vous aviez sur votre
+ portable.
+
+
+
+
+
La recette
+
Une recette qui vit à côté des tests
+
+ Celle-ci écrit vingt-cinq factures qui doivent être acceptées et deux images au-dessus d'une limite
+ qui doivent être refusées, et le manifeste note les deux attentes :
+
+ La ligne de somme de contrôle compare l'archive à verify-SHA256SUMS.txt de la même
+ version. La version est épinglée, donc une nouvelle version ne change jamais un build que vous
+ n'avez pas touché.
+
+ Chaque fin a son propre code de sortie, donc l'étape échoue d'elle-même et le journal dit lequel.
+ Ceux que rencontre un pipeline :
+
+
+
3 - la recette n'est pas valide. Rien n'a été écrit, et chaque problème est nommé
+
4 - le format ne sait pas faire ce qui a été demandé, par exemple une taille sous son minimum
+
6 - il n'y a pas assez d'espace disque
+
7 - tfg verify a trouvé un fichier qui ne correspond pas à son manifeste
+
8 - l'exécution est terminée, mais tout n'a pas été produit
+
+
+ Une exécution échouée n'écrit rien sur la sortie standard, donc un analyseur de journaux ne prend
+ jamais une erreur pour des données. Le tableau complet est sur
+ la page de documentation.
+
+
+
+
+
PowerShell
+
Un script PowerShell demande une ligne de plus
+
+ PowerShell ne fait pas sortir le code de sortie d'un programme d'un fichier .ps1.
+ Lancez-en un avec -File et le script répond 0 même quand l'outil à
+ l'intérieur a refusé le travail, si bien qu'un build qui devrait être rouge passe au vert. La
+ dernière ligne est toute la correction :
+
+ C'est ainsi que se comporte PowerShell, pas une particularité de cet outil. cmd,
+ bash et zsh n'ont besoin de rien de plus.
+
+
+
+
+
Plusieurs jobs
+
Partager les fixtures entre les jobs
+
+ Il n'y a généralement pas besoin de les envoyer. Comme la même recette écrit les mêmes octets,
+ chaque job peut lancer son propre tfg generate, ce qui est plus rapide qu'un envoi
+ suivi d'un téléchargement. Quand un job doit recevoir des fichiers d'un autre, lancez tfg
+ verify sur le manifeste après le transfert, et il dit si ce qui est arrivé est ce qui a
+ été écrit.
+
26 formats de fichiers, chacun généré à une taille exacte
+
+ Chacun est un vrai fichier de ce format. Il s'ouvre dans le logiciel qui lui
+ correspond et fait exactement le nombre d'octets que vous avez demandé. Aucun n'est du remplissage
+ de zéros avec une extension collée dessus.
+
+
+
+
+
+
+
Format
+
Nom
+
Extension
+
Plus petit fichier
+
Fidélité
+
Vérifié avec
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
sans objet
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
sans objet
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
sans objet
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
Ce que signifient les colonnes
+
+
+
Plus petit fichier
+
+ Le moins d'octets que cet outil accepte pour ce format, y compris l'étiquette qu'il écrit dans le
+ fichier. Demandez moins et vous obtenez une erreur qui nomme le plancher et sa raison,
+ jamais un fichier de mauvaise taille.
+
+
+
+
Fidélité
+
+ À quel point le fichier est complet. full signifie qu'un lecteur qui analyse vraiment
+ le format l'accepte, et pas seulement que l'extension correspond.
+
+
+
+
Vérifié avec
+
+ Le lecteur indépendant qui ouvre chaque fichier généré avant la livraison du format - une
+ implémentation distincte, pas notre propre code qui corrige ses propres devoirs.
+
+
+
+
+ Chaque format se répète aussi à l'octet près : la même recette et la même graine produisent des
+ fichiers identiques sur n'importe quelle machine, ce qui rend une recette sûre à commiter à la
+ place des fixtures elles-mêmes.
+
+
+
+
+
Réglages que chaque format accepte
+
+ La plupart des formats ont des réglages propres - dimensions d'image, qualité JPEG, nombre de pages
+ PDF, lignes et colonnes d'un tableur, nombre d'entrées dans une archive. Définissez-les avec
+ --set key=value en ligne de commande, ou sous properties: dans une
+ recette.
+
une date comme 2024-02-29 ou 2024-02-29T13:45:00+02:00, ou none
+
+
+
+
modified
+
une date comme 2024-02-29 ou 2024-02-29T13:45:00+02:00, ou none
+
+
+
png
+
width
+
1 - 20000 pixels
+
+
+
+
height
+
1 - 20000 pixels
+
+
+
pptx
+
slides
+
1 - 500 diapositives
+
+
+
svg
+
width
+
1 - 20000 pixels
+
+
+
+
height
+
1 - 20000 pixels
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
l'identifiant d'un format, comme le liste tfg formats
+
+
+
+
entry_size
+
une taille comme 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
vrai ou faux
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 pixels
+
+
+
+
height
+
1 - 20000 pixels
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
vrai ou faux
+
+
+
wav
+
sample_rate
+
8000 - 192000 hertz
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 pixels
+
+
+
+
height
+
1 - 16383 pixels
+
+
+
xlsx
+
rows
+
1 - 200000 lignes
+
+
+
+
columns
+
1 - 32768 colonnes
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
vrai ou faux
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
l'identifiant d'un format, comme le liste tfg formats
+
+
+
+
entry_size
+
une taille comme 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
vrai ou faux
+
+
+
+
password
+
le mot de passe, en clair
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ Une valeur hors de ce qu'un réglage accepte est refusée avec un message qui nomme le réglage, la
+ plage autorisée et quoi utiliser à la place. Un réglage inconnu est aussi une erreur, jamais une
+ valeur par défaut silencieuse - une faute de frappe acceptée en silence donne un fichier aux
+ mauvais réglages et une heure à se demander pourquoi le test passe alors qu'il ne devrait pas.
+
+
+ Lancez tfg formats <id> pour voir exactement ce qu'un format accepte dans la
+ version que vous avez.
+
+
+
+
+
Les archives contiennent de vrais fichiers
+
+ targz et zip
+ peuvent être remplis d'entrées plutôt que laissés en coquille vide. Une archive générée contient
+ réellement les documents qu'elle prétend contenir, si bien que tout ce qui la décompresse
+ pendant un test y trouve de vrais fichiers.
+
Générez de vrais fichiers de test à la taille exacte
+
+ PDF, PNG, DOCX, ZIP - 26 formats au total, et chacun est un
+ vrai fichier qui s'ouvre dans le logiciel qui lui correspond, à la taille exacte que
+ vous avez demandée. Chaque exécution note aussi ce que votre application doit faire de
+ chaque fichier. Ligne de commande et fenêtre de bureau, gratuit et open source, entièrement sur
+ votre machine.
+
Gratuit et open source, GPL-3.0. Aucune inscription. Les téléchargements Windows et macOS sont signés et démarrent sans avertissement.
+
+
+
+
+ La fenêtre de bureau, prête à écrire un lot de fichiers. Le même moteur fonctionne derrière la ligne de commande.
+
+
+
+
+
+ 26
+
vrais formats, chacun s'ouvrant dans le logiciel qui lui correspond
+
+
+ 1 octet
+
la précision de chaque taille demandée, jamais arrondie en silence
+
+
+ 0
+
connexions vers où que ce soit - pas de compte, pas de télémétrie, pas de vérification de mises à jour
+
+
+
+
+
Le problème
+
Fabriquer un fichier de test est facile. Fabriquer les mille bons est la partie fastidieuse
+
Vous testez un logiciel qui reçoit des fichiers de la part de personnes. Tôt ou tard, il vous faut :
+
+
un PDF de exactement 10 Mo, pour savoir si la limite d'envoi est réelle
+
les trois fichiers de part et d'autre de cette limite, pour attraper les erreurs d'un
+
10 000 fichiers journaux, pour voir ce que fait la tâche de nuit quand le dossier est gros
+
un ZIP qui contient vraiment 200 documents, pas une coquille vide avec la bonne extension
+
un fichier de 4 Go, sans garder un fichier de 4 Go dans votre dépôt
+
les mêmes fixtures sur votre portable et sur le serveur de build, à l'octet près
+
+
+ C'est ce que cela remplace. C'est conçu pour les ingénieurs QA, l'automatisation de tests et tous
+ ceux dont le code a derrière lui un formulaire d'envoi, une routine d'import, un analyseur ou un
+ quota de stockage.
+
+
+
+
+
Ce qui le distingue
+
Les autres générateurs s'arrêtent aux octets. Celui-ci répond à ce que votre test demande vraiment
+
+ Un dossier de fichiers vous laisse encore décider ce que chacun est censé prouver. Chaque exécution
+ écrit ici un manifest.json à côté des fichiers - une simple liste de tout ce qui a
+ été produit et, pour chaque entrée, une attente déclarée.
+
+
Admettons que votre point d'envoi accepte 1 Mo. Demandez les trois fichiers situés sur cette ligne :
Trois fichiers, trois réponses différentes, sous forme lisible par machine. Votre test lit le manifeste au lieu que vous écriviez les assertions à la main :
Quand la réponse dépend de votre propre politique, le manifeste le dit
+
+ Il consigne unspecified plutôt que d'inventer une attente. Un générateur qui devine
+ produit de faux échecs, et une suite qui crie au loup finit par être désactivée.
+
+
+
+
+
+
Préréglages
+
Choisissez la question, obtenez tout le jeu
+
+ Un préréglage est un jeu de fichiers de test conçu autour d'une question de test, pour que vous
+ n'ayez pas à chercher quels fichiers prouvent quoi. Chacun a une page qui dit ce qu'il trouve
+ d'habitude, ce que contient le jeu et chaque réglage qu'il accepte.
+
+ Dix mille fichiers journaux, chacun entre un et huit kilooctets, avec des tailles tirées de la
+ graine pour que demain donne le même jeu. Donnez à chaque exécution son propre
+ répertoire - le manifeste est la seule trace de ce qu'une exécution a écrit, donc
+ l'outil refuse d'en écrire un second par-dessus :
+
+ Les tailles se comptent par 1024, comme le fait votre gestionnaire de fichiers, donc
+ 2mb signifie 2097152 octets. Un nombre d'octets brut fonctionne aussi. La
+ documentation couvre les recettes, le manifeste et les codes de
+ sortie.
+
+
+
+
+
Ce que vous obtenez
+
Conçu pour une suite qui tourne sans surveillance
+
+
+
Taille exacte, à l'octet près
+
Demandez 10485761 octets et obtenez exactement cela. Une taille qu'un format ne peut pas atteindre est une erreur avec une raison, jamais un fichier de mauvaise taille.
+
+
+
26 vrais formats
+
Pas des zéros de remplissage avec une extension. Un PNG généré s'ouvre dans une visionneuse d'images, un DOCX s'ouvre dans Word, un ZIP se décompresse. Chacun est vérifié avec des lecteurs indépendants avant d'être livré.
+
+
+
Un manifeste qui fait office d'oracle de test
+
Chemin, taille, SHA-256, format, graine, version de l'outil - et ce que votre système doit faire du fichier.
+
+
+
Reproductible
+
Même recette et même graine, mêmes octets, sur n'importe quelle machine. Commitez une petite recette YAML plutôt que de gros fixtures binaires.
+
+
+
Deux interfaces, un seul moteur
+
Une ligne de commande conçue pour la CI et une fenêtre de bureau pour les tests exploratoires. Aucune n'est une version amputée de l'autre, et un test les compare fonctionnalité par fonctionnalité.
+
+
+
Entièrement hors ligne
+
Pas de compte, pas de cloud, pas de télémétrie, pas de vérification de mises à jour. Le binaire en ligne de commande n'a aucune pile réseau compilée dedans.
+
+
+
+
+
+
Téléchargement
+
Choisissez la version pour votre système
+
+ Décompressez l'archive et lancez-la. tfg est la ligne de commande et
+ tfg-gui est la fenêtre de bureau. Il n'y a pas d'installateur et rien à ajouter à
+ votre machine.
+
+
+
+
+
+
Système
+
Ligne de commande
+
Fenêtre de bureau
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
Ce qui est signé, et ce qui ne l'est pas
+
+ Les téléchargements Windows et macOS sont signés, ils démarrent donc sans avertissement sur un
+ développeur inconnu. Ceux de Linux ne le sont pas, car Linux de bureau n'a pas d'équivalent
+ pour les signer. Chaque archive est listée dans verify-SHA256SUMS.txt sur la page
+ des versions, pour que vous puissiez vérifier ce que vous avez téléchargé.
+
Un fichier valide et aussi petit que le format le permet passe-t-il ?
+
+ Le préréglage empty-and-minimal construit en une commande tout un jeu de vrais fichiers de test
+ pour cette question, avec un manifest.json à côté qui dit comment votre système doit
+ réagir à chaque fichier. Tout ce qui suit est lu depuis le programme, aux valeurs par défaut de
+ cette version.
+
+
+
+
+
Que trouve-t-il d'habitude ?
+
+
un fichier valide refusé parce que trop petit, quand le contrôle compte les octets au lieu de les lire
+
un fichier vide qui fait tomber le lecteur au lieu d'être signalé
+
une image d'un pixel de large qui divise par zéro en route vers la miniature
+
un stockage qui lit zéro octet comme un envoi échoué et recommence sans fin
+
+
+
+
+
+
Que contient le jeu ?
+
Aux valeurs par défaut, comme le rapporte tfg preset show empty-and-minimal :
Mon système va-t-il stocker, afficher et restituer un nom de fichier auquel il ne s'attendait pas ?
+
+ Le préréglage filename-handling construit en une commande tout un jeu de vrais fichiers de test
+ pour cette question, avec un manifest.json à côté qui dit comment votre système doit
+ réagir à chaque fichier. Tout ce qui suit est lu depuis le programme, aux valeurs par défaut de
+ cette version.
+
+
+
+
+
Que trouve-t-il d'habitude ?
+
+
un nom qui ressemble à un autre à l'écran, dans un journal ou dans une liste
+
un nom coupé, rogné ou réécrit entre l'envoi et le stockage
+
une limite de longueur comptée en caractères là où le stockage compte en octets
+
+
+
+
+
+
Que contient le jeu ?
+
Aux valeurs par défaut, comme le rapporte tfg preset show filename-handling :
+
+
+
+
Fichiers
50
+
Cibles dans sa recette
50
+
Taille totale
51 200 B
+
Formats
txt
+
+
+
+
Et ce que le manifeste de ce jeu attend de votre système :
+
+
+
+
Attendu
Signification
Fichiers
+
+
+
accept
Votre système doit accepter le fichier.
4
+
unspecified
Cela dépend des règles de votre système. Vous décidez, puis vous vérifiez que ce qui se passe est ce que vous aviez voulu.
46
+
+
+
+
+
+
+
Que pouvez-vous modifier ?
+
+
+
+
Réglage
Accepte
Par défaut
Ce qu'il fait
+
+
+
+
--format
+
un identifiant de format de la page des formats
+
txt
+
Le format de chaque fichier du jeu. C'est une option de l'outil lui-même, et le préréglage ne fait que lui donner une valeur par défaut.
+
+
+
+
+
+
+
+
Comment le lancer ?
+
Voyez ce que coûterait le jeu, construisez-le ou prenez sa recette pour la modifier :
Préréglages de fichiers de test, un jeu pour chaque question de test
+
+ Un préréglage est tout un jeu de fichiers de test conçu autour d'une question, avec un manifeste qui
+ dit comment votre système doit réagir à chaque fichier. Vous choisissez la question, l'outil
+ construit le jeu. Chaque préréglage a sa propre page qui dit ce qu'il trouve d'habitude, ce que
+ contient le jeu et chaque réglage qu'il accepte.
+
Mon formulaire d'envoi accepte-t-il ce qu'il doit et refuse-t-il le reste ?
+
upload-validation
+
+
+
+
+
En quoi un préréglage diffère-t-il d'une recette ?
+
+ En dessous, il n'en diffère pas. Un préréglage est une recette que l'outil écrit pour vous à partir
+ de quelques réglages. tfg preset eject affiche cette recette pour que vous la
+ gardiez à côté de vos tests et la modifiiez, et une recette à vous peut s'appuyer sur un
+ préréglage en une ligne, extends: preset: suivi de son identifiant.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Puis-je me fier aux valeurs par défaut ?
+
+ Pour les fichiers, oui. Pour un nombre que seul votre système connaît, comme la limite d'un
+ formulaire d'envoi, une valeur par défaut est un substitut de notre part, et l'outil le dit
+ chaque fois qu'il en utilise une. La page de chaque préréglage marque ces réglages, et tfg
+ preset show le dit avant que rien ne soit écrit.
+
Une limite de taille est-elle appliquée exactement là où elle est déclarée ?
+
+ Le préréglage size-boundaries construit en une commande tout un jeu de vrais fichiers de test
+ pour cette question, avec un manifest.json à côté qui dit comment votre système doit
+ réagir à chaque fichier. Tout ce qui suit est lu depuis le programme, aux valeurs par défaut de
+ cette version.
+
+
+
+
+
Que trouve-t-il d'habitude ?
+
+
des erreurs d'un à la limite
+
Mo confondu avec Mio, soit 4,8 pour cent, assez pour laisser passer un fichier qui ne devrait pas passer
+
une limite appliquée dans le navigateur et pas sur le serveur
+
+
+
+
+
+
Que contient le jeu ?
+
Aux valeurs par défaut, comme le rapporte tfg preset show size-boundaries :
+
+
+
+
Fichiers
7
+
Cibles dans sa recette
7
+
Taille totale
73 400 320 B
+
Formats
pdf
+
+
+
+
Et ce que le manifeste de ce jeu attend de votre système :
+
+
+
+
Attendu
Signification
Fichiers
+
+
+
accept
Votre système doit accepter le fichier.
4
+
reject
Votre système doit refuser le fichier.
3
+
+
+
+
+
+
+
Que pouvez-vous modifier ?
+
+
+
+
Réglage
Accepte
Par défaut
Ce qu'il fait
+
+
+
+
--limit
+
une taille comme 2mb
+
10mb
+
La limite de taille que déclare votre système. Tout le reste se mesure à partir d'elle. Cette valeur par défaut est notre substitut, pas la valeur de votre système. Passez la vôtre.
+
+
+
--spread
+
tailles séparées par des virgules
+
1B,1kb,1mb
+
Jusqu'où aller de part et d'autre de la limite, sous forme de liste de tailles.
+
+
+
--format
+
un identifiant de format de la page des formats
+
pdf
+
Le format de chaque fichier du jeu. C'est une option de l'outil lui-même, et le préréglage ne fait que lui donner une valeur par défaut.
+
+
+
+
+
+
+
+
Comment le lancer ?
+
Voyez ce que coûterait le jeu, construisez-le ou prenez sa recette pour la modifier :
Mon import de tableaux résiste-t-il à ce qu'exportent les vrais outils ?
+
+ Le préréglage tabular-import construit en une commande tout un jeu de vrais fichiers de test
+ pour cette question, avec un manifest.json à côté qui dit comment votre système doit
+ réagir à chaque fichier. Tout ce qui suit est lu depuis le programme, aux valeurs par défaut de
+ cette version.
+
+
+
+
+
Que trouve-t-il d'habitude ?
+
+
un fichier à point-virgule lu comme une seule colonne, parce que le séparateur a été supposé au lieu d'être cherché
+
un fichier CRLF découpé en lignes avec une ligne vide après chacune
+
un tableau sans en-tête dont la première ligne de données est avalée comme noms de colonnes
+
un import qui garde les colonnes qu'il peut afficher et abandonne le reste sans un mot
+
un lecteur qui prend les enregistrements JSON une ligne à la fois et s'arrête au premier document indenté
+
+
+
+
+
+
Que contient le jeu ?
+
Aux valeurs par défaut, comme le rapporte tfg preset show tabular-import :
+
+
+
+
Fichiers
13
+
Cibles dans sa recette
13
+
Taille totale
3 080 060 B
+
Formats
csv, json, xlsx
+
+
+
+
Et ce que le manifeste de ce jeu attend de votre système :
+
+
+
+
Attendu
Signification
Fichiers
+
+
+
accept
Votre système doit accepter le fichier.
8
+
unspecified
Cela dépend des règles de votre système. Vous décidez, puis vous vérifiez que ce qui se passe est ce que vous aviez voulu.
5
+
+
+
+
+
+
+
Que pouvez-vous modifier ?
+
+
+
+
Réglage
Accepte
Par défaut
Ce qu'il fait
+
+
+
+
--rows
+
1 - 200000 lignes
+
1000
+
Le nombre de lignes du tableur. Il est écrit exactement à la taille que font autant de lignes, donc le budget ci-dessus bouge avec cette valeur.
+
+
+
--columns
+
1 - 32768 colonnes
+
10
+
Le nombre de colonnes de chaque ligne du tableur. Lignes fois colonnes a un plafond, et le dépasser est refusé avant que rien ne soit écrit.
+
+
+
+
+
+
+
+
Comment le lancer ?
+
Voyez ce que coûterait le jeu, construisez-le ou prenez sa recette pour la modifier :
Mon lecteur sait-il dans quel encodage est un fichier, ou devine-t-il ?
+
+ Le préréglage text-encoding construit en une commande tout un jeu de vrais fichiers de test
+ pour cette question, avec un manifest.json à côté qui dit comment votre système doit
+ réagir à chaque fichier. Tout ce qui suit est lu depuis le programme, aux valeurs par défaut de
+ cette version.
+
+
+
+
+
Que trouve-t-il d'habitude ?
+
+
un lecteur qui suppose de l'UTF-8 et montre un fichier UTF-16 avec un caractère sur trois, ou en rangées de carrés
+
une marque d'ordre des octets lue comme du contenu, si bien que le premier champ d'un import commence par trois caractères parasites
+
un importeur qui devine l'encodage d'après les premiers octets et devine autrement pour un fichier plus long
+
un fichier CRLF découpé en lignes avec une ligne vide après chacune, ou un retour chariot resté dans le dernier champ
+
+
+
+
+
+
Que contient le jeu ?
+
Aux valeurs par défaut, comme le rapporte tfg preset show text-encoding :
+
+
+
+
Fichiers
20
+
Cibles dans sa recette
20
+
Taille totale
81 920 B
+
Formats
csv, log, md, txt, xml
+
+
+
+
Et ce que le manifeste de ce jeu attend de votre système :
+
+
+
+
Attendu
Signification
Fichiers
+
+
+
accept
Votre système doit accepter le fichier.
10
+
unspecified
Cela dépend des règles de votre système. Vous décidez, puis vous vérifiez que ce qui se passe est ce que vous aviez voulu.
10
+
+
+
+
+
+
+
Que pouvez-vous modifier ?
+
+
+
+
Réglage
Accepte
Par défaut
Ce qu'il fait
+
+
+
+
--sample
+
une taille comme 2mb
+
4kb
+
La taille de chaque fichier du jeu. L'UTF-16 stocke deux octets par caractère, donc un nombre impair est refusé.
+
+
+
+
+
+
+
+
Comment le lancer ?
+
Voyez ce que coûterait le jeu, construisez-le ou prenez sa recette pour la modifier :
Mon formulaire d'envoi accepte-t-il ce qu'il doit et refuse-t-il le reste ?
+
+ Le préréglage upload-validation construit en une commande tout un jeu de vrais fichiers de test
+ pour cette question, avec un manifest.json à côté qui dit comment votre système doit
+ réagir à chaque fichier. Tout ce qui suit est lu depuis le programme, aux valeurs par défaut de
+ cette version.
+
+
+
+
+
Que trouve-t-il d'habitude ?
+
+
une limite appliquée dans le navigateur et pas sur le serveur
+
un SVG ou un HTML pris pour une image ou pour du texte brut, un moyen de faire passer un script à travers un formulaire
+
un fichier contrôlé par son extension et jamais ouvert, si bien qu'un PDF nommé .jpg passe
+
un formulaire qui lit tout le corps en mémoire avant de regarder sa taille
+
un envoi nommé PHOTO.JPG refusé là où photo.jpg est accepté, ou l'inverse
+
un nom avec des espaces, des parenthèses ou des caractères hors ASCII écrit sur le disque tel quel
+
+
+
+
+
+
Que contient le jeu ?
+
Aux valeurs par défaut, comme le rapporte tfg preset show upload-validation :
+
+
+
+
Fichiers
71
+
Cibles dans sa recette
22
+
Taille totale
120 639 488 B
+
Formats
html, jpg, pdf, png, svg, txt
+
+
+
+
Et ce que le manifeste de ce jeu attend de votre système :
+
+
+
+
Attendu
Signification
Fichiers
+
+
+
accept
Votre système doit accepter le fichier.
56
+
reject
Votre système doit refuser le fichier.
10
+
unspecified
Cela dépend des règles de votre système. Vous décidez, puis vous vérifiez que ce qui se passe est ce que vous aviez voulu.
5
+
+
+
+
+
+
+
Que pouvez-vous modifier ?
+
+
+
+
Réglage
Accepte
Par défaut
Ce qu'il fait
+
+
+
+
--limit
+
une taille comme 2mb
+
10mb
+
La limite de taille que déclare votre formulaire d'envoi. Ce jeu fait un pas de chaque côté - pour un fichier à chaque distance, lancez le préréglage size-boundaries. Cette valeur par défaut est notre substitut, pas la valeur de votre système. Passez la vôtre.
+
+
+
--allow
+
identifiants de format séparés par des virgules
+
jpg,png,pdf
+
Les types que votre formulaire doit accepter. Chacun devient un vrai fichier de ce type, et ils forment le témoin positif de tout le jeu.
+
+
+
--deny
+
extensions séparées par des virgules
+
svg,html,exe,sh
+
Les extensions que votre formulaire doit refuser. Une extension pour laquelle cette version n'a pas de format reçoit quand même un fichier à ce nom, contenant du texte brut.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
Jusqu'où le grand fichier dépasse la limite. Désactivez-le là où écrire plusieurs fois la limite ne vaut pas le disque.
+
+
+
--bulk
+
0 - 10000 fichiers
+
50
+
Le nombre de fichiers de l'envoi en masse. Zéro retire complètement ce groupe du jeu.
+
+
+
+
+
+
+
+
Comment le lancer ?
+
Voyez ce que coûterait le jeu, construisez-le ou prenez sa recette pour la modifier :
+ जिस वैलिडेटर को केवल स्वस्थ फ़ाइलें दिखाई गई हों, उसे सचमुच परखा नहीं गया है। यहाँ बताया गया है कि
+ ऐसी फ़ाइल कैसे पाएँ जो जानबूझकर बिगाड़ी गई हो, ठीक उतने आकार की निकले जितना आपने
+ माँगा, और ऐसा मैनिफ़ेस्ट साथ लाए जो बताता है कि आपके सिस्टम को उसका क्या करना चाहिए।
+
+
+
+
छोटा जवाब
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out ठीक 2097152 बाइट की
+ एक PNG लिखता है जिसके शुरुआती बाइट शून्य हैं, और उसके बगल का मैनिफ़ेस्ट दर्ज करता है कि आपके
+ सिस्टम को उसे अस्वीकार करना चाहिए।
+
+
+
+
+
आम तरीका
+
हाथ से बिगाड़ी गई फ़ाइल खराब टेस्ट क्यों है
+
+ आम तरीके हैं हेक्स एडिटर, कुछ यादृच्छिक बाइट पलटने वाली स्क्रिप्ट, या head अथवा
+ truncate से फ़ाइल को छोटा काट देना। ये एक बार चलते हैं, फिर महँगे पड़ते हैं:
+
+
+
+ हर बार अलग होता है। यादृच्छिक बाइट हर रन में नई जगह पड़ता है, इसलिए मंगलवार की
+ विफलता बुधवार को लौटे, यह ज़रूरी नहीं।
+
+
+ यह आकार बदल देता है। कटी हुई फ़ाइल उस सीमा से छोटी होती है जिसके नीचे उसे रहना था,
+ इसलिए आकार की जाँच सामग्री की जाँच से पहले जवाब दे देती है और टेस्ट गलत कारण से पास हो जाता
+ है।
+
+
+ यह अक्सर किसी की नज़र में नहीं आता। सादा पाठ बीच में एक बाइट बदलने पर भी पढ़ा जाता
+ है, और उदार इमेज रीडर उसे बस बना देता है, इसलिए जो फ़ाइल खराब होनी थी वह स्वीकार हो जाती है।
+
+
+ यह नहीं बताता कि क्या होना चाहिए। फ़ाइल सिर्फ़ बाइट है, और जो बाद में टेस्ट पढ़ेगा
+ उसे अंदाज़ा लगाना पड़ेगा कि इरादा स्वीकार करने का था या अस्वीकार करने का।
+
+
+
+
+
+
आपको क्या मिलता है
+
खराब फ़ाइल का आकार वही रहता है जो आपने माँगा था
+
+ फ़ाइल सामान्य रूप से बनती है और बाद में, डिस्क तक जाते समय, बिगाड़ी जाती है। वह माँगा हुआ आकार बनाए
+ रखती है, और वही कमांड फिर वही बाइट लिखता है।
+
+ सेटिंग कोलन के बाद लिखी जाती है। विकल्प दोहराया जा सकता है, और बिगाड़ आपके लिखे क्रम में लागू होते
+ हैं। यह सभी 26 फ़ॉर्मैट के साथ चलता है।
+
+
+
+
+
यह क्या कर सकता है
+
कौन-कौन से बिगाड़ हैं?
+
+ यह वह सूची है जो प्रोग्राम छापता है, इस पेज को बनाते समय उसी से पढ़ी गई। tfg damage यही
+ सूची छापता है, और tfg damage <id> बताता है कि उनमें से एक क्या लेता है।
+
+
+
+
+
+
बिगाड़
+
बाइट के साथ क्या करता है
+
सबसे छोटी फ़ाइल
+
सेटिंग
+
+
+
+
+
zero-head
+
फ़ाइल के शुरुआती बाइट को शून्य से ढक देता है और लंबाई नहीं छेड़ता। ज़्यादातर रीडर सबसे पहले वहीं देखते हैं, इसलिए यह बिगाड़ लगभग हर चीज़ पकड़ लेती है।
+
8
+
bytes
+
+
+
+
+
+ zero-head फ़ाइल की शुरुआत पर शून्य लिख देता है। ज़्यादातर रीडर सबसे पहले वहीं देखते
+ हैं, उस सिग्नेचर और हेडर पर जो बताते हैं कि फ़ाइल क्या है, इसलिए लगभग हर रीडर इसे भाँप लेता है।
+ सादे पाठ और लॉग में सिग्नेचर नहीं होता और वे भी अस्वीकार होते हैं, क्योंकि शून्य बाइट की कतार
+ पाठ नहीं है। चार बाइट से नीचे कुछ फ़ॉर्मैट ऐसे बिगाड़ के साथ निकलते हैं जिसकी कोई रीडर शिकायत
+ नहीं करता, इसीलिए सेटिंग चार से शुरू होती है।
+
+
+
+
+
मैनिफ़ेस्ट क्या कहता है
+
एक मैनिफ़ेस्ट जो बताता है कि क्या होना चाहिए
+
+ हर खराब फ़ाइल को एक प्रविष्टि मिलती है जो कहती है कि आपके सिस्टम को उसे अस्वीकार करना चाहिए, और
+ बिगाड़ उसके बगल में दर्ज रहता है:
+
+ दो अनुरोध कुछ भी लिखे जाने से पहले ठुकरा दिए जाते हैं, क्योंकि हर एक डिस्क पर ऐसी फ़ाइल छोड़ देता
+ जिसका मैनिफ़ेस्ट गलत वर्णन करता:
+
+
+
बिगाड़ को जितना चाहिए उससे छोटी फ़ाइल, जो ज्यों की त्यों निकलती
+
+ बिगाड़ के साथ expected: accept, क्योंकि कोई भी उसे पूरा नहीं कर सकता। अगर आपके सिस्टम
+ को फ़ाइल सुधारनी है तो sanitize लिखें, या अगर आप यही सवाल पूछ रहे हैं तो
+ unspecified
+
+
+
+
+
+
रेसिपी में
+
एक रन में स्वस्थ और खराब फ़ाइलें
+
+ दोनों को एक रेसिपी में रखें, और मैनिफ़ेस्ट हर फ़ाइल की अपेक्षा साथ रखता है, इसलिए टेस्ट को यह बताने
+ वाली सूची नहीं चाहिए कि कौन-सी कौन-सी है:
+
+ टेस्ट मैनिफ़ेस्ट पढ़ता है और जाँचता है कि जो हुआ वही है जो घोषित किया गया था। उसे फ़ाइल नामों की
+ सूची नहीं चाहिए:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ अच्छा इनकार साफ़ इनकार होता है। जो संदेश बताए कि क्या गलत था, वही वह जवाब है जो आप चाहते हैं। सर्वर
+ त्रुटि, अटक जाना या आधी सहेजी फ़ाइल वह खराबी है जिसे ढूँढ़ने के लिए यह टेस्ट है।
+
+ हर सिस्टम में इसके लिए एक कमांड है, और तीनों नीचे हैं। वे आपको ठीक सही बाइट संख्या की फ़ाइल देती हैं
+ - और बहुत से टेस्ट के लिए आपको बस यही चाहिए। इस पेज की हर कमांड प्रकाशित करने से पहले उस
+ सिस्टम पर चलाई गई जिसकी वह है।
+
+
+
+
छोटा जवाब
+
+ Windows: fsutil file createnew name 10485760। Linux: dd if=/dev/zero of=name
+ bs=1M count=10। macOS: mkfile 10m name। आकार बाइट में होते हैं, और आपके
+ फ़ाइल मैनेजर के गिनने के तरीके से 10 MB यानी 10485760।
+
+
+
+
+
Windows
+
fsutil, और बिना किसी अतिरिक्त चीज़ वाला PowerShell रूप
+
+ fsutil Windows के साथ आता है। यह आकार बाइट में लेता है, इसलिए पहले
+ संख्या निकाल लें - 10 MB यानी 10485760, 100 MB यानी 104857600, 1 GB यानी 1073741824।
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Windows 11 पर मापा गया: यह सामान्य प्रॉम्प्ट से चलता है और उन्नत प्रॉम्प्ट नहीं माँगता, और फ़ाइल ठीक
+ 10485760 बाइट की बनती है।
+
+
PowerShell बिना किसी दूसरे प्रोग्राम को बुलाए यही कर सकता है, और इकाइयाँ समझता है:
+ PowerShell में 10MB का मतलब 10485760 बाइट है, वही 1024 आधारित गिनती जो एक्सप्लोरर
+ इस्तेमाल करता है, इसलिए ऊपर की दोनों कमांड एक ही आकार बनाती हैं।
+
+
+
+
+
Linux
+
dd, truncate और fallocate, और वह अंतर जो लोगों को फँसाता है
+
dd वह है जिसे सब जानते हैं। यह बाइट सच में लिखता है:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate तुरंत होता है, और यही पेंच है। Alpine Linux पर मापने पर फ़ाइल 10485760 बाइट
+ बताती है और शून्य ब्लॉक घेरती है - यह एक स्पार्स फ़ाइल है। जो
+ भी इसे पढ़ता है उसे दस मेगाबाइट शून्य मिलते हैं, पर डिस्क ने जगह कभी दी ही नहीं:
+
+
truncate -s 10M test10mb.bin
+
+ अपलोड सीमा परखने के लिए यह ठीक है और डिस्क कोटा परखने के लिए भ्रामक। जब जगह असली होनी चाहिए तब
+ fallocate की ओर जाएँ:
+
+
fallocate -l 10M test10mb.bin
+
और जब सामग्री असंपीड्य होनी चाहिए, ताकि कोई आर्काइवर उसे फिर से छोटा न कर सके:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, जो स्पार्स नहीं है, और वे दो जिन्हें आप पहले से जानते हैं
+
+ macOS में mkfile आता है। macOS 26.6.2 पर मापा गया: 10485760 बाइट और 20480 ब्लॉक, यानी
+ जगह वादे से नहीं, सच में आवंटित होती है:
+
+
mkfile 10m test10mb.bin
+
dd और truncate भी वहाँ हैं और Linux की तरह ही चलते हैं:
+ ऊपर की सारी चीज़ें आपको शून्यों का एक ब्लॉक देती हैं। जब जाँचा जा रहा हिस्सा सिर्फ़ आकार देखता है -
+ अपलोड सीमा, कोटा, ट्रांसफ़र - तब यह काफ़ी है। जिस पल कोई चीज़ फ़ाइल को खोलती
+ है, यह काफ़ी नहीं रहता।
+
+
+ मापा गया, और खुद करके देखना लायक है: fsutil से 2 MB की फ़ाइल बनाएँ, उसका नाम
+ photo.png रखें, और किसी इमेज लाइब्रेरी को दें। Pillow जवाब देता है cannot
+ identify image file। यह PNG नहीं है। यह कभी था ही नहीं - सिर्फ़ नाम ऐसा कहता था।
+
+
+ यह सुनने में जितना लगता है उससे ज़्यादा मायने रखता है, क्योंकि टेस्ट फिर किस तरफ़ विफल होता
+ है यही सवाल है। आपका अपलोड एंडपॉइंट फ़ाइल ठुकरा देता है, आपका टेस्ट हरा हो जाता है, और
+ आप मान लेते हैं कि आकार सीमा काम करती है। उसने फ़ाइल आकार की वजह से नहीं ठुकराई। उसने इसलिए
+ ठुकराई कि बाइट तस्वीर नहीं थे, और जिस नियम को आप जाँचना चाहते थे वह कभी छुआ ही नहीं गया।
+
+
+
कोई पार्सर आकार का कोई नियम देखे जाने से पहले ही उसे ठुकरा देता है
+
थंबनेल का चरण विफल होता है और जो त्रुटि आप पढ़ते हैं वह थंबनेल के बारे में होती है
+
कोई एंटीवायरस या सामग्री जाँच उसे तीसरे कारण से मना कर देती है
+
कोई व्यूअर कुछ नहीं दिखाता, और कोई नहीं बता सकता कि यही बग है या नहीं
+
+
+
+
+
दूसरा रास्ता
+
उस फ़ॉर्मैट की असली फ़ाइल, ठीक उसी आकार में जो आपने माँगा
+
+ Testing Files Generator यही करता है। फ़ाइल अपने फ़ॉर्मैट की सच्ची फ़ाइल है - वह अपने सॉफ़्टवेयर में
+ खुलती है - और उसमें ठीक उतने बाइट हैं जितने आपने माँगे, बाइट तक:
+
+ ऐसा आकार माँगें जिस तक कोई फ़ॉर्मैट नहीं पहुँच सकता और आपको न्यूनतम सीमा और उसका कारण बताने वाली
+ त्रुटि मिलती है, गलत आकार की फ़ाइल कभी नहीं। फ़ॉर्मैट पेज हर फ़ॉर्मैट
+ को उसकी सबसे छोटी संभव फ़ाइल के साथ सूचीबद्ध करता है।
+
+
और एक सीमा एक नहीं, तीन टेस्ट केस होती है, इसलिए टूल तीनों बनाता है:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ इससे आपको 10485759, 10485760 और 10485761 बाइट की फ़ाइलें मिलती हैं, और एक मैनिफ़ेस्ट जो बताता है कि
+ आपके सिस्टम को किन्हें स्वीकार करना चाहिए और किन्हें अस्वीकार। उपयोग के
+ मामलों का पेज इसे और चार दूसरे काम समझाता है जिनके लिए यह बना है।
+
मुफ़्त और ओपन सोर्स, GPL-3.0। साइन अप की ज़रूरत नहीं। Windows और macOS के डाउनलोड हस्ताक्षरित हैं और बिना चेतावनी के शुरू होते हैं।
+
+
+
+
तो कौन सा इस्तेमाल करें?
+
+
+
सिस्टम की कमांड इस्तेमाल करें
+
+ जब कुछ भी फ़ाइल नहीं खोलता। ऐसे एंडपॉइंट पर आकार सीमा की जाँच जो पहले आकार देखता है, कोई ट्रांसफ़र,
+ कोटा, डिस्क भरने की स्थिति। यह एक पंक्ति है और पहले से इंस्टॉल है।
+
+
+
+
असली जनरेटर इस्तेमाल करें
+
+ जब कुछ भी फ़ाइल को पार्स, रेंडर, इंपोर्ट या एक्सट्रैक्ट करता है - और जब आपको कल दूसरी मशीन पर वही
+ फ़िक्स्चर बाइट-दर-बाइट फिर से चाहिए।
+
+
+
+
+ दोनों इस पेज पर इसलिए हैं क्योंकि दोनों कभी-कभी सही होते हैं। जिस गलती से बचना है वह है दूसरे की
+ ज़रूरत वाली जगह पहले को इस्तेमाल करना और हरे टेस्ट को सबूत मान लेना।
+
+ टूल जो कुछ भी करता है, उन सवालों के रूप में सजाया गया जिन्हें लेकर लोग सच में आते हैं।
+ रिपॉज़िटरी का README पूरा संदर्भ है और हमेशा आपके डाउनलोड किए
+ बिल्ड से मेल खाता है।
+
+
+
+
कौन सी कमांड हैं?
+
हर एक सिर्फ़ एक काम करती है:
+
tfg generate रेसिपी या फ़्लैग से फ़ाइलें बनाएँ
+tfg validate रेसिपी जाँचें और कुछ न लिखें
+tfg verify किसी डायरेक्टरी को मैनिफ़ेस्ट से मिलाकर जाँचें
+tfg cleanup मैनिफ़ेस्ट में सूचीबद्ध फ़ाइलें हटाएँ
+tfg recipe fmt रेसिपी को उसके स्थिर रूप में छापें
+tfg preset किसी नामित टेस्ट सवाल से फ़ाइलों का सेट बनाएँ
+tfg formats इस बिल्ड के समर्थित फ़ॉर्मैट सूचीबद्ध करें
+tfg damage इस बिल्ड द्वारा किसी फ़ाइल को जानबूझकर बिगाड़ने के तरीके सूचीबद्ध करें
+tfg tool आपके पास पहले से मौजूद फ़ाइलों के लिए छोटे टूल
+tfg version टूल का संस्करण छापें
+tfg license लाइसेंस और बनाई गई फ़ाइलों के लिए उसका अर्थ छापें
+
+
+
+
सटीक आकार की एक फ़ाइल कैसे बनाऊँ?
+
+ फ़ॉर्मैट, आकार और जगह बताएँ। आकार 1024 के गुणकों में गिने जाते हैं, इसलिए 2mb 2097152
+ बाइट है। सादी बाइट संख्या भी चलती है, इसलिए --size 10485761 ठीक उतने ही बाइट माँगता
+ है।
+
+
tfg generate --format png --size 2mb --out ./out
+
generate के काम के फ़्लैग:
+
+
+
फ़्लैग
क्या करता है
+
+
--format <id>
फ़ाइलों का फ़ॉर्मैट, जैसे txt
+
--size <size>
हर फ़ाइल का सटीक आकार, जैसे 10mb या सादी बाइट संख्या
+
--size-range <a-b>
किसी सीमा में से हर फ़ाइल के लिए निकाला गया आकार, जैसे 1kb-8kb। निकालना सीड से होता है
+
--boundary <size>
सीमा के आसपास तीन फ़ाइलें: एक बाइट नीचे, सीमा, एक बाइट ऊपर
+
--count <n>
कितनी फ़ाइलें बनानी हैं। डिफ़ॉल्ट 1
+
--name <template>
नाम का साँचा, जैसे invoice_{index:04}.txt
+
--out <dir>
जिस डायरेक्टरी में लिखना है
+
--seed <n>
रन का सीड। वही सीड वही बाइट देता है
+
--set <k>=<v>
फ़ॉर्मैट की एक सेटिंग, दोहराई जा सकती है
+
--damage <name>
फ़ाइलों को जानबूझकर बिगाड़ें, दोहराया जा सकता है और क्रम से लागू होता है। सूची के लिए tfg damage चलाएँ
+
--expected <outcome>
accept, reject, sanitize या unspecified
+
--dry-run
गिनें और दिखाएँ, कुछ भी न लिखें
+
--json
मैनिफ़ेस्ट को स्टैंडर्ड आउटपुट पर लिखें
+
+
+
+
+
+
+
जानबूझकर टूटी फ़ाइल कैसे बनाऊँ?
+
+ यह टूल जो भी दूसरी फ़ाइल लिखता है वह बनावट से सही होती है, और इससे अपलोड वैलिडेटर के तीन सवालों में
+ से दो का जवाब मिल जाता है। --damage तीसरे का जवाब देता है - क्या फ़ाइल खुलती भी है।
+ फ़ाइल सामान्य रूप से बनती है और फिर बिगाड़ी जाती है, इसलिए उसका आकार वही रहता है जो आपने माँगा।
+
+ सेटिंग कोलन के बाद आती हैं। फ़्लैग दोहराया जा सकता है, और आप जिस क्रम में लिखते हैं वही उनके लागू
+ होने का क्रम है। tfg damage बताता है कि यह बिल्ड क्या कर सकता है और हर एक क्या लेता
+ है।
+
+
रेसिपी में कुंजी एक सूची है, नामों की या सेटिंग की:
+ बिगाड़ी गई फ़ाइल को मैनिफ़ेस्ट में expected: reject मिलता है, और बिगाड़ने का ब्योरा
+ उसके बगल में दर्ज होता है। दो चीज़ें कुछ भी लिखे जाने से पहले ठुकरा दी जाती हैं, क्योंकि हर एक
+ डिस्क पर ऐसी फ़ाइल छोड़ देती जिसे मैनिफ़ेस्ट गलत बताता:
+
+
+
बिगाड़ने के लिए ज़रूरी से छोटी फ़ाइल, क्योंकि वह बिना बदले निकल आती
+
+ बिगाड़ के बगल में expected: accept, क्योंकि कुछ भी उसे पूरा नहीं कर सकता। अगर जाँचे जा
+ रहे सिस्टम को फ़ाइल सुधारनी है तो sanitize लिखें, या अगर आप यही सवाल पूछ रहे हैं
+ तो unspecified
+
+
+
+ तीसरी बात पहले से नहीं जानी जा सकती। अगर कोई बिगाड़ चलता है और एक भी बाइट नहीं हिलाता, तो वह फ़ाइल
+ लिखे जाने के बजाय छोड़ दी जाती है - रन चलता रहता है, बताता है कि वह कौन सी फ़ाइल थी, और आंशिक
+ एग्ज़िट कोड के साथ ख़त्म होता है।
+
+ रेसिपी एक YAML फ़ाइल है जो पूरे रन का वर्णन करती है। इसे अपने टेस्ट के बगल में कमिट करें और
+ फ़िक्स्चर आपकी रिपॉज़िटरी में बाइनरी नहीं रह जाते - कोई भी उन्हें कुछ सौ अक्षरों की फ़ाइल से
+ बाइट-दर-बाइट दोबारा बना सकता है।
+
+ हर टार्गेट को size, size-range, boundary या
+ contains में से ठीक एक चाहिए। दो होना त्रुटि है और एक भी न होना भी। अमान्य रेसिपी
+ कोई फ़ाइल नहीं लिखती और सिर्फ़ पहली नहीं, सारी समस्याएँ एक साथ बताती है, हर एक
+ उस सेटिंग का नाम लेकर जिससे वह जुड़ी है।
+
+
+
+
+
मैं कैसे बताऊँ कि मेरे सिस्टम को किसी फ़ाइल के साथ क्या करना चाहिए?
+
जब नतीजा काफ़ी हो तो छोटा रूप, जब कारण मायने रखे तो लंबा रूप:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ नतीजे हैं accept, reject, sanitize और
+ unspecified। कारण एक बंद सूची हैं ताकि रिपोर्ट उनके आधार पर समूह बना सके:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit और size_zero।
+
+
+ कारण काम कर रहे नियम का नाम लेता है, फ़ैसले का नहीं। इसीलिए एक ही कारण किसी भी
+ नतीजे के नीचे आ सकता है - सीमा से एक बाइट नीचे की फ़ाइल accept है, और जिस नियम की
+ बात है वह फिर भी size_limit है।
+
+
+
+
+
मैनिफ़ेस्ट में क्या है?
+
+ यह हर रन के अंत में फ़ाइलों के बगल में लिखा जाता है, बीच में रोके गए रन में भी। हर फ़ाइल के लिए एक
+ प्रविष्टि:
+
+ रन रेसिपी से आया हो तो recipe_hash जुड़ता है, और प्रीसेट से आया हो तो
+ overrides के साथ preset, इसलिए मैनिफ़ेस्ट को हमेशा उसके स्रोत तक खोजा
+ जा सकता है।
+
+
+ हर प्रविष्टि में target_id भी होता है, यानी रेसिपी के उस टार्गेट का id जिसने फ़ाइल
+ बनाई, और summary.by_target गिनता है कि हर टार्गेट के हिस्से कितनी फ़ाइलें आईं।
+ इसलिए कई टार्गेट वाली रेसिपी को फ़ाइल नाम पढ़े बिना टार्गेट-दर-टार्गेट जाँचा जा सकता है।
+
+
+
+
+
प्रीसेट क्या है?
+
+ किसी आम टेस्ट सवाल का जवाब देने वाला फ़ाइलों का तैयार सेट, ताकि आपको सेट खुद डिज़ाइन न करना पड़े।
+ प्रीसेट अंदर से सामान्य रेसिपी हैं, और eject रेसिपी छापता है ताकि आप वहीं से उसे
+ संपादित कर सकें। हर प्रीसेट का अपना पेज है जो बताता है कि वह आम तौर
+ पर क्या पकड़ता है, सेट में क्या है और वह कौन सी सेटिंग लेता है।
+
+ show सेट बनाने से पहले बताता है कि उसकी क़ीमत क्या होगी, और साफ़ कहता है जब कोई संख्या
+ आपकी सीमा नहीं बल्कि हमारी अस्थायी जगह-धारक संख्या हो।
+
+
+
+
+
एग्ज़िट कोड का क्या अर्थ है?
+
+ हर अंत का अपना कोड है, मशीन के पढ़ने लायक आउटपुट स्टैंडर्ड आउटपुट पर जाता है, और विफल रन वहाँ कुछ
+ नहीं छापता। तालिका एक जमाया हुआ अनुबंध है - किसी कोड का अर्थ बदलने के लिए मुख्य संस्करण बढ़ाना
+ पड़ता है।
+
+
+
+
+
+
कोड
+
अर्थ
+
+
+
+
+
0
+
सब कुछ ठीक चला।
+
+
+
1
+
टूल के अंदर एक अप्रत्याशित त्रुटि।
+
+
+
2
+
गलत कमांड या फ़्लैग।
+
+
+
3
+
रेसिपी मान्य नहीं है।
+
+
+
4
+
फ़ॉर्मैट वह नहीं कर सकता जो माँगा गया।
+
+
+
5
+
पढ़ना या लिखना विफल रहा।
+
+
+
6
+
डिस्क पर पर्याप्त जगह नहीं है।
+
+
+
7
+
verify को असंगति मिली।
+
+
+
8
+
रन पूरा हुआ, पर सब कुछ नहीं बना।
+
+
+
130
+
Ctrl+C से रोका गया।
+
+
+
143
+
एक सिग्नल से रोका गया, CI का टाइमआउट ऐसा ही दिखता है।
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Ctrl+C से रोका गया रन फिर भी मैनिफ़ेस्ट छोड़ता है और कभी आधी लिखी फ़ाइल नहीं छोड़ता, इसलिए रद्द किए
+ गए जॉब को अगला जॉब साफ़ कर सकता है।
+
+ हाँ, वही इंजन जिस पर एक विंडो लगी है, उस टेस्टिंग के लिए जो स्क्रिप्ट से नहीं होती। यह घटाया हुआ रूप
+ नहीं है: एक टेस्ट दोनों इंटरफ़ेस की क्षमता-दर-क्षमता तुलना करता है, और जो सिर्फ़ एक ही कर सकता
+ है उसे चुपचाप अलग होने देने के बजाय घोषित और उचित ठहराना पड़ता है।
+
+
+ स्क्रीन हैं एक बैच, प्रीसेट, एक साथ कई बैच, और परिचय। यह कुछ भी लिखने से पहले रन की क़ीमत दिखाती है,
+ चलते समय प्रगति बताती है, और बीच में रद्द की जा सकती है बिना आधी लिखी फ़ाइल छोड़े। यह अभी रेसिपी
+ फ़ाइल नहीं खोलती - फ़िलहाल रेसिपी कमांड लाइन की चीज़ हैं, और विंडो अपने बैच फ़ॉर्म में बनाती है।
+
+ लाइसेंस, निजता, दोहराव, और वे बातें जो लोग जनरेटर को बिल्ड पाइपलाइन में लगाने से पहले जाँचते हैं।
+ अगर आपका सवाल यहाँ नहीं है, तो इश्यू ट्रैकर खुला है।
+
+
+
+
+
यह dd, fsutil या truncate से कैसे अलग है?
+
+
वे आपको सही आकार की फ़ाइल देते हैं जो खालीपन से भरी होती है। इस तरह बनी photo.png नाम की 2 MB की फ़ाइल PNG नहीं होती, इसलिए जो भी उसे सच में पार्स करता है वह गलत कारण से उसे ठुकरा देता है, और आपका टेस्ट भी गलत कारण से पास हो जाता है। यह टूल ठीक 2 MB की असली PNG बनाता है जो इमेज व्यूअर में खुलती है, और उसके साथ यह घोषणा आती है कि आपके सिस्टम को उसके साथ क्या करना चाहिए।
क्या यह मुफ़्त है, और क्या मैं इसे काम पर इस्तेमाल कर सकता हूँ?
+
+
दोनों के लिए हाँ। यह GPL-3.0 के तहत जारी है और इसकी कोई कीमत नहीं। कोई खाता, लाइसेंस कुंजी या सशुल्क स्तर नहीं है।
+
+
+
+
क्या मैं बनाई गई फ़ाइलें क्लोज़्ड सोर्स उत्पाद में इस्तेमाल कर सकता हूँ?
+
+
हाँ। लाइसेंस टूल के कोड पर लागू होता है, उस पर नहीं जो टूल बनाता है। बनाई गई फ़ाइलें, रेसिपी और मैनिफ़ेस्ट आउटपुट हैं, व्युत्पन्न कृतियाँ नहीं, इसलिए आप उन्हें बिना किसी बाध्यता के कमिट और वितरित कर सकते हैं।
+
+
+
+
क्या बनाई गई फ़ाइलों में असली निजी डेटा होता है?
+
+
नहीं। अंदर का सब कुछ एक सीड से बनाया जाता है। कोई डेटासेट नहीं पढ़ा जाता, किसी सेवा से संपर्क नहीं किया जाता और किसी तीसरे पक्ष की सामग्री नहीं जोड़ी जाती। बनाए गए ईमेल पते को अप्रयुक्त नहीं, बल्कि अनुपयोगी मानें, क्योंकि कोई भी यादृच्छिक स्ट्रिंग संयोग से किसी असली पते से मेल खा सकती है।
+
+
+
+
क्या मुझे दूसरी मशीन पर ठीक वही फ़ाइलें मिलेंगी?
+
+
हाँ, बाइट-दर-बाइट, उसी रेसिपी और उसी सीड के साथ। प्रोजेक्ट हर बदलाव पर इसका परीक्षण करता है, और इसे तोड़ने के लिए मुख्य संस्करण बढ़ाना पड़ता है। इसी वजह से आप बड़े बाइनरी फ़िक्स्चर की जगह एक छोटी रेसिपी कमिट कर सकते हैं।
+
+
+
+
क्या इसे इंटरनेट कनेक्शन चाहिए?
+
+
कभी नहीं। कोई टेलीमेट्री नहीं, कोई अपडेट जाँच नहीं और कोई क्लाउड क्लाइंट नहीं, और कमांड लाइन बाइनरी में नेटवर्क स्टैक कंपाइल ही नहीं किया गया है। यह बिना नेटवर्क की मशीन पर और बंद कॉर्पोरेट माहौल में भी चलता है।
+
+
+
+
अगर मैं ऐसा आकार माँगूँ जो कोई फ़ॉर्मैट हासिल नहीं कर सकता, तो क्या होता है?
+
+
आपको एक त्रुटि मिलती है जो फ़ॉर्मैट, सबसे छोटा संभव आकार, उस न्यूनतम सीमा का कारण और इसके बदले क्या करें यह बताती है, और कोई फ़ाइल नहीं लिखी जाती। टूल कभी आकार को चुपचाप राउंड नहीं करता। हर न्यूनतम सीमा फ़ॉर्मैट पेज पर सूचीबद्ध है।
+
tfg formats png
+
+
+
+
क्या मैं जानबूझकर टूटी हुई फ़ाइल बना सकता हूँ?
+
+
हाँ। --damage zero-head जोड़ें और फ़ाइल ठीक माँगे गए आकार में निकलती है, शुरुआती बाइट शून्य से ढके हुए, इसलिए रीडर उसे ठुकरा देता है, और मैनिफ़ेस्ट कहता है कि आपके सिस्टम को उसे अस्वीकार करना चाहिए। ब्योरा खराब टेस्ट फ़ाइलों वाले पेज पर है।
7z, mp3 और mp4। आज 26 फ़ॉर्मैट शुरू से अंत तक काम करते हैं।
+
+
+
+
मैं इसे किन सिस्टम पर चला सकता हूँ?
+
+
कमांड लाइन Windows और Linux पर Intel और ARM दोनों पर, और Apple Silicon Mac पर चलती है। डेस्कटॉप विंडो Intel पर Windows, Intel पर Linux और Apple Silicon Mac के लिए आती है। Intel Mac समर्थित नहीं हैं और उनके लिए कुछ नहीं बनाया जाता।
+
+
+
+
क्या मुझे कुछ इंस्टॉल करना होगा?
+
+
नहीं। अपने सिस्टम का आर्काइव डाउनलोड करें, खोलें और बाइनरी चलाएँ। कोई इंस्टॉलर नहीं, जोड़ने के लिए कोई रनटाइम नहीं और सुलझाने के लिए कोई निर्भरता नहीं। अगर आपके पास Go है तो एक ही go install कमांड भी काम करती है।
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
हज़ारों फ़ाइलों पर रन Windows पर धीमा क्यों है?
+
+
क्योंकि Windows हर उस पाथ के लिए ज़्यादा वसूलता है जिसे वह देखता है, और हज़ारों फ़ाइलों से गुज़रने वाली कमांड हज़ारों पाथ देखती है। 1 kB की 3000 फ़ाइलों वाली एक मशीन पर मापने पर, verify को Windows पर लगभग 0.9 सेकंड और कंटेनर में Linux पर लगभग 0.2 सेकंड लगे। छोटा आउटपुट पाथ Windows का आँकड़ा घटाता है, क्योंकि फ़ाइलों के ऊपर का हर फ़ोल्डर उसमें शामिल होता है जिसे देखा जाता है।
+ इनमें से हर एक उस फ़ॉर्मैट की असली फ़ाइल है। वह अपने सॉफ़्टवेयर में खुलती है और
+ उसमें ठीक उतने बाइट हैं जितने आपने माँगे। इनमें से कोई भी एक्सटेंशन चिपकाए गए भराव के शून्य नहीं
+ है।
+
+
+
+
+
+
+
फ़ॉर्मैट
+
नाम
+
एक्सटेंशन
+
सबसे छोटी फ़ाइल
+
पूर्णता
+
जाँच का साधन
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
लागू नहीं
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
लागू नहीं
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
लागू नहीं
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
कॉलम का अर्थ
+
+
+
सबसे छोटी फ़ाइल
+
+ उस फ़ॉर्मैट के लिए यह टूल जितने कम से कम बाइट स्वीकार करेगा, उस लेबल समेत जो वह फ़ाइल के अंदर लिखता
+ है। इससे कम माँगें और आपको न्यूनतम सीमा और उसका कारण बताने वाली त्रुटि मिलती है, गलत आकार की
+ फ़ाइल कभी नहीं।
+
+
+
+
पूर्णता
+
+ फ़ाइल कितनी पूरी है। full का मतलब है कि फ़ॉर्मैट को सच में पार्स करने वाला रीडर उसे
+ स्वीकार करता है, सिर्फ़ यह नहीं कि एक्सटेंशन मिलता है।
+
+
+
+
जाँच का साधन
+
+ वह स्वतंत्र रीडर जो फ़ॉर्मैट भेजे जाने से पहले हर बनाई गई फ़ाइल खोलता है - एक अलग कार्यान्वयन, हमारा
+ अपना कोड नहीं जो अपना ही गृहकार्य जाँचे।
+
+
+
+
+ हर फ़ॉर्मैट बाइट तक दोहराया भी जाता है: वही रेसिपी और वही सीड किसी भी मशीन पर एक जैसी फ़ाइलें बनाते
+ हैं, और इसी से फ़िक्स्चर की जगह रेसिपी कमिट करना सुरक्षित होता है।
+
+
+
+
+
हर फ़ॉर्मैट की स्वीकार की जाने वाली सेटिंग
+
+ ज़्यादातर फ़ॉर्मैट की अपनी सेटिंग होती हैं - इमेज के आयाम, JPEG गुणवत्ता, PDF के पेज, स्प्रेडशीट की
+ पंक्तियाँ और कॉलम, आर्काइव के अंदर कितनी प्रविष्टियाँ जाएँ। इन्हें कमांड लाइन पर --set
+ key=value से, या रेसिपी में properties: के नीचे सेट करें।
+
2024-02-29 या 2024-02-29T13:45:00+02:00 जैसी तारीख, या none
+
+
+
+
modified
+
2024-02-29 या 2024-02-29T13:45:00+02:00 जैसी तारीख, या none
+
+
+
png
+
width
+
1 - 20000 पिक्सेल
+
+
+
+
height
+
1 - 20000 पिक्सेल
+
+
+
pptx
+
slides
+
1 - 500 स्लाइड
+
+
+
svg
+
width
+
1 - 20000 पिक्सेल
+
+
+
+
height
+
1 - 20000 पिक्सेल
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
किसी फ़ॉर्मैट का id, जैसा tfg formats सूचीबद्ध करता है
+
+
+
+
entry_size
+
2mb जैसा आकार
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
सही या गलत
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 पिक्सेल
+
+
+
+
height
+
1 - 20000 पिक्सेल
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
सही या गलत
+
+
+
wav
+
sample_rate
+
8000 - 192000 हर्ट्ज़
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 पिक्सेल
+
+
+
+
height
+
1 - 16383 पिक्सेल
+
+
+
xlsx
+
rows
+
1 - 200000 पंक्तियाँ
+
+
+
+
columns
+
1 - 32768 कॉलम
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
सही या गलत
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
किसी फ़ॉर्मैट का id, जैसा tfg formats सूचीबद्ध करता है
+
+
+
+
entry_size
+
2mb जैसा आकार
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
सही या गलत
+
+
+
+
password
+
पासवर्ड, सादे टेक्स्ट में
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ किसी सेटिंग की स्वीकार्य सीमा से बाहर का मान एक संदेश के साथ ठुकरा दिया जाता है जो सेटिंग, मान्य
+ सीमा और इसके बदले क्या इस्तेमाल करें यह बताता है। अज्ञात सेटिंग भी त्रुटि है, कभी चुपचाप
+ डिफ़ॉल्ट नहीं - चुपचाप मान ली गई टाइपो गलत सेटिंग की फ़ाइल देती है और एक घंटा यह सोचने में जाता
+ है कि जिस टेस्ट को विफल होना था वह पास क्यों हो रहा है।
+
+
+ जो बिल्ड आपके पास है उसमें कोई फ़ॉर्मैट ठीक क्या स्वीकार करता है, यह देखने के लिए tfg formats
+ <id> चलाएँ।
+
+
+
+
+
आर्काइव में असली फ़ाइलें होती हैं
+
+ targz और zip को
+ खाली खोल छोड़ने के बजाय प्रविष्टियों से भरा जा सकता है। बनाया गया आर्काइव सच में वे दस्तावेज़
+ रखता है जिनका वह दावा करता है, इसलिए टेस्ट के दौरान उसे खोलने वाली कोई भी चीज़ अंदर असली फ़ाइलें
+ पाती है।
+
+ PDF, PNG, DOCX, ZIP - कुल 26 फ़ॉर्मैट, और हर एक असली फ़ाइल है
+ जो अपने सॉफ़्टवेयर में खुलती है, ठीक उसी आकार में जो आपने माँगा। हर रन यह भी
+ लिखता है कि आपके एप्लिकेशन को हर फ़ाइल के साथ क्या करना चाहिए। कमांड लाइन और डेस्कटॉप विंडो,
+ मुफ़्त और ओपन सोर्स, पूरी तरह आपकी मशीन पर चलता है।
+
मुफ़्त और ओपन सोर्स, GPL-3.0। साइन अप की ज़रूरत नहीं। Windows और macOS के डाउनलोड हस्ताक्षरित हैं और बिना चेतावनी के शुरू होते हैं।
+
+
+
+
+ फ़ाइलों का बैच लिखने के लिए तैयार डेस्कटॉप विंडो। कमांड लाइन के पीछे वही इंजन चलता है।
+
+
+
+
+
+ 26
+
असली फ़ॉर्मैट, हर एक अपने सॉफ़्टवेयर में खुलता है
+
+
+ 1 बाइट
+
आपके माँगे हर आकार की सटीकता, कभी चुपचाप राउंड नहीं की जाती
+
+
+ 0
+
कहीं भी कनेक्शन - न खाता, न टेलीमेट्री, न अपडेट जाँच
+
+
+
+
+
समस्या
+
एक टेस्ट फ़ाइल बनाना आसान है। सही हज़ार बनाना थकाऊ हिस्सा है
+
आप ऐसे सॉफ़्टवेयर को टेस्ट कर रहे हैं जो लोगों से फ़ाइलें लेता है। देर-सबेर आपको चाहिए होगा:
+
+
ठीक 10 MB की एक PDF, यह पता करने के लिए कि अपलोड सीमा असली है या नहीं
+
उस सीमा के दोनों ओर की तीन फ़ाइलें, एक से चूकने वाली गलतियाँ पकड़ने के लिए
+
10,000 लॉग फ़ाइलें, यह देखने के लिए कि फ़ोल्डर बड़ा होने पर रात का जॉब क्या करता है
+
एक ZIP जिसमें सच में 200 दस्तावेज़ हों, सही एक्सटेंशन वाला खोखला खोल नहीं
+
एक 4 GB की फ़ाइल, बिना अपनी रिपॉज़िटरी में 4 GB की फ़ाइल रखे
+
आपके लैपटॉप और बिल्ड सर्वर पर एक जैसे फ़िक्स्चर, बाइट-दर-बाइट
+
+
+ यही वह है जिसे यह बदलता है। यह QA इंजीनियरों, टेस्ट ऑटोमेशन और हर उस व्यक्ति के लिए बना है जिसके कोड
+ के पीछे अपलोड फ़ॉर्म, इंपोर्ट रूटीन, पार्सर या स्टोरेज कोटा है।
+
+
+
+
+
यह अलग क्यों है
+
दूसरे जनरेटर बाइट पर रुक जाते हैं। यह वह बताता है जो आपका टेस्ट असल में पूछता है
+
+ फ़ाइलों से भरा फ़ोल्डर आपको फिर भी तय करने देता है कि हर फ़ाइल क्या साबित करे। यहाँ हर रन फ़ाइलों के
+ बगल में एक manifest.json लिखता है - जो कुछ बना उसकी सादी सूची, और हर प्रविष्टि के
+ लिए एक घोषित अपेक्षा।
+
+
मान लें कि आपका अपलोड एंडपॉइंट 1 MB की अनुमति देता है। उस रेखा पर आने वाली तीन फ़ाइलें माँगें:
जहाँ जवाब आपकी अपनी नीति पर निर्भर है, वहाँ मैनिफ़ेस्ट यही कहता है
+
+ वह कोई अपेक्षा गढ़ने के बजाय unspecified दर्ज करता है। अंदाज़ा लगाने वाला जनरेटर झूठी
+ विफलताएँ पैदा करता है, और झूठा शोर मचाने वाला टेस्ट सूट आख़िरकार बंद कर दिया जाता है।
+
+
+
+
+
+
प्रीसेट
+
सवाल चुनें, पूरा सेट पाएँ
+
+ प्रीसेट एक टेस्ट सवाल के इर्द-गिर्द बनाया गया टेस्ट फ़ाइलों का सेट है, ताकि आपको खुद न सोचना पड़े कि
+ कौन सी फ़ाइल क्या साबित करती है। हर एक का एक पेज है जो बताता है कि वह आम तौर पर क्या पकड़ता है,
+ सेट में क्या है और वह कौन सी सेटिंग लेता है।
+
+ दस हज़ार लॉग फ़ाइलें, हर एक एक से आठ किलोबाइट के बीच, आकार सीड से निकाले गए ताकि कल वही सेट मिले।
+ हर रन को उसकी अपनी डायरेक्टरी दें - रन ने जो लिखा उसका एकमात्र रिकॉर्ड
+ मैनिफ़ेस्ट है, इसलिए टूल उसके ऊपर दूसरा लिखने से इनकार कर देता है:
+
+ आकार 1024 के गुणकों में गिने जाते हैं, जैसा आपका फ़ाइल मैनेजर करता है, इसलिए 2mb का
+ मतलब 2097152 बाइट है। सादी बाइट संख्या भी चलती है। दस्तावेज़ीकरण में
+ रेसिपी, मैनिफ़ेस्ट और एग्ज़िट कोड समझाए गए हैं।
+
+
+
+
+
आपको क्या मिलता है
+
बिना निगरानी के चलने वाले सूट के लिए बना
+
+
+
सटीक आकार, बाइट तक
+
10485761 बाइट माँगें और ठीक वही पाएँ। जिस आकार तक कोई फ़ॉर्मैट नहीं पहुँच सकता, वह कारण सहित त्रुटि है, गलत आकार की फ़ाइल कभी नहीं।
+
+
+
26 असली फ़ॉर्मैट
+
एक्सटेंशन वाले भराव के शून्य नहीं। बनाई गई PNG इमेज व्यूअर में खुलती है, DOCX Word में खुलता है, ZIP खुल जाता है। हर एक को भेजने से पहले स्वतंत्र रीडरों से जाँचा जाता है।
+
+
+
टेस्ट ऑरेकल जैसा मैनिफ़ेस्ट
+
पाथ, आकार, SHA-256, फ़ॉर्मैट, सीड, टूल का संस्करण - और आपके सिस्टम को फ़ाइल के साथ क्या करना चाहिए।
+
+
+
दोहराए जा सकने वाला
+
वही रेसिपी और वही सीड, वही बाइट, किसी भी मशीन पर। बड़े बाइनरी फ़िक्स्चर की जगह एक छोटी YAML रेसिपी कमिट करें।
+
+
+
दो इंटरफ़ेस, एक इंजन
+
CI के लिए बनी कमांड लाइन और खोजपरक टेस्टिंग के लिए डेस्कटॉप विंडो। कोई भी दूसरे का घटाया हुआ रूप नहीं है, और एक टेस्ट दोनों की क्षमता-दर-क्षमता तुलना करता है।
+
+
+
पूरी तरह ऑफ़लाइन
+
कोई खाता नहीं, कोई क्लाउड नहीं, कोई टेलीमेट्री नहीं, कोई अपडेट जाँच नहीं। कमांड लाइन बाइनरी में नेटवर्क स्टैक कंपाइल ही नहीं किया गया है।
+
+
+
+
+
+
डाउनलोड
+
अपने सिस्टम का बिल्ड चुनें
+
+ आर्काइव खोलें और चलाएँ। tfg कमांड लाइन है और tfg-gui डेस्कटॉप विंडो। कोई
+ इंस्टॉलर नहीं और आपकी मशीन पर जोड़ने को कुछ नहीं।
+
+
+
+
+
+
सिस्टम
+
कमांड लाइन
+
डेस्कटॉप विंडो
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
क्या हस्ताक्षरित है, और क्या नहीं
+
+ Windows और macOS के डाउनलोड हस्ताक्षरित हैं, इसलिए वे अज्ञात डेवलपर की चेतावनी के बिना शुरू होते
+ हैं। Linux वाले नहीं हैं, क्योंकि डेस्कटॉप Linux में उन पर हस्ताक्षर करने का कोई समकक्ष तरीका
+ नहीं है। हर आर्काइव रिलीज़ पेज पर verify-SHA256SUMS.txt में सूचीबद्ध है, ताकि आप
+ जाँच सकें कि आपने क्या डाउनलोड किया।
+
क्या फ़ॉर्मैट की अनुमति जितनी छोटी वैध फ़ाइल पास हो जाती है?
+
+ empty-and-minimal प्रीसेट एक कमांड में इस सवाल के लिए असली टेस्ट फ़ाइलों का पूरा सेट बनाता है,
+ और उनके बगल में एक manifest.json जो बताता है कि आपके सिस्टम को हर फ़ाइल पर क्या
+ प्रतिक्रिया देनी चाहिए। नीचे सब कुछ इस संस्करण के डिफ़ॉल्ट पर प्रोग्राम से पढ़ा गया है।
+
+
+
+
+
यह आम तौर पर क्या पकड़ता है?
+
+
एक वैध फ़ाइल जो बहुत छोटी होने के कारण ठुकरा दी जाती है, क्योंकि जाँच बाइट पढ़ने के बजाय गिनती है
+
एक खाली फ़ाइल जो रिपोर्ट होने के बजाय रीडर को क्रैश कर देती है
+
एक पिक्सेल चौड़ी तस्वीर जो थंबनेल तक के रास्ते में शून्य से भाग देती है
+
ऐसा स्टोरेज जो शून्य बाइट को असफल अपलोड समझकर बार-बार कोशिश करता रहता है
+
+
+
+
+
+
सेट में क्या है?
+
डिफ़ॉल्ट पर, जैसा tfg preset show empty-and-minimal बताता है:
क्या मेरा सिस्टम ऐसा फ़ाइल नाम सहेजेगा, दिखाएगा और लौटाएगा जिसकी उसे उम्मीद नहीं थी?
+
+ filename-handling प्रीसेट एक कमांड में इस सवाल के लिए असली टेस्ट फ़ाइलों का पूरा सेट बनाता है,
+ और उनके बगल में एक manifest.json जो बताता है कि आपके सिस्टम को हर फ़ाइल पर क्या
+ प्रतिक्रिया देनी चाहिए। नीचे सब कुछ इस संस्करण के डिफ़ॉल्ट पर प्रोग्राम से पढ़ा गया है।
+
+
+
+
+
यह आम तौर पर क्या पकड़ता है?
+
+
ऐसा नाम जो स्क्रीन, लॉग या सूची में किसी और नाम जैसा दिखता है
+
ऐसा नाम जो अपलोड और स्टोरेज के बीच कट जाता है, छँट जाता है या दोबारा लिख दिया जाता है
+
अक्षरों में गिनी जाने वाली लंबाई की सीमा, जबकि स्टोरेज बाइट गिनता है
+
+
+
+
+
+
सेट में क्या है?
+
डिफ़ॉल्ट पर, जैसा tfg preset show filename-handling बताता है:
+
+
+
+
फ़ाइलें
50
+
इसकी रेसिपी में टार्गेट
50
+
कुल आकार
51 200 B
+
फ़ॉर्मैट
txt
+
+
+
+
और उस सेट का मैनिफ़ेस्ट आपके सिस्टम से क्या अपेक्षा रखता है:
+
+
+
+
अपेक्षित
अर्थ
फ़ाइलें
+
+
+
accept
आपके सिस्टम को फ़ाइल मंज़ूर करनी चाहिए।
4
+
unspecified
यह आपके सिस्टम के नियमों पर निर्भर है। आप तय करें, फिर जाँचें कि जो होता है वही है जो आप चाहते थे।
46
+
+
+
+
+
+
+
आप क्या बदल सकते हैं?
+
+
+
+
सेटिंग
लेती है
डिफ़ॉल्ट
क्या करती है
+
+
+
+
--format
+
फ़ॉर्मैट पेज से एक फ़ॉर्मैट id
+
txt
+
सेट की हर फ़ाइल का फ़ॉर्मैट। यह टूल का अपना फ़्लैग है, और प्रीसेट बस उसे एक डिफ़ॉल्ट देता है।
+
+
+
+
+
+
+
+
इसे कैसे चलाएँ?
+
देखें कि सेट की क़ीमत क्या होगी, उसे बनाएँ, या संपादन के लिए उसकी रेसिपी लें:
+ प्रीसेट एक सवाल के इर्द-गिर्द बनाया गया टेस्ट फ़ाइलों का पूरा सेट है, एक मैनिफ़ेस्ट के साथ जो बताता
+ है कि आपके सिस्टम को हर फ़ाइल पर क्या प्रतिक्रिया देनी चाहिए। आप सवाल चुनते हैं, टूल सेट बनाता है।
+ हर प्रीसेट का अपना पेज है जो बताता है कि वह आम तौर पर क्या पकड़ता है, सेट में क्या है और वह कौन सी
+ सेटिंग लेता है।
+
क्या मेरा अपलोड फ़ॉर्म वह लेता है जो उसे लेना चाहिए और बाकी को लौटा देता है?
+
upload-validation
+
+
+
+
+
प्रीसेट और रेसिपी में क्या अंतर है?
+
+ अंदर से, कोई नहीं। प्रीसेट वह रेसिपी है जो टूल कुछ सेटिंग से आपके लिए लिखता है। tfg preset
+ eject उस रेसिपी को छापता है ताकि आप उसे अपने टेस्ट के बगल में रखकर संपादित कर सकें, और
+ आपकी अपनी रेसिपी एक पंक्ति से प्रीसेट पर आगे बन सकती है, extends: preset: और उसके
+ बाद उसका id।
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
क्या मैं डिफ़ॉल्ट पर भरोसा कर सकता हूँ?
+
+ फ़ाइलों के लिए, हाँ। ऐसी संख्या के लिए जो सिर्फ़ आपका सिस्टम जानता है, जैसे अपलोड फ़ॉर्म की सीमा,
+ डिफ़ॉल्ट हमारी अस्थायी जगह-धारक संख्या होती है, और टूल जब भी ऐसा कोई इस्तेमाल करता है तब यह
+ बताता है। हर प्रीसेट का पेज उन सेटिंग पर निशान लगाता है, और tfg preset show कुछ भी
+ लिखे जाने से पहले यह बता देता है।
+
क्या आकार की सीमा ठीक वहीं लागू होती है जहाँ उसकी घोषणा की गई है?
+
+ size-boundaries प्रीसेट एक कमांड में इस सवाल के लिए असली टेस्ट फ़ाइलों का पूरा सेट बनाता है,
+ और उनके बगल में एक manifest.json जो बताता है कि आपके सिस्टम को हर फ़ाइल पर क्या
+ प्रतिक्रिया देनी चाहिए। नीचे सब कुछ इस संस्करण के डिफ़ॉल्ट पर प्रोग्राम से पढ़ा गया है।
+
+
+
+
+
यह आम तौर पर क्या पकड़ता है?
+
+
सीमा पर एक से चूकने वाली गलतियाँ
+
MB और MiB का घालमेल, जो 4.8 प्रतिशत का फ़र्क है और ऐसी फ़ाइल निकल जाने देने के लिए काफ़ी है जिसे नहीं निकलना चाहिए
+
सीमा जो ब्राउज़र में लागू होती है, सर्वर पर नहीं
+
+
+
+
+
+
सेट में क्या है?
+
डिफ़ॉल्ट पर, जैसा tfg preset show size-boundaries बताता है:
+
+
+
+
फ़ाइलें
7
+
इसकी रेसिपी में टार्गेट
7
+
कुल आकार
73 400 320 B
+
फ़ॉर्मैट
pdf
+
+
+
+
और उस सेट का मैनिफ़ेस्ट आपके सिस्टम से क्या अपेक्षा रखता है:
+
+
+
+
अपेक्षित
अर्थ
फ़ाइलें
+
+
+
accept
आपके सिस्टम को फ़ाइल मंज़ूर करनी चाहिए।
4
+
reject
आपके सिस्टम को फ़ाइल अस्वीकार करनी चाहिए।
3
+
+
+
+
+
+
+
आप क्या बदल सकते हैं?
+
+
+
+
सेटिंग
लेती है
डिफ़ॉल्ट
क्या करती है
+
+
+
+
--limit
+
2mb जैसा आकार
+
10mb
+
आपके सिस्टम की घोषित आकार सीमा। बाकी सब कुछ इसी से नापा जाता है। यह डिफ़ॉल्ट हमारी अस्थायी जगह-धारक संख्या है, आपके सिस्टम का मान नहीं। अपना मान दें।
+
+
+
--spread
+
अल्पविराम से अलग किए गए आकार
+
1B,1kb,1mb
+
सीमा के दोनों ओर कितनी दूर तक जाना है, आकारों की सूची के रूप में।
+
+
+
--format
+
फ़ॉर्मैट पेज से एक फ़ॉर्मैट id
+
pdf
+
सेट की हर फ़ाइल का फ़ॉर्मैट। यह टूल का अपना फ़्लैग है, और प्रीसेट बस उसे एक डिफ़ॉल्ट देता है।
+
+
+
+
+
+
+
+
इसे कैसे चलाएँ?
+
देखें कि सेट की क़ीमत क्या होगी, उसे बनाएँ, या संपादन के लिए उसकी रेसिपी लें:
क्या मेरा टेबल इंपोर्ट वह झेल पाता है जो असली टूल एक्सपोर्ट करते हैं?
+
+ tabular-import प्रीसेट एक कमांड में इस सवाल के लिए असली टेस्ट फ़ाइलों का पूरा सेट बनाता है,
+ और उनके बगल में एक manifest.json जो बताता है कि आपके सिस्टम को हर फ़ाइल पर क्या
+ प्रतिक्रिया देनी चाहिए। नीचे सब कुछ इस संस्करण के डिफ़ॉल्ट पर प्रोग्राम से पढ़ा गया है।
+
+
+
+
+
यह आम तौर पर क्या पकड़ता है?
+
+
अर्धविराम वाली फ़ाइल जो एक ही कॉलम की तरह पढ़ी जाती है, क्योंकि डेलिमिटर खोजा नहीं गया, मान लिया गया
+
CRLF फ़ाइल जो पंक्तियों में बँट जाती है और हर पंक्ति के बाद एक खाली पंक्ति आ जाती है
+
बिना हेडर की टेबल जिसकी डेटा की पहली पंक्ति कॉलम नाम समझकर निगल ली जाती है
+
ऐसा इंपोर्ट जो दिखा सकने वाले कॉलम रखता है और बाकी चुपचाप गिरा देता है
+
ऐसा रीडर जो JSON रिकॉर्ड एक-एक पंक्ति में लेता है और पहले इंडेंट वाले दस्तावेज़ पर रुक जाता है
+
+
+
+
+
+
सेट में क्या है?
+
डिफ़ॉल्ट पर, जैसा tfg preset show tabular-import बताता है:
+
+
+
+
फ़ाइलें
13
+
इसकी रेसिपी में टार्गेट
13
+
कुल आकार
3 080 060 B
+
फ़ॉर्मैट
csv, json, xlsx
+
+
+
+
और उस सेट का मैनिफ़ेस्ट आपके सिस्टम से क्या अपेक्षा रखता है:
+
+
+
+
अपेक्षित
अर्थ
फ़ाइलें
+
+
+
accept
आपके सिस्टम को फ़ाइल मंज़ूर करनी चाहिए।
8
+
unspecified
यह आपके सिस्टम के नियमों पर निर्भर है। आप तय करें, फिर जाँचें कि जो होता है वही है जो आप चाहते थे।
5
+
+
+
+
+
+
+
आप क्या बदल सकते हैं?
+
+
+
+
सेटिंग
लेती है
डिफ़ॉल्ट
क्या करती है
+
+
+
+
--rows
+
1 - 200000 पंक्तियाँ
+
1000
+
स्प्रेडशीट में कितनी पंक्तियाँ हैं। फ़ाइल ठीक उसी आकार में लिखी जाती है जितने में उतनी पंक्तियाँ पैक होती हैं, इसलिए ऊपर का बजट इस मान के साथ खिसकता है।
+
+
+
--columns
+
1 - 32768 कॉलम
+
10
+
स्प्रेडशीट की हर पंक्ति में कितने कॉलम हैं। पंक्तियों गुणा कॉलम की एक ऊपरी सीमा है, और उससे आगे माँगने पर कुछ भी लिखे जाने से पहले ही इनकार कर दिया जाता है।
+
+
+
+
+
+
+
+
इसे कैसे चलाएँ?
+
देखें कि सेट की क़ीमत क्या होगी, उसे बनाएँ, या संपादन के लिए उसकी रेसिपी लें:
क्या मेरा रीडर जानता है कि फ़ाइल किस एन्कोडिंग में है, या अंदाज़ा लगा रहा है?
+
+ text-encoding प्रीसेट एक कमांड में इस सवाल के लिए असली टेस्ट फ़ाइलों का पूरा सेट बनाता है,
+ और उनके बगल में एक manifest.json जो बताता है कि आपके सिस्टम को हर फ़ाइल पर क्या
+ प्रतिक्रिया देनी चाहिए। नीचे सब कुछ इस संस्करण के डिफ़ॉल्ट पर प्रोग्राम से पढ़ा गया है।
+
+
+
+
+
यह आम तौर पर क्या पकड़ता है?
+
+
ऐसा रीडर जो UTF-8 मान लेता है और UTF-16 फ़ाइल को तीन में से एक अक्षर या डिब्बों की पंक्तियों की तरह दिखाता है
+
बाइट ऑर्डर मार्क जो सामग्री की तरह पढ़ा जाता है, जिससे इंपोर्ट का पहला फ़ील्ड तीन अनजान अक्षरों से शुरू होता है
+
ऐसा इंपोर्टर जो शुरुआती बाइट से एन्कोडिंग का अंदाज़ा लगाता है और लंबी फ़ाइल पर अलग अंदाज़ा लगाता है
+
CRLF फ़ाइल जो हर पंक्ति के बाद खाली पंक्ति के साथ बँट जाती है, या कैरिज रिटर्न जो आख़िरी फ़ील्ड में रह जाता है
+
+
+
+
+
+
सेट में क्या है?
+
डिफ़ॉल्ट पर, जैसा tfg preset show text-encoding बताता है:
+
+
+
+
फ़ाइलें
20
+
इसकी रेसिपी में टार्गेट
20
+
कुल आकार
81 920 B
+
फ़ॉर्मैट
csv, log, md, txt, xml
+
+
+
+
और उस सेट का मैनिफ़ेस्ट आपके सिस्टम से क्या अपेक्षा रखता है:
+
+
+
+
अपेक्षित
अर्थ
फ़ाइलें
+
+
+
accept
आपके सिस्टम को फ़ाइल मंज़ूर करनी चाहिए।
10
+
unspecified
यह आपके सिस्टम के नियमों पर निर्भर है। आप तय करें, फिर जाँचें कि जो होता है वही है जो आप चाहते थे।
10
+
+
+
+
+
+
+
आप क्या बदल सकते हैं?
+
+
+
+
सेटिंग
लेती है
डिफ़ॉल्ट
क्या करती है
+
+
+
+
--sample
+
2mb जैसा आकार
+
4kb
+
सेट की हर फ़ाइल कितनी बड़ी है। UTF-16 हर अक्षर के लिए दो बाइट रखता है, इसलिए विषम संख्या अस्वीकार हो जाती है।
+
+
+
+
+
+
+
+
इसे कैसे चलाएँ?
+
देखें कि सेट की क़ीमत क्या होगी, उसे बनाएँ, या संपादन के लिए उसकी रेसिपी लें:
क्या मेरा अपलोड फ़ॉर्म वह लेता है जो उसे लेना चाहिए और बाकी को लौटा देता है?
+
+ upload-validation प्रीसेट एक कमांड में इस सवाल के लिए असली टेस्ट फ़ाइलों का पूरा सेट बनाता है,
+ और उनके बगल में एक manifest.json जो बताता है कि आपके सिस्टम को हर फ़ाइल पर क्या
+ प्रतिक्रिया देनी चाहिए। नीचे सब कुछ इस संस्करण के डिफ़ॉल्ट पर प्रोग्राम से पढ़ा गया है।
+
+
+
+
+
यह आम तौर पर क्या पकड़ता है?
+
+
सीमा जो ब्राउज़र में लागू होती है, सर्वर पर नहीं
+
SVG या HTML फ़ाइल जिसे तस्वीर या सादा टेक्स्ट समझ लिया जाता है, जो फ़ॉर्म से स्क्रिप्ट निकाल ले जाने का एक तरीका है
+
फ़ाइल जो सिर्फ़ एक्सटेंशन से जाँची जाती है और कभी खोली नहीं जाती, इसलिए .jpg नाम की PDF निकल जाती है
+
ऐसा फ़ॉर्म जो आकार देखने से पहले पूरी बॉडी मेमोरी में पढ़ लेता है
+
PHOTO.JPG नाम का अपलोड जो ठुकरा दिया जाता है जबकि photo.jpg ले लिया जाता है, या उल्टा
+
रिक्त स्थान, कोष्ठक या ASCII से बाहर के अक्षरों वाला नाम जो बिना बदले डिस्क पर लिख दिया जाता है
+
+
+
+
+
+
सेट में क्या है?
+
डिफ़ॉल्ट पर, जैसा tfg preset show upload-validation बताता है:
+
+
+
+
फ़ाइलें
71
+
इसकी रेसिपी में टार्गेट
22
+
कुल आकार
120 639 488 B
+
फ़ॉर्मैट
html, jpg, pdf, png, svg, txt
+
+
+
+
और उस सेट का मैनिफ़ेस्ट आपके सिस्टम से क्या अपेक्षा रखता है:
+
+
+
+
अपेक्षित
अर्थ
फ़ाइलें
+
+
+
accept
आपके सिस्टम को फ़ाइल मंज़ूर करनी चाहिए।
56
+
reject
आपके सिस्टम को फ़ाइल अस्वीकार करनी चाहिए।
10
+
unspecified
यह आपके सिस्टम के नियमों पर निर्भर है। आप तय करें, फिर जाँचें कि जो होता है वही है जो आप चाहते थे।
5
+
+
+
+
+
+
+
आप क्या बदल सकते हैं?
+
+
+
+
सेटिंग
लेती है
डिफ़ॉल्ट
क्या करती है
+
+
+
+
--limit
+
2mb जैसा आकार
+
10mb
+
आपके अपलोड फ़ॉर्म की घोषित आकार सीमा। यह सेट इसके दोनों ओर एक-एक क़दम लेता है - हर दूरी की फ़ाइल के लिए size-boundaries प्रीसेट चलाएँ। यह डिफ़ॉल्ट हमारी अस्थायी जगह-धारक संख्या है, आपके सिस्टम का मान नहीं। अपना मान दें।
+
+
+
--allow
+
अल्पविराम से अलग किए गए फ़ॉर्मैट id
+
jpg,png,pdf
+
आपका फ़ॉर्म किन प्रकारों को स्वीकार करे। हर प्रकार उसी प्रकार की असली फ़ाइल बन जाता है, और ये पूरे सेट का सकारात्मक नियंत्रण हैं।
+
+
+
--deny
+
अल्पविराम से अलग किए गए एक्सटेंशन
+
svg,html,exe,sh
+
आपका फ़ॉर्म किन एक्सटेंशन को ठुकराए। जिस एक्सटेंशन का इस बिल्ड में कोई फ़ॉर्मैट नहीं है, उसे भी उसी नाम की एक फ़ाइल मिलती है जिसमें सादा टेक्स्ट होता है।
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
एकमात्र बड़ी फ़ाइल सीमा से कितनी आगे जाती है। जहाँ सीमा के कई गुना लिखना डिस्क के लायक न हो, वहाँ इसे बंद कर दें।
+
+
+
--bulk
+
0 - 10000 फ़ाइलें
+
50
+
एक साथ अपलोड में कितनी फ़ाइलें हैं। शून्य होने पर वह समूह सेट से पूरी तरह हट जाता है।
+
+
+
+
+
+
+
+
इसे कैसे चलाएँ?
+
देखें कि सेट की क़ीमत क्या होगी, उसे बनाएँ, या संपादन के लिए उसकी रेसिपी लें:
+ रिपॉज़िटरी में बाइनरी फ़िक्स्चर उसके इतिहास में हमेशा के लिए रह जाता है, diff में उसकी समीक्षा नहीं
+ हो सकती, और फ़ाइल बड़ी हो तो वह संभव ही नहीं रहता। इसके बजाय फ़ाइलें पाइपलाइन के भीतर रेसिपी से
+ बनाएँ। रेसिपी पाठ है, बाइट हर बार एक जैसे निकलते हैं, और आख़िरी कदम साबित करता है कि कुछ नहीं
+ खिसका।
+
+
+
+
छोटा जवाब
+
+ tfg इंस्टॉल करें, टेस्ट से पहले tfg generate fixtures.yaml --out
+ ./fixtures चलाएँ और उनके बाद tfg verify ./fixtures/manifest.json। दोनों कदम
+ अपने आप बिल्ड को विफल करते हैं, एक ऐसे एग्ज़िट कोड के साथ जो कारण बताता है।
+
+
+
+
+
कमिट क्यों न करें
+
फ़िक्स्चर रिपॉज़िटरी में क्यों नहीं रहना चाहिए
+
+
+ यह इतिहास में रह जाता है। बाद में बाइनरी हटाने से क्लोन छोटा नहीं होता, क्योंकि
+ उसका हर संस्करण अब भी वहीं है।
+
+
+ diff नहीं दिखाता कि क्या बदला। समीक्षक को बस दिखता है कि PDF अलग है, और कुछ नहीं।
+ रेसिपी एक पंक्ति से बदलती है।
+
+
+ बड़ी फ़ाइलें समाती नहीं। GitHub 100 MB से बड़ी फ़ाइल वाले पुश को ठुकरा देता है,
+ इसलिए 500 MB की अपलोड सीमा के टेस्ट के पास कमिट करने को कुछ नहीं है।
+
+
+
+ कमिट करने की चीज़ रेसिपी है। वही रेसिपी और वही सीड हर मशीन पर वही बाइट लिखते हैं, इसलिए पाइपलाइन में
+ बनी फ़ाइल वही फ़ाइल है जो आपके लैपटॉप पर थी।
+
+
+
+
+
रेसिपी
+
टेस्ट के बगल में रहने वाली रेसिपी
+
+ यह पच्चीस चालान लिखती है जिन्हें स्वीकार होना चाहिए और सीमा से ऊपर की दो छवियाँ जिन्हें अस्वीकार
+ होना चाहिए, और मैनिफ़ेस्ट दोनों अपेक्षाएँ दर्ज करता है:
+
+ चेकसम वाली पंक्ति संग्रह को उसी रिलीज़ की verify-SHA256SUMS.txt से मिलाती है। संस्करण
+ तय कर दिया गया है, इसलिए नई रिलीज़ कभी ऐसे बिल्ड को नहीं बदलती जिसे आपने छुआ नहीं।
+
+ हर अंत का अपना एग्ज़िट कोड है, इसलिए कदम अपने आप विफल होता है और लॉग बताता है कि कौन-सा था। जो
+ पाइपलाइन को मिलते हैं:
+
+
+
3 - रेसिपी मान्य नहीं है। कुछ नहीं लिखा गया, और हर समस्या का नाम लिया गया है
+
4 - फ़ॉर्मैट वह नहीं कर सकता जो माँगा गया, जैसे अपने न्यूनतम से नीचे का आकार
+
6 - डिस्क पर पर्याप्त जगह नहीं है
+
7 - tfg verify को एक फ़ाइल मिली जो अपने मैनिफ़ेस्ट से मेल नहीं खाती
+
8 - रन पूरा हुआ, पर सब कुछ बना नहीं
+
+
+ विफल रन स्टैंडर्ड आउटपुट पर कुछ नहीं छापता, इसलिए लॉग पार्सर कभी किसी त्रुटि को डेटा नहीं समझता।
+ पूरी तालिका दस्तावेज़ के पेज पर है।
+
+
+
+
+
PowerShell
+
PowerShell स्क्रिप्ट को एक पंक्ति और चाहिए
+
+ PowerShell किसी प्रोग्राम का एग्ज़िट कोड .ps1 फ़ाइल से बाहर नहीं ले जाता। एक को
+ -File से चलाएँ तो स्क्रिप्ट 0 देती है, चाहे भीतर के टूल ने काम से
+ इनकार कर दिया हो, और जो बिल्ड लाल होना चाहिए वह हरा हो जाता है। आख़िरी पंक्ति ही पूरा सुधार है:
+
+ PowerShell ऐसा ही बरतता है, यह इस टूल की बात नहीं है। cmd, bash और
+ zsh को कुछ अतिरिक्त नहीं चाहिए।
+
+
+
+
+
कई जॉब
+
जॉब के बीच फ़िक्स्चर साझा करना
+
+ आम तौर पर उन्हें अपलोड करने की ज़रूरत नहीं होती। क्योंकि वही रेसिपी वही बाइट लिखती है, हर जॉब अपना
+ tfg generate चला सकता है, जो अपलोड और डाउनलोड से तेज़ है। जब किसी जॉब को दूसरे से
+ फ़ाइलें लेनी हों, तो ट्रांसफ़र के बाद मैनिफ़ेस्ट पर tfg verify चलाएँ, और वह बताएगा
+ कि जो पहुँचा वही है जो लिखा गया था।
+
+
+
+
+
आगे
+
यहाँ से कहाँ जाएँ
+
+
+ खराब टेस्ट फ़ाइलें उसी रेसिपी में जानबूझकर बिगाड़ी गई फ़ाइलें
+ जोड़ती हैं।
+
+
+ उपयोग के मामले दिखाते हैं कि पाइपलाइन में एक रन और क्या जाँच सकता है।
+
+
+ दस्तावेज़ में हर कमांड, हर रेसिपी कुंजी और हर एग्ज़िट कोड है।
+
+ पाँच काम जो लोगों से फ़ाइलें लेने वाले लगभग हर प्रोजेक्ट में आते हैं, और हर एक को करने वाली कमांड।
+ नीचे का हर उदाहरण जैसा लिखा है वैसा चलता है।
+
+
+
+
अपलोड सीमाएँ
+
यह जाँचना कि फ़ाइल आकार सीमा वहीं लागू होती है जहाँ वह कहती है
+
+ एक सीमा एक नहीं, तीन टेस्ट केस है: ठीक नीचे, ठीक पर, और ठीक ऊपर। इन्हें हाथ से बनाने का मतलब बाइट
+ संख्या निकालना और उम्मीद करना है कि आप एक से नहीं चूके। इसके बजाय सेट माँगें:
+
+ आपको 1048575, 1048576 और 1048577 बाइट की तीन असली PDF मिलती हैं, और एक मैनिफ़ेस्ट जो कहता है कि पहली
+ दो स्वीकार होनी चाहिए और तीसरी size_limit के कारण अस्वीकार। आपका टेस्ट तीन असर्शन
+ हाथ से लिखने के बजाय अपेक्षा पढ़ता है - और जब सीमा बदलती है तो आप एक संख्या बदलकर दोबारा चलाते
+ हैं।
+
+
+ जब आप इनलाइन एक ही सीमा सेट चाहें तो यही प्रीसेट के बिना भी चलता है:
+
+ बड़े बाइनरी फ़िक्स्चर रिपॉज़िटरी क्लोन करना धीमा और रिव्यू करना कठिन बनाते हैं, और किसी एक के बदले
+ जाने पर कोई नहीं बता सकता कि क्या बदला। रेसिपी कुछ सौ अक्षरों की YAML है जो वही फ़ाइलें दोबारा
+ बना देती है - किसी भी मशीन पर बाइट-दर-बाइट - क्योंकि हर फ़ाइल रन के सीड से
+ निकलती है।
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ हर अंत का अपना एग्ज़िट कोड है, इसलिए पाइपलाइन खराब रेसिपी, भरी डिस्क और सत्यापन असंगति में अंतर कर
+ सकती है। विफल रन स्टैंडर्ड आउटपुट पर कुछ नहीं छापता, जिससे लॉग पार्सर किसी त्रुटि को डेटा नहीं
+ पढ़ता।
+
+
+
+
+
पैमाना
+
यह जानना कि फ़ोल्डर बड़ा होने पर क्या होता है
+
+ इंपोर्ट रूटीन, रात के जॉब और डायरेक्टरी सूचियाँ दस हज़ार फ़ाइलों पर दस की तुलना में अलग व्यवहार करती
+ हैं। किसी सीमा से निकाले गए आकार सेट को दस हज़ार एक जैसी फ़ाइलों के बजाय असली ट्रैफ़िक जैसा
+ दिखाते हैं, और निकालना सीड से होता है, इसलिए सेट कल भी वही रहता है।
+
+ डिस्क की खाली जगह से बड़ा रन पहला बाइट लिखे जाने से पहले ठुकरा दिया जाता है, डिस्क भरकर बीच में विफल
+ होने के बजाय।
+
+
+
+
+
आर्काइव
+
ऐसे आर्काइव से अनपैकर का परीक्षण जिसमें सच में फ़ाइलें हैं
+
+ सही एक्सटेंशन वाला खाली आर्काइव उस कोड के बारे में कुछ साबित नहीं करता जो उसे खोलकर अंदर की चीज़ों
+ से गुज़रता है। सामग्री घोषित करें और आर्काइव सच में उसे रखता है:
+
+ नेस्टिंग की गहराई, प्रविष्टियों की संख्या और अंदर की चीज़ों का आकार, ये सब वे बातें हैं जिन पर
+ इंपोर्ट रूटीन की अपनी राय होती है, और इसी तरह आप जानते हैं कि वह राय क्या है।
+
+
+
+
+
पार्सर और व्यूअर
+
यह जाँचना कि आपका अपना कोड फ़ॉर्मैट को असली सॉफ़्टवेयर की तरह पढ़ता है
+
+ यहाँ का हर फ़ॉर्मैट भेजे जाने से पहले स्वतंत्र रीडर से जाँचा जाता है - PNG खोली जाती है और उसके
+ पिक्सेल मिलाए जाते हैं, DOCX अलग लाइब्रेरी से वापस पढ़ा जाता है, आर्काइव खोला जाता है। इसका मतलब
+ है कि जो फ़ाइल आपका पार्सर ठुकराता है वह आपके पार्सर के बारे में एक खोज है, जनरेटर के बारे में
+ नहीं।
+
+ फ़ॉर्मैट पेज हर एक की स्वीकार की जाने वाली सेटिंग और हर एक की सबसे छोटी
+ संभव फ़ाइल सूचीबद्ध करता है।
+
+
+
+
+
गाइड
+
इनमें से दो, विस्तार से
+
+
+ खराब टेस्ट फ़ाइलें - जानबूझकर बिगाड़ी गई, ठीक-ठीक आकार की
+ फ़ाइल, जिसके साथ क्या होना चाहिए वह मैनिफ़ेस्ट में लिखा है।
+
+
+ CI में टेस्ट फ़ाइलें - GitHub Actions का वर्कफ़्लो, GitLab का
+ जॉब और वे एग्ज़िट कोड जो बिल्ड को विफल करते हैं।
+
+
+
+
+
+
यह किसके लिए है
+
+ QA इंजीनियर, टेस्ट ऑटोमेशन और हर वह व्यक्ति जिसके कोड के पीछे अपलोड फ़ॉर्म, इंपोर्ट रूटीन, पार्सर या
+ स्टोरेज कोटा है। यह बिना किसी नेटवर्क की मशीन पर चलता है, जो बंद कॉर्पोरेट माहौल में मायने रखता
+ है जहाँ ब्राउज़र आधारित जनरेटर विकल्प नहीं होता।
+
+ Semua yang dilakukan alat ini, disusun sebagai pertanyaan yang benar-benar dibawa orang.
+ README di repositori adalah referensi lengkap dan selalu sesuai
+ dengan build yang Anda unduh.
+
+
+
+
Perintah apa saja yang ada?
+
Masing-masing melakukan satu hal:
+
tfg generate menghasilkan file, dari resep atau dari opsi
+tfg validate memeriksa resep tanpa menulis apa pun
+tfg verify memeriksa direktori terhadap manifes
+tfg cleanup menghapus file yang tercantum dalam manifes
+tfg recipe fmt mencetak resep dalam bentuk bakunya
+tfg preset membuat set file dari pertanyaan pengujian bernama
+tfg formats mendaftar format yang didukung build ini
+tfg damage mendaftar cara build ini dapat merusak file dengan sengaja
+tfg tool alat kecil untuk file yang sudah Anda miliki
+tfg version mencetak versi alat
+tfg license mencetak lisensi dan artinya bagi file yang dihasilkan
+
+
+
+
Bagaimana cara membuat satu file dengan ukuran tepat?
+
+ Sebutkan format, ukuran, dan tujuannya. Ukuran dihitung dalam kelipatan 1024, jadi 2mb
+ adalah 2097152 byte. Jumlah byte biasa juga bisa, jadi --size 10485761 meminta
+ persis sebanyak itu.
+
+
tfg generate --format png --size 2mb --out ./out
+
Opsi yang berguna pada generate:
+
+
+
Opsi
Fungsinya
+
+
--format <id>
format file, misalnya txt
+
--size <size>
ukuran tepat setiap file, seperti 10mb atau jumlah byte biasa
+
--size-range <a-b>
ukuran yang diundi per file dari suatu rentang, seperti 1kb-8kb. Undiannya berasal dari seed
+
--boundary <size>
tiga file di sekitar batas: satu byte di bawah, batas itu sendiri, satu byte di atas
+
--count <n>
berapa banyak file yang dibuat. Bawaan 1
+
--name <template>
templat nama, misalnya invoice_{index:04}.txt
+
--out <dir>
direktori tujuan penulisan
+
--seed <n>
seed run. Seed yang sama menghasilkan byte yang sama
+
--set <k>=<v>
pengaturan format, dapat diulang
+
--damage <name>
merusak file dengan sengaja, dapat diulang dan diterapkan berurutan. Jalankan tfg damage untuk daftarnya
+
--expected <outcome>
accept, reject, sanitize, atau unspecified
+
--dry-run
menghitung dan menampilkan, tidak menulis apa pun
+
--json
menulis manifes ke keluaran standar
+
+
+
+
+
+
+
Bagaimana membuat file yang sengaja dirusak?
+
+ Setiap file lain yang ditulis alat ini benar menurut konstruksinya, yang menjawab dua dari tiga
+ pertanyaan yang diajukan validator unggahan. --damage menjawab yang ketiga - apakah
+ file itu dapat dibuka sama sekali. File dibuat secara normal lalu dirusak, sehingga ukurannya
+ tetap seperti yang Anda minta.
+
+ Pengaturan ditulis setelah titik dua. Opsinya dapat diulang, dan urutan penulisannya adalah urutan
+ penerapannya. tfg damage mendaftar apa yang bisa dilakukan build ini dan apa yang
+ diterima masing-masing.
+
+
Dalam resep, kuncinya adalah daftar, berisi nama atau pengaturan:
+ File yang dirusak mendapat expected: reject di manifes, dengan kerusakan dicatat di
+ sampingnya. Dua hal ditolak sebelum apa pun ditulis, karena masing-masing akan menaruh file di
+ disk yang digambarkan manifes secara keliru:
+
+
+
file yang lebih kecil dari yang dibutuhkan kerusakan, karena akan keluar tanpa perubahan
+
+ expected: accept di samping kerusakan, karena tidak ada yang dapat memenuhinya. Tulis
+ sanitize bila sistem yang diuji dimaksudkan memperbaiki file, atau
+ unspecified bila itulah pertanyaan yang Anda ajukan
+
+
+
+ Yang ketiga tidak dapat diketahui sebelumnya. Bila suatu kerusakan berjalan dan tidak menggeser satu
+ byte pun, file itu dibuang alih-alih ditulis - run berlanjut, menyebut file mana itu, dan
+ berakhir dengan kode keluar parsial.
+
+ Resep adalah file YAML yang menggambarkan satu run utuh. Commit di samping pengujian Anda dan
+ fixture berhenti menjadi biner di repositori Anda - siapa pun dapat membangunnya kembali, byte
+ demi byte, dari file berisi beberapa ratus karakter.
+
+ Setiap target memerlukan tepat satu dari size, size-range,
+ boundary, atau contains. Dua adalah galat dan tidak ada juga galat.
+ Resep yang tidak valid menulis tidak ada file sama sekali dan melaporkan semua
+ masalah sekaligus, bukan hanya yang pertama, masing-masing menyebut pengaturan yang dimaksud.
+
+
+
+
+
Bagaimana menyatakan apa yang harus dilakukan sistem saya terhadap sebuah file?
+
Bentuk pendek bila hasilnya sudah cukup, bentuk panjang bila alasannya penting:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Hasilnya adalah accept, reject, sanitize, dan
+ unspecified. Alasannya adalah daftar tertutup agar laporan dapat mengelompokkan
+ berdasarkan itu: content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit, dan
+ size_zero.
+
+
+ Alasan menyebut aturan yang berlaku, bukan putusannya. Itulah sebabnya alasan yang
+ sama dapat berada di bawah kedua hasil - file satu byte di bawah batas adalah
+ accept, dan aturan yang dimaksud tetap size_limit.
+
+
+
+
+
Apa isi manifes?
+
+ Manifes ditulis di samping file pada akhir setiap run, termasuk run yang terhenti. Satu entri per
+ file:
+
+ recipe_hash ditambahkan bila run berasal dari resep, dan preset dengan
+ overrides bila berasal dari preset, sehingga manifes selalu dapat ditelusuri ke apa
+ yang menghasilkannya.
+
+
+ Setiap entri juga membawa target_id, id target dalam resep yang menghasilkan file, dan
+ summary.by_target menghitung file yang dihasilkan tiap target. Resep dengan
+ beberapa target dapat diperiksa target demi target tanpa membaca nama file.
+
+
+
+
+
Apa itu preset?
+
+ Set file siap pakai yang menjawab pertanyaan pengujian umum, sehingga Anda tidak perlu merancang
+ setnya sendiri. Preset pada dasarnya resep biasa, dan eject mencetak resepnya agar
+ dapat Anda sunting dari sana. Setiap preset memiliki halamannya
+ sendiri berisi apa yang biasanya ditemukan, isi set, dan setiap pengaturan yang diterimanya.
+
+ show memberi tahu berapa biaya set sebelum Anda membuatnya, dan menyatakan terus terang
+ bila sebuah angka adalah nilai sementara dari kami, bukan batas dari Anda.
+
+
+
+
+
Apa arti kode keluar?
+
+ Setiap akhir punya kodenya sendiri, keluaran yang terbaca mesin masuk ke keluaran standar, dan run
+ yang gagal tidak mencetak apa pun di sana. Tabelnya adalah kontrak beku - mengubah arti sebuah
+ kode memerlukan kenaikan versi mayor.
+
+
+
+
+
+
Kode
+
Arti
+
+
+
+
+
0
+
Semuanya berjalan.
+
+
+
1
+
Kesalahan tak terduga di dalam alat.
+
+
+
2
+
Perintah atau opsi salah.
+
+
+
3
+
Resep tidak valid.
+
+
+
4
+
Format tidak dapat melakukan yang diminta.
+
+
+
5
+
Pembacaan atau penulisan gagal.
+
+
+
6
+
Ruang disk tidak cukup.
+
+
+
7
+
verify menemukan ketidakcocokan.
+
+
+
8
+
Run selesai tetapi tidak semuanya dihasilkan.
+
+
+
130
+
Dihentikan dengan Ctrl+C.
+
+
+
143
+
Dihentikan oleh sinyal, seperti tampilan batas waktu CI.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Run yang dihentikan dengan Ctrl+C tetap meninggalkan manifes dan tidak pernah meninggalkan file yang
+ tertulis setengah, sehingga job yang dibatalkan masih dapat dibersihkan oleh yang berikutnya.
+
+ Ada, mesin yang sama dengan jendela di atasnya, untuk pengujian yang tidak diskripkan. Ini bukan
+ versi terpangkas: sebuah pengujian membandingkan kedua antarmuka kemampuan demi kemampuan, dan
+ apa pun yang hanya dapat dilakukan salah satunya harus dinyatakan dan dibenarkan alih-alih
+ diam-diam menyimpang.
+
+
+ Layarnya adalah satu batch, preset, beberapa batch sekaligus, dan tentang. Jendela ini menunjukkan
+ biaya sebuah run sebelum menulis apa pun, melaporkan kemajuan selama berjalan, dan dapat
+ dibatalkan di tengah jalan tanpa meninggalkan file yang tertulis setengah. Jendela ini belum
+ membuka file resep - untuk saat ini resep urusan baris perintah, dan jendela membangun batch-nya
+ di formulir.
+
+ Lisensi, privasi, reproduksibilitas, dan hal-hal yang diperiksa orang sebelum memasukkan generator
+ ke pipeline build. Bila pertanyaan Anda tidak ada di sini, pelacak
+ isu terbuka.
+
+
+
+
+
Apa bedanya dengan dd, fsutil, atau truncate?
+
+
Perintah itu memberi Anda file berukuran benar yang berisi kekosongan. File 2 MB bernama photo.png yang dibuat begitu bukanlah PNG, sehingga apa pun yang benar-benar mem-parsing-nya akan menolaknya karena alasan yang salah, dan pengujian Anda pun lolos karena alasan yang salah juga. Alat ini menghasilkan PNG asli berukuran tepat 2 MB yang terbuka di penampil gambar, dan disertai pernyataan tentang bagaimana sistem Anda harus memperlakukannya.
Apakah gratis, dan bisakah saya pakai di tempat kerja?
+
+
Ya untuk keduanya. Dirilis di bawah GPL-3.0 dan tidak berbayar. Tidak ada akun, kunci lisensi, atau tingkat berbayar.
+
+
+
+
Bisakah saya memakai file yang dihasilkan dalam produk closed source?
+
+
Bisa. Lisensi mencakup kode alatnya, bukan apa yang dihasilkan alat itu. File, resep, dan manifes yang dihasilkan adalah keluaran, bukan karya turunan, sehingga Anda dapat meng-commit dan mendistribusikannya tanpa kewajiban apa pun.
+
+
+
+
Apakah file yang dihasilkan berisi data pribadi sungguhan?
+
+
Tidak. Semua isinya disintesis dari sebuah seed. Tidak ada dataset yang dibaca, tidak ada layanan yang dihubungi, dan tidak ada konten pihak ketiga yang disematkan. Perlakukan alamat e-mail yang dihasilkan sebagai tidak dapat dipakai, bukan sekadar belum dipakai, karena string acak apa pun bisa kebetulan sama dengan alamat sungguhan.
+
+
+
+
Apakah saya akan mendapat file yang persis sama di mesin lain?
+
+
Ya, byte demi byte, dengan resep dan seed yang sama. Proyek ini mengujinya pada setiap perubahan, dan melanggarnya memerlukan kenaikan versi mayor. Itulah yang memungkinkan Anda meng-commit resep kecil alih-alih fixture biner besar.
+
+
+
+
Apakah memerlukan koneksi internet?
+
+
Tidak pernah. Tidak ada telemetri, pemeriksaan pembaruan, atau klien cloud, dan biner baris perintah sama sekali tidak memiliki stack jaringan yang dikompilasi di dalamnya. Alat ini berjalan di mesin tanpa jaringan dan di lingkungan korporat yang tertutup.
+
+
+
+
Apa yang terjadi bila saya meminta ukuran yang tidak dapat dicapai suatu format?
+
+
Anda mendapat galat yang menyebut format, ukuran terkecilnya, alasan batas bawah itu, dan apa yang harus dilakukan sebagai gantinya, dan tidak ada file yang ditulis. Alat ini tidak pernah membulatkan ukuran secara diam-diam. Setiap batas bawah tercantum di halaman format.
+
tfg formats png
+
+
+
+
Bisakah saya membuat file yang sengaja dirusak?
+
+
Ya. Tambahkan --damage zero-head dan file keluar dengan ukuran tepat seperti yang diminta, dengan byte pertamanya ditimpa nol, sehingga pembaca menolaknya, dan manifes menyatakan sistem Anda harus menolaknya. Rinciannya ada di halaman tentang file uji yang rusak.
7z, mp3, dan mp4. Saat ini 26 format bekerja dari ujung ke ujung.
+
+
+
+
Di sistem apa saya bisa menjalankannya?
+
+
Baris perintah berjalan di Windows dan Linux pada Intel maupun ARM, dan di Mac Apple Silicon. Jendela desktop disediakan untuk Windows di Intel, Linux di Intel, dan Mac Apple Silicon. Mac Intel tidak didukung dan tidak ada build untuknya.
+
+
+
+
Apakah saya harus menginstal sesuatu?
+
+
Tidak. Unduh arsip untuk sistem Anda, ekstrak, dan jalankan binernya. Tidak ada installer, tidak ada runtime yang harus ditambahkan, dan tidak ada dependensi yang harus diselesaikan. Bila Anda punya Go, satu perintah go install juga bisa.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
Mengapa run atas ribuan file lebih lambat di Windows?
+
+
Karena Windows membebankan lebih banyak untuk setiap path yang diperiksanya, dan perintah yang menelusuri ribuan file memeriksa ribuan path. Diukur di satu mesin dengan 3000 file berukuran 1 kB, verify memakan sekitar 0,9 detik di Windows dan sekitar 0,2 detik di Linux dalam container. Path keluaran yang lebih pendek memperkecil angka Windows, karena setiap folder di atas file ikut diperiksa.
+ Fixture biner di repositori tinggal selamanya dalam riwayatnya, tidak bisa ditinjau di diff, dan
+ menjadi mustahil ketika filenya besar. Buat file di dalam pipeline dari sebuah resep. Resep adalah
+ teks, byte keluar sama setiap kali, dan langkah terakhir membuktikan tidak ada yang bergeser.
+
+
+
+
Jawaban singkat
+
+ Pasang tfg, jalankan tfg generate fixtures.yaml --out ./fixtures sebelum
+ tes dan tfg verify ./fixtures/manifest.json sesudahnya. Kedua langkah menggagalkan
+ build dengan sendirinya, dengan kode keluar yang menyebut alasannya.
+
+
+
+
+
Mengapa tidak di-commit
+
Mengapa fixture tidak seharusnya tinggal di repositori
+
+
+ Ia tetap ada di riwayat. Menghapus file biner kemudian tidak mengecilkan klon,
+ karena setiap versinya masih ada.
+
+
+ Diff tidak menunjukkan apa yang berubah. Peninjau hanya melihat bahwa sebuah PDF
+ berbeda, tidak lebih. Resep berubah satu baris.
+
+
+ File besar tidak muat. GitHub menolak push yang berisi file lebih dari 100 MB, jadi
+ tes batas unggah 500 MB tidak punya apa pun untuk di-commit.
+
+
+
+ Yang di-commit adalah resepnya. Resep dan seed yang sama menulis byte yang sama di setiap mesin,
+ jadi file yang dibuat di pipeline adalah file yang Anda punya di laptop.
+
+
+
+
+
Resep
+
Resep yang tinggal di samping tes
+
+ Resep ini menulis dua puluh lima faktur yang harus diterima dan dua gambar di atas batas yang harus
+ ditolak, dan manifes mencatat kedua harapan itu:
+
+ Baris checksum membandingkan arsip dengan verify-SHA256SUMS.txt dari rilis yang sama.
+ Versinya dikunci, jadi rilis baru tidak pernah mengubah build yang tidak Anda sentuh.
+
Apa yang membuat sebuah langkah gagal, dan mengapa
+
+ Setiap akhir punya kode keluarnya sendiri, jadi langkah gagal dengan sendirinya dan log menyebut
+ yang mana. Yang dijumpai pipeline:
+
+
+
3 - resep tidak valid. Tidak ada yang ditulis, dan setiap masalah disebut
+
4 - format tidak bisa melakukan yang diminta, misalnya ukuran di bawah minimumnya
+
6 - ruang disk tidak cukup
+
7 - tfg verify menemukan file yang tidak cocok dengan manifesnya
+
8 - proses selesai, tetapi tidak semuanya dihasilkan
+
+
+ Proses yang gagal tidak mencetak apa pun ke keluaran standar, sehingga parser log tidak pernah salah
+ mengira error sebagai data. Tabel lengkapnya ada di halaman
+ dokumentasi.
+
+
+
+
+
PowerShell
+
Skrip PowerShell butuh satu baris lagi
+
+ PowerShell tidak membawa kode keluar sebuah program keluar dari file .ps1. Jalankan
+ satu dengan -File dan skrip menjawab 0 bahkan ketika alat di dalamnya
+ menolak pekerjaan, sehingga build yang seharusnya merah menjadi hijau. Baris terakhir adalah
+ seluruh perbaikannya:
+
+ Begitulah PowerShell bekerja, bukan sesuatu dari alat ini. cmd, bash, dan
+ zsh tidak butuh tambahan apa pun.
+
+
+
+
+
Beberapa job
+
Berbagi fixture antar job
+
+ Biasanya tidak perlu mengunggahnya. Karena resep yang sama menulis byte yang sama, setiap job bisa
+ menjalankan tfg generate sendiri, yang lebih cepat daripada mengunggah lalu
+ mengunduh. Ketika sebuah job harus menerima file dari job lain, jalankan tfg verify
+ pada manifes setelah transfer, dan ia menyatakan apakah yang tiba sama dengan yang ditulis.
+
+
+
+
+
Berikutnya
+
Ke mana dari sini
+
+
+ File uji yang rusak menambahkan file yang sengaja dirusak ke resep
+ yang sama.
+
+
+ Kasus penggunaan menunjukkan apa lagi yang bisa diperiksa sebuah
+ proses di pipeline.
+
+
+ Dokumentasi memuat setiap perintah, kunci resep, dan kode keluar.
+
+ Validator yang hanya pernah diberi file sehat belum benar-benar diuji. Inilah cara mendapatkan file
+ yang sengaja dirusak, keluar dengan tepat sebesar yang Anda minta, dan membawa
+ manifes yang menyatakan apa yang harus dilakukan sistem Anda terhadapnya.
+
+
+
+
Jawaban singkat
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out menulis PNG
+ berukuran tepat 2097152 byte yang byte pertamanya nol, dan manifes di sebelahnya mencatat bahwa
+ sistem Anda harus menolaknya.
+
+
+
+
+
Cara yang biasa
+
Mengapa file yang dirusak dengan tangan adalah tes yang buruk
+
+ Cara yang biasa adalah editor hex, skrip yang membalik beberapa byte acak, atau memotong file dengan
+ head atau truncate. Berhasil sekali, lalu merugikan Anda:
+
+
+
+ Hasilnya berbeda setiap kali. Byte acak jatuh di tempat baru pada setiap proses,
+ jadi kegagalan hari Selasa mungkin tidak muncul lagi hari Rabu.
+
+
+ Ukurannya berubah. File yang dipotong lebih kecil daripada batas yang seharusnya
+ tidak dilewatinya, sehingga pemeriksaan ukuran menjawab sebelum pemeriksaan isi dan tes lulus
+ karena alasan yang salah.
+
+
+ Sering tidak terdeteksi. Teks biasa masih terbaca dengan satu byte berubah di
+ tengah, dan pembaca gambar yang toleran hanya menggambarnya, sehingga file yang seharusnya
+ rusak malah diterima.
+
+
+ Tidak mengatakan apa yang seharusnya terjadi. File hanyalah byte, dan siapa pun
+ yang membaca tes itu kemudian harus menebak apakah yang dimaksud penerimaan atau penolakan.
+
+
+
+
+
+
Yang Anda dapatkan
+
File yang rusak tetap berukuran seperti yang Anda minta
+
+ File dibuat seperti biasa lalu dirusak, dalam perjalanan ke disk. Ukurannya tetap seperti yang Anda
+ minta, dan perintah yang sama menulis byte yang sama lagi.
+
+ Pengaturan ditulis setelah titik dua. Opsi ini bisa diulang, dan kerusakan diterapkan menurut urutan
+ yang Anda tulis. Berlaku untuk semua 26 format.
+
+
+
+
+
Yang bisa dilakukan
+
Kerusakan apa saja yang ada?
+
+ Ini daftar yang dicetak program, dibaca darinya saat halaman ini dibangun. tfg damage
+ mencetak daftar yang sama, dan tfg damage <id> menjelaskan apa yang diterima
+ salah satunya.
+
+
+
+
+
+
Kerusakan
+
Yang dilakukannya pada byte
+
File terkecil
+
Pengaturan
+
+
+
+
+
zero-head
+
Menimpa byte pertama file dengan nol tanpa mengubah panjangnya. Sebagian besar pembaca melihat ke sana lebih dulu, jadi hampir semua hal menyadari kerusakan ini.
+
8
+
bytes
+
+
+
+
+
+ zero-head menulis nol di atas awal file. Sebagian besar pembaca melihat ke sana lebih
+ dulu, ke tanda pengenal dan header yang menyatakan file itu apa, jadi hampir semua pembaca
+ menyadarinya. Teks biasa dan log tidak punya tanda pengenal dan juga ditolak, karena deretan
+ byte nol bukan teks. Di bawah empat byte, sebagian format keluar dengan kerusakan yang tidak
+ dikeluhkan pembaca mana pun, itulah sebabnya pengaturan dimulai dari empat.
+
+
+
+
+
Yang dikatakan manifes
+
Manifes yang menyatakan apa yang harus terjadi
+
+ Setiap file yang rusak mendapat catatan yang menyatakan sistem Anda harus menolaknya, dengan
+ kerusakannya dicatat di sampingnya:
+
+ Dua permintaan ditolak sebelum apa pun ditulis, karena masing-masing akan meninggalkan file di disk
+ yang dijelaskan keliru oleh manifes:
+
+
+
file yang lebih kecil dari yang dibutuhkan kerusakan, yang akan keluar tanpa perubahan
+
+ expected: accept di samping kerusakan, karena tidak ada yang bisa memenuhinya. Tulis
+ sanitize jika sistem Anda memang harus memperbaiki file itu, atau
+ unspecified jika justru itu pertanyaan Anda
+
+
+
+
+
+
Dalam resep
+
File sehat dan rusak dalam satu proses
+
+ Taruh keduanya dalam satu resep, dan manifes membawa harapan setiap file, sehingga tes tidak butuh
+ daftar mana yang mana:
+
+ Tes membaca manifes dan memeriksa bahwa yang terjadi sama dengan yang dinyatakan. Tidak perlu daftar
+ nama file:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Penolakan yang baik adalah penolakan yang bersih. Pesan yang menyebut apa yang salah adalah jawaban
+ yang Anda inginkan. Kesalahan server, macet, atau file yang tersimpan setengah adalah cacat yang
+ ingin ditemukan tes ini.
+
+
+
+
+
Berikutnya
+
Ke mana dari sini
+
+
+ Preset upload-validation mengajukan dua pertanyaan lain
+ kepada sebuah formulir, soal ukuran dan soal jenis.
+
+
+ File uji di CI menjalankan resep seperti ini di pipeline.
+
26 format file, masing-masing dibuat dengan ukuran tepat
+
+ Masing-masing adalah file asli dari format itu. File terbuka di aplikasi yang
+ memilikinya dan persis berjumlah byte yang Anda minta. Tidak ada yang berupa nol pengisi dengan
+ ekstensi yang ditempelkan.
+
+
+
+
+
+
+
Format
+
Nama
+
Ekstensi
+
File terkecil
+
Kelengkapan
+
Diperiksa dengan
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
tidak berlaku
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
tidak berlaku
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
tidak berlaku
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
Arti kolom-kolom
+
+
+
File terkecil
+
+ Jumlah byte paling sedikit yang akan diterima alat ini untuk format itu, termasuk label yang
+ ditulisnya di dalam file. Minta lebih kecil dan Anda mendapat galat yang menyebut batas
+ bawah dan alasannya, tidak pernah file berukuran salah.
+
+
+
+
Kelengkapan
+
+ Seberapa lengkap file itu. full berarti pembaca yang benar-benar mem-parsing format
+ menerimanya, bukan sekadar ekstensinya cocok.
+
+
+
+
Diperiksa dengan
+
+ Pembaca independen yang membuka setiap file yang dihasilkan sebelum format dirilis - implementasi
+ terpisah, bukan kode kami sendiri yang menilai pekerjaan rumahnya sendiri.
+
+
+
+
+ Setiap format juga berulang sampai ke byte: resep dan seed yang sama menghasilkan file identik di
+ mesin mana pun, dan itulah yang membuat resep aman di-commit menggantikan fixture-nya.
+
+
+
+
+
Pengaturan yang diterima setiap format
+
+ Sebagian besar format punya pengaturan sendiri - dimensi gambar, kualitas JPEG, jumlah halaman PDF,
+ baris dan kolom spreadsheet, berapa banyak entri di dalam arsip. Atur dengan --set
+ key=value di baris perintah, atau di bawah properties: dalam resep.
+
tanggal seperti 2024-02-29 atau 2024-02-29T13:45:00+02:00, atau none
+
+
+
+
modified
+
tanggal seperti 2024-02-29 atau 2024-02-29T13:45:00+02:00, atau none
+
+
+
png
+
width
+
1 - 20000 piksel
+
+
+
+
height
+
1 - 20000 piksel
+
+
+
pptx
+
slides
+
1 - 500 slide
+
+
+
svg
+
width
+
1 - 20000 piksel
+
+
+
+
height
+
1 - 20000 piksel
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
id sebuah format, seperti yang didaftar tfg formats
+
+
+
+
entry_size
+
ukuran seperti 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
benar atau salah
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 piksel
+
+
+
+
height
+
1 - 20000 piksel
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
benar atau salah
+
+
+
wav
+
sample_rate
+
8000 - 192000 hertz
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 piksel
+
+
+
+
height
+
1 - 16383 piksel
+
+
+
xlsx
+
rows
+
1 - 200000 baris
+
+
+
+
columns
+
1 - 32768 kolom
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
benar atau salah
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
id sebuah format, seperti yang didaftar tfg formats
+
+
+
+
entry_size
+
ukuran seperti 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
benar atau salah
+
+
+
+
password
+
kata sandi, dalam teks biasa
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ Nilai di luar yang diterima suatu pengaturan ditolak dengan pesan yang menyebut pengaturan, rentang
+ yang diizinkan, dan apa yang dipakai sebagai gantinya. Pengaturan yang tidak dikenal juga galat,
+ tidak pernah nilai bawaan diam-diam - salah ketik yang diterima diam-diam menghasilkan file
+ dengan pengaturan yang salah dan satu jam bertanya-tanya mengapa pengujian lolos padahal
+ seharusnya tidak.
+
+
+ Jalankan tfg formats <id> untuk melihat persis apa yang diterima satu format pada
+ build yang Anda miliki.
+
+
+
+
+
Arsip berisi file asli
+
+ targz dan zip
+ dapat diisi dengan entri alih-alih dibiarkan sebagai cangkang kosong. Arsip yang dihasilkan
+ benar-benar berisi dokumen yang diklaimnya, sehingga apa pun yang mengekstraknya selama
+ pengujian menemukan file asli di dalamnya.
+
+ PDF, PNG, DOCX, ZIP - 26 format seluruhnya, dan setiap file
+ adalah file asli yang terbuka di aplikasi yang memilikinya, dengan ukuran persis seperti
+ yang Anda minta. Setiap run juga mencatat apa yang harus dilakukan aplikasi Anda
+ terhadap tiap file. Baris perintah dan jendela desktop, gratis dan open source, bekerja
+ sepenuhnya di mesin Anda.
+
Gratis dan open source, GPL-3.0. Tanpa pendaftaran. Unduhan Windows dan macOS sudah ditandatangani dan berjalan tanpa peringatan.
+
+
+
+
+ Jendela desktop, siap menulis sekumpulan file. Mesin yang sama berjalan di balik baris perintah.
+
+
+
+
+
+ 26
+
format asli, masing-masing terbuka di aplikasi yang memilikinya
+
+
+ 1 byte
+
ketepatan setiap ukuran yang Anda minta, tidak pernah dibulatkan diam-diam
+
+
+ 0
+
koneksi ke mana pun - tanpa akun, tanpa telemetri, tanpa pemeriksaan pembaruan
+
+
+
+
+
Masalahnya
+
Membuat satu file uji itu mudah. Membuat seribu yang tepat adalah bagian yang membosankan
+
Anda menguji perangkat lunak yang menerima file dari orang. Cepat atau lambat Anda memerlukan:
+
+
PDF berukuran tepat 10 MB, untuk mengetahui apakah batas unggahan itu nyata
+
tiga file di kedua sisi batas itu, untuk menangkap kesalahan selisih satu
+
10.000 file log, untuk melihat apa yang dilakukan job malam saat foldernya besar
+
ZIP yang benar-benar berisi 200 dokumen, bukan cangkang kosong dengan ekstensi yang tepat
+
file 4 GB, tanpa menyimpan file 4 GB di repositori Anda
+
fixture yang sama di laptop Anda dan di server build, byte demi byte
+
+
+ Itulah yang digantikan oleh alat ini. Dibuat untuk insinyur QA, otomasi pengujian, dan siapa pun
+ yang kodenya memiliki formulir unggah, rutinitas impor, parser, atau kuota penyimpanan di
+ baliknya.
+
+
+
+
+
Apa yang membuatnya berbeda
+
Generator lain berhenti di byte. Alat ini menjawab apa yang sebenarnya ditanyakan pengujian Anda
+
+ Sebuah folder berisi file masih membuat Anda yang memutuskan apa yang seharusnya dibuktikan tiap
+ file. Setiap run di sini menulis manifest.json di samping file - daftar sederhana
+ semua yang dihasilkan, dan untuk tiap entri sebuah ekspektasi yang dinyatakan.
+
+
Misalkan endpoint unggah Anda mengizinkan 1 MB. Mintalah tiga file yang berada di garis itu:
Bila jawabannya bergantung pada kebijakan Anda sendiri, manifes mengatakannya
+
+ Alat ini mencatat unspecified alih-alih mengarang ekspektasi. Generator yang menebak
+ menghasilkan kegagalan palsu, dan suite yang berteriak serigala akhirnya dimatikan.
+
+
+
+
+
+
Preset
+
Pilih pertanyaannya, dapatkan seluruh setnya
+
+ Preset adalah set file uji yang dirancang di sekitar satu pertanyaan pengujian, sehingga Anda tidak
+ perlu mencari tahu file mana yang membuktikan apa. Masing-masing punya halaman yang menjelaskan
+ apa yang biasanya ditemukan, isi set, dan setiap pengaturan yang diterimanya.
+
+ Sepuluh ribu file log, masing-masing antara satu dan delapan kilobyte, dengan ukuran diundi dari
+ seed sehingga besok menghasilkan set yang sama. Beri setiap run direktorinya
+ sendiri - manifes adalah satu-satunya catatan tentang apa yang ditulis sebuah run,
+ sehingga alat ini menolak menulis manifes kedua di atasnya:
+
+ Ukuran dihitung dalam kelipatan 1024, seperti pengelola file Anda, jadi 2mb berarti
+ 2097152 byte. Jumlah byte biasa juga bisa. Dokumentasi membahas
+ resep, manifes, dan kode keluar.
+
+
+
+
+
Yang Anda dapatkan
+
Dibuat untuk suite yang berjalan tanpa pengawasan
+
+
+
Ukuran tepat, sampai ke byte
+
Minta 10485761 byte dan dapatkan persis itu. Ukuran yang tidak dapat dicapai format adalah galat dengan alasan, tidak pernah file berukuran salah.
+
+
+
26 format asli
+
Bukan nol pengisi dengan ekstensi. PNG yang dihasilkan terbuka di penampil gambar, DOCX terbuka di Word, ZIP bisa diekstrak. Masing-masing diperiksa dengan pembaca independen sebelum dirilis.
+
+
+
Manifes yang menjadi oracle pengujian
+
Path, ukuran, SHA-256, format, seed, versi alat - dan apa yang harus dilakukan sistem Anda terhadap file itu.
+
+
+
Dapat direproduksi
+
Resep dan seed yang sama, byte yang sama, di mesin mana pun. Commit resep YAML kecil alih-alih fixture biner besar.
+
+
+
Dua antarmuka, satu mesin
+
Baris perintah yang dibuat untuk CI dan jendela desktop untuk pengujian eksploratif. Tidak ada yang merupakan versi terpangkas dari yang lain, dan sebuah pengujian membandingkannya kemampuan demi kemampuan.
+
+
+
Sepenuhnya offline
+
Tanpa akun, tanpa cloud, tanpa telemetri, tanpa pemeriksaan pembaruan. Biner baris perintah sama sekali tidak memiliki stack jaringan yang dikompilasi di dalamnya.
+
+
+
+
+
+
Unduh
+
Pilih build untuk sistem Anda
+
+ Ekstrak arsip dan jalankan. tfg adalah baris perintah dan tfg-gui adalah
+ jendela desktop. Tidak ada installer dan tidak ada yang perlu ditambahkan ke mesin Anda.
+
+
+
+
+
+
Sistem
+
Baris perintah
+
Jendela desktop
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
Apa yang ditandatangani, dan apa yang tidak
+
+ Unduhan Windows dan macOS ditandatangani, sehingga berjalan tanpa peringatan tentang pengembang tak
+ dikenal. Yang untuk Linux tidak, karena Linux desktop tidak punya padanan untuk
+ menandatanganinya. Setiap arsip tercantum di verify-SHA256SUMS.txt pada halaman
+ rilis, sehingga Anda dapat memeriksa apa yang Anda unduh.
+
+ Lima pekerjaan yang muncul di hampir setiap proyek yang menerima file dari orang, dan perintah yang
+ melakukan masing-masing. Setiap contoh di bawah berjalan sebagaimana tertulis.
+
+
+
+
Batas unggahan
+
Menguji apakah batas ukuran file ditegakkan di tempat yang dinyatakan
+
+ Sebuah batas adalah tiga kasus uji, bukan satu: tepat di bawah, tepat pada, dan tepat di atas.
+ Mendapatkannya secara manual berarti menghitung jumlah byte dan berharap tidak salah selisih
+ satu. Mintalah setnya:
+
+ Anda mendapat tiga PDF asli berukuran 1048575, 1048576, dan 1048577 byte, serta manifes yang
+ menyatakan dua yang pertama harus diterima dan yang ketiga ditolak karena
+ size_limit. Pengujian Anda membaca ekspektasi alih-alih Anda menulis tiga asersi
+ secara manual - dan bila batas berubah, Anda mengganti satu angka dan menjalankan ulang.
+
+
+ Hal yang sama berfungsi tanpa preset bila Anda menginginkan satu set batas inline:
+
Menjaga fixture di luar repositori tanpa kehilangannya
+
+ Fixture biner besar membuat repositori lambat di-clone dan sulit di-review, dan tak seorang pun tahu
+ apa yang berubah saat satu diganti. Resep adalah beberapa ratus karakter YAML yang membangun
+ ulang file identik - byte demi byte, di mesin mana pun - karena setiap file
+ diturunkan dari seed run.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Setiap akhir punya kode keluarnya sendiri, sehingga pipeline dapat membedakan resep yang buruk dari
+ disk penuh dan dari ketidakcocokan verifikasi. Run yang gagal tidak mencetak apa pun di keluaran
+ standar, sehingga parser log tidak membaca galat sebagai data.
+
+
+
+
+
Skala
+
Mencari tahu apa yang terjadi saat folder besar
+
+ Rutinitas impor, job malam, dan daftar direktori berperilaku berbeda pada sepuluh ribu file
+ dibanding sepuluh. Ukuran yang diundi dari suatu rentang membuat set tampak seperti lalu lintas
+ nyata alih-alih sepuluh ribu file identik, dan undiannya berasal dari seed, sehingga set itu
+ sama besok.
+
+ Run yang lebih besar dari ruang kosong di disk ditolak sebelum byte pertama ditulis, alih-alih
+ memenuhi disk dan gagal di tengah jalan.
+
+
+
+
+
Arsip
+
Menguji pengekstrak dengan arsip yang benar-benar berisi file
+
+ Arsip kosong dengan ekstensi yang tepat tidak membuktikan apa pun tentang kode yang membukanya dan
+ menelusuri isinya. Nyatakan isinya dan arsip benar-benar memuatnya:
+
+ Kedalaman bersarang, jumlah entri, dan ukuran isinya adalah hal-hal yang dipersoalkan rutinitas
+ impor, dan begitulah cara Anda mengetahui apa persoalan itu.
+
+
+
+
+
Parser dan penampil
+
Memeriksa bahwa kode Anda sendiri membaca format seperti perangkat lunak sungguhan
+
+ Setiap format di sini diperiksa dengan pembaca independen sebelum dirilis - PNG dibuka dan pikselnya
+ dibandingkan, DOCX dibaca kembali oleh pustaka terpisah, arsip diekstrak. Artinya file yang
+ ditolak parser Anda adalah temuan tentang parser Anda, bukan tentang generator.
+
+ Halaman format mencantumkan pengaturan yang diterima tiap format dan file
+ terkecil yang dapat dibuat tiap format.
+
+
+
+
+
Panduan
+
Dua di antaranya lebih rinci
+
+
+ File uji yang rusak - file yang sengaja dirusak, berukuran tepat,
+ dengan apa yang harus terjadi padanya tertulis di manifes.
+
+
+ File uji di CI - workflow GitHub Actions, job GitLab, dan kode
+ keluar yang menggagalkan build.
+
+
+
+
+
+
Untuk siapa ini
+
+ Insinyur QA, otomasi pengujian, dan siapa pun yang kodenya memiliki formulir unggah, rutinitas
+ impor, parser, atau kuota penyimpanan di baliknya. Berjalan di mesin tanpa jaringan sama sekali,
+ yang penting di lingkungan korporat tertutup di mana generator berbasis browser bukan pilihan.
+
+ Setiap sistem punya perintah untuk itu, dan ketiganya ada di bawah. Perintah-perintah itu memberi
+ Anda file dengan jumlah byte yang tepat - dan untuk banyak pengujian itu sudah cukup.
+ Setiap perintah di halaman ini dijalankan sebelum dipublikasikan, di sistem
+ tempat perintah itu berada.
+
+
+
+
Jawaban singkat
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Ukuran dalam byte, dan 10 MB yang
+ dihitung seperti pengelola file Anda menghitung adalah 10485760.
+
+
+
+
+
Windows
+
fsutil, dan versi PowerShell yang tidak memerlukan tambahan apa pun
+
+ fsutil disertakan dengan Windows. Perintah ini menerima ukuran dalam
+ byte, jadi hitung dulu angkanya - 10 MB adalah 10485760, 100 MB adalah 104857600, 1 GB
+ adalah 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Diukur di Windows 11: berjalan dari prompt biasa dan tidak memerlukan prompt dengan hak istimewa,
+ dan file keluar tepat 10485760 byte.
+
+
PowerShell dapat melakukan hal yang sama tanpa memanggil program lain, dan memahami satuan:
+ 10MB di PowerShell berarti 10485760 byte, hitungan berbasis 1024 yang sama dengan yang
+ dipakai Explorer, sehingga kedua perintah di atas menghasilkan ukuran yang sama.
+
+
+
+
+
Linux
+
dd, truncate, dan fallocate, dan perbedaan yang menjebak orang
+
dd adalah yang dikenal semua orang. Perintah ini benar-benar menulis byte:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate instan, dan di situlah jebakannya. Diukur di Alpine Linux, file melaporkan
+ 10485760 byte dan menempati nol blok - ini adalah sparse file.
+ Apa pun yang membacanya mendapat sepuluh megabyte nol, tetapi disk tidak pernah menyerahkan
+ ruangnya:
+
+
truncate -s 10M test10mb.bin
+
+ Itu baik untuk menguji batas unggahan dan menyesatkan untuk menguji kuota disk.
+ fallocate adalah yang dipakai bila ruangnya harus nyata:
+
+
fallocate -l 10M test10mb.bin
+
Dan bila isinya harus tak dapat dikompres, agar pengarsip tidak bisa memadatkannya kembali:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, yang bukan sparse, dan dua yang sudah Anda kenal
+
+ macOS menyertakan mkfile. Diukur di macOS 26.6.2: 10485760 byte dan 20480 blok,
+ sehingga ruangnya benar-benar dialokasikan, bukan dijanjikan:
+
+
mkfile 10m test10mb.bin
+
dd dan truncate juga ada dan berperilaku seperti di Linux:
File dengan ukuran yang benar bukan file dengan jenis yang benar
+
+ Semua di atas memberi Anda blok nol. Itu cukup bila yang diuji hanya melihat ukuran - batas
+ unggahan, kuota, transfer. Itu berhenti cukup begitu ada yang membuka file itu.
+
+
+ Diukur, dan layak Anda coba sendiri: buat file 2 MB dengan fsutil, namai
+ photo.png, dan serahkan ke pustaka gambar. Pillow menjawab cannot identify
+ image file. Itu bukan PNG. Tidak pernah - hanya namanya yang berkata begitu.
+
+
+ Itu lebih penting daripada kedengarannya, karena arah kegagalan pengujian itu
+ kemudian. Endpoint unggah Anda menolak file, pengujian Anda hijau, dan Anda
+ menyimpulkan batas ukuran berfungsi. Endpoint itu tidak menolaknya karena ukuran. Ia menolaknya
+ karena byte-nya bukan gambar, dan aturan yang ingin Anda uji tidak pernah tercapai.
+
+
+
parser menolaknya sebelum aturan ukuran apa pun diperiksa
+
langkah thumbnail gagal dan galat yang Anda baca adalah tentang thumbnail
+
antivirus atau pemeriksaan konten menolaknya karena alasan ketiga
+
penampil tidak menampilkan apa pun, dan tak seorang pun tahu apakah itu bug-nya
+
+
+
+
+
Jalan lainnya
+
File asli dari format itu, dengan ukuran persis seperti yang Anda minta
+
+ Inilah yang dilakukan Testing Files Generator. File itu adalah file asli dari formatnya - terbuka di
+ aplikasi yang memilikinya - dan berjumlah byte persis seperti yang Anda minta, sampai ke byte:
+
+ Minta ukuran yang tidak dapat dicapai suatu format dan Anda mendapat galat yang menyebut batas bawah
+ dan alasannya, tidak pernah file berukuran salah. Halaman format
+ mencantumkan setiap format beserta file terkecil yang dapat dibuatnya.
+
+
Dan sebuah batas adalah tiga kasus uji, bukan satu, jadi alat ini membuat ketiganya:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Itu memberi Anda 10485759, 10485760, dan 10485761 byte, dan manifes yang menyatakan mana yang harus
+ diterima sistem Anda dan mana yang harus ditolak. Halaman kasus
+ penggunaan membahas itu dan empat pekerjaan lain yang untuknya alat ini dibuat.
+
Gratis dan open source, GPL-3.0. Tanpa pendaftaran. Unduhan Windows dan macOS sudah ditandatangani dan berjalan tanpa peringatan.
+
+
+
+
Jadi mana yang sebaiknya dipakai?
+
+
+
Pakai perintah sistem
+
+ Bila tidak ada yang membuka file. Menguji batas ukuran pada endpoint yang memeriksa ukuran lebih
+ dulu, transfer, kuota, disk penuh. Hanya satu baris dan sudah terpasang.
+
+
+
+
Pakai generator sungguhan
+
+ Bila ada yang mem-parsing, merender, mengimpor, atau mengekstrak file - dan bila Anda memerlukan
+ fixture yang sama besok, di mesin lain, byte demi byte.
+
+
+
+
+ Keduanya ada di halaman ini karena keduanya benar sebagian waktu. Kesalahan yang perlu dihindari
+ adalah memakai yang pertama di tempat yang kedua dibutuhkan dan membaca pengujian hijau sebagai
+ bukti.
+
Apakah file valid yang sekecil yang diizinkan format dapat lolos?
+
+ Preset empty-and-minimal membuat satu set lengkap file uji asli untuk pertanyaan ini dengan
+ satu perintah, dan manifest.json di sampingnya yang menyatakan bagaimana sistem Anda
+ harus bereaksi terhadap tiap file. Semua di bawah dibaca dari program, pada nilai bawaan versi
+ ini.
+
+
+
+
+
Apa yang biasanya ditemukan?
+
+
file valid yang ditolak karena terlalu kecil, ketika pemeriksaan menghitung byte alih-alih membacanya
+
file kosong yang membuat pembaca crash alih-alih dilaporkan
+
gambar selebar satu piksel yang membagi dengan nol dalam perjalanan ke thumbnail
+
penyimpanan yang membaca nol byte sebagai unggahan gagal dan terus mencoba ulang
+
+
+
+
+
+
Apa isi set?
+
Pada nilai bawaan, seperti yang dilaporkan tfg preset show empty-and-minimal:
Apakah sistem saya akan menyimpan, menampilkan, dan mengembalikan nama file yang tidak diduganya?
+
+ Preset filename-handling membuat satu set lengkap file uji asli untuk pertanyaan ini dengan
+ satu perintah, dan manifest.json di sampingnya yang menyatakan bagaimana sistem Anda
+ harus bereaksi terhadap tiap file. Semua di bawah dibaca dari program, pada nilai bawaan versi
+ ini.
+
+
+
+
+
Apa yang biasanya ditemukan?
+
+
nama yang tampak seperti nama lain di layar, di log, atau dalam daftar
+
nama yang dipotong, dipangkas, atau ditulis ulang antara unggahan dan penyimpanan
+
batas panjang yang dihitung dalam karakter padahal penyimpanan menghitung byte
+
+
+
+
+
+
Apa isi set?
+
Pada nilai bawaan, seperti yang dilaporkan tfg preset show filename-handling:
+
+
+
+
File
50
+
Target dalam resepnya
50
+
Ukuran total
51 200 B
+
Format
txt
+
+
+
+
Dan apa yang diharapkan manifes set itu dari sistem Anda:
+
+
+
+
Diharapkan
Arti
File
+
+
+
accept
Sistem Anda harus menerima file ini.
4
+
unspecified
Tergantung pada aturan sistem Anda. Anda yang memutuskan, lalu memeriksa apakah yang terjadi sesuai maksud Anda.
46
+
+
+
+
+
+
+
Apa yang dapat Anda ubah?
+
+
+
+
Pengaturan
Menerima
Bawaan
Fungsinya
+
+
+
+
--format
+
id format dari halaman format
+
txt
+
Format setiap file dalam set. Ini adalah opsi alat itu sendiri, dan preset hanya memberinya nilai bawaan.
+
+
+
+
+
+
+
+
Bagaimana menjalankannya?
+
Lihat biaya set, buat, atau ambil resepnya untuk disunting:
Preset file uji, satu set untuk setiap pertanyaan pengujian
+
+ Preset adalah satu set lengkap file uji yang dirancang di sekitar satu pertanyaan, dengan manifes
+ yang menyatakan bagaimana sistem Anda harus bereaksi terhadap tiap file. Anda memilih pertanyaan,
+ alat membuat setnya. Setiap preset punya halamannya sendiri berisi apa yang biasanya ditemukan,
+ isi set, dan setiap pengaturan yang diterimanya.
+
Apakah formulir unggah saya menerima yang seharusnya dan menolak sisanya?
+
upload-validation
+
+
+
+
+
Apa bedanya preset dengan resep?
+
+ Pada dasarnya tidak ada. Preset adalah resep yang ditulis alat untuk Anda dari beberapa pengaturan.
+ tfg preset eject mencetak resep itu agar dapat Anda simpan di samping pengujian dan
+ sunting, dan resep Anda sendiri dapat dibangun di atas preset dengan satu baris, extends:
+ preset: diikuti id-nya.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Bisakah saya memercayai nilai bawaan?
+
+ Untuk file, ya. Untuk angka yang hanya diketahui sistem Anda, seperti batas formulir unggah, nilai
+ bawaan adalah nilai sementara dari kami, dan alat menyatakannya setiap kali memakainya. Halaman
+ setiap preset menandai pengaturan itu, dan tfg preset show menyatakannya sebelum
+ apa pun ditulis.
+
Apakah batas ukuran ditegakkan tepat di tempat batas itu dinyatakan?
+
+ Preset size-boundaries membuat satu set lengkap file uji asli untuk pertanyaan ini dengan
+ satu perintah, dan manifest.json di sampingnya yang menyatakan bagaimana sistem Anda
+ harus bereaksi terhadap tiap file. Semua di bawah dibaca dari program, pada nilai bawaan versi
+ ini.
+
+
+
+
+
Apa yang biasanya ditemukan?
+
+
kesalahan selisih satu di batas
+
MB tertukar dengan MiB, yaitu 4,8 persen dan cukup untuk meloloskan file yang seharusnya tidak lolos
+
batas yang ditegakkan di browser dan tidak di server
+
+
+
+
+
+
Apa isi set?
+
Pada nilai bawaan, seperti yang dilaporkan tfg preset show size-boundaries:
+
+
+
+
File
7
+
Target dalam resepnya
7
+
Ukuran total
73 400 320 B
+
Format
pdf
+
+
+
+
Dan apa yang diharapkan manifes set itu dari sistem Anda:
+
+
+
+
Diharapkan
Arti
File
+
+
+
accept
Sistem Anda harus menerima file ini.
4
+
reject
Sistem Anda harus menolak file ini.
3
+
+
+
+
+
+
+
Apa yang dapat Anda ubah?
+
+
+
+
Pengaturan
Menerima
Bawaan
Fungsinya
+
+
+
+
--limit
+
ukuran seperti 2mb
+
10mb
+
Batas ukuran yang dinyatakan sistem Anda. Semua yang lain diukur dari sini. Nilai bawaan ini adalah nilai sementara dari kami, bukan nilai sistem Anda. Berikan nilai Anda sendiri.
+
+
+
--spread
+
ukuran dipisahkan koma
+
1B,1kb,1mb
+
Seberapa jauh menjangkau di kedua sisi batas, sebagai daftar ukuran.
+
+
+
--format
+
id format dari halaman format
+
pdf
+
Format setiap file dalam set. Ini adalah opsi alat itu sendiri, dan preset hanya memberinya nilai bawaan.
+
+
+
+
+
+
+
+
Bagaimana menjalankannya?
+
Lihat biaya set, buat, atau ambil resepnya untuk disunting:
Apakah impor tabel saya tahan terhadap apa yang diekspor alat sungguhan?
+
+ Preset tabular-import membuat satu set lengkap file uji asli untuk pertanyaan ini dengan
+ satu perintah, dan manifest.json di sampingnya yang menyatakan bagaimana sistem Anda
+ harus bereaksi terhadap tiap file. Semua di bawah dibaca dari program, pada nilai bawaan versi
+ ini.
+
+
+
+
+
Apa yang biasanya ditemukan?
+
+
file titik koma yang terbaca sebagai satu kolom, karena pemisah diasumsikan alih-alih dicari
+
file CRLF yang terpecah menjadi baris dengan baris kosong setelah masing-masing
+
tabel tanpa header yang baris data pertamanya termakan sebagai nama kolom
+
impor yang mempertahankan kolom yang bisa ditampilkan dan membuang sisanya tanpa kata
+
pembaca yang mengambil record JSON satu baris sekaligus dan berhenti di dokumen berindentasi pertama
+
+
+
+
+
+
Apa isi set?
+
Pada nilai bawaan, seperti yang dilaporkan tfg preset show tabular-import:
+
+
+
+
File
13
+
Target dalam resepnya
13
+
Ukuran total
3 080 060 B
+
Format
csv, json, xlsx
+
+
+
+
Dan apa yang diharapkan manifes set itu dari sistem Anda:
+
+
+
+
Diharapkan
Arti
File
+
+
+
accept
Sistem Anda harus menerima file ini.
8
+
unspecified
Tergantung pada aturan sistem Anda. Anda yang memutuskan, lalu memeriksa apakah yang terjadi sesuai maksud Anda.
5
+
+
+
+
+
+
+
Apa yang dapat Anda ubah?
+
+
+
+
Pengaturan
Menerima
Bawaan
Fungsinya
+
+
+
+
--rows
+
1 - 200000 baris
+
1000
+
Berapa banyak baris yang dimuat spreadsheet. File ditulis tepat pada ukuran sebanyak itu baris, sehingga anggaran di atas bergeser mengikuti nilai ini.
+
+
+
--columns
+
1 - 32768 kolom
+
10
+
Berapa banyak kolom di setiap baris spreadsheet. Baris kali kolom memiliki batas atas, dan meminta melebihinya ditolak sebelum apa pun ditulis.
+
+
+
+
+
+
+
+
Bagaimana menjalankannya?
+
Lihat biaya set, buat, atau ambil resepnya untuk disunting:
Apakah pembaca saya tahu enkoding suatu file, atau hanya menebak?
+
+ Preset text-encoding membuat satu set lengkap file uji asli untuk pertanyaan ini dengan
+ satu perintah, dan manifest.json di sampingnya yang menyatakan bagaimana sistem Anda
+ harus bereaksi terhadap tiap file. Semua di bawah dibaca dari program, pada nilai bawaan versi
+ ini.
+
+
+
+
+
Apa yang biasanya ditemukan?
+
+
pembaca yang mengasumsikan UTF-8 dan menampilkan file UTF-16 sebagai satu karakter dari tiga, atau sebagai deretan kotak
+
byte order mark terbaca sebagai isi, sehingga kolom pertama impor dimulai dengan tiga karakter asing
+
importer yang menebak enkoding dari byte pembuka dan menebak berbeda untuk file yang lebih panjang
+
file CRLF yang terpecah menjadi baris dengan baris kosong setelah masing-masing, atau carriage return yang tertinggal di kolom terakhir
+
+
+
+
+
+
Apa isi set?
+
Pada nilai bawaan, seperti yang dilaporkan tfg preset show text-encoding:
+
+
+
+
File
20
+
Target dalam resepnya
20
+
Ukuran total
81 920 B
+
Format
csv, log, md, txt, xml
+
+
+
+
Dan apa yang diharapkan manifes set itu dari sistem Anda:
+
+
+
+
Diharapkan
Arti
File
+
+
+
accept
Sistem Anda harus menerima file ini.
10
+
unspecified
Tergantung pada aturan sistem Anda. Anda yang memutuskan, lalu memeriksa apakah yang terjadi sesuai maksud Anda.
10
+
+
+
+
+
+
+
Apa yang dapat Anda ubah?
+
+
+
+
Pengaturan
Menerima
Bawaan
Fungsinya
+
+
+
+
--sample
+
ukuran seperti 2mb
+
4kb
+
Seberapa besar setiap file dalam set. UTF-16 menyimpan dua byte untuk setiap karakter, sehingga angka ganjil ditolak.
+
+
+
+
+
+
+
+
Bagaimana menjalankannya?
+
Lihat biaya set, buat, atau ambil resepnya untuk disunting:
Apakah formulir unggah saya menerima yang seharusnya dan menolak sisanya?
+
+ Preset upload-validation membuat satu set lengkap file uji asli untuk pertanyaan ini dengan
+ satu perintah, dan manifest.json di sampingnya yang menyatakan bagaimana sistem Anda
+ harus bereaksi terhadap tiap file. Semua di bawah dibaca dari program, pada nilai bawaan versi
+ ini.
+
+
+
+
+
Apa yang biasanya ditemukan?
+
+
batas yang ditegakkan di browser dan tidak di server
+
file SVG atau HTML yang dikira gambar atau teks biasa, yang merupakan cara meloloskan skrip lewat formulir
+
file yang diperiksa dari ekstensinya dan tak pernah dibuka, sehingga PDF bernama .jpg lolos
+
formulir yang membaca seluruh isi ke memori sebelum melihat seberapa besar isinya
+
unggahan bernama PHOTO.JPG yang ditolak sementara photo.jpg diterima, atau sebaliknya
+
nama dengan spasi, tanda kurung, atau karakter di luar ASCII yang ditulis ke disk tanpa perubahan
+
+
+
+
+
+
Apa isi set?
+
Pada nilai bawaan, seperti yang dilaporkan tfg preset show upload-validation:
+
+
+
+
File
71
+
Target dalam resepnya
22
+
Ukuran total
120 639 488 B
+
Format
html, jpg, pdf, png, svg, txt
+
+
+
+
Dan apa yang diharapkan manifes set itu dari sistem Anda:
+
+
+
+
Diharapkan
Arti
File
+
+
+
accept
Sistem Anda harus menerima file ini.
56
+
reject
Sistem Anda harus menolak file ini.
10
+
unspecified
Tergantung pada aturan sistem Anda. Anda yang memutuskan, lalu memeriksa apakah yang terjadi sesuai maksud Anda.
5
+
+
+
+
+
+
+
Apa yang dapat Anda ubah?
+
+
+
+
Pengaturan
Menerima
Bawaan
Fungsinya
+
+
+
+
--limit
+
ukuran seperti 2mb
+
10mb
+
Batas ukuran yang dinyatakan formulir unggah Anda. Set ini mengambil satu langkah di tiap sisinya - untuk file di setiap jarak, jalankan preset size-boundaries. Nilai bawaan ini adalah nilai sementara dari kami, bukan nilai sistem Anda. Berikan nilai Anda sendiri.
+
+
+
--allow
+
id format dipisahkan koma
+
jpg,png,pdf
+
Tipe apa yang seharusnya diterima formulir Anda. Masing-masing menjadi file asli bertipe itu, dan menjadi kontrol positif bagi seluruh set.
+
+
+
--deny
+
ekstensi dipisahkan koma
+
svg,html,exe,sh
+
Ekstensi apa yang seharusnya ditolak formulir Anda. Ekstensi yang tidak punya format di build ini tetap mendapat file bernama itu, berisi teks biasa.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
Seberapa jauh di atas batas file besar tunggal itu. Matikan bila menulis beberapa kali batas tidak sepadan dengan disknya.
+
+
+
--bulk
+
0 - 10000 file
+
50
+
Berapa banyak file dalam unggahan massal. Nol membuang kelompok itu dari set sepenuhnya.
+
+
+
+
+
+
+
+
Bagaimana menjalankannya?
+
Lihat biaya set, buat, atau ambil resepnya untuk disunting:
+ Cinque compiti che ricorrono in quasi ogni progetto che accetta file dalle persone, e il comando che
+ esegue ciascuno. Ogni esempio qui sotto funziona così com'è scritto.
+
+
+
+
Limiti di upload
+
Testare se un limite di dimensione dei file è applicato dove dice di esserlo
+
+ Un limite sono tre casi di test, non uno: appena sotto, esattamente sul limite e appena sopra.
+ Ottenerli a mano significa calcolare numeri di byte sperando di non sbagliare di uno. Chiedi
+ invece il set:
+
+ Ottieni tre PDF reali da 1048575, 1048576 e 1048577 byte, e un manifest che dice che i primi due
+ vanno accettati e il terzo rifiutato per size_limit. Il tuo test legge
+ l'aspettativa invece che tu scriva tre asserzioni a mano - e quando il limite cambia, cambi un
+ numero e riesegui.
+
+
+ Lo stesso funziona senza preset quando vuoi un singolo set di limiti in linea:
+
Tenere le fixture fuori dal repository senza perderle
+
+ Grandi fixture binarie rendono un repository lento da clonare e scomodo da rivedere, e nessuno sa
+ dire cosa è cambiato quando una viene sostituita. Una ricetta è qualche centinaio di caratteri
+ di YAML che ricostruiscono i file identici - byte per byte, su qualsiasi
+ macchina - perché ogni file deriva dal seed dell'esecuzione.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Ogni conclusione ha il suo codice di uscita, quindi una pipeline distingue una ricetta sbagliata da
+ un disco pieno e da una discrepanza di verifica. Un'esecuzione fallita non stampa nulla sullo
+ standard output, il che evita che un parser di log legga un errore come dato.
+
+
+
+
+
Scala
+
Scoprire cosa succede quando la cartella è grande
+
+ Routine di importazione, job notturni ed elenchi di directory si comportano diversamente con
+ diecimila file che con dieci. Dimensioni estratte da un intervallo fanno sembrare il set
+ traffico reale anziché diecimila file identici, e l'estrazione viene dal seed, quindi il set è
+ lo stesso domani.
+
+ Un'esecuzione più grande dello spazio libero sul disco viene rifiutata prima che sia scritto il
+ primo byte, invece di riempire il disco e fallire a metà.
+
+
+
+
+
Archivi
+
Testare un decompressore con un archivio che contiene davvero dei file
+
+ Un archivio vuoto con l'estensione giusta non dimostra nulla sul codice che lo apre e percorre ciò
+ che c'è dentro. Dichiara il contenuto e l'archivio lo contiene davvero:
+
+ Profondità di annidamento, numero di voci e dimensione di ciò che c'è dentro sono tutte cose su cui
+ una routine di importazione ha opinioni, ed è così che scopri quali sono.
+
+
+
+
+
Parser e visualizzatori
+
Verificare che il tuo codice legga un formato come fa il software reale
+
+ Ogni formato qui è verificato con un lettore indipendente prima del rilascio - un PNG viene aperto e
+ i suoi pixel confrontati, un DOCX viene riletto da librerie separate, un archivio viene
+ estratto. Ciò significa che un file che il tuo parser rifiuta è una scoperta sul tuo parser, non
+ sul generatore.
+
+ La pagina dei formati elenca le impostazioni che ciascuno accetta e il
+ file più piccolo che ciascuno può essere.
+
+
+
+
+
Guide
+
Due di questi più in dettaglio
+
+
+ File di test corrotti - un file rotto di proposito, della
+ dimensione esatta, con nel manifest ciò che deve succedergli.
+
+
+ File di test in CI - un workflow GitHub Actions, un job GitLab
+ e i codici di uscita che fanno fallire una build.
+
+
+
+
+
+
Per chi è
+
+ Ingegneri QA, automazione dei test e chiunque abbia dietro al proprio codice un modulo di upload,
+ una routine di importazione, un parser o una quota di storage. Gira su una macchina senza alcuna
+ rete, il che conta in un ambiente aziendale chiuso dove un generatore basato su browser non è
+ un'opzione.
+
+ Ogni sistema ha un comando per farlo, e tutti e tre sono qui sotto. Ti danno un file con esattamente
+ il numero giusto di byte - e per molti test è tutto ciò che serve. Ogni comando di questa
+ pagina è stato eseguito prima della pubblicazione, sul sistema a cui appartiene.
+
+
+
+
La risposta breve
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Le dimensioni sono in byte, e 10 MB
+ contati come li conta il tuo file manager sono 10485760.
+
+
+
+
+
Windows
+
fsutil, e una versione PowerShell che non richiede nulla di extra
+
+ fsutil è incluso in Windows. Prende la dimensione in byte, quindi
+ calcola prima il numero - 10 MB sono 10485760, 100 MB sono 104857600, 1 GB è 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Misurato su Windows 11: funziona da un prompt normale senza richiederne uno con privilegi elevati, e
+ il file esce di esattamente 10485760 byte.
+
+
PowerShell può fare lo stesso senza chiamare un altro programma, e capisce le unità:
+ 10MB in PowerShell significa 10485760 byte, lo stesso conteggio in base 1024 che usa
+ Esplora risorse, quindi i due comandi qui sopra producono la stessa dimensione.
+
+
+
+
+
Linux
+
dd, truncate e fallocate, e la differenza che frega le persone
+
dd è quello che conoscono tutti. Scrive davvero i byte:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate è istantaneo, ed è questa la trappola. Misurato su Alpine Linux, il file
+ riporta 10485760 byte e occupa zero blocchi - è un file
+ sparso. Qualsiasi cosa lo legga ottiene dieci megabyte di zeri, ma il disco non ha mai
+ ceduto lo spazio:
+
+
truncate -s 10M test10mb.bin
+
+ Va bene per testare un limite di upload ed è fuorviante per testare una quota di disco.
+ fallocate è quello da usare quando lo spazio deve essere reale:
+
+
fallocate -l 10M test10mb.bin
+
E quando il contenuto deve essere incomprimibile, così un archiviatore non può ridurlo di nuovo:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, che non è sparso, e i due che conosci già
+
+ macOS include mkfile. Misurato su macOS 26.6.2: 10485760 byte e 20480 blocchi, quindi
+ lo spazio è davvero allocato invece che promesso:
+
+
mkfile 10m test10mb.bin
+
Ci sono anche dd e truncate, e si comportano come su Linux:
Un file della dimensione giusta non è un file del tipo giusto
+
+ Tutto quanto sopra ti dà un blocco di zeri. Basta quando ciò che è sotto test guarda solo la
+ dimensione - un limite di upload, una quota, un trasferimento. Smette di bastare nel momento in
+ cui qualcosa apre il file.
+
+
+ Misurato, e vale la pena provarlo di persona: crea un file da 2 MB con fsutil, chiamalo
+ photo.png e passalo a una libreria di immagini. Pillow risponde cannot
+ identify image file. Non è un PNG. Non lo è mai stato - lo diceva solo il nome.
+
+
+ Conta più di quanto sembri, per via di come il test fallisce a quel punto. Il tuo
+ endpoint di upload rifiuta il file, il tuo test diventa verde e concludi che il limite di
+ dimensione funziona. Non lo ha rifiutato per la dimensione. Lo ha rifiutato perché i byte non
+ erano un'immagine, e la regola che volevi testare non è mai stata raggiunta.
+
+
+
un parser lo rifiuta prima che venga guardata qualsiasi regola di dimensione
+
un passaggio di miniatura fallisce e l'errore che leggi riguarda la miniatura
+
un antivirus o un controllo del contenuto lo rifiuta per un terzo motivo
+
un visualizzatore non mostra nulla, e nessuno sa dire se sia quello il bug
+
+
+
+
+
L'altra strada
+
Un file reale di quel formato, della dimensione esatta che hai chiesto
+
+ È ciò che fa Testing Files Generator. Il file è un vero file del suo formato - si apre nel programma
+ che gli appartiene - e ha l'esatto numero di byte che hai chiesto, al byte:
+
+ Chiedi una dimensione che un formato non può raggiungere e ottieni un errore che nomina il minimo e
+ il suo motivo, mai un file della dimensione sbagliata. La pagina dei
+ formati elenca ogni formato con il file più piccolo che può produrre.
+
+
E un limite sono tre casi di test anziché uno, quindi lo strumento li costruisce tutti e tre:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Ti dà 10485759, 10485760 e 10485761 byte, e un manifest che dice quali il tuo sistema deve accettare
+ e quali rifiutare. La pagina dei casi d'uso ripercorre questo e
+ altri quattro compiti per cui è pensato.
+
Gratuito e open source, GPL-3.0. Nessuna registrazione. I download per Windows e macOS sono firmati e si avviano senza avvisi.
+
+
+
+
Quindi, quale usare?
+
+
+
Usa il comando di sistema
+
+ Quando nulla apre il file. Testare un limite di dimensione su un endpoint che controlla prima la
+ dimensione, un trasferimento, una quota, un disco pieno. È una riga ed è già installato.
+
+
+
+
Usa un generatore vero
+
+ Quando qualcosa analizza, renderizza, importa o estrae il file - e quando ti servono le stesse
+ fixture domani, su un'altra macchina, byte per byte.
+
+
+
+
+ Entrambi sono su questa pagina perché entrambi hanno ragione una parte del tempo. L'errore da
+ evitare è usare il primo dove serve il secondo e leggere il test verde come una prova.
+
+ Tutto ciò che fa lo strumento, organizzato come le domande con cui le persone arrivano davvero. Il
+ README nel repository è il riferimento completo e corrisponde
+ sempre alla build che hai scaricato.
+
+
+
+
Quali comandi esistono?
+
Ognuno fa una cosa sola:
+
tfg generate produrre file, da una ricetta o da opzioni
+tfg validate controllare una ricetta senza scrivere nulla
+tfg verify controllare una directory rispetto a un manifest
+tfg cleanup rimuovere i file elencati da un manifest
+tfg recipe fmt stampare una ricetta nella sua forma normalizzata
+tfg preset costruire un set di file a partire da una domanda di test con nome
+tfg formats elencare i formati supportati da questa versione
+tfg damage elencare i modi in cui questa versione può rompere un file di proposito
+tfg tool piccole utilità per file che hai già
+tfg version stampare la versione dello strumento
+tfg license stampare la licenza e cosa significa per i file generati
+
+
+
+
Come genero un singolo file di dimensione esatta?
+
+ Indica il formato, la dimensione e la destinazione. Le dimensioni si contano a 1024, quindi
+ 2mb sono 2097152 byte. Funziona anche un semplice numero di byte, quindi
+ --size 10485761 chiede esattamente quel numero.
+
+
tfg generate --format png --size 2mb --out ./out
+
Le opzioni utili di generate:
+
+
+
Opzione
Cosa fa
+
+
--format <id>
formato dei file, per esempio txt
+
--size <size>
dimensione esatta di ogni file, come 10mb o un semplice numero di byte
+
--size-range <a-b>
una dimensione estratta per file da un intervallo, come 1kb-8kb. L'estrazione viene dal seed
+
--boundary <size>
tre file attorno a un limite: un byte sotto, il limite, un byte sopra
+
--count <n>
quanti file produrre. Predefinito 1
+
--name <template>
modello del nome, per esempio invoice_{index:04}.txt
+
--out <dir>
directory in cui scrivere
+
--seed <n>
seed dell'esecuzione. Lo stesso seed dà gli stessi byte
+
--set <k>=<v>
un'impostazione di formato, ripetibile
+
--damage <name>
rompere i file di proposito, ripetibile e applicato in ordine. Esegui tfg damage per l'elenco
+
--expected <outcome>
accept, reject, sanitize oppure unspecified
+
--dry-run
contare e mostrare, senza scrivere assolutamente nulla
+
--json
scrivere il manifest sullo standard output
+
+
+
+
+
+
+
Come faccio un file rotto di proposito?
+
+ Ogni altro file che questo strumento scrive è corretto per costruzione, il che risponde a due delle
+ tre domande che pone un validatore di upload. --damage risponde alla terza - il
+ file si apre, almeno. Il file viene prodotto normalmente e poi rotto, quindi ha ancora la
+ dimensione che hai chiesto.
+
+ Le impostazioni vanno dopo i due punti. L'opzione si ripete, e l'ordine in cui le scrivi è l'ordine
+ in cui vengono applicate. tfg damage elenca cosa può fare questa versione e cosa
+ accetta ciascuno.
+
+
In una ricetta la chiave è un elenco, di nomi o di impostazioni:
+ Un file danneggiato riceve expected: reject nel manifest, con il danno registrato
+ accanto. Due cose vengono rifiutate prima di scrivere qualsiasi cosa, perché ciascuna metterebbe
+ su disco un file che il manifest descrive in modo sbagliato:
+
+
+
un file più piccolo di quanto serve al danno, perché uscirebbe invariato
+
+ expected: accept accanto a un danno, perché nulla potrebbe soddisfarlo. Scrivi
+ sanitize se il sistema sotto test deve riparare il file, oppure
+ unspecified se è proprio la domanda che stai ponendo
+
+
+
+ Una terza non si può sapere in anticipo. Se un danno viene eseguito e non sposta alcun byte, quel
+ file viene scartato invece di essere scritto - l'esecuzione prosegue, dice di quale file si
+ trattava e termina con il codice di uscita parziale.
+
+ Una ricetta è un file YAML che descrive un'intera esecuzione. Committala accanto ai tuoi test e le
+ fixture smettono di essere binari nel tuo repository - chiunque può ricostruirle, byte per byte,
+ da un file di poche centinaia di caratteri.
+
+ Ogni target richiede esattamente una di queste chiavi: size, size-range,
+ boundary o contains. Due è un errore, e anche nessuna. Una ricetta non
+ valida scrive nessun file e segnala tutti i problemi insieme invece del solo
+ primo, ognuno con il nome dell'impostazione a cui si riferisce.
+
+
+
+
+
Come dichiaro cosa deve fare il mio sistema con un file?
+
Forma breve quando basta l'esito, forma lunga quando conta il motivo:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Gli esiti sono accept, reject, sanitize e
+ unspecified. I motivi sono un elenco chiuso così un report può raggrupparli:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit e size_zero.
+
+
+ Un motivo nomina la regola in gioco, non il verdetto. Ecco perché lo stesso motivo
+ può stare sotto l'uno o l'altro esito - un file un byte sotto un limite è accept, e
+ la regola in questione resta size_limit.
+
+
+
+
+
Cosa c'è nel manifest?
+
+ Viene scritto accanto ai file alla fine di ogni esecuzione, compresa un'esecuzione interrotta. Una
+ voce per file:
+
+ Un recipe_hash viene aggiunto quando l'esecuzione viene da una ricetta, e
+ preset con overrides quando viene da un preset, così un manifest si
+ può sempre ricondurre a ciò che lo ha prodotto.
+
+
+ Ogni voce porta anche target_id, l'id del target della ricetta che ha prodotto il file,
+ e summary.by_target conta i file a cui è arrivato ciascun target. Una ricetta con
+ più target si può quindi controllare target per target senza leggere i nomi dei file.
+
+
+
+
+
Cos'è un preset?
+
+ Un set di file pronto che risponde a una domanda di test comune, così non devi progettare il set tu.
+ I preset sono ricette ordinarie sotto il cofano, e eject stampa la ricetta così
+ puoi modificarla da lì. Ogni preset ha una pagina tutta sua con cosa
+ trova di solito, cosa c'è nel set e ogni impostazione che accetta.
+
+ show ti dice quanto costerebbe il set prima di costruirlo, e dice apertamente quando un
+ numero è un segnaposto nostro anziché un limite tuo.
+
+
+
+
+
Cosa significano i codici di uscita?
+
+ Ogni conclusione ha il suo codice, l'output leggibile da macchina va sullo standard output, e
+ un'esecuzione fallita non vi stampa nulla. La tabella è un contratto congelato - cambiare il
+ significato di un codice richiede una versione maggiore.
+
+
+
+
+
+
Codice
+
Significato
+
+
+
+
+
0
+
Tutto ha funzionato.
+
+
+
1
+
Un errore imprevisto dentro lo strumento.
+
+
+
2
+
Comando od opzione errati.
+
+
+
3
+
La ricetta non è valida.
+
+
+
4
+
Il formato non può fare ciò che è stato chiesto.
+
+
+
5
+
Una lettura o una scrittura è fallita.
+
+
+
6
+
Spazio su disco insufficiente.
+
+
+
7
+
verify ha trovato una discrepanza.
+
+
+
8
+
L'esecuzione è terminata ma non tutto è stato prodotto.
+
+
+
130
+
Interrotto con Ctrl+C.
+
+
+
143
+
Fermato da un segnale, che è l'aspetto di un timeout della CI.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Un'esecuzione fermata con Ctrl+C lascia comunque un manifest e non lascia mai un file scritto a
+ metà, così un job annullato può ancora essere ripulito dal successivo.
+
+ Sì, lo stesso motore con una finestra sopra, per il test che non è automatizzato. Non è una versione
+ ridotta: un test confronta le due interfacce capacità per capacità, e tutto ciò che può fare
+ solo una delle due va dichiarato e giustificato invece di divergere in silenzio.
+
+
+ Le schermate sono un lotto, i preset, più lotti insieme e Informazioni. Mostra quanto costerebbe
+ un'esecuzione prima di scrivere qualsiasi cosa, riporta l'avanzamento mentre gira e si può
+ annullare a metà senza lasciare un file scritto a metà. Non apre ancora un file di ricetta - per
+ ora le ricette sono una faccenda da riga di comando, e la finestra costruisce i suoi lotti nel
+ modulo.
+
+ Licenza, privacy, riproducibilità e le cose che le persone controllano prima di mettere un
+ generatore in una pipeline di build. Se la tua domanda non c'è, il
+ tracker delle issue è aperto.
+
+
+
+
+
In cosa è diverso da dd, fsutil o truncate?
+
+
Quei comandi ti danno un file della dimensione giusta pieno di niente. Un file da 2 MB chiamato photo.png fatto così non è un PNG, quindi qualsiasi cosa lo analizzi davvero lo rifiuta per il motivo sbagliato, e anche il tuo test passa per il motivo sbagliato. Questo produce un vero PNG di esattamente 2 MB che si apre in un visualizzatore di immagini, e arriva con una dichiarazione su come il tuo sistema deve trattarlo.
Sì a entrambe. È rilasciato sotto GPL-3.0 e non costa nulla. Non c'è un account, né una chiave di licenza, né un livello a pagamento.
+
+
+
+
Posso usare i file generati in un prodotto closed source?
+
+
Sì. La licenza copre il codice dello strumento, non ciò che lo strumento produce. File, ricette e manifest generati sono output e non opere derivate, quindi puoi committarli e distribuirli senza alcun obbligo.
+
+
+
+
I file generati contengono dati personali reali?
+
+
No. Tutto ciò che contengono è sintetizzato da un seed. Nessun dataset viene letto, nessun servizio viene contattato e nessun contenuto di terzi è incorporato. Considera un indirizzo e-mail generato inutilizzabile anziché inutilizzato, perché qualsiasi stringa casuale può coincidere per caso con uno reale.
+
+
+
+
Otterrò esattamente gli stessi file su un'altra macchina?
+
+
Sì, byte per byte, con la stessa ricetta e lo stesso seed. Il progetto lo verifica a ogni modifica, e romperlo richiede una versione maggiore. È ciò che ti permette di committare una piccola ricetta invece di grandi fixture binarie.
+
+
+
+
Serve una connessione a internet?
+
+
Mai. Non c'è telemetria, né controllo degli aggiornamenti, né client cloud, e il binario della riga di comando non ha alcuno stack di rete compilato al suo interno. Funziona su una macchina senza rete e in un ambiente aziendale chiuso.
+
+
+
+
Cosa succede se chiedo una dimensione che un formato non può raggiungere?
+
+
Ottieni un errore che nomina il formato, il minimo possibile, il motivo di quel limite inferiore e cosa fare invece, e nessun file viene scritto. Lo strumento non arrotonda mai una dimensione in silenzio. Ogni minimo è elencato nella pagina dei formati.
+
tfg formats png
+
+
+
+
Posso generare un file deliberatamente rotto?
+
+
Sì. Aggiungi --damage zero-head e il file esce con esattamente la dimensione richiesta, con i primi byte sovrascritti da zeri, così un lettore lo rifiuta, e il manifest dice che il tuo sistema deve rifiutarlo. I dettagli sono nella pagina sui file di test corrotti.
7z, mp3 e mp4. Oggi 26 formati funzionano da un capo all'altro.
+
+
+
+
Su quali sistemi posso eseguirlo?
+
+
La riga di comando gira su Windows e Linux sia su Intel sia su ARM, e sui Mac con Apple Silicon. La finestra desktop è fornita per Windows su Intel, Linux su Intel e Mac con Apple Silicon. I Mac Intel non sono supportati e non viene compilato nulla per loro.
+
+
+
+
Devo installare qualcosa?
+
+
No. Scarica l'archivio per il tuo sistema, decomprimilo ed esegui il binario. Non c'è un installer, né un runtime da aggiungere, né una dipendenza da risolvere. Se hai Go, funziona anche un solo comando go install.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
Perché un'esecuzione su migliaia di file è più lenta su Windows?
+
+
Perché Windows fa pagare di più ogni percorso che esamina, e un comando che passa su migliaia di file esamina migliaia di percorsi. Misurato su una macchina con 3000 file da 1 kB, verify impiega circa 0,9 secondi su Windows e circa 0,2 secondi su Linux in un container. Un percorso di output più corto abbassa il valore di Windows, perché ogni cartella sopra i file fa parte di ciò che viene esaminato.
+ Un validatore a cui sono stati mostrati solo file sani non è stato davvero testato. Ecco come
+ ottenere un file rotto di proposito, che esce con esattamente la dimensione
+ richiesta e porta un manifest che dice cosa il tuo sistema deve farne.
+
+
+
+
La risposta breve
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out scrive un PNG di
+ esattamente 2097152 byte i cui primi byte sono zeri, e il manifest accanto registra che il tuo
+ sistema deve rifiutarlo.
+
+
+
+
+
Il modo solito
+
Perché un file corrotto a mano è un cattivo test
+
+ I modi soliti sono un editor esadecimale, uno script che cambia qualche byte a caso o un file
+ accorciato con head o truncate. Funzionano una volta, poi costano:
+
+
+
+ È diverso ogni volta. Un byte casuale cade in un punto nuovo a ogni esecuzione,
+ quindi un errore del martedì può non ripresentarsi il mercoledì.
+
+
+ Cambia la dimensione. Un file tagliato è più piccolo del limite sotto cui doveva
+ stare, quindi il controllo della dimensione risponde prima di quello del contenuto e il test
+ passa per il motivo sbagliato.
+
+
+ Spesso passa inosservato. Il testo semplice si legge ancora con un byte cambiato
+ nel mezzo, e un lettore di immagini indulgente lo disegna e basta, così il file che doveva
+ essere rotto viene accettato.
+
+
+ Non dice nulla su cosa deve succedere. Il file è solo byte, e chi legge il test
+ dopo deve indovinare se si voleva l'accettazione o il rifiuto.
+
+
+
+
+
+
Cosa ottieni
+
Un file danneggiato ha ancora la dimensione richiesta
+
+ Il file viene generato normalmente e rotto dopo, mentre va verso il disco. Mantiene la dimensione
+ richiesta, e lo stesso comando riscrive gli stessi byte.
+
+ Le impostazioni vanno dopo i due punti. L'opzione si può ripetere, e i danni vengono applicati
+ nell'ordine in cui li scrivi. Funziona con ognuno dei 26 formati.
+
+
+
+
+
Cosa sa fare
+
Quali danni ci sono?
+
+ Questa è la lista che il programma stampa, letta da lui quando si costruisce questa pagina.
+ tfg damage stampa la stessa, e tfg damage <id> dice cosa accetta
+ ciascuno.
+
+
+
+
+
+
Danno
+
Cosa fa ai byte
+
File più piccolo
+
Impostazioni
+
+
+
+
+
zero-head
+
Sovrascrive con zeri i primi byte del file, lasciandone intatta la lunghezza. La maggior parte dei lettori guarda prima lì, quindi quasi tutto si accorge di questo danno.
+
8
+
bytes
+
+
+
+
+
+ zero-head scrive zeri sull'inizio del file. La maggior parte dei lettori guarda prima
+ lì, la firma e l'intestazione che dicono cos'è il file, quindi quasi ogni lettore se ne accorge.
+ Il testo semplice e i log non hanno firma e vengono rifiutati lo stesso, perché una serie di
+ byte nulli non è testo. Sotto i quattro byte alcuni formati escono con un danno di cui nessun
+ lettore si lamenta, ed è per questo che l'impostazione parte da quattro.
+
+
+
+
+
Cosa dice il manifest
+
Un manifest che dice cosa deve succedere
+
+ Ogni file danneggiato riceve una voce che dice che il tuo sistema deve rifiutarlo, con il danno
+ registrato accanto:
+
+ Due richieste vengono rifiutate prima che venga scritto qualcosa, perché ciascuna lascerebbe su
+ disco un file che il manifest descrive male:
+
+
+
un file più piccolo di quanto serve al danno, che uscirebbe intatto
+
+ expected: accept accanto a un danno, perché nulla potrebbe soddisfarlo. Scrivi
+ sanitize se il tuo sistema deve riparare il file, oppure unspecified
+ se è proprio questa la domanda che poni
+
+
+
+
+
+
In una ricetta
+
File sani e rotti in una sola esecuzione
+
+ Metti entrambi in una ricetta, e il manifest porta l'aspettativa di ogni file, così il test non ha
+ bisogno di un elenco di quale sia quale:
+
+ Il test legge il manifest e controlla che ciò che è successo sia ciò che era stato dichiarato. Non
+ ha bisogno di un elenco di nomi di file:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Un buon rifiuto è un rifiuto pulito. Un messaggio che dice cosa non andava è la risposta che vuoi.
+ Un errore del server, un blocco o un file salvato a metà è il difetto che questo test esiste per
+ trovare.
+
+
+
+
+
Avanti
+
Dove andare da qui
+
+
+ Il preset upload-validation pone a un modulo le altre
+ due domande, quella sulla dimensione e quella sul tipo.
+
+
+ File di test in CI esegue in una pipeline una ricetta come
+ questa.
+
+ Una fixture binaria in un repository resta per sempre nella sua cronologia, non si può rivedere in
+ un diff e diventa impossibile quando il file è grande. Genera invece i file dentro la pipeline a
+ partire da una ricetta. La ricetta è testo, i byte escono uguali ogni volta e un ultimo passo
+ dimostra che nulla si è mosso.
+
+
+
+
La risposta breve
+
+ Installa tfg, esegui tfg generate fixtures.yaml --out ./fixtures prima dei
+ test e tfg verify ./fixtures/manifest.json dopo. Entrambi i passi fanno fallire la
+ build da soli, con un codice di uscita che dice perché.
+
+
+
+
+
Perché non committarli
+
Perché una fixture non deve stare nel repository
+
+
+ Resta nella cronologia. Cancellare un binario in seguito non rende più piccolo un
+ clone, perché ogni sua versione è ancora lì.
+
+
+ Un diff non mostra cosa è cambiato. Chi rivede vede che un PDF è diverso e
+ nient'altro. Una ricetta cambia di una riga.
+
+
+ I file grandi non ci stanno. GitHub rifiuta un push che contiene un file sopra i
+ 100 MB, quindi un test di un limite di upload di 500 MB non ha nulla da committare.
+
+
+
+ Quello da committare è la ricetta. La stessa ricetta con lo stesso seme scrive gli stessi byte su
+ ogni macchina, quindi il file generato nella pipeline è il file che avevi sul portatile.
+
+
+
+
+
La ricetta
+
Una ricetta che vive accanto ai test
+
+ Questa scrive venticinque fatture che devono essere accettate e due immagini oltre un limite che
+ devono essere rifiutate, e il manifest registra entrambe le aspettative:
+
+ La riga della somma di controllo confronta l'archivio con verify-SHA256SUMS.txt della
+ stessa versione. La versione è fissata, quindi una nuova versione non cambia mai una build che
+ non hai toccato.
+
+ Ogni conclusione ha il suo codice di uscita, quindi il passo fallisce da solo e il log dice quale.
+ Quelli che incontra una pipeline:
+
+
+
3 - la ricetta non è valida. Non è stato scritto nulla e ogni problema è nominato
+
4 - il formato non può fare ciò che è stato chiesto, per esempio una dimensione sotto il suo minimo
+
6 - non c'è abbastanza spazio su disco
+
7 - tfg verify ha trovato un file che non corrisponde al suo manifest
+
8 - l'esecuzione è finita, ma non tutto è stato prodotto
+
+
+ Un'esecuzione fallita non stampa nulla sullo standard output, così un parser di log non scambia mai
+ un errore per dati. La tabella completa è nella pagina della
+ documentazione.
+
+
+
+
+
PowerShell
+
Uno script PowerShell richiede una riga in più
+
+ PowerShell non porta fuori da un file .ps1 il codice di uscita di un programma.
+ Eseguine uno con -File e lo script risponde 0 anche quando lo
+ strumento al suo interno ha rifiutato il lavoro, così una build che dovrebbe essere rossa
+ diventa verde. L'ultima riga è tutta la correzione:
+
+ È così che si comporta PowerShell, non qualcosa di questo strumento. cmd,
+ bash e zsh non richiedono nulla di più.
+
+
+
+
+
Più job
+
Condividere le fixture tra i job
+
+ Di solito non serve caricarle. Poiché la stessa ricetta scrive gli stessi byte, ogni job può
+ eseguire il proprio tfg generate, che è più rapido di un upload e di un download.
+ Quando un job deve ricevere file da un altro, esegui tfg verify sul manifest dopo
+ il trasferimento, e ti dice se ciò che è arrivato è ciò che è stato scritto.
+
26 formati di file, ognuno generato a una dimensione esatta
+
+ Ognuno è un file reale di quel formato. Si apre nel programma che gli appartiene ed
+ è esattamente il numero di byte che hai chiesto. Nessuno è riempimento di zeri con un'estensione
+ appiccicata.
+
+
+
+
+
+
+
Formato
+
Nome
+
Estensione
+
File più piccolo
+
Fedeltà
+
Verificato con
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
non applicabile
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
non applicabile
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
non applicabile
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
Cosa significano le colonne
+
+
+
File più piccolo
+
+ Il minimo di byte che questo strumento accetta per quel formato, compresa l'etichetta che scrive
+ dentro il file. Chiedi meno e ottieni un errore che nomina il minimo e il suo motivo, mai un
+ file della dimensione sbagliata.
+
+
+
+
Fedeltà
+
+ Quanto è completo il file. full significa che un lettore che analizza davvero il
+ formato lo accetta, non solo che l'estensione corrisponde.
+
+
+
+
Verificato con
+
+ Il lettore indipendente che apre ogni file generato prima che il formato venga rilasciato -
+ un'implementazione separata, non il nostro codice che corregge i propri compiti.
+
+
+
+
+ Ogni formato si ripete anche al byte: la stessa ricetta e lo stesso seed producono file identici su
+ qualsiasi macchina, ed è ciò che rende sicuro committare una ricetta al posto delle fixture
+ stesse.
+
+
+
+
+
Impostazioni che ogni formato accetta
+
+ La maggior parte dei formati ha impostazioni proprie - dimensioni dell'immagine, qualità JPEG,
+ numero di pagine PDF, righe e colonne di un foglio di calcolo, quante voci vanno dentro un
+ archivio. Impostale con --set key=value dalla riga di comando, o sotto
+ properties: in una ricetta.
+
una data come 2024-02-29 o 2024-02-29T13:45:00+02:00, oppure none
+
+
+
+
modified
+
una data come 2024-02-29 o 2024-02-29T13:45:00+02:00, oppure none
+
+
+
png
+
width
+
1 - 20000 pixel
+
+
+
+
height
+
1 - 20000 pixel
+
+
+
pptx
+
slides
+
1 - 500 diapositive
+
+
+
svg
+
width
+
1 - 20000 pixel
+
+
+
+
height
+
1 - 20000 pixel
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
l'id di un formato, come lo elenca tfg formats
+
+
+
+
entry_size
+
una dimensione come 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
vero o falso
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 pixel
+
+
+
+
height
+
1 - 20000 pixel
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
vero o falso
+
+
+
wav
+
sample_rate
+
8000 - 192000 hertz
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 pixel
+
+
+
+
height
+
1 - 16383 pixel
+
+
+
xlsx
+
rows
+
1 - 200000 righe
+
+
+
+
columns
+
1 - 32768 colonne
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
vero o falso
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
l'id di un formato, come lo elenca tfg formats
+
+
+
+
entry_size
+
una dimensione come 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
vero o falso
+
+
+
+
password
+
la password, in chiaro
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ Un valore fuori da ciò che un'impostazione accetta viene rifiutato con un messaggio che nomina
+ l'impostazione, l'intervallo consentito e cosa usare al suo posto. Anche un'impostazione
+ sconosciuta è un errore, mai un valore predefinito silenzioso - un refuso accettato in silenzio
+ dà un file con le impostazioni sbagliate e un'ora a chiedersi perché il test passa quando non
+ dovrebbe.
+
+
+ Esegui tfg formats <id> per vedere esattamente cosa accetta un formato nella
+ build che hai.
+
+
+
+
+
Gli archivi contengono file reali
+
+ targz e zip
+ possono essere riempiti di voci invece di restare un guscio vuoto. Un archivio generato contiene
+ davvero i documenti che dichiara di contenere, quindi qualsiasi cosa lo decomprima durante un
+ test trova file reali al suo interno.
+
+ PDF, PNG, DOCX, ZIP - 26 formati in tutto, e ognuno è un file
+ reale che si apre nel programma che gli appartiene, di esattamente la dimensione che hai
+ chiesto. Ogni esecuzione annota anche cosa la tua applicazione deve fare con ogni file.
+ Riga di comando e finestra desktop, gratuito e open source, interamente sulla tua macchina.
+
Gratuito e open source, GPL-3.0. Nessuna registrazione. I download per Windows e macOS sono firmati e si avviano senza avvisi.
+
+
+
+
+ La finestra desktop, pronta a scrivere un lotto di file. Lo stesso motore gira dietro la riga di comando.
+
+
+
+
+
+ 26
+
formati reali, ognuno si apre nel programma che gli appartiene
+
+
+ 1 byte
+
la precisione di ogni dimensione che chiedi, mai arrotondata in silenzio
+
+
+ 0
+
connessioni verso chiunque - nessun account, nessuna telemetria, nessun controllo degli aggiornamenti
+
+
+
+
+
Il problema
+
Fare un file di test è facile. Fare i mille giusti è la parte noiosa
+
Stai testando software che accetta file dalle persone. Prima o poi ti servono:
+
+
un PDF di esattamente 10 MB, per scoprire se il limite di upload è reale
+
i tre file ai due lati di quel limite, per scovare errori di uno in più o in meno
+
10.000 file di log, per vedere cosa fa il job notturno quando la cartella è grande
+
uno ZIP che contiene davvero 200 documenti, non un guscio vuoto con l'estensione giusta
+
un file da 4 GB, senza tenere un file da 4 GB nel tuo repository
+
le stesse fixture sul tuo portatile e sul server di build, byte per byte
+
+
+ È ciò che questo sostituisce. È pensato per ingegneri QA, automazione dei test e chiunque abbia
+ dietro al proprio codice un modulo di upload, una routine di importazione, un parser o una quota
+ di storage.
+
+
+
+
+
Cosa lo rende diverso
+
Gli altri generatori si fermano ai byte. Questo risponde a ciò che il tuo test chiede davvero
+
+ Una cartella di file ti lascia ancora a decidere cosa dovrebbe dimostrare ciascuno. Ogni esecuzione
+ qui scrive un manifest.json accanto ai file - un semplice elenco di tutto ciò che è
+ stato prodotto e, per ogni voce, un'aspettativa dichiarata.
+
+
Poniamo che il tuo endpoint di upload permetta 1 MB. Chiedi i tre file che stanno su quella linea:
Dove la risposta dipende dalla tua politica, il manifest lo dice
+
+ Registra unspecified invece di inventare un'aspettativa. Un generatore che tira a
+ indovinare produce falsi fallimenti, e una suite che grida al lupo finisce spenta.
+
+
+
+
+
+
Preset
+
Scegli la domanda, ottieni l'intero set
+
+ Un preset è un set di file di test progettato attorno a una domanda di test, così non devi capire tu
+ quali file dimostrano cosa. Ognuno ha una pagina che dice cosa trova di solito, cosa c'è nel set
+ e ogni impostazione che accetta.
+
+ Diecimila file di log, ciascuno tra uno e otto kilobyte, con le dimensioni estratte dal seed così
+ domani dà lo stesso set. Dai a ogni esecuzione la sua directory - il
+ manifest è l'unica traccia di ciò che un'esecuzione ha scritto, quindi lo strumento si
+ rifiuta di scriverne un secondo sopra:
+
+ Le dimensioni si contano a 1024, come fa il tuo file manager, quindi 2mb significa
+ 2097152 byte. Funziona anche un semplice numero di byte. La
+ documentazione copre le ricette, il manifest e i codici di
+ uscita.
+
+
+
+
+
Cosa ottieni
+
Costruito per una suite che gira senza supervisione
+
+
+
Dimensione esatta, al byte
+
Chiedi 10485761 byte e ottieni esattamente quelli. Una dimensione che un formato non può raggiungere è un errore con un motivo, mai un file della dimensione sbagliata.
+
+
+
26 formati reali
+
Non zeri di riempimento con un'estensione. Un PNG generato si apre in un visualizzatore di immagini, un DOCX si apre in Word, uno ZIP si estrae. Ognuno è verificato con lettori indipendenti prima del rilascio.
+
+
+
Un manifest che è un oracolo di test
+
Percorso, dimensione, SHA-256, formato, seed, versione dello strumento - e cosa il tuo sistema deve fare con il file.
+
+
+
Riproducibile
+
Stessa ricetta e stesso seed, stessi byte, su qualsiasi macchina. Committa una piccola ricetta YAML invece di grandi fixture binarie.
+
+
+
Due interfacce, un solo motore
+
Una riga di comando pensata per la CI e una finestra desktop per il test esplorativo. Nessuna è una versione ridotta dell'altra, e un test le confronta capacità per capacità.
+
+
+
Completamente offline
+
Nessun account, nessun cloud, nessuna telemetria, nessun controllo degli aggiornamenti. Il binario della riga di comando non ha alcuno stack di rete compilato al suo interno.
+
+
+
+
+
+
Download
+
Scegli la build per il tuo sistema
+
+ Decomprimi l'archivio ed eseguilo. tfg è la riga di comando e tfg-gui è la
+ finestra desktop. Non c'è un installer e nulla da aggiungere alla tua macchina.
+
+
+
+
+
+
Sistema
+
Riga di comando
+
Finestra desktop
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
Cosa è firmato e cosa no
+
+ I download per Windows e macOS sono firmati, quindi si avviano senza l'avviso di sviluppatore
+ sconosciuto. Quelli per Linux no, perché Linux desktop non ha un equivalente con cui firmarli.
+ Ogni archivio è elencato in verify-SHA256SUMS.txt nella pagina delle release,
+ così puoi controllare cosa hai scaricato.
+
Un file valido e piccolo quanto il formato consente passa?
+
+ Il preset empty-and-minimal costruisce con un solo comando un intero set di file di test reali
+ per questa domanda, e un manifest.json accanto che dice come il tuo sistema deve
+ reagire a ogni file. Tutto ciò che segue è letto dal programma, ai valori predefiniti di questa
+ versione.
+
+
+
+
+
Cosa trova di solito?
+
+
un file valido respinto perché troppo piccolo, quando il controllo conta i byte invece di leggerli
+
un file vuoto che manda in crash il lettore invece di essere segnalato
+
un'immagine larga un pixel che divide per zero lungo la strada verso la miniatura
+
uno storage che legge zero byte come un upload fallito e continua a riprovare
+
+
+
+
+
+
Cosa c'è nel set?
+
Ai valori predefiniti, come lo riporta tfg preset show empty-and-minimal:
Il mio sistema salverà, mostrerà e restituirà un nome di file che non si aspettava?
+
+ Il preset filename-handling costruisce con un solo comando un intero set di file di test reali
+ per questa domanda, e un manifest.json accanto che dice come il tuo sistema deve
+ reagire a ogni file. Tutto ciò che segue è letto dal programma, ai valori predefiniti di questa
+ versione.
+
+
+
+
+
Cosa trova di solito?
+
+
un nome che sembra un altro sullo schermo, in un log o in un elenco
+
un nome tagliato, accorciato o riscritto tra l'upload e il salvataggio
+
un limite di lunghezza contato in caratteri dove lo storage conta byte
+
+
+
+
+
+
Cosa c'è nel set?
+
Ai valori predefiniti, come lo riporta tfg preset show filename-handling:
+
+
+
+
File
50
+
Target nella sua ricetta
50
+
Dimensione totale
51 200 B
+
Formati
txt
+
+
+
+
E ciò che il manifest di quel set si aspetta dal tuo sistema:
+
+
+
+
Atteso
Significato
File
+
+
+
accept
Il tuo sistema deve accettare il file.
4
+
unspecified
Dipende dalle regole del tuo sistema. Decidi tu, poi controlli che ciò che accade sia ciò che intendevi.
46
+
+
+
+
+
+
+
Cosa puoi cambiare?
+
+
+
+
Impostazione
Accetta
Predefinito
Cosa fa
+
+
+
+
--format
+
un id di formato dalla pagina dei formati
+
txt
+
Il formato di ogni file del set. È un'opzione dello strumento stesso, e il preset le dà solo un valore predefinito.
+
+
+
+
+
+
+
+
Come si esegue?
+
Guarda quanto costerebbe il set, costruiscilo o prendi la sua ricetta da modificare:
Preset di file di test, un set per ogni domanda di test
+
+ Un preset è un intero set di file di test progettato attorno a una domanda, con un manifest che dice
+ come il tuo sistema deve reagire a ogni file. Scegli la domanda, lo strumento costruisce il set.
+ Ogni preset ha una pagina tutta sua con cosa trova di solito, cosa c'è nel set e ogni impostazione
+ che accetta.
+
Il mio modulo di upload accetta ciò che deve e respinge il resto?
+
upload-validation
+
+
+
+
+
In cosa un preset è diverso da una ricetta?
+
+ Sotto il cofano, in niente. Un preset è una ricetta che lo strumento scrive per te a partire da
+ poche impostazioni. tfg preset eject stampa quella ricetta così puoi tenerla
+ accanto ai tuoi test e modificarla, e una ricetta tua può basarsi su un preset con una riga,
+ extends: preset: seguito dal suo id.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Posso fidarmi dei valori predefiniti?
+
+ Per i file, sì. Per un numero che solo il tuo sistema conosce, come il limite di un modulo di
+ upload, un valore predefinito è un nostro segnaposto, e lo strumento lo dice ogni volta che ne
+ usa uno. La pagina di ogni preset marca queste impostazioni, e tfg preset show lo
+ dice prima che venga scritto qualsiasi cosa.
+
Un limite di dimensione viene applicato esattamente dove è dichiarato?
+
+ Il preset size-boundaries costruisce con un solo comando un intero set di file di test reali
+ per questa domanda, e un manifest.json accanto che dice come il tuo sistema deve
+ reagire a ogni file. Tutto ciò che segue è letto dal programma, ai valori predefiniti di questa
+ versione.
+
+
+
+
+
Cosa trova di solito?
+
+
errori di uno in più o in meno al limite
+
MB confuso con MiB, che fa il 4,8 per cento e basta a far passare un file che non dovrebbe passare
+
un limite applicato nel browser e non sul server
+
+
+
+
+
+
Cosa c'è nel set?
+
Ai valori predefiniti, come lo riporta tfg preset show size-boundaries:
+
+
+
+
File
7
+
Target nella sua ricetta
7
+
Dimensione totale
73 400 320 B
+
Formati
pdf
+
+
+
+
E ciò che il manifest di quel set si aspetta dal tuo sistema:
+
+
+
+
Atteso
Significato
File
+
+
+
accept
Il tuo sistema deve accettare il file.
4
+
reject
Il tuo sistema deve rifiutare il file.
3
+
+
+
+
+
+
+
Cosa puoi cambiare?
+
+
+
+
Impostazione
Accetta
Predefinito
Cosa fa
+
+
+
+
--limit
+
una dimensione come 2mb
+
10mb
+
Il limite di dimensione dichiarato dal tuo sistema. Tutto il resto si misura a partire da esso. Questo valore predefinito è un nostro segnaposto, non il valore del tuo sistema. Passa il tuo.
+
+
+
--spread
+
dimensioni separate da virgole
+
1B,1kb,1mb
+
Fin dove spingersi ai due lati del limite, come elenco di dimensioni.
+
+
+
--format
+
un id di formato dalla pagina dei formati
+
pdf
+
Il formato di ogni file del set. È un'opzione dello strumento stesso, e il preset le dà solo un valore predefinito.
+
+
+
+
+
+
+
+
Come si esegue?
+
Guarda quanto costerebbe il set, costruiscilo o prendi la sua ricetta da modificare:
La mia importazione di tabelle regge a ciò che esportano gli strumenti reali?
+
+ Il preset tabular-import costruisce con un solo comando un intero set di file di test reali
+ per questa domanda, e un manifest.json accanto che dice come il tuo sistema deve
+ reagire a ogni file. Tutto ciò che segue è letto dal programma, ai valori predefiniti di questa
+ versione.
+
+
+
+
+
Cosa trova di solito?
+
+
un file con punto e virgola letto come una sola colonna, perché il delimitatore è stato dato per scontato invece di cercarlo
+
un file CRLF diviso in righe con una riga vuota dopo ciascuna
+
una tabella senza intestazione la cui prima riga di dati viene mangiata come nomi di colonna
+
un'importazione che tiene le colonne che sa mostrare e scarta il resto senza dire nulla
+
un lettore che prende i record JSON una riga alla volta e si ferma al primo documento indentato
+
+
+
+
+
+
Cosa c'è nel set?
+
Ai valori predefiniti, come lo riporta tfg preset show tabular-import:
+
+
+
+
File
13
+
Target nella sua ricetta
13
+
Dimensione totale
3 080 060 B
+
Formati
csv, json, xlsx
+
+
+
+
E ciò che il manifest di quel set si aspetta dal tuo sistema:
+
+
+
+
Atteso
Significato
File
+
+
+
accept
Il tuo sistema deve accettare il file.
8
+
unspecified
Dipende dalle regole del tuo sistema. Decidi tu, poi controlli che ciò che accade sia ciò che intendevi.
5
+
+
+
+
+
+
+
Cosa puoi cambiare?
+
+
+
+
Impostazione
Accetta
Predefinito
Cosa fa
+
+
+
+
--rows
+
1 - 200000 righe
+
1000
+
Quante righe contiene il foglio di calcolo. Viene scritto esattamente alla dimensione che occupano tante righe, quindi il budget qui sopra si sposta con questo valore.
+
+
+
--columns
+
1 - 32768 colonne
+
10
+
Quante colonne ha ogni riga del foglio di calcolo. Righe per colonne ha un tetto, e chiedere oltre viene rifiutato prima di scrivere qualsiasi cosa.
+
+
+
+
+
+
+
+
Come si esegue?
+
Guarda quanto costerebbe il set, costruiscilo o prendi la sua ricetta da modificare:
Il mio lettore sa in quale codifica è un file, o tira a indovinare?
+
+ Il preset text-encoding costruisce con un solo comando un intero set di file di test reali
+ per questa domanda, e un manifest.json accanto che dice come il tuo sistema deve
+ reagire a ogni file. Tutto ciò che segue è letto dal programma, ai valori predefiniti di questa
+ versione.
+
+
+
+
+
Cosa trova di solito?
+
+
un lettore che presume UTF-8 e mostra un file UTF-16 con un carattere ogni tre, o come file di quadratini
+
un byte order mark letto come contenuto, così il primo campo di un'importazione inizia con tre caratteri estranei
+
un importatore che indovina la codifica dai primi byte e indovina in modo diverso con un file più lungo
+
un file CRLF diviso in righe con una riga vuota dopo ciascuna, o un ritorno a capo rimasto nell'ultimo campo
+
+
+
+
+
+
Cosa c'è nel set?
+
Ai valori predefiniti, come lo riporta tfg preset show text-encoding:
+
+
+
+
File
20
+
Target nella sua ricetta
20
+
Dimensione totale
81 920 B
+
Formati
csv, log, md, txt, xml
+
+
+
+
E ciò che il manifest di quel set si aspetta dal tuo sistema:
+
+
+
+
Atteso
Significato
File
+
+
+
accept
Il tuo sistema deve accettare il file.
10
+
unspecified
Dipende dalle regole del tuo sistema. Decidi tu, poi controlli che ciò che accade sia ciò che intendevi.
10
+
+
+
+
+
+
+
Cosa puoi cambiare?
+
+
+
+
Impostazione
Accetta
Predefinito
Cosa fa
+
+
+
+
--sample
+
una dimensione come 2mb
+
4kb
+
Quanto è grande ogni file del set. UTF-16 memorizza due byte per carattere, quindi un numero dispari viene rifiutato.
+
+
+
+
+
+
+
+
Come si esegue?
+
Guarda quanto costerebbe il set, costruiscilo o prendi la sua ricetta da modificare:
Il mio modulo di upload accetta ciò che deve e respinge il resto?
+
+ Il preset upload-validation costruisce con un solo comando un intero set di file di test reali
+ per questa domanda, e un manifest.json accanto che dice come il tuo sistema deve
+ reagire a ogni file. Tutto ciò che segue è letto dal programma, ai valori predefiniti di questa
+ versione.
+
+
+
+
+
Cosa trova di solito?
+
+
un limite applicato nel browser e non sul server
+
un SVG o un HTML scambiato per un'immagine o per testo semplice, che è un modo per far passare uno script attraverso un modulo
+
un file controllato dall'estensione e mai aperto, così un PDF chiamato .jpg passa
+
un modulo che legge l'intero corpo in memoria prima di guardare quanto è grande
+
un upload chiamato PHOTO.JPG respinto dove photo.jpg viene accettato, o il contrario
+
un nome con spazi, parentesi o caratteri fuori dall'ASCII scritto su disco senza modifiche
+
+
+
+
+
+
Cosa c'è nel set?
+
Ai valori predefiniti, come lo riporta tfg preset show upload-validation:
+
+
+
+
File
71
+
Target nella sua ricetta
22
+
Dimensione totale
120 639 488 B
+
Formati
html, jpg, pdf, png, svg, txt
+
+
+
+
E ciò che il manifest di quel set si aspetta dal tuo sistema:
+
+
+
+
Atteso
Significato
File
+
+
+
accept
Il tuo sistema deve accettare il file.
56
+
reject
Il tuo sistema deve rifiutare il file.
10
+
unspecified
Dipende dalle regole del tuo sistema. Decidi tu, poi controlli che ciò che accade sia ciò che intendevi.
5
+
+
+
+
+
+
+
Cosa puoi cambiare?
+
+
+
+
Impostazione
Accetta
Predefinito
Cosa fa
+
+
+
+
--limit
+
una dimensione come 2mb
+
10mb
+
Il limite di dimensione dichiarato dal tuo modulo di upload. Questo set fa un passo per lato - per un file a ogni distanza, esegui il preset size-boundaries. Questo valore predefinito è un nostro segnaposto, non il valore del tuo sistema. Passa il tuo.
+
+
+
--allow
+
id di formato separati da virgole
+
jpg,png,pdf
+
Quali tipi il tuo modulo deve accettare. Ognuno diventa un file reale di quel tipo, e sono il controllo positivo dell'intero set.
+
+
+
--deny
+
estensioni separate da virgole
+
svg,html,exe,sh
+
Quali estensioni il tuo modulo deve respingere. Un'estensione per cui questa versione non ha un formato riceve comunque un file con quel nome, contenente testo semplice.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
Quanto oltre il limite arriva l'unico file grande. Disattivalo dove scrivere diverse volte il limite non vale il disco.
+
+
+
--bulk
+
0 - 10000 file
+
50
+
Quanti file contiene l'upload di massa. Zero lascia del tutto fuori dal set quel gruppo.
+
+
+
+
+
+
+
+
Come si esegue?
+
Guarda quanto costerebbe il set, costruiscilo o prendi la sua ricetta da modificare:
+ 설정은 콜론 뒤에 씁니다. 옵션은 반복할 수 있고, 손상은 쓴 순서대로 적용됩니다. 26개 형식 모두에서 동작합니다.
+
+
+
+
+
할 수 있는 것
+
어떤 손상이 있나요?
+
+ 이것은 프로그램이 출력하는 목록이며, 이 페이지를 빌드할 때 프로그램에서 읽어 옵니다. tfg damage는 같은 목록을 출력하고, tfg
+ damage <id>는 그중 하나가 받는 설정을 알려 줍니다.
+
+
+
+
+
+
손상
+
바이트에 하는 일
+
가장 작은 파일
+
설정
+
+
+
+
+
zero-head
+
파일의 첫 바이트들을 길이는 그대로 둔 채 0으로 덮어씁니다. 대부분의 리더가 가장 먼저 그곳을 보므로 거의 모든 것이 이 손상을 알아챕니다.
+
8
+
bytes
+
+
+
+
+
+ zero-head는 파일의 시작 부분을 0으로 덮어씁니다. 대부분의 리더는 파일이 무엇인지 알려 주는 시그니처와 헤더가 있는 그곳을 가장 먼저 봅니다.
+ 그래서 거의 모든 리더가 알아챕니다. 일반 텍스트와 로그에는 시그니처가 없지만 역시 거부됩니다. 0 바이트의 연속은 텍스트가 아니기 때문입니다. 4바이트 미만에서는 어떤
+ 리더도 불평하지 않는 손상이 나오는 형식이 있으며, 설정이 4부터 시작하는 이유가 그것입니다.
+
+
+
+
+
매니페스트가 말하는 것
+
무엇이 일어나야 하는지 말해 주는 매니페스트
+
+ 손상된 파일마다 시스템이 그것을 거부해야 한다는 항목이 붙고, 손상 내용이 그 옆에 기록됩니다.
+
+ PowerShell의 10MB는 탐색기가 쓰는 것과 같은 1024 기준 계산으로 10485760바이트를 뜻하므로, 위의 두 명령은 같은 크기를 만듭니다.
+
+
+
+
+
Linux
+
dd, truncate, fallocate, 그리고 사람들이 걸려 넘어지는 차이
+
dd는 누구나 아는 명령입니다. 바이트를 실제로 씁니다.
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate는 즉시 끝나는데, 그것이 함정입니다. Alpine Linux에서 측정해 보면 파일은 10485760바이트로 보고되지만 차지하는 블록은
+ 0개로, 희소 파일입니다. 읽는 쪽은 0으로 채워진 10메가바이트를 받지만, 디스크는 공간을 내준 적이
+ 없습니다.
+
+
truncate -s 10M test10mb.bin
+
+ 업로드 한도를 테스트하기에는 괜찮지만 디스크 할당량을 테스트할 때는 오해를 부릅니다. 공간이 실제여야 할 때는 fallocate를 쓰세요.
+
+
fallocate -l 10M test10mb.bin
+
그리고 압축 프로그램이 다시 줄일 수 없도록 내용이 압축 불가능해야 할 때는:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
희소 파일이 아닌 mkfile, 그리고 이미 아시는 두 가지
+
+ macOS에는 mkfile이 포함되어 있습니다. macOS 26.6.2에서 측정하니 10485760바이트에 20480블록이었으므로, 공간은 약속이 아니라
+ 실제로 할당됩니다.
+
+ 위의 방법은 모두 0으로 된 덩어리를 줍니다. 테스트 대상이 크기만 본다면, 예를 들어 업로드 한도, 할당량, 전송이라면 충분합니다. 하지만 무엇이든 그 파일을
+ 여는 순간 충분하지 않게 됩니다.
+
+
+ 직접 측정했으며, 여러분도 해 볼 만합니다. fsutil로 2MB 파일을 만들고 photo.png라고 이름 붙인 다음 이미지
+ 라이브러리에 넘겨 보세요. Pillow는 cannot identify image file이라고 답합니다. 그것은 PNG가 아닙니다. 처음부터
+ 아니었고, 이름만 그렇게 말했을 뿐입니다.
+
+
+ 이는 들리는 것보다 중요합니다. 테스트가 그다음에 어느 쪽으로 실패하는지가 걸려 있기 때문입니다. 업로드 엔드포인트가 파일을 거부하고, 테스트가
+ 초록색이 되며, 크기 한도가 동작한다고 결론짓게 됩니다. 하지만 크기 때문에 거부한 것이 아닙니다. 바이트가 이미지가 아니어서 거부한 것이며, 테스트하려던 규칙에는 닿지도
+ 않았습니다.
+
+
+
파서가 크기 규칙을 살펴보기도 전에 거부한다
+
썸네일 단계가 실패하고 읽게 되는 오류가 썸네일에 관한 것이다
+
백신이나 콘텐츠 검사가 세 번째 이유로 거부한다
+
뷰어가 아무것도 보여 주지 않고, 그것이 버그인지 아무도 알 수 없다
+
+
+
+
+
다른 방법
+
그 형식의 실제 파일, 요청한 크기 그대로
+
+ 이것이 Testing Files Generator가 하는 일입니다. 파일은 해당 형식의 진짜 파일로, 해당 소프트웨어에서 열리며, 요청한 바이트 수와 정확히 같습니다.
+
+ 도구가 하는 모든 일을 사람들이 실제로 가져오는 질문 형태로 정리했습니다. 저장소의 README가 전체 레퍼런스이며,
+ 내려받은 빌드와 항상 일치합니다.
+
+
+
+
어떤 명령이 있나요?
+
각 명령은 한 가지 일만 합니다.
+
tfg generate 레시피나 플래그로 파일을 만든다
+tfg validate 레시피를 검사하고 아무것도 쓰지 않는다
+tfg verify 디렉터리를 매니페스트와 대조해 검사한다
+tfg cleanup 매니페스트에 나열된 파일을 삭제한다
+tfg recipe fmt 레시피를 정돈된 형태로 출력한다
+tfg preset 이름 붙은 테스트 질문으로 파일 세트를 만든다
+tfg formats 이 빌드가 지원하는 형식을 나열한다
+tfg damage 이 빌드가 파일을 일부러 망가뜨릴 수 있는 방법을 나열한다
+tfg tool 이미 가진 파일을 위한 작은 도구
+tfg version 도구 버전을 출력한다
+tfg license 라이선스와 생성된 파일에 대한 의미를 출력한다
+
+
+
+
정확한 크기의 파일 하나는 어떻게 만드나요?
+
+ 형식, 크기, 저장 위치를 지정합니다. 크기는 1024 단위로 세므로 2mb는 2097152바이트입니다. 바이트 수를 그대로 써도 되므로
+ --size 10485761은 정확히 그만큼을 요청합니다.
+
+
tfg generate --format png --size 2mb --out ./out
+
generate에서 유용한 플래그:
+
+
+
플래그
동작
+
+
--format <id>
파일의 형식. 예: txt
+
--size <size>
각 파일의 정확한 크기. 10mb와 같은 값 또는 바이트 수
+
--size-range <a-b>
범위에서 파일마다 뽑는 크기. 예: 1kb-8kb. 추첨은 시드에서 나옵니다
+
--boundary <size>
한도 주변의 파일 세 개: 1바이트 아래, 한도 값, 1바이트 위
+
--count <n>
만들 파일 수. 기본값은 1
+
--name <template>
이름 템플릿. 예: invoice_{index:04}.txt
+
--out <dir>
쓸 디렉터리
+
--seed <n>
실행의 시드. 같은 시드는 같은 바이트를 만듭니다
+
--set <k>=<v>
형식 설정, 여러 번 지정할 수 있음
+
--damage <name>
파일을 일부러 망가뜨립니다. 여러 번 지정할 수 있으며 순서대로 적용됩니다. 목록은 tfg damage로 봅니다
+
--expected <outcome>
accept, reject, sanitize, unspecified
+
--dry-run
세어서 보여 주기만 하고 아무것도 쓰지 않음
+
--json
매니페스트를 표준 출력에 씀
+
+
+
+
+
+
+
일부러 망가진 파일은 어떻게 만드나요?
+
+ 이 도구가 쓰는 다른 모든 파일은 구조상 올바르며, 이는 업로드 검증기가 던지는 세 가지 질문 중 두 가지에 답합니다. --damage는 세 번째, 곧
+ 파일이 아예 열리는지에 답합니다. 파일은 정상적으로 만들어진 뒤 망가지므로 요청한 크기는 그대로입니다.
+
+ 각 타깃에는 size, size-range, boundary, contains 중
+ 정확히 하나가 필요합니다. 둘은 오류이고 하나도 없는 것도 오류입니다. 올바르지 않은 레시피는 파일을 하나도 쓰지 않으며, 첫 번째 문제만이
+ 아니라 모든 문제를 한꺼번에 보고하고 각각 해당 설정의 이름을 알려 줍니다.
+
+
+
+
+
시스템이 파일을 어떻게 처리해야 하는지는 어떻게 선언하나요?
+
결과만 있으면 충분할 때는 짧은 형식을, 이유가 중요할 때는 긴 형식을 씁니다.
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ 결과는 accept, reject, sanitize, unspecified입니다.
+ 이유는 닫힌 목록이라 보고서가 이유별로 묶을 수 있습니다. content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit, size_zero.
+
+
+ 이유가 가리키는 것은 판정이 아니라 문제가 되는 규칙입니다. 그래서 같은 이유가 어느 결과 아래에도 올 수 있습니다. 한도보다 1바이트 작은 파일은
+ accept이지만, 관련된 규칙은 여전히 size_limit입니다.
+
+
+
+
+
매니페스트에는 무엇이 들어 있나요?
+
+ 중단된 실행을 포함해 모든 실행이 끝날 때 파일 옆에 쓰입니다. 파일마다 항목이 하나씩 있습니다.
+
+ 실행이 레시피에서 왔다면 recipe_hash가, 프리셋에서 왔다면 preset과 overrides가
+ 추가되므로, 매니페스트는 항상 그것을 만든 출처까지 추적할 수 있습니다.
+
+
+ 각 항목에는 파일을 만든 레시피 타깃의 id인 target_id도 들어 있고, summary.by_target은 각 타깃이 만든 파일
+ 수를 셉니다. 따라서 타깃이 여러 개인 레시피도 파일 이름을 읽지 않고 타깃별로 확인할 수 있습니다.
+
+
+
+
+
프리셋이란 무엇인가요?
+
+ 흔한 테스트 질문에 답하는 기성 파일 세트로, 세트를 직접 설계할 필요가 없습니다. 프리셋은 내부적으로 평범한 레시피이며, eject가 레시피를 출력하므로
+ 거기서부터 편집할 수 있습니다. 각 프리셋에는 보통 무엇을 찾아내는지, 세트에 무엇이 들어 있는지, 어떤 설정을 받는지 설명하는
+ 전용 페이지가 있습니다.
+
+ 네. 같은 엔진 위에 창을 얹은 것으로, 스크립트로 하지 않는 테스트를 위한 것입니다. 축소판이 아닙니다. 테스트가 두 인터페이스를 기능별로 비교하며, 한쪽만 할 수 있는 것은
+ 조용히 벌어지는 대신 선언하고 이유를 밝혀야 합니다.
+
+
+ 화면은 단일 배치, 프리셋, 여러 배치 동시 실행, 정보입니다. 무엇이든 쓰기 전에 실행 비용을 보여 주고, 실행 중에는 진행 상황을 알려 주며, 쓰다 만 파일을 남기지 않고
+ 도중에 취소할 수 있습니다. 아직 레시피 파일은 열지 못합니다. 지금은 레시피가 명령줄의 몫이고, 창은 양식에서 배치를 구성합니다.
+
+ 라이선스, 개인정보, 재현성, 그리고 사람들이 생성기를 빌드 파이프라인에 넣기 전에 확인하는 것들. 질문이 여기에 없다면 이슈
+ 트래커가 열려 있습니다.
+
+
+
+
+
dd, fsutil, truncate와는 무엇이 다른가요?
+
+
그 명령들은 크기만 맞고 내용이 텅 빈 파일을 줍니다. 그렇게 만든 2MB짜리 photo.png는 PNG가 아니므로, 실제로 파싱하는 것은 모두 엉뚱한 이유로 거부하고, 여러분의 테스트도 엉뚱한 이유로 통과합니다. 이 도구는 정확히 2MB인 실제 PNG를 만듭니다. 이미지 뷰어에서 열리며, 시스템이 이를 어떻게 다루어야 하는지에 대한 선언도 함께 제공됩니다.
둘 다 가능합니다. GPL-3.0으로 배포되며 비용이 들지 않습니다. 계정도, 라이선스 키도, 유료 요금제도 없습니다.
+
+
+
+
생성한 파일을 클로즈드 소스 제품에 써도 되나요?
+
+
네. 라이선스는 도구의 코드에 적용되며 도구가 만든 것에는 적용되지 않습니다. 생성된 파일, 레시피, 매니페스트는 파생 저작물이 아니라 출력물이므로, 어떤 의무도 없이 커밋하고 배포할 수 있습니다.
+
+
+
+
생성된 파일에 실제 개인 정보가 들어 있나요?
+
+
아니요. 내부의 모든 내용은 시드에서 합성됩니다. 어떤 데이터 세트도 읽지 않고, 어떤 서비스에도 접속하지 않으며, 제3자 콘텐츠도 포함하지 않습니다. 생성된 이메일 주소는 아직 쓰이지 않은 주소가 아니라 쓸 수 없는 주소로 여기세요. 임의의 문자열이 우연히 실제 주소와 같을 수 있기 때문입니다.
+
+
+
+
다른 컴퓨터에서도 완전히 같은 파일이 나오나요?
+
+
네. 같은 레시피와 같은 시드라면 바이트 단위로 같습니다. 프로젝트는 변경할 때마다 이를 테스트하며, 이를 깨려면 메이저 버전을 올려야 합니다. 그래서 큰 바이너리 픽스처 대신 작은 레시피를 커밋할 수 있습니다.
+
+
+
+
인터넷 연결이 필요한가요?
+
+
전혀 필요 없습니다. 텔레메트리도, 업데이트 확인도, 클라우드 클라이언트도 없으며, 명령줄 바이너리에는 네트워크 스택이 아예 컴파일되어 있지 않습니다. 네트워크가 없는 컴퓨터와 폐쇄된 기업 환경에서도 동작합니다.
+
+
+
+
형식이 도달할 수 없는 크기를 요청하면 어떻게 되나요?
+
+
형식, 가능한 가장 작은 크기, 그 하한의 이유, 대신 해야 할 일을 알려 주는 오류가 나오고 파일은 쓰이지 않습니다. 도구는 크기를 조용히 반올림하지 않습니다. 모든 하한은 형식 페이지에 나와 있습니다.
+
tfg formats png
+
+
+
+
일부러 망가진 파일도 만들 수 있나요?
+
+
네. --damage zero-head를 추가하면 파일은 요청한 크기 그대로, 첫 바이트가 0으로 덮어쓰인 채 나오므로 리더가 그것을 거부하고, 매니페스트에는 시스템이 그것을 거부해야 한다고 적힙니다. 자세한 내용은 손상된 테스트 파일 페이지에 있습니다.
명령줄은 Windows와 Linux의 Intel과 ARM, 그리고 Apple Silicon Mac에서 실행됩니다. 데스크톱 창은 Intel의 Windows, Intel의 Linux, Apple Silicon Mac용으로 제공됩니다. Intel Mac은 지원하지 않으며 빌드도 하지 않습니다.
+
+
+
+
설치해야 하는 것이 있나요?
+
+
없습니다. 시스템에 맞는 압축 파일을 내려받아 풀고 바이너리를 실행하면 됩니다. 설치 프로그램도, 추가할 런타임도, 해결할 의존성도 없습니다. Go가 있다면 go install 명령 하나로도 됩니다.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
수천 개의 파일을 처리하는 실행이 Windows에서 더 느린 이유는 무엇인가요?
+
+
Windows는 살펴보는 경로 하나하나에 더 많은 비용을 치르게 하고, 수천 개의 파일을 훑는 명령은 수천 개의 경로를 살펴보기 때문입니다. 1kB 파일 3000개가 있는 한 컴퓨터에서 측정하니 verify는 Windows에서 약 0.9초, 컨테이너 안의 Linux에서 약 0.2초가 걸렸습니다. 출력 경로를 짧게 하면 Windows 수치가 줄어듭니다. 파일 위의 모든 폴더도 살펴보는 대상에 포함되기 때문입니다.
2024-02-29 또는 2024-02-29T13:45:00+02:00 같은 날짜, 또는 none
+
+
+
+
modified
+
2024-02-29 또는 2024-02-29T13:45:00+02:00 같은 날짜, 또는 none
+
+
+
png
+
width
+
1 - 20000 픽셀
+
+
+
+
height
+
1 - 20000 픽셀
+
+
+
pptx
+
slides
+
1 - 500 슬라이드
+
+
+
svg
+
width
+
1 - 20000 픽셀
+
+
+
+
height
+
1 - 20000 픽셀
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
tfg formats가 나열하는 형식의 id
+
+
+
+
entry_size
+
2mb와 같은 크기
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
참 또는 거짓
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 픽셀
+
+
+
+
height
+
1 - 20000 픽셀
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
참 또는 거짓
+
+
+
wav
+
sample_rate
+
8000 - 192000 헤르츠
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 픽셀
+
+
+
+
height
+
1 - 16383 픽셀
+
+
+
xlsx
+
rows
+
1 - 200000 행
+
+
+
+
columns
+
1 - 32768 열
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
참 또는 거짓
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
tfg formats가 나열하는 형식의 id
+
+
+
+
entry_size
+
2mb와 같은 크기
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
참 또는 거짓
+
+
+
+
password
+
암호(평문)
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ 설정이 받는 범위를 벗어난 값은 설정, 허용 범위, 대신 쓸 값을 알려 주는 메시지와 함께 거부됩니다. 알 수 없는 설정도 오류이며 조용히 기본값이 되는 일은 없습니다. 조용히
+ 받아들여진 오타는 잘못된 설정의 파일과, 통과하면 안 되는 테스트가 왜 통과하는지 고민하는 한 시간을 낳습니다.
+
+
+ 가지고 있는 빌드에서 한 형식이 정확히 무엇을 받는지 보려면 tfg formats <id>를 실행하세요.
+
+
+
+
+
아카이브에는 실제 파일이 들어 있습니다
+
+ targz와 zip는 빈
+ 껍데기로 두지 않고 항목으로 채울 수 있습니다. 생성된 아카이브는 담았다고 하는 문서를 실제로 담고 있으므로, 테스트 중에 이를 푸는 것은 무엇이든 안에서 실제 파일을
+ 찾습니다.
+
+ PDF, PNG, DOCX, ZIP 등 모두 26가지 형식이며, 모두 해당 소프트웨어에서 열리는 실제 파일로
+ 요청한 크기와 정확히 같습니다. 매 실행마다 애플리케이션이 각 파일을 어떻게 처리해야 하는지도 함께 기록합니다. 명령줄과 데스크톱 창, 무료
+ 오픈 소스이며, 모두 여러분의 컴퓨터에서 동작합니다.
+
+ 크기는 파일 관리자처럼 1024 단위로 세므로 2mb는 2097152바이트입니다. 바이트 수를 그대로 써도 됩니다.
+ 문서에서 레시피, 매니페스트, 종료 코드를 다룹니다.
+
+
+
+
+
얻는 것
+
무인으로 실행되는 테스트 묶음을 위해 만들었습니다
+
+
+
정확한 크기, 바이트 단위까지
+
10485761바이트를 요청하면 정확히 그 크기가 나옵니다. 형식이 도달할 수 없는 크기는 이유가 붙은 오류가 되며, 크기가 틀린 파일이 되는 일은 없습니다.
+
+
+
실제 형식 26가지
+
확장자만 붙인 채운 0이 아닙니다. 생성된 PNG는 이미지 뷰어에서 열리고, DOCX는 Word에서 열리며, ZIP은 풀립니다. 모든 형식은 출시 전에 독립적인 리더로 검증됩니다.
+
+
+
테스트 오라클이 되는 매니페스트
+
경로, 크기, SHA-256, 형식, 시드, 도구 버전, 그리고 시스템이 그 파일을 어떻게 처리해야 하는지.
+
+
+
재현 가능
+
같은 레시피와 같은 시드라면 어느 컴퓨터에서나 바이트까지 같습니다. 큰 바이너리 픽스처 대신 작은 YAML 레시피를 커밋하세요.
+
+
+
두 가지 인터페이스, 하나의 엔진
+
CI를 위해 만든 명령줄과 탐색적 테스트를 위한 데스크톱 창. 어느 쪽도 다른 쪽의 축소판이 아니며, 테스트가 두 인터페이스를 기능별로 비교합니다.
+
+
+
완전한 오프라인
+
계정도, 클라우드도, 텔레메트리도, 업데이트 확인도 없습니다. 명령줄 바이너리에는 네트워크 스택이 아예 컴파일되어 있지 않습니다.
+
+
+
+
+
+
다운로드
+
시스템에 맞는 빌드를 고르세요
+
+ 압축 파일을 풀고 실행하세요. tfg는 명령줄이고 tfg-gui는 데스크톱 창입니다. 설치 프로그램은 없으며 컴퓨터에 추가할 것도
+ 없습니다.
+
+
+
+
+
+
시스템
+
명령줄
+
데스크톱 창
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
서명된 것과 그렇지 않은 것
+
+ Windows와 macOS 다운로드는 서명되어 있어 확인되지 않은 개발자 경고 없이 실행됩니다. Linux용은 데스크톱 Linux에 서명할 수 있는 대응 수단이 없어 서명되어 있지
+ 않습니다. 모든 압축 파일은 릴리스 페이지의 verify-SHA256SUMS.txt에 나열되어 있으므로 내려받은 것을 확인할 수 있습니다.
+
+ empty-and-minimal 프리셋은 이 질문에 대한 실제 테스트 파일 세트 전체를 명령 하나로 만들고, 그 옆에 시스템이 각 파일에 어떻게 반응해야 하는지 알려 주는
+ manifest.json을 둡니다. 아래의 모든 내용은 이 버전의 기본값으로 프로그램에서 읽어 온 것입니다.
+
+
+
+
+
보통 무엇을 찾아내나요?
+
+
검사가 바이트를 읽지 않고 개수만 세기 때문에 너무 작다며 거부되는 유효한 파일
+
보고되지 않고 읽는 쪽을 비정상 종료시키는 빈 파일
+
썸네일을 만드는 도중 0으로 나누기가 발생하는 너비 1픽셀의 이미지
+
0바이트를 업로드 실패로 보고 계속 재시도하는 스토리지
+
+
+
+
+
+
세트에는 무엇이 들어 있나요?
+
기본값에서 tfg preset show empty-and-minimal가 보고하는 대로입니다.
+ filename-handling 프리셋은 이 질문에 대한 실제 테스트 파일 세트 전체를 명령 하나로 만들고, 그 옆에 시스템이 각 파일에 어떻게 반응해야 하는지 알려 주는
+ manifest.json을 둡니다. 아래의 모든 내용은 이 버전의 기본값으로 프로그램에서 읽어 온 것입니다.
+
+
+
+
+
보통 무엇을 찾아내나요?
+
+
화면이나 로그, 목록에서 다른 이름처럼 보이는 이름
+
업로드와 저장 사이에 잘리거나 다듬어지거나 다시 쓰이는 이름
+
스토리지는 바이트로 세는데 문자로 세는 길이 제한
+
+
+
+
+
+
세트에는 무엇이 들어 있나요?
+
기본값에서 tfg preset show filename-handling가 보고하는 대로입니다.
+
+
+
+
파일 수
50
+
레시피의 타깃 수
50
+
총 크기
51 200 B
+
형식
txt
+
+
+
+
그리고 그 세트의 매니페스트가 시스템에 기대하는 것:
+
+
+
+
기대값
의미
파일 수
+
+
+
accept
시스템은 이 파일을 받아야 합니다.
4
+
unspecified
시스템의 규칙에 따라 다릅니다. 직접 결정한 뒤 실제 일어나는 일이 의도한 것인지 확인하세요.
46
+
+
+
+
+
+
+
무엇을 바꿀 수 있나요?
+
+
+
+
설정
값
기본값
동작
+
+
+
+
--format
+
형식 페이지의 형식 id
+
txt
+
세트에 포함된 모든 파일의 형식입니다. 도구 자체의 플래그이며, 프리셋은 기본값만 지정합니다.
+ 프리셋은 하나의 질문을 중심으로 설계한 테스트 파일 세트 전체이며, 시스템이 각 파일에 어떻게 반응해야 하는지 알려 주는 매니페스트가 함께 제공됩니다. 질문을 고르면 도구가 세트를
+ 만듭니다. 각 프리셋에는 보통 무엇을 찾아내는지, 세트에 무엇이 들어 있는지, 어떤 설정을 받는지 설명하는 고유한 페이지가 있습니다.
+
+ 내부적으로는 다르지 않습니다. 프리셋은 몇 가지 설정으로 도구가 대신 써 주는 레시피입니다. tfg preset eject가 그 레시피를 출력하므로 테스트
+ 옆에 두고 편집할 수 있으며, 직접 만든 레시피는 extends: preset: 뒤에 id를 붙인 한 줄로 프리셋을 바탕으로 할 수 있습니다.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
기본값을 믿어도 되나요?
+
+ 파일에 대해서는 그렇습니다. 업로드 양식의 한도처럼 여러분의 시스템만 아는 숫자라면 기본값은 우리 쪽의 임시값이며, 도구는 임시값을 쓸 때마다 그렇게 알려 줍니다. 각 프리셋의
+ 페이지는 그러한 설정을 표시하고, tfg preset show는 무엇이든 쓰기 전에 그 사실을 알려 줍니다.
+
+ size-boundaries 프리셋은 이 질문에 대한 실제 테스트 파일 세트 전체를 명령 하나로 만들고, 그 옆에 시스템이 각 파일에 어떻게 반응해야 하는지 알려 주는
+ manifest.json을 둡니다. 아래의 모든 내용은 이 버전의 기본값으로 프로그램에서 읽어 온 것입니다.
+
+
+
+
+
보통 무엇을 찾아내나요?
+
+
한도에서 발생하는 하나 차이 오류
+
MB와 MiB를 혼동하는 경우로, 4.8퍼센트 차이이며 통과하면 안 되는 파일을 통과시키기에 충분합니다
+
서버가 아니라 브라우저에서만 적용되는 한도
+
+
+
+
+
+
세트에는 무엇이 들어 있나요?
+
기본값에서 tfg preset show size-boundaries가 보고하는 대로입니다.
+
+
+
+
파일 수
7
+
레시피의 타깃 수
7
+
총 크기
73 400 320 B
+
형식
pdf
+
+
+
+
그리고 그 세트의 매니페스트가 시스템에 기대하는 것:
+
+
+
+
기대값
의미
파일 수
+
+
+
accept
시스템은 이 파일을 받아야 합니다.
4
+
reject
시스템은 이 파일을 거부해야 합니다.
3
+
+
+
+
+
+
+
무엇을 바꿀 수 있나요?
+
+
+
+
설정
값
기본값
동작
+
+
+
+
--limit
+
2mb와 같은 크기
+
10mb
+
시스템이 선언한 크기 한도입니다. 다른 모든 값은 이 값을 기준으로 측정됩니다. 이 기본값은 우리 쪽의 임시값이며 여러분 시스템의 값이 아닙니다. 직접 값을 지정하세요.
+
+
+
--spread
+
쉼표로 구분한 크기
+
1B,1kb,1mb
+
한도 양쪽으로 얼마나 멀리 갈지를 크기 목록으로 지정합니다.
+
+
+
--format
+
형식 페이지의 형식 id
+
pdf
+
세트에 포함된 모든 파일의 형식입니다. 도구 자체의 플래그이며, 프리셋은 기본값만 지정합니다.
+ tabular-import 프리셋은 이 질문에 대한 실제 테스트 파일 세트 전체를 명령 하나로 만들고, 그 옆에 시스템이 각 파일에 어떻게 반응해야 하는지 알려 주는
+ manifest.json을 둡니다. 아래의 모든 내용은 이 버전의 기본값으로 프로그램에서 읽어 온 것입니다.
+
+
+
+
+
보통 무엇을 찾아내나요?
+
+
구분자를 찾지 않고 가정했기 때문에 한 열로 읽히는 세미콜론 구분 파일
+
각 줄 뒤에 빈 줄이 생기며 행으로 나뉘는 CRLF 파일
+
첫 데이터 행이 열 이름으로 처리되어 사라지는 머리글 없는 표
+
표시할 수 있는 열만 남기고 나머지는 말없이 버리는 가져오기
+
JSON 레코드를 한 줄씩 읽다가 들여쓰기된 첫 문서에서 멈추는 리더
+
+
+
+
+
+
세트에는 무엇이 들어 있나요?
+
기본값에서 tfg preset show tabular-import가 보고하는 대로입니다.
+
+
+
+
파일 수
13
+
레시피의 타깃 수
13
+
총 크기
3 080 060 B
+
형식
csv, json, xlsx
+
+
+
+
그리고 그 세트의 매니페스트가 시스템에 기대하는 것:
+
+
+
+
기대값
의미
파일 수
+
+
+
accept
시스템은 이 파일을 받아야 합니다.
8
+
unspecified
시스템의 규칙에 따라 다릅니다. 직접 결정한 뒤 실제 일어나는 일이 의도한 것인지 확인하세요.
5
+
+
+
+
+
+
+
무엇을 바꿀 수 있나요?
+
+
+
+
설정
값
기본값
동작
+
+
+
+
--rows
+
1 - 200000 행
+
1000
+
스프레드시트에 담길 행 수입니다. 그만큼의 행이 패키징되는 정확한 크기로 파일이 쓰이므로, 위의 예산이 이 값에 따라 움직입니다.
+
+
+
--columns
+
1 - 32768 열
+
10
+
스프레드시트의 각 행에 있는 열 수입니다. 행 수와 열 수의 곱에는 상한이 있으며, 이를 넘는 요청은 아무것도 쓰기 전에 거부됩니다.
+ text-encoding 프리셋은 이 질문에 대한 실제 테스트 파일 세트 전체를 명령 하나로 만들고, 그 옆에 시스템이 각 파일에 어떻게 반응해야 하는지 알려 주는
+ manifest.json을 둡니다. 아래의 모든 내용은 이 버전의 기본값으로 프로그램에서 읽어 온 것입니다.
+
+
+
+
+
보통 무엇을 찾아내나요?
+
+
UTF-8로 가정하여 UTF-16 파일을 세 글자에 한 글자만, 또는 네모 칸의 행으로 보여 주는 리더
+
바이트 순서 표시를 내용으로 읽어서 가져오기의 첫 필드가 낯선 문자 세 개로 시작하는 문제
+
앞쪽 바이트로 인코딩을 추측하고 더 긴 파일에서는 다르게 추측하는 임포터
+
각 줄 뒤에 빈 줄이 생기며 행으로 나뉘는 CRLF 파일, 또는 마지막 필드에 남는 캐리지 리턴
+
+
+
+
+
+
세트에는 무엇이 들어 있나요?
+
기본값에서 tfg preset show text-encoding가 보고하는 대로입니다.
+
+
+
+
파일 수
20
+
레시피의 타깃 수
20
+
총 크기
81 920 B
+
형식
csv, log, md, txt, xml
+
+
+
+
그리고 그 세트의 매니페스트가 시스템에 기대하는 것:
+
+
+
+
기대값
의미
파일 수
+
+
+
accept
시스템은 이 파일을 받아야 합니다.
10
+
unspecified
시스템의 규칙에 따라 다릅니다. 직접 결정한 뒤 실제 일어나는 일이 의도한 것인지 확인하세요.
10
+
+
+
+
+
+
+
무엇을 바꿀 수 있나요?
+
+
+
+
설정
값
기본값
동작
+
+
+
+
--sample
+
2mb와 같은 크기
+
4kb
+
세트에 포함된 각 파일의 크기입니다. UTF-16은 글자당 2바이트를 저장하므로 홀수는 거부됩니다.
+ upload-validation 프리셋은 이 질문에 대한 실제 테스트 파일 세트 전체를 명령 하나로 만들고, 그 옆에 시스템이 각 파일에 어떻게 반응해야 하는지 알려 주는
+ manifest.json을 둡니다. 아래의 모든 내용은 이 버전의 기본값으로 프로그램에서 읽어 온 것입니다.
+
+
+
+
+
보통 무엇을 찾아내나요?
+
+
서버가 아니라 브라우저에서만 적용되는 한도
+
이미지나 일반 텍스트로 오인되는 SVG 또는 HTML 파일로, 스크립트가 양식 검사를 통과하는 방법이 됩니다
+
확장자로만 검사하고 열어 보지 않아서 .jpg라는 이름의 PDF가 통과하는 파일
+
크기를 확인하기 전에 본문 전체를 메모리로 읽어 들이는 양식
+
photo.jpg는 받으면서 PHOTO.JPG는 거부하거나 그 반대인 업로드
+
공백, 괄호, ASCII 이외의 문자가 든 이름이 그대로 디스크에 쓰이는 문제
+
+
+
+
+
+
세트에는 무엇이 들어 있나요?
+
기본값에서 tfg preset show upload-validation가 보고하는 대로입니다.
+
+
+
+
파일 수
71
+
레시피의 타깃 수
22
+
총 크기
120 639 488 B
+
형식
html, jpg, pdf, png, svg, txt
+
+
+
+
그리고 그 세트의 매니페스트가 시스템에 기대하는 것:
+
+
+
+
기대값
의미
파일 수
+
+
+
accept
시스템은 이 파일을 받아야 합니다.
56
+
reject
시스템은 이 파일을 거부해야 합니다.
10
+
unspecified
시스템의 규칙에 따라 다릅니다. 직접 결정한 뒤 실제 일어나는 일이 의도한 것인지 확인하세요.
5
+
+
+
+
+
+
+
무엇을 바꿀 수 있나요?
+
+
+
+
설정
값
기본값
동작
+
+
+
+
--limit
+
2mb와 같은 크기
+
10mb
+
업로드 양식이 선언한 크기 한도입니다. 이 세트는 한도 양쪽으로 한 단계씩 만듭니다. 모든 거리의 파일이 필요하면 size-boundaries 프리셋을 실행하세요. 이 기본값은 우리 쪽의 임시값이며 여러분 시스템의 값이 아닙니다. 직접 값을 지정하세요.
+
+
+
--allow
+
쉼표로 구분한 형식 id
+
jpg,png,pdf
+
양식이 받아야 할 유형입니다. 각 유형이 해당 유형의 실제 파일이 되며, 세트 전체의 양성 대조군이 됩니다.
+
+
+
--deny
+
쉼표로 구분한 확장자
+
svg,html,exe,sh
+
양식이 거부해야 할 확장자입니다. 이 빌드에 형식이 없는 확장자도 그 이름의 파일이 만들어지며, 내용은 일반 텍스트입니다.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
하나뿐인 큰 파일이 한도를 얼마나 넘는지입니다. 한도의 몇 배를 쓰는 것이 디스크 낭비라면 꺼 두세요.
+ 저장소의 바이너리 픽스처는 기록에 영원히 남고, diff에서 검토할 수 없으며, 파일이 커지면 아예 불가능해집니다. 대신 파이프라인 안에서 레시피로 파일을 생성하세요. 레시피는
+ 텍스트이고, 바이트는 매번 같게 나오며, 마지막 단계가 아무것도 움직이지 않았음을 증명합니다.
+
+
+
+
짧은 답
+
+ tfg를 설치하고, 테스트 전에 tfg generate fixtures.yaml --out ./fixtures를, 테스트 후에
+ tfg verify ./fixtures/manifest.json을 실행하세요. 두 단계 모두 스스로 빌드를 실패시키며, 이유를 알려 주는 종료 코드를
+ 남깁니다.
+
+
+
+
+
커밋하지 않는 이유
+
픽스처가 저장소에 있으면 안 되는 이유
+
+
+ 기록에 남습니다. 바이너리를 나중에 삭제해도 모든 버전이 그대로 있으므로 클론은 작아지지 않습니다.
+
+
+ diff로는 무엇이 바뀌었는지 알 수 없습니다. 검토자는 PDF가 다르다는 것만 볼 뿐 그 이상은 모릅니다. 레시피는 한 줄만 바뀝니다.
+
+
+ 큰 파일은 들어가지 않습니다. GitHub는 100 MB를 넘는 파일이 든 푸시를 거부하므로, 500 MB 업로드 한도를 테스트하려면 커밋할 것이
+ 없습니다.
+
+
+
+ 커밋할 것은 레시피입니다. 같은 레시피와 같은 시드는 어느 머신에서나 같은 바이트를 쓰므로, 파이프라인에서 생성한 파일은 노트북에 있던 바로 그 파일입니다.
+
+
+
+
+
레시피
+
테스트 옆에 두는 레시피
+
+ 이 레시피는 수락되어야 하는 청구서 25건과 한도를 넘어 거부되어야 하는 이미지 2장을 쓰며, 매니페스트는 두 기대 결과를 모두 기록합니다.
+
+ 이것은 PowerShell의 동작이지 이 도구와는 무관합니다. cmd, bash, zsh에는 따로 필요한 것이
+ 없습니다.
+
+
+
+
+
여러 작업
+
작업 사이에서 픽스처 공유하기
+
+ 보통은 업로드할 필요가 없습니다. 같은 레시피가 같은 바이트를 쓰므로 각 작업이 자기 tfg generate를 실행할 수 있고, 이것이 업로드 후
+ 다운로드보다 빠릅니다. 한 작업이 다른 작업에서 파일을 받아야 한다면 전송 후 매니페스트에 tfg verify를 실행하세요. 도착한 것이 기록된 것과
+ 같은지 알려 줍니다.
+
+ 1048575, 1048576, 1048577바이트의 실제 PDF 세 개와, 처음 두 개는 수락하고 세 번째는 size_limit으로 거부해야 한다고 알려
+ 주는 매니페스트를 얻습니다. 어서션 세 개를 직접 쓰는 대신 테스트가 기대값을 읽으며, 한도가 바뀌면 숫자 하나를 바꾸고 다시 실행하면 됩니다.
+
+
+ 경계 세트 하나를 인라인으로 만들고 싶다면 프리셋 없이도 같은 일을 할 수 있습니다.
+
+ 큰 바이너리 픽스처는 저장소 복제를 느리게 하고 리뷰를 불편하게 하며, 하나가 교체되어도 무엇이 바뀌었는지 아무도 알 수 없습니다. 레시피는 똑같은 파일을 다시 만드는 몇백 자의
+ YAML입니다. 어느 컴퓨터에서나 바이트 단위로 같습니다. 모든 파일이 실행의 시드에서 파생되기 때문입니다.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ 끝나는 방식마다 고유한 종료 코드가 있으므로 파이프라인은 잘못된 레시피, 디스크 가득 참, 검증 불일치를 구별할 수 있습니다. 실패한 실행은 표준 출력에 아무것도 출력하지 않아
+ 로그 파서가 오류를 데이터로 읽지 않습니다.
+
+
+
+
+
규모
+
폴더가 클 때 무슨 일이 일어나는지 알아내기
+
+ 가져오기 루틴, 야간 작업, 디렉터리 목록은 파일이 10개일 때와 1만 개일 때 다르게 동작합니다. 범위에서 뽑은 크기는 똑같은 파일 1만 개가 아니라 실제 트래픽처럼 보이는
+ 세트를 만들며, 추첨은 시드에서 나오므로 세트는 내일도 같습니다.
+
Hoe maak je een beschadigd bestand om mee te testen
+
+ Een validator aan wie alleen gezonde bestanden zijn getoond, is niet echt getest. Zo krijg je een
+ bestand dat met opzet kapot is, precies de grootte heeft die je vraagt en een
+ manifest meebrengt dat zegt wat je systeem ermee moet doen.
+
+
+
+
Het korte antwoord
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out schrijft een PNG
+ van precies 2097152 bytes waarvan de eerste bytes nullen zijn, en het manifest ernaast legt vast
+ dat je systeem het moet weigeren.
+
+
+
+
+
De gebruikelijke weg
+
Waarom een met de hand beschadigd bestand een slechte test is
+
+ Gebruikelijk zijn een hexeditor, een script dat een paar willekeurige bytes omgooit, of een bestand
+ dat met head of truncate wordt ingekort. Het werkt één keer, en daarna
+ kost het je:
+
+
+
+ Het is elke keer anders. Een willekeurige byte komt bij elke run ergens anders
+ terecht, dus een fout van dinsdag komt woensdag misschien niet terug.
+
+
+ Het verandert de grootte. Een ingekort bestand is kleiner dan de limiet waaronder
+ het hoorde te blijven, dus de groottecontrole antwoordt vóór de inhoudscontrole en de test
+ slaagt om de verkeerde reden.
+
+
+ Het valt vaak niet op. Platte tekst blijft leesbaar met een gewijzigde byte in het
+ midden, en een toegeeflijke afbeeldingslezer tekent het gewoon, waardoor het bestand dat kapot
+ moest zijn wordt geaccepteerd.
+
+
+ Het zegt niets over wat er moet gebeuren. Het bestand is alleen bytes, en wie de
+ test later leest, moet raden of acceptatie of weigering de bedoeling was.
+
+
+
+
+
+
Wat je krijgt
+
Een beschadigd bestand heeft nog steeds de grootte die je vroeg
+
+ Het bestand wordt normaal gegenereerd en daarna kapotgemaakt, op weg naar de schijf. Het houdt de
+ grootte die je vroeg, en hetzelfde commando schrijft opnieuw dezelfde bytes.
+
+ Instellingen komen achter een dubbele punt. De optie mag herhaald worden, en de beschadigingen
+ worden toegepast in de volgorde waarin je ze schrijft. Het werkt met elk van de
+ 26 formaten.
+
+
+
+
+
Wat het kan
+
Welke beschadigingen zijn er?
+
+ Dit is de lijst die het programma afdrukt, uit het programma gelezen op het moment dat deze pagina
+ wordt gebouwd. tfg damage drukt dezelfde af, en tfg damage <id>
+ zegt wat één ervan aanneemt.
+
+
+
+
+
+
Beschadiging
+
Wat het met de bytes doet
+
Kleinste bestand
+
Instellingen
+
+
+
+
+
zero-head
+
Overschrijft de eerste bytes van het bestand met nullen en laat de lengte ongemoeid. De meeste lezers kijken daar eerst, dus bijna alles merkt deze beschadiging.
+
8
+
bytes
+
+
+
+
+
+ zero-head schrijft nullen over het begin van het bestand. De meeste lezers kijken daar
+ eerst, naar de handtekening en de kop die zeggen wat het bestand is, dus bijna elke lezer merkt
+ het. Platte tekst en logbestanden hebben geen handtekening en worden ook geweigerd, omdat een
+ reeks nulbytes geen tekst is. Onder vier bytes komen sommige formaten uit met schade waar geen
+ lezer over klaagt, en daarom begint de instelling bij vier.
+
+
+
+
+
Wat het manifest zegt
+
Een manifest dat zegt wat er moet gebeuren
+
+ Elk beschadigd bestand krijgt een regel die zegt dat je systeem het moet weigeren, met de
+ beschadiging ernaast vastgelegd:
+
+ Twee verzoeken worden geweigerd voordat er iets wordt geschreven, omdat elk een bestand op schijf
+ zou laten staan dat het manifest verkeerd beschrijft:
+
+
+
een bestand dat kleiner is dan de beschadiging nodig heeft en ongewijzigd zou uitkomen
+
+ expected: accept naast een beschadiging, omdat niets daaraan kan voldoen. Schrijf
+ sanitize als je systeem het bestand moet repareren, of unspecified
+ als dat juist de vraag is die je stelt
+
+
+
+
+
+
In een recept
+
Gezonde en kapotte bestanden in één run
+
+ Zet beide in één recept, en het manifest draagt de verwachting van elk bestand, zodat de test geen
+ lijst nodig heeft van welk bestand welk is:
+
+ De test leest het manifest en controleert dat wat er gebeurde is wat er werd opgegeven. Hij heeft
+ geen lijst met bestandsnamen nodig:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Een goede weigering is een schone weigering. Een melding die zegt wat er mis was, is het antwoord
+ dat je wilt. Een serverfout, een vastloper of een half opgeslagen bestand is het gebrek dat deze
+ test moet vinden.
+
+
+
+
+
Verder
+
Waar je vandaar heen kunt
+
+
+ De preset upload-validation stelt een formulier de
+ andere twee vragen, die over de grootte en die over het type.
+
+ Elk systeem heeft er een opdracht voor, en alle drie staan hieronder. Ze geven je een bestand met
+ precies het juiste aantal bytes - en voor veel tests is dat alles wat je nodig hebt. Elke
+ opdracht op deze pagina is uitgevoerd vóór publicatie, op het systeem waartoe hij
+ behoort.
+
+
+
+
Het korte antwoord
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Groottes zijn in bytes, en 10 MB
+ geteld zoals je bestandsbeheer telt is 10485760.
+
+
+
+
+
Windows
+
fsutil, en een PowerShell-versie die niets extra's nodig heeft
+
+ fsutil wordt met Windows meegeleverd. Het neemt de grootte in bytes,
+ reken het getal dus eerst uit - 10 MB is 10485760, 100 MB is 104857600, 1 GB is 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Gemeten op Windows 11: het werkt vanaf een gewone prompt en heeft geen verhoogde nodig, en het
+ bestand komt uit op precies 10485760 bytes.
+
+
PowerShell kan hetzelfde zonder een ander programma aan te roepen, en begrijpt eenheden:
+ 10MB betekent in PowerShell 10485760 bytes, dezelfde telling op basis van 1024 die
+ Verkenner gebruikt, dus de twee opdrachten hierboven geven dezelfde grootte.
+
+
+
+
+
Linux
+
dd, truncate en fallocate, en het verschil dat mensen te pakken neemt
+
dd is degene die iedereen kent. Het schrijft de bytes echt:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate is direct klaar, en dat is de adder onder het gras. Gemeten op Alpine Linux
+ meldt het bestand 10485760 bytes en neemt het nul blokken in beslag - het is
+ een sparse bestand. Alles wat het leest krijgt tien megabyte aan nullen, maar
+ de schijf heeft de ruimte nooit afgestaan:
+
+
truncate -s 10M test10mb.bin
+
+ Dat is prima om een uploadlimiet te testen en misleidend om een schijfquotum te testen.
+ fallocate is degene waar je naar grijpt als de ruimte echt moet zijn:
+
+
fallocate -l 10M test10mb.bin
+
En als de inhoud onsamendrukbaar moet zijn, zodat een archiefprogramma hem niet weer kan verkleinen:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, dat niet sparse is, en de twee die je al kent
+
+ macOS levert mkfile mee. Gemeten op macOS 26.6.2: 10485760 bytes en 20480 blokken, dus
+ de ruimte is echt toegewezen in plaats van beloofd:
+
+
mkfile 10m test10mb.bin
+
dd en truncate zijn er ook en gedragen zich zoals op Linux:
Een bestand van de juiste grootte is geen bestand van het juiste soort
+
+ Alles hierboven geeft je een blok nullen. Dat is genoeg als wat getest wordt alleen naar de grootte
+ kijkt - een uploadlimiet, een quotum, een overdracht. Het is niet meer genoeg zodra iets het
+ bestand opent.
+
+
+ Gemeten, en het is de moeite waard om het zelf te doen: maak een bestand van 2 MB met
+ fsutil, noem het photo.png en geef het aan een afbeeldingsbibliotheek.
+ Pillow antwoordt cannot identify image file. Het is geen PNG. Dat is het ook nooit
+ geweest - alleen de naam zei het.
+
+
+ Dat doet er meer toe dan het klinkt, vanwege de kant waarop de test dan faalt. Je
+ upload-endpoint weigert het bestand, je test wordt groen en je concludeert dat de groottelimiet
+ werkt. Het weigerde het niet vanwege de grootte. Het weigerde het omdat de bytes geen afbeelding
+ waren, en de regel die je wilde testen is nooit bereikt.
+
+
+
een parser weigert het voordat een groottegrens wordt bekeken
+
een miniatuurstap faalt en de fout die je leest gaat over het miniatuur
+
een virusscanner of inhoudscontrole weigert het om een derde reden
+
een viewer toont niets, en niemand kan zeggen of dat de bug is
+
+
+
+
+
De andere weg
+
Een echt bestand van dat formaat, in precies de grootte die je vroeg
+
+ Dit is wat Testing Files Generator doet. Het bestand is een echt bestand van zijn formaat - het
+ opent in het programma waartoe het behoort - en het heeft het exacte aantal bytes dat je vroeg,
+ tot op de byte:
+
+ Vraag een grootte die een formaat niet kan halen en je krijgt een fout die de ondergrens en de reden
+ noemt, nooit een bestand van de verkeerde grootte. De pagina met
+ formaten toont elk formaat met het kleinste bestand dat het kan maken.
+
+
En een limiet is drie testgevallen in plaats van één, dus de tool bouwt ze alle drie:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Dat geeft je 10485759, 10485760 en 10485761 bytes, en een manifest dat zegt welke je systeem moet
+ accepteren en welke het moet weigeren. De pagina met
+ toepassingen loopt dat en vier andere taken door waarvoor het is gebouwd.
+
Gratis en open source, GPL-3.0. Geen account nodig. De downloads voor Windows en macOS zijn ondertekend en starten zonder waarschuwing.
+
+
+
+
Dus wat moet je gebruiken?
+
+
+
Gebruik de systeemopdracht
+
+ Als niets het bestand opent. Een groottelimiet testen op een endpoint dat eerst de grootte
+ controleert, een overdracht, een quotum, een volle schijf. Het is één regel en het is al
+ geïnstalleerd.
+
+
+
+
Gebruik een echte generator
+
+ Als iets het bestand parset, rendert, importeert of uitpakt - en als je morgen op een andere machine
+ dezelfde fixtures nodig hebt, byte voor byte.
+
+
+
+
+ Beide staan op deze pagina omdat beide soms goed zijn. De fout die je moet vermijden is de eerste
+ gebruiken waar de tweede nodig is en de groene test als bewijs lezen.
+
+ Alles wat de tool doet, geordend als de vragen waarmee mensen echt komen. De
+ README in de repository is de volledige referentie en komt altijd
+ overeen met de build die je hebt gedownload.
+
+
+
+
Welke opdrachten zijn er?
+
Elke doet precies één ding:
+
tfg generate bestanden maken, uit een recept of met opties
+tfg validate een recept controleren en niets schrijven
+tfg verify een map controleren tegen een manifest
+tfg cleanup de bestanden verwijderen die een manifest opsomt
+tfg recipe fmt een recept in zijn vaste vorm afdrukken
+tfg preset een set bestanden bouwen uit een benoemde testvraag
+tfg formats de formaten opsommen die deze build ondersteunt
+tfg damage de manieren opsommen waarop deze build een bestand met opzet kan beschadigen
+tfg tool kleine hulpmiddelen voor bestanden die je al hebt
+tfg version de versie van de tool tonen
+tfg license de licentie tonen en wat die betekent voor gegenereerde bestanden
+
+
+
+
Hoe genereer ik één bestand van een exacte grootte?
+
+ Noem het formaat, de grootte en waar het naartoe moet. Groottes tellen in 1024-tallen, dus
+ 2mb is 2097152 bytes. Een gewoon aantal bytes werkt ook, dus --size
+ 10485761 vraagt precies zoveel.
+
+
tfg generate --format png --size 2mb --out ./out
+
De nuttige opties van generate:
+
+
+
Optie
Wat het doet
+
+
--format <id>
formaat van de bestanden, bijvoorbeeld txt
+
--size <size>
exacte grootte van elk bestand, zoals 10mb of een gewoon aantal bytes
+
--size-range <a-b>
een grootte die per bestand uit een bereik wordt getrokken, zoals 1kb-8kb. De trekking komt uit de seed
+
--boundary <size>
drie bestanden rond een limiet: één byte eronder, de limiet, één byte erboven
+
--count <n>
hoeveel bestanden te maken. Standaard 1
+
--name <template>
naamsjabloon, bijvoorbeeld invoice_{index:04}.txt
+
--out <dir>
map om naartoe te schrijven
+
--seed <n>
seed van de run. Dezelfde seed geeft dezelfde bytes
+
--set <k>=<v>
een formaatinstelling, herhaalbaar
+
--damage <name>
de bestanden met opzet beschadigen, herhaalbaar en in volgorde toegepast. Draai tfg damage voor de lijst
+
--expected <outcome>
accept, reject, sanitize of unspecified
+
--dry-run
tellen en tonen, helemaal niets schrijven
+
--json
het manifest naar de standaarduitvoer schrijven
+
+
+
+
+
+
+
Hoe maak ik een bestand dat met opzet kapot is?
+
+ Elk ander bestand dat deze tool schrijft is correct per constructie, wat twee van de drie vragen
+ beantwoordt die een uploadvalidator stelt. --damage beantwoordt de derde - gaat het
+ bestand überhaupt open. Het bestand wordt normaal gemaakt en daarna beschadigd, dus het heeft
+ nog steeds de grootte die je vroeg.
+
+ Instellingen komen na een dubbele punt. De optie herhaalt zich, en de volgorde waarin je ze schrijft
+ is de volgorde waarin ze worden toegepast. tfg damage toont wat deze build kan en
+ wat elke variant accepteert.
+
+
In een recept is de sleutel een lijst, van namen of van instellingen:
+ Een beschadigd bestand krijgt expected: reject in het manifest, met de beschadiging
+ ernaast vastgelegd. Twee dingen worden geweigerd voordat er iets wordt geschreven, omdat elk
+ anders een bestand op schijf zou zetten dat het manifest verkeerd beschrijft:
+
+
+
een bestand dat kleiner is dan de beschadiging nodig heeft, omdat het ongewijzigd zou uitkomen
+
+ expected: accept naast een beschadiging, omdat niets daaraan kan voldoen. Schrijf
+ sanitize als het geteste systeem het bestand moet repareren, of
+ unspecified als dat de vraag is die je stelt
+
+
+
+ Een derde is vooraf niet te weten. Als een beschadiging draait en geen enkele byte verschuift, wordt
+ dat bestand weggegooid in plaats van geschreven - de run gaat door, zegt om welk bestand het
+ ging en eindigt met de gedeeltelijke afsluitcode.
+
+ Een recept is een YAML-bestand dat een hele run beschrijft. Commit het naast je tests en de fixtures
+ zijn geen binaries meer in je repository - iedereen kan ze byte voor byte opnieuw opbouwen uit
+ een bestand van een paar honderd tekens.
+
+ Elk target heeft precies één van deze sleutels nodig: size, size-range,
+ boundary of contains. Twee is een fout en geen ook. Een ongeldig
+ recept schrijft helemaal geen bestanden en meldt alle problemen tegelijk in
+ plaats van alleen het eerste, elk met de instelling waar het over gaat.
+
+
+
+
+
Hoe leg ik vast wat mijn systeem met een bestand moet doen?
+
Korte vorm als de uitkomst genoeg is, lange vorm als de reden ertoe doet:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ De uitkomsten zijn accept, reject, sanitize en
+ unspecified. De redenen zijn een gesloten lijst zodat een rapport erop kan
+ groeperen: content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit en
+ size_zero.
+
+
+ Een reden noemt de regel die in het spel is, niet het oordeel. Daarom kan dezelfde
+ reden onder beide uitkomsten staan - een bestand één byte onder een limiet is
+ accept, en de regel waar het om gaat is nog steeds size_limit.
+
+
+
+
+
Wat staat er in het manifest?
+
+ Het wordt aan het einde van elke run naast de bestanden geschreven, ook bij een onderbroken run. Eén
+ item per bestand:
+
+ Er komt een recipe_hash bij als de run uit een recept kwam, en preset met
+ overrides als hij uit een preset kwam, zodat een manifest altijd te herleiden is
+ tot wat het maakte.
+
+
+ Elk item draagt ook target_id, de id van het target in het recept dat het bestand
+ maakte, en summary.by_target telt de bestanden waar elk target op uitkwam. Een
+ recept met meerdere targets kan zo target voor target worden gecontroleerd zonder bestandsnamen
+ te lezen.
+
+
+
+
+
Wat is een preset?
+
+ Een kant-en-klare set bestanden die een veelvoorkomende testvraag beantwoordt, zodat je de set niet
+ zelf hoeft te ontwerpen. Presets zijn gewone recepten onder de motorkap, en eject
+ drukt het recept af zodat je het vanaf daar kunt bewerken. Elke preset heeft
+ een eigen pagina met wat hij meestal vindt, wat er in de set zit en
+ welke instellingen hij kent.
+
+ show zegt je wat de set zou kosten voordat je hem bouwt, en zegt zonder omwegen wanneer
+ een getal een tijdelijke waarde van ons is in plaats van een limiet van jou.
+
+
+
+
+
Wat betekenen de afsluitcodes?
+
+ Elk einde heeft zijn eigen code, machineleesbare uitvoer gaat naar de standaarduitvoer, en een
+ mislukte run drukt daar niets af. De tabel is een bevroren contract - de betekenis van een code
+ wijzigen vereist een major-versie.
+
+
+
+
+
+
Code
+
Betekenis
+
+
+
+
+
0
+
Alles werkte.
+
+
+
1
+
Een onverwachte fout in de tool.
+
+
+
2
+
Verkeerde opdracht of optie.
+
+
+
3
+
Het recept is niet geldig.
+
+
+
4
+
Het formaat kan niet wat er gevraagd werd.
+
+
+
5
+
Een lees- of schrijfactie is mislukt.
+
+
+
6
+
Niet genoeg schijfruimte.
+
+
+
7
+
verify vond een afwijking.
+
+
+
8
+
De run is klaar, maar niet alles is gemaakt.
+
+
+
130
+
Onderbroken met Ctrl+C.
+
+
+
143
+
Gestopt door een signaal, zo ziet een CI-timeout eruit.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Een run die met Ctrl+C is gestopt laat nog steeds een manifest achter en nooit een half geschreven
+ bestand, zodat een afgebroken taak door de volgende nog kan worden opgeruimd.
+
+ Ja, dezelfde engine met een venster erop, voor het testen dat niet geautomatiseerd is. Het is geen
+ uitgeklede versie: een test vergelijkt de twee interfaces mogelijkheid voor mogelijkheid, en
+ alles wat maar één van beide kan moet worden verklaard en gerechtvaardigd in plaats van
+ ongemerkt uit elkaar te drijven.
+
+
+ De schermen zijn één batch, presets, meerdere batches tegelijk en info. Het toont wat een run zou
+ kosten voordat er iets wordt geschreven, meldt de voortgang terwijl het draait en kan halverwege
+ worden afgebroken zonder een half geschreven bestand achter te laten. Het opent nog geen
+ receptbestand - recepten zijn voorlopig iets van de opdrachtregel, en het venster bouwt zijn
+ batches in het formulier.
+
26 bestandsformaten, elk gegenereerd in een exacte grootte
+
+ Elk daarvan is een echt bestand van dat formaat. Het opent in het programma waartoe
+ het behoort en is precies het aantal bytes dat je vroeg. Geen enkele is opgevulde nullen met een
+ extensie eraan geplakt.
+
+
+
+
+
+
+
Formaat
+
Naam
+
Extensie
+
Kleinste bestand
+
Volledigheid
+
Gecontroleerd met
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
niet van toepassing
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
niet van toepassing
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
niet van toepassing
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
Wat de kolommen betekenen
+
+
+
Kleinste bestand
+
+ Het minste aantal bytes dat deze tool voor dat formaat accepteert, inclusief het label dat hij in
+ het bestand schrijft. Vraag je minder, dan krijg je een fout die de ondergrens en de reden
+ noemt, nooit een bestand van de verkeerde grootte.
+
+
+
+
Volledigheid
+
+ Hoe volledig het bestand is. full betekent dat een lezer die het formaat echt parset
+ het accepteert, niet alleen dat de extensie klopt.
+
+
+
+
Gecontroleerd met
+
+ De onafhankelijke lezer die elk gegenereerd bestand opent voordat het formaat wordt uitgebracht -
+ een aparte implementatie, niet onze eigen code die haar eigen huiswerk nakijkt.
+
+
+
+
+ Elk formaat herhaalt zich ook tot op de byte: hetzelfde recept en dezelfde seed geven op elke
+ machine identieke bestanden, en daardoor is het veilig een recept te committen in plaats van de
+ fixtures zelf.
+
+
+
+
+
Instellingen die elk formaat accepteert
+
+ De meeste formaten hebben eigen instellingen - afbeeldingsafmetingen, JPEG-kwaliteit, aantal
+ PDF-pagina's, rijen en kolommen in een spreadsheet, hoeveel items er in een archief zitten. Stel
+ ze in met --set key=value op de opdrachtregel, of onder properties: in
+ een recept.
+
een datum zoals 2024-02-29 of 2024-02-29T13:45:00+02:00, of none
+
+
+
+
modified
+
een datum zoals 2024-02-29 of 2024-02-29T13:45:00+02:00, of none
+
+
+
png
+
width
+
1 - 20000 pixels
+
+
+
+
height
+
1 - 20000 pixels
+
+
+
pptx
+
slides
+
1 - 500 dia's
+
+
+
svg
+
width
+
1 - 20000 pixels
+
+
+
+
height
+
1 - 20000 pixels
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
de id van een formaat, zoals tfg formats ze opsomt
+
+
+
+
entry_size
+
een grootte zoals 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
waar of onwaar
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 pixels
+
+
+
+
height
+
1 - 20000 pixels
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
waar of onwaar
+
+
+
wav
+
sample_rate
+
8000 - 192000 hertz
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 pixels
+
+
+
+
height
+
1 - 16383 pixels
+
+
+
xlsx
+
rows
+
1 - 200000 rijen
+
+
+
+
columns
+
1 - 32768 kolommen
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
waar of onwaar
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
de id van een formaat, zoals tfg formats ze opsomt
+
+
+
+
entry_size
+
een grootte zoals 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
waar of onwaar
+
+
+
+
password
+
het wachtwoord, als platte tekst
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ Een waarde buiten wat een instelling accepteert wordt geweigerd met een melding die de instelling,
+ het toegestane bereik en het alternatief noemt. Een onbekende instelling is ook een fout, nooit
+ een stille standaardwaarde - een stilzwijgend geaccepteerde typefout geeft een bestand met de
+ verkeerde instellingen en een uur zoeken waarom de test slaagt terwijl dat niet zou moeten.
+
+
+ Draai tfg formats <id> om precies te zien wat één formaat accepteert in de build
+ die je hebt.
+
+
+
+
+
Archieven bevatten echte bestanden
+
+ targz en zip
+ kunnen met items worden gevuld in plaats van als lege huls te blijven. Een gegenereerd archief
+ bevat echt de documenten die het zegt te bevatten, dus alles wat het tijdens een test uitpakt
+ vindt er echte bestanden in.
+
Genereer echte testbestanden in elke exacte grootte
+
+ PDF, PNG, DOCX, ZIP - 26 formaten in totaal, en elk is een
+ echt bestand dat opent in het programma waartoe het behoort, in precies de grootte die
+ je vroeg. Elke run schrijft ook op wat je applicatie met elk bestand moet doen.
+ Opdrachtregel en bureaubladvenster, gratis en open source, volledig op je eigen machine.
+
Gratis en open source, GPL-3.0. Geen account nodig. De downloads voor Windows en macOS zijn ondertekend en starten zonder waarschuwing.
+
+
+
+
+ Het bureaubladvenster, klaargezet om een reeks bestanden te schrijven. Dezelfde engine draait achter de opdrachtregel.
+
+
+
+
+
+ 26
+
echte formaten, elk opent in het programma waartoe het behoort
+
+
+ 1 byte
+
de nauwkeurigheid van elke grootte die je vraagt, nooit stilzwijgend afgerond
+
+
+ 0
+
verbindingen naar wat dan ook - geen account, geen telemetrie, geen updatecontrole
+
+
+
+
+
Het probleem
+
Eén testbestand maken is makkelijk. De juiste duizend maken is het vervelende deel
+
Je test software die bestanden van mensen aanneemt. Vroeg of laat heb je nodig:
+
+
een PDF van precies 10 MB, om uit te zoeken of de uploadlimiet echt is
+
de drie bestanden aan weerszijden van die limiet, om off-by-one-fouten te vangen
+
10.000 logbestanden, om te zien wat de nachtelijke taak doet als de map groot is
+
een ZIP die echt 200 documenten bevat, geen lege huls met de juiste extensie
+
een bestand van 4 GB, zonder een bestand van 4 GB in je repository te bewaren
+
dezelfde fixtures op je laptop en op de buildserver, byte voor byte
+
+
+ Dat is wat dit vervangt. Het is gebouwd voor QA-engineers, testautomatisering en iedereen wiens code
+ een uploadformulier, een importroutine, een parser of een opslagquotum achter zich heeft.
+
+
+
+
+
Wat het anders maakt
+
Andere generatoren stoppen bij de bytes. Deze beantwoordt wat je test werkelijk vraagt
+
+ Een map met bestanden laat je nog steeds beslissen wat elk bestand moet bewijzen. Elke run schrijft
+ hier een manifest.json naast de bestanden - een eenvoudige lijst van alles wat is
+ gemaakt, en bij elk item een gedeclareerde verwachting.
+
+
Stel dat je upload-endpoint 1 MB toestaat. Vraag de drie bestanden die op die lijn zitten:
Drie bestanden, drie verschillende antwoorden, in machineleesbare vorm. Je test leest het manifest in plaats van dat jij de asserties met de hand schrijft:
Waar het antwoord van je eigen beleid afhangt, zegt het manifest dat
+
+ Het legt unspecified vast in plaats van een verwachting te verzinnen. Een generator die
+ gokt levert valse fouten op, en een suite die loos alarm slaat wordt uitgezet.
+
+
+
+
+
+
Presets
+
Kies de vraag, krijg de hele set
+
+ Een preset is een set testbestanden ontworpen rond één testvraag, zodat je zelf niet hoeft uit te
+ zoeken welke bestanden wat bewijzen. Elke heeft een pagina die zegt wat hij meestal vindt, wat
+ er in de set zit en welke instellingen hij kent.
+
+ Tienduizend logbestanden, elk tussen één en acht kilobyte, met groottes getrokken uit de seed zodat
+ morgen dezelfde set oplevert. Geef elke run een eigen map - het manifest is
+ het enige verslag van wat een run schreef, dus de tool weigert er een tweede overheen te
+ schrijven:
+
+ Groottes tellen in 1024-tallen, zoals je bestandsbeheer doet, dus 2mb betekent 2097152
+ bytes. Een gewoon aantal bytes werkt ook. De documentatie
+ behandelt recepten, het manifest en de afsluitcodes.
+
+
+
+
+
Wat je krijgt
+
Gebouwd voor een suite die onbeheerd draait
+
+
+
Exacte grootte, tot op de byte
+
Vraag 10485761 bytes en krijg precies dat. Een grootte die een formaat niet kan halen is een fout met een reden, nooit een bestand van de verkeerde grootte.
+
+
+
26 echte formaten
+
Geen opgevulde nullen met een extensie. Een gegenereerde PNG opent in een afbeeldingsviewer, een DOCX opent in Word, een ZIP pakt uit. Elk wordt vóór levering gecontroleerd met onafhankelijke lezers.
+
+
+
Een manifest dat een testorakel is
+
Pad, grootte, SHA-256, formaat, seed, toolversie - en wat je systeem met het bestand moet doen.
+
+
+
Reproduceerbaar
+
Hetzelfde recept en dezelfde seed, dezelfde bytes, op elke machine. Commit een klein YAML-recept in plaats van grote binaire fixtures.
+
+
+
Twee interfaces, één engine
+
Een opdrachtregel gebouwd voor CI en een bureaubladvenster voor verkennend testen. Geen van beide is een uitgeklede versie van de ander, en een test vergelijkt ze mogelijkheid voor mogelijkheid.
+
+
+
Volledig offline
+
Geen account, geen cloud, geen telemetrie, geen updatecontrole. In de opdrachtregel-binary is helemaal geen netwerkstack gecompileerd.
+
+
+
+
+
+
Download
+
Kies de build voor je systeem
+
+ Pak het archief uit en start het. tfg is de opdrachtregel en tfg-gui is
+ het bureaubladvenster. Er is geen installatieprogramma en niets om aan je machine toe te voegen.
+
+
+
+
+
+
Systeem
+
Opdrachtregel
+
Bureaubladvenster
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
Wat is ondertekend, en wat niet
+
+ De downloads voor Windows en macOS zijn ondertekend, dus ze starten zonder waarschuwing over een
+ onbekende ontwikkelaar. Die voor Linux niet, omdat desktop-Linux niets vergelijkbaars heeft om
+ ze mee te ondertekenen. Elk archief staat in verify-SHA256SUMS.txt op de
+ releasepagina, zodat je kunt controleren wat je hebt gedownload.
+
Komt een geldig bestand dat zo klein is als het formaat toestaat door de controle?
+
+ De preset empty-and-minimal bouwt met één opdracht een hele set echte testbestanden voor deze
+ vraag, en een manifest.json ernaast dat zegt hoe je systeem op elk bestand moet
+ reageren. Alles hieronder wordt uit het programma gelezen, bij de standaardwaarden van deze
+ versie.
+
+
+
+
+
Wat vindt hij meestal?
+
+
een geldig bestand dat als te klein wordt geweigerd, omdat de controle bytes telt in plaats van ze te lezen
+
een leeg bestand dat de lezer laat crashen in plaats van gemeld te worden
+
een afbeelding van één pixel breed die op weg naar het miniatuur door nul deelt
+
opslag die nul bytes als een mislukte upload leest en blijft opnieuw proberen
+
+
+
+
+
+
Wat zit er in de set?
+
Bij de standaardwaarden, zoals tfg preset show empty-and-minimal het meldt:
Slaat mijn systeem een bestandsnaam op, toont en geeft het die terug, ook als het die niet verwachtte?
+
+ De preset filename-handling bouwt met één opdracht een hele set echte testbestanden voor deze
+ vraag, en een manifest.json ernaast dat zegt hoe je systeem op elk bestand moet
+ reageren. Alles hieronder wordt uit het programma gelezen, bij de standaardwaarden van deze
+ versie.
+
+
+
+
+
Wat vindt hij meestal?
+
+
een naam die er op het scherm, in een log of in een lijst als een andere uitziet
+
een naam die tussen upload en opslag wordt afgekapt, ingekort of herschreven
+
een lengtelimiet die in tekens wordt geteld waar de opslag bytes telt
+
+
+
+
+
+
Wat zit er in de set?
+
Bij de standaardwaarden, zoals tfg preset show filename-handling het meldt:
+
+
+
+
Bestanden
50
+
Targets in het recept
50
+
Totale grootte
51 200 B
+
Formaten
txt
+
+
+
+
En wat het manifest van die set van je systeem verwacht:
+
+
+
+
Verwacht
Betekenis
Bestanden
+
+
+
accept
Je systeem moet het bestand aannemen.
4
+
unspecified
Het hangt af van de regels van je systeem. Jij beslist, en controleert daarna of wat er gebeurt is wat je bedoelde.
46
+
+
+
+
+
+
+
Wat kun je wijzigen?
+
+
+
+
Instelling
Accepteert
Standaard
Wat het doet
+
+
+
+
--format
+
een formaat-id van de pagina met formaten
+
txt
+
Het formaat van elk bestand in de set. Het is een optie van de tool zelf, en de preset geeft er alleen een standaardwaarde aan.
+
+
+
+
+
+
+
+
Hoe draai je hem?
+
Bekijk wat de set zou kosten, bouw hem, of neem zijn recept om te bewerken:
Presets voor testbestanden, een set voor elke testvraag
+
+ Een preset is een hele set testbestanden ontworpen rond één vraag, met een manifest dat zegt hoe je
+ systeem op elk bestand moet reageren. Jij kiest de vraag, de tool bouwt de set. Elke preset heeft
+ een eigen pagina met wat hij meestal vindt, wat er in de set zit en welke instellingen hij kent.
+
Neemt mijn uploadformulier aan wat het moet en weigert het de rest?
+
upload-validation
+
+
+
+
+
Hoe verschilt een preset van een recept?
+
+ Eronder niet. Een preset is een recept dat de tool voor je schrijft uit een paar instellingen.
+ tfg preset eject drukt dat recept af zodat je het naast je tests kunt bewaren en
+ bewerken, en een eigen recept kan met één regel op een preset voortbouwen, extends:
+ preset: gevolgd door zijn id.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Kan ik de standaardwaarden vertrouwen?
+
+ Voor de bestanden wel. Voor een getal dat alleen je systeem kent, zoals de limiet van een
+ uploadformulier, is een standaardwaarde een tijdelijke waarde van ons, en de tool zegt dat elke
+ keer dat hij er een gebruikt. De pagina van elke preset markeert die instellingen, en tfg
+ preset show zegt het voordat er iets wordt geschreven.
+
Wordt een groottelimiet precies afgedwongen waar hij is opgegeven?
+
+ De preset size-boundaries bouwt met één opdracht een hele set echte testbestanden voor deze
+ vraag, en een manifest.json ernaast dat zegt hoe je systeem op elk bestand moet
+ reageren. Alles hieronder wordt uit het programma gelezen, bij de standaardwaarden van deze
+ versie.
+
+
+
+
+
Wat vindt hij meestal?
+
+
off-by-one-fouten bij de limiet
+
MB verward met MiB, wat 4,8 procent is en genoeg om een bestand door te laten dat niet door zou mogen
+
een limiet die in de browser wordt afgedwongen en niet op de server
+
+
+
+
+
+
Wat zit er in de set?
+
Bij de standaardwaarden, zoals tfg preset show size-boundaries het meldt:
+
+
+
+
Bestanden
7
+
Targets in het recept
7
+
Totale grootte
73 400 320 B
+
Formaten
pdf
+
+
+
+
En wat het manifest van die set van je systeem verwacht:
+
+
+
+
Verwacht
Betekenis
Bestanden
+
+
+
accept
Je systeem moet het bestand aannemen.
4
+
reject
Je systeem moet het bestand weigeren.
3
+
+
+
+
+
+
+
Wat kun je wijzigen?
+
+
+
+
Instelling
Accepteert
Standaard
Wat het doet
+
+
+
+
--limit
+
een grootte zoals 2mb
+
10mb
+
De groottelimiet die je systeem opgeeft. Al het andere wordt hiervan afgemeten. Deze standaardwaarde is onze tijdelijke waarde, niet de waarde van je systeem. Geef je eigen op.
+
+
+
--spread
+
groottes gescheiden door komma's
+
1B,1kb,1mb
+
Hoe ver aan beide kanten van de limiet te gaan, als een lijst met groottes.
+
+
+
--format
+
een formaat-id van de pagina met formaten
+
pdf
+
Het formaat van elk bestand in de set. Het is een optie van de tool zelf, en de preset geeft er alleen een standaardwaarde aan.
+
+
+
+
+
+
+
+
Hoe draai je hem?
+
Bekijk wat de set zou kosten, bouw hem, of neem zijn recept om te bewerken:
Overleeft mijn tabelimport wat echte tools exporteren?
+
+ De preset tabular-import bouwt met één opdracht een hele set echte testbestanden voor deze
+ vraag, en een manifest.json ernaast dat zegt hoe je systeem op elk bestand moet
+ reageren. Alles hieronder wordt uit het programma gelezen, bij de standaardwaarden van deze
+ versie.
+
+
+
+
+
Wat vindt hij meestal?
+
+
een bestand met puntkomma's dat als één kolom wordt gelezen, omdat het scheidingsteken is aangenomen in plaats van gezocht
+
een CRLF-bestand dat in rijen wordt gesplitst met na elke rij een lege rij
+
een tabel zonder koprij waarvan de eerste gegevensrij als kolomnamen wordt opgegeten
+
een import die de kolommen houdt die hij kan tonen en de rest zonder een woord weggooit
+
een lezer die JSON-records regel voor regel leest en stopt bij het eerste ingesprongen document
+
+
+
+
+
+
Wat zit er in de set?
+
Bij de standaardwaarden, zoals tfg preset show tabular-import het meldt:
+
+
+
+
Bestanden
13
+
Targets in het recept
13
+
Totale grootte
3 080 060 B
+
Formaten
csv, json, xlsx
+
+
+
+
En wat het manifest van die set van je systeem verwacht:
+
+
+
+
Verwacht
Betekenis
Bestanden
+
+
+
accept
Je systeem moet het bestand aannemen.
8
+
unspecified
Het hangt af van de regels van je systeem. Jij beslist, en controleert daarna of wat er gebeurt is wat je bedoelde.
5
+
+
+
+
+
+
+
Wat kun je wijzigen?
+
+
+
+
Instelling
Accepteert
Standaard
Wat het doet
+
+
+
+
--rows
+
1 - 200000 rijen
+
1000
+
Hoeveel rijen de spreadsheet bevat. Het bestand wordt precies zo groot geschreven als zoveel rijen verpakt worden, dus het budget hierboven verschuift met deze waarde.
+
+
+
--columns
+
1 - 32768 kolommen
+
10
+
Hoeveel kolommen elke rij van de spreadsheet heeft. Rijen maal kolommen heeft een plafond, en erboven vragen wordt geweigerd voordat er iets geschreven wordt.
+
+
+
+
+
+
+
+
Hoe draai je hem?
+
Bekijk wat de set zou kosten, bouw hem, of neem zijn recept om te bewerken:
Weet mijn lezer in welke codering een bestand staat, of gokt hij?
+
+ De preset text-encoding bouwt met één opdracht een hele set echte testbestanden voor deze
+ vraag, en een manifest.json ernaast dat zegt hoe je systeem op elk bestand moet
+ reageren. Alles hieronder wordt uit het programma gelezen, bij de standaardwaarden van deze
+ versie.
+
+
+
+
+
Wat vindt hij meestal?
+
+
een lezer die UTF-8 aanneemt en een UTF-16-bestand toont als één teken op de drie, of als rijen vakjes
+
een byte order mark die als inhoud wordt gelezen, zodat het eerste veld van een import met drie vreemde tekens begint
+
een importeur die de codering uit de eerste bytes raadt en bij een langer bestand anders raadt
+
een CRLF-bestand dat in rijen wordt gesplitst met na elke rij een lege rij, of een regelterugloop die in het laatste veld blijft staan
+
+
+
+
+
+
Wat zit er in de set?
+
Bij de standaardwaarden, zoals tfg preset show text-encoding het meldt:
+
+
+
+
Bestanden
20
+
Targets in het recept
20
+
Totale grootte
81 920 B
+
Formaten
csv, log, md, txt, xml
+
+
+
+
En wat het manifest van die set van je systeem verwacht:
+
+
+
+
Verwacht
Betekenis
Bestanden
+
+
+
accept
Je systeem moet het bestand aannemen.
10
+
unspecified
Het hangt af van de regels van je systeem. Jij beslist, en controleert daarna of wat er gebeurt is wat je bedoelde.
10
+
+
+
+
+
+
+
Wat kun je wijzigen?
+
+
+
+
Instelling
Accepteert
Standaard
Wat het doet
+
+
+
+
--sample
+
een grootte zoals 2mb
+
4kb
+
Hoe groot elk bestand van de set is. UTF-16 slaat twee bytes per teken op, dus een oneven getal wordt geweigerd.
+
+
+
+
+
+
+
+
Hoe draai je hem?
+
Bekijk wat de set zou kosten, bouw hem, of neem zijn recept om te bewerken:
Neemt mijn uploadformulier aan wat het moet en weigert het de rest?
+
+ De preset upload-validation bouwt met één opdracht een hele set echte testbestanden voor deze
+ vraag, en een manifest.json ernaast dat zegt hoe je systeem op elk bestand moet
+ reageren. Alles hieronder wordt uit het programma gelezen, bij de standaardwaarden van deze
+ versie.
+
+
+
+
+
Wat vindt hij meestal?
+
+
een limiet die in de browser wordt afgedwongen en niet op de server
+
een SVG- of HTML-bestand dat voor een afbeelding of platte tekst wordt aangezien, een manier om een script langs een formulier te smokkelen
+
een bestand dat op extensie wordt gecontroleerd en nooit geopend, zodat een PDF met de naam .jpg erdoor komt
+
een formulier dat de hele body in het geheugen leest voordat het kijkt hoe groot hij is
+
een upload met de naam PHOTO.JPG die wordt geweigerd terwijl photo.jpg wordt aangenomen, of andersom
+
een naam met spaties, haakjes of tekens buiten ASCII die ongewijzigd naar schijf wordt geschreven
+
+
+
+
+
+
Wat zit er in de set?
+
Bij de standaardwaarden, zoals tfg preset show upload-validation het meldt:
+
+
+
+
Bestanden
71
+
Targets in het recept
22
+
Totale grootte
120 639 488 B
+
Formaten
html, jpg, pdf, png, svg, txt
+
+
+
+
En wat het manifest van die set van je systeem verwacht:
+
+
+
+
Verwacht
Betekenis
Bestanden
+
+
+
accept
Je systeem moet het bestand aannemen.
56
+
reject
Je systeem moet het bestand weigeren.
10
+
unspecified
Het hangt af van de regels van je systeem. Jij beslist, en controleert daarna of wat er gebeurt is wat je bedoelde.
5
+
+
+
+
+
+
+
Wat kun je wijzigen?
+
+
+
+
Instelling
Accepteert
Standaard
Wat het doet
+
+
+
+
--limit
+
een grootte zoals 2mb
+
10mb
+
De groottelimiet die je uploadformulier opgeeft. Deze set zet één stap aan beide kanten - voor een bestand op elke afstand draai je de preset size-boundaries. Deze standaardwaarde is onze tijdelijke waarde, niet de waarde van je systeem. Geef je eigen op.
+
+
+
--allow
+
formaat-id's gescheiden door komma's
+
jpg,png,pdf
+
Welke typen je formulier moet accepteren. Elk wordt een echt bestand van dat type, en ze vormen de positieve controle van de hele set.
+
+
+
--deny
+
extensies gescheiden door komma's
+
svg,html,exe,sh
+
Welke extensies je formulier moet weigeren. Een extensie waarvoor deze build geen formaat heeft, krijgt toch een bestand met die naam, met platte tekst erin.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
Hoe ver boven de limiet het ene grote bestand komt. Zet het uit waar het schrijven van een veelvoud van de limiet de schijfruimte niet waard is.
+
+
+
--bulk
+
0 - 10000 bestanden
+
50
+
Hoeveel bestanden de bulkupload bevat. Nul laat die groep helemaal uit de set.
+
+
+
+
+
+
+
+
Hoe draai je hem?
+
Bekijk wat de set zou kosten, bouw hem, of neem zijn recept om te bewerken:
+ Een binaire fixture in een repository blijft voorgoed in de geschiedenis, kan niet in een diff
+ worden beoordeeld en wordt onmogelijk zodra het bestand groot is. Genereer de bestanden in plaats
+ daarvan in de pipeline uit een recept. Het recept is tekst, de bytes komen elke keer hetzelfde uit
+ en een laatste stap bewijst dat er niets is veranderd.
+
+
+
+
Het korte antwoord
+
+ Installeer tfg, voer vóór de tests tfg generate fixtures.yaml --out
+ ./fixtures uit en erna tfg verify ./fixtures/manifest.json. Beide stappen
+ laten de build vanzelf mislukken, met een afsluitcode die zegt waarom.
+
+
+
+
+
Waarom niet committen
+
Waarom een fixture niet in de repository hoort
+
+
+ Het blijft in de geschiedenis. Een binair bestand later verwijderen maakt een kloon
+ niet kleiner, want elke versie ervan staat er nog.
+
+
+ Een diff laat niet zien wat er veranderde. De reviewer ziet dat een PDF anders is
+ en verder niets. Een recept verandert met één regel.
+
+
+ Grote bestanden passen niet. GitHub weigert een push met een bestand van meer dan
+ 100 MB, dus voor een test van een uploadlimiet van 500 MB valt er niets te committen.
+
+
+
+ Het recept is wat je commit. Hetzelfde recept en dezelfde seed schrijven op elke machine dezelfde
+ bytes, dus het bestand dat in de pipeline wordt gegenereerd is het bestand dat je op je laptop
+ had.
+
+
+
+
+
Het recept
+
Een recept dat naast de tests staat
+
+ Dit schrijft vijfentwintig facturen die geaccepteerd moeten worden en twee afbeeldingen boven een
+ limiet die geweigerd moeten worden, en het manifest legt beide verwachtingen vast:
+
+ De regel met de controlesom vergelijkt het archief met verify-SHA256SUMS.txt uit
+ dezelfde release. De versie is vastgezet, dus een nieuwe release verandert nooit een build die
+ je niet hebt aangeraakt.
+
+ Elk einde heeft zijn eigen afsluitcode, dus de stap mislukt vanzelf en het log zegt welke. De codes
+ die een pipeline tegenkomt:
+
+
+
3 - het recept is niet geldig. Er is niets geschreven en elk probleem wordt genoemd
+
4 - het formaat kan niet wat er gevraagd werd, bijvoorbeeld een grootte onder zijn minimum
+
6 - er is niet genoeg schijfruimte
+
7 - tfg verify vond een bestand dat niet bij zijn manifest past
+
8 - de run is klaar, maar niet alles is gemaakt
+
+
+ Een mislukte run drukt niets af op de standaarduitvoer, zodat een logparser een fout nooit voor data
+ aanziet. De hele tabel staat op de documentatiepagina.
+
+
+
+
+
PowerShell
+
Een PowerShell-script heeft nog één regel nodig
+
+ PowerShell neemt de afsluitcode van een programma niet mee uit een .ps1-bestand. Start
+ er een met -File en het script antwoordt 0, ook als de tool erin het
+ werk weigerde, waardoor een build die rood hoort te zijn groen wordt. De laatste regel is de
+ hele oplossing:
+
+ Zo gedraagt PowerShell zich, het ligt niet aan deze tool. cmd, bash en
+ zsh hebben niets extra nodig.
+
+
+
+
+
Meerdere jobs
+
De fixtures delen tussen jobs
+
+ Uploaden is meestal niet nodig. Omdat hetzelfde recept dezelfde bytes schrijft, kan elke job zijn
+ eigen tfg generate uitvoeren, wat sneller is dan uploaden en downloaden. Moet een
+ job bestanden van een andere ontvangen, voer dan na de overdracht tfg verify uit op
+ het manifest, en het zegt of wat aankwam is wat werd geschreven.
+
+ Vijf taken die in bijna elk project voorkomen dat bestanden van mensen aanneemt, en de opdracht die
+ elk doet. Elk voorbeeld hieronder werkt zoals het is geschreven.
+
+
+
+
Uploadlimieten
+
Testen of een limiet voor bestandsgrootte wordt afgedwongen waar hij zegt dat hij dat doet
+
+ Een limiet is drie testgevallen, niet één: net eronder, precies erop en net erboven. Die met de hand
+ maken betekent bytetellingen uitrekenen en hopen dat je er niet één naast zit. Vraag in plaats
+ daarvan de set:
+
+ Je krijgt drie echte PDF's van 1048575, 1048576 en 1048577 bytes, en een manifest dat zegt dat de
+ eerste twee geaccepteerd moeten worden en de derde geweigerd wegens size_limit. Je
+ test leest de verwachting in plaats van dat jij drie asserties met de hand schrijft - en als de
+ limiet verandert, wijzig je één getal en draai je opnieuw.
+
+
+ Hetzelfde werkt zonder preset als je één set grenzen inline wilt:
+
Fixtures uit de repository houden zonder ze kwijt te raken
+
+ Grote binaire fixtures maken een repository traag om te klonen en lastig te reviewen, en niemand kan
+ zien wat er veranderde toen er een werd vervangen. Een recept is een paar honderd tekens YAML
+ die de identieke bestanden opnieuw opbouwen - byte voor byte, op elke machine -
+ omdat elk bestand is afgeleid van de seed van de run.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Elk einde heeft zijn eigen afsluitcode, dus een pipeline kan een slecht recept onderscheiden van een
+ volle schijf en van een afwijking bij verificatie. Een mislukte run drukt niets af op de
+ standaarduitvoer, waardoor een logparser een fout niet als gegevens leest.
+
+
+
+
+
Schaal
+
Uitzoeken wat er gebeurt als de map groot is
+
+ Importroutines, nachtelijke taken en maplijsten gedragen zich anders bij tienduizend bestanden dan
+ bij tien. Groottes getrokken uit een bereik laten de set op echt verkeer lijken in plaats van op
+ tienduizend identieke bestanden, en de trekking komt uit de seed, dus de set is morgen dezelfde.
+
+ Een run die groter is dan de vrije ruimte op de schijf wordt geweigerd voordat de eerste byte is
+ geschreven, in plaats van de schijf te vullen en halverwege te falen.
+
+
+
+
+
Archieven
+
Een uitpakprogramma testen met een archief dat echt bestanden bevat
+
+ Een leeg archief met de juiste extensie bewijst niets over code die het opent en doorloopt wat erin
+ zit. Declareer de inhoud en het archief bevat die echt:
+
+ Nestdiepte, aantal items en de grootte van wat erin zit zijn allemaal dingen waar een importroutine
+ een mening over heeft, en zo kom je erachter wat die meningen zijn.
+
+
+
+
+
Parsers en viewers
+
Controleren dat je eigen code een formaat leest zoals echte software dat doet
+
+ Elk formaat hier wordt vóór levering gecontroleerd met een onafhankelijke lezer - een PNG wordt
+ geopend en de pixels worden vergeleken, een DOCX wordt teruggelezen door aparte bibliotheken,
+ een archief wordt uitgepakt. Dat betekent dat een bestand dat je parser weigert een bevinding is
+ over je parser, niet over de generator.
+
+ De pagina met formaten toont de instellingen die elk accepteert en het
+ kleinste bestand dat elk kan zijn.
+
+
+
+
+
Handleidingen
+
Twee hiervan in detail
+
+
+ Beschadigde testbestanden - een bestand dat met opzet
+ kapot is, op exacte grootte, met in het manifest wat ermee moet gebeuren.
+
+
+ Testbestanden in CI - een GitHub Actions-workflow, een
+ GitLab-job en de afsluitcodes die een build laten mislukken.
+
+
+
+
+
+
Voor wie dit is
+
+ QA-engineers, testautomatisering en iedereen wiens code een uploadformulier, een importroutine, een
+ parser of een opslagquotum achter zich heeft. Het draait op een machine zonder enig netwerk, wat
+ telt in een afgesloten bedrijfsomgeving waar een generator in de browser geen optie is.
+
+ Licentie, privacy, reproduceerbaarheid en de dingen die mensen nagaan voordat ze een generator in
+ een buildpipeline zetten. Staat je vraag er niet bij, dan staat de
+ issuetracker open.
+
+
+
+
+
Waarin verschilt dit van dd, fsutil of truncate?
+
+
Die geven je een bestand van de juiste grootte vol met niets. Een bestand van 2 MB met de naam photo.png dat zo is gemaakt is geen PNG, dus alles wat het echt parset weigert het om de verkeerde reden, en je test slaagt dan ook om de verkeerde reden. Dit maakt een echte PNG van precies 2 MB die opent in een afbeeldingsviewer, en komt met een verklaring over hoe je systeem ermee om moet gaan.
Is het gratis, en mag ik het op het werk gebruiken?
+
+
Ja op beide. Het is uitgebracht onder de GPL-3.0 en kost niets. Er is geen account, geen licentiesleutel en geen betaalde variant.
+
+
+
+
Mag ik de gegenereerde bestanden in een closed source product gebruiken?
+
+
Ja. De licentie geldt voor de code van de tool, niet voor wat de tool produceert. Gegenereerde bestanden, recepten en manifesten zijn uitvoer en geen afgeleide werken, dus je kunt ze committen en verspreiden zonder enige verplichting.
+
+
+
+
Bevatten de gegenereerde bestanden echte persoonsgegevens?
+
+
Nee. Alles erin wordt gesynthetiseerd uit een seed. Er wordt geen dataset gelezen, geen dienst benaderd en geen inhoud van derden ingebed. Behandel een gegenereerd e-mailadres als onbruikbaar in plaats van als ongebruikt, want elke willekeurige tekenreeks kan bij toeval samenvallen met een echte.
+
+
+
+
Krijg ik op een andere machine precies dezelfde bestanden?
+
+
Ja, byte voor byte, bij hetzelfde recept en dezelfde seed. Het project test dat bij elke wijziging, en het breken ervan vereist een major-versie. Daardoor kun je een klein recept committen in plaats van grote binaire fixtures.
+
+
+
+
Heeft het een internetverbinding nodig?
+
+
Nooit. Er is geen telemetrie, geen updatecontrole en geen cloudclient, en in de opdrachtregel-binary is helemaal geen netwerkstack gecompileerd. Het werkt op een machine zonder netwerk en binnen een afgesloten bedrijfsomgeving.
+
+
+
+
Wat gebeurt er als ik een grootte vraag die een formaat niet kan halen?
+
+
Je krijgt een fout die het formaat noemt, de kleinst mogelijke grootte, de reden voor die ondergrens en wat je in plaats daarvan kunt doen, en er wordt geen bestand geschreven. De tool rondt een grootte nooit stilzwijgend af. Elke ondergrens staat op de pagina met formaten.
+
tfg formats png
+
+
+
+
Kan ik een bewust kapot bestand genereren?
+
+
Ja. Voeg --damage zero-head toe en het bestand komt uit op precies de gevraagde grootte, met de eerste bytes overschreven door nullen, zodat een lezer het weigert, en het manifest zegt dat je systeem het moet weigeren. De details staan op de pagina over beschadigde testbestanden.
7z, mp3 en mp4. Vandaag werken 26 formaten van begin tot eind.
+
+
+
+
Op welke systemen kan ik het draaien?
+
+
De opdrachtregel draait op Windows en Linux, zowel op Intel als op ARM, en op Macs met Apple Silicon. Het bureaubladvenster wordt geleverd voor Windows op Intel, Linux op Intel en Macs met Apple Silicon. Intel-Macs worden niet ondersteund en daar wordt niets voor gebouwd.
+
+
+
+
Moet ik iets installeren?
+
+
Nee. Download het archief voor je systeem, pak het uit en start de binary. Er is geen installatieprogramma, geen runtime om toe te voegen en geen afhankelijkheid om op te lossen. Als je Go hebt, werkt ook één enkele go install-opdracht.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
Waarom is een run over duizenden bestanden trager op Windows?
+
+
Omdat Windows meer rekent voor elk pad dat het bekijkt, en een opdracht die over duizenden bestanden gaat bekijkt duizenden paden. Gemeten op één machine met 3000 bestanden van 1 kB doet verify er ongeveer 0,9 seconde over op Windows en ongeveer 0,2 seconde op Linux in een container. Een korter uitvoerpad maakt het cijfer voor Windows kleiner, omdat elke map boven de bestanden deel uitmaakt van wat wordt bekeken.
jednego bajtu, taki plik zostaje odrzucony zamiast zapisany - przebieg idzie dalej, mówi,
którego pliku to dotyczyło, i kończy się kodem częściowego wyniku.
+
Przebieg zatrzymany przez Ctrl+C i tak zostawia manifest i nigdy nie zostawia pliku zapisanego
w połowie, więc anulowane zadanie da się posprzątać następnym.
+
Jeszcze nie. Pliki uszkodzone i niepoprawne są zaplanowaną funkcją. Dziś każdy plik, który narzędzie zapisuje, jest poprawnym plikiem swojego formatu.
+
Tak. Dodaj --damage zero-head, a plik wyjdzie dokładnie o podanym rozmiarze, z pierwszymi bajtami nadpisanymi zerami, więc czytnik go odrzuci, a manifest powie, że system powinien go odrzucić. Szczegóły są na stronie o uszkodzonych plikach testowych.
+ Binarny plik testowy w repozytorium zostaje w jego historii na zawsze, nie da się go ocenić w
+ różnicach i przestaje być możliwy, gdy plik jest duży. Zamiast tego generuj pliki w potoku z
+ przepisu. Przepis jest tekstem, bajty wychodzą za każdym razem takie same, a ostatni krok dowodzi,
+ że nic się nie ruszyło.
+
+
+
+
Krótka odpowiedź
+
+ Zainstaluj tfg, uruchom tfg generate fixtures.yaml --out ./fixtures przed
+ testami, a tfg verify ./fixtures/manifest.json po nich. Oba kroki same przerywają
+ build, z kodem wyjścia mówiącym dlaczego.
+
+
+
+
+
Dlaczego nie commitować
+
Dlaczego pliku testowego nie powinno być w repozytorium
+
+
+ Zostaje w historii. Usunięcie pliku binarnego później nie zmniejsza klonu, bo każda
+ jego wersja nadal tam jest.
+
+
+ Różnice nie pokażą, co się zmieniło. Recenzent widzi, że PDF jest inny, i nic
+ więcej. Przepis zmienia się o jedną linię.
+
+
+ Duże pliki się nie mieszczą. GitHub odrzuca push z plikiem większym niż 100 MB,
+ więc test limitu uploadu 500 MB nie ma czego commitować.
+
+
+
+ Commitować trzeba przepis. Ten sam przepis i ziarno zapisują te same bajty na każdej maszynie, więc
+ plik wygenerowany w potoku jest tym plikiem, który miałeś na laptopie.
+
+
+
+
+
Przepis
+
Przepis, który leży obok testów
+
+ Ten zapisuje dwadzieścia pięć faktur, które powinny zostać przyjęte, i dwa obrazy ponad limitem,
+ które powinny zostać odrzucone, a manifest zapisuje oba oczekiwania:
+
+ Wiersz z sumą kontrolną porównuje archiwum z verify-SHA256SUMS.txt z tego samego
+ wydania. Wersja jest przypięta, więc nowe wydanie nigdy nie zmieni buildu, którego nie ruszałeś.
+
+ Każde zakończenie ma własny kod wyjścia, więc krok sam się przerywa, a log mówi, który to był. Te,
+ które spotyka potok:
+
+
+
3 - przepis jest niepoprawny. Nic nie zapisano, a każdy problem jest nazwany
+
4 - format nie potrafi tego, o co poproszono, na przykład rozmiaru poniżej swojego najmniejszego
+
6 - brakuje miejsca na dysku
+
7 - tfg verify znalazł plik, który nie zgadza się z manifestem
+
8 - przebieg się skończył, ale nie wszystko powstało
+
+
+ Nieudany przebieg nie wypisuje niczego na standardowe wyjście, więc parser logów nigdy nie weźmie
+ błędu za dane. Cała tabela jest na stronie dokumentacji.
+
+
+
+
+
PowerShell
+
Skrypt PowerShella potrzebuje jeszcze jednej linii
+
+ PowerShell nie wynosi kodu wyjścia programu poza plik .ps1. Uruchom go z
+ -File, a skrypt odpowie 0, nawet gdy narzędzie w środku odmówiło
+ pracy, więc build, który powinien być czerwony, robi się zielony. Ostatnia linia to cała
+ poprawka:
+
+ Tak zachowuje się PowerShell, a nie to narzędzie. cmd, bash i
+ zsh nie potrzebują niczego więcej.
+
+
+
+
+
Kilka zadań
+
Przekazywanie plików testowych między zadaniami
+
+ Zwykle nie trzeba ich wysyłać. Skoro ten sam przepis zapisuje te same bajty, każde zadanie może
+ uruchomić własne tfg generate, co jest szybsze niż wysyłanie i pobieranie. Gdy
+ zadanie musi dostać pliki z innego, uruchom tfg verify na manifeście po przesłaniu,
+ a powie, czy to, co dotarło, jest tym, co zapisano.
+
+ Walidator, któremu pokazywano tylko zdrowe pliki, nie został naprawdę przetestowany. Oto jak dostać
+ plik zepsuty celowo, o dokładnie takim rozmiarze, jaki podasz, z manifestem
+ mówiącym, co system ma z nim zrobić.
+
+
+
+
Krótka odpowiedź
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out zapisuje PNG o
+ dokładnie 2097152 bajtach, którego pierwsze bajty są zerami, a manifest obok zapisuje, że system
+ powinien go odrzucić.
+
+
+
+
+
Zwykła droga
+
Dlaczego plik uszkodzony ręcznie to kiepski test
+
+ Zwykle używa się edytora szesnastkowego, skryptu zmieniającego kilka losowych bajtów albo ucięcia
+ pliku przez head lub truncate. Za pierwszym razem działa, a potem
+ kosztuje:
+
+
+
+ Za każdym razem jest inaczej. Losowy bajt trafia w nowe miejsce przy każdym
+ przebiegu, więc błąd z wtorku może nie wrócić w środę.
+
+
+ Zmienia rozmiar. Plik ucięty jest mniejszy niż limit, pod którym miał się mieścić,
+ więc kontrola rozmiaru odpowiada przed kontrolą zawartości, a test przechodzi z niewłaściwego
+ powodu.
+
+
+ Często nikt tego nie zauważa. Zwykły tekst da się czytać mimo zmienionego bajtu w
+ środku, a pobłażliwy czytnik obrazów po prostu go narysuje, więc plik, który miał być zepsuty,
+ zostaje przyjęty.
+
+
+ Nic nie mówi o tym, co ma się stać. Plik to same bajty, a ten, kto później czyta
+ test, musi zgadywać, czy chodziło o przyjęcie, czy o odrzucenie.
+
+
+
+
+
+
Co dostajesz
+
Uszkodzony plik ma nadal rozmiar, o który prosiłeś
+
+ Plik jest generowany normalnie, a psuty dopiero w drodze na dysk. Zachowuje rozmiar, który podałeś,
+ a to samo polecenie zapisuje znowu te same bajty.
+
+ Ustawienia podaje się po dwukropku. Flagę można powtarzać, a uszkodzenia są stosowane w kolejności,
+ w jakiej je zapiszesz. Działa z każdym z 26 formatów.
+
+
+
+
+
Co potrafi
+
Jakie są uszkodzenia?
+
+ To lista, którą wypisuje program, odczytana z niego w chwili budowania tej strony. tfg
+ damage wypisuje to samo, a tfg damage <id> mówi, co przyjmuje jedno z
+ nich.
+
+
+
+
+
+
Uszkodzenie
+
Co robi z bajtami
+
Najmniejszy plik
+
Ustawienia
+
+
+
+
+
zero-head
+
Nadpisuje pierwsze bajty pliku zerami, nie zmieniając jego długości. Większość czytników zagląda tam najpierw, więc to uszkodzenie zauważy prawie wszystko.
+
8
+
bytes
+
+
+
+
+
+ zero-head zapisuje zera na początku pliku. Większość czytników zagląda tam najpierw, w
+ sygnaturę i nagłówek mówiące, czym jest plik, więc zauważy to prawie każdy czytnik. Zwykły tekst
+ i logi nie mają sygnatury i też są odrzucane, bo ciąg zerowych bajtów nie jest tekstem. Poniżej
+ czterech bajtów niektóre formaty wychodzą z uszkodzeniem, na które nie skarży się żaden czytnik,
+ dlatego ustawienie zaczyna się od czterech.
+
+
+
+
+
Co mówi manifest
+
Manifest, który mówi, co ma się stać
+
+ Każdy uszkodzony plik dostaje wpis mówiący, że system powinien go odrzucić, a obok zapisane jest
+ uszkodzenie:
+
+ Dwie prośby są odrzucane, zanim cokolwiek powstanie, bo każda zostawiłaby na dysku plik, który
+ manifest opisuje błędnie:
+
+
+
plik mniejszy, niż potrzebuje uszkodzenie, bo wyszedłby nietknięty
+
+ expected: accept obok uszkodzenia, bo nic nie mogłoby tego spełnić. Napisz
+ sanitize, jeśli system ma plik naprawić, albo unspecified, jeśli
+ właśnie o to pytasz
+
+
+
+
+
+
W przepisie
+
Zdrowe i zepsute pliki w jednym przebiegu
+
+ Włóż jedno i drugie do jednego przepisu, a manifest niesie oczekiwanie każdego pliku, więc test nie
+ potrzebuje listy, który jest który:
+
+ Test czyta manifest i sprawdza, czy to, co się stało, jest tym, co zadeklarowano. Nie potrzebuje
+ listy nazw plików:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Dobre odrzucenie jest czyste. Komunikat mówiący, co było nie tak, to odpowiedź, o którą chodzi. Błąd
+ serwera, zawieszenie albo plik zapisany do połowy to wada, którą ten test ma znaleźć.
+
+ Um validador que só viu arquivos saudáveis não foi realmente testado. Veja como obter um arquivo
+ quebrado de propósito, que sai com exatamente o tamanho que você pede e traz um
+ manifesto dizendo o que o seu sistema deve fazer com ele.
+
+
+
+
A resposta curta
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out grava um PNG de
+ exatamente 2097152 bytes cujos primeiros bytes são zeros, e o manifesto ao lado registra que o
+ seu sistema deve rejeitá-lo.
+
+
+
+
+
O jeito de sempre
+
Por que um arquivo corrompido à mão é um teste ruim
+
+ O jeito de sempre é um editor hexadecimal, um script que troca alguns bytes aleatórios ou cortar um
+ arquivo com head ou truncate. Funciona uma vez, e depois sai caro:
+
+
+
+ É diferente a cada vez. Um byte aleatório cai num lugar novo a cada execução, então
+ uma falha de terça pode não voltar na quarta.
+
+
+ Muda o tamanho. Um arquivo cortado fica menor que o limite abaixo do qual deveria
+ ficar, então a checagem de tamanho responde antes da checagem de conteúdo e o teste passa pelo
+ motivo errado.
+
+
+ Muitas vezes passa despercebido. Texto simples continua legível com um byte
+ alterado no meio, e um leitor de imagens tolerante simplesmente o desenha, então o arquivo que
+ deveria estar quebrado é aceito.
+
+
+ Não diz nada sobre o que deve acontecer. O arquivo é só bytes, e quem ler o teste
+ depois precisa adivinhar se a intenção era aceitação ou rejeição.
+
+
+
+
+
+
O que você recebe
+
Um arquivo danificado continua com o tamanho que você pediu
+
+ O arquivo é gerado normalmente e quebrado depois, a caminho do disco. Ele mantém o tamanho pedido, e
+ o mesmo comando grava os mesmos bytes outra vez.
+
+ As configurações vão depois de dois-pontos. A opção pode ser repetida, e os danos são aplicados na
+ ordem em que você os escreve. Funciona com cada um dos 26 formatos.
+
+
+
+
+
O que ele sabe fazer
+
Quais danos existem?
+
+ Esta é a lista que o programa imprime, lida dele quando esta página é construída. tfg
+ damage imprime a mesma, e tfg damage <id> diz o que cada um aceita.
+
+
+
+
+
+
Dano
+
O que faz com os bytes
+
Menor arquivo
+
Configurações
+
+
+
+
+
zero-head
+
Sobrescreve os primeiros bytes do arquivo com zeros, sem mexer no comprimento. A maioria dos leitores olha ali primeiro, então quase tudo percebe este dano.
+
8
+
bytes
+
+
+
+
+
+ zero-head grava zeros sobre o início do arquivo. A maioria dos leitores olha ali
+ primeiro, para a assinatura e o cabeçalho que dizem o que o arquivo é, então quase todo leitor
+ percebe. Texto simples e logs não têm assinatura e também são recusados, porque uma sequência de
+ bytes zero não é texto. Abaixo de quatro bytes, alguns formatos saem com um dano de que nenhum
+ leitor reclama, e por isso a configuração começa em quatro.
+
+
+
+
+
O que o manifesto diz
+
Um manifesto que diz o que deve acontecer
+
+ Cada arquivo danificado recebe uma entrada dizendo que o seu sistema deve rejeitá-lo, com o dano
+ registrado ao lado:
+
+ Dois pedidos são recusados antes de qualquer coisa ser gravada, porque cada um deixaria no disco um
+ arquivo que o manifesto descreve errado:
+
+
+
um arquivo menor do que o dano precisa, que sairia intacto
+
+ expected: accept ao lado de um dano, porque nada poderia cumprir isso. Escreva
+ sanitize se o seu sistema deve consertar o arquivo, ou unspecified
+ se essa é justamente a pergunta que você faz
+
+
+
+
+
+
Em uma receita
+
Arquivos saudáveis e quebrados em uma execução
+
+ Ponha os dois em uma receita, e o manifesto leva a expectativa de cada arquivo, então o teste não
+ precisa de uma lista de qual é qual:
+
+ O teste lê o manifesto e confere se o que aconteceu é o que foi declarado. Não precisa de uma lista
+ de nomes de arquivo:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Uma boa recusa é uma recusa limpa. Uma mensagem que diz o que estava errado é a resposta que você
+ quer. Um erro de servidor, uma trava ou um arquivo salvo pela metade é o defeito que este teste
+ existe para achar.
+
+
+
+
+
A seguir
+
Para onde ir daqui
+
+
+ O preset upload-validation faz a um formulário as
+ outras duas perguntas, a do tamanho e a do tipo.
+
+ Uma fixture binária em um repositório fica para sempre no histórico, não pode ser revisada em um
+ diff e deixa de ser viável quando o arquivo é grande. Gere os arquivos dentro do pipeline a partir
+ de uma receita. A receita é texto, os bytes saem iguais a cada vez e um último passo prova que
+ nada mudou.
+
+
+
+
A resposta curta
+
+ Instale o tfg, rode tfg generate fixtures.yaml --out ./fixtures antes dos
+ testes e tfg verify ./fixtures/manifest.json depois. Os dois passos fazem o build
+ falhar sozinhos, com um código de saída que diz o motivo.
+
+
+
+
+
Por que não commitar
+
Por que uma fixture não deve morar no repositório
+
+
+ Ela fica no histórico. Apagar um binário depois não deixa um clone menor, porque
+ todas as versões dele continuam lá.
+
+
+ Um diff não mostra o que mudou. O revisor vê que um PDF é diferente e nada mais.
+ Uma receita muda em uma linha.
+
+
+ Arquivos grandes não cabem. O GitHub recusa um push que contenha um arquivo acima
+ de 100 MB, então um teste de limite de upload de 500 MB não tem o que commitar.
+
+
+
+ O que se commita é a receita. A mesma receita e a mesma semente gravam os mesmos bytes em qualquer
+ máquina, então o arquivo gerado no pipeline é o arquivo que você tinha no notebook.
+
+
+
+
+
A receita
+
Uma receita que mora junto dos testes
+
+ Esta grava vinte e cinco faturas que devem ser aceitas e duas imagens acima de um limite que devem
+ ser recusadas, e o manifesto registra as duas expectativas:
+
+ A linha da soma de verificação compara o arquivo com verify-SHA256SUMS.txt da mesma
+ versão. A versão está fixada, então uma versão nova nunca altera um build que você não mexeu.
+
+ Cada final tem o seu próprio código de saída, então o passo falha sozinho e o log diz qual foi. Os
+ que um pipeline encontra:
+
+
+
3 - a receita não é válida. Nada foi gravado, e cada problema é nomeado
+
4 - o formato não consegue fazer o que foi pedido, por exemplo um tamanho abaixo do seu mínimo
+
6 - não há espaço em disco suficiente
+
7 - tfg verify achou um arquivo que não bate com o manifesto
+
8 - a execução terminou, mas nem tudo foi produzido
+
+
+ Uma execução que falhou não imprime nada na saída padrão, então um analisador de logs nunca toma um
+ erro por dado. A tabela completa está na página de
+ documentação.
+
+
+
+
+
PowerShell
+
Um script PowerShell precisa de mais uma linha
+
+ O PowerShell não leva o código de saída de um programa para fora de um arquivo .ps1.
+ Rode um com -File e o script responde 0 mesmo quando a ferramenta lá
+ dentro recusou o trabalho, então um build que deveria ficar vermelho fica verde. A última linha
+ é a correção inteira:
+
+ É assim que o PowerShell se comporta, não algo desta ferramenta. cmd, bash
+ e zsh não precisam de mais nada.
+
+
+
+
+
Vários jobs
+
Compartilhando as fixtures entre jobs
+
+ Em geral não é preciso enviá-las. Como a mesma receita grava os mesmos bytes, cada job pode rodar o
+ seu próprio tfg generate, que é mais rápido que um upload e um download. Quando um
+ job precisa receber arquivos de outro, rode tfg verify no manifesto depois da
+ transferência, e ele diz se o que chegou é o que foi gravado.
+
+ Cinco tarefas que aparecem em quase todo projeto que aceita arquivos de pessoas, e o comando que faz
+ cada uma. Todo exemplo abaixo roda como está escrito.
+
+
+
+
Limites de upload
+
Testar se um limite de tamanho de arquivo é aplicado onde diz que é
+
+ Um limite são três casos de teste, não um: logo abaixo, exatamente nele e logo acima. Conseguir
+ esses à mão significa calcular contagens de bytes e torcer para não ter errado por um. Peça o
+ conjunto no lugar:
+
+ Você recebe três PDFs reais com 1048575, 1048576 e 1048577 bytes, e um manifesto dizendo que os dois
+ primeiros devem ser aceitos e o terceiro rejeitado por size_limit. Seu teste lê a
+ expectativa em vez de você escrever três asserções à mão - e quando o limite muda, você muda um
+ número e roda de novo.
+
+
+ O mesmo funciona sem preset quando você quer um único conjunto de limites embutido:
+
+ Fixtures binárias grandes deixam um repositório lento de clonar e chato de revisar, e ninguém sabe
+ dizer o que mudou quando uma é substituída. Uma receita são algumas centenas de caracteres de
+ YAML que reconstroem os arquivos idênticos - byte a byte, em qualquer máquina -
+ porque cada arquivo é derivado do seed da execução.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Cada término tem seu próprio código de saída, então um pipeline consegue distinguir uma receita ruim
+ de um disco cheio e de uma divergência de verificação. Uma execução com falha não imprime nada
+ na saída padrão, o que impede um parser de logs de ler um erro como dado.
+
+
+
+
+
Escala
+
Descobrir o que acontece quando a pasta é grande
+
+ Rotinas de importação, jobs noturnos e listagens de diretório se comportam diferente com dez mil
+ arquivos do que com dez. Tamanhos sorteados de um intervalo fazem o conjunto parecer tráfego
+ real em vez de dez mil arquivos idênticos, e o sorteio vem do seed, então o conjunto é o mesmo
+ amanhã.
+
+ Uma execução maior que o espaço livre no disco é recusada antes de o primeiro byte ser escrito, em
+ vez de encher o disco e falhar no meio.
+
+
+
+
+
Arquivos compactados
+
Testar um descompactador com um arquivo compactado que realmente contém arquivos
+
+ Um arquivo compactado vazio com a extensão certa não prova nada sobre o código que o abre e percorre
+ o que há dentro. Declare o conteúdo e o arquivo compactado realmente o contém:
+
+ Profundidade de aninhamento, contagem de entradas e tamanho do que há dentro são coisas sobre as
+ quais uma rotina de importação tem opinião, e é assim que você descobre quais são.
+
+
+
+
+
Parsers e visualizadores
+
Conferir se o seu próprio código lê um formato como o software real
+
+ Todo formato aqui é verificado com um leitor independente antes de ser liberado - um PNG é aberto e
+ seus pixels comparados, um DOCX é relido por bibliotecas separadas, um arquivo compactado é
+ extraído. Isso significa que um arquivo que o seu parser recusa é uma descoberta sobre o seu
+ parser, não sobre o gerador.
+
+ A página de formatos lista as configurações que cada um aceita e o
+ menor arquivo que cada um pode ser.
+
+
+
+
+
Guias
+
Dois deles em detalhe
+
+
+ Arquivos de teste corrompidos - um arquivo
+ quebrado de propósito, com o tamanho exato e com o que deve acontecer com ele escrito no
+ manifesto.
+
+
+ Arquivos de teste no CI - um workflow do GitHub
+ Actions, um job do GitLab e os códigos de saída que fazem um build falhar.
+
+
+
+
+
+
Para quem é
+
+ Engenheiros de QA, automação de testes e qualquer pessoa cujo código tenha atrás um formulário de
+ upload, uma rotina de importação, um parser ou uma cota de armazenamento. Roda em uma máquina
+ sem rede nenhuma, o que importa em um ambiente corporativo fechado onde um gerador baseado em
+ navegador não é opção.
+
+ Todo sistema tem um comando para isso, e os três estão abaixo. Eles dão um arquivo com exatamente o
+ número certo de bytes - e para muito teste isso é tudo de que você precisa. Todo comando
+ desta página foi executado antes de ser publicado, no sistema a que pertence.
+
+
+
+
A resposta curta
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Os tamanhos são em bytes, e 10 MB
+ contados como o seu gerenciador de arquivos conta são 10485760.
+
+
+
+
+
Windows
+
fsutil, e uma versão em PowerShell que não precisa de nada extra
+
+ O fsutil vem com o Windows. Ele recebe o tamanho em bytes, então
+ calcule o número antes - 10 MB são 10485760, 100 MB são 104857600, 1 GB é 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Medido no Windows 11: funciona em um prompt comum, sem precisar de um elevado, e o arquivo sai com
+ exatamente 10485760 bytes.
+
+
O PowerShell faz o mesmo sem chamar outro programa, e entende unidades:
+ 10MB no PowerShell significa 10485760 bytes, a mesma contagem em base 1024 que o
+ Explorer usa, então os dois comandos acima produzem o mesmo tamanho.
+
+
+
+
+
Linux
+
dd, truncate e fallocate, e a diferença que pega as pessoas
+
O dd é o que todo mundo conhece. Ele escreve os bytes de verdade:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ O truncate é instantâneo, e essa é a pegadinha. Medido no Alpine Linux, o arquivo
+ informa 10485760 bytes e ocupa zero blocos - é um arquivo
+ esparso. Qualquer coisa que o leia recebe dez megabytes de zeros, mas o disco nunca
+ cedeu o espaço:
+
+
truncate -s 10M test10mb.bin
+
+ Isso serve para testar um limite de upload e engana para testar uma cota de disco. O
+ fallocate é o que se deve usar quando o espaço precisa ser real:
+
+
fallocate -l 10M test10mb.bin
+
E quando o conteúdo precisa ser incompressível, para que um compactador não consiga comprimi-lo de volta:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, que não é esparso, e os dois que você já conhece
+
+ O macOS traz o mkfile. Medido no macOS 26.6.2: 10485760 bytes e 20480 blocos, então o
+ espaço é realmente alocado em vez de prometido:
+
+
mkfile 10m test10mb.bin
+
dd e truncate também estão lá e se comportam como no Linux:
Um arquivo do tamanho certo não é um arquivo do tipo certo
+
+ Tudo acima dá um bloco de zeros. Isso basta quando o que está sob teste olha só o tamanho - um
+ limite de upload, uma cota, uma transferência. Deixa de bastar no momento em que qualquer coisa
+ abre o arquivo.
+
+
+ Medido, e vale a pena fazer você mesmo: crie um arquivo de 2 MB com fsutil, chame-o de
+ photo.png e entregue a uma biblioteca de imagens. O Pillow responde cannot
+ identify image file. Não é um PNG. Nunca foi - só o nome dizia que era.
+
+
+ Isso importa mais do que parece, por causa de o jeito como o teste então falha. Seu
+ endpoint de upload recusa o arquivo, seu teste fica verde e você conclui que o limite de tamanho
+ funciona. Ele não recusou pelo tamanho. Recusou porque os bytes não eram uma imagem, e a regra
+ que você queria testar nunca foi alcançada.
+
+
+
um parser o recusa antes de qualquer regra de tamanho ser olhada
+
uma etapa de miniatura falha e o erro que você lê é sobre a miniatura
+
um antivírus ou uma verificação de conteúdo o recusa por um terceiro motivo
+
um visualizador não mostra nada, e ninguém sabe dizer se esse é o bug
+
+
+
+
+
O outro caminho
+
Um arquivo real desse formato, exatamente no tamanho que você pediu
+
+ É isso que o Testing Files Generator faz. O arquivo é um genuíno do seu formato - abre no programa a
+ que pertence - e tem o número exato de bytes que você pediu, ao byte:
+
+ Peça um tamanho que um formato não alcança e você recebe um erro que nomeia o piso e o motivo, nunca
+ um arquivo de tamanho errado. A página de formatos lista cada
+ formato com o menor arquivo que ele pode produzir.
+
+
E um limite são três casos de teste em vez de um, então a ferramenta monta os três:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Isso dá 10485759, 10485760 e 10485761 bytes, e um manifesto dizendo quais deles seu sistema deve
+ aceitar e quais deve rejeitar. A página de casos de uso
+ percorre isso e outras quatro tarefas para as quais foi feito.
+
Gratuito e de código aberto, GPL-3.0. Sem cadastro. Os downloads de Windows e macOS são assinados e iniciam sem aviso.
+
+
+
+
Então qual usar?
+
+
+
Use o comando do sistema
+
+ Quando nada abre o arquivo. Testar um limite de tamanho em um endpoint que checa o tamanho primeiro,
+ uma transferência, uma cota, um disco cheio. É uma linha e já está instalado.
+
+
+
+
Use um gerador de verdade
+
+ Quando qualquer coisa interpreta, renderiza, importa ou extrai o arquivo - e quando você precisa das
+ mesmas fixtures amanhã, em outra máquina, byte a byte.
+
+
+
+
+ Os dois estão nesta página porque os dois estão certos parte do tempo. O erro a evitar é usar o
+ primeiro onde o segundo é necessário e ler o teste verde como prova.
+
+ Tudo o que a ferramenta faz, organizado como as perguntas com que as pessoas realmente chegam. O
+ README do repositório é a referência completa e sempre corresponde
+ à versão que você baixou.
+
+
+
+
Quais comandos existem?
+
Cada um faz uma única coisa:
+
tfg generate produzir arquivos, a partir de uma receita ou de opções
+tfg validate verificar uma receita sem escrever nada
+tfg verify verificar um diretório contra um manifesto
+tfg cleanup remover os arquivos que um manifesto lista
+tfg recipe fmt imprimir uma receita na sua forma normalizada
+tfg preset montar um conjunto de arquivos a partir de uma pergunta de teste nomeada
+tfg formats listar os formatos que esta versão suporta
+tfg damage listar as formas como esta versão pode quebrar um arquivo de propósito
+tfg tool pequenas utilidades para arquivos que você já tem
+tfg version imprimir a versão da ferramenta
+tfg license imprimir a licença e o que ela significa para os arquivos gerados
+
+
+
+
Como gero um único arquivo de tamanho exato?
+
+ Informe o formato, o tamanho e o destino. Os tamanhos contam de 1024 em 1024, então 2mb
+ são 2097152 bytes. Uma contagem simples de bytes também funciona, então --size
+ 10485761 pede exatamente essa quantidade.
+
+
tfg generate --format png --size 2mb --out ./out
+
As opções úteis de generate:
+
+
+
Opção
O que faz
+
+
--format <id>
formato dos arquivos, por exemplo txt
+
--size <size>
tamanho exato de cada arquivo, como 10mb ou uma contagem simples de bytes
+
--size-range <a-b>
um tamanho sorteado por arquivo dentro de um intervalo, como 1kb-8kb. O sorteio vem do seed
+
--boundary <size>
três arquivos ao redor de um limite: um byte abaixo, o limite, um byte acima
+
--count <n>
quantos arquivos produzir. Padrão 1
+
--name <template>
modelo de nome, por exemplo invoice_{index:04}.txt
+
--out <dir>
diretório onde escrever
+
--seed <n>
seed da execução. O mesmo seed dá os mesmos bytes
+
--set <k>=<v>
uma configuração de formato, repetível
+
--damage <name>
quebrar os arquivos de propósito, repetível e aplicado em ordem. Rode tfg damage para ver a lista
+
--expected <outcome>
accept, reject, sanitize ou unspecified
+
--dry-run
contar e mostrar, sem escrever absolutamente nada
+
--json
escrever o manifesto na saída padrão
+
+
+
+
+
+
+
Como faço um arquivo quebrado de propósito?
+
+ Todo outro arquivo que esta ferramenta escreve é correto por construção, o que responde a duas das
+ três perguntas que um validador de upload faz. --damage responde à terceira - se o
+ arquivo abre, afinal. O arquivo é produzido normalmente e depois quebrado, então continua com o
+ tamanho que você pediu.
+
+ As configurações vão depois de dois-pontos. A opção se repete, e a ordem em que você as escreve é a
+ ordem em que são aplicadas. tfg damage lista o que esta versão pode fazer e o que
+ cada uma aceita.
+
+
Em uma receita a chave é uma lista, de nomes ou de configurações:
+ Um arquivo danificado recebe expected: reject no manifesto, com o dano registrado ao
+ lado. Duas coisas são recusadas antes de escrever qualquer coisa, porque cada uma deixaria no
+ disco um arquivo que o manifesto descreve errado:
+
+
+
um arquivo menor do que o dano precisa, porque sairia sem alteração
+
+ expected: accept ao lado de um dano, porque nada poderia cumpri-lo. Escreva
+ sanitize se o sistema sob teste deve reparar o arquivo, ou
+ unspecified se essa é a pergunta que você está fazendo
+
+
+
+ Uma terceira não pode ser conhecida de antemão. Se um dano roda e não move nenhum byte, esse arquivo
+ é descartado em vez de escrito - a execução continua, diz qual arquivo foi e termina com o
+ código de saída parcial.
+
+ Uma receita é um arquivo YAML que descreve uma execução inteira. Versione-a ao lado dos seus testes
+ e as fixtures deixam de ser binários no seu repositório - qualquer pessoa pode reconstruí-las,
+ byte a byte, a partir de um arquivo de algumas centenas de caracteres.
+
+ Cada target precisa de exatamente uma destas chaves: size, size-range,
+ boundary ou contains. Duas é um erro e nenhuma também. Uma receita
+ inválida escreve nenhum arquivo e relata todos os problemas de uma vez em vez
+ de só o primeiro, cada um nomeando a configuração a que se refere.
+
+
+
+
+
Como declaro o que meu sistema deve fazer com um arquivo?
+
Forma curta quando o resultado basta, forma longa quando o motivo importa:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Os resultados são accept, reject, sanitize e
+ unspecified. Os motivos são uma lista fechada para que um relatório possa agrupar
+ por eles: content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit e size_zero.
+
+
+ Um motivo nomeia a regra em jogo, não o veredito. Por isso o mesmo motivo pode
+ ficar sob qualquer um dos resultados - um arquivo um byte abaixo de um limite é
+ accept, e a regra de que se trata continua sendo size_limit.
+
+
+
+
+
O que há no manifesto?
+
+ Ele é escrito ao lado dos arquivos no fim de cada execução, inclusive de uma execução interrompida.
+ Uma entrada por arquivo:
+
+ Um recipe_hash é adicionado quando a execução veio de uma receita, e
+ preset com overrides quando veio de um preset, de modo que um
+ manifesto sempre pode ser rastreado até o que o produziu.
+
+
+ Cada entrada também traz target_id, o id do target da receita que produziu o arquivo, e
+ summary.by_target conta os arquivos a que cada target chegou. Uma receita com
+ vários targets pode assim ser verificada target por target sem ler nomes de arquivo.
+
+
+
+
+
O que é um preset?
+
+ Um conjunto de arquivos pronto que responde a uma pergunta de teste comum, para que você não precise
+ desenhar o conjunto. Presets são receitas comuns por baixo, e eject imprime a
+ receita para você editá-la a partir dali. Cada preset tem uma página
+ própria com o que costuma encontrar, o que há no conjunto e cada configuração que aceita.
+
+ show diz quanto o conjunto custaria antes de você montá-lo, e diz abertamente quando um
+ número é um valor provisório nosso, e não um limite seu.
+
+
+
+
+
O que significam os códigos de saída?
+
+ Cada término tem seu próprio código, a saída legível por máquina vai para a saída padrão, e uma
+ execução com falha não imprime nada lá. A tabela é um contrato congelado - mudar o que um código
+ significa exige uma versão maior.
+
+
+
+
+
+
Código
+
Significado
+
+
+
+
+
0
+
Tudo funcionou.
+
+
+
1
+
Um erro inesperado dentro da ferramenta.
+
+
+
2
+
Comando ou opção incorretos.
+
+
+
3
+
A receita não é válida.
+
+
+
4
+
O formato não consegue fazer o que foi pedido.
+
+
+
5
+
Uma leitura ou escrita falhou.
+
+
+
6
+
Espaço em disco insuficiente.
+
+
+
7
+
verify encontrou uma divergência.
+
+
+
8
+
A execução terminou, mas nem tudo foi produzido.
+
+
+
130
+
Interrompido com Ctrl+C.
+
+
+
143
+
Encerrado por um sinal, que é a cara de um timeout de CI.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Uma execução parada com Ctrl+C ainda deixa um manifesto e nunca deixa um arquivo pela metade, então
+ um job cancelado ainda pode ser limpo pelo seguinte.
+
+ Sim, o mesmo motor com uma janela por cima, para o teste que não é automatizado. Não é uma versão
+ reduzida: um teste compara as duas interfaces capacidade por capacidade, e tudo que só uma delas
+ pode fazer precisa ser declarado e justificado em vez de divergir em silêncio.
+
+
+ As telas são um lote, presets, vários lotes de uma vez e Sobre. Ela mostra quanto uma execução
+ custaria antes de escrever qualquer coisa, informa o progresso enquanto roda e pode ser
+ cancelada no meio sem deixar um arquivo pela metade. Ainda não abre um arquivo de receita - por
+ enquanto receitas são coisa de linha de comando, e a janela monta seus lotes no formulário.
+
26 formatos de arquivo, cada um gerado em um tamanho exato
+
+ Cada um é um arquivo real daquele formato. Abre no programa a que pertence e tem
+ exatamente o número de bytes que você pediu. Nenhum é preenchimento de zeros com uma extensão
+ colada.
+
+
+
+
+
+
+
Formato
+
Nome
+
Extensão
+
Menor arquivo
+
Fidelidade
+
Verificado com
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
não se aplica
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
não se aplica
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
não se aplica
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
O que as colunas significam
+
+
+
Menor arquivo
+
+ O menor número de bytes que esta ferramenta aceita para aquele formato, incluindo o rótulo que ela
+ escreve dentro do arquivo. Peça menos e você recebe um erro que nomeia o piso e o motivo,
+ nunca um arquivo de tamanho errado.
+
+
+
+
Fidelidade
+
+ Quão completo é o arquivo. full significa que um leitor que realmente interpreta o
+ formato o aceita, e não apenas que a extensão combina.
+
+
+
+
Verificado com
+
+ O leitor independente que abre todo arquivo gerado antes de o formato ser liberado - uma
+ implementação separada, não o nosso próprio código corrigindo o próprio dever de casa.
+
+
+
+
+ Todo formato também se repete ao byte: a mesma receita e o mesmo seed produzem arquivos idênticos em
+ qualquer máquina, o que torna seguro versionar uma receita no lugar das próprias fixtures.
+
+
+
+
+
Configurações que cada formato aceita
+
+ A maioria dos formatos tem configurações próprias - dimensões de imagem, qualidade JPEG, número de
+ páginas do PDF, linhas e colunas de uma planilha, quantas entradas vão dentro de um arquivo
+ compactado. Defina-as com --set key=value na linha de comando, ou em
+ properties: numa receita.
+
uma data como 2024-02-29 ou 2024-02-29T13:45:00+02:00, ou none
+
+
+
+
modified
+
uma data como 2024-02-29 ou 2024-02-29T13:45:00+02:00, ou none
+
+
+
png
+
width
+
1 - 20000 pixels
+
+
+
+
height
+
1 - 20000 pixels
+
+
+
pptx
+
slides
+
1 - 500 slides
+
+
+
svg
+
width
+
1 - 20000 pixels
+
+
+
+
height
+
1 - 20000 pixels
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
o id de um formato, como o tfg formats lista
+
+
+
+
entry_size
+
um tamanho como 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
verdadeiro ou falso
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 pixels
+
+
+
+
height
+
1 - 20000 pixels
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
verdadeiro ou falso
+
+
+
wav
+
sample_rate
+
8000 - 192000 hertz
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 pixels
+
+
+
+
height
+
1 - 16383 pixels
+
+
+
xlsx
+
rows
+
1 - 200000 linhas
+
+
+
+
columns
+
1 - 32768 colunas
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
verdadeiro ou falso
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
o id de um formato, como o tfg formats lista
+
+
+
+
entry_size
+
um tamanho como 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
verdadeiro ou falso
+
+
+
+
password
+
a senha, em texto simples
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ Um valor fora do que uma configuração aceita é recusado com uma mensagem que nomeia a configuração,
+ o intervalo permitido e o que usar no lugar. Uma configuração desconhecida também é um erro,
+ nunca um padrão silencioso - um erro de digitação aceito em silêncio dá um arquivo com as
+ configurações erradas e uma hora se perguntando por que o teste passa quando não deveria.
+
+
+ Rode tfg formats <id> para ver exatamente o que um formato aceita na versão que
+ você tem.
+
+
+
+
+
Arquivos compactados contêm arquivos reais
+
+ targz e zip
+ podem ser preenchidos com entradas em vez de ficarem como uma casca vazia. Um arquivo compactado
+ gerado realmente contém os documentos que diz conter, então qualquer coisa que o descompacte
+ durante um teste encontra arquivos reais dentro.
+
+ PDF, PNG, DOCX, ZIP - 26 formatos no total, e cada um é um
+ arquivo real que abre no programa a que pertence, com exatamente o tamanho que você
+ pediu. Cada execução também registra o que sua aplicação deve fazer com cada arquivo.
+ Linha de comando e janela de desktop, gratuito e de código aberto, funcionando inteiramente na
+ sua máquina.
+
Gratuito e de código aberto, GPL-3.0. Sem cadastro. Os downloads de Windows e macOS são assinados e iniciam sem aviso.
+
+
+
+
+ A janela de desktop, pronta para escrever um lote de arquivos. O mesmo motor roda por trás da linha de comando.
+
+
+
+
+
+ 26
+
formatos reais, cada um abre no programa a que pertence
+
+
+ 1 byte
+
a precisão de cada tamanho que você pede, nunca arredondado em silêncio
+
+
+ 0
+
conexões para lugar nenhum - sem conta, sem telemetria, sem verificação de atualizações
+
+
+
+
+
O problema
+
Fazer um arquivo de teste é fácil. Fazer os mil certos é a parte tediosa
+
Você está testando um software que aceita arquivos de pessoas. Mais cedo ou mais tarde, você precisa de:
+
+
um PDF de exatamente 10 MB, para descobrir se o limite de upload é real
+
os três arquivos dos dois lados desse limite, para pegar erros de um a mais ou a menos
+
10.000 arquivos de log, para ver o que o job noturno faz quando a pasta é grande
+
um ZIP que realmente contém 200 documentos, não uma casca com a extensão certa
+
um arquivo de 4 GB, sem guardar um arquivo de 4 GB no seu repositório
+
as mesmas fixtures no seu notebook e no servidor de build, byte a byte
+
+
+ É isso que isto substitui. Foi feito para engenheiros de QA, automação de testes e qualquer pessoa
+ cujo código tenha atrás um formulário de upload, uma rotina de importação, um parser ou uma cota
+ de armazenamento.
+
+
+
+
+
O que o torna diferente
+
Outros geradores param nos bytes. Este responde ao que o seu teste realmente pergunta
+
+ Uma pasta de arquivos ainda deixa você decidindo o que cada um deve provar. Cada execução aqui
+ escreve um manifest.json ao lado dos arquivos - uma lista simples de tudo que foi
+ produzido e, para cada entrada, uma expectativa declarada.
+
+
Digamos que seu endpoint de upload permita 1 MB. Peça os três arquivos que ficam nessa linha:
Onde a resposta depende da sua própria política, o manifesto diz isso
+
+ Ele registra unspecified em vez de inventar uma expectativa. Um gerador que adivinha
+ produz falhas falsas, e uma suíte que dá alarme falso acaba desligada.
+
+
+
+
+
+
Presets
+
Escolha a pergunta, receba o conjunto inteiro
+
+ Um preset é um conjunto de arquivos de teste desenhado em torno de uma pergunta de teste, para que
+ você não precise descobrir quais arquivos provam o quê. Cada um tem uma página dizendo o que
+ costuma encontrar, o que há no conjunto e cada configuração que aceita.
+
+ Dez mil arquivos de log, cada um entre um e oito kilobytes, com os tamanhos sorteados a partir do
+ seed para que amanhã dê o mesmo conjunto. Dê a cada execução o seu próprio
+ diretório - o manifesto é o único registro do que uma execução escreveu, então a
+ ferramenta se recusa a escrever um segundo por cima:
+
+ Os tamanhos contam de 1024 em 1024, como o seu gerenciador de arquivos faz, então 2mb
+ significa 2097152 bytes. Uma contagem simples de bytes também funciona. A
+ documentação cobre receitas, o manifesto e os códigos de
+ saída.
+
+
+
+
+
O que você recebe
+
Feito para uma suíte que roda sem supervisão
+
+
+
Tamanho exato, ao byte
+
Peça 10485761 bytes e receba exatamente isso. Um tamanho que um formato não alcança é um erro com um motivo, nunca um arquivo de tamanho errado.
+
+
+
26 formatos reais
+
Não são zeros de preenchimento com uma extensão. Um PNG gerado abre em um visualizador de imagens, um DOCX abre no Word, um ZIP extrai. Cada um é verificado com leitores independentes antes de ser liberado.
+
+
+
Um manifesto que é um oráculo de teste
+
Caminho, tamanho, SHA-256, formato, seed, versão da ferramenta - e o que seu sistema deve fazer com o arquivo.
+
+
+
Reproduzível
+
Mesma receita e mesmo seed, mesmos bytes, em qualquer máquina. Versione uma pequena receita YAML em vez de fixtures binárias grandes.
+
+
+
Duas interfaces, um motor
+
Uma linha de comando feita para CI e uma janela de desktop para testes exploratórios. Nenhuma é uma versão reduzida da outra, e um teste compara as duas capacidade por capacidade.
+
+
+
Totalmente offline
+
Sem conta, sem nuvem, sem telemetria, sem verificação de atualizações. O binário da linha de comando não tem nenhuma pilha de rede compilada nele.
+
+
+
+
+
+
Download
+
Escolha a versão para o seu sistema
+
+ Descompacte o arquivo e execute. tfg é a linha de comando e tfg-gui é a
+ janela de desktop. Não há instalador e nada para adicionar à sua máquina.
+
+
+
+
+
+
Sistema
+
Linha de comando
+
Janela de desktop
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
O que é assinado e o que não é
+
+ Os downloads de Windows e macOS são assinados, então iniciam sem aviso de desenvolvedor
+ desconhecido. Os de Linux não são, porque o Linux de desktop não tem equivalente para
+ assiná-los. Cada arquivo está listado em verify-SHA256SUMS.txt na página de
+ releases, para que você possa conferir o que baixou.
+
+ Licença, privacidade, reprodutibilidade e o que as pessoas conferem antes de colocar um gerador em
+ um pipeline de build. Se a sua pergunta não está aqui, o rastreador
+ de issues está aberto.
+
+
+
+
+
Como isso é diferente de dd, fsutil ou truncate?
+
+
Esses comandos dão um arquivo do tamanho certo cheio de nada. Um arquivo de 2 MB chamado photo.png feito assim não é um PNG, então qualquer coisa que realmente o interprete o recusa pelo motivo errado, e o seu teste também passa pelo motivo errado. Isto produz um PNG real de exatamente 2 MB que abre em um visualizador de imagens e vem com uma declaração de como o seu sistema deve tratá-lo.
Sim para os dois. É distribuído sob a GPL-3.0 e não custa nada. Não há conta, chave de licença nem plano pago.
+
+
+
+
Posso usar os arquivos gerados em um produto de código fechado?
+
+
Sim. A licença cobre o código da ferramenta, não o que ela produz. Arquivos, receitas e manifestos gerados são saída e não obras derivadas, então você pode versioná-los e distribuí-los sem nenhuma obrigação.
+
+
+
+
Os arquivos gerados contêm dados pessoais reais?
+
+
Não. Tudo dentro deles é sintetizado a partir de um seed. Nenhum conjunto de dados é lido, nenhum serviço é contatado e nenhum conteúdo de terceiros é embutido. Trate um endereço de e-mail gerado como inutilizável em vez de não usado, porque qualquer texto aleatório pode coincidir por acaso com um real.
+
+
+
+
Vou obter exatamente os mesmos arquivos em outra máquina?
+
+
Sim, byte a byte, com a mesma receita e o mesmo seed. O projeto testa isso a cada mudança, e quebrá-lo exige uma versão maior. É isso que permite versionar uma receita pequena em vez de fixtures binárias grandes.
+
+
+
+
Precisa de conexão com a internet?
+
+
Nunca. Não há telemetria, verificação de atualizações nem cliente de nuvem, e o binário da linha de comando não tem pilha de rede compilada nele. Funciona em uma máquina sem rede e dentro de um ambiente corporativo fechado.
+
+
+
+
O que acontece se eu pedir um tamanho que um formato não consegue alcançar?
+
+
Você recebe um erro que nomeia o formato, o menor tamanho possível, o motivo desse piso e o que fazer em vez disso, e nenhum arquivo é escrito. A ferramenta nunca arredonda um tamanho em silêncio. Cada piso está listado na página de formatos.
+
tfg formats png
+
+
+
+
Posso gerar um arquivo deliberadamente quebrado?
+
+
Sim. Adicione --damage zero-head e o arquivo sai com exatamente o tamanho pedido, com os primeiros bytes sobrescritos por zeros, de modo que um leitor o recusa, e o manifesto diz que o seu sistema deve rejeitá-lo. A página sobre arquivos de teste corrompidos traz os detalhes.
7z, mp3 e mp4. Hoje 26 formatos funcionam de ponta a ponta.
+
+
+
+
Em quais sistemas posso rodar?
+
+
A linha de comando roda em Windows e Linux, tanto em Intel quanto em ARM, e em Macs com Apple Silicon. A janela de desktop é distribuída para Windows em Intel, Linux em Intel e Macs com Apple Silicon. Macs Intel não são suportados e nada é compilado para eles.
+
+
+
+
Preciso instalar alguma coisa?
+
+
Não. Baixe o arquivo do seu sistema, descompacte e execute o binário. Não há instalador, runtime para adicionar nem dependência para resolver. Se você tem Go, um único comando go install também funciona.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
Por que uma execução sobre milhares de arquivos é mais lenta no Windows?
+
+
Porque o Windows cobra mais por cada caminho que examina, e um comando que percorre milhares de arquivos examina milhares de caminhos. Medido em uma máquina com 3000 arquivos de 1 kB, o verify leva cerca de 0,9 segundo no Windows e cerca de 0,2 segundo no Linux em um contêiner. Um caminho de saída mais curto reduz o valor do Windows, porque cada pasta acima dos arquivos faz parte do que é examinado.
Um arquivo válido e tão pequeno quanto o formato permite passa?
+
+ O preset empty-and-minimal monta com um único comando um conjunto inteiro de arquivos de teste
+ reais para esta pergunta, e um manifest.json ao lado dizendo como seu sistema deve
+ reagir a cada arquivo. Tudo abaixo é lido do programa, com os valores padrão desta versão.
+
+
+
+
+
O que ele costuma encontrar?
+
+
um arquivo válido recusado por ser pequeno demais, porque a verificação conta bytes em vez de lê-los
+
um arquivo vazio que derruba o leitor em vez de ser reportado
+
uma imagem de um pixel de largura que divide por zero a caminho da miniatura
+
um armazenamento que lê zero byte como upload com falha e fica tentando de novo
+
+
+
+
+
+
O que há no conjunto?
+
Com os valores padrão, como o tfg preset show empty-and-minimal informa:
Meu sistema vai guardar, mostrar e devolver um nome de arquivo que ele não esperava?
+
+ O preset filename-handling monta com um único comando um conjunto inteiro de arquivos de teste
+ reais para esta pergunta, e um manifest.json ao lado dizendo como seu sistema deve
+ reagir a cada arquivo. Tudo abaixo é lido do programa, com os valores padrão desta versão.
+
+
+
+
+
O que ele costuma encontrar?
+
+
um nome que parece outro na tela, em um log ou em uma lista
+
um nome cortado, aparado ou reescrito entre o upload e o armazenamento
+
um limite de tamanho contado em caracteres onde o armazenamento conta bytes
+
+
+
+
+
+
O que há no conjunto?
+
Com os valores padrão, como o tfg preset show filename-handling informa:
+
+
+
+
Arquivos
50
+
Targets na sua receita
50
+
Tamanho total
51 200 B
+
Formatos
txt
+
+
+
+
E o que o manifesto desse conjunto espera do seu sistema:
+
+
+
+
Esperado
Significado
Arquivos
+
+
+
accept
Seu sistema deve aceitar o arquivo.
4
+
unspecified
Depende das regras do seu sistema. Você decide e depois confere se o que acontece é o que você queria.
46
+
+
+
+
+
+
+
O que você pode mudar?
+
+
+
+
Configuração
Aceita
Padrão
O que faz
+
+
+
+
--format
+
um id de formato da página de formatos
+
txt
+
O formato de cada arquivo do conjunto. É uma opção da própria ferramenta, e o preset apenas dá a ela um valor padrão.
+
+
+
+
+
+
+
+
Como executar?
+
Veja quanto o conjunto custaria, monte-o ou pegue a receita dele para editar:
Presets de arquivos de teste, um conjunto para cada pergunta de teste
+
+ Um preset é um conjunto inteiro de arquivos de teste desenhado em torno de uma pergunta, com um
+ manifesto dizendo como seu sistema deve reagir a cada arquivo. Você escolhe a pergunta, a
+ ferramenta monta o conjunto. Cada preset tem sua própria página com o que costuma encontrar, o que
+ há no conjunto e cada configuração que aceita.
+
Meu formulário de upload aceita o que deve e recusa o resto?
+
upload-validation
+
+
+
+
+
Como um preset é diferente de uma receita?
+
+ Por baixo, não é. Um preset é uma receita que a ferramenta escreve para você a partir de algumas
+ configurações. tfg preset eject imprime essa receita para você guardá-la ao lado
+ dos seus testes e editá-la, e uma receita sua pode se basear em um preset com uma linha,
+ extends: preset: seguido do id dele.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Posso confiar nos valores padrão?
+
+ Para os arquivos, sim. Para um número que só o seu sistema conhece, como o limite de um formulário
+ de upload, um valor padrão é um provisório nosso, e a ferramenta diz isso toda vez que usa um. A
+ página de cada preset marca essas configurações, e tfg preset show diz isso antes
+ de qualquer coisa ser escrita.
+
Um limite de tamanho é aplicado exatamente onde foi declarado?
+
+ O preset size-boundaries monta com um único comando um conjunto inteiro de arquivos de teste
+ reais para esta pergunta, e um manifest.json ao lado dizendo como seu sistema deve
+ reagir a cada arquivo. Tudo abaixo é lido do programa, com os valores padrão desta versão.
+
+
+
+
+
O que ele costuma encontrar?
+
+
erros de um a mais ou a menos no limite
+
MB confundido com MiB, que dá 4,8 por cento e basta para deixar passar um arquivo que não deveria passar
+
um limite aplicado no navegador e não no servidor
+
+
+
+
+
+
O que há no conjunto?
+
Com os valores padrão, como o tfg preset show size-boundaries informa:
+
+
+
+
Arquivos
7
+
Targets na sua receita
7
+
Tamanho total
73 400 320 B
+
Formatos
pdf
+
+
+
+
E o que o manifesto desse conjunto espera do seu sistema:
+
+
+
+
Esperado
Significado
Arquivos
+
+
+
accept
Seu sistema deve aceitar o arquivo.
4
+
reject
Seu sistema deve recusar o arquivo.
3
+
+
+
+
+
+
+
O que você pode mudar?
+
+
+
+
Configuração
Aceita
Padrão
O que faz
+
+
+
+
--limit
+
um tamanho como 2mb
+
10mb
+
O limite de tamanho que seu sistema declara. Todo o resto é medido a partir dele. Este valor padrão é o nosso provisório, não o valor do seu sistema. Passe o seu.
+
+
+
--spread
+
tamanhos separados por vírgulas
+
1B,1kb,1mb
+
Até onde ir de cada lado do limite, como uma lista de tamanhos.
+
+
+
--format
+
um id de formato da página de formatos
+
pdf
+
O formato de cada arquivo do conjunto. É uma opção da própria ferramenta, e o preset apenas dá a ela um valor padrão.
+
+
+
+
+
+
+
+
Como executar?
+
Veja quanto o conjunto custaria, monte-o ou pegue a receita dele para editar:
A minha importação de tabelas sobrevive ao que ferramentas reais exportam?
+
+ O preset tabular-import monta com um único comando um conjunto inteiro de arquivos de teste
+ reais para esta pergunta, e um manifest.json ao lado dizendo como seu sistema deve
+ reagir a cada arquivo. Tudo abaixo é lido do programa, com os valores padrão desta versão.
+
+
+
+
+
O que ele costuma encontrar?
+
+
um arquivo com ponto e vírgula lido como uma coluna só, porque o delimitador foi presumido em vez de procurado
+
um arquivo CRLF dividido em linhas com uma linha vazia depois de cada uma
+
uma tabela sem cabeçalho cuja primeira linha de dados é engolida como nomes de coluna
+
uma importação que mantém as colunas que consegue mostrar e descarta o resto sem dizer nada
+
um leitor que lê registros JSON uma linha por vez e para no primeiro documento indentado
+
+
+
+
+
+
O que há no conjunto?
+
Com os valores padrão, como o tfg preset show tabular-import informa:
+
+
+
+
Arquivos
13
+
Targets na sua receita
13
+
Tamanho total
3 080 060 B
+
Formatos
csv, json, xlsx
+
+
+
+
E o que o manifesto desse conjunto espera do seu sistema:
+
+
+
+
Esperado
Significado
Arquivos
+
+
+
accept
Seu sistema deve aceitar o arquivo.
8
+
unspecified
Depende das regras do seu sistema. Você decide e depois confere se o que acontece é o que você queria.
5
+
+
+
+
+
+
+
O que você pode mudar?
+
+
+
+
Configuração
Aceita
Padrão
O que faz
+
+
+
+
--rows
+
1 - 200000 linhas
+
1000
+
Quantas linhas a planilha tem. Ela é escrita exatamente no tamanho que essas linhas ocupam, então o orçamento acima muda com este valor.
+
+
+
--columns
+
1 - 32768 colunas
+
10
+
Quantas colunas cada linha da planilha tem. Linhas vezes colunas tem um teto, e pedir além disso é recusado antes de escrever qualquer coisa.
+
+
+
+
+
+
+
+
Como executar?
+
Veja quanto o conjunto custaria, monte-o ou pegue a receita dele para editar:
Meu leitor sabe em que codificação um arquivo está, ou está adivinhando?
+
+ O preset text-encoding monta com um único comando um conjunto inteiro de arquivos de teste
+ reais para esta pergunta, e um manifest.json ao lado dizendo como seu sistema deve
+ reagir a cada arquivo. Tudo abaixo é lido do programa, com os valores padrão desta versão.
+
+
+
+
+
O que ele costuma encontrar?
+
+
um leitor que presume UTF-8 e mostra um arquivo UTF-16 com um caractere a cada três, ou como fileiras de quadradinhos
+
uma marca de ordem de bytes lida como conteúdo, de modo que o primeiro campo de uma importação começa com três caracteres estranhos
+
um importador que adivinha a codificação pelos primeiros bytes e adivinha diferente num arquivo mais longo
+
um arquivo CRLF dividido em linhas com uma linha vazia depois de cada uma, ou um retorno de carro que sobra dentro do último campo
+
+
+
+
+
+
O que há no conjunto?
+
Com os valores padrão, como o tfg preset show text-encoding informa:
+
+
+
+
Arquivos
20
+
Targets na sua receita
20
+
Tamanho total
81 920 B
+
Formatos
csv, log, md, txt, xml
+
+
+
+
E o que o manifesto desse conjunto espera do seu sistema:
+
+
+
+
Esperado
Significado
Arquivos
+
+
+
accept
Seu sistema deve aceitar o arquivo.
10
+
unspecified
Depende das regras do seu sistema. Você decide e depois confere se o que acontece é o que você queria.
10
+
+
+
+
+
+
+
O que você pode mudar?
+
+
+
+
Configuração
Aceita
Padrão
O que faz
+
+
+
+
--sample
+
um tamanho como 2mb
+
4kb
+
O tamanho de cada arquivo do conjunto. UTF-16 guarda dois bytes por caractere, então um número ímpar é recusado.
+
+
+
+
+
+
+
+
Como executar?
+
Veja quanto o conjunto custaria, monte-o ou pegue a receita dele para editar:
Meu formulário de upload aceita o que deve e recusa o resto?
+
+ O preset upload-validation monta com um único comando um conjunto inteiro de arquivos de teste
+ reais para esta pergunta, e um manifest.json ao lado dizendo como seu sistema deve
+ reagir a cada arquivo. Tudo abaixo é lido do programa, com os valores padrão desta versão.
+
+
+
+
+
O que ele costuma encontrar?
+
+
um limite aplicado no navegador e não no servidor
+
um SVG ou HTML tomado por imagem ou por texto simples, que é um jeito de passar um script por um formulário
+
um arquivo verificado pela extensão e nunca aberto, de modo que um PDF chamado .jpg passa
+
um formulário que lê o corpo inteiro na memória antes de olhar o tamanho
+
um upload chamado PHOTO.JPG recusado onde photo.jpg é aceito, ou o contrário
+
um nome com espaços, parênteses ou caracteres fora do ASCII gravado em disco sem alteração
+
+
+
+
+
+
O que há no conjunto?
+
Com os valores padrão, como o tfg preset show upload-validation informa:
+
+
+
+
Arquivos
71
+
Targets na sua receita
22
+
Tamanho total
120 639 488 B
+
Formatos
html, jpg, pdf, png, svg, txt
+
+
+
+
E o que o manifesto desse conjunto espera do seu sistema:
+
+
+
+
Esperado
Significado
Arquivos
+
+
+
accept
Seu sistema deve aceitar o arquivo.
56
+
reject
Seu sistema deve recusar o arquivo.
10
+
unspecified
Depende das regras do seu sistema. Você decide e depois confere se o que acontece é o que você queria.
5
+
+
+
+
+
+
+
O que você pode mudar?
+
+
+
+
Configuração
Aceita
Padrão
O que faz
+
+
+
+
--limit
+
um tamanho como 2mb
+
10mb
+
O limite de tamanho que seu formulário de upload declara. Este conjunto dá um passo para cada lado - para um arquivo em cada distância, rode o preset size-boundaries. Este valor padrão é o nosso provisório, não o valor do seu sistema. Passe o seu.
+
+
+
--allow
+
ids de formato separados por vírgulas
+
jpg,png,pdf
+
Quais tipos seu formulário deve aceitar. Cada um vira um arquivo real desse tipo, e eles são o controle positivo do conjunto todo.
+
+
+
--deny
+
extensões separadas por vírgulas
+
svg,html,exe,sh
+
Quais extensões seu formulário deve recusar. Uma extensão para a qual esta versão não tem formato ainda recebe um arquivo com esse nome, com texto simples.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
O quanto acima do limite vai o único arquivo grande. Desligue onde escrever várias vezes o limite não vale o disco.
+
+
+
--bulk
+
0 - 10000 arquivos
+
50
+
Quantos arquivos o upload em massa contém. Zero deixa esse grupo totalmente fora do conjunto.
+
+
+
+
+
+
+
+
Como executar?
+
Veja quanto o conjunto custaria, monte-o ou pegue a receita dele para editar:
+ Cinci sarcini care apar în aproape orice proiect care primește fișiere de la oameni și comanda care
+ face fiecare. Fiecare exemplu de mai jos rulează așa cum e scris.
+
+
+
+
Limite de încărcare
+
Testarea dacă o limită de dimensiune a fișierelor este aplicată acolo unde spune că este
+
+ O limită înseamnă trei cazuri de test, nu unul: puțin sub, exact pe ea și puțin peste. Să le faci de
+ mână înseamnă să calculezi numere de octeți și să speri că n-ai greșit cu unu. Cere în schimb
+ setul:
+
+ Primești trei PDF-uri reale de 1048575, 1048576 și 1048577 de octeți și un manifest care spune că
+ primele două trebuie acceptate, iar al treilea respins pentru size_limit. Testul
+ tău citește așteptarea în loc să scrii tu trei asertări de mână - iar când limita se schimbă,
+ schimbi un număr și rulezi din nou.
+
+
+ La fel merge fără presetare când vrei un singur set de limite inline:
+
Ținerea fixture-urilor în afara repository-ului fără a le pierde
+
+ Fixture-urile binare mari fac un repository lent la clonare și incomod la revizuire, și nimeni nu
+ poate spune ce s-a schimbat când una e înlocuită. O rețetă este câteva sute de caractere de YAML
+ care reconstruiesc fișierele identice - octet cu octet, pe orice mașină -
+ pentru că fiecare fișier derivă din seed-ul rulării.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Fiecare final are propriul cod de ieșire, așa că un pipeline poate deosebi o rețetă proastă de un
+ disc plin și de o nepotrivire la verificare. O rulare eșuată nu tipărește nimic la ieșirea
+ standard, ceea ce împiedică un parser de jurnale să citească o eroare drept date.
+
+
+
+
+
Scară
+
Aflarea a ce se întâmplă când folderul e mare
+
+ Rutinele de import, joburile de noapte și listările de directoare se comportă altfel la zece mii de
+ fișiere decât la zece. Dimensiunile extrase dintr-un interval fac setul să semene cu trafic
+ real, nu cu zece mii de fișiere identice, iar extragerea vine din seed, deci setul e același
+ mâine.
+
+ O rulare mai mare decât spațiul liber de pe disc este refuzată înainte de a se scrie primul octet,
+ în loc să umple discul și să eșueze pe la jumătate.
+
+
+
+
+
Arhive
+
Testarea unui dezarhivator cu o arhivă care conține cu adevărat fișiere
+
+ O arhivă goală cu extensia potrivită nu dovedește nimic despre codul care o deschide și parcurge ce
+ e înăuntru. Declară conținutul și arhiva îl conține cu adevărat:
+
+ Adâncimea de imbricare, numărul de intrări și dimensiunea a ce e înăuntru sunt toate lucruri despre
+ care o rutină de import are păreri, iar așa afli care sunt acele păreri.
+
+
+
+
+
Parsere și vizualizatoare
+
Verificarea că propriul tău cod citește un format cum o face software-ul real
+
+ Fiecare format de aici este verificat cu un cititor independent înainte de livrare - un PNG este
+ deschis și pixelii lui comparați, un DOCX este recitit de biblioteci separate, o arhivă este
+ extrasă. Asta înseamnă că un fișier pe care parserul tău îl respinge este o constatare despre
+ parserul tău, nu despre generator.
+
+ Pagina de formate listează setările pe care le acceptă fiecare format și
+ cel mai mic fișier posibil pentru fiecare.
+
+
+
+
+
Ghiduri
+
Două dintre ele mai în detaliu
+
+
+ Fișiere de test corupte - un fișier stricat intenționat,
+ de mărime exactă, cu ce trebuie să se întâmple cu el scris în manifest.
+
+
+ Fișiere de test în CI - un workflow GitHub Actions, un job
+ GitLab și codurile de ieșire care fac un build să eșueze.
+
+
+
+
+
+
Pentru cine este
+
+ Ingineri QA, automatizarea testelor și oricine are în spatele codului un formular de încărcare, o
+ rutină de import, un parser sau o cotă de stocare. Rulează pe o mașină fără nicio rețea, ceea ce
+ contează într-un mediu corporativ închis unde un generator din browser nu e o opțiune.
+
+ Fiecare sistem are o comandă pentru asta, iar toate trei sunt mai jos. Îți dau un fișier cu exact
+ numărul potrivit de octeți - și pentru multe teste atât îți trebuie. Fiecare comandă de pe
+ această pagină a fost rulată înainte de publicare, pe sistemul căruia îi aparține.
+
+
+
+
Răspunsul scurt
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Dimensiunile sunt în octeți, iar 10
+ MB numărați cum numără managerul tău de fișiere sunt 10485760.
+
+
+
+
+
Windows
+
fsutil și o variantă PowerShell care nu are nevoie de nimic în plus
+
+ fsutil vine cu Windows. Primește dimensiunea în octeți, așa că
+ calculează mai întâi numărul - 10 MB sunt 10485760, 100 MB sunt 104857600, 1 GB este 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Măsurat pe Windows 11: merge dintr-un prompt obișnuit, fără să ceară unul cu privilegii ridicate,
+ iar fișierul iese de exact 10485760 de octeți.
+
+
PowerShell poate face același lucru fără să cheme alt program și înțelege unitățile:
+ 10MB în PowerShell înseamnă 10485760 de octeți, aceeași numărare în baza 1024 pe care o
+ folosește Explorer, deci cele două comenzi de mai sus produc aceeași dimensiune.
+
+
+
+
+
Linux
+
dd, truncate și fallocate, și diferența care îi prinde pe oameni
+
dd este cel pe care îl știe toată lumea. Scrie într-adevăr octeții:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate e instantaneu și asta e capcana. Măsurat pe Alpine Linux, fișierul raportează
+ 10485760 de octeți și ocupă zero blocuri - este un fișier rar
+ (sparse). Tot ce îl citește primește zece megaocteți de zerouri, dar discul nu a cedat niciodată
+ spațiul:
+
+
truncate -s 10M test10mb.bin
+
+ E bine pentru a testa o limită de încărcare și înșelător pentru a testa o cotă de disc.
+ fallocate este cel de folosit când spațiul trebuie să fie real:
+
+
fallocate -l 10M test10mb.bin
+
Și când conținutul trebuie să fie incompresibil, ca un arhivator să nu-l poată strânge la loc:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, care nu e rar, și cele două pe care le știi deja
+
+ macOS vine cu mkfile. Măsurat pe macOS 26.6.2: 10485760 de octeți și 20480 de blocuri,
+ deci spațiul este alocat cu adevărat, nu doar promis:
+
+
mkfile 10m test10mb.bin
+
dd și truncate sunt și ele acolo și se comportă ca pe Linux:
Un fișier de dimensiunea potrivită nu este un fișier de tipul potrivit
+
+ Tot ce e mai sus îți dă un bloc de zerouri. Asta ajunge când ce se testează se uită doar la
+ dimensiune - o limită de încărcare, o cotă, un transfer. Nu mai ajunge din clipa în care ceva
+ deschide fișierul.
+
+
+ Măsurat, și merită să încerci singur: fă un fișier de 2 MB cu fsutil, numește-l
+ photo.png și dă-l unei biblioteci de imagini. Pillow răspunde cannot identify
+ image file. Nu e un PNG. N-a fost niciodată - doar numele o spunea.
+
+
+ Contează mai mult decât pare, din cauza direcției în care eșuează testul.
+ Endpointul tău de încărcare respinge fișierul, testul tău devine verde și tragi concluzia că
+ limita de dimensiune funcționează. Nu l-a respins pentru dimensiune. L-a respins pentru că
+ octeții nu erau o imagine, iar regula pe care voiai s-o testezi n-a fost niciodată atinsă.
+
+
+
un parser îl respinge înainte să se uite vreo regulă de dimensiune
+
un pas de miniatură eșuează și eroarea pe care o citești e despre miniatură
+
un antivirus sau o verificare de conținut îl refuză dintr-un al treilea motiv
+
un vizualizator nu arată nimic și nimeni nu poate spune dacă asta e bug-ul
+
+
+
+
+
Cealaltă cale
+
Un fișier real de acel format, la exact dimensiunea cerută
+
+ Asta face Testing Files Generator. Fișierul este unul autentic al formatului său - se deschide în
+ programul căruia îi aparține - și are numărul exact de octeți pe care l-ai cerut, la octet:
+
+ Cere o dimensiune pe care un format nu o poate atinge și primești o eroare care numește pragul și
+ motivul lui, niciodată un fișier de dimensiune greșită. Pagina de
+ formate listează fiecare format cu cel mai mic fișier pe care îl poate produce.
+
+
Iar o limită înseamnă trei cazuri de test, nu unul, așa că instrumentul le construiește pe toate trei:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Asta îți dă 10485759, 10485760 și 10485761 de octeți și un manifest care spune pe care sistemul tău
+ trebuie să le accepte și pe care să le respingă. Pagina de
+ cazuri de utilizare parcurge asta și alte patru sarcini pentru care a fost făcut.
+
Gratuit și open source, GPL-3.0. Fără cont. Descărcările pentru Windows și macOS sunt semnate și pornesc fără avertisment.
+
+
+
+
Deci pe care să-l folosești?
+
+
+
Folosește comanda sistemului
+
+ Când nimic nu deschide fișierul. Testarea unei limite de dimensiune pe un endpoint care verifică
+ întâi dimensiunea, un transfer, o cotă, un disc plin. E o singură linie și e deja instalat.
+
+
+
+
Folosește un generator adevărat
+
+ Când ceva analizează, randează, importă sau extrage fișierul - și când ai nevoie de aceleași
+ fixture-uri mâine, pe altă mașină, octet cu octet.
+
+
+
+
+ Ambele sunt pe această pagină pentru că ambele au dreptate o parte din timp. Greșeala de evitat este
+ să-l folosești pe primul unde îl trebuie pe al doilea și să citești testul verde drept dovadă.
+
+ Tot ce face instrumentul, aranjat ca întrebările cu care vin oamenii de fapt.
+ README-ul din repository este referința completă și se potrivește
+ mereu cu versiunea pe care ai descărcat-o.
+
+
+
+
Ce comenzi există?
+
Fiecare face un singur lucru:
+
tfg generate produce fișiere, dintr-o rețetă sau din opțiuni
+tfg validate verifică o rețetă fără a scrie nimic
+tfg verify verifică un director față de un manifest
+tfg cleanup șterge fișierele pe care le listează un manifest
+tfg recipe fmt afișează o rețetă în forma ei normalizată
+tfg preset construiește un set de fișiere dintr-o întrebare de test cu nume
+tfg formats listează formatele acceptate de această versiune
+tfg damage listează modurile în care această versiune poate strica un fișier intenționat
+tfg tool mici unelte pentru fișiere pe care le ai deja
+tfg version afișează versiunea instrumentului
+tfg license afișează licența și ce înseamnă ea pentru fișierele generate
+
+
+
+
Cum generez un singur fișier de dimensiune exactă?
+
+ Spune formatul, dimensiunea și unde merge. Dimensiunile se numără din 1024 în 1024, deci
+ 2mb sunt 2097152 octeți. Merge și un simplu număr de octeți, deci --size
+ 10485761 cere exact atât.
+
+
tfg generate --format png --size 2mb --out ./out
+
Opțiunile utile ale comenzii generate:
+
+
+
Opțiune
Ce face
+
+
--format <id>
formatul fișierelor, de exemplu txt
+
--size <size>
dimensiunea exactă a fiecărui fișier, precum 10mb sau un simplu număr de octeți
+
--size-range <a-b>
o dimensiune extrasă pentru fiecare fișier dintr-un interval, precum 1kb-8kb. Extragerea vine din seed
+
--boundary <size>
trei fișiere în jurul unei limite: un octet sub, limita, un octet peste
+
--count <n>
câte fișiere să producă. Implicit 1
+
--name <template>
șablon de nume, de exemplu invoice_{index:04}.txt
+
--out <dir>
directorul în care se scrie
+
--seed <n>
seed-ul rulării. Același seed dă aceiași octeți
+
--set <k>=<v>
o setare de format, repetabilă
+
--damage <name>
strică fișierele intenționat, repetabil și aplicat în ordine. Rulează tfg damage pentru listă
+
--expected <outcome>
accept, reject, sanitize sau unspecified
+
--dry-run
numără și arată, nu scrie absolut nimic
+
--json
scrie manifestul la ieșirea standard
+
+
+
+
+
+
+
Cum fac un fișier stricat intenționat?
+
+ Orice alt fișier scris de acest instrument este corect prin construcție, ceea ce răspunde la două
+ din cele trei întrebări pe care le pune un validator de încărcare. --damage
+ răspunde la a treia - se deschide oare fișierul. Fișierul este produs normal și apoi stricat,
+ deci are în continuare dimensiunea cerută.
+
+ Setările se pun după două puncte. Opțiunea se repetă, iar ordinea în care le scrii este ordinea în
+ care se aplică. tfg damage listează ce poate face această versiune și ce acceptă
+ fiecare.
+
+
Într-o rețetă cheia este o listă, de nume sau de setări:
+ Un fișier deteriorat primește expected: reject în manifest, cu deteriorarea consemnată
+ alături. Două lucruri sunt refuzate înainte de a se scrie ceva, pentru că fiecare ar pune pe
+ disc un fișier pe care manifestul îl descrie greșit:
+
+
+
un fișier mai mic decât are nevoie deteriorarea, pentru că ar ieși neschimbat
+
+ expected: accept alături de o deteriorare, pentru că nimic nu l-ar putea îndeplini.
+ Scrie sanitize dacă sistemul testat trebuie să repare fișierul sau
+ unspecified dacă exact asta e întrebarea pe care o pui
+
+
+
+ O a treia nu se poate ști dinainte. Dacă o deteriorare rulează și nu mută niciun octet, fișierul
+ respectiv este abandonat în loc să fie scris - rularea continuă, spune care a fost fișierul și
+ se termină cu codul de ieșire parțial.
+
+ O rețetă este un fișier YAML care descrie o rulare întreagă. Comite-o lângă testele tale și
+ fixture-urile nu mai sunt binare în repository - oricine le poate reconstrui, octet cu octet,
+ dintr-un fișier de câteva sute de caractere.
+
+ Fiecare target are nevoie de exact una dintre cheile size, size-range,
+ boundary sau contains. Două este o eroare și la fel niciuna. O rețetă
+ invalidă nu scrie niciun fișier și raportează toate problemele deodată, nu doar
+ prima, fiecare numind setarea la care se referă.
+
+
+
+
+
Cum declar ce trebuie să facă sistemul meu cu un fișier?
+
Formă scurtă când rezultatul e de ajuns, formă lungă când contează motivul:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Rezultatele sunt accept, reject, sanitize și
+ unspecified. Motivele sunt o listă închisă ca un raport să poată grupa după ele:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit și size_zero.
+
+
+ Un motiv numește regula în joc, nu verdictul. De aceea același motiv poate sta sub
+ oricare dintre rezultate - un fișier cu un octet sub o limită este accept, iar
+ regula la care se referă rămâne size_limit.
+
+
+
+
+
Ce conține manifestul?
+
+ Se scrie lângă fișiere la sfârșitul fiecărei rulări, inclusiv a uneia întrerupte. O intrare pentru
+ fiecare fișier:
+
+ Se adaugă un recipe_hash când rularea a venit dintr-o rețetă și preset cu
+ overrides când a venit dintr-o presetare, astfel încât un manifest poate fi mereu
+ urmărit până la ce l-a produs.
+
+
+ Fiecare intrare poartă și target_id, id-ul targetului din rețeta care a produs
+ fișierul, iar summary.by_target numără fișierele la care a ajuns fiecare target. O
+ rețetă cu mai multe targeturi poate fi verificată astfel target cu target, fără a citi nume de
+ fișiere.
+
+
+
+
+
Ce este o presetare?
+
+ Un set de fișiere gata făcut care răspunde unei întrebări de test obișnuite, ca să nu trebuiască să
+ proiectezi tu setul. Presetările sunt rețete obișnuite pe dedesubt, iar eject
+ afișează rețeta ca s-o poți edita de acolo. Fiecare presetare are o
+ pagină proprie cu ce găsește de obicei, ce este în set și fiecare setare pe care o acceptă.
+
+ show îți spune cât ar costa setul înainte să-l construiești și spune pe față când un
+ număr este o valoare provizorie de-a noastră, nu o limită de-a ta.
+
+
+
+
+
Ce înseamnă codurile de ieșire?
+
+ Fiecare final are propriul cod, ieșirea citibilă de mașină merge la ieșirea standard, iar o rulare
+ eșuată nu tipărește nimic acolo. Tabelul este un contract înghețat - schimbarea sensului unui
+ cod cere o versiune majoră.
+
+
+
+
+
+
Cod
+
Semnificație
+
+
+
+
+
0
+
Totul a mers.
+
+
+
1
+
O eroare neașteptată în interiorul instrumentului.
+
+
+
2
+
Comandă sau opțiune greșită.
+
+
+
3
+
Rețeta nu este validă.
+
+
+
4
+
Formatul nu poate face ce s-a cerut.
+
+
+
5
+
O citire sau o scriere a eșuat.
+
+
+
6
+
Nu este destul spațiu pe disc.
+
+
+
7
+
verify a găsit o nepotrivire.
+
+
+
8
+
Rularea s-a terminat, dar nu s-a produs totul.
+
+
+
130
+
Întreruptă cu Ctrl+C.
+
+
+
143
+
Oprită de un semnal, așa arată o depășire de timp în CI.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ O rulare oprită cu Ctrl+C lasă totuși un manifest și nu lasă niciodată un fișier scris pe jumătate,
+ așa că un job anulat poate fi curățat de următorul.
+
+ Da, același motor cu o fereastră deasupra, pentru testarea care nu e automatizată. Nu e o versiune
+ redusă: un test compară cele două interfețe capacitate cu capacitate, iar tot ce poate face doar
+ una dintre ele trebuie declarat și justificat, nu lăsat să divergă pe tăcute.
+
+
+ Ecranele sunt un lot, presetări, mai multe loturi deodată și Despre. Arată cât ar costa o rulare
+ înainte să scrie ceva, raportează progresul cât rulează și poate fi anulată pe la jumătate fără
+ să lase un fișier scris pe jumătate. Nu deschide încă un fișier de rețetă - rețetele sunt
+ deocamdată treaba liniei de comandă, iar fereastra își construiește loturile în formular.
+
+ Un validator căruia i s-au arătat doar fișiere sănătoase nu a fost cu adevărat testat. Iată cum
+ obții un fișier stricat intenționat, care iese cu exact mărimea pe care o ceri și
+ vine cu un manifest care spune ce trebuie să facă sistemul tău cu el.
+
+
+
+
Răspunsul scurt
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out scrie un PNG de
+ exact 2097152 de octeți ai cărui primi octeți sunt zerouri, iar manifestul de lângă el notează
+ că sistemul tău trebuie să îl respingă.
+
+
+
+
+
Calea obișnuită
+
De ce un fișier corupt de mână face un test prost
+
+ Căile obișnuite sunt un editor hexazecimal, un script care schimbă câțiva octeți la întâmplare sau
+ un fișier scurtat cu head ori truncate. Merg o dată, apoi te costă:
+
+
+
+ Este altfel de fiecare dată. Un octet ales la întâmplare cade în alt loc la fiecare
+ rulare, deci o eroare de marți poate să nu se mai întoarcă miercuri.
+
+
+ Schimbă mărimea. Un fișier tăiat este mai mic decât limita sub care trebuia să
+ stea, deci verificarea mărimii răspunde înaintea celei a conținutului, iar testul trece din
+ motivul greșit.
+
+
+ Adesea trece neobservat. Textul simplu se citește în continuare cu un octet
+ schimbat la mijloc, iar un cititor de imagini îngăduitor îl desenează pur și simplu, așa că
+ fișierul care trebuia să fie stricat este acceptat.
+
+
+ Nu spune nimic despre ce trebuie să se întâmple. Fișierul este doar octeți, iar
+ cine citește testul mai târziu trebuie să ghicească dacă s-a urmărit acceptarea sau
+ respingerea.
+
+
+
+
+
+
Ce primești
+
Un fișier deteriorat are în continuare mărimea cerută
+
+ Fișierul este generat normal și stricat după aceea, pe drumul spre disc. Păstrează mărimea cerută,
+ iar aceeași comandă scrie din nou aceiași octeți.
+
+ Setările se scriu după două puncte. Opțiunea poate fi repetată, iar deteriorările se aplică în
+ ordinea în care le scrii. Funcționează cu fiecare dintre cele 26 formate.
+
+
+
+
+
Ce poate face
+
Ce deteriorări există?
+
+ Aceasta este lista pe care o afișează programul, citită din el când se construiește pagina.
+ tfg damage o afișează pe aceeași, iar tfg damage <id> spune ce
+ primește una dintre ele.
+
+
+
+
+
+
Deteriorare
+
Ce face cu octeții
+
Cel mai mic fișier
+
Setări
+
+
+
+
+
zero-head
+
Suprascrie cu zerouri primii octeți ai fișierului, fără să îi schimbe lungimea. Majoritatea cititorilor se uită întâi acolo, deci aproape orice observă această deteriorare.
+
8
+
bytes
+
+
+
+
+
+ zero-head scrie zerouri peste începutul fișierului. Majoritatea cititorilor se uită
+ întâi acolo, la semnătura și antetul care spun ce este fișierul, așa că aproape orice cititor
+ observă. Textul simplu și jurnalele nu au semnătură și sunt respinse și ele, pentru că un șir de
+ octeți nuli nu este text. Sub patru octeți, unele formate ies cu o deteriorare de care nu se
+ plânge niciun cititor, de aceea setarea începe de la patru.
+
+
+
+
+
Ce spune manifestul
+
Un manifest care spune ce trebuie să se întâmple
+
+ Fiecare fișier deteriorat primește o intrare care spune că sistemul tău trebuie să îl respingă, cu
+ deteriorarea notată alături:
+
+ Două cereri sunt refuzate înainte să se scrie ceva, pentru că fiecare ar lăsa pe disc un fișier pe
+ care manifestul îl descrie greșit:
+
+
+
un fișier mai mic decât are nevoie deteriorarea, care ar ieși neschimbat
+
+ expected: accept lângă o deteriorare, pentru că nimic nu ar putea îndeplini asta. Scrie
+ sanitize dacă sistemul tău trebuie să repare fișierul sau
+ unspecified dacă tocmai asta este întrebarea pe care o pui
+
+
+
+
+
+
Într-o rețetă
+
Fișiere sănătoase și stricate într-o singură rulare
+
+ Pune-le pe amândouă într-o rețetă, iar manifestul poartă așteptarea fiecărui fișier, deci testul nu
+ are nevoie de o listă cu care este care:
+
+ Testul citește manifestul și verifică dacă ce s-a întâmplat este ce s-a declarat. Nu are nevoie de o
+ listă de nume de fișiere:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ O respingere bună este una curată. Un mesaj care spune ce a fost greșit este răspunsul pe care îl
+ vrei. O eroare de server, o blocare sau un fișier salvat pe jumătate este defectul pe care acest
+ test există ca să îl găsească.
+
+
+
+
+
Mai departe
+
Unde să mergi de aici
+
+
+ Presetarea upload-validation pune unui formular
+ celelalte două întrebări, cea despre mărime și cea despre tip.
+
+ Un fixture binar într-un repository rămâne pentru totdeauna în istoricul lui, nu poate fi revizuit
+ într-un diff și devine imposibil când fișierul este mare. Generează în schimb fișierele în
+ pipeline, dintr-o rețetă. Rețeta este text, octeții ies la fel de fiecare dată, iar un ultim pas
+ dovedește că nimic nu s-a mișcat.
+
+
+
+
Răspunsul scurt
+
+ Instalează tfg, rulează tfg generate fixtures.yaml --out ./fixtures
+ înaintea testelor și tfg verify ./fixtures/manifest.json după ele. Ambii pași fac
+ singuri build-ul să eșueze, cu un cod de ieșire care spune de ce.
+
+
+
+
+
De ce să nu le comiți
+
De ce un fixture nu trebuie să stea în repository
+
+
+ Rămâne în istoric. Ștergerea ulterioară a unui binar nu face un clon mai mic,
+ pentru că fiecare versiune a lui este încă acolo.
+
+
+ Un diff nu arată ce s-a schimbat. Cel care revizuiește vede că un PDF este diferit
+ și nimic altceva. O rețetă se schimbă cu o linie.
+
+
+ Fișierele mari nu încap. GitHub refuză un push care conține un fișier de peste 100
+ MB, așa că un test al unei limite de încărcare de 500 MB nu are ce comite.
+
+
+
+ Ce trebuie comis este rețeta. Aceeași rețetă și același seed scriu aceiași octeți pe orice mașină,
+ deci fișierul generat în pipeline este fișierul pe care l-ai avut pe laptop.
+
+
+
+
+
Rețeta
+
O rețetă care stă lângă teste
+
+ Aceasta scrie douăzeci și cinci de facturi care trebuie acceptate și două imagini peste o limită
+ care trebuie respinse, iar manifestul notează ambele așteptări:
+
+ Linia cu suma de control compară arhiva cu verify-SHA256SUMS.txt din aceeași versiune.
+ Versiunea este fixată, așa că o versiune nouă nu schimbă niciodată un build pe care nu l-ai
+ atins.
+
+ Fiecare final are propriul cod de ieșire, deci pasul eșuează singur, iar jurnalul spune care a fost.
+ Cele pe care le întâlnește un pipeline:
+
+
+
3 - rețeta nu este validă. Nu s-a scris nimic, iar fiecare problemă este numită
+
4 - formatul nu poate face ce s-a cerut, de exemplu o mărime sub minimul lui
+
6 - nu este destul spațiu pe disc
+
7 - tfg verify a găsit un fișier care nu se potrivește cu manifestul lui
+
8 - rularea s-a încheiat, dar nu s-a produs totul
+
+
+ O rulare eșuată nu afișează nimic la ieșirea standard, așa că un parser de jurnale nu ia niciodată o
+ eroare drept date. Tabelul complet este pe pagina de
+ documentație.
+
+
+
+
+
PowerShell
+
Un script PowerShell mai are nevoie de o linie
+
+ PowerShell nu scoate codul de ieșire al unui program dintr-un fișier .ps1. Rulează unul
+ cu -File și scriptul răspunde 0 chiar și când instrumentul dinăuntru a
+ refuzat lucrul, așa că un build care ar trebui să fie roșu devine verde. Ultima linie este toată
+ soluția:
+
+ Așa se comportă PowerShell, nu este ceva legat de acest instrument. cmd,
+ bash și zsh nu au nevoie de nimic în plus.
+
+
+
+
+
Mai multe joburi
+
Împărțirea fixture-urilor între joburi
+
+ De obicei nu e nevoie să le încarci. Fiindcă aceeași rețetă scrie aceiași octeți, fiecare job își
+ poate rula propriul tfg generate, ceea ce e mai rapid decât o încărcare și o
+ descărcare. Când un job trebuie să primească fișiere de la altul, rulează tfg
+ verify pe manifest după transfer, și îți spune dacă ce a ajuns este ce s-a scris.
+
26 formate de fișiere, fiecare generat la o dimensiune exactă
+
+ Fiecare este un fișier real al acelui format. Se deschide în programul căruia îi
+ aparține și are exact numărul de octeți pe care l-ai cerut. Niciunul nu e umplutură de zerouri cu
+ o extensie lipită.
+
+
+
+
+
+
+
Format
+
Nume
+
Extensie
+
Cel mai mic fișier
+
Fidelitate
+
Verificat cu
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
nu se aplică
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
nu se aplică
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
nu se aplică
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
Ce înseamnă coloanele
+
+
+
Cel mai mic fișier
+
+ Cel mai mic număr de octeți pe care instrumentul îl acceptă pentru acel format, inclusiv eticheta pe
+ care o scrie în fișier. Cere mai puțin și primești o eroare care numește pragul și motivul
+ lui, niciodată un fișier de dimensiune greșită.
+
+
+
+
Fidelitate
+
+ Cât de complet este fișierul. full înseamnă că un cititor care analizează cu adevărat
+ formatul îl acceptă, nu doar că extensia se potrivește.
+
+
+
+
Verificat cu
+
+ Cititorul independent care deschide fiecare fișier generat înainte ca formatul să fie livrat - o
+ implementare separată, nu propriul nostru cod care își corectează singur temele.
+
+
+
+
+ Fiecare format se și repetă la octet: aceeași rețetă și același seed produc fișiere identice pe
+ orice mașină, ceea ce face sigur să comiți o rețetă în locul fixture-urilor înseși.
+
+
+
+
+
Setările pe care le acceptă fiecare format
+
+ Majoritatea formatelor au setări proprii - dimensiunile imaginii, calitatea JPEG, numărul de pagini
+ PDF, rândurile și coloanele dintr-o foaie de calcul, câte intrări intră într-o arhivă.
+ Setează-le cu --set key=value în linia de comandă sau sub properties:
+ într-o rețetă.
+
o dată precum 2024-02-29 sau 2024-02-29T13:45:00+02:00, sau none
+
+
+
+
modified
+
o dată precum 2024-02-29 sau 2024-02-29T13:45:00+02:00, sau none
+
+
+
png
+
width
+
1 - 20000 pixeli
+
+
+
+
height
+
1 - 20000 pixeli
+
+
+
pptx
+
slides
+
1 - 500 diapozitive
+
+
+
svg
+
width
+
1 - 20000 pixeli
+
+
+
+
height
+
1 - 20000 pixeli
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
id-ul unui format, așa cum îl listează tfg formats
+
+
+
+
entry_size
+
o dimensiune precum 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
adevărat sau fals
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 pixeli
+
+
+
+
height
+
1 - 20000 pixeli
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
adevărat sau fals
+
+
+
wav
+
sample_rate
+
8000 - 192000 herți
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 pixeli
+
+
+
+
height
+
1 - 16383 pixeli
+
+
+
xlsx
+
rows
+
1 - 200000 rânduri
+
+
+
+
columns
+
1 - 32768 coloane
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
adevărat sau fals
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
id-ul unui format, așa cum îl listează tfg formats
+
+
+
+
entry_size
+
o dimensiune precum 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
adevărat sau fals
+
+
+
+
password
+
parola, în text simplu
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ O valoare în afara a ce acceptă o setare este refuzată cu un mesaj care numește setarea, intervalul
+ permis și ce să folosești în loc. O setare necunoscută este și ea o eroare, niciodată o valoare
+ implicită tăcută - o greșeală de scriere acceptată pe tăcute dă un fișier cu setările greșite și
+ o oră de întrebări de ce trece testul când n-ar trebui.
+
+
+ Rulează tfg formats <id> ca să vezi exact ce acceptă un format în versiunea pe
+ care o ai.
+
+
+
+
+
Arhivele conțin fișiere reale
+
+ targz și zip pot
+ fi umplute cu intrări, nu lăsate ca o carcasă goală. O arhivă generată conține cu adevărat
+ documentele pe care spune că le conține, așa că tot ce o dezarhivează în timpul unui test
+ găsește înăuntru fișiere reale.
+
Generează fișiere de test reale la dimensiunea exactă
+
+ PDF, PNG, DOCX, ZIP - 26 formate în total, și fiecare este un
+ fișier real care se deschide în programul căruia îi aparține, la exact dimensiunea pe
+ care ai cerut-o. Fiecare rulare notează și ce trebuie să facă aplicația ta cu fiecare
+ fișier. Linie de comandă și fereastră desktop, gratuit și open source, funcționând în întregime
+ pe mașina ta.
+
Gratuit și open source, GPL-3.0. Fără cont. Descărcările pentru Windows și macOS sunt semnate și pornesc fără avertisment.
+
+
+
+
+ Fereastra desktop, pregătită să scrie un lot de fișiere. Același motor rulează în spatele liniei de comandă.
+
+
+
+
+
+ 26
+
formate reale, fiecare se deschide în programul căruia îi aparține
+
+
+ 1 octet
+
precizia fiecărei dimensiuni cerute, niciodată rotunjită pe tăcute
+
+
+ 0
+
conexiuni către orice loc - fără cont, fără telemetrie, fără verificare de actualizări
+
+
+
+
+
Problema
+
Să faci un fișier de test e ușor. Să faci cele o mie potrivite e partea plictisitoare
+
Testezi software care primește fișiere de la oameni. Mai devreme sau mai târziu ai nevoie de:
+
+
un PDF de exact 10 MB, ca să afli dacă limita de încărcare e reală
+
cele trei fișiere de o parte și de alta a acelei limite, ca să prinzi erorile de unu
+
10.000 de fișiere de jurnal, ca să vezi ce face jobul de noapte când folderul e mare
+
un ZIP care chiar conține 200 de documente, nu o carcasă goală cu extensia potrivită
+
un fișier de 4 GB, fără să ții un fișier de 4 GB în repository
+
aceleași fixture-uri pe laptopul tău și pe serverul de build, octet cu octet
+
+
+ Asta înlocuiește acesta. Este construit pentru ingineri QA, automatizarea testelor și oricine are în
+ spatele codului un formular de încărcare, o rutină de import, un parser sau o cotă de stocare.
+
+
+
+
+
Ce îl face diferit
+
Alte generatoare se opresc la octeți. Acesta răspunde la ce întreabă de fapt testul tău
+
+ Un folder de fișiere te lasă tot pe tine să hotărăști ce trebuie să demonstreze fiecare. Fiecare
+ rulare scrie aici un manifest.json lângă fișiere - o listă simplă a tot ce s-a
+ produs și, pentru fiecare intrare, o așteptare declarată.
+
+
Să zicem că endpointul tău de încărcare permite 1 MB. Cere cele trei fișiere de pe acea linie:
Acolo unde răspunsul depinde de propria ta politică, manifestul spune asta
+
+ Înregistrează unspecified în loc să inventeze o așteptare. Un generator care ghicește
+ produce eșecuri false, iar o suită care dă alarme false ajunge oprită.
+
+
+
+
+
+
Presetări
+
Alege întrebarea, primești setul întreg
+
+ O presetare este un set de fișiere de test conceput în jurul unei întrebări de test, ca să nu fie
+ nevoie să afli tu ce fișiere dovedesc ce. Fiecare are o pagină care spune ce găsește de obicei,
+ ce este în set și fiecare setare pe care o acceptă.
+
+ Zece mii de fișiere de jurnal, fiecare între unu și opt kiloocteți, cu dimensiunile extrase din seed
+ ca mâine să dea același set. Dă fiecărei rulări propriul director -
+ manifestul este singura evidență a ce a scris o rulare, așa că instrumentul refuză să scrie
+ un al doilea peste el:
+
+ Dimensiunile se numără din 1024 în 1024, cum o face managerul tău de fișiere, deci 2mb
+ înseamnă 2097152 octeți. Merge și un simplu număr de octeți.
+ Documentația acoperă rețetele, manifestul și codurile de ieșire.
+
+
+
+
+
Ce primești
+
Construit pentru o suită care rulează nesupravegheată
+
+
+
Dimensiune exactă, la octet
+
Cere 10485761 de octeți și primești exact atât. O dimensiune pe care un format nu o poate atinge este o eroare cu un motiv, niciodată un fișier de dimensiune greșită.
+
+
+
26 formate reale
+
Nu zerouri de umplutură cu o extensie. Un PNG generat se deschide într-un vizualizator de imagini, un DOCX se deschide în Word, un ZIP se extrage. Fiecare este verificat cu cititori independenți înainte de livrare.
+
+
+
Un manifest care este un oracol de test
+
Cale, dimensiune, SHA-256, format, seed, versiunea instrumentului - și ce trebuie să facă sistemul tău cu fișierul.
+
+
+
Reproductibil
+
Aceeași rețetă și același seed, aceiași octeți, pe orice mașină. Comite o rețetă YAML mică în loc de fixture-uri binare mari.
+
+
+
Două interfețe, un singur motor
+
O linie de comandă făcută pentru CI și o fereastră desktop pentru testarea exploratorie. Niciuna nu e o versiune redusă a celeilalte, iar un test le compară capacitate cu capacitate.
+
+
+
Complet offline
+
Fără cont, fără cloud, fără telemetrie, fără verificare de actualizări. Binarul liniei de comandă nu are compilat în el niciun stack de rețea.
+
+
+
+
+
+
Descărcare
+
Alege versiunea pentru sistemul tău
+
+ Dezarhivează arhiva și rulează-o. tfg este linia de comandă și tfg-gui
+ este fereastra desktop. Nu există instalator și nimic de adăugat pe mașina ta.
+
+
+
+
+
+
Sistem
+
Linie de comandă
+
Fereastră desktop
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
Ce este semnat și ce nu
+
+ Descărcările pentru Windows și macOS sunt semnate, așa că pornesc fără avertisment despre un
+ dezvoltator necunoscut. Cele pentru Linux nu sunt, pentru că Linux pe desktop nu are un
+ echivalent cu care să le semnezi. Fiecare arhivă este listată în
+ verify-SHA256SUMS.txt pe pagina de versiuni, ca să poți verifica ce ai descărcat.
+
+ Licență, confidențialitate, reproductibilitate și lucrurile pe care oamenii le verifică înainte să
+ pună un generator într-un pipeline de build. Dacă întrebarea ta nu e aici,
+ sistemul de issue-uri este deschis.
+
+
+
+
+
Prin ce diferă de dd, fsutil sau truncate?
+
+
Acelea îți dau un fișier de dimensiunea potrivită, plin de nimic. Un fișier de 2 MB numit photo.png făcut așa nu este un PNG, deci tot ce îl analizează cu adevărat îl respinge din motivul greșit, iar testul tău trece apoi tot din motivul greșit. Acesta produce un PNG real de exact 2 MB care se deschide într-un vizualizator de imagini și vine cu o declarație despre cum trebuie să îl trateze sistemul tău.
Da la amândouă. Este publicat sub GPL-3.0 și nu costă nimic. Nu există cont, cheie de licență sau nivel plătit.
+
+
+
+
Pot folosi fișierele generate într-un produs cu cod închis?
+
+
Da. Licența acoperă codul instrumentului, nu ce produce el. Fișierele, rețetele și manifestele generate sunt rezultat și nu lucrări derivate, deci le poți comite și distribui fără nicio obligație.
+
+
+
+
Conțin fișierele generate date personale reale?
+
+
Nu. Tot ce se află în ele este sintetizat dintr-un seed. Nu se citește niciun set de date, nu se contactează niciun serviciu și nu se încorporează conținut de la terți. Tratează o adresă de e-mail generată ca inutilizabilă, nu ca neutilizată, pentru că orice șir aleatoriu poate coincide din întâmplare cu una reală.
+
+
+
+
Voi obține exact aceleași fișiere pe altă mașină?
+
+
Da, octet cu octet, cu aceeași rețetă și același seed. Proiectul testează asta la fiecare modificare, iar încălcarea ei cere o versiune majoră. Asta îți permite să comiți o rețetă mică în loc de fixture-uri binare mari.
+
+
+
+
Are nevoie de conexiune la internet?
+
+
Niciodată. Nu există telemetrie, verificare de actualizări sau client cloud, iar binarul liniei de comandă nu are compilat în el niciun stack de rețea. Funcționează pe o mașină fără rețea și într-un mediu corporativ închis.
+
+
+
+
Ce se întâmplă dacă cer o dimensiune pe care un format nu o poate atinge?
+
+
Primești o eroare care numește formatul, cea mai mică dimensiune posibilă, motivul acelui prag și ce să faci în loc, și nu se scrie niciun fișier. Instrumentul nu rotunjește niciodată o dimensiune pe tăcute. Fiecare prag este listat în pagina de formate.
+
tfg formats png
+
+
+
+
Pot genera un fișier stricat în mod deliberat?
+
+
Da. Adaugă --damage zero-head și fișierul iese cu exact mărimea cerută, cu primii octeți suprascriși cu zerouri, așa că un cititor îl respinge, iar manifestul spune că sistemul tău trebuie să îl respingă. Detaliile sunt pe pagina despre fișierele de test corupte.
7z, mp3 și mp4. Azi funcționează de la un capăt la altul 26 formate.
+
+
+
+
Pe ce sisteme îl pot rula?
+
+
Linia de comandă rulează pe Windows și Linux, atât pe Intel, cât și pe ARM, și pe Mac-uri cu Apple Silicon. Fereastra desktop este livrată pentru Windows pe Intel, Linux pe Intel și Mac-uri cu Apple Silicon. Mac-urile Intel nu sunt acceptate și nu se construiește nimic pentru ele.
+
+
+
+
Trebuie să instalez ceva?
+
+
Nu. Descarcă arhiva pentru sistemul tău, dezarhiveaz-o și rulează binarul. Nu există instalator, mediu de execuție de adăugat sau dependență de rezolvat. Dacă ai Go, funcționează și o singură comandă go install.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
De ce o rulare peste mii de fișiere este mai lentă pe Windows?
+
+
Pentru că Windows cere mai mult pentru fiecare cale pe care o examinează, iar o comandă care parcurge mii de fișiere examinează mii de căi. Măsurat pe o mașină cu 3000 de fișiere de 1 kB, verify durează aproximativ 0,9 secunde pe Windows și aproximativ 0,2 secunde pe Linux într-un container. O cale de ieșire mai scurtă micșorează cifra de pe Windows, pentru că fiecare folder de deasupra fișierelor face parte din ce se examinează.
Trece un fișier valid, cât de mic permite formatul?
+
+ Presetarea empty-and-minimal construiește cu o singură comandă un set întreg de fișiere de test
+ reale pentru această întrebare, și un manifest.json alături care spune cum trebuie să
+ reacționeze sistemul tău la fiecare fișier. Tot ce urmează este citit din program, la valorile
+ implicite ale acestei versiuni.
+
+
+
+
+
Ce găsește de obicei?
+
+
un fișier valid respins pentru că e prea mic, când verificarea numără octeți în loc să îi citească
+
un fișier gol care prăbușește cititorul în loc să fie raportat
+
o imagine lată de un pixel care împarte la zero pe drumul spre miniatură
+
un depozit care citește zero octeți ca pe o încărcare eșuată și tot reîncearcă
+
+
+
+
+
+
Ce este în set?
+
La valorile implicite, așa cum le raportează tfg preset show empty-and-minimal:
Va stoca, va afișa și va returna sistemul meu un nume de fișier la care nu se aștepta?
+
+ Presetarea filename-handling construiește cu o singură comandă un set întreg de fișiere de test
+ reale pentru această întrebare, și un manifest.json alături care spune cum trebuie să
+ reacționeze sistemul tău la fiecare fișier. Tot ce urmează este citit din program, la valorile
+ implicite ale acestei versiuni.
+
+
+
+
+
Ce găsește de obicei?
+
+
un nume care arată ca altul pe ecran, într-un jurnal sau într-o listă
+
un nume tăiat, scurtat sau rescris între încărcare și stocare
+
o limită de lungime numărată în caractere acolo unde depozitul numără octeți
+
+
+
+
+
+
Ce este în set?
+
La valorile implicite, așa cum le raportează tfg preset show filename-handling:
+
+
+
+
Fișiere
50
+
Targeturi în rețeta lui
50
+
Dimensiune totală
51 200 B
+
Formate
txt
+
+
+
+
Și ce așteaptă manifestul acelui set de la sistemul tău:
+
+
+
+
Așteptat
Semnificație
Fișiere
+
+
+
accept
Sistemul tău trebuie să accepte fișierul.
4
+
unspecified
Depinde de regulile sistemului tău. Tu decizi, apoi verifici că ce se întâmplă este ce ai vrut.
46
+
+
+
+
+
+
+
Ce poți schimba?
+
+
+
+
Setare
Primește
Implicit
Ce face
+
+
+
+
--format
+
un id de format din pagina de formate
+
txt
+
Formatul fiecărui fișier din set. Este o opțiune a instrumentului însuși, iar presetarea îi dă doar o valoare implicită.
+
+
+
+
+
+
+
+
Cum o rulezi?
+
Vezi cât ar costa setul, construiește-l sau ia-i rețeta ca s-o editezi:
Presetări de fișiere de test, câte un set pentru fiecare întrebare de test
+
+ O presetare este un set întreg de fișiere de test conceput în jurul unei întrebări, cu un manifest
+ care spune cum trebuie să reacționeze sistemul tău la fiecare fișier. Tu alegi întrebarea,
+ instrumentul construiește setul. Fiecare presetare are propria pagină cu ce găsește de obicei, ce
+ este în set și fiecare setare pe care o acceptă.
+
Acceptă formularul meu de încărcare ce trebuie și respinge restul?
+
upload-validation
+
+
+
+
+
Prin ce diferă o presetare de o rețetă?
+
+ Pe dedesubt, prin nimic. O presetare este o rețetă pe care instrumentul o scrie pentru tine din
+ câteva setări. tfg preset eject afișează acea rețetă ca s-o poți păstra lângă
+ testele tale și s-o editezi, iar o rețetă proprie se poate sprijini pe o presetare cu o singură
+ linie, extends: preset: urmat de id-ul ei.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Pot avea încredere în valorile implicite?
+
+ Pentru fișiere, da. Pentru un număr pe care îl știe doar sistemul tău, precum limita unui formular
+ de încărcare, o valoare implicită este o valoare provizorie de-a noastră, iar instrumentul o
+ spune de fiecare dată când folosește una. Pagina fiecărei presetări marchează acele setări, iar
+ tfg preset show o spune înainte să se scrie ceva.
+
Este o limită de dimensiune aplicată exact acolo unde este declarată?
+
+ Presetarea size-boundaries construiește cu o singură comandă un set întreg de fișiere de test
+ reale pentru această întrebare, și un manifest.json alături care spune cum trebuie să
+ reacționeze sistemul tău la fiecare fișier. Tot ce urmează este citit din program, la valorile
+ implicite ale acestei versiuni.
+
+
+
+
+
Ce găsește de obicei?
+
+
erori de unu în plus sau în minus la limită
+
MB confundat cu MiB, adică 4,8 la sută, suficient cât să treacă un fișier care n-ar trebui să treacă
+
o limită aplicată în browser și nu pe server
+
+
+
+
+
+
Ce este în set?
+
La valorile implicite, așa cum le raportează tfg preset show size-boundaries:
+
+
+
+
Fișiere
7
+
Targeturi în rețeta lui
7
+
Dimensiune totală
73 400 320 B
+
Formate
pdf
+
+
+
+
Și ce așteaptă manifestul acelui set de la sistemul tău:
+
+
+
+
Așteptat
Semnificație
Fișiere
+
+
+
accept
Sistemul tău trebuie să accepte fișierul.
4
+
reject
Sistemul tău trebuie să respingă fișierul.
3
+
+
+
+
+
+
+
Ce poți schimba?
+
+
+
+
Setare
Primește
Implicit
Ce face
+
+
+
+
--limit
+
o dimensiune precum 2mb
+
10mb
+
Limita de dimensiune declarată de sistemul tău. Tot restul se măsoară pornind de la ea. Această valoare implicită este valoarea noastră provizorie, nu valoarea sistemului tău. Dă-o pe a ta.
+
+
+
--spread
+
dimensiuni separate prin virgule
+
1B,1kb,1mb
+
Cât de departe să se meargă de ambele părți ale limitei, ca listă de dimensiuni.
+
+
+
--format
+
un id de format din pagina de formate
+
pdf
+
Formatul fiecărui fișier din set. Este o opțiune a instrumentului însuși, iar presetarea îi dă doar o valoare implicită.
+
+
+
+
+
+
+
+
Cum o rulezi?
+
Vezi cât ar costa setul, construiește-l sau ia-i rețeta ca s-o editezi:
Supraviețuiește importul meu de tabele la ce exportă instrumentele reale?
+
+ Presetarea tabular-import construiește cu o singură comandă un set întreg de fișiere de test
+ reale pentru această întrebare, și un manifest.json alături care spune cum trebuie să
+ reacționeze sistemul tău la fiecare fișier. Tot ce urmează este citit din program, la valorile
+ implicite ale acestei versiuni.
+
+
+
+
+
Ce găsește de obicei?
+
+
un fișier cu punct și virgulă citit ca o singură coloană, pentru că delimitatorul a fost presupus în loc să fie căutat
+
un fișier CRLF împărțit în rânduri cu un rând gol după fiecare
+
un tabel fără antet al cărui prim rând de date este înghițit drept nume de coloane
+
un import care păstrează coloanele pe care le poate arăta și aruncă restul fără o vorbă
+
un cititor care ia înregistrările JSON câte o linie și se oprește la primul document indentat
+
+
+
+
+
+
Ce este în set?
+
La valorile implicite, așa cum le raportează tfg preset show tabular-import:
+
+
+
+
Fișiere
13
+
Targeturi în rețeta lui
13
+
Dimensiune totală
3 080 060 B
+
Formate
csv, json, xlsx
+
+
+
+
Și ce așteaptă manifestul acelui set de la sistemul tău:
+
+
+
+
Așteptat
Semnificație
Fișiere
+
+
+
accept
Sistemul tău trebuie să accepte fișierul.
8
+
unspecified
Depinde de regulile sistemului tău. Tu decizi, apoi verifici că ce se întâmplă este ce ai vrut.
5
+
+
+
+
+
+
+
Ce poți schimba?
+
+
+
+
Setare
Primește
Implicit
Ce face
+
+
+
+
--rows
+
1 - 200000 rânduri
+
1000
+
Câte rânduri are foaia de calcul. Se scrie exact la dimensiunea pe care o ocupă atâtea rânduri, așa că bugetul de mai sus se mută odată cu această valoare.
+
+
+
--columns
+
1 - 32768 coloane
+
10
+
Câte coloane are fiecare rând al foii de calcul. Rânduri înmulțit cu coloane are un plafon, iar cererea peste el este refuzată înainte de a se scrie ceva.
+
+
+
+
+
+
+
+
Cum o rulezi?
+
Vezi cât ar costa setul, construiește-l sau ia-i rețeta ca s-o editezi:
Știe cititorul meu în ce codare este un fișier sau doar ghicește?
+
+ Presetarea text-encoding construiește cu o singură comandă un set întreg de fișiere de test
+ reale pentru această întrebare, și un manifest.json alături care spune cum trebuie să
+ reacționeze sistemul tău la fiecare fișier. Tot ce urmează este citit din program, la valorile
+ implicite ale acestei versiuni.
+
+
+
+
+
Ce găsește de obicei?
+
+
un cititor care presupune UTF-8 și arată un fișier UTF-16 cu un caracter din trei sau ca rânduri de pătrățele
+
o marcă de ordine a octeților citită ca și conținut, astfel încât primul câmp al unui import începe cu trei caractere străine
+
un importator care ghicește codarea din primii octeți și ghicește altfel pentru un fișier mai lung
+
un fișier CRLF împărțit în rânduri cu un rând gol după fiecare sau un retur de car rămas în ultimul câmp
+
+
+
+
+
+
Ce este în set?
+
La valorile implicite, așa cum le raportează tfg preset show text-encoding:
+
+
+
+
Fișiere
20
+
Targeturi în rețeta lui
20
+
Dimensiune totală
81 920 B
+
Formate
csv, log, md, txt, xml
+
+
+
+
Și ce așteaptă manifestul acelui set de la sistemul tău:
+
+
+
+
Așteptat
Semnificație
Fișiere
+
+
+
accept
Sistemul tău trebuie să accepte fișierul.
10
+
unspecified
Depinde de regulile sistemului tău. Tu decizi, apoi verifici că ce se întâmplă este ce ai vrut.
10
+
+
+
+
+
+
+
Ce poți schimba?
+
+
+
+
Setare
Primește
Implicit
Ce face
+
+
+
+
--sample
+
o dimensiune precum 2mb
+
4kb
+
Cât de mare este fiecare fișier din set. UTF-16 stochează doi octeți pentru fiecare caracter, așa că un număr impar este refuzat.
+
+
+
+
+
+
+
+
Cum o rulezi?
+
Vezi cât ar costa setul, construiește-l sau ia-i rețeta ca s-o editezi:
Acceptă formularul meu de încărcare ce trebuie și respinge restul?
+
+ Presetarea upload-validation construiește cu o singură comandă un set întreg de fișiere de test
+ reale pentru această întrebare, și un manifest.json alături care spune cum trebuie să
+ reacționeze sistemul tău la fiecare fișier. Tot ce urmează este citit din program, la valorile
+ implicite ale acestei versiuni.
+
+
+
+
+
Ce găsește de obicei?
+
+
o limită aplicată în browser și nu pe server
+
un SVG sau un HTML luat drept imagine sau text simplu, o cale de a strecura un script printr-un formular
+
un fișier verificat după extensie și niciodată deschis, așa că un PDF numit .jpg trece
+
un formular care citește tot corpul în memorie înainte să vadă cât de mare e
+
o încărcare numită PHOTO.JPG respinsă acolo unde photo.jpg e acceptată, sau invers
+
un nume cu spații, paranteze sau caractere în afara ASCII scris pe disc neschimbat
+
+
+
+
+
+
Ce este în set?
+
La valorile implicite, așa cum le raportează tfg preset show upload-validation:
+
+
+
+
Fișiere
71
+
Targeturi în rețeta lui
22
+
Dimensiune totală
120 639 488 B
+
Formate
html, jpg, pdf, png, svg, txt
+
+
+
+
Și ce așteaptă manifestul acelui set de la sistemul tău:
+
+
+
+
Așteptat
Semnificație
Fișiere
+
+
+
accept
Sistemul tău trebuie să accepte fișierul.
56
+
reject
Sistemul tău trebuie să respingă fișierul.
10
+
unspecified
Depinde de regulile sistemului tău. Tu decizi, apoi verifici că ce se întâmplă este ce ai vrut.
5
+
+
+
+
+
+
+
Ce poți schimba?
+
+
+
+
Setare
Primește
Implicit
Ce face
+
+
+
+
--limit
+
o dimensiune precum 2mb
+
10mb
+
Limita de dimensiune declarată de formularul tău de încărcare. Acest set face câte un pas de fiecare parte - pentru un fișier la orice distanță rulează presetarea size-boundaries. Această valoare implicită este valoarea noastră provizorie, nu valoarea sistemului tău. Dă-o pe a ta.
+
+
+
--allow
+
id-uri de format separate prin virgule
+
jpg,png,pdf
+
Ce tipuri trebuie să accepte formularul tău. Fiecare devine un fișier real de acel tip și ele formează controlul pozitiv al întregului set.
+
+
+
--deny
+
extensii separate prin virgule
+
svg,html,exe,sh
+
Ce extensii trebuie să respingă formularul tău. O extensie pentru care această versiune nu are format primește totuși un fișier cu acel nume, conținând text simplu.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
Cât de mult peste limită ajunge singurul fișier mare. Oprește-l unde scrierea de mai multe ori limita nu merită discul.
+
+
+
--bulk
+
0 - 10000 fișiere
+
50
+
Câte fișiere conține încărcarea în masă. Zero scoate acel grup complet din set.
+
+
+
+
+
+
+
+
Cum o rulezi?
+
Vezi cât ar costa setul, construiește-l sau ia-i rețeta ca s-o editezi:
+ Валидатор, которому показывали только здоровые файлы, на самом деле не проверен. Вот как получить
+ файл, намеренно испорченный, выходящий точно того размера, который вы просите, и
+ несущий манифест с указанием, что ваша система должна с ним сделать.
+
+
+
+
Короткий ответ
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out записывает PNG
+ ровно в 2097152 байта, первые байты которого нули, а манифест рядом фиксирует, что ваша система
+ должна его отклонить.
+
+
+
+
+
Обычный путь
+
Почему файл, испорченный вручную, - плохой тест
+
+ Обычно берут шестнадцатеричный редактор, скрипт, переворачивающий несколько случайных байтов, или
+ укорачивают файл через head либо truncate. Один раз это работает, а
+ потом обходится дорого:
+
+
+
+ Каждый раз по-разному. Случайный байт при каждом запуске попадает в новое место,
+ поэтому сбой во вторник в среду может не повториться.
+
+
+ Меняется размер. Обрезанный файл меньше лимита, под которым он должен был
+ оставаться, поэтому проверка размера отвечает раньше проверки содержимого, и тест проходит по
+ неверной причине.
+
+
+ Это часто остаётся незамеченным. Простой текст читается и с изменённым байтом
+ посередине, а снисходительная программа чтения изображений просто рисует его, так что файл,
+ который должен быть испорчен, принимается.
+
+
+ Не сказано, что должно произойти. Файл - это просто байты, и тому, кто будет читать
+ тест позже, придётся гадать, имелось в виду принятие или отклонение.
+
+
+
+
+
+
Что вы получаете
+
Повреждённый файл остаётся нужного размера
+
+ Файл создаётся как обычно и портится потом, по пути на диск. Он сохраняет заданный размер, а та же
+ команда снова записывает те же байты.
+
+ Настройки пишутся после двоеточия. Параметр можно повторять, а повреждения применяются в том
+ порядке, в каком вы их записали. Это работает с каждым из 26 форматов.
+
+
+
+
+
Что он умеет
+
Какие бывают повреждения?
+
+ Это список, который печатает программа, прочитанный из неё при сборке этой страницы. tfg
+ damage печатает тот же список, а tfg damage <id> говорит, что
+ принимает одно из них.
+
+
+
+
+
+
Повреждение
+
Что оно делает с байтами
+
Наименьший файл
+
Настройки
+
+
+
+
+
zero-head
+
Перезаписывает первые байты файла нулями, не меняя его длину. Большинство программ чтения смотрят сначала туда, поэтому это повреждение замечает почти всё.
+
8
+
bytes
+
+
+
+
+
+ zero-head записывает нули поверх начала файла. Большинство программ чтения смотрят
+ сначала туда, на сигнатуру и заголовок, которые говорят, что это за файл, поэтому замечает почти
+ любая. У простого текста и журналов сигнатуры нет, и их тоже отклоняют, потому что
+ последовательность нулевых байтов не является текстом. Меньше четырёх байтов у некоторых
+ форматов получается повреждение, на которое не жалуется ни одна программа чтения, поэтому
+ настройка начинается с четырёх.
+
+
+
+
+
Что говорит манифест
+
Манифест, который говорит, что должно произойти
+
+ Каждый повреждённый файл получает запись о том, что ваша система должна его отклонить, а рядом
+ записано повреждение:
+
+ Два запроса отклоняются до того, как что-либо записано, потому что каждый оставил бы на диске файл,
+ который манифест описывает неверно:
+
+
+
файл меньше, чем нужно повреждению, который вышел бы нетронутым
+
+ expected: accept рядом с повреждением, потому что ничто не могло бы этого выполнить.
+ Напишите sanitize, если ваша система должна починить файл, или
+ unspecified, если именно это вы и проверяете
+
+
+
+
+
+
В рецепте
+
Здоровые и сломанные файлы за один запуск
+
+ Положите оба вида в один рецепт, и манифест несёт ожидание для каждого файла, так что тесту не нужен
+ список, какой файл какой:
+
+ Тест читает манифест и проверяет, что произошедшее совпадает с заявленным. Список имён файлов ему не
+ нужен:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Хороший отказ - это чистый отказ. Сообщение, говорящее, что было не так, - тот ответ, который вам
+ нужен. Ошибка сервера, зависание или наполовину сохранённый файл - тот дефект, ради которого
+ этот тест и существует.
+
+ В каждой системе для этого есть команда, и все три приведены ниже. Они дают файл с точным числом
+ байт, а для многих тестов этого достаточно. Каждая команда на этой странице была выполнена
+ до публикации в той системе, к которой она относится.
+
+
+
+
Короткий ответ
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Размеры указываются в байтах, а 10
+ МБ, посчитанные так, как считает ваш файловый менеджер, - это 10485760.
+
+
+
+
+
Windows
+
fsutil и вариант на PowerShell, которому ничего дополнительного не нужно
+
+ fsutil входит в Windows. Он принимает размер в байтах, поэтому сначала
+ посчитайте число: 10 МБ - это 10485760, 100 МБ - 104857600, 1 ГБ - 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Измерено в Windows 11: работает из обычной командной строки без повышенных прав, и файл получается
+ ровно в 10485760 байт.
+
+
PowerShell может сделать то же самое, не вызывая другую программу, и понимает единицы:
+ 10MB в PowerShell означает 10485760 байт, тот же счёт по основанию 1024, что использует
+ Проводник, поэтому две команды выше дают один и тот же размер.
+
+
+
+
+
Linux
+
dd, truncate и fallocate, и разница, которая ловит людей
+
dd знают все. Он действительно записывает байты:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate срабатывает мгновенно, и в этом подвох. Измерено в Alpine Linux: файл сообщает
+ 10485760 байт и занимает ноль блоков - это разреженный файл.
+ Всё, что его читает, получает десять мегабайт нулей, но диск место так и не отдал:
+
+
truncate -s 10M test10mb.bin
+
+ Для проверки лимита загрузки это нормально, а для проверки дисковой квоты вводит в заблуждение.
+ fallocate - то, к чему стоит обратиться, когда место должно быть настоящим:
+
+
fallocate -l 10M test10mb.bin
+
А когда содержимое должно быть несжимаемым, чтобы архиватор не мог снова его ужать:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, который не разреженный, и две команды, которые вы уже знаете
+
+ В macOS есть mkfile. Измерено в macOS 26.6.2: 10485760 байт и 20480 блоков, то есть
+ место действительно выделено, а не обещано:
+
Файл правильного размера - не файл правильного вида
+
+ Всё сказанное выше даёт блок нулей. Этого достаточно, когда тестируемое смотрит только на размер:
+ лимит загрузки, квота, передача. Этого перестаёт хватать, как только что-либо
+ открывает файл.
+
+
+ Измерено, и стоит проверить самому: сделайте файл на 2 МБ командой fsutil, назовите его
+ photo.png и передайте библиотеке работы с изображениями. Pillow ответит
+ cannot identify image file. Это не PNG. Он им никогда и не был, так говорило лишь
+ имя.
+
+
+ Это важнее, чем кажется, из-за того, в какую сторону тест тогда проваливается. Ваша
+ точка загрузки отклоняет файл, ваш тест зеленеет, и вы заключаете, что лимит размера работает.
+ Она отклонила его не из-за размера. Она отклонила его потому, что байты не были изображением, и
+ правило, которое вы хотели проверить, так и не было достигнуто.
+
+
+
парсер отклоняет его, не дойдя до каких-либо правил размера
+
шаг создания миниатюры падает, и ошибка, которую вы читаете, относится к миниатюре
+
антивирус или проверка содержимого отклоняет его по третьей причине
+
просмотрщик ничего не показывает, и никто не может сказать, в этом ли ошибка
+
+
+
+
+
Другой путь
+
Настоящий файл этого формата точно того размера, который вы запросили
+
+ Именно это делает Testing Files Generator. Файл - настоящий файл своего формата, он открывается в
+ своей программе, и в нём ровно то число байт, которое вы запросили, с точностью до байта:
+
+ Запросите размер, которого формат не может достичь, и вы получите ошибку с названием минимума и
+ причиной, а не файл неверного размера. Страница форматов перечисляет
+ каждый формат с наименьшим файлом, который он может создать.
+
+
А лимит - это три тестовых случая, а не один, поэтому инструмент собирает все три:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Вы получите 10485759, 10485760 и 10485761 байт и манифест, который говорит, какие из них ваша
+ система должна принять, а какие отклонить. Страница сценариев
+ разбирает это и ещё четыре задачи, для которых инструмент создан.
+
Бесплатно, открытый код, GPL-3.0. Без регистрации. Сборки для Windows и macOS подписаны и запускаются без предупреждений.
+
+
+
+
Так что же использовать?
+
+
+
Используйте системную команду
+
+ Когда ничто не открывает файл. Проверка лимита размера на точке, которая сначала смотрит размер,
+ передача, квота, переполнение диска. Это одна строка, и она уже установлена.
+
+
+
+
Используйте настоящий генератор
+
+ Когда что-либо разбирает, отображает, импортирует или распаковывает файл - и когда завтра на другой
+ машине нужны те же фикстуры, байт в байт.
+
+
+
+
+ Обе есть на этой странице, потому что обе бывают правы. Ошибка, которой стоит избегать, -
+ использовать первую там, где нужна вторая, и принимать зелёный тест за доказательство.
+
+ Всё, что делает инструмент, разложено по вопросам, с которыми люди действительно приходят.
+ README в репозитории - полный справочник, и он всегда
+ соответствует скачанной вами сборке.
+
+
+
+
Какие есть команды?
+
Каждая делает одно дело:
+
tfg generate создать файлы по рецепту или по флагам
+tfg validate проверить рецепт, ничего не записывая
+tfg verify сверить каталог с манифестом
+tfg cleanup удалить файлы, перечисленные в манифесте
+tfg recipe fmt вывести рецепт в устоявшемся виде
+tfg preset собрать набор файлов по именованному тестовому вопросу
+tfg formats перечислить форматы этой сборки
+tfg damage перечислить способы, которыми эта сборка может намеренно испортить файл
+tfg tool небольшие инструменты для уже имеющихся файлов
+tfg version вывести версию инструмента
+tfg license вывести лицензию и что она означает для созданных файлов
+
+
+
+
Как создать один файл точного размера?
+
+ Укажите формат, размер и место назначения. Размеры считаются по 1024, поэтому 2mb - это
+ 2097152 байта. Подойдёт и простое число байт, так что --size 10485761 запрашивает
+ ровно столько.
+
+
tfg generate --format png --size 2mb --out ./out
+
Полезные флаги команды generate:
+
+
+
Флаг
Что делает
+
+
--format <id>
формат файлов, например txt
+
--size <size>
точный размер каждого файла, например 10mb или простое число байт
+
--size-range <a-b>
размер, выбираемый для каждого файла из диапазона, например 1kb-8kb. Выбор идёт от seed
+
--boundary <size>
три файла вокруг лимита: на байт меньше, сам лимит, на байт больше
+
--count <n>
сколько файлов создать. По умолчанию 1
+
--name <template>
шаблон имени, например invoice_{index:04}.txt
+
--out <dir>
каталог, в который записывать
+
--seed <n>
seed запуска. Один и тот же seed даёт те же байты
+
--set <k>=<v>
настройка формата, можно повторять
+
--damage <name>
намеренно испортить файлы, можно повторять, применяется по порядку. Список выводит tfg damage
+
--expected <outcome>
accept, reject, sanitize или unspecified
+
--dry-run
посчитать и показать, ничего не записывая
+
--json
записать манифест в стандартный вывод
+
+
+
+
+
+
+
Как сделать намеренно сломанный файл?
+
+ Любой другой файл, который записывает этот инструмент, корректен по построению, и это отвечает на
+ два из трёх вопросов, которые задаёт проверка загрузки. --damage отвечает на третий
+ - открывается ли файл вообще. Файл создаётся как обычно, а затем портится, поэтому у него
+ остаётся запрошенный размер.
+
+ Настройки указываются после двоеточия. Флаг можно повторять, и порядок записи - это порядок
+ применения. tfg damage перечисляет, что умеет эта сборка и что принимает каждый вид
+ повреждения.
+
+ Повреждённый файл получает в манифесте expected: reject с записанным рядом
+ повреждением. Две вещи отклоняются до записи чего-либо, потому что каждая оставила бы на диске
+ файл, неверно описанный манифестом:
+
+
+
файл меньше, чем нужно повреждению, потому что он вышел бы без изменений
+
+ expected: accept рядом с повреждением, потому что этому не мог бы соответствовать ни
+ один файл. Пишите sanitize, если тестируемая система должна починить файл, или
+ unspecified, если именно этот вопрос вы и задаёте
+
+
+
+ Третье заранее узнать нельзя. Если повреждение выполняется и не меняет ни одного байта, такой файл
+ отбрасывается, а не записывается - запуск продолжается, сообщает, что это был за файл, и
+ завершается кодом частичного завершения.
+
+ Рецепт - это файл YAML, описывающий целый запуск. Закоммитьте его рядом с тестами, и фикстуры
+ перестанут быть бинарными файлами в вашем репозитории - любой сможет пересоздать их байт в байт
+ из файла в несколько сотен символов.
+
+ Каждой цели нужен ровно один из ключей size, size-range,
+ boundary или contains. Два - это ошибка, и ни одного - тоже.
+ Недопустимый рецепт записывает ни одного файла и сообщает обо всех проблемах
+ сразу, а не только о первой, называя каждый раз настройку, к которой она относится.
+
+
+
+
+
Как объявить, что моя система должна делать с файлом?
+
Краткая форма, когда достаточно исхода, и длинная, когда важна причина:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Исходы - accept, reject, sanitize и unspecified.
+ Причины образуют закрытый список, чтобы отчёт мог по ним группировать:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit и size_zero.
+
+
+ Причина называет действующее правило, а не вердикт. Поэтому одна и та же причина
+ может стоять под любым исходом - файл на байт меньше лимита получает accept, а
+ правило, о котором речь, всё равно size_limit.
+
+
+
+
+
Что в манифесте?
+
+ Он записывается рядом с файлами в конце каждого запуска, в том числе прерванного. Одна запись на
+ файл:
+
+ recipe_hash добавляется, если запуск был по рецепту, а preset с
+ overrides - если по пресету, так что манифест всегда можно отследить до того, что
+ его создало.
+
+
+ Каждая запись также содержит target_id - id цели рецепта, которая создала файл, а
+ summary.by_target считает файлы каждой цели. Рецепт с несколькими целями можно
+ поэтому проверить цель за целью, не читая имена файлов.
+
+
+
+
+
Что такое пресет?
+
+ Готовый набор файлов, отвечающий на распространённый тестовый вопрос, чтобы вам не приходилось
+ проектировать набор самостоятельно. Пресеты - обычные рецепты внутри, а eject
+ выводит рецепт, чтобы вы могли отредактировать его. У каждого пресета есть
+ отдельная страница о том, что он обычно находит, что входит в набор и
+ какие настройки принимает.
+
+ show сообщает, чего стоил бы набор, прежде чем вы его соберёте, и прямо говорит, когда
+ число - наша временная подстановка, а не ваш лимит.
+
+
+
+
+
Что означают коды завершения?
+
+ У каждого исхода свой код, машиночитаемый вывод идёт в стандартный вывод, а неудачный запуск ничего
+ туда не печатает. Таблица - замороженный контракт: смена значения кода требует повышения
+ мажорной версии.
+
+
+
+
+
+
Код
+
Значение
+
+
+
+
+
0
+
Всё сработало.
+
+
+
1
+
Непредвиденная ошибка внутри инструмента.
+
+
+
2
+
Неверная команда или флаг.
+
+
+
3
+
Рецепт недопустим.
+
+
+
4
+
Формат не может сделать то, что запрошено.
+
+
+
5
+
Не удалось прочитать или записать.
+
+
+
6
+
Недостаточно места на диске.
+
+
+
7
+
verify обнаружил расхождение.
+
+
+
8
+
Запуск завершён, но создано не всё.
+
+
+
130
+
Прерван с помощью Ctrl+C.
+
+
+
143
+
Остановлен сигналом, так выглядит тайм-аут в CI.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Запуск, остановленный с помощью Ctrl+C, всё равно оставляет манифест и никогда не оставляет
+ наполовину записанный файл, поэтому отменённое задание может быть убрано следующим.
+
+ Да, тот же движок с окном сверху, для тестирования, которое не автоматизируется. Это не урезанная
+ версия: тест сравнивает два интерфейса возможность за возможностью, и всё, что умеет только один
+ из них, должно быть объявлено и обосновано, а не тихо расходиться.
+
+
+ Экраны: одна партия, пресеты, несколько партий одновременно и о программе. Окно показывает, чего
+ стоил бы запуск, прежде чем что-либо записать, отображает ход работы и может быть отменено на
+ полпути без наполовину записанного файла. Файл рецепта оно пока не открывает - рецепты пока дело
+ командной строки, а окно собирает свои партии в форме.
+
+ Лицензия, приватность, воспроизводимость и то, что люди проверяют, прежде чем включать генератор в
+ конвейер сборки. Если вашего вопроса здесь нет, трекер задач
+ открыт.
+
+
+
+
+
Чем это отличается от dd, fsutil или truncate?
+
+
Они дают файл нужного размера, набитый пустотой. Файл photo.png на 2 МБ, сделанный так, не является PNG, поэтому всё, что действительно его разбирает, отклоняет его по неверной причине, и ваш тест тоже проходит по неверной причине. Этот инструмент создаёт настоящий PNG ровно на 2 МБ, который открывается в просмотрщике изображений, и сопровождает его заявлением о том, как ваша система должна с ним поступать.
Да в обоих случаях. Инструмент выпущен под GPL-3.0 и ничего не стоит. Нет ни учётной записи, ни лицензионного ключа, ни платного тарифа.
+
+
+
+
Можно ли использовать созданные файлы в продукте с закрытым кодом?
+
+
Да. Лицензия охватывает код инструмента, а не то, что он создаёт. Созданные файлы, рецепты и манифесты являются результатом, а не производными произведениями, поэтому их можно коммитить и поставлять без каких-либо обязательств.
+
+
+
+
Содержат ли созданные файлы настоящие персональные данные?
+
+
Нет. Всё внутри синтезируется из seed. Никакой набор данных не читается, ни к какому сервису не обращаются и никакое стороннее содержимое не встраивается. Считайте созданный адрес электронной почты непригодным, а не неиспользованным, потому что любая случайная строка может случайно совпасть с настоящим адресом.
+
+
+
+
Получу ли я точно такие же файлы на другой машине?
+
+
Да, байт в байт, при том же рецепте и том же seed. Проект проверяет это при каждом изменении, а нарушить это можно только повышением мажорной версии. Именно поэтому вы можете коммитить небольшой рецепт вместо больших бинарных фикстур.
+
+
+
+
Нужно ли подключение к интернету?
+
+
Никогда. Нет ни телеметрии, ни проверки обновлений, ни облачного клиента, а в бинарный файл командной строки вообще не скомпилирован сетевой стек. Он работает на машине без сети и в закрытой корпоративной среде.
+
+
+
+
Что будет, если запросить размер, которого формат не может достичь?
+
+
Вы получите ошибку с названием формата, наименьшим возможным размером, причиной этого минимума и тем, что делать вместо этого, а файл записан не будет. Инструмент никогда не округляет размер молча. Каждый минимум указан на странице форматов.
+
tfg formats png
+
+
+
+
Можно ли создать намеренно сломанный файл?
+
+
Да. Добавьте --damage zero-head, и файл выйдет точно заданного размера, с первыми байтами, перезаписанными нулями, так что программа чтения его отклонит, а манифест скажет, что ваша система должна его отклонить. Подробности на странице о повреждённых тестовых файлах.
7z, mp3 и mp4. Сегодня полностью работают 26 форматов.
+
+
+
+
На каких системах это можно запускать?
+
+
Командная строка работает в Windows и Linux на Intel и ARM, а также на Mac с Apple Silicon. Десктопное окно поставляется для Windows на Intel, Linux на Intel и Mac с Apple Silicon. Mac на Intel не поддерживаются, и для них ничего не собирается.
+
+
+
+
Нужно ли что-нибудь устанавливать?
+
+
Нет. Скачайте архив для своей системы, распакуйте и запустите бинарный файл. Нет установщика, среды выполнения, которую нужно добавлять, и зависимостей, которые нужно разрешать. Если у вас есть Go, подойдёт и одна команда go install.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
Почему запуск на тысячах файлов в Windows медленнее?
+
+
Потому что Windows берёт больше за каждый просматриваемый путь, а команда, обходящая тысячи файлов, просматривает тысячи путей. Измерено на одной машине с 3000 файлов по 1 КБ: verify занимает около 0,9 секунды в Windows и около 0,2 секунды в Linux в контейнере. Более короткий путь вывода уменьшает цифру для Windows, потому что каждая папка над файлами входит в то, что просматривается.
26 форматов файлов, каждый создаётся точного размера
+
+ Каждый из них - настоящий файл этого формата. Он открывается в своей программе и
+ имеет ровно то число байт, которое вы запросили. Ни один не является нулями-заполнителями с
+ приклеенным расширением.
+
+
+
+
+
+
+
Формат
+
Название
+
Расширение
+
Наименьший файл
+
Полнота
+
Проверяется с помощью
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
не применимо
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
не применимо
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
не применимо
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
Что означают столбцы
+
+
+
Наименьший файл
+
+ Наименьшее число байт, которое этот инструмент принимает для формата, включая метку, которую он
+ пишет внутри файла. Запросите меньше, и вы получите ошибку с названием минимума и причиной,
+ а не файл неверного размера.
+
+
+
+
Полнота
+
+ Насколько полон файл. full означает, что его принимает читатель, который по-настоящему
+ разбирает формат, а не просто совпадает расширение.
+
+
+
+
Проверяется с помощью
+
+ Независимый читатель, который открывает каждый созданный файл до выпуска формата, - отдельная
+ реализация, а не наш собственный код, проверяющий собственные домашние задания.
+
+
+
+
+ Каждый формат к тому же повторяется до байта: тот же рецепт и тот же seed дают одинаковые файлы на
+ любой машине, и именно это делает безопасным коммит рецепта вместо самих фикстур.
+
+
+
+
+
Настройки, которые принимает каждый формат
+
+ У большинства форматов есть свои настройки - размеры изображения, качество JPEG, число страниц PDF,
+ строки и столбцы в таблице, сколько записей входит в архив. Задайте их через --set
+ key=value в командной строке или в разделе properties: рецепта.
+
дата вида 2024-02-29 или 2024-02-29T13:45:00+02:00, либо none
+
+
+
+
modified
+
дата вида 2024-02-29 или 2024-02-29T13:45:00+02:00, либо none
+
+
+
png
+
width
+
1 - 20000 пикселей
+
+
+
+
height
+
1 - 20000 пикселей
+
+
+
pptx
+
slides
+
1 - 500 слайдов
+
+
+
svg
+
width
+
1 - 20000 пикселей
+
+
+
+
height
+
1 - 20000 пикселей
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
id формата в том виде, как его выводит tfg formats
+
+
+
+
entry_size
+
размер, например 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
истина или ложь
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 пикселей
+
+
+
+
height
+
1 - 20000 пикселей
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
истина или ложь
+
+
+
wav
+
sample_rate
+
8000 - 192000 герц
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 пикселей
+
+
+
+
height
+
1 - 16383 пикселей
+
+
+
xlsx
+
rows
+
1 - 200000 строк
+
+
+
+
columns
+
1 - 32768 столбцов
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
истина или ложь
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
id формата в том виде, как его выводит tfg formats
+
+
+
+
entry_size
+
размер, например 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
истина или ложь
+
+
+
+
password
+
пароль открытым текстом
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ Значение вне допустимого для настройки отклоняется сообщением с названием настройки, допустимым
+ диапазоном и тем, что использовать вместо этого. Неизвестная настройка тоже ошибка, а не
+ молчаливое значение по умолчанию - опечатка, принятая молча, даёт файл с неверными настройками и
+ час раздумий, почему тест проходит, хотя не должен.
+
+
+ Выполните tfg formats <id>, чтобы увидеть, что именно принимает один формат в
+ вашей сборке.
+
+
+
+
+
Архивы содержат настоящие файлы
+
+ targz и zip
+ можно наполнить записями, а не оставлять пустой оболочкой. Созданный архив действительно
+ содержит документы, которые заявляет, поэтому всё, что распаковывает его во время теста, находит
+ внутри настоящие файлы.
+
+ PDF, PNG, DOCX, ZIP - всего 26 форматов, и каждый из них
+ настоящий файл, который открывается в своей программе, точно того размера, который вы
+ запросили. Каждый запуск ещё и записывает, что ваше приложение должно делать с каждым
+ файлом. Командная строка и десктопное окно, бесплатно и с открытым кодом, всё работает на вашей
+ машине.
+
Бесплатно, открытый код, GPL-3.0. Без регистрации. Сборки для Windows и macOS подписаны и запускаются без предупреждений.
+
+
+
+
+ Десктопное окно, подготовленное к записи партии файлов. За командной строкой работает тот же движок.
+
+
+
+
+
+ 26
+
настоящих форматов, каждый открывается в своей программе
+
+
+ 1 байт
+
точность каждого запрошенного размера, никогда не округляется молча
+
+
+ 0
+
соединений куда бы то ни было - без учётной записи, без телеметрии, без проверки обновлений
+
+
+
+
+
Проблема
+
Сделать один тестовый файл легко. Сделать нужную тысячу - вот утомительная часть
+
Вы тестируете программу, принимающую файлы от людей. Рано или поздно вам понадобятся:
+
+
PDF ровно на 10 МБ, чтобы выяснить, реален ли лимит загрузки
+
три файла по обе стороны этого лимита, чтобы поймать ошибки на единицу
+
10 000 файлов журнала, чтобы увидеть, что делает ночное задание, когда папка велика
+
ZIP, который действительно содержит 200 документов, а не пустышку с правильным расширением
+
файл на 4 ГБ без хранения файла на 4 ГБ в вашем репозитории
+
одинаковые фикстуры на ноутбуке и на сервере сборки, байт в байт
+
+
+ Именно это он заменяет. Он создан для QA-инженеров, автоматизации тестирования и всех, за чьим кодом
+ стоит форма загрузки, процедура импорта, парсер или квота хранилища.
+
+
+
+
+
Чем он отличается
+
Другие генераторы останавливаются на байтах. Этот отвечает на то, о чём на самом деле спрашивает ваш тест
+
+ Папка с файлами всё равно оставляет вам решать, что должен доказывать каждый из них. Каждый запуск
+ здесь записывает рядом с файлами manifest.json - простой список всего созданного и
+ для каждой записи заявленное ожидание.
+
+
Допустим, ваша точка загрузки допускает 1 МБ. Запросите три файла, лежащие на этой границе:
Там, где ответ зависит от вашей собственной политики, манифест так и говорит
+
+ Он записывает unspecified, а не придумывает ожидание. Генератор, который гадает, даёт
+ ложные сбои, а набор тестов, который кричит «волки», в итоге отключают.
+
+
+
+
+
+
Пресеты
+
Выберите вопрос, получите весь набор
+
+ Пресет - это набор тестовых файлов, продуманный вокруг одного тестового вопроса, чтобы вам не
+ пришлось выяснять, какие файлы что доказывают. У каждого есть страница о том, что он обычно
+ находит, что входит в набор и какие настройки принимает.
+
+ Десять тысяч файлов журнала, каждый от одного до восьми килобайт, с размерами из seed, чтобы завтра
+ получился тот же набор. Давайте каждому запуску свой каталог - манифест
+ остаётся единственной записью о том, что записал запуск, поэтому инструмент отказывается
+ записывать второй поверх него:
+
+ Размеры считаются по 1024, как в вашем файловом менеджере, поэтому 2mb означает 2097152
+ байта. Подойдёт и простое число байт. Документация охватывает рецепты,
+ манифест и коды завершения.
+
+
+
+
+
Что вы получаете
+
Создан для набора тестов, работающего без присмотра
+
+
+
Точный размер, до байта
+
Запросите 10485761 байт и получите ровно столько. Размер, которого формат не может достичь, - это ошибка с причиной, а не файл неверного размера.
+
+
+
26 настоящих форматов
+
Не нули-заполнители с расширением. Созданный PNG открывается в просмотрщике изображений, DOCX - в Word, ZIP распаковывается. Каждый формат проверяется независимыми читателями до выпуска.
+
+
+
Манифест, который служит тестовым оракулом
+
Путь, размер, SHA-256, формат, seed, версия инструмента - и то, что ваша система должна сделать с файлом.
+
+
+
Воспроизводимость
+
Тот же рецепт и тот же seed, те же байты на любой машине. Коммитьте небольшой рецепт YAML вместо больших бинарных фикстур.
+
+
+
Два интерфейса, один движок
+
Командная строка, созданная для CI, и десктопное окно для исследовательского тестирования. Ни один не урезанная версия другого, и тест сравнивает их возможность за возможностью.
+
+
+
Полностью офлайн
+
Нет учётной записи, облака, телеметрии и проверки обновлений. В бинарный файл командной строки вообще не скомпилирован сетевой стек.
+
+
+
+
+
+
Скачать
+
Выберите сборку для вашей системы
+
+ Распакуйте архив и запустите. tfg - это командная строка, а tfg-gui -
+ десктопное окно. Нет установщика и ничего, что нужно добавлять на вашу машину.
+
+
+
+
+
+
Система
+
Командная строка
+
Десктопное окно
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
Что подписано, а что нет
+
+ Сборки для Windows и macOS подписаны, поэтому запускаются без предупреждения о неизвестном
+ разработчике. Сборки для Linux не подписаны, потому что у десктопного Linux нет эквивалента,
+ которым их можно подписать. Каждый архив указан в verify-SHA256SUMS.txt на
+ странице релиза, так что вы можете проверить, что скачали.
+
Пройдёт ли корректный файл, настолько маленький, насколько позволяет формат?
+
+ Пресет empty-and-minimal одной командой собирает целый набор настоящих тестовых файлов для
+ этого вопроса и рядом manifest.json с ожидаемой реакцией вашей системы на каждый
+ файл. Всё ниже прочитано из программы со значениями по умолчанию этой версии.
+
+
+
+
+
Что он обычно находит?
+
+
корректный файл, отклонённый как слишком маленький, потому что проверка считает байты, а не читает их
+
пустой файл, который роняет читающий код вместо того, чтобы быть замеченным
+
картинка шириной в один пиксель, которая делит на ноль на пути к миниатюре
+
хранилище, которое воспринимает ноль байт как неудачную загрузку и бесконечно повторяет попытки
+
+
+
+
+
+
Что входит в набор?
+
Со значениями по умолчанию, как сообщает tfg preset show empty-and-minimal:
Сохранит, покажет и вернёт ли моя система имя файла, которого не ожидала?
+
+ Пресет filename-handling одной командой собирает целый набор настоящих тестовых файлов для
+ этого вопроса и рядом manifest.json с ожидаемой реакцией вашей системы на каждый
+ файл. Всё ниже прочитано из программы со значениями по умолчанию этой версии.
+
+
+
+
+
Что он обычно находит?
+
+
имя, которое на экране, в журнале или в списке выглядит как другое
+
имя, обрезанное, укороченное или переписанное между загрузкой и хранением
+
лимит длины, который считается в символах там, где хранилище считает байты
+
+
+
+
+
+
Что входит в набор?
+
Со значениями по умолчанию, как сообщает tfg preset show filename-handling:
+
+
+
+
Файлов
50
+
Целей в его рецепте
50
+
Общий размер
51 200 B
+
Форматы
txt
+
+
+
+
И чего манифест этого набора ожидает от вашей системы:
+
+
+
+
Ожидается
Значение
Файлов
+
+
+
accept
Ваша система должна принять файл.
4
+
unspecified
Зависит от правил вашей системы. Вы решаете, а затем проверяете, что происходит именно то, что вы имели в виду.
46
+
+
+
+
+
+
+
Что можно изменить?
+
+
+
+
Настройка
Принимает
По умолчанию
Что делает
+
+
+
+
--format
+
id формата со страницы форматов
+
txt
+
Формат каждого файла набора. Это флаг самого инструмента, а пресет лишь задаёт ему значение по умолчанию.
+
+
+
+
+
+
+
+
Как его запустить?
+
Посмотрите, чего стоил бы набор, соберите его или возьмите его рецепт для правки:
Пресеты тестовых файлов, по набору на каждый тестовый вопрос
+
+ Пресет - это целый набор тестовых файлов, продуманный вокруг одного вопроса, с манифестом об
+ ожидаемой реакции вашей системы на каждый файл. Вы выбираете вопрос, инструмент собирает набор. У
+ каждого пресета своя страница о том, что он обычно находит, что входит в набор и какие настройки
+ принимает.
+
Принимает ли моя форма загрузки то, что должна, и отклоняет ли остальное?
+
upload-validation
+
+
+
+
+
Чем пресет отличается от рецепта?
+
+ По сути ничем. Пресет - это рецепт, который инструмент пишет для вас из нескольких настроек.
+ tfg preset eject выводит этот рецепт, чтобы вы могли хранить его рядом с тестами и
+ править, а ваш собственный рецепт может опираться на пресет одной строкой: extends:
+ preset: и его id.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Можно ли доверять значениям по умолчанию?
+
+ Для файлов - да. Для числа, которое знает только ваша система, например лимита формы загрузки,
+ значение по умолчанию - наша временная подстановка, и инструмент говорит об этом каждый раз,
+ когда её использует. Страница каждого пресета отмечает такие настройки, а tfg preset
+ show сообщает об этом до записи чего-либо.
+
Применяется ли лимит размера ровно там, где он объявлен?
+
+ Пресет size-boundaries одной командой собирает целый набор настоящих тестовых файлов для
+ этого вопроса и рядом manifest.json с ожидаемой реакцией вашей системы на каждый
+ файл. Всё ниже прочитано из программы со значениями по умолчанию этой версии.
+
+
+
+
+
Что он обычно находит?
+
+
ошибки на единицу на границе лимита
+
МБ, перепутанные с МиБ, то есть 4,8 процента, чего достаточно, чтобы пропустить файл, который не должен проходить
+
лимит, который применяется в браузере, а не на сервере
+
+
+
+
+
+
Что входит в набор?
+
Со значениями по умолчанию, как сообщает tfg preset show size-boundaries:
+
+
+
+
Файлов
7
+
Целей в его рецепте
7
+
Общий размер
73 400 320 B
+
Форматы
pdf
+
+
+
+
И чего манифест этого набора ожидает от вашей системы:
+
+
+
+
Ожидается
Значение
Файлов
+
+
+
accept
Ваша система должна принять файл.
4
+
reject
Ваша система должна отклонить файл.
3
+
+
+
+
+
+
+
Что можно изменить?
+
+
+
+
Настройка
Принимает
По умолчанию
Что делает
+
+
+
+
--limit
+
размер, например 2mb
+
10mb
+
Лимит размера, который объявляет ваша система. Всё остальное отмеряется от него. Это значение по умолчанию - наша временная подстановка, а не значение вашей системы. Передайте своё.
+
+
+
--spread
+
размеры через запятую
+
1B,1kb,1mb
+
Как далеко отходить от лимита в обе стороны, списком размеров.
+
+
+
--format
+
id формата со страницы форматов
+
pdf
+
Формат каждого файла набора. Это флаг самого инструмента, а пресет лишь задаёт ему значение по умолчанию.
+
+
+
+
+
+
+
+
Как его запустить?
+
Посмотрите, чего стоил бы набор, соберите его или возьмите его рецепт для правки:
Переживёт ли мой импорт таблиц то, что экспортируют настоящие инструменты?
+
+ Пресет tabular-import одной командой собирает целый набор настоящих тестовых файлов для
+ этого вопроса и рядом manifest.json с ожидаемой реакцией вашей системы на каждый
+ файл. Всё ниже прочитано из программы со значениями по умолчанию этой версии.
+
+
+
+
+
Что он обычно находит?
+
+
файл с точкой с запятой, прочитанный как один столбец, потому что разделитель предположили, а не искали
+
файл CRLF, разбитый на строки с пустой строкой после каждой
+
таблица без заголовка, первая строка данных которой съедается как имена столбцов
+
импорт, который оставляет столбцы, что может показать, и молча отбрасывает остальные
+
читатель, который берёт записи JSON по одной строке и останавливается на первом документе с отступами
+
+
+
+
+
+
Что входит в набор?
+
Со значениями по умолчанию, как сообщает tfg preset show tabular-import:
+
+
+
+
Файлов
13
+
Целей в его рецепте
13
+
Общий размер
3 080 060 B
+
Форматы
csv, json, xlsx
+
+
+
+
И чего манифест этого набора ожидает от вашей системы:
+
+
+
+
Ожидается
Значение
Файлов
+
+
+
accept
Ваша система должна принять файл.
8
+
unspecified
Зависит от правил вашей системы. Вы решаете, а затем проверяете, что происходит именно то, что вы имели в виду.
5
+
+
+
+
+
+
+
Что можно изменить?
+
+
+
+
Настройка
Принимает
По умолчанию
Что делает
+
+
+
+
--rows
+
1 - 200000 строк
+
1000
+
Сколько строк в таблице. Файл записывается ровно того размера, в который упаковывается столько строк, поэтому бюджет выше меняется вместе с этим значением.
+
+
+
--columns
+
1 - 32768 столбцов
+
10
+
Сколько столбцов в каждой строке таблицы. У произведения строк на столбцы есть потолок, и запрос сверх него отклоняется до записи чего-либо.
+
+
+
+
+
+
+
+
Как его запустить?
+
Посмотрите, чего стоил бы набор, соберите его или возьмите его рецепт для правки:
Знает ли мой читатель, в какой кодировке файл, или угадывает?
+
+ Пресет text-encoding одной командой собирает целый набор настоящих тестовых файлов для
+ этого вопроса и рядом manifest.json с ожидаемой реакцией вашей системы на каждый
+ файл. Всё ниже прочитано из программы со значениями по умолчанию этой версии.
+
+
+
+
+
Что он обычно находит?
+
+
читатель, который предполагает UTF-8 и показывает файл UTF-16 с одним символом из трёх или рядами квадратиков
+
метка порядка байтов, прочитанная как содержимое, из-за чего первое поле импорта начинается с трёх лишних символов
+
импортёр, который угадывает кодировку по первым байтам и угадывает иначе для более длинного файла
+
файл CRLF, разбитый на строки с пустой строкой после каждой, или возврат каретки, оставшийся в последнем поле
+
+
+
+
+
+
Что входит в набор?
+
Со значениями по умолчанию, как сообщает tfg preset show text-encoding:
+
+
+
+
Файлов
20
+
Целей в его рецепте
20
+
Общий размер
81 920 B
+
Форматы
csv, log, md, txt, xml
+
+
+
+
И чего манифест этого набора ожидает от вашей системы:
+
+
+
+
Ожидается
Значение
Файлов
+
+
+
accept
Ваша система должна принять файл.
10
+
unspecified
Зависит от правил вашей системы. Вы решаете, а затем проверяете, что происходит именно то, что вы имели в виду.
10
+
+
+
+
+
+
+
Что можно изменить?
+
+
+
+
Настройка
Принимает
По умолчанию
Что делает
+
+
+
+
--sample
+
размер, например 2mb
+
4kb
+
Размер каждого файла набора. UTF-16 хранит по два байта на символ, поэтому нечётное число отклоняется.
+
+
+
+
+
+
+
+
Как его запустить?
+
Посмотрите, чего стоил бы набор, соберите его или возьмите его рецепт для правки:
Принимает ли моя форма загрузки то, что должна, и отклоняет ли остальное?
+
+ Пресет upload-validation одной командой собирает целый набор настоящих тестовых файлов для
+ этого вопроса и рядом manifest.json с ожидаемой реакцией вашей системы на каждый
+ файл. Всё ниже прочитано из программы со значениями по умолчанию этой версии.
+
+
+
+
+
Что он обычно находит?
+
+
лимит, который применяется в браузере, а не на сервере
+
SVG или HTML, принятый за картинку или простой текст, что позволяет провести скрипт через форму
+
файл, проверенный по расширению и ни разу не открытый, так что PDF с именем .jpg проходит
+
форма, которая читает всё тело в память, прежде чем посмотреть, насколько оно велико
+
загрузка с именем PHOTO.JPG отклонена там, где photo.jpg принимается, или наоборот
+
имя с пробелами, скобками или символами вне ASCII, записанное на диск без изменений
+
+
+
+
+
+
Что входит в набор?
+
Со значениями по умолчанию, как сообщает tfg preset show upload-validation:
+
+
+
+
Файлов
71
+
Целей в его рецепте
22
+
Общий размер
120 639 488 B
+
Форматы
html, jpg, pdf, png, svg, txt
+
+
+
+
И чего манифест этого набора ожидает от вашей системы:
+
+
+
+
Ожидается
Значение
Файлов
+
+
+
accept
Ваша система должна принять файл.
56
+
reject
Ваша система должна отклонить файл.
10
+
unspecified
Зависит от правил вашей системы. Вы решаете, а затем проверяете, что происходит именно то, что вы имели в виду.
5
+
+
+
+
+
+
+
Что можно изменить?
+
+
+
+
Настройка
Принимает
По умолчанию
Что делает
+
+
+
+
--limit
+
размер, например 2mb
+
10mb
+
Лимит размера, который объявляет ваша форма загрузки. Этот набор делает по одному шагу в обе стороны - для файла на любом расстоянии запустите пресет size-boundaries. Это значение по умолчанию - наша временная подстановка, а не значение вашей системы. Передайте своё.
+
+
+
--allow
+
id форматов через запятую
+
jpg,png,pdf
+
Какие типы должна принимать ваша форма. Каждый становится настоящим файлом этого типа, и вместе они служат положительным контролем всего набора.
+
+
+
--deny
+
расширения через запятую
+
svg,html,exe,sh
+
Какие расширения должна отклонять ваша форма. Расширение, для которого в этой сборке нет формата, всё равно получает файл с таким именем и простым текстом внутри.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
Насколько далеко за лимит заходит единственный большой файл. Отключите, если запись нескольких лимитов не стоит места на диске.
+
+
+
--bulk
+
0 - 10000 файлов
+
50
+
Сколько файлов в массовой загрузке. Ноль полностью убирает эту группу из набора.
+
+
+
+
+
+
+
+
Как его запустить?
+
Посмотрите, чего стоил бы набор, соберите его или возьмите его рецепт для правки:
+ Двоичная фикстура в репозитории остаётся в его истории навсегда, её нельзя проверить в диффе, и она
+ перестаёт быть возможной, когда файл велик. Генерируйте файлы внутри конвейера из рецепта. Рецепт
+ - это текст, байты каждый раз выходят одинаковыми, а последний шаг доказывает, что ничего не
+ сдвинулось.
+
+
+
+
Короткий ответ
+
+ Установите tfg, запустите tfg generate fixtures.yaml --out ./fixtures
+ перед тестами и tfg verify ./fixtures/manifest.json после них. Оба шага сами роняют
+ сборку, с кодом завершения, который говорит почему.
+
+
+
+
+
Почему не коммитить
+
Почему фикстуре не место в репозитории
+
+
+ Она остаётся в истории. Удаление двоичного файла позже не делает клон меньше,
+ потому что каждая его версия всё ещё там.
+
+
+ Дифф не показывает, что изменилось. Рецензент видит, что PDF другой, и ничего
+ больше. Рецепт меняется на одну строку.
+
+
+ Большие файлы не помещаются. GitHub отклоняет push, в котором есть файл больше 100
+ МБ, поэтому тесту лимита загрузки в 500 МБ нечего коммитить.
+
+
+
+ Коммитить нужно рецепт. Один и тот же рецепт с тем же зерном записывает одни и те же байты на любой
+ машине, поэтому файл, созданный в конвейере, - это файл, который был у вас на ноутбуке.
+
+
+
+
+
Рецепт
+
Рецепт, который лежит рядом с тестами
+
+ Этот записывает двадцать пять счетов, которые должны быть приняты, и два изображения сверх лимита,
+ которые должны быть отклонены, а манифест фиксирует оба ожидания:
+
+ Строка с контрольной суммой сверяет архив с verify-SHA256SUMS.txt из того же выпуска.
+ Версия зафиксирована, так что новый выпуск никогда не изменит сборку, которой вы не касались.
+
+ У каждого завершения свой код, так что шаг падает сам, а журнал говорит, какой именно. Те, что
+ встречает конвейер:
+
+
+
3 - рецепт недопустим. Ничего не записано, и названа каждая проблема
+
4 - формат не умеет того, что попросили, например размера меньше своего минимума
+
6 - не хватает места на диске
+
7 - tfg verify нашёл файл, не совпадающий со своим манифестом
+
8 - запуск закончился, но создано не всё
+
+
+ Неудачный запуск ничего не печатает в стандартный вывод, поэтому разборщик журналов никогда не
+ примет ошибку за данные. Вся таблица на странице документации.
+
+
+
+
+
PowerShell
+
Скрипту PowerShell нужна ещё одна строка
+
+ PowerShell не выносит код завершения программы из файла .ps1. Запустите такой файл с
+ -File, и скрипт ответит 0, даже когда инструмент внутри отказался
+ работать, так что сборка, которая должна быть красной, становится зелёной. Последняя строка -
+ это всё исправление:
+
+ Так ведёт себя PowerShell, а не этот инструмент. cmd, bash и
+ zsh ничего лишнего не требуют.
+
+
+
+
+
Несколько заданий
+
Как делиться фикстурами между заданиями
+
+ Обычно загружать их не нужно. Поскольку один и тот же рецепт записывает одни и те же байты, каждое
+ задание может запустить собственный tfg generate, что быстрее загрузки и
+ скачивания. Когда задание должно получить файлы от другого, запустите после передачи tfg
+ verify на манифесте, и он скажет, совпадает ли полученное с записанным.
+
+ Пять задач, которые возникают почти в каждом проекте, принимающем файлы от людей, и команда,
+ решающая каждую. Каждый пример ниже запускается как написано.
+
+
+
+
Лимиты загрузки
+
Проверка того, что лимит размера файла применяется там, где заявлено
+
+ Лимит - это три тестовых случая, а не один: чуть ниже, ровно по лимиту и чуть выше. Получить их
+ вручную значит считать числа байт и надеяться, что вы не ошиблись на единицу. Запросите вместо
+ этого набор:
+
+ Вы получите три настоящих PDF по 1048575, 1048576 и 1048577 байт и манифест, который говорит, что
+ первые два нужно принять, а третий отклонить по size_limit. Ваш тест читает
+ ожидание, вместо того чтобы вы писали три проверки вручную, а когда лимит меняется, вы меняете
+ одно число и запускаете заново.
+
+
+ То же работает и без пресета, когда нужен один набор границ прямо в команде:
+
+ Большие бинарные фикстуры замедляют клонирование репозитория и мешают ревью, а при замене никто не
+ может сказать, что изменилось. Рецепт - это несколько сотен символов YAML, которые пересоздают
+ те же файлы - байт в байт, на любой машине - потому что каждый файл выводится
+ из seed запуска.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ У каждого исхода свой код завершения, поэтому конвейер отличает плохой рецепт от полного диска и от
+ расхождения при проверке. Неудачный запуск ничего не печатает в стандартный вывод, и разборщик
+ журналов не принимает ошибку за данные.
+
+
+
+
+
Масштаб
+
Выяснить, что происходит, когда папка велика
+
+ Процедуры импорта, ночные задания и списки каталогов ведут себя иначе при десяти тысячах файлов, чем
+ при десяти. Размеры, выбранные из диапазона, делают набор похожим на настоящий трафик, а не на
+ десять тысяч одинаковых файлов, и выбор идёт от seed, так что завтра набор будет тем же.
+
+ Запуск больше свободного места на диске отклоняется до записи первого байта, а не заполняет диск и
+ не падает на полпути.
+
+
+
+
+
Архивы
+
Проверка распаковщика на архиве, который действительно содержит файлы
+
+ Пустой архив с правильным расширением ничего не доказывает о коде, который его открывает и обходит
+ содержимое. Объявите содержимое, и архив действительно его содержит:
+
+ Глубина вложенности, число записей и размер содержимого - это то, о чём у процедуры импорта есть
+ своё мнение, и так вы узнаёте, каково оно.
+
+
+
+
+
Парсеры и просмотрщики
+
Проверка того, что ваш собственный код читает формат так же, как настоящее ПО
+
+ Каждый формат здесь проверяется независимым читателем до выпуска: PNG открывается и сравниваются его
+ пиксели, DOCX перечитывается отдельными библиотеками, архив распаковывается. Это значит, что
+ файл, который отклоняет ваш парсер, - находка о вашем парсере, а не о генераторе.
+
+ Страница форматов перечисляет настройки каждого формата и наименьший
+ файл, каким он может быть.
+
+
+
+
+
Руководства
+
Два из них подробнее
+
+
+ Повреждённые тестовые файлы - файл, намеренно испорченный,
+ точного размера, с записанным в манифесте тем, что с ним должно произойти.
+
+
+ Тестовые файлы в CI - workflow для GitHub Actions, задание
+ GitLab и коды завершения, которые роняют сборку.
+
+
+
+
+
+
Для кого это
+
+ QA-инженеры, автоматизация тестирования и все, за чьим кодом стоит форма загрузки, процедура
+ импорта, парсер или квота хранилища. Работает на машине вообще без сети, что важно в закрытой
+ корпоративной среде, где генератор в браузере - не вариант.
+
+ A binary fixture in a repository stays in its history for good, cannot be reviewed in a diff, and
+ stops being possible once the file is large. Generate the files inside the pipeline from a recipe
+ instead. The recipe is text, the bytes come out the same every time, and a last step proves that
+ nothing moved.
+
+
+
+
The short answer
+
+ Install tfg, run tfg generate fixtures.yaml --out ./fixtures before the
+ tests, and tfg verify ./fixtures/manifest.json after them. Both steps fail the build
+ by themselves, with an exit code that says why.
+
+
+
+
+
Why not commit them
+
Why a fixture should not live in the repository
+
+
+ It stays in the history. Deleting a binary later does not make a clone smaller,
+ because every version of it is still there.
+
+
+ A diff cannot show what changed. A reviewer sees that a PDF is different and
+ nothing else. A recipe changes by a line.
+
+
+ Large files do not fit. GitHub refuses a push that holds a file over 100 MB, so
+ a test of a 500 MB upload limit has nothing to commit.
+
+
+
+ The recipe is the thing to commit. The same recipe and seed write the same bytes on every machine,
+ so the file generated in the pipeline is the file you had on your laptop.
+
+
+
+
+
The recipe
+
A recipe that lives beside the tests
+
+ This one writes twenty five invoices that should be accepted and two images over a limit that
+ should be turned away, and the manifest records both expectations:
+
+ The checksum line compares the archive with verify-SHA256SUMS.txt from the same
+ release. The version is pinned, so a new release never changes a build you did not touch.
+
+ Every ending has its own exit code, so the step fails on its own and the log says which one. The
+ ones a pipeline meets:
+
+
+
3 - the recipe is not valid. Nothing was written, and every problem is named
+
4 - the format cannot do what was asked, for example a size below its smallest
+
6 - there is not enough disk space
+
7 - tfg verify found a file that does not match its manifest
+
8 - the run finished, but not everything was produced
+
+
+ A failed run prints nothing on standard output, so a log parser never reads an error as data. The
+ whole table is on the documentation page.
+
+
+
+
+
PowerShell
+
A PowerShell script needs one more line
+
+ PowerShell does not carry the exit code of a program out of a .ps1 file. Run one with
+ -File and the script answers 0 even when the tool inside refused the
+ work, so a build that should be red goes green. The last line is the whole fix:
+
+ That is how PowerShell behaves, not something about this tool. cmd,
+ bash and zsh need nothing extra.
+
+
+
+
+
Several jobs
+
Sharing the fixtures between jobs
+
+ There is usually no need to upload them. Because the same recipe writes the same bytes, each job
+ can run its own tfg generate, which is quicker than an upload and a download. When a
+ job has to receive files from another, run tfg verify on the manifest after the
+ transfer, and it tells you whether what arrived is what was written.
+
+
+
+
+
Next
+
Where to go from here
+
+
+ Corrupt test files adds files that are broken on purpose to
+ the same recipe.
+
+
+ The use cases show what else a run in a pipeline can check.
+
บรรทัดคำสั่งทำงานบน Windows และ Linux ทั้ง Intel และ ARM และบน Mac ที่ใช้ Apple Silicon หน้าต่างเดสก์ท็อปมีให้สำหรับ Windows บน Intel, Linux บน Intel และ Mac ที่ใช้ Apple Silicon ไม่รองรับ Mac แบบ Intel และไม่มีการสร้างบิลด์สำหรับเครื่องเหล่านั้น
+
+
+
+
ต้องติดตั้งอะไรไหม
+
+
ไม่ ดาวน์โหลดไฟล์บีบอัดสำหรับระบบของคุณ แตกไฟล์ แล้วรันไบนารี ไม่มีตัวติดตั้ง ไม่มีรันไทม์ที่ต้องเพิ่ม และไม่มีไลบรารีที่ต้องแก้ ถ้าคุณมี Go คำสั่ง go install เพียงคำสั่งเดียวก็ใช้ได้เช่นกัน
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
ทำไมการรันกับไฟล์นับพันจึงช้ากว่าบน Windows
+
+
เพราะ Windows คิดค่าใช้จ่ายมากกว่าสำหรับทุกพาธที่มันดู และคำสั่งที่วนผ่านไฟล์นับพันก็ดูพาธนับพัน วัดบนเครื่องหนึ่งที่มีไฟล์ขนาด 1 kB จำนวน 3000 ไฟล์ verify ใช้เวลาประมาณ 0.9 วินาทีบน Windows และประมาณ 0.2 วินาทีบน Linux ในคอนเทนเนอร์ พาธเอาต์พุตที่สั้นลงทำให้ตัวเลขบน Windows น้อยลง เพราะทุกโฟลเดอร์เหนือไฟล์เป็นส่วนหนึ่งของสิ่งที่ถูกดู
บรรทัดคำสั่งที่สร้างมาสำหรับ CI และหน้าต่างเดสก์ท็อปสำหรับการทดสอบเชิงสำรวจ ไม่มีอันใดเป็นฉบับตัดทอนของอีกอัน และมีการทดสอบเปรียบเทียบทั้งสองทีละความสามารถ
+ Bunların her biri o biçimde gerçek bir dosyadır. Ait olduğu programda açılır ve tam
+ istediğiniz bayt sayısındadır. Hiçbiri yapıştırılmış uzantılı dolgu sıfırları değildir.
+
+
+
+
+
+
+
Biçim
+
Ad
+
Uzantı
+
En küçük dosya
+
Bütünlük
+
Doğrulayan
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
uygulanamaz
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
uygulanamaz
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
uygulanamaz
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
Sütunların anlamı
+
+
+
En küçük dosya
+
+ Bu aracın o biçim için kabul edeceği en az bayt sayısı, dosyanın içine yazdığı etiket dahil. Daha
+ azını isterseniz alt sınırı ve nedenini adlandıran bir hata alırsınız, asla yanlış boyutta
+ bir dosya değil.
+
+
+
+
Bütünlük
+
+ Dosyanın ne kadar tam olduğu. full, biçimi gerçekten ayrıştıran bir okuyucunun onu
+ kabul ettiği anlamına gelir, yalnızca uzantının uyduğu anlamına değil.
+
+
+
+
Doğrulayan
+
+ Biçim yayımlanmadan önce üretilen her dosyayı açan bağımsız okuyucu - ayrı bir uygulama, kendi
+ ödevini kendi notlayan bizim kodumuz değil.
+
+
+
+
+ Her biçim ayrıca bayta kadar tekrarlanır: aynı tarif ve aynı seed her makinede özdeş dosyalar üretir
+ ve bir tarifi fixture'ların kendisi yerine commit etmeyi güvenli kılan budur.
+
+
+
+
+
Her biçimin kabul ettiği ayarlar
+
+ Çoğu biçimin kendi ayarları vardır - görüntü boyutları, JPEG kalitesi, PDF sayfa sayısı, bir
+ elektronik tablodaki satır ve sütunlar, bir arşivin içine kaç girdi gireceği. Bunları komut
+ satırında --set key=value ile veya bir tarifte properties: altında
+ ayarlayın.
+
2024-02-29 veya 2024-02-29T13:45:00+02:00 gibi bir tarih, veya none
+
+
+
+
modified
+
2024-02-29 veya 2024-02-29T13:45:00+02:00 gibi bir tarih, veya none
+
+
+
png
+
width
+
1 - 20000 piksel
+
+
+
+
height
+
1 - 20000 piksel
+
+
+
pptx
+
slides
+
1 - 500 slayt
+
+
+
svg
+
width
+
1 - 20000 piksel
+
+
+
+
height
+
1 - 20000 piksel
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
tfg formats'ın listelediği gibi bir biçimin kimliği
+
+
+
+
entry_size
+
2mb gibi bir boyut
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
doğru veya yanlış
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 piksel
+
+
+
+
height
+
1 - 20000 piksel
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
doğru veya yanlış
+
+
+
wav
+
sample_rate
+
8000 - 192000 hertz
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 piksel
+
+
+
+
height
+
1 - 16383 piksel
+
+
+
xlsx
+
rows
+
1 - 200000 satır
+
+
+
+
columns
+
1 - 32768 sütun
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
doğru veya yanlış
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
tfg formats'ın listelediği gibi bir biçimin kimliği
+
+
+
+
entry_size
+
2mb gibi bir boyut
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
doğru veya yanlış
+
+
+
+
password
+
parola, düz metin olarak
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ Bir ayarın kabul ettiğinin dışındaki değer, ayarı, izin verilen aralığı ve onun yerine ne
+ kullanılacağını söyleyen bir iletiyle reddedilir. Bilinmeyen bir ayar da hatadır, asla sessiz
+ bir varsayılan değil - sessizce kabul edilen bir yazım hatası yanlış ayarlı bir dosya ve testin
+ geçmemesi gerekirken neden geçtiğini merak ederek geçen bir saat verir.
+
+
+ Elinizdeki sürümde bir biçimin tam olarak ne kabul ettiğini görmek için tfg formats
+ <id> çalıştırın.
+
+
+
+
+
Arşivler gerçek dosyalar içerir
+
+ targz ve zip boş
+ bir kabuk olarak bırakılmak yerine girdilerle doldurulabilir. Üretilmiş bir arşiv, içerdiğini
+ söylediği belgeleri gerçekten içerir, bu yüzden bir test sırasında onu açan her şey içinde
+ gerçek dosyalar bulur.
+
+ Yalnızca sağlam dosyalar gösterilmiş bir doğrulayıcı gerçekten sınanmış sayılmaz. İşte kasıtlı
+ bozulmuş, tam istediğiniz boyutta çıkan ve sisteminizin onunla ne yapması
+ gerektiğini söyleyen bir bildirimle gelen bir dosyayı nasıl elde edeceğiniz.
+
+
+
+
Kısa yanıt
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out tam 2097152 bayt
+ boyutunda, ilk baytları sıfır olan bir PNG yazar ve yanındaki bildirim sisteminizin onu
+ reddetmesi gerektiğini kaydeder.
+
+
+
+
+
Olağan yol
+
Elle bozulmuş bir dosya neden kötü bir testtir
+
+ Olağan yollar bir onaltılık düzenleyici, birkaç rastgele baytı çeviren bir betik ya da bir dosyayı
+ head veya truncate ile kısaltmaktır. Bir kez işe yarar, sonra size
+ pahalıya mal olur:
+
+
+
+ Her seferinde farklıdır. Rastgele bir bayt her çalıştırmada başka bir yere düşer,
+ bu yüzden salı günkü bir hata çarşamba dönmeyebilir.
+
+
+ Boyutu değiştirir. Kesilmiş bir dosya, altında kalması gereken sınırdan küçüktür.
+ Böylece boyut denetimi içerik denetiminden önce yanıt verir ve test yanlış nedenle geçer.
+
+
+ Çoğu zaman fark edilmez. Düz metin ortasında değişmiş bir baytla da okunur,
+ hoşgörülü bir görüntü okuyucusu ise onu olduğu gibi çizer. Böylece bozuk olması gereken dosya
+ kabul edilir.
+
+
+ Ne olması gerektiğini söylemez. Dosya yalnızca bayttır ve testi sonradan okuyan,
+ kabulün mü reddin mi amaçlandığını tahmin etmek zorunda kalır.
+
+
+
+
+
+
Ne elde edersiniz
+
Hasarlı bir dosya yine istediğiniz boyuttadır
+
+ Dosya normal üretilir, sonra diske giderken bozulur. İstediğiniz boyutu korur ve aynı komut yine
+ aynı baytları yazar.
+
+ Ayarlar iki noktadan sonra yazılır. Seçenek tekrarlanabilir ve hasarlar yazdığınız sırayla
+ uygulanır. 26 biçimin her biriyle çalışır.
+
+
+
+
+
Neler yapabilir
+
Hangi hasarlar var?
+
+ Bu, programın yazdırdığı listedir ve bu sayfa oluşturulurken programdan okunur. tfg
+ damage aynısını yazdırır, tfg damage <id> ise birinin neyi kabul
+ ettiğini söyler.
+
+
+
+
+
+
Hasar
+
Baytlara ne yapar
+
En küçük dosya
+
Ayarlar
+
+
+
+
+
zero-head
+
Dosyanın ilk baytlarını uzunluğuna dokunmadan sıfırlarla ezer. Okuyucuların çoğu önce oraya bakar, bu yüzden hemen her şey bu hasarı fark eder.
+
8
+
bytes
+
+
+
+
+
+ zero-head dosyanın başına sıfırlar yazar. Okuyucuların çoğu önce oraya bakar, dosyanın
+ ne olduğunu söyleyen imzaya ve başlığa, bu yüzden hemen her okuyucu fark eder. Düz metin ve
+ günlüklerin imzası yoktur ve onlar da reddedilir, çünkü bir sıfır baytı dizisi metin değildir.
+ Dört baytın altında bazı biçimler hiçbir okuyucunun şikâyet etmediği bir hasarla çıkar, ayarın
+ dörtten başlamasının nedeni budur.
+
+
+
+
+
Bildirim ne söyler
+
Ne olması gerektiğini söyleyen bir bildirim
+
+ Hasarlı her dosya, sisteminizin onu reddetmesi gerektiğini söyleyen bir kayıt alır ve hasar yanına
+ yazılır:
+
+ İki istek, bir şey yazılmadan önce reddedilir, çünkü her biri diskte bildirimin yanlış tarif ettiği
+ bir dosya bırakırdı:
+
+
+
hasarın gerektirdiğinden küçük bir dosya, ki değişmeden çıkardı
+
+ Bir hasarın yanında expected: accept, çünkü hiçbir şey bunu karşılayamaz. Sisteminiz
+ dosyayı onarmalıysa sanitize, tam da bunu soruyorsanız unspecified
+ yazın
+
+
+
+
+
+
Bir tarifte
+
Tek çalıştırmada sağlam ve bozuk dosyalar
+
+ İkisini de tek bir tarife koyun, bildirim her dosyanın beklentisini taşır. Böylece testin hangisinin
+ hangisi olduğuna dair bir listeye ihtiyacı kalmaz:
+
+ Test bildirimi okur ve olanın bildirilenle aynı olup olmadığına bakar. Dosya adı listesine ihtiyacı
+ yoktur:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ İyi bir ret temiz bir rettir. Neyin yanlış olduğunu söyleyen bir ileti istediğiniz yanıttır. Sunucu
+ hatası, takılma ya da yarım kaydedilmiş dosya, bu testin bulmak için var olduğu kusurdur.
+
+ Bir depodaki ikili fixture sonsuza dek geçmişinde kalır, bir diff'te incelenemez ve dosya
+ büyüdüğünde olanaksız hale gelir. Bunun yerine dosyaları hat içinde bir tariften üretin. Tarif
+ metindir, baytlar her seferinde aynı çıkar ve son bir adım hiçbir şeyin kaymadığını kanıtlar.
+
+
+
+
Kısa yanıt
+
+ tfg'yi kurun, testlerden önce tfg generate fixtures.yaml --out ./fixtures,
+ sonra tfg verify ./fixtures/manifest.json çalıştırın. Her iki adım da derlemeyi
+ kendiliğinden başarısız kılar ve nedenini söyleyen bir çıkış koduyla bunu yapar.
+
+
+
+
+
Neden commit edilmez
+
Bir fixture neden depoda durmamalı
+
+
+ Geçmişte kalır. Bir ikili dosyayı sonradan silmek klonu küçültmez, çünkü onun her
+ sürümü hâlâ oradadır.
+
+
+ Diff neyin değiştiğini göstermez. İnceleyen kişi bir PDF'nin farklı olduğunu görür,
+ başka bir şey değil. Bir tarif ise bir satırla değişir.
+
+
+ Büyük dosyalar sığmaz. GitHub, 100 MB'ın üzerinde bir dosya içeren bir push'u
+ reddeder. Bu yüzden 500 MB'lık bir yükleme sınırı testinin commit edecek bir şeyi olmaz.
+
+
+
+ Commit edilecek olan tariftir. Aynı tarif ve aynı tohum her makinede aynı baytları yazar, bu yüzden
+ hatta üretilen dosya dizüstünüzde sahip olduğunuz dosyadır.
+
+
+
+
+
Tarif
+
Testlerin yanında duran bir tarif
+
+ Bu tarif, kabul edilmesi gereken yirmi beş fatura ile bir sınırın üzerinde olup reddedilmesi gereken
+ iki görüntü yazar ve bildirim iki beklentiyi de kaydeder:
+
+ Sağlama toplamı satırı arşivi aynı sürümdeki verify-SHA256SUMS.txt ile karşılaştırır.
+ Sürüm sabitlenmiştir, bu yüzden yeni bir sürüm dokunmadığınız bir derlemeyi asla değiştirmez.
+
+ Her sonun kendi çıkış kodu vardır, bu yüzden adım kendiliğinden başarısız olur ve günlük hangisi
+ olduğunu söyler. Bir hattın karşılaştıkları:
+
+
+
3 - tarif geçerli değil. Hiçbir şey yazılmadı ve her sorun adlandırıldı
+
4 - biçim istenileni yapamıyor, örneğin kendi en küçüğünün altında bir boyut
+
6 - yeterli disk alanı yok
+
7 - tfg verify bildirimiyle uyuşmayan bir dosya buldu
+
8 - çalıştırma bitti ama her şey üretilmedi
+
+
+ Başarısız bir çalıştırma standart çıktıya hiçbir şey yazmaz, bu yüzden bir günlük ayrıştırıcısı
+ hatayı asla veri sanmaz. Tablonun tamamı belgeler
+ sayfasında.
+
+
+
+
+
PowerShell
+
Bir PowerShell betiği bir satır daha ister
+
+ PowerShell, bir programın çıkış kodunu bir .ps1 dosyasının dışına taşımaz. Birini
+ -File ile çalıştırın. İçindeki araç işi reddetse bile betik 0 yanıtı
+ verir ve kırmızı olması gereken bir derleme yeşile döner. Son satır düzeltmenin tamamıdır:
+
+ PowerShell böyle davranır, bu aracla ilgili bir şey değildir. cmd, bash ve
+ zsh fazladan hiçbir şeye gerek duymaz.
+
+
+
+
+
Birkaç iş
+
Fixture'ları işler arasında paylaşmak
+
+ Genellikle yüklemeye gerek yoktur. Aynı tarif aynı baytları yazdığı için her iş kendi tfg
+ generate komutunu çalıştırabilir ve bu, yükleyip indirmekten daha hızlıdır. Bir işin
+ başka bir işten dosya alması gerekiyorsa, aktarımdan sonra bildirim üzerinde tfg
+ verify çalıştırın. Gelenin yazılanla aynı olup olmadığını söyler.
+
+ Aracın yaptığı her şey, insanların gerçekten geldiği sorular şeklinde düzenlendi.
+ Depodaki README tam başvurudur ve her zaman indirdiğiniz sürümle
+ eşleşir.
+
+
+
+
Hangi komutlar var?
+
Her biri tek bir iş yapar:
+
tfg generate tariften veya bayraklardan dosya üret
+tfg validate bir tarifi denetle, hiçbir şey yazma
+tfg verify bir dizini bir manifeste göre denetle
+tfg cleanup bir manifestin listelediği dosyaları sil
+tfg recipe fmt bir tarifi oturmuş biçiminde yazdır
+tfg preset adlandırılmış bir test sorusundan dosya seti oluştur
+tfg formats bu sürümün desteklediği biçimleri listele
+tfg damage bu sürümün bir dosyayı kasıtlı bozma yollarını listele
+tfg tool elinizdeki dosyalar için küçük araçlar
+tfg version araç sürümünü yazdır
+tfg license lisansı ve üretilen dosyalar için anlamını yazdır
+
+
+
+
Tam boyutta tek bir dosyayı nasıl üretirim?
+
+ Biçimi, boyutu ve nereye gideceğini söyleyin. Boyutlar 1024'lerle sayılır, yani 2mb
+ 2097152 bayttır. Düz bir bayt sayısı da olur, yani --size 10485761 tam o kadarını
+ ister.
+
+
tfg generate --format png --size 2mb --out ./out
+
generate için işe yarar bayraklar:
+
+
+
Bayrak
Ne yapar
+
+
--format <id>
dosyaların biçimi, örneğin txt
+
--size <size>
her dosyanın tam boyutu, 10mb gibi veya düz bir bayt sayısı
+
--size-range <a-b>
bir aralıktan dosya başına çekilen boyut, 1kb-8kb gibi. Çekiliş seed'den gelir
+
--boundary <size>
bir sınırın çevresinde üç dosya: bir bayt altı, sınırın kendisi, bir bayt üstü
+
--count <n>
kaç dosya üretileceği. Varsayılan 1
+
--name <template>
ad şablonu, örneğin invoice_{index:04}.txt
+
--out <dir>
yazılacak dizin
+
--seed <n>
çalıştırmanın seed'i. Aynı seed aynı baytları verir
+
--set <k>=<v>
bir biçim ayarı, tekrarlanabilir
+
--damage <name>
dosyaları kasıtlı bozar, tekrarlanabilir ve sırayla uygulanır. Liste için tfg damage çalıştırın
+
--expected <outcome>
accept, reject, sanitize veya unspecified
+
--dry-run
say ve göster, hiçbir şey yazma
+
--json
manifesti standart çıktıya yaz
+
+
+
+
+
+
+
Kasıtlı bozuk bir dosyayı nasıl yaparım?
+
+ Bu aracın yazdığı diğer her dosya yapısı gereği doğrudur ve bu, bir yükleme doğrulayıcısının sorduğu
+ üç sorudan ikisini yanıtlar. --damage üçüncüsünü yanıtlar - dosya hiç açılıyor mu.
+ Dosya normal üretilir, sonra bozulur, böylece hâlâ istediğiniz boyuttadır.
+
+ Ayarlar iki noktadan sonra gelir. Bayrak tekrarlanır ve yazdığınız sıra uygulanma sırasıdır.
+ tfg damage bu sürümün neler yapabildiğini ve her birinin ne aldığını listeler.
+
+
Bir tarifte anahtar, adlardan veya ayarlardan oluşan bir listedir:
+ Hasarlı bir dosya manifestte expected: reject alır, hasar yanında kaydedilir. İki şey
+ bir şey yazılmadan önce reddedilir, çünkü her biri aksi hâlde diske manifestin yanlış tarif
+ ettiği bir dosya koyardı:
+
+
+
hasarın gerektirdiğinden küçük bir dosya, çünkü değişmeden çıkardı
+
+ bir hasarın yanında expected: accept, çünkü hiçbir şey bunu karşılayamaz. Test edilen
+ sistemin dosyayı onarması amaçlanıyorsa sanitize, sorduğunuz soru buysa
+ unspecified yazın
+
+
+
+ Üçüncüsü önceden bilinemez. Bir hasar çalışıp hiçbir baytı oynatmazsa o dosya yazılmak yerine atılır
+ - çalıştırma sürer, hangi dosya olduğunu söyler ve kısmi çıkış koduyla biter.
+
+ Tarif, tüm bir çalıştırmayı anlatan bir YAML dosyasıdır. Testlerinizin yanına commit edin,
+ fixture'lar deponuzda ikili dosya olmaktan çıkar - herkes onları birkaç yüz karakterlik bir
+ dosyadan bayt bayt yeniden kurabilir.
+
+ Her target, size, size-range, boundary veya
+ contains anahtarlarından tam birine ihtiyaç duyar. İkisi hatadır, hiçbiri de öyle.
+ Geçersiz bir tarif hiç dosya yazmaz ve yalnızca ilkini değil tüm sorunları bir
+ seferde bildirir, her biri ilgili ayarı adlandırır.
+
+
+
+
+
Sistemimin bir dosyayla ne yapması gerektiğini nasıl bildiririm?
+
Sonuç yeterliyse kısa biçim, neden önemliyse uzun biçim:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Sonuçlar accept, reject, sanitize ve
+ unspecified. Nedenler, bir rapor onlara göre gruplayabilsin diye kapalı bir
+ listedir: content_malformed, count_limit,
+ dimensions_limit, duplicate, encoding_invalid,
+ extension_rule, filename_invalid, filename_too_long,
+ filename_traversal, malware_signature, mime_mismatch,
+ nesting_depth, none, size_limit ve
+ size_zero.
+
+
+ Bir neden söz konusu kuralı adlandırır, hükmü değil. Bu yüzden aynı neden iki
+ sonucun altında da durabilir - sınırın bir bayt altındaki dosya accept olur ve söz
+ konusu kural yine size_limit kalır.
+
+
+
+
+
Manifestte ne var?
+
+ Her çalıştırmanın sonunda, kesilen çalıştırma dahil, dosyaların yanına yazılır. Dosya başına bir
+ girdi:
+
+ Çalıştırma bir tariften geldiyse bir recipe_hash, bir hazır ayardan geldiyse
+ overrides ile birlikte preset eklenir, böylece bir manifest her zaman
+ onu üreten şeye kadar izlenebilir.
+
+
+ Her girdi ayrıca dosyayı üreten tarifteki hedefin kimliği olan target_id taşır ve
+ summary.by_target her hedefin kaç dosyaya vardığını sayar. Birkaç hedefli bir tarif
+ böylece dosya adlarını okumadan hedef hedef denetlenebilir.
+
+
+
+
+
Hazır ayar nedir?
+
+ Yaygın bir test sorusunu yanıtlayan hazır bir dosya seti, böylece seti kendiniz tasarlamanız
+ gerekmez. Hazır ayarlar altta sıradan tariflerdir ve eject tarifi yazdırır, oradan
+ düzenleyebilirsiniz. Her hazır ayarın genelde ne bulduğunu, sette ne olduğunu ve kabul ettiği
+ her ayarı anlatan kendi sayfası vardır.
+
+ show, seti kurmadan önce neye mal olacağını söyler ve bir sayının sizin sınırınız değil
+ bizim geçici değerimiz olduğunu açıkça belirtir.
+
+
+
+
+
Çıkış kodları ne anlama gelir?
+
+ Her sonun kendi kodu vardır, makine tarafından okunabilir çıktı standart çıktıya gider ve başarısız
+ bir çalıştırma orada hiçbir şey yazdırmaz. Tablo dondurulmuş bir sözleşmedir - bir kodun
+ anlamını değiştirmek büyük sürüm artışı gerektirir.
+
+
+
+
+
+
Kod
+
Anlamı
+
+
+
+
+
0
+
Her şey çalıştı.
+
+
+
1
+
Araç içinde beklenmeyen bir hata.
+
+
+
2
+
Yanlış komut veya bayrak.
+
+
+
3
+
Tarif geçerli değil.
+
+
+
4
+
Biçim istenen şeyi yapamıyor.
+
+
+
5
+
Bir okuma veya yazma başarısız oldu.
+
+
+
6
+
Yeterli disk alanı yok.
+
+
+
7
+
verify bir uyuşmazlık buldu.
+
+
+
8
+
Çalıştırma bitti ama her şey üretilmedi.
+
+
+
130
+
Ctrl+C ile kesildi.
+
+
+
143
+
Bir sinyalle durduruldu, CI zaman aşımı böyle görünür.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Ctrl+C ile durdurulan bir çalıştırma yine bir manifest bırakır ve asla yarım yazılmış bir dosya
+ bırakmaz, böylece iptal edilen bir işi bir sonraki temizleyebilir.
+
+ Evet, betiklenmeyen test için üzerine bir pencere konmuş aynı motor. Kırpılmış bir sürüm değildir:
+ bir test iki arayüzü yetenek yetenek karşılaştırır ve yalnızca birinin yapabildiği her şey
+ sessizce ayrışmak yerine bildirilip gerekçelendirilmelidir.
+
+
+ Ekranlar tek bir grup, hazır ayarlar, aynı anda birkaç grup ve hakkında. Bir çalıştırmanın neye mal
+ olacağını bir şey yazmadan önce gösterir, çalışırken ilerlemeyi bildirir ve yarım yazılmış dosya
+ bırakmadan yarıda iptal edilebilir. Henüz bir tarif dosyası açmaz - tarifler şimdilik komut
+ satırının işidir ve pencere gruplarını formda kurar.
+
Biçimin izin verdiği kadar küçük, geçerli bir dosya geçer mi?
+
+ empty-and-minimal hazır ayarı, bu soru için tek komutla gerçek test dosyalarından oluşan bütün
+ bir set ve yanında sisteminizin her dosyaya nasıl tepki vermesi gerektiğini söyleyen bir
+ manifest.json kurar. Aşağıdaki her şey programdan, bu sürümün varsayılanlarıyla
+ okunur.
+
+
+
+
+
Genelde ne bulur?
+
+
kontrol baytları okumak yerine saydığı için çok küçük diye reddedilen geçerli bir dosya
+
bildirilmek yerine okuyucuyu çökerten boş bir dosya
+
küçük resme giderken sıfıra bölen bir piksel genişliğinde görüntü
+
sıfır baytı başarısız yükleme sayıp durmadan yeniden deneyen depolama
+
+
+
+
+
+
Sette ne var?
+
Varsayılanlarda, tfg preset show empty-and-minimal çıktısının bildirdiği gibi:
Sistemim beklemediği bir dosya adını saklayıp gösterecek ve geri verecek mi?
+
+ filename-handling hazır ayarı, bu soru için tek komutla gerçek test dosyalarından oluşan bütün
+ bir set ve yanında sisteminizin her dosyaya nasıl tepki vermesi gerektiğini söyleyen bir
+ manifest.json kurar. Aşağıdaki her şey programdan, bu sürümün varsayılanlarıyla
+ okunur.
+
+
+
+
+
Genelde ne bulur?
+
+
ekranda, bir günlükte veya bir listede başka bir ad gibi görünen bir ad
+
yükleme ile depolama arasında kesilen, kırpılan veya yeniden yazılan bir ad
+
depolama bayt sayarken karakterle sayılan bir uzunluk sınırı
+
+
+
+
+
+
Sette ne var?
+
Varsayılanlarda, tfg preset show filename-handling çıktısının bildirdiği gibi:
+
+
+
+
Dosya
50
+
Tarifindeki hedefler
50
+
Toplam boyut
51 200 B
+
Biçimler
txt
+
+
+
+
Ve o setin manifestinin sisteminizden beklediği:
+
+
+
+
Beklenen
Anlamı
Dosya
+
+
+
accept
Sisteminiz dosyayı kabul etmeli.
4
+
unspecified
Sisteminizin kurallarına bağlı. Siz karar verirsiniz, sonra olanın amaçladığınız şey olduğunu doğrularsınız.
46
+
+
+
+
+
+
+
Neyi değiştirebilirsiniz?
+
+
+
+
Ayar
Aldığı
Varsayılan
Ne yapar
+
+
+
+
--format
+
biçimler sayfasındaki bir biçim kimliği
+
txt
+
Setteki her dosyanın biçimi. Aracın kendi bayrağıdır ve hazır ayar yalnızca ona bir varsayılan verir.
+
+
+
+
+
+
+
+
Nasıl çalıştırılır?
+
Setin neye mal olacağına bakın, kurun veya düzenlemek için tarifini alın:
Test dosyası hazır ayarları, her test sorusu için bir set
+
+ Hazır ayar, tek bir soru etrafında tasarlanmış, sisteminizin her dosyaya nasıl tepki vermesi
+ gerektiğini söyleyen bir manifestle gelen bütün bir test dosyası setidir. Soruyu siz seçersiniz,
+ aracın seti kurar. Her hazır ayarın genelde ne bulduğunu, sette ne olduğunu ve kabul ettiği her
+ ayarı anlatan kendi sayfası vardır.
+
Yükleme formum alması gerekeni alıp geri kalanı reddediyor mu?
+
upload-validation
+
+
+
+
+
Hazır ayar bir tariften nasıl farklıdır?
+
+ Altta, hiç farklı değildir. Hazır ayar, aracın sizin için birkaç ayardan yazdığı bir tariftir.
+ tfg preset eject o tarifi yazdırır, böylece testlerinizin yanında tutup
+ düzenleyebilirsiniz ve kendi tarifiniz tek satırla bir hazır ayarın üzerine kurulabilir:
+ extends: preset: ve ardından kimliği.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Varsayılanlara güvenebilir miyim?
+
+ Dosyalar için evet. Yükleme formunun sınırı gibi yalnızca sisteminizin bildiği bir sayı için
+ varsayılan bizim geçici değerimizdir ve araç birini kullandığı her seferde bunu söyler. Her
+ hazır ayarın sayfası bu ayarları işaretler ve tfg preset show bir şey yazılmadan
+ önce söyler.
+
Bir boyut sınırı tam bildirildiği yerde uygulanıyor mu?
+
+ size-boundaries hazır ayarı, bu soru için tek komutla gerçek test dosyalarından oluşan bütün
+ bir set ve yanında sisteminizin her dosyaya nasıl tepki vermesi gerektiğini söyleyen bir
+ manifest.json kurar. Aşağıdaki her şey programdan, bu sürümün varsayılanlarıyla
+ okunur.
+
+
+
+
+
Genelde ne bulur?
+
+
sınırda bir eksik veya fazla hataları
+
MB ile MiB'in karıştırılması, yani yüzde 4,8, geçmemesi gereken bir dosyayı geçirmeye yeter
+
tarayıcıda uygulanan ama sunucuda uygulanmayan bir sınır
+
+
+
+
+
+
Sette ne var?
+
Varsayılanlarda, tfg preset show size-boundaries çıktısının bildirdiği gibi:
+
+
+
+
Dosya
7
+
Tarifindeki hedefler
7
+
Toplam boyut
73 400 320 B
+
Biçimler
pdf
+
+
+
+
Ve o setin manifestinin sisteminizden beklediği:
+
+
+
+
Beklenen
Anlamı
Dosya
+
+
+
accept
Sisteminiz dosyayı kabul etmeli.
4
+
reject
Sisteminiz dosyayı reddetmeli.
3
+
+
+
+
+
+
+
Neyi değiştirebilirsiniz?
+
+
+
+
Ayar
Aldığı
Varsayılan
Ne yapar
+
+
+
+
--limit
+
2mb gibi bir boyut
+
10mb
+
Sisteminizin bildirdiği boyut sınırı. Geri kalan her şey buradan ölçülür. Bu varsayılan sizin sisteminizin değeri değil, bizim geçici değerimizdir. Kendinizinkini verin.
+
+
+
--spread
+
virgülle ayrılmış boyutlar
+
1B,1kb,1mb
+
Sınırın iki yanında ne kadar uzağa gidileceği, boyutlar listesi olarak.
+
+
+
--format
+
biçimler sayfasındaki bir biçim kimliği
+
pdf
+
Setteki her dosyanın biçimi. Aracın kendi bayrağıdır ve hazır ayar yalnızca ona bir varsayılan verir.
+
+
+
+
+
+
+
+
Nasıl çalıştırılır?
+
Setin neye mal olacağına bakın, kurun veya düzenlemek için tarifini alın:
Tablo içe aktarmam gerçek araçların dışa aktardıklarına dayanıyor mu?
+
+ tabular-import hazır ayarı, bu soru için tek komutla gerçek test dosyalarından oluşan bütün
+ bir set ve yanında sisteminizin her dosyaya nasıl tepki vermesi gerektiğini söyleyen bir
+ manifest.json kurar. Aşağıdaki her şey programdan, bu sürümün varsayılanlarıyla
+ okunur.
+
+
+
+
+
Genelde ne bulur?
+
+
ayırıcı aranmak yerine varsayıldığı için tek sütun olarak okunan noktalı virgüllü dosya
+
her satırdan sonra boş bir satırla satırlara bölünen CRLF dosyası
+
ilk veri satırı sütun adı diye yutulan başlıksız bir tablo
+
gösterebildiği sütunları tutup geri kalanını tek söz etmeden atan bir içe aktarma
+
JSON kayıtlarını satır satır alıp ilk girintili belgede duran bir okuyucu
+
+
+
+
+
+
Sette ne var?
+
Varsayılanlarda, tfg preset show tabular-import çıktısının bildirdiği gibi:
+
+
+
+
Dosya
13
+
Tarifindeki hedefler
13
+
Toplam boyut
3 080 060 B
+
Biçimler
csv, json, xlsx
+
+
+
+
Ve o setin manifestinin sisteminizden beklediği:
+
+
+
+
Beklenen
Anlamı
Dosya
+
+
+
accept
Sisteminiz dosyayı kabul etmeli.
8
+
unspecified
Sisteminizin kurallarına bağlı. Siz karar verirsiniz, sonra olanın amaçladığınız şey olduğunu doğrularsınız.
5
+
+
+
+
+
+
+
Neyi değiştirebilirsiniz?
+
+
+
+
Ayar
Aldığı
Varsayılan
Ne yapar
+
+
+
+
--rows
+
1 - 200000 satır
+
1000
+
Elektronik tablonun kaç satır içerdiği. O kadar satırın paketlendiği tam boyutta yazılır, bu yüzden yukarıdaki bütçe bu değerle kayar.
+
+
+
--columns
+
1 - 32768 sütun
+
10
+
Elektronik tablonun her satırında kaç sütun olduğu. Satır çarpı sütunun bir tavanı vardır ve aşılması bir şey yazılmadan önce reddedilir.
+
+
+
+
+
+
+
+
Nasıl çalıştırılır?
+
Setin neye mal olacağına bakın, kurun veya düzenlemek için tarifini alın:
Okuyucum bir dosyanın hangi kodlamada olduğunu biliyor mu, yoksa tahmin mi ediyor?
+
+ text-encoding hazır ayarı, bu soru için tek komutla gerçek test dosyalarından oluşan bütün
+ bir set ve yanında sisteminizin her dosyaya nasıl tepki vermesi gerektiğini söyleyen bir
+ manifest.json kurar. Aşağıdaki her şey programdan, bu sürümün varsayılanlarıyla
+ okunur.
+
+
+
+
+
Genelde ne bulur?
+
+
UTF-8 varsayıp bir UTF-16 dosyasını üç karakterde bir karakter olarak veya kutu sıraları olarak gösteren okuyucu
+
içerik olarak okunan bir bayt sırası işareti, böylece bir içe aktarmanın ilk alanı üç yabancı karakterle başlar
+
kodlamayı ilk baytlardan tahmin edip daha uzun bir dosyada farklı tahmin eden bir içe aktarıcı
+
her satırdan sonra boş bir satırla satırlara bölünen CRLF dosyası veya son alanda kalan bir satır başı karakteri
+
+
+
+
+
+
Sette ne var?
+
Varsayılanlarda, tfg preset show text-encoding çıktısının bildirdiği gibi:
+
+
+
+
Dosya
20
+
Tarifindeki hedefler
20
+
Toplam boyut
81 920 B
+
Biçimler
csv, log, md, txt, xml
+
+
+
+
Ve o setin manifestinin sisteminizden beklediği:
+
+
+
+
Beklenen
Anlamı
Dosya
+
+
+
accept
Sisteminiz dosyayı kabul etmeli.
10
+
unspecified
Sisteminizin kurallarına bağlı. Siz karar verirsiniz, sonra olanın amaçladığınız şey olduğunu doğrularsınız.
10
+
+
+
+
+
+
+
Neyi değiştirebilirsiniz?
+
+
+
+
Ayar
Aldığı
Varsayılan
Ne yapar
+
+
+
+
--sample
+
2mb gibi bir boyut
+
4kb
+
Setteki her dosyanın büyüklüğü. UTF-16 her karakter için iki bayt saklar, bu yüzden tek sayı reddedilir.
+
+
+
+
+
+
+
+
Nasıl çalıştırılır?
+
Setin neye mal olacağına bakın, kurun veya düzenlemek için tarifini alın:
Yükleme formum alması gerekeni alıp geri kalanı reddediyor mu?
+
+ upload-validation hazır ayarı, bu soru için tek komutla gerçek test dosyalarından oluşan bütün
+ bir set ve yanında sisteminizin her dosyaya nasıl tepki vermesi gerektiğini söyleyen bir
+ manifest.json kurar. Aşağıdaki her şey programdan, bu sürümün varsayılanlarıyla
+ okunur.
+
+
+
+
+
Genelde ne bulur?
+
+
tarayıcıda uygulanan ama sunucuda uygulanmayan bir sınır
+
resim veya düz metin sanılan bir SVG ya da HTML dosyası, yani bir betiği formdan geçirmenin yolu
+
uzantısına bakılıp hiç açılmayan bir dosya, böylece .jpg adlı bir PDF geçer
+
ne kadar büyük olduğuna bakmadan önce tüm gövdeyi belleğe okuyan bir form
+
photo.jpg kabul edilirken reddedilen PHOTO.JPG adlı bir yükleme veya tersi
+
boşluk, parantez veya ASCII dışı karakter içeren bir adın diske değişmeden yazılması
+
+
+
+
+
+
Sette ne var?
+
Varsayılanlarda, tfg preset show upload-validation çıktısının bildirdiği gibi:
+
+
+
+
Dosya
71
+
Tarifindeki hedefler
22
+
Toplam boyut
120 639 488 B
+
Biçimler
html, jpg, pdf, png, svg, txt
+
+
+
+
Ve o setin manifestinin sisteminizden beklediği:
+
+
+
+
Beklenen
Anlamı
Dosya
+
+
+
accept
Sisteminiz dosyayı kabul etmeli.
56
+
reject
Sisteminiz dosyayı reddetmeli.
10
+
unspecified
Sisteminizin kurallarına bağlı. Siz karar verirsiniz, sonra olanın amaçladığınız şey olduğunu doğrularsınız.
5
+
+
+
+
+
+
+
Neyi değiştirebilirsiniz?
+
+
+
+
Ayar
Aldığı
Varsayılan
Ne yapar
+
+
+
+
--limit
+
2mb gibi bir boyut
+
10mb
+
Yükleme formunuzun bildirdiği boyut sınırı. Bu set her iki yanda birer adım atar - her uzaklıktaki dosya için size-boundaries hazır ayarını çalıştırın. Bu varsayılan sizin sisteminizin değeri değil, bizim geçici değerimizdir. Kendinizinkini verin.
+
+
+
--allow
+
virgülle ayrılmış biçim kimlikleri
+
jpg,png,pdf
+
Formunuzun hangi türleri kabul etmesi gerektiği. Her biri o türden gerçek bir dosya olur ve tüm setin pozitif kontrolünü oluşturur.
+
+
+
--deny
+
virgülle ayrılmış uzantılar
+
svg,html,exe,sh
+
Formunuzun hangi uzantıları reddetmesi gerektiği. Bu sürümde biçimi olmayan bir uzantı yine de o adla, düz metin içeren bir dosya alır.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
Tek büyük dosyanın sınırın ne kadar ötesine geçtiği. Sınırın birkaç katını yazmak diske değmiyorsa kapatın.
+
+
+
--bulk
+
0 - 10000 dosya
+
50
+
Toplu yüklemenin kaç dosya içerdiği. Sıfır, bu grubu setten tamamen çıkarır.
+
+
+
+
+
+
+
+
Nasıl çalıştırılır?
+
Setin neye mal olacağına bakın, kurun veya düzenlemek için tarifini alın:
+ PDF, PNG, DOCX, ZIP - toplam 26 biçim ve her biri ait olduğu
+ programda açılan, tam istediğiniz boyutta gerçek bir dosya. Her çalıştırma
+ ayrıca uygulamanızın her dosyayla ne yapması gerektiğini de yazar. Komut satırı ve masaüstü
+ penceresi, ücretsiz ve açık kaynak, tamamen makinenizde çalışır.
+
Ücretsiz ve açık kaynak, GPL-3.0. Kayıt gerekmez. Windows ve macOS indirmeleri imzalıdır ve uyarı vermeden başlar.
+
+
+
+
+ Bir dosya grubu yazmaya hazırlanmış masaüstü penceresi. Aynı motor komut satırının arkasında çalışır.
+
+
+
+
+
+ 26
+
gerçek biçim, her biri ait olduğu programda açılır
+
+
+ 1 bayt
+
istediğiniz her boyutun doğruluğu, asla sessizce yuvarlanmaz
+
+
+ 0
+
hiçbir yere bağlantı - hesap yok, telemetri yok, güncelleme denetimi yok
+
+
+
+
+
Sorun
+
Bir test dosyası yapmak kolay. Doğru bini yapmak sıkıcı kısım
+
İnsanlardan dosya kabul eden bir yazılımı test ediyorsunuz. Er ya da geç şunlara ihtiyacınız olur:
+
+
yükleme sınırının gerçek olup olmadığını anlamak için tam 10 MB'lık bir PDF
+
bir eksik veya fazla hatalarını yakalamak için o sınırın iki yanındaki üç dosya
+
klasör büyükken gece işinin ne yaptığını görmek için 10.000 günlük dosyası
+
doğru uzantılı boş bir kabuk değil, gerçekten 200 belge içeren bir ZIP
+
deponuzda 4 GB'lık bir dosya tutmadan 4 GB'lık bir dosya
+
dizüstü bilgisayarınızda ve derleme sunucusunda aynı fixture'lar, bayt bayt
+
+
+ Bunun yerini alan şey bu. QA mühendisleri, test otomasyonu ve kodunun arkasında bir yükleme formu,
+ içe aktarma rutini, ayrıştırıcı veya depolama kotası olan herkes için yapıldı.
+
+
+
+
+
Onu farklı kılan
+
Diğer üreticiler baytlarda durur. Bu, testinizin gerçekte ne sorduğunu yanıtlar
+
+ Bir dosya klasörü, her birinin neyi kanıtlaması gerektiğine yine sizin karar vermenize bırakır.
+ Burada her çalıştırma dosyaların yanına bir manifest.json yazar - üretilen her
+ şeyin düz bir listesi ve her girdi için bir bildirilmiş beklenti.
+
+
Yükleme endpoint'inizin 1 MB'a izin verdiğini varsayalım. O çizgideki üç dosyayı isteyin:
Yanıt kendi politikanıza bağlıysa manifest bunu söyler
+
+ Bir beklenti uydurmak yerine unspecified kaydeder. Tahmin yürüten bir üretici yanlış
+ hatalar üretir ve sürekli yalancı alarm veren bir test takımı kapatılır.
+
+
+
+
+
+
Hazır ayarlar
+
Soruyu seçin, setin tamamını alın
+
+ Hazır ayar, hangi dosyanın neyi kanıtladığını sizin çözmeniz gerekmesin diye tek bir test sorusu
+ etrafında tasarlanmış bir test dosyası setidir. Her birinin, genelde ne bulduğunu, sette ne
+ olduğunu ve kabul ettiği her ayarı anlatan bir sayfası vardır.
+
+ Her biri bir ile sekiz kilobayt arasında on bin günlük dosyası, boyutlar seed'den çekilir ki yarın
+ aynı seti versin. Her çalıştırmaya kendi dizinini verin - manifest bir
+ çalıştırmanın ne yazdığının tek kaydıdır, bu yüzden araç üzerine ikincisini yazmayı
+ reddeder:
+
+ Boyutlar, dosya yöneticinizin yaptığı gibi 1024'lerle sayılır, yani 2mb 2097152 bayt
+ demektir. Düz bir bayt sayısı da olur. Dokümantasyon tarifleri,
+ manifesti ve çıkış kodlarını kapsar.
+
+
+
+
+
Neler elde edersiniz
+
Gözetimsiz çalışan bir test takımı için yapıldı
+
+
+
Tam boyut, bayta kadar
+
10485761 bayt isteyin ve tam olarak onu alın. Bir biçimin ulaşamayacağı boyut nedeni olan bir hatadır, asla yanlış boyutta bir dosya değil.
+
+
+
26 gerçek biçim
+
Uzantılı dolgu sıfırları değil. Üretilmiş bir PNG resim görüntüleyicide, bir DOCX Word'de açılır, bir ZIP çıkarılır. Her biri yayımlanmadan önce bağımsız okuyucularla doğrulanır.
+
+
+
Test oracle'ı olan bir manifest
+
Yol, boyut, SHA-256, biçim, seed, araç sürümü - ve sisteminizin dosyayla ne yapması gerektiği.
+
+
+
Tekrarlanabilir
+
Aynı tarif ve aynı seed, aynı baytlar, her makinede. Büyük ikili fixture'lar yerine küçük bir YAML tarifini commit edin.
+
+
+
İki arayüz, tek motor
+
CI için yapılmış bir komut satırı ve keşif amaçlı testler için bir masaüstü penceresi. Hiçbiri diğerinin kırpılmış sürümü değildir ve bir test ikisini yetenek yetenek karşılaştırır.
+
+
+
Tamamen çevrimdışı
+
Hesap yok, bulut yok, telemetri yok, güncelleme denetimi yok. Komut satırı ikilisinin içine hiç ağ yığını derlenmemiştir.
+
+
+
+
+
+
İndirme
+
Sisteminiz için derlemeyi seçin
+
+ Arşivi açın ve çalıştırın. tfg komut satırı, tfg-gui masaüstü
+ penceresidir. Yükleyici yok ve makinenize eklenecek hiçbir şey yok.
+
+
+
+
+
+
Sistem
+
Komut satırı
+
Masaüstü penceresi
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
Neler imzalı, neler değil
+
+ Windows ve macOS indirmeleri imzalıdır, bu yüzden bilinmeyen geliştirici uyarısı olmadan başlar.
+ Linux olanlar değildir, çünkü masaüstü Linux'ta onları imzalayacak bir karşılık yoktur. Her
+ arşiv sürüm sayfasındaki verify-SHA256SUMS.txt içinde listelenir, böylece
+ indirdiğinizi doğrulayabilirsiniz.
+
+ İnsanlardan dosya kabul eden hemen her projede çıkan beş iş ve her birini yapan komut. Aşağıdaki her
+ örnek yazıldığı gibi çalışır.
+
+
+
+
Yükleme sınırları
+
Bir dosya boyutu sınırının söylediği yerde uygulanıp uygulanmadığını test etmek
+
+ Bir sınır bir değil üç test durumudur: hemen altı, tam üstü ve hemen üzeri. Bunları elle yapmak bayt
+ sayıları hesaplamak ve bir kayma yapmadığınızı ummak demektir. Bunun yerine seti isteyin:
+
+ 1048575, 1048576 ve 1048577 baytlık üç gerçek PDF ve ilk ikisinin kabul edilmesi, üçüncünün
+ size_limit nedeniyle reddedilmesi gerektiğini söyleyen bir manifest alırsınız.
+ Testiniz üç assertion'ı elle yazmanız yerine beklentiyi okur - sınır değiştiğinde bir sayıyı
+ değiştirip yeniden çalıştırırsınız.
+
+
+ Satır içi tek bir sınır seti istediğinizde aynısı hazır ayar olmadan da çalışır:
+
+ Büyük ikili fixture'lar bir depoyu klonlamada yavaş, incelemede zahmetli yapar ve biri
+ değiştirildiğinde neyin değiştiğini kimse söyleyemez. Tarif, özdeş dosyaları yeniden kuran
+ birkaç yüz karakterlik YAML'dir - bayt bayt, her makinede - çünkü her dosya
+ çalıştırmanın seed'inden türetilir.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Her sonun kendi çıkış kodu vardır, bu yüzden bir hat kötü bir tarifi dolu bir diskten ve bir
+ doğrulama uyuşmazlığından ayırt edebilir. Başarısız bir çalıştırma standart çıktıya hiçbir şey
+ yazdırmaz, bu da bir günlük ayrıştırıcısının hatayı veri sanmasını önler.
+
+
+
+
+
Ölçek
+
Klasör büyükken ne olduğunu öğrenmek
+
+ İçe aktarma rutinleri, gece işleri ve dizin listeleri on bin dosyada ona göre farklı davranır. Bir
+ aralıktan çekilen boyutlar seti on bin özdeş dosya yerine gerçek trafiğe benzetir ve çekiliş
+ seed'den gelir, yani set yarın da aynıdır.
+
+ İç içe geçme derinliği, girdi sayıları ve içindekilerin boyutu, bir içe aktarma rutininin görüş
+ sahibi olduğu şeylerdir ve bu görüşlerin ne olduğunu böyle öğrenirsiniz.
+
+
+
+
+
Ayrıştırıcılar ve görüntüleyiciler
+
Kendi kodunuzun bir biçimi gerçek yazılım gibi okuduğunu denetlemek
+
+ Buradaki her biçim yayımlanmadan önce bağımsız bir okuyucuyla doğrulanır - bir PNG açılır ve
+ pikselleri karşılaştırılır, bir DOCX ayrı kitaplıklarca geri okunur, bir arşiv çıkarılır. Bu,
+ ayrıştırıcınızın reddettiği bir dosyanın üretici hakkında değil ayrıştırıcınız hakkında bir
+ bulgu olduğu anlamına gelir.
+
+ Biçimler sayfası her birinin kabul ettiği ayarları ve her birinin
+ olabileceği en küçük dosyayı listeler.
+
+
+
+
+
Rehberler
+
Bunlardan ikisi daha ayrıntılı
+
+
+ Bozuk test dosyaları - kasıtlı bozulmuş, tam boyutta bir
+ dosya ve ona ne olması gerektiği bildirimde yazılı.
+
+
+ CI'da test dosyaları - bir GitHub Actions iş akışı, bir
+ GitLab işi ve derlemeyi başarısız kılan çıkış kodları.
+
+
+
+
+
+
Kimler için
+
+ QA mühendisleri, test otomasyonu ve kodunun arkasında bir yükleme formu, içe aktarma rutini,
+ ayrıştırıcı veya depolama kotası olan herkes. Hiç ağı olmayan bir makinede çalışır, bu da
+ tarayıcı tabanlı bir üreticinin seçenek olmadığı kapalı bir kurumsal ortamda önem taşır.
+
+ Lisans, gizlilik, tekrarlanabilirlik ve insanların bir üreticiyi derleme hattına koymadan önce
+ denetlediği şeyler. Sorunuz burada yoksa sorun takipçisi açık.
+
+
+
+
+
dd, fsutil veya truncate'ten farkı nedir?
+
+
Onlar size doğru boyutta, içi bomboş bir dosya verir. Bu şekilde yapılmış photo.png adlı 2 MB'lık bir dosya PNG değildir, bu yüzden onu gerçekten ayrıştıran her şey yanlış nedenle reddeder ve testiniz de yanlış nedenle geçer. Bu araç tam 2 MB'lık gerçek bir PNG üretir, resim görüntüleyicide açılır ve sisteminizin onu nasıl ele alması gerektiğine dair bir bildirimle gelir.
İkisi de evet. GPL-3.0 altında yayımlanır ve hiçbir şeye mal olmaz. Hesap, lisans anahtarı veya ücretli katman yoktur.
+
+
+
+
Üretilen dosyaları kapalı kaynaklı bir üründe kullanabilir miyim?
+
+
Evet. Lisans aracın kodunu kapsar, aracın ürettiğini değil. Üretilen dosyalar, tarifler ve manifestler türev eser değil çıktıdır, bu yüzden hiçbir yükümlülük olmadan commit edip dağıtabilirsiniz.
+
+
+
+
Üretilen dosyalar gerçek kişisel veri içeriyor mu?
+
+
Hayır. İçindeki her şey bir seed'den sentezlenir. Hiçbir veri kümesi okunmaz, hiçbir servise bağlanılmaz ve üçüncü taraf içeriği gömülmez. Üretilmiş bir e-posta adresini kullanılmamış değil kullanılamaz sayın, çünkü rastgele bir dize tesadüfen gerçek biriyle çakışabilir.
+
+
+
+
Başka bir makinede tam olarak aynı dosyaları alır mıyım?
+
+
Evet, aynı tarif ve aynı seed ile bayt bayt. Proje bunu her değişiklikte test eder ve bozmak büyük sürüm artışı gerektirir. Büyük ikili fixture'lar yerine küçük bir tarifi commit etmenizi sağlayan da budur.
+
+
+
+
İnternet bağlantısı gerekiyor mu?
+
+
Asla. Telemetri, güncelleme denetimi veya bulut istemcisi yoktur ve komut satırı ikilisinin içine hiç ağ yığını derlenmemiştir. Ağı olmayan bir makinede ve kapalı bir kurumsal ortamda çalışır.
+
+
+
+
Bir biçimin ulaşamayacağı bir boyut istersem ne olur?
+
+
Biçimi, olabilecek en küçük boyutu, bu alt sınırın nedenini ve bunun yerine ne yapılacağını söyleyen bir hata alırsınız ve hiçbir dosya yazılmaz. Araç bir boyutu asla sessizce yuvarlamaz. Her alt sınır biçimler sayfasında listelenir.
+
tfg formats png
+
+
+
+
Kasıtlı olarak bozuk bir dosya üretebilir miyim?
+
+
Evet. --damage zero-head ekleyin, dosya tam istediğiniz boyutta ve ilk baytları sıfırlarla ezilmiş olarak çıkar. Böylece bir okuyucu onu reddeder ve bildirim sisteminizin onu reddetmesi gerektiğini söyler. Ayrıntılar bozuk test dosyaları sayfasındadır.
7z, mp3 ve mp4. Bugün 26 biçim uçtan uca çalışıyor.
+
+
+
+
Hangi sistemlerde çalıştırabilirim?
+
+
Komut satırı Windows ve Linux'ta hem Intel hem ARM üzerinde, ayrıca Apple Silicon Mac'lerde çalışır. Masaüstü penceresi Intel üzerinde Windows, Intel üzerinde Linux ve Apple Silicon Mac'ler için sunulur. Intel Mac'ler desteklenmez ve onlar için hiçbir şey derlenmez.
+
+
+
+
Bir şey kurmam gerekiyor mu?
+
+
Hayır. Sisteminiz için arşivi indirin, açın ve ikiliyi çalıştırın. Yükleyici, eklenecek bir çalışma zamanı veya çözülecek bir bağımlılık yoktur. Go'nuz varsa tek bir go install komutu da işe yarar.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
Binlerce dosya üzerindeki çalıştırma Windows'ta neden daha yavaş?
+
+
Çünkü Windows baktığı her yol için daha fazla bedel ister ve binlerce dosyayı dolaşan bir komut binlerce yola bakar. Her biri 1 kB'lık 3000 dosyalı bir makinede ölçüldü: verify Windows'ta yaklaşık 0,9 saniye, bir konteynerdeki Linux'ta yaklaşık 0,2 saniye sürer. Daha kısa bir çıktı yolu Windows rakamını küçültür, çünkü dosyaların üstündeki her klasör bakılanın parçasıdır.
+ Her sistemin bunun için bir komutu var ve üçü de aşağıda. Size tam doğru bayt sayısında bir dosya
+ verirler - ve birçok test için gereken tek şey budur. Bu sayfadaki her komut,
+ yayımlanmadan önce ait olduğu sistemde çalıştırıldı.
+
+ PowerShell'de 10MB, Gezgin'in kullandığı aynı 1024 tabanlı sayımla 10485760 bayt
+ demektir, yani yukarıdaki iki komut aynı boyutu üretir.
+
+
+
+
+
Linux
+
dd, truncate ve fallocate ve insanları yakalayan fark
+
dd herkesin bildiğidir. Baytları gerçekten yazar:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate anlıktır ve tuzak da budur. Alpine Linux'ta ölçüldü: dosya 10485760 bayt
+ bildirir ve sıfır blok kaplar - bir seyrek dosyadır. Onu
+ okuyan her şey on megabayt sıfır alır ama disk alanı hiç vermemiştir:
+
+
truncate -s 10M test10mb.bin
+
+ Bu, yükleme sınırını sınamak için iyidir ve disk kotasını sınamak için yanıltıcıdır. Alan gerçek
+ olmalıysa başvurulacak olan fallocate'tir:
+
+
fallocate -l 10M test10mb.bin
+
Ve içerik, bir arşivleyici onu yeniden sıkıştıramasın diye sıkıştırılamaz olmalıysa:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
seyrek olmayan mkfile ve zaten bildiğiniz iki komut
+
+ macOS mkfile ile gelir. macOS 26.6.2'de ölçüldü: 10485760 bayt ve 20480 blok, yani alan
+ söz verilmek yerine gerçekten ayrılır:
+
+
mkfile 10m test10mb.bin
+
dd ve truncate da var ve Linux'taki gibi davranır:
Doğru boyutta bir dosya doğru türde bir dosya değildir
+
+ Yukarıdakilerin hepsi size bir sıfır bloğu verir. Test edilen şey yalnızca boyuta bakıyorsa -
+ yükleme sınırı, kota, aktarım - bu yeterlidir. Bir şey dosyayı açtığı anda
+ yeterli olmaktan çıkar.
+
+
+ Ölçüldü ve kendiniz yapmaya değer: fsutil ile 2 MB'lık bir dosya yapın, adını
+ photo.png koyun ve bir görüntü kitaplığına verin. Pillow cannot identify
+ image file yanıtını verir. PNG değil. Hiç de olmadı - yalnızca adı öyle diyordu.
+
+
+ Bu, göründüğünden daha önemlidir, çünkü testin bundan sonra hangi yönde başarısız
+ olduğu belirleyicidir. Yükleme endpoint'iniz dosyayı reddeder, testiniz yeşile döner ve
+ boyut sınırının çalıştığı sonucuna varırsınız. Onu boyut yüzünden reddetmedi. Baytlar resim
+ olmadığı için reddetti ve sınamak istediğiniz kurala hiç ulaşılmadı.
+
+
+
bir ayrıştırıcı herhangi bir boyut kuralına bakılmadan önce onu reddeder
+
küçük resim adımı başarısız olur ve okuduğunuz hata küçük resimle ilgilidir
+
bir antivirüs veya içerik denetimi onu üçüncü bir nedenle reddeder
+
bir görüntüleyici hiçbir şey göstermez ve bunun hata olup olmadığını kimse söyleyemez
+
+
+
+
+
Öbür yol
+
O biçimden gerçek bir dosya, tam istediğiniz boyutta
+
+ Testing Files Generator'ın yaptığı budur. Dosya biçiminin gerçek bir örneğidir - ait olduğu
+ programda açılır - ve istediğiniz tam bayt sayısındadır, bayta kadar:
+
+ Bir biçimin ulaşamayacağı bir boyut isteyin, alt sınırı ve nedenini adlandıran bir hata alırsınız,
+ asla yanlış boyutta bir dosya değil. Biçimler sayfası her biçimi
+ üretebildiği en küçük dosyayla listeler.
+
+
Ve bir sınır bir değil üç test durumudur, bu yüzden araç üçünü de kurar:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Bu size 10485759, 10485760 ve 10485761 bayt ile hangilerini sisteminizin kabul etmesi, hangilerini
+ reddetmesi gerektiğini söyleyen bir manifest verir. Kullanım
+ senaryoları sayfası bunu ve aracın yapıldığı dört işi daha anlatır.
+
Ücretsiz ve açık kaynak, GPL-3.0. Kayıt gerekmez. Windows ve macOS indirmeleri imzalıdır ve uyarı vermeden başlar.
+
+
+
+
Peki hangisini kullanmalı?
+
+
+
Sistem komutunu kullanın
+
+ Hiçbir şey dosyayı açmıyorsa. Önce boyuta bakan bir endpoint'te boyut sınırını sınamak, bir aktarım,
+ bir kota, disk dolu durumu. Tek satırdır ve zaten kuruludur.
+
+
+
+
Gerçek bir üretici kullanın
+
+ Bir şey dosyayı ayrıştırıyor, işliyor, içe aktarıyor veya çıkarıyorsa - ve yarın başka bir makinede
+ aynı fixture'lara bayt bayt ihtiyacınız varsa.
+
+
+
+
+ İkisi de bu sayfada çünkü ikisi de zamanın bir kısmında haklı. Kaçınılması gereken hata, ikincisinin
+ gerektiği yerde birincisini kullanmak ve yeşil testi kanıt saymaktır.
+
+ Валідатор, якому показували лише здорові файли, насправді не перевірений. Ось як отримати файл,
+ навмисно зіпсований, що виходить точно такого розміру, який ви просите, і несе
+ маніфест із вказівкою, що ваша система має з ним зробити.
+
+
+
+
Коротка відповідь
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out записує PNG рівно в
+ 2097152 байти, перші байти якого нулі, а маніфест поруч фіксує, що ваша система має його
+ відхилити.
+
+
+
+
+
Звичайний шлях
+
Чому файл, зіпсований вручну, - поганий тест
+
+ Зазвичай беруть шістнадцятковий редактор, скрипт, що перевертає кілька випадкових байтів, або
+ вкорочують файл через head чи truncate. Один раз це працює, а потім
+ коштує дорого:
+
+
+
+ Щоразу по-різному. Випадковий байт при кожному запуску потрапляє в нове місце, тому
+ збій у вівторок у середу може не повторитися.
+
+
+ Змінюється розмір. Обрізаний файл менший за ліміт, під яким він мав залишатися,
+ тому перевірка розміру відповідає раніше за перевірку вмісту, і тест проходить із неправильної
+ причини.
+
+
+ Це часто лишається непоміченим. Простий текст читається і зі зміненим байтом
+ посередині, а поблажлива програма читання зображень просто малює його, тож файл, який мав бути
+ зіпсований, приймається.
+
+
+ Не сказано, що має статися. Файл - це лише байти, і тому, хто читатиме тест
+ пізніше, доведеться гадати, чи йшлося про прийняття, чи про відхилення.
+
+
+
+
+
+
Що ви отримуєте
+
Пошкоджений файл лишається потрібного розміру
+
+ Файл створюється як зазвичай і псується потім, дорогою на диск. Він зберігає заданий розмір, а та
+ сама команда знову записує ті самі байти.
+
+ Налаштування пишуться після двокрапки. Параметр можна повторювати, а пошкодження застосовуються в
+ тому порядку, в якому ви їх записали. Це працює з кожним із 26 форматів.
+
+
+
+
+
Що він уміє
+
Які бувають пошкодження?
+
+ Це список, який друкує програма, прочитаний із неї під час збирання цієї сторінки. tfg
+ damage друкує той самий список, а tfg damage <id> каже, що приймає
+ одне з них.
+
+
+
+
+
+
Пошкодження
+
Що воно робить із байтами
+
Найменший файл
+
Налаштування
+
+
+
+
+
zero-head
+
Перезаписує перші байти файлу нулями, не змінюючи його довжину. Більшість програм читання дивляться спочатку туди, тому це пошкодження помічає майже все.
+
8
+
bytes
+
+
+
+
+
+ zero-head записує нулі поверх початку файлу. Більшість програм читання дивляться
+ спочатку туди, на сигнатуру й заголовок, які кажуть, що це за файл, тому помічає майже будь-яка.
+ У простого тексту та журналів сигнатури немає, і їх теж відхиляють, бо послідовність нульових
+ байтів не є текстом. Менше ніж чотири байти - і в деяких форматів виходить пошкодження, на яке
+ не скаржиться жодна програма читання, тому налаштування починається з чотирьох.
+
+
+
+
+
Що каже маніфест
+
Маніфест, який каже, що має статися
+
+ Кожен пошкоджений файл отримує запис про те, що ваша система має його відхилити, а поруч записано
+ пошкодження:
+
+ Два запити відхиляються, перш ніж щось буде записано, бо кожен залишив би на диску файл, який
+ маніфест описує хибно:
+
+
+
файл менший, ніж потрібно пошкодженню, який вийшов би недоторканим
+
+ expected: accept поруч із пошкодженням, бо ніщо не могло б цього виконати. Напишіть
+ sanitize, якщо ваша система має полагодити файл, або unspecified,
+ якщо саме це ви й перевіряєте
+
+
+
+
+
+
У рецепті
+
Здорові й зламані файли за один запуск
+
+ Покладіть обидва види в один рецепт, і маніфест несе очікування для кожного файлу, тож тесту не
+ потрібен список, який файл який:
+
+ Тест читає маніфест і перевіряє, що сталося те, що було заявлено. Список імен файлів йому не
+ потрібен:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Гарна відмова - це чиста відмова. Повідомлення, що каже, що було не так, - та відповідь, яка вам
+ потрібна. Помилка сервера, зависання або наполовину збережений файл - той дефект, заради якого
+ цей тест і існує.
+
+ У кожній системі для цього є команда, і всі три наведено нижче. Вони дають файл із точною кількістю
+ байтів, а для багатьох тестів цього досить. Кожну команду на цій сторінці було виконано до
+ публікації у тій системі, до якої вона належить.
+
+
+
+
Коротка відповідь
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Розміри вказуються в байтах, а 10
+ МБ, пораховані так, як рахує ваш файловий менеджер, - це 10485760.
+
+
+
+
+
Windows
+
fsutil і варіант на PowerShell, якому не потрібно нічого додаткового
+
+ fsutil входить до Windows. Він приймає розмір у байтах, тому спершу
+ порахуйте число: 10 МБ - це 10485760, 100 МБ - 104857600, 1 ГБ - 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Виміряно у Windows 11: працює зі звичайного командного рядка без підвищених прав, і файл виходить
+ рівно в 10485760 байт.
+
+
PowerShell може зробити те саме, не викликаючи іншу програму, і розуміє одиниці:
+ 10MB у PowerShell означає 10485760 байт, той самий рахунок за основою 1024, що його
+ використовує Провідник, тому дві команди вище дають той самий розмір.
+
+
+
+
+
Linux
+
dd, truncate і fallocate, і різниця, що ловить людей
+
dd знають усі. Він справді записує байти:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate спрацьовує миттєво, і в цьому підступ. Виміряно в Alpine Linux: файл
+ повідомляє 10485760 байт і займає нуль блоків - це розріджений
+ файл. Усе, що його читає, отримує десять мегабайт нулів, але диск місця так і не
+ віддав:
+
+
truncate -s 10M test10mb.bin
+
+ Для перевірки ліміту завантаження це нормально, а для перевірки дискової квоти вводить в оману.
+ fallocate - те, до чого варто вдатися, коли місце має бути справжнім:
+
+
fallocate -l 10M test10mb.bin
+
А коли вміст має бути нестисливим, щоб архіватор не міг знову його стиснути:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, що не є розрідженим, і дві команди, які ви вже знаєте
+
+ У macOS є mkfile. Виміряно в macOS 26.6.2: 10485760 байт і 20480 блоків, тобто місце
+ справді виділено, а не обіцяно:
+
Файл правильного розміру - не файл правильного виду
+
+ Усе сказане вище дає блок нулів. Цього досить, коли тестоване дивиться лише на розмір: ліміт
+ завантаження, квота, передача. Цього перестає вистачати, щойно щось відкриває
+ файл.
+
+
+ Виміряно, і варто перевірити самому: зробіть файл на 2 МБ командою fsutil, назвіть його
+ photo.png і передайте бібліотеці роботи із зображеннями. Pillow відповість
+ cannot identify image file. Це не PNG. Він ним ніколи й не був, так казало лише
+ ім'я.
+
+
+ Це важливіше, ніж здається, через те, в який бік тест тоді провалюється. Ваша точка
+ завантаження відхиляє файл, ваш тест зеленіє, і ви робите висновок, що ліміт розміру працює.
+ Вона відхилила його не через розмір. Вона відхилила його тому, що байти не були зображенням, і
+ правило, яке ви хотіли перевірити, так і не було досягнуте.
+
+
+
парсер відхиляє його, не дійшовши до жодних правил розміру
+
крок створення мініатюри падає, і помилка, яку ви читаєте, стосується мініатюри
+
антивірус чи перевірка вмісту відхиляє його з третьої причини
+
переглядач нічого не показує, і ніхто не може сказати, чи в цьому помилка
+
+
+
+
+
Інший шлях
+
Справжній файл цього формату точно того розміру, який ви запросили
+
+ Саме це робить Testing Files Generator. Файл - справжній файл свого формату, він відкривається у
+ своїй програмі, і в ньому рівно стільки байтів, скільки ви запросили, з точністю до байта:
+
+ Запросіть розмір, якого формат не може досягти, і ви отримаєте помилку з назвою мінімуму та
+ причиною, а не файл неправильного розміру. Сторінка форматів
+ перелічує кожен формат з найменшим файлом, який він може створити.
+
+
А ліміт - це три тестові випадки, а не один, тому інструмент збирає всі три:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Ви отримаєте 10485759, 10485760 і 10485761 байт та маніфест, що каже, які з них ваша система має
+ прийняти, а які відхилити. Сторінка сценаріїв розбирає це та ще
+ чотири завдання, для яких інструмент створений.
+
Безкоштовно, відкритий код, GPL-3.0. Без реєстрації. Збірки для Windows і macOS підписані та запускаються без попереджень.
+
+
+
+
Тож що використовувати?
+
+
+
Використовуйте системну команду
+
+ Коли ніщо не відкриває файл. Перевірка ліміту розміру на точці, що спершу дивиться розмір, передача,
+ квота, переповнення диска. Це один рядок, і він уже встановлений.
+
+
+
+
Використовуйте справжній генератор
+
+ Коли будь-що розбирає, відображає, імпортує чи розпаковує файл - і коли завтра на іншій машині
+ потрібні ті самі фікстури, байт у байт.
+
+
+
+
+ Обидві є на цій сторінці, бо обидві бувають слушними. Помилка, якої слід уникати, - використати
+ першу там, де потрібна друга, і сприйняти зелений тест за доказ.
+
+ Усе, що робить інструмент, розкладено за питаннями, з якими люди справді приходять.
+ README у репозиторії - повний довідник, і він завжди відповідає
+ завантаженій вами збірці.
+
+
+
+
Які є команди?
+
Кожна робить одну справу:
+
tfg generate створити файли за рецептом або за прапорцями
+tfg validate перевірити рецепт, нічого не записуючи
+tfg verify звірити каталог із маніфестом
+tfg cleanup видалити файли, перелічені в маніфесті
+tfg recipe fmt вивести рецепт у усталеному вигляді
+tfg preset зібрати набір файлів за іменованим тестовим питанням
+tfg formats перелічити формати цієї збірки
+tfg damage перелічити способи, якими ця збірка може навмисно зіпсувати файл
+tfg tool невеликі інструменти для вже наявних файлів
+tfg version вивести версію інструмента
+tfg license вивести ліцензію та що вона означає для створених файлів
+
+
+
+
Як створити один файл точного розміру?
+
+ Укажіть формат, розмір і місце призначення. Розміри рахуються по 1024, тому 2mb - це
+ 2097152 байти. Підійде й просте число байтів, тож --size 10485761 запитує рівно
+ стільки.
+
+
tfg generate --format png --size 2mb --out ./out
+
Корисні прапорці команди generate:
+
+
+
Прапорець
Що робить
+
+
--format <id>
формат файлів, наприклад txt
+
--size <size>
точний розмір кожного файлу, наприклад 10mb або просте число байтів
+
--size-range <a-b>
розмір, що вибирається для кожного файлу з діапазону, наприклад 1kb-8kb. Вибір іде від seed
+
--boundary <size>
три файли навколо ліміту: на байт менше, сам ліміт, на байт більше
+
--count <n>
скільки файлів створити. За замовчуванням 1
+
--name <template>
шаблон імені, наприклад invoice_{index:04}.txt
+
--out <dir>
каталог, у який записувати
+
--seed <n>
seed запуску. Той самий seed дає ті самі байти
+
--set <k>=<v>
налаштування формату, можна повторювати
+
--damage <name>
навмисно зіпсувати файли, можна повторювати, застосовується по порядку. Список виводить tfg damage
+
--expected <outcome>
accept, reject, sanitize або unspecified
+
--dry-run
порахувати й показати, нічого не записуючи
+
--json
записати маніфест у стандартний вивід
+
+
+
+
+
+
+
Як зробити навмисно зламаний файл?
+
+ Будь-який інший файл, що його записує цей інструмент, коректний за побудовою, і це відповідає на два
+ з трьох питань, які ставить перевірка завантаження. --damage відповідає на третє -
+ чи відкривається файл узагалі. Файл створюється як зазвичай, а потім псується, тому в нього
+ лишається запитаний розмір.
+
+ Налаштування вказуються після двокрапки. Прапорець можна повторювати, і порядок запису - це порядок
+ застосування. tfg damage перелічує, що вміє ця збірка та що приймає кожен вид
+ пошкодження.
+
+ Пошкоджений файл отримує в маніфесті expected: reject із записаним поруч пошкодженням.
+ Дві речі відхиляються до запису чого-небудь, бо кожна залишила б на диску файл, неправильно
+ описаний маніфестом:
+
+
+
файл менший, ніж потрібно пошкодженню, бо він вийшов би без змін
+
+ expected: accept поруч із пошкодженням, бо цьому не міг би відповідати жоден файл.
+ Пишіть sanitize, якщо тестована система має полагодити файл, або
+ unspecified, якщо саме це питання ви й ставите
+
+
+
+ Третє наперед дізнатися не можна. Якщо пошкодження виконується й не змінює жодного байта, такий файл
+ відкидається, а не записується - запуск триває, повідомляє, що це був за файл, і завершується
+ кодом часткового завершення.
+
+ Рецепт - це файл YAML, що описує цілий запуск. Закомітьте його поряд із тестами, і фікстури
+ перестануть бути бінарними файлами у вашому репозиторії - будь-хто зможе відтворити їх байт у
+ байт із файлу в кілька сотень символів.
+
+ Кожній цілі потрібен рівно один із ключів size, size-range,
+ boundary або contains. Два - це помилка, і жодного - теж. Недійсний
+ рецепт записує жодного файлу і повідомляє про всі проблеми одразу, а не лише
+ про першу, щоразу називаючи налаштування, якого вона стосується.
+
+
+
+
+
Як оголосити, що моя система має робити з файлом?
+
Коротка форма, коли досить результату, і довга, коли важлива причина:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Результати - accept, reject, sanitize і
+ unspecified. Причини утворюють закритий список, щоб звіт міг за ними групувати:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit і size_zero.
+
+
+ Причина називає чинне правило, а не вердикт. Тому та сама причина може стояти під
+ будь-яким результатом - файл на байт менший за ліміт отримує accept, а правило, про
+ яке йдеться, усе одно size_limit.
+
+
+
+
+
Що в маніфесті?
+
+ Він записується поряд із файлами наприкінці кожного запуску, зокрема й перерваного. Один запис на
+ файл:
+
+ recipe_hash додається, якщо запуск був за рецептом, а preset з
+ overrides - якщо за пресетом, тож маніфест завжди можна простежити до того, що його
+ створило.
+
+
+ Кожен запис також містить target_id - id цілі рецепта, що створила файл, а
+ summary.by_target рахує файли кожної цілі. Рецепт із кількома цілями можна тому
+ перевірити ціль за ціллю, не читаючи імена файлів.
+
+
+
+
+
Що таке пресет?
+
+ Готовий набір файлів, що відповідає на поширене тестове питання, щоб вам не доводилося проєктувати
+ набір самостійно. Пресети - звичайні рецепти всередині, а eject виводить рецепт,
+ щоб ви могли його відредагувати. Кожен пресет має окрему сторінку про
+ те, що він зазвичай знаходить, що входить у набір і які налаштування приймає.
+
+ show повідомляє, скільки коштував би набір, перш ніж ви його зберете, і прямо каже,
+ коли число - наша тимчасова підстановка, а не ваш ліміт.
+
+
+
+
+
Що означають коди завершення?
+
+ Кожен кінець має власний код, машиночитний вивід іде в стандартний вивід, а невдалий запуск нічого
+ туди не друкує. Таблиця - заморожений контракт: зміна значення коду вимагає підвищення мажорної
+ версії.
+
+
+
+
+
+
Код
+
Значення
+
+
+
+
+
0
+
Усе спрацювало.
+
+
+
1
+
Непередбачена помилка всередині інструмента.
+
+
+
2
+
Неправильна команда або прапорець.
+
+
+
3
+
Рецепт недійсний.
+
+
+
4
+
Формат не може зробити те, що просили.
+
+
+
5
+
Не вдалося прочитати або записати.
+
+
+
6
+
Недостатньо місця на диску.
+
+
+
7
+
verify виявив розбіжність.
+
+
+
8
+
Запуск завершено, але створено не все.
+
+
+
130
+
Перервано за допомогою Ctrl+C.
+
+
+
143
+
Зупинено сигналом, так виглядає тайм-аут у CI.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Запуск, зупинений за допомогою Ctrl+C, усе одно залишає маніфест і ніколи не залишає наполовину
+ записаного файлу, тож скасоване завдання може бути прибране наступним.
+
+ Так, той самий рушій із вікном згори, для тестування, яке не автоматизується. Це не урізана версія:
+ тест порівнює два інтерфейси можливість за можливістю, і все, що вміє лише один із них, має бути
+ оголошене й обґрунтоване, а не тихо розходитися.
+
+
+ Екрани: одна партія, пресети, кілька партій одночасно та про програму. Вікно показує, скільки
+ коштував би запуск, перш ніж щось записати, відображає перебіг роботи й може бути скасоване на
+ півдорозі без наполовину записаного файлу. Файл рецепта воно поки не відкриває - рецепти поки
+ справа командного рядка, а вікно збирає свої партії у формі.
+
+ Ліцензія, приватність, відтворюваність і те, що люди перевіряють, перш ніж додавати генератор до
+ конвеєра збірки. Якщо вашого питання тут немає, трекер задач
+ відкритий.
+
+
+
+
+
Чим це відрізняється від dd, fsutil чи truncate?
+
+
Вони дають файл потрібного розміру, набитий порожнечею. Файл photo.png на 2 МБ, зроблений так, не є PNG, тому все, що справді його розбирає, відхиляє його з хибної причини, і ваш тест теж проходить із хибної причини. Цей інструмент створює справжній PNG рівно на 2 МБ, який відкривається в переглядачі зображень, і супроводжує його заявою про те, як ваша система має з ним вчинити.
Це безкоштовно, і чи можна використовувати на роботі?
+
+
Так в обох випадках. Інструмент випущено під GPL-3.0, і він нічого не коштує. Немає ні облікового запису, ні ліцензійного ключа, ні платного тарифу.
+
+
+
+
Чи можна використовувати створені файли в продукті із закритим кодом?
+
+
Так. Ліцензія охоплює код інструмента, а не те, що він створює. Створені файли, рецепти й маніфести є результатом, а не похідними творами, тож їх можна комітити та постачати без жодних зобов'язань.
+
+
+
+
Чи містять створені файли справжні персональні дані?
+
+
Ні. Усе всередині синтезується з seed. Жоден набір даних не читається, до жодного сервісу не звертаються і жоден сторонній вміст не вбудовується. Вважайте створену адресу електронної пошти непридатною, а не невикористаною, бо будь-який випадковий рядок може випадково збігтися зі справжнім.
+
+
+
+
Чи отримаю я точно такі самі файли на іншій машині?
+
+
Так, байт у байт, за того самого рецепта й того самого seed. Проєкт перевіряє це при кожній зміні, а порушити це можна лише підвищенням мажорної версії. Саме тому ви можете комітити невеликий рецепт замість великих бінарних фікстур.
+
+
+
+
Чи потрібне підключення до інтернету?
+
+
Ніколи. Немає ні телеметрії, ні перевірки оновлень, ні хмарного клієнта, а в бінарний файл командного рядка взагалі не скомпільовано мережевий стек. Він працює на машині без мережі й у закритому корпоративному середовищі.
+
+
+
+
Що буде, якщо запросити розмір, якого формат не може досягти?
+
+
Ви отримаєте помилку з назвою формату, найменшим можливим розміром, причиною цього мінімуму та тим, що робити натомість, а файл записано не буде. Інструмент ніколи не округлює розмір мовчки. Кожен мінімум указано на сторінці форматів.
+
tfg formats png
+
+
+
+
Чи можна створити навмисно зламаний файл?
+
+
Так. Додайте --damage zero-head, і файл вийде точно заданого розміру, з першими байтами, перезаписаними нулями, тож програма читання його відхилить, а маніфест скаже, що ваша система має його відхилити. Подробиці на сторінці про пошкоджені тестові файли.
7z, mp3 і mp4. Сьогодні повністю працюють 26 форматів.
+
+
+
+
У яких системах це можна запускати?
+
+
Командний рядок працює у Windows і Linux на Intel та ARM, а також на Mac з Apple Silicon. Десктопне вікно постачається для Windows на Intel, Linux на Intel і Mac з Apple Silicon. Mac на Intel не підтримуються, і для них нічого не збирається.
+
+
+
+
Чи потрібно щось установлювати?
+
+
Ні. Завантажте архів для своєї системи, розпакуйте й запустіть бінарний файл. Немає інсталятора, середовища виконання, яке треба додавати, і залежностей, які треба розв'язувати. Якщо у вас є Go, підійде й одна команда go install.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
Чому запуск на тисячах файлів у Windows повільніший?
+
+
Бо Windows бере більше за кожен шлях, який переглядає, а команда, що обходить тисячі файлів, переглядає тисячі шляхів. Виміряно на одній машині з 3000 файлів по 1 КБ: verify займає близько 0,9 секунди у Windows і близько 0,2 секунди в Linux у контейнері. Коротший шлях виводу зменшує цифру для Windows, бо кожна тека над файлами входить у те, що переглядається.
26 форматів файлів, кожен створюється точного розміру
+
+ Кожен із них - справжній файл цього формату. Він відкривається у своїй програмі та
+ має рівно стільки байтів, скільки ви запросили. Жоден не є нулями-заповнювачами з приклеєним
+ розширенням.
+
+
+
+
+
+
+
Формат
+
Назва
+
Розширення
+
Найменший файл
+
Повнота
+
Перевіряється за допомогою
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
не застосовується
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
не застосовується
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
не застосовується
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
Що означають стовпці
+
+
+
Найменший файл
+
+ Найменша кількість байтів, яку цей інструмент приймає для формату, разом із позначкою, яку він пише
+ всередині файлу. Запросіть менше, і ви отримаєте помилку з назвою мінімуму та причиною, а не
+ файл неправильного розміру.
+
+
+
+
Повнота
+
+ Наскільки повний файл. full означає, що його приймає читач, який по-справжньому
+ розбирає формат, а не просто збігається розширення.
+
+
+
+
Перевіряється за допомогою
+
+ Незалежний читач, що відкриває кожен створений файл до випуску формату, - окрема реалізація, а не
+ наш власний код, що перевіряє власні домашні завдання.
+
+
+
+
+ Кожен формат до того ж повторюється до байта: той самий рецепт і той самий seed дають однакові файли
+ на будь-якій машині, і саме це робить безпечним коміт рецепта замість самих фікстур.
+
+
+
+
+
Налаштування, які приймає кожен формат
+
+ Більшість форматів мають власні налаштування - розміри зображення, якість JPEG, кількість сторінок
+ PDF, рядки й стовпці в таблиці, скільки записів входить в архів. Задайте їх через --set
+ key=value у командному рядку або в розділі properties: рецепта.
+
дата на кшталт 2024-02-29 або 2024-02-29T13:45:00+02:00, або none
+
+
+
+
modified
+
дата на кшталт 2024-02-29 або 2024-02-29T13:45:00+02:00, або none
+
+
+
png
+
width
+
1 - 20000 пікселів
+
+
+
+
height
+
1 - 20000 пікселів
+
+
+
pptx
+
slides
+
1 - 500 слайдів
+
+
+
svg
+
width
+
1 - 20000 пікселів
+
+
+
+
height
+
1 - 20000 пікселів
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
id формату в тому вигляді, як його виводить tfg formats
+
+
+
+
entry_size
+
розмір, наприклад 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
істина або хибність
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 пікселів
+
+
+
+
height
+
1 - 20000 пікселів
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
істина або хибність
+
+
+
wav
+
sample_rate
+
8000 - 192000 герців
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 пікселів
+
+
+
+
height
+
1 - 16383 пікселів
+
+
+
xlsx
+
rows
+
1 - 200000 рядків
+
+
+
+
columns
+
1 - 32768 стовпців
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
істина або хибність
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
id формату в тому вигляді, як його виводить tfg formats
+
+
+
+
entry_size
+
розмір, наприклад 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
істина або хибність
+
+
+
+
password
+
пароль відкритим текстом
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ Значення поза допустимим для налаштування відхиляється повідомленням із назвою налаштування,
+ допустимим діапазоном і тим, що використати натомість. Невідоме налаштування теж помилка, а не
+ мовчазне значення за замовчуванням - друкарська помилка, прийнята мовчки, дає файл із хибними
+ налаштуваннями та годину роздумів, чому тест проходить, хоча не мав би.
+
+
+ Виконайте tfg formats <id>, щоб побачити, що саме приймає один формат у вашій
+ збірці.
+
+
+
+
+
Архіви містять справжні файли
+
+ targz і zip
+ можна наповнити записами, а не лишати порожньою оболонкою. Створений архів справді містить
+ документи, які заявляє, тому все, що розпаковує його під час тесту, знаходить усередині справжні
+ файли.
+
+ PDF, PNG, DOCX, ZIP - усього 26 форматів, і кожен із них -
+ справжній файл, що відкривається у своїй програмі, точно того розміру, який ви
+ запросили. Кожен запуск ще й записує, що ваш застосунок має робити з кожним файлом.
+ Командний рядок і десктопне вікно, безкоштовно та з відкритим кодом, усе працює на вашій машині.
+
Безкоштовно, відкритий код, GPL-3.0. Без реєстрації. Збірки для Windows і macOS підписані та запускаються без попереджень.
+
+
+
+
+ Десктопне вікно, підготовлене до запису партії файлів. За командним рядком працює той самий рушій.
+
+
+
+
+
+ 26
+
справжніх форматів, кожен відкривається у своїй програмі
+
+
+ 1 байт
+
точність кожного запитаного розміру, ніколи не округлюється мовчки
+
+
+ 0
+
з'єднань будь-куди - без облікового запису, без телеметрії, без перевірки оновлень
+
+
+
+
+
Проблема
+
Зробити один тестовий файл легко. Зробити потрібну тисячу - ось виснажлива частина
+
Ви тестуєте програму, що приймає файли від людей. Рано чи пізно вам знадобляться:
+
+
PDF рівно на 10 МБ, щоб з'ясувати, чи реальний ліміт завантаження
+
три файли по обидва боки цього ліміту, щоб упіймати помилки на одиницю
+
10 000 файлів журналу, щоб побачити, що робить нічне завдання, коли тека велика
+
ZIP, який справді містить 200 документів, а не порожню оболонку з правильним розширенням
+
файл на 4 ГБ без зберігання файлу на 4 ГБ у вашому репозиторії
+
однакові фікстури на ноутбуці та на сервері збірки, байт у байт
+
+
+ Саме це він замінює. Він створений для QA-інженерів, автоматизації тестування та всіх, за чиїм кодом
+ стоїть форма завантаження, процедура імпорту, парсер чи квота сховища.
+
+
+
+
+
Чим він відрізняється
+
Інші генератори зупиняються на байтах. Цей відповідає на те, про що насправді питає ваш тест
+
+ Тека з файлами все одно залишає вам вирішувати, що має доводити кожен із них. Кожен запуск тут
+ записує поряд із файлами manifest.json - простий перелік усього створеного та для
+ кожного запису заявлене очікування.
+
+
Припустімо, ваша точка завантаження допускає 1 МБ. Запросіть три файли, що лежать на цій межі:
Там, де відповідь залежить від вашої власної політики, маніфест так і каже
+
+ Він записує unspecified, а не вигадує очікування. Генератор, що вгадує, дає хибні збої,
+ а набір тестів, що кричить «вовки», зрештою вимикають.
+
+
+
+
+
+
Пресети
+
Виберіть питання, отримайте весь набір
+
+ Пресет - це набір тестових файлів, продуманий навколо одного тестового питання, щоб вам не довелося
+ з'ясовувати, які файли що доводять. Кожен має сторінку про те, що він зазвичай знаходить, що
+ входить у набір і які налаштування приймає.
+
+ Десять тисяч файлів журналу, кожен від одного до восьми кілобайтів, з розмірами з seed, щоб завтра
+ вийшов той самий набір. Давайте кожному запуску власний каталог - маніфест
+ лишається єдиним записом про те, що записав запуск, тому інструмент відмовляється записувати
+ другий поверх нього:
+
+ Розміри рахуються по 1024, як у вашому файловому менеджері, тому 2mb означає 2097152
+ байти. Підійде й просте число байтів. Документація охоплює рецепти,
+ маніфест і коди завершення.
+
+
+
+
+
Що ви отримуєте
+
Створений для набору тестів, що працює без нагляду
+
+
+
Точний розмір, до байта
+
Запросіть 10485761 байт і отримайте рівно стільки. Розмір, якого формат не може досягти, - це помилка з причиною, а не файл неправильного розміру.
+
+
+
26 справжніх форматів
+
Не нулі-заповнювачі з розширенням. Створений PNG відкривається в переглядачі зображень, DOCX - у Word, ZIP розпаковується. Кожен формат перевіряється незалежними читачами до випуску.
+
+
+
Маніфест, що править за тестовий оракул
+
Шлях, розмір, SHA-256, формат, seed, версія інструмента - і те, що ваша система має зробити з файлом.
+
+
+
Відтворюваність
+
Той самий рецепт і той самий seed, ті самі байти на будь-якій машині. Комітьте невеликий рецепт YAML замість великих бінарних фікстур.
+
+
+
Два інтерфейси, один рушій
+
Командний рядок, створений для CI, і десктопне вікно для дослідницького тестування. Жоден не є урізаною версією іншого, і тест порівнює їх можливість за можливістю.
+
+
+
Повністю офлайн
+
Немає облікового запису, хмари, телеметрії та перевірки оновлень. У бінарний файл командного рядка взагалі не скомпільовано мережевий стек.
+
+
+
+
+
+
Завантаження
+
Виберіть збірку для вашої системи
+
+ Розпакуйте архів і запустіть. tfg - це командний рядок, а tfg-gui -
+ десктопне вікно. Немає інсталятора й нічого, що треба додавати на вашу машину.
+
+
+
+
+
+
Система
+
Командний рядок
+
Десктопне вікно
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
Що підписано, а що ні
+
+ Збірки для Windows і macOS підписані, тому запускаються без попередження про невідомого розробника.
+ Збірки для Linux не підписані, бо в десктопного Linux немає еквівалента, яким їх можна
+ підписати. Кожен архів указано в verify-SHA256SUMS.txt на сторінці релізу, тож ви
+ можете перевірити, що завантажили.
+
Чи пройде коректний файл, настільки малий, наскільки дозволяє формат?
+
+ Пресет empty-and-minimal однією командою збирає цілий набір справжніх тестових файлів для цього
+ питання та поруч manifest.json з очікуваною реакцією вашої системи на кожен файл. Усе
+ нижче прочитано з програми зі значеннями за замовчуванням цієї версії.
+
+
+
+
+
Що він зазвичай знаходить?
+
+
коректний файл, відхилений як надто малий, бо перевірка рахує байти, а не читає їх
+
порожній файл, який валить читальний код замість того, щоб бути поміченим
+
картинка завширшки один піксель, яка ділить на нуль дорогою до мініатюри
+
сховище, яке сприймає нуль байтів як невдале завантаження й безкінечно повторює спроби
+
+
+
+
+
+
Що входить у набір?
+
Зі значеннями за замовчуванням, як повідомляє tfg preset show empty-and-minimal:
Чи збереже, покаже та поверне моя система ім'я файлу, якого не очікувала?
+
+ Пресет filename-handling однією командою збирає цілий набір справжніх тестових файлів для цього
+ питання та поруч manifest.json з очікуваною реакцією вашої системи на кожен файл. Усе
+ нижче прочитано з програми зі значеннями за замовчуванням цієї версії.
+
+
+
+
+
Що він зазвичай знаходить?
+
+
ім'я, що на екрані, в журналі чи в списку виглядає як інше
+
ім'я, обрізане, скорочене або переписане між завантаженням і зберіганням
+
ліміт довжини, що рахується в символах там, де сховище рахує байти
+
+
+
+
+
+
Що входить у набір?
+
Зі значеннями за замовчуванням, як повідомляє tfg preset show filename-handling:
+
+
+
+
Файлів
50
+
Цілей у його рецепті
50
+
Загальний розмір
51 200 B
+
Формати
txt
+
+
+
+
І чого маніфест цього набору очікує від вашої системи:
+
+
+
+
Очікується
Значення
Файлів
+
+
+
accept
Ваша система має прийняти файл.
4
+
unspecified
Залежить від правил вашої системи. Ви вирішуєте, а потім перевіряєте, що відбувається саме те, що ви мали на увазі.
46
+
+
+
+
+
+
+
Що можна змінити?
+
+
+
+
Налаштування
Приймає
За замовчуванням
Що робить
+
+
+
+
--format
+
id формату зі сторінки форматів
+
txt
+
Формат кожного файлу набору. Це прапорець самого інструмента, а пресет лише задає йому значення за замовчуванням.
+
+
+
+
+
+
+
+
Як його запустити?
+
Подивіться, скільки коштував би набір, зберіть його або візьміть його рецепт для правки:
Пресети тестових файлів, по набору на кожне тестове питання
+
+ Пресет - це цілий набір тестових файлів, продуманий навколо одного питання, з маніфестом про
+ очікувану реакцію вашої системи на кожен файл. Ви вибираєте питання, інструмент збирає набір.
+ Кожен пресет має власну сторінку про те, що він зазвичай знаходить, що входить у набір і які
+ налаштування приймає.
+
Чи приймає моя форма завантаження те, що має, і відхиляє решту?
+
upload-validation
+
+
+
+
+
Чим пресет відрізняється від рецепта?
+
+ По суті нічим. Пресет - це рецепт, який інструмент пише для вас із кількох налаштувань. tfg
+ preset eject виводить цей рецепт, щоб ви могли зберігати його поряд із тестами й
+ редагувати, а ваш власний рецепт може спиратися на пресет одним рядком: extends:
+ preset: і його id.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Чи можна довіряти значенням за замовчуванням?
+
+ Для файлів - так. Для числа, яке знає лише ваша система, як-от ліміту форми завантаження, значення
+ за замовчуванням - наша тимчасова підстановка, і інструмент каже про це щоразу, коли її
+ використовує. Сторінка кожного пресета позначає такі налаштування, а tfg preset
+ show повідомляє про це до запису чого-небудь.
+
Чи застосовується ліміт розміру саме там, де його оголошено?
+
+ Пресет size-boundaries однією командою збирає цілий набір справжніх тестових файлів для цього
+ питання та поруч manifest.json з очікуваною реакцією вашої системи на кожен файл. Усе
+ нижче прочитано з програми зі значеннями за замовчуванням цієї версії.
+
+
+
+
+
Що він зазвичай знаходить?
+
+
помилки на одиницю на межі ліміту
+
МБ, сплутані з МіБ, тобто 4,8 відсотка, чого досить, щоб пропустити файл, який не мав би пройти
+
ліміт, що застосовується в браузері, а не на сервері
+
+
+
+
+
+
Що входить у набір?
+
Зі значеннями за замовчуванням, як повідомляє tfg preset show size-boundaries:
+
+
+
+
Файлів
7
+
Цілей у його рецепті
7
+
Загальний розмір
73 400 320 B
+
Формати
pdf
+
+
+
+
І чого маніфест цього набору очікує від вашої системи:
+
+
+
+
Очікується
Значення
Файлів
+
+
+
accept
Ваша система має прийняти файл.
4
+
reject
Ваша система має відхилити файл.
3
+
+
+
+
+
+
+
Що можна змінити?
+
+
+
+
Налаштування
Приймає
За замовчуванням
Що робить
+
+
+
+
--limit
+
розмір, наприклад 2mb
+
10mb
+
Ліміт розміру, який оголошує ваша система. Усе інше відмірюється від нього. Це значення за замовчуванням - наша тимчасова підстановка, а не значення вашої системи. Передайте своє.
+
+
+
--spread
+
розміри через кому
+
1B,1kb,1mb
+
Як далеко відходити від ліміту в обидва боки, списком розмірів.
+
+
+
--format
+
id формату зі сторінки форматів
+
pdf
+
Формат кожного файлу набору. Це прапорець самого інструмента, а пресет лише задає йому значення за замовчуванням.
+
+
+
+
+
+
+
+
Як його запустити?
+
Подивіться, скільки коштував би набір, зберіть його або візьміть його рецепт для правки:
Чи переживе мій імпорт таблиць те, що експортують справжні інструменти?
+
+ Пресет tabular-import однією командою збирає цілий набір справжніх тестових файлів для цього
+ питання та поруч manifest.json з очікуваною реакцією вашої системи на кожен файл. Усе
+ нижче прочитано з програми зі значеннями за замовчуванням цієї версії.
+
+
+
+
+
Що він зазвичай знаходить?
+
+
файл із крапкою з комою, прочитаний як один стовпець, бо роздільник припустили, а не шукали
+
файл CRLF, розбитий на рядки з порожнім рядком після кожного
+
таблиця без заголовка, перший рядок даних якої з'їдається як імена стовпців
+
імпорт, що залишає стовпці, які може показати, і мовчки відкидає решту
+
читач, що бере записи JSON по одному рядку й зупиняється на першому документі з відступами
+
+
+
+
+
+
Що входить у набір?
+
Зі значеннями за замовчуванням, як повідомляє tfg preset show tabular-import:
+
+
+
+
Файлів
13
+
Цілей у його рецепті
13
+
Загальний розмір
3 080 060 B
+
Формати
csv, json, xlsx
+
+
+
+
І чого маніфест цього набору очікує від вашої системи:
+
+
+
+
Очікується
Значення
Файлів
+
+
+
accept
Ваша система має прийняти файл.
8
+
unspecified
Залежить від правил вашої системи. Ви вирішуєте, а потім перевіряєте, що відбувається саме те, що ви мали на увазі.
5
+
+
+
+
+
+
+
Що можна змінити?
+
+
+
+
Налаштування
Приймає
За замовчуванням
Що робить
+
+
+
+
--rows
+
1 - 200000 рядків
+
1000
+
Скільки рядків у таблиці. Файл записується рівно того розміру, у який пакується стільки рядків, тому бюджет вище змінюється разом із цим значенням.
+
+
+
--columns
+
1 - 32768 стовпців
+
10
+
Скільки стовпців у кожному рядку таблиці. Добуток рядків на стовпці має стелю, і запит понад неї відхиляється до запису чого-небудь.
+
+
+
+
+
+
+
+
Як його запустити?
+
Подивіться, скільки коштував би набір, зберіть його або візьміть його рецепт для правки:
Чи знає мій читач, у якому кодуванні файл, чи вгадує?
+
+ Пресет text-encoding однією командою збирає цілий набір справжніх тестових файлів для цього
+ питання та поруч manifest.json з очікуваною реакцією вашої системи на кожен файл. Усе
+ нижче прочитано з програми зі значеннями за замовчуванням цієї версії.
+
+
+
+
+
Що він зазвичай знаходить?
+
+
читач, що припускає UTF-8 і показує файл UTF-16 з одним символом із трьох або рядами квадратиків
+
позначка порядку байтів, прочитана як вміст, через що перше поле імпорту починається з трьох зайвих символів
+
імпортер, що вгадує кодування за першими байтами й вгадує інакше для довшого файлу
+
файл CRLF, розбитий на рядки з порожнім рядком після кожного, або повернення каретки, що залишилося в останньому полі
+
+
+
+
+
+
Що входить у набір?
+
Зі значеннями за замовчуванням, як повідомляє tfg preset show text-encoding:
+
+
+
+
Файлів
20
+
Цілей у його рецепті
20
+
Загальний розмір
81 920 B
+
Формати
csv, log, md, txt, xml
+
+
+
+
І чого маніфест цього набору очікує від вашої системи:
+
+
+
+
Очікується
Значення
Файлів
+
+
+
accept
Ваша система має прийняти файл.
10
+
unspecified
Залежить від правил вашої системи. Ви вирішуєте, а потім перевіряєте, що відбувається саме те, що ви мали на увазі.
10
+
+
+
+
+
+
+
Що можна змінити?
+
+
+
+
Налаштування
Приймає
За замовчуванням
Що робить
+
+
+
+
--sample
+
розмір, наприклад 2mb
+
4kb
+
Розмір кожного файлу набору. UTF-16 зберігає по два байти на символ, тому непарне число відхиляється.
+
+
+
+
+
+
+
+
Як його запустити?
+
Подивіться, скільки коштував би набір, зберіть його або візьміть його рецепт для правки:
Чи приймає моя форма завантаження те, що має, і відхиляє решту?
+
+ Пресет upload-validation однією командою збирає цілий набір справжніх тестових файлів для цього
+ питання та поруч manifest.json з очікуваною реакцією вашої системи на кожен файл. Усе
+ нижче прочитано з програми зі значеннями за замовчуванням цієї версії.
+
+
+
+
+
Що він зазвичай знаходить?
+
+
ліміт, що застосовується в браузері, а не на сервері
+
SVG або HTML, прийнятий за картинку чи простий текст, що дає змогу провести скрипт крізь форму
+
файл, перевірений за розширенням і жодного разу не відкритий, тож PDF з ім'ям .jpg проходить
+
форма, що читає все тіло в пам'ять, перш ніж подивитися, наскільки воно велике
+
завантаження з ім'ям PHOTO.JPG відхилене там, де photo.jpg приймається, або навпаки
+
ім'я з пробілами, дужками чи символами поза ASCII, записане на диск без змін
+
+
+
+
+
+
Що входить у набір?
+
Зі значеннями за замовчуванням, як повідомляє tfg preset show upload-validation:
+
+
+
+
Файлів
71
+
Цілей у його рецепті
22
+
Загальний розмір
120 639 488 B
+
Формати
html, jpg, pdf, png, svg, txt
+
+
+
+
І чого маніфест цього набору очікує від вашої системи:
+
+
+
+
Очікується
Значення
Файлів
+
+
+
accept
Ваша система має прийняти файл.
56
+
reject
Ваша система має відхилити файл.
10
+
unspecified
Залежить від правил вашої системи. Ви вирішуєте, а потім перевіряєте, що відбувається саме те, що ви мали на увазі.
5
+
+
+
+
+
+
+
Що можна змінити?
+
+
+
+
Налаштування
Приймає
За замовчуванням
Що робить
+
+
+
+
--limit
+
розмір, наприклад 2mb
+
10mb
+
Ліміт розміру, який оголошує ваша форма завантаження. Цей набір робить по одному кроку в обидва боки - для файлу на кожній відстані запустіть пресет size-boundaries. Це значення за замовчуванням - наша тимчасова підстановка, а не значення вашої системи. Передайте своє.
+
+
+
--allow
+
id форматів через кому
+
jpg,png,pdf
+
Які типи має приймати ваша форма. Кожен стає справжнім файлом цього типу, і разом вони є позитивним контролем усього набору.
+
+
+
--deny
+
розширення через кому
+
svg,html,exe,sh
+
Які розширення має відхиляти ваша форма. Розширення, для якого в цій збірці немає формату, усе одно отримує файл із таким ім'ям і простим текстом усередині.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
Наскільки далеко за ліміт заходить єдиний великий файл. Вимкніть, якщо запис кількох лімітів не вартий місця на диску.
+
+
+
--bulk
+
0 - 10000 файлів
+
50
+
Скільки файлів у масовому завантаженні. Нуль повністю прибирає цю групу з набору.
+
+
+
+
+
+
+
+
Як його запустити?
+
Подивіться, скільки коштував би набір, зберіть його або візьміть його рецепт для правки:
+ Двійкова фікстура в репозиторії лишається в його історії назавжди, її не можна перевірити в діфі, і
+ вона перестає бути можливою, коли файл великий. Генеруйте файли всередині конвеєра з рецепта.
+ Рецепт - це текст, байти щоразу виходять однакові, а останній крок доводить, що нічого не
+ зсунулося.
+
+
+
+
Коротка відповідь
+
+ Установіть tfg, запустіть tfg generate fixtures.yaml --out ./fixtures
+ перед тестами і tfg verify ./fixtures/manifest.json після них. Обидва кроки самі
+ валять збірку, з кодом завершення, який каже чому.
+
+
+
+
+
Чому не комітити
+
Чому фікстурі не місце в репозиторії
+
+
+ Вона лишається в історії. Видалення двійкового файлу пізніше не робить клон меншим,
+ бо кожна його версія все ще там.
+
+
+ Діф не показує, що змінилося. Рецензент бачить, що PDF інший, і нічого більше.
+ Рецепт змінюється на один рядок.
+
+
+ Великі файли не вміщаються. GitHub відхиляє push, у якому є файл більший за 100 МБ,
+ тож тесту ліміту завантаження в 500 МБ нічого комітити.
+
+
+
+ Комітити потрібно рецепт. Той самий рецепт із тим самим зерном записує ті самі байти на будь-якій
+ машині, тож файл, створений у конвеєрі, - це файл, який був у вас на ноутбуці.
+
+
+
+
+
Рецепт
+
Рецепт, що лежить поруч із тестами
+
+ Цей записує двадцять п'ять рахунків, які мають бути прийняті, і два зображення понад ліміт, які
+ мають бути відхилені, а маніфест фіксує обидва очікування:
+
+ Рядок із контрольною сумою звіряє архів із verify-SHA256SUMS.txt з того самого випуску.
+ Версію закріплено, тож новий випуск ніколи не змінить збірку, якої ви не торкалися.
+
+ У кожного завершення свій код, тож крок падає сам, а журнал каже, який саме. Ті, що трапляються
+ конвеєру:
+
+
+
3 - рецепт недопустимий. Нічого не записано, і названо кожну проблему
+
4 - формат не вміє того, про що попросили, наприклад розміру менше за свій мінімум
+
6 - не вистачає місця на диску
+
7 - tfg verify знайшов файл, що не збігається зі своїм маніфестом
+
8 - запуск закінчився, але створено не все
+
+
+ Невдалий запуск нічого не друкує у стандартний вивід, тож розбирач журналів ніколи не сприйме
+ помилку за дані. Уся таблиця на сторінці документації.
+
+
+
+
+
PowerShell
+
Скрипту PowerShell потрібен ще один рядок
+
+ PowerShell не виносить код завершення програми з файлу .ps1. Запустіть такий файл із
+ -File, і скрипт відповість 0, навіть коли інструмент усередині
+ відмовився працювати, тож збірка, яка мала б бути червоною, стає зеленою. Останній рядок - це
+ все виправлення:
+
+ Так поводиться PowerShell, а не цей інструмент. cmd, bash і
+ zsh нічого зайвого не потребують.
+
+
+
+
+
Кілька завдань
+
Як ділитися фікстурами між завданнями
+
+ Зазвичай завантажувати їх не треба. Оскільки той самий рецепт записує ті самі байти, кожне завдання
+ може запустити власний tfg generate, що швидше за завантаження й скачування. Коли
+ завдання має отримати файли від іншого, запустіть після передачі tfg verify на
+ маніфесті, і він скаже, чи збігається отримане із записаним.
+
+ П'ять завдань, що виникають майже в кожному проєкті, який приймає файли від людей, і команда, що
+ розв'язує кожне. Кожен приклад нижче запускається як написано.
+
+
+
+
Ліміти завантаження
+
Перевірка того, що ліміт розміру файлу застосовується там, де заявлено
+
+ Ліміт - це три тестові випадки, а не один: трохи нижче, рівно за лімітом і трохи вище. Отримати їх
+ вручну означає рахувати числа байтів і сподіватися, що ви не помилилися на одиницю. Запросіть
+ натомість набір:
+
+ Ви отримаєте три справжні PDF по 1048575, 1048576 і 1048577 байт та маніфест, що каже: перші два
+ слід прийняти, а третій відхилити за size_limit. Ваш тест читає очікування, замість
+ того щоб ви писали три перевірки вручну, а коли ліміт змінюється, ви змінюєте одне число й
+ запускаєте знову.
+
+
+ Те саме працює й без пресета, коли потрібен один набір меж просто в команді:
+
Тримати фікстури поза репозиторієм, не втрачаючи їх
+
+ Великі бінарні фікстури сповільнюють клонування репозиторію й заважають рев'ю, а при заміні ніхто не
+ може сказати, що змінилося. Рецепт - це кілька сотень символів YAML, що відтворюють ті самі
+ файли - байт у байт, на будь-якій машині - бо кожен файл виводиться з seed
+ запуску.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Кожен кінець має власний код завершення, тому конвеєр відрізняє поганий рецепт від повного диска й
+ від розбіжності під час перевірки. Невдалий запуск нічого не друкує в стандартний вивід, і
+ розбірник журналів не сприймає помилку за дані.
+
+
+
+
+
Масштаб
+
З'ясувати, що відбувається, коли тека велика
+
+ Процедури імпорту, нічні завдання та списки каталогів поводяться інакше за десяти тисяч файлів, ніж
+ за десяти. Розміри, вибрані з діапазону, роблять набір схожим на справжній трафік, а не на
+ десять тисяч однакових файлів, і вибір іде від seed, тож завтра набір буде той самий.
+
+ Запуск, більший за вільне місце на диску, відхиляється до запису першого байта, а не заповнює диск і
+ не падає на півдорозі.
+
+
+
+
+
Архіви
+
Перевірка розпакувальника на архіві, що справді містить файли
+
+ Порожній архів із правильним розширенням нічого не доводить про код, який його відкриває й обходить
+ вміст. Оголосіть вміст, і архів справді його містить:
+
+ Глибина вкладеності, кількість записів і розмір вмісту - це те, про що в процедури імпорту є власна
+ думка, і так ви дізнаєтеся, яка вона.
+
+
+
+
+
Парсери та переглядачі
+
Перевірка того, що ваш власний код читає формат так само, як справжнє ПЗ
+
+ Кожен формат тут перевіряється незалежним читачем до випуску: PNG відкривається й порівнюються його
+ пікселі, DOCX перечитується окремими бібліотеками, архів розпаковується. Це означає, що файл,
+ який відхиляє ваш парсер, - знахідка про ваш парсер, а не про генератор.
+
+ Сторінка форматів перелічує налаштування кожного формату та найменший
+ файл, яким він може бути.
+
+
+
+
+
Посібники
+
Два з них докладніше
+
+
+ Пошкоджені тестові файли - файл, навмисно зіпсований, точного
+ розміру, із записаним у маніфесті тим, що з ним має статися.
+
+
+ Тестові файли в CI - workflow для GitHub Actions, завдання
+ GitLab і коди завершення, що валять збірку.
+
+
+
+
+
+
Для кого це
+
+ QA-інженери, автоматизація тестування та всі, за чиїм кодом стоїть форма завантаження, процедура
+ імпорту, парсер чи квота сховища. Працює на машині взагалі без мережі, що важливо в закритому
+ корпоративному середовищі, де генератор у браузері - не варіант.
+
26 định dạng tệp, mỗi định dạng được tạo ở kích thước chính xác
+
+ Mỗi cái là một tệp thật của định dạng đó. Nó mở được bằng phần mềm của nó và có
+ đúng số byte bạn đã yêu cầu. Không cái nào là số không độn với phần mở rộng dán vào.
+
+
+
+
+
+
+
Định dạng
+
Tên
+
Phần mở rộng
+
Tệp nhỏ nhất
+
Độ đầy đủ
+
Kiểm tra bằng
+
+
+
+
+
avif
+
AV1 Image File Format
+
.avif
+
311
+
full
+
pillow
+
+
+
bmp
+
Windows Bitmap
+
.bmp
+
58
+
full
+
pillow
+
+
+
csv
+
Comma-Separated Values
+
.csv
+
115
+
full
+
python-csv
+
+
+
docx
+
Word (Office Open XML)
+
.docx
+
1220
+
full
+
libreoffice
+
+
+
gif
+
Graphics Interchange Format
+
.gif
+
114
+
full
+
pillow
+
+
+
html
+
HyperText Markup Language
+
.html
+
118
+
full
+
python-html
+
+
+
ico
+
Windows Icon
+
.ico
+
70
+
full
+
pillow
+
+
+
jpg
+
JPEG
+
.jpg
+
602
+
full
+
pillow
+
+
+
json
+
JavaScript Object Notation
+
.json
+
219
+
full
+
node-json
+
+
+
jxl
+
JPEG XL
+
.jxl
+
147
+
full
+
pillow-jxl
+
+
+
log
+
Server and application log
+
.log
+
155
+
full
+
không áp dụng
+
+
+
md
+
Markdown
+
.md
+
0
+
full
+
không áp dụng
+
+
+
pdf
+
Portable Document Format
+
.pdf
+
3415
+
full
+
pdftotext
+
+
+
png
+
Portable Network Graphics
+
.png
+
74
+
full
+
pillow
+
+
+
pptx
+
PowerPoint (Office Open XML)
+
.pptx
+
4809
+
full
+
libreoffice
+
+
+
svg
+
Scalable Vector Graphics
+
.svg
+
194
+
full
+
inkscape
+
+
+
targz
+
tar + gzip
+
.tar.gz
+
9790
+
full
+
7z
+
+
+
tiff
+
Tagged Image File Format
+
.tiff
+
183
+
full
+
pillow
+
+
+
toml
+
TOML
+
.toml
+
212
+
full
+
python-toml
+
+
+
txt
+
Plain text
+
.txt
+
0
+
full
+
không áp dụng
+
+
+
wav
+
Waveform Audio
+
.wav
+
98
+
full
+
ffprobe
+
+
+
webp
+
WebP
+
.webp
+
148
+
full
+
pillow
+
+
+
xlsx
+
Excel (Office Open XML)
+
.xlsx
+
1726
+
full
+
libreoffice
+
+
+
xml
+
Extensible Markup Language
+
.xml
+
264
+
full
+
python-xml
+
+
+
yaml
+
YAML
+
.yaml
+
241
+
full
+
python-yaml
+
+
+
zip
+
ZIP
+
.zip
+
8382
+
full
+
7z
+
+
+
+
+
+
+
Ý nghĩa các cột
+
+
+
Tệp nhỏ nhất
+
+ Số byte ít nhất mà công cụ này chấp nhận cho định dạng đó, gồm cả nhãn nó ghi vào trong tệp. Yêu cầu
+ ít hơn và bạn nhận một lỗi nêu mức sàn cùng lý do, không bao giờ là tệp sai kích thước.
+
+
+
+
Độ đầy đủ
+
+ Tệp đầy đủ đến đâu. full nghĩa là một trình đọc thật sự phân tích định dạng sẽ chấp
+ nhận nó, chứ không chỉ là phần mở rộng khớp.
+
+
+
+
Kiểm tra bằng
+
+ Trình đọc độc lập mở mọi tệp được tạo trước khi định dạng được phát hành - một bản cài đặt riêng,
+ không phải mã của chính chúng tôi tự chấm bài tập của mình.
+
+
+
+
+ Mỗi định dạng cũng lặp lại đến từng byte: cùng công thức và cùng seed cho các tệp giống hệt trên mọi
+ máy, điều làm cho việc commit một công thức thay cho chính các fixture trở nên an toàn.
+
+
+
+
+
Các thiết lập mỗi định dạng nhận
+
+ Hầu hết định dạng có thiết lập riêng - kích thước ảnh, chất lượng JPEG, số trang PDF, số dòng và cột
+ trong bảng tính, số mục nằm trong một tệp nén. Đặt chúng bằng --set key=value trên
+ dòng lệnh, hoặc dưới properties: trong công thức.
+
ngày như 2024-02-29 hoặc 2024-02-29T13:45:00+02:00, hoặc none
+
+
+
+
modified
+
ngày như 2024-02-29 hoặc 2024-02-29T13:45:00+02:00, hoặc none
+
+
+
png
+
width
+
1 - 20000 pixel
+
+
+
+
height
+
1 - 20000 pixel
+
+
+
pptx
+
slides
+
1 - 500 trang chiếu
+
+
+
svg
+
width
+
1 - 20000 pixel
+
+
+
+
height
+
1 - 20000 pixel
+
+
+
targz
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
id của một định dạng, như tfg formats liệt kê
+
+
+
+
entry_size
+
kích thước như 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
đúng hoặc sai
+
+
+
+
entry_mode
+
000, 400, 444, 600, 644, 664, 666, 700, 755, 777
+
+
+
+
entry_owner
+
root, unset, user
+
+
+
tiff
+
width
+
1 - 20000 pixel
+
+
+
+
height
+
1 - 20000 pixel
+
+
+
txt
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
đúng hoặc sai
+
+
+
wav
+
sample_rate
+
8000 - 192000 hertz
+
+
+
+
bit_depth
+
8, 16, 24, 32
+
+
+
+
channels
+
1 - 8
+
+
+
+
content
+
noise, silence, sweep, tone
+
+
+
webp
+
width
+
1 - 16383 pixel
+
+
+
+
height
+
1 - 16383 pixel
+
+
+
xlsx
+
rows
+
1 - 200000 dòng
+
+
+
+
columns
+
1 - 32768 cột
+
+
+
xml
+
encoding
+
utf-16be, utf-16le, utf-8
+
+
+
+
bom
+
đúng hoặc sai
+
+
+
zip
+
entries
+
0 - 10000
+
+
+
+
entry_format
+
id của một định dạng, như tfg formats liệt kê
+
+
+
+
entry_size
+
kích thước như 2mb
+
+
+
+
compression
+
best, default, fast, none
+
+
+
+
depth
+
0 - 50
+
+
+
+
directory_entries
+
đúng hoặc sai
+
+
+
+
password
+
mật khẩu, ở dạng văn bản thuần
+
+
+
+
encryption
+
aes-128, aes-192, aes-256, none, zipcrypto
+
+
+
+
+
+ Giá trị nằm ngoài thứ một thiết lập chấp nhận bị từ chối bằng thông báo nêu thiết lập, khoảng cho
+ phép và nên dùng gì thay thế. Thiết lập lạ cũng là lỗi, không bao giờ là mặc định im lặng - lỗi
+ gõ được chấp nhận trong im lặng cho ra tệp sai thiết lập và một giờ tự hỏi vì sao bài kiểm thử
+ qua khi lẽ ra không.
+
+
+ Chạy tfg formats <id> để xem chính xác một định dạng nhận gì trong bản dựng bạn
+ có.
+
+
+
+
+
Tệp nén chứa tệp thật
+
+ targz và zip có
+ thể được nhồi các mục thay vì để thành cái vỏ rỗng. Tệp nén được tạo thật sự chứa các tài liệu
+ nó tuyên bố chứa, nên bất cứ thứ gì giải nén nó trong lúc kiểm thử đều thấy tệp thật bên trong.
+
+ Giấy phép, quyền riêng tư, khả năng tái lập và những điều mọi người kiểm tra trước khi đưa một trình
+ tạo vào pipeline build. Nếu câu hỏi của bạn chưa có ở đây, trình
+ theo dõi issue luôn mở.
+
+
+
+
+
Điều này khác gì dd, fsutil hay truncate?
+
+
Chúng cho bạn một tệp đúng kích thước nhưng đầy sự trống rỗng. Tệp 2 MB tên photo.png tạo kiểu đó không phải PNG, nên bất cứ thứ gì thực sự phân tích nó sẽ từ chối vì lý do sai, và bài kiểm thử của bạn cũng qua vì lý do sai. Công cụ này tạo ra một PNG thật đúng 2 MB, mở được trong trình xem ảnh, và đi kèm lời khai về cách hệ thống của bạn cần xử lý nó.
Nó có miễn phí không, và tôi dùng ở chỗ làm được không?
+
+
Có cho cả hai. Nó phát hành theo GPL-3.0 và không tốn gì. Không có tài khoản, khóa giấy phép hay gói trả phí.
+
+
+
+
Tôi có dùng tệp được tạo trong sản phẩm mã nguồn đóng được không?
+
+
Được. Giấy phép áp dụng cho mã của công cụ, không áp dụng cho thứ công cụ tạo ra. Tệp, công thức và manifest được tạo là đầu ra chứ không phải tác phẩm phái sinh, nên bạn có thể commit và phân phối mà không có nghĩa vụ nào.
+
+
+
+
Tệp được tạo có chứa dữ liệu cá nhân thật không?
+
+
Không. Mọi thứ bên trong đều được tổng hợp từ một seed. Không có tập dữ liệu nào được đọc, không dịch vụ nào được liên hệ và không nội dung bên thứ ba nào được nhúng. Hãy coi địa chỉ e-mail được tạo là không dùng được thay vì chưa dùng, vì chuỗi ngẫu nhiên nào cũng có thể ngẫu nhiên trùng với địa chỉ thật.
+
+
+
+
Tôi có nhận đúng các tệp giống hệt trên máy khác không?
+
+
Có, từng byte, với cùng công thức và cùng seed. Dự án kiểm thử điều đó ở mỗi thay đổi, và phá vỡ nó đòi hỏi tăng phiên bản chính. Đó là điều cho phép bạn commit một công thức nhỏ thay vì các fixture nhị phân lớn.
+
+
+
+
Nó có cần kết nối internet không?
+
+
Không bao giờ. Không có telemetry, không kiểm tra cập nhật và không có máy khách đám mây, và bản nhị phân dòng lệnh hoàn toàn không biên dịch sẵn ngăn xếp mạng. Nó chạy trên máy không có mạng và trong môi trường doanh nghiệp đóng.
+
+
+
+
Chuyện gì xảy ra nếu tôi yêu cầu kích thước mà một định dạng không thể đạt tới?
+
+
Bạn nhận một lỗi nêu định dạng, kích thước nhỏ nhất có thể, lý do của mức sàn đó và việc nên làm thay thế, và không có tệp nào được ghi. Công cụ không bao giờ làm tròn kích thước một cách lặng lẽ. Mỗi mức sàn đều được liệt kê trên trang định dạng.
+
tfg formats png
+
+
+
+
Tôi có thể tạo một tệp cố ý bị hỏng không?
+
+
Có. Thêm --damage zero-head và tệp ra đúng kích thước bạn yêu cầu, với các byte đầu bị ghi đè bằng số không, nên trình đọc từ chối nó, và manifest nói hệ thống của bạn phải từ chối nó. Chi tiết nằm ở trang về tệp kiểm thử bị hỏng.
7z, mp3 và mp4. Hôm nay có 26 định dạng hoạt động trọn vẹn từ đầu đến cuối.
+
+
+
+
Tôi chạy nó trên những hệ thống nào?
+
+
Dòng lệnh chạy trên Windows và Linux cả Intel lẫn ARM, và trên Mac Apple Silicon. Cửa sổ desktop được cung cấp cho Windows trên Intel, Linux trên Intel và Mac Apple Silicon. Mac Intel không được hỗ trợ và không có gì được dựng cho chúng.
+
+
+
+
Tôi có phải cài gì không?
+
+
Không. Tải kho lưu trữ cho hệ thống của bạn, giải nén và chạy bản nhị phân. Không có trình cài đặt, không có runtime cần thêm và không có phụ thuộc cần giải quyết. Nếu bạn có Go, một lệnh go install duy nhất cũng được.
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
Vì sao chạy trên hàng nghìn tệp chậm hơn trên Windows?
+
+
Vì Windows tính phí nhiều hơn cho mỗi đường dẫn nó xem, và một lệnh duyệt hàng nghìn tệp xem hàng nghìn đường dẫn. Đo trên một máy với 3000 tệp 1 kB, verify mất khoảng 0,9 giây trên Windows và khoảng 0,2 giây trên Linux trong container. Đường dẫn đầu ra ngắn hơn làm con số Windows nhỏ đi, vì mỗi thư mục phía trên các tệp đều nằm trong thứ được xem.
+ PDF, PNG, DOCX, ZIP - tổng cộng 26 định dạng, và mỗi tệp là
+ tệp thật mở được bằng phần mềm của nó, ở đúng kích thước bạn yêu cầu. Mỗi lần
+ chạy còn ghi lại ứng dụng của bạn cần làm gì với từng tệp. Dòng lệnh và cửa sổ desktop, miễn
+ phí, mã nguồn mở, chạy hoàn toàn trên máy của bạn.
+
Miễn phí, mã nguồn mở, GPL-3.0. Không cần đăng ký. Bản tải cho Windows và macOS đã được ký nên khởi động không cảnh báo.
+
+
+
+
+ Cửa sổ desktop, sẵn sàng ghi một lô tệp. Cùng một động cơ chạy phía sau dòng lệnh.
+
+
+
+
+
+ 26
+
định dạng thật, mỗi định dạng mở được bằng phần mềm của nó
+
+
+ 1 byte
+
độ chính xác của mọi kích thước bạn yêu cầu, không bao giờ bị làm tròn lặng lẽ
+
+
+ 0
+
kết nối đến bất cứ đâu - không tài khoản, không telemetry, không kiểm tra cập nhật
+
+
+
+
+
Vấn đề
+
Làm một tệp kiểm thử thì dễ. Làm đúng một nghìn tệp mới là phần mệt mỏi
+
Bạn đang kiểm thử phần mềm nhận tệp từ con người. Sớm hay muộn bạn sẽ cần:
+
+
một PDF đúng 10 MB, để biết giới hạn tải lên có thật không
+
ba tệp nằm hai bên giới hạn đó, để bắt lỗi lệch một
+
10.000 tệp nhật ký, để xem tác vụ ban đêm làm gì khi thư mục lớn
+
một ZIP thật sự chứa 200 tài liệu, không phải cái vỏ rỗng với đuôi đúng
+
một tệp 4 GB, mà không phải giữ tệp 4 GB trong kho mã của bạn
+
các fixture giống hệt trên laptop và trên máy chủ build, từng byte
+
+
+ Đó là thứ nó thay thế. Nó được làm cho kỹ sư QA, tự động hóa kiểm thử và bất kỳ ai có mã đứng sau là
+ biểu mẫu tải lên, quy trình nhập, bộ phân tích cú pháp hoặc hạn ngạch lưu trữ.
+
+
+
+
+
Điều làm nó khác biệt
+
Các trình tạo khác dừng ở các byte. Cái này trả lời điều bài kiểm thử của bạn thật sự hỏi
+
+ Một thư mục tệp vẫn để bạn tự quyết định mỗi tệp chứng minh điều gì. Mỗi lần chạy ở đây ghi một
+ manifest.json bên cạnh các tệp - danh sách đơn giản mọi thứ đã tạo, và với mỗi mục
+ là một kỳ vọng được khai báo.
+
+
Giả sử endpoint tải lên của bạn cho phép 1 MB. Hãy yêu cầu ba tệp nằm trên ranh giới đó:
Khi câu trả lời phụ thuộc chính sách của riêng bạn, manifest sẽ nói rõ
+
+ Nó ghi unspecified thay vì bịa ra kỳ vọng. Một trình tạo đoán mò tạo ra thất bại giả,
+ và bộ kiểm thử cứ báo động giả sẽ bị tắt.
+
+
+
+
+
+
Preset
+
Chọn câu hỏi, nhận cả bộ
+
+ Preset là một bộ tệp kiểm thử được thiết kế quanh một câu hỏi kiểm thử, để bạn không phải tự tìm ra
+ tệp nào chứng minh điều gì. Mỗi preset có một trang nói nó thường tìm thấy gì, trong bộ có gì và
+ mọi thiết lập nó nhận.
+
+ Mười nghìn tệp nhật ký, mỗi tệp từ một đến tám kilobyte, với kích thước rút từ seed để ngày mai ra
+ cùng một bộ. Cho mỗi lần chạy một thư mục riêng - manifest là bản ghi duy
+ nhất về những gì một lần chạy đã ghi, nên công cụ từ chối ghi cái thứ hai đè lên:
+
+ Kích thước đếm theo 1024, như trình quản lý tệp của bạn, nên 2mb nghĩa là 2097152 byte.
+ Số byte thuần cũng được. Tài liệu bao gồm công thức, manifest và các
+ mã thoát.
+
+
+
+
+
Bạn nhận được gì
+
Làm cho bộ kiểm thử chạy không cần người trông
+
+
+
Kích thước chính xác, đến từng byte
+
Yêu cầu 10485761 byte và nhận đúng như vậy. Kích thước mà định dạng không thể đạt là một lỗi có lý do, không bao giờ là tệp sai kích thước.
+
+
+
26 định dạng thật
+
Không phải số không độn kèm một phần mở rộng. PNG được tạo mở trong trình xem ảnh, DOCX mở trong Word, ZIP giải nén được. Mỗi định dạng được kiểm tra bằng các trình đọc độc lập trước khi phát hành.
+
+
+
Một manifest là một oracle kiểm thử
+
Đường dẫn, kích thước, SHA-256, định dạng, seed, phiên bản công cụ - và việc hệ thống của bạn cần làm với tệp.
+
+
+
Tái lập được
+
Cùng công thức và cùng seed, cùng các byte, trên mọi máy. Hãy commit một công thức YAML nhỏ thay vì các fixture nhị phân lớn.
+
+
+
Hai giao diện, một động cơ
+
Một dòng lệnh làm cho CI và một cửa sổ desktop cho kiểm thử khám phá. Cái nào cũng không phải bản cắt giảm của cái kia, và một bài kiểm thử so sánh chúng từng khả năng một.
+
+
+
Hoàn toàn ngoại tuyến
+
Không tài khoản, không đám mây, không telemetry, không kiểm tra cập nhật. Bản nhị phân dòng lệnh hoàn toàn không biên dịch sẵn ngăn xếp mạng.
+
+
+
+
+
+
Tải xuống
+
Chọn bản dựng cho hệ thống của bạn
+
+ Giải nén kho lưu trữ rồi chạy. tfg là dòng lệnh và tfg-gui là cửa sổ
+ desktop. Không có trình cài đặt và không có gì phải thêm vào máy của bạn.
+
+
+
+
+
+
Hệ thống
+
Dòng lệnh
+
Cửa sổ desktop
+
+
+
+
+
Windows
+
amd64, arm64
+
amd64
+
+
+
Linux
+
amd64, arm64
+
amd64
+
+
+
macOS
+
arm64
+
arm64
+
+
+
+
+
+
Cái nào được ký, cái nào không
+
+ Bản tải cho Windows và macOS đã được ký, nên khởi động mà không có cảnh báo nhà phát triển không xác
+ định. Bản Linux thì không, vì Linux desktop không có gì tương đương để ký. Mỗi kho lưu trữ
+ được liệt kê trong verify-SHA256SUMS.txt trên trang phát hành, để bạn kiểm tra
+ thứ mình đã tải.
+
Một tệp hợp lệ và nhỏ nhất mà định dạng cho phép có qua được không?
+
+ Preset empty-and-minimal dựng bằng một lệnh cả một bộ tệp kiểm thử thật cho câu hỏi này, kèm
+ một manifest.json bên cạnh nêu cách hệ thống của bạn cần phản ứng với từng tệp. Mọi
+ thứ bên dưới được đọc từ chương trình, ở các giá trị mặc định của phiên bản này.
+
+
+
+
+
Nó thường tìm thấy gì?
+
+
tệp hợp lệ bị từ chối vì quá nhỏ, khi bước kiểm tra đếm byte thay vì đọc chúng
+
tệp rỗng làm trình đọc sập thay vì được báo cáo
+
ảnh rộng một pixel chia cho không trên đường tạo ảnh thu nhỏ
+
bộ lưu trữ đọc không byte như một lần tải lên thất bại và cứ thử lại mãi
+
+
+
+
+
+
Trong bộ có gì?
+
Ở các giá trị mặc định, như tfg preset show empty-and-minimal báo cáo:
Hệ thống của tôi có lưu, hiển thị và trả lại một tên tệp mà nó không ngờ tới không?
+
+ Preset filename-handling dựng bằng một lệnh cả một bộ tệp kiểm thử thật cho câu hỏi này, kèm
+ một manifest.json bên cạnh nêu cách hệ thống của bạn cần phản ứng với từng tệp. Mọi
+ thứ bên dưới được đọc từ chương trình, ở các giá trị mặc định của phiên bản này.
+
+
+
+
+
Nó thường tìm thấy gì?
+
+
một tên trông như tên khác trên màn hình, trong nhật ký hoặc trong danh sách
+
một tên bị cắt, xén hoặc viết lại giữa lúc tải lên và lưu trữ
+
giới hạn độ dài tính bằng ký tự trong khi bộ lưu trữ tính bằng byte
+
+
+
+
+
+
Trong bộ có gì?
+
Ở các giá trị mặc định, như tfg preset show filename-handling báo cáo:
+
+
+
+
Tệp
50
+
Target trong công thức của nó
50
+
Tổng kích thước
51 200 B
+
Định dạng
txt
+
+
+
+
Và điều manifest của bộ đó mong đợi từ hệ thống của bạn:
+
+
+
+
Mong đợi
Ý nghĩa
Tệp
+
+
+
accept
Hệ thống của bạn nên nhận tệp.
4
+
unspecified
Tùy vào quy tắc của hệ thống bạn. Bạn quyết định, rồi kiểm tra điều xảy ra có đúng ý bạn không.
46
+
+
+
+
+
+
+
Bạn có thể đổi gì?
+
+
+
+
Thiết lập
Nhận
Mặc định
Tác dụng
+
+
+
+
--format
+
id định dạng từ trang định dạng
+
txt
+
Định dạng của mọi tệp trong bộ. Đây là một cờ của chính công cụ, và preset chỉ cho nó một giá trị mặc định.
+
+
+
+
+
+
+
+
Chạy nó thế nào?
+
Xem bộ sẽ tốn bao nhiêu, dựng nó, hoặc lấy công thức của nó để chỉnh sửa:
Preset tệp kiểm thử, một bộ cho mỗi câu hỏi kiểm thử
+
+ Preset là cả một bộ tệp kiểm thử được thiết kế quanh một câu hỏi, kèm manifest nêu cách hệ thống của
+ bạn cần phản ứng với từng tệp. Bạn chọn câu hỏi, công cụ dựng bộ. Mỗi preset có trang riêng nói nó
+ thường tìm thấy gì, trong bộ có gì và mọi thiết lập nó nhận.
+
Biểu mẫu tải lên của tôi có nhận đúng thứ nó cần và từ chối phần còn lại không?
+
upload-validation
+
+
+
+
+
Preset khác công thức thế nào?
+
+ Về bản chất thì không khác. Preset là công thức mà công cụ viết cho bạn từ vài thiết lập. tfg
+ preset eject in công thức đó ra để bạn giữ cạnh các bài kiểm thử và chỉnh sửa, và công
+ thức của riêng bạn có thể xây trên một preset bằng một dòng, extends: preset: theo
+ sau là id của nó.
+
+
tfg preset list
+tfg preset show size-boundaries
+tfg preset eject size-boundaries > my.yaml
+
+
+
+
Tôi có thể tin các giá trị mặc định không?
+
+ Với các tệp thì có. Với con số chỉ hệ thống của bạn biết, như giới hạn của một biểu mẫu tải lên, giá
+ trị mặc định là giá trị tạm của chúng tôi, và công cụ nói vậy mỗi lần dùng một giá trị như thế.
+ Trang của mỗi preset đánh dấu các thiết lập đó, và tfg preset show nói điều đó
+ trước khi ghi bất cứ gì.
+
Giới hạn kích thước có được áp dụng đúng nơi nó được khai báo không?
+
+ Preset size-boundaries dựng bằng một lệnh cả một bộ tệp kiểm thử thật cho câu hỏi này, kèm
+ một manifest.json bên cạnh nêu cách hệ thống của bạn cần phản ứng với từng tệp. Mọi
+ thứ bên dưới được đọc từ chương trình, ở các giá trị mặc định của phiên bản này.
+
+
+
+
+
Nó thường tìm thấy gì?
+
+
lỗi lệch một ở giới hạn
+
nhầm MB với MiB, tức 4,8 phần trăm và đủ để lọt một tệp lẽ ra không được qua
+
giới hạn được áp dụng ở trình duyệt chứ không phải ở máy chủ
+
+
+
+
+
+
Trong bộ có gì?
+
Ở các giá trị mặc định, như tfg preset show size-boundaries báo cáo:
+
+
+
+
Tệp
7
+
Target trong công thức của nó
7
+
Tổng kích thước
73 400 320 B
+
Định dạng
pdf
+
+
+
+
Và điều manifest của bộ đó mong đợi từ hệ thống của bạn:
+
+
+
+
Mong đợi
Ý nghĩa
Tệp
+
+
+
accept
Hệ thống của bạn nên nhận tệp.
4
+
reject
Hệ thống của bạn nên từ chối tệp.
3
+
+
+
+
+
+
+
Bạn có thể đổi gì?
+
+
+
+
Thiết lập
Nhận
Mặc định
Tác dụng
+
+
+
+
--limit
+
kích thước như 2mb
+
10mb
+
Giới hạn kích thước mà hệ thống của bạn khai báo. Mọi thứ khác được đo từ đó. Giá trị mặc định này là giá trị tạm của chúng tôi, không phải giá trị của hệ thống bạn. Hãy truyền giá trị của riêng bạn.
+
+
+
--spread
+
các kích thước cách nhau bằng dấu phẩy
+
1B,1kb,1mb
+
Vươn ra xa bao nhiêu về hai phía của giới hạn, dưới dạng danh sách kích thước.
+
+
+
--format
+
id định dạng từ trang định dạng
+
pdf
+
Định dạng của mọi tệp trong bộ. Đây là một cờ của chính công cụ, và preset chỉ cho nó một giá trị mặc định.
+
+
+
+
+
+
+
+
Chạy nó thế nào?
+
Xem bộ sẽ tốn bao nhiêu, dựng nó, hoặc lấy công thức của nó để chỉnh sửa:
Việc nhập bảng của tôi có chịu được những gì công cụ thật xuất ra không?
+
+ Preset tabular-import dựng bằng một lệnh cả một bộ tệp kiểm thử thật cho câu hỏi này, kèm
+ một manifest.json bên cạnh nêu cách hệ thống của bạn cần phản ứng với từng tệp. Mọi
+ thứ bên dưới được đọc từ chương trình, ở các giá trị mặc định của phiên bản này.
+
+
+
+
+
Nó thường tìm thấy gì?
+
+
tệp dùng dấu chấm phẩy bị đọc thành một cột, vì dấu phân cách được giả định thay vì được dò tìm
+
tệp CRLF bị tách thành các dòng với một dòng trống sau mỗi dòng
+
bảng không có tiêu đề mà dòng dữ liệu đầu bị nuốt làm tên cột
+
lần nhập giữ các cột nó hiển thị được và lặng lẽ bỏ phần còn lại
+
trình đọc lấy bản ghi JSON từng dòng một và dừng ở tài liệu thụt lề đầu tiên
+
+
+
+
+
+
Trong bộ có gì?
+
Ở các giá trị mặc định, như tfg preset show tabular-import báo cáo:
+
+
+
+
Tệp
13
+
Target trong công thức của nó
13
+
Tổng kích thước
3 080 060 B
+
Định dạng
csv, json, xlsx
+
+
+
+
Và điều manifest của bộ đó mong đợi từ hệ thống của bạn:
+
+
+
+
Mong đợi
Ý nghĩa
Tệp
+
+
+
accept
Hệ thống của bạn nên nhận tệp.
8
+
unspecified
Tùy vào quy tắc của hệ thống bạn. Bạn quyết định, rồi kiểm tra điều xảy ra có đúng ý bạn không.
5
+
+
+
+
+
+
+
Bạn có thể đổi gì?
+
+
+
+
Thiết lập
Nhận
Mặc định
Tác dụng
+
+
+
+
--rows
+
1 - 200000 dòng
+
1000
+
Bảng tính có bao nhiêu dòng. Tệp được ghi đúng bằng kích thước mà chừng đó dòng đóng gói thành, nên ngân sách ở trên dịch chuyển theo giá trị này.
+
+
+
--columns
+
1 - 32768 cột
+
10
+
Mỗi dòng của bảng tính có bao nhiêu cột. Số dòng nhân số cột có trần, và yêu cầu vượt trần sẽ bị từ chối trước khi ghi bất cứ thứ gì.
+
+
+
+
+
+
+
+
Chạy nó thế nào?
+
Xem bộ sẽ tốn bao nhiêu, dựng nó, hoặc lấy công thức của nó để chỉnh sửa:
Trình đọc của tôi có biết tệp ở mã hóa nào, hay chỉ đoán?
+
+ Preset text-encoding dựng bằng một lệnh cả một bộ tệp kiểm thử thật cho câu hỏi này, kèm
+ một manifest.json bên cạnh nêu cách hệ thống của bạn cần phản ứng với từng tệp. Mọi
+ thứ bên dưới được đọc từ chương trình, ở các giá trị mặc định của phiên bản này.
+
+
+
+
+
Nó thường tìm thấy gì?
+
+
trình đọc giả định UTF-8 và hiện tệp UTF-16 thành cứ ba ký tự mới có một, hoặc thành hàng ô vuông
+
dấu thứ tự byte bị đọc như nội dung, nên trường đầu tiên của lần nhập bắt đầu bằng ba ký tự lạ
+
trình nhập đoán mã hóa từ các byte đầu và đoán khác đi với tệp dài hơn
+
tệp CRLF bị tách thành các dòng với một dòng trống sau mỗi dòng, hoặc ký tự xuống dòng còn sót trong trường cuối
+
+
+
+
+
+
Trong bộ có gì?
+
Ở các giá trị mặc định, như tfg preset show text-encoding báo cáo:
+
+
+
+
Tệp
20
+
Target trong công thức của nó
20
+
Tổng kích thước
81 920 B
+
Định dạng
csv, log, md, txt, xml
+
+
+
+
Và điều manifest của bộ đó mong đợi từ hệ thống của bạn:
+
+
+
+
Mong đợi
Ý nghĩa
Tệp
+
+
+
accept
Hệ thống của bạn nên nhận tệp.
10
+
unspecified
Tùy vào quy tắc của hệ thống bạn. Bạn quyết định, rồi kiểm tra điều xảy ra có đúng ý bạn không.
10
+
+
+
+
+
+
+
Bạn có thể đổi gì?
+
+
+
+
Thiết lập
Nhận
Mặc định
Tác dụng
+
+
+
+
--sample
+
kích thước như 2mb
+
4kb
+
Mỗi tệp trong bộ lớn bao nhiêu. UTF-16 lưu hai byte cho mỗi ký tự, nên số lẻ bị từ chối.
+
+
+
+
+
+
+
+
Chạy nó thế nào?
+
Xem bộ sẽ tốn bao nhiêu, dựng nó, hoặc lấy công thức của nó để chỉnh sửa:
Biểu mẫu tải lên của tôi có nhận đúng thứ nó cần và từ chối phần còn lại không?
+
+ Preset upload-validation dựng bằng một lệnh cả một bộ tệp kiểm thử thật cho câu hỏi này, kèm
+ một manifest.json bên cạnh nêu cách hệ thống của bạn cần phản ứng với từng tệp. Mọi
+ thứ bên dưới được đọc từ chương trình, ở các giá trị mặc định của phiên bản này.
+
+
+
+
+
Nó thường tìm thấy gì?
+
+
giới hạn được áp dụng ở trình duyệt chứ không phải ở máy chủ
+
tệp SVG hoặc HTML bị tưởng là ảnh hay văn bản thuần, một cách để lách tập lệnh qua biểu mẫu
+
tệp chỉ được kiểm bằng phần mở rộng mà không bao giờ mở, nên PDF đặt tên .jpg vẫn qua
+
biểu mẫu đọc cả phần thân vào bộ nhớ trước khi xem nó lớn đến đâu
+
lần tải lên tên PHOTO.JPG bị từ chối trong khi photo.jpg được nhận, hoặc ngược lại
+
tên có dấu cách, ngoặc hoặc ký tự ngoài ASCII được ghi xuống đĩa không thay đổi
+
+
+
+
+
+
Trong bộ có gì?
+
Ở các giá trị mặc định, như tfg preset show upload-validation báo cáo:
+
+
+
+
Tệp
71
+
Target trong công thức của nó
22
+
Tổng kích thước
120 639 488 B
+
Định dạng
html, jpg, pdf, png, svg, txt
+
+
+
+
Và điều manifest của bộ đó mong đợi từ hệ thống của bạn:
+
+
+
+
Mong đợi
Ý nghĩa
Tệp
+
+
+
accept
Hệ thống của bạn nên nhận tệp.
56
+
reject
Hệ thống của bạn nên từ chối tệp.
10
+
unspecified
Tùy vào quy tắc của hệ thống bạn. Bạn quyết định, rồi kiểm tra điều xảy ra có đúng ý bạn không.
5
+
+
+
+
+
+
+
Bạn có thể đổi gì?
+
+
+
+
Thiết lập
Nhận
Mặc định
Tác dụng
+
+
+
+
--limit
+
kích thước như 2mb
+
10mb
+
Giới hạn kích thước mà biểu mẫu tải lên của bạn khai báo. Bộ này đi một bước về mỗi phía - muốn tệp ở mọi khoảng cách, hãy chạy preset size-boundaries. Giá trị mặc định này là giá trị tạm của chúng tôi, không phải giá trị của hệ thống bạn. Hãy truyền giá trị của riêng bạn.
+
+
+
--allow
+
các id định dạng cách nhau bằng dấu phẩy
+
jpg,png,pdf
+
Biểu mẫu của bạn nên chấp nhận những loại nào. Mỗi loại trở thành một tệp thật thuộc loại đó, và chúng là đối chứng dương của cả bộ.
+
+
+
--deny
+
các phần mở rộng cách nhau bằng dấu phẩy
+
svg,html,exe,sh
+
Biểu mẫu của bạn nên từ chối những phần mở rộng nào. Phần mở rộng mà bản dựng này không có định dạng vẫn nhận một tệp mang tên đó, chứa văn bản thuần.
+
+
+
--far-over
+
10x, 2x, off
+
2x
+
Tệp lớn duy nhất vượt giới hạn bao xa. Tắt đi nếu ghi gấp nhiều lần giới hạn không đáng với dung lượng đĩa.
+
+
+
--bulk
+
0 - 10000 tệp
+
50
+
Số tệp trong lần tải lên hàng loạt. Bằng không thì bỏ hẳn nhóm đó khỏi bộ.
+
+
+
+
+
+
+
+
Chạy nó thế nào?
+
Xem bộ sẽ tốn bao nhiêu, dựng nó, hoặc lấy công thức của nó để chỉnh sửa:
+ Mọi thứ công cụ làm, sắp xếp theo những câu hỏi mà mọi người thật sự mang đến.
+ README trong kho mã là tài liệu tham chiếu đầy đủ và luôn khớp với
+ bản dựng bạn đã tải.
+
+
+
+
Có những lệnh nào?
+
Mỗi lệnh làm đúng một việc:
+
tfg generate tạo tệp, từ công thức hoặc từ các cờ
+tfg validate kiểm tra công thức và không ghi gì cả
+tfg verify kiểm tra một thư mục đối chiếu với manifest
+tfg cleanup xóa các tệp mà manifest liệt kê
+tfg recipe fmt in công thức ở dạng chuẩn hóa
+tfg preset dựng một bộ tệp từ một câu hỏi kiểm thử có tên
+tfg formats liệt kê các định dạng bản dựng này hỗ trợ
+tfg damage liệt kê các cách bản dựng này có thể cố ý làm hỏng một tệp
+tfg tool các tiện ích nhỏ cho tệp bạn đã có
+tfg version in phiên bản công cụ
+tfg license in giấy phép và ý nghĩa của nó với tệp được tạo
+
+
+
+
Làm sao tạo một tệp đơn có kích thước chính xác?
+
+ Nêu định dạng, kích thước và nơi đặt. Kích thước đếm theo 1024, nên 2mb là 2097152
+ byte. Số byte thuần cũng được, nên --size 10485761 yêu cầu đúng chừng đó.
+
+
tfg generate --format png --size 2mb --out ./out
+
Các cờ hữu ích của generate:
+
+
+
Cờ
Tác dụng
+
+
--format <id>
định dạng của các tệp, ví dụ txt
+
--size <size>
kích thước chính xác của mỗi tệp, như 10mb hoặc số byte thuần
+
--size-range <a-b>
kích thước rút cho từng tệp từ một khoảng, như 1kb-8kb. Lần rút lấy từ seed
+
--boundary <size>
ba tệp quanh một giới hạn: thấp hơn một byte, đúng giới hạn, cao hơn một byte
+
--count <n>
tạo bao nhiêu tệp. Mặc định 1
+
--name <template>
mẫu tên, ví dụ invoice_{index:04}.txt
+
--out <dir>
thư mục để ghi vào
+
--seed <n>
seed của lần chạy. Cùng seed cho cùng các byte
+
--set <k>=<v>
một thiết lập định dạng, lặp lại được
+
--damage <name>
cố ý làm hỏng tệp, lặp lại được và áp dụng theo thứ tự. Chạy tfg damage để xem danh sách
+
--expected <outcome>
accept, reject, sanitize hoặc unspecified
+
--dry-run
đếm và hiển thị, hoàn toàn không ghi gì
+
--json
ghi manifest ra đầu ra chuẩn
+
+
+
+
+
+
+
Làm sao tạo một tệp cố ý bị hỏng?
+
+ Mọi tệp khác mà công cụ này ghi đều đúng theo cách xây dựng, điều đó trả lời hai trong ba câu hỏi mà
+ trình kiểm tra tải lên đặt ra. --damage trả lời câu thứ ba - tệp có mở được không.
+ Tệp được tạo bình thường rồi bị làm hỏng, nên nó vẫn có kích thước bạn đã yêu cầu.
+
+ Các thiết lập đặt sau dấu hai chấm. Cờ lặp lại được, và thứ tự bạn viết là thứ tự chúng được áp
+ dụng. tfg damage liệt kê những gì bản dựng này làm được và mỗi kiểu nhận gì.
+
+
Trong công thức, khóa là một danh sách, gồm tên hoặc thiết lập:
+ Tệp bị làm hỏng nhận expected: reject trong manifest, kèm kiểu hỏng được ghi bên cạnh.
+ Hai thứ bị từ chối trước khi ghi bất cứ gì, vì mỗi thứ sẽ đặt lên đĩa một tệp mà manifest mô tả
+ sai:
+
+
+
tệp nhỏ hơn mức kiểu hỏng cần, vì nó sẽ ra mà không thay đổi
+
+ expected: accept bên cạnh một kiểu hỏng, vì không gì có thể đáp ứng. Hãy viết
+ sanitize nếu hệ thống được kiểm thử phải sửa tệp, hoặc unspecified
+ nếu đó chính là câu hỏi bạn đang đặt
+
+
+
+ Thứ ba không thể biết trước. Nếu một kiểu hỏng chạy mà không đổi byte nào, tệp đó bị bỏ thay vì được
+ ghi - lần chạy tiếp tục, nói đó là tệp nào và kết thúc bằng mã thoát một phần.
+
+ Công thức là một tệp YAML mô tả cả một lần chạy. Hãy commit nó bên cạnh các bài kiểm thử và fixture
+ thôi là tệp nhị phân trong kho mã - ai cũng có thể dựng lại chúng, từng byte, từ một tệp vài
+ trăm ký tự.
+
+ Mỗi target cần đúng một trong size, size-range, boundary hoặc
+ contains. Hai cái là lỗi và không cái nào cũng là lỗi. Công thức không hợp lệ ghi
+ không tệp nào và báo mọi vấn đề cùng lúc thay vì chỉ cái đầu, mỗi cái nêu thiết
+ lập mà nó nói đến.
+
+
+
+
+
Làm sao khai báo hệ thống của tôi cần làm gì với một tệp?
+
Dạng ngắn khi kết quả là đủ, dạng dài khi lý do quan trọng:
+
expected: accept
+
expected:
+ outcome: reject
+ reason: size_limit
+
+ Các kết quả là accept, reject, sanitize và
+ unspecified. Các lý do là một danh sách đóng để báo cáo có thể nhóm theo chúng:
+ content_malformed, count_limit, dimensions_limit,
+ duplicate, encoding_invalid, extension_rule,
+ filename_invalid, filename_too_long, filename_traversal,
+ malware_signature, mime_mismatch, nesting_depth,
+ none, size_limit và size_zero.
+
+
+ Một lý do nêu quy tắc đang áp dụng, không phải phán quyết. Vì vậy cùng một lý do có
+ thể nằm dưới cả hai kết quả - tệp thấp hơn giới hạn một byte là accept, và quy tắc
+ liên quan vẫn là size_limit.
+
+
+
+
+
Manifest chứa gì?
+
+ Nó được ghi bên cạnh các tệp ở cuối mỗi lần chạy, kể cả lần chạy bị ngắt. Một mục cho mỗi tệp:
+
+ recipe_hash được thêm khi lần chạy đến từ một công thức, và preset cùng
+ overrides khi nó đến từ một preset, nên manifest luôn truy ngược được về thứ đã tạo
+ ra nó.
+
+
+ Mỗi mục còn mang target_id, id của target trong công thức đã tạo tệp, và
+ summary.by_target đếm số tệp mà mỗi target tạo ra. Một công thức có nhiều target
+ nhờ vậy kiểm tra được từng target mà không cần đọc tên tệp.
+
+
+
+
+
Preset là gì?
+
+ Một bộ tệp dựng sẵn trả lời một câu hỏi kiểm thử thường gặp, để bạn không phải tự thiết kế bộ.
+ Preset thực chất là công thức bình thường, và eject in công thức ra để bạn chỉnh
+ sửa từ đó. Mỗi preset có trang riêng nói nó thường tìm thấy gì, trong
+ bộ có gì và mọi thiết lập nó nhận.
+
+ show cho bạn biết bộ sẽ tốn bao nhiêu trước khi dựng, và nói thẳng khi một con số là
+ giá trị tạm của chúng tôi chứ không phải giới hạn của bạn.
+
+
+
+
+
Các mã thoát có nghĩa gì?
+
+ Mỗi kết cục có mã riêng, đầu ra máy đọc được đi ra đầu ra chuẩn, và lần chạy thất bại không in gì ở
+ đó. Bảng này là một hợp đồng đóng băng - đổi nghĩa của một mã đòi hỏi tăng phiên bản chính.
+
+
+
+
+
+
Mã
+
Ý nghĩa
+
+
+
+
+
0
+
Mọi thứ đều chạy tốt.
+
+
+
1
+
Lỗi bất ngờ bên trong công cụ.
+
+
+
2
+
Lệnh hoặc cờ sai.
+
+
+
3
+
Công thức không hợp lệ.
+
+
+
4
+
Định dạng không làm được điều được yêu cầu.
+
+
+
5
+
Đọc hoặc ghi thất bại.
+
+
+
6
+
Không đủ dung lượng đĩa.
+
+
+
7
+
verify phát hiện sai lệch.
+
+
+
8
+
Lần chạy đã xong nhưng không phải mọi thứ đều được tạo.
+
+
+
130
+
Bị ngắt bằng Ctrl+C.
+
+
+
143
+
Bị dừng bởi một tín hiệu, đó là hình dạng của việc CI hết thời gian.
+
+
+
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Lần chạy bị dừng bằng Ctrl+C vẫn để lại manifest và không bao giờ để lại tệp ghi dở, nên tác vụ bị
+ hủy vẫn có thể được dọn bởi tác vụ sau.
+
+ Có, cùng một động cơ với một cửa sổ phủ lên, cho kiểu kiểm thử không viết kịch bản. Nó không phải
+ bản cắt giảm: một bài kiểm thử so sánh hai giao diện từng khả năng một, và bất cứ điều gì chỉ
+ một bên làm được đều phải được khai báo và biện minh thay vì lặng lẽ lệch nhau.
+
+
+ Các màn hình là một lô, preset, nhiều lô cùng lúc và giới thiệu. Nó cho biết một lần chạy sẽ tốn bao
+ nhiêu trước khi ghi gì, báo tiến độ khi đang chạy và có thể hủy giữa chừng mà không để lại tệp
+ ghi dở. Nó chưa mở được tệp công thức - hiện công thức là việc của dòng lệnh, còn cửa sổ dựng
+ các lô trong biểu mẫu.
+
+ Hệ thống nào cũng có một lệnh cho việc này, và cả ba nằm bên dưới. Chúng cho bạn một tệp có đúng số
+ byte cần thiết - và với nhiều bài kiểm thử, thế là đủ. Mọi lệnh trên trang này đã được
+ chạy trước khi đăng, trên hệ thống mà nó thuộc về.
+
+
+
+
Câu trả lời ngắn
+
+ Windows: fsutil file createnew name 10485760. Linux: dd if=/dev/zero of=name
+ bs=1M count=10. macOS: mkfile 10m name. Kích thước tính bằng byte, và 10 MB
+ đếm theo cách trình quản lý tệp của bạn đếm là 10485760.
+
+
+
+
+
Windows
+
fsutil, và một bản PowerShell không cần thêm gì
+
+ fsutil có sẵn trong Windows. Nó nhận kích thước bằng byte, nên hãy
+ tính số trước - 10 MB là 10485760, 100 MB là 104857600, 1 GB là 1073741824.
+
+
fsutil file createnew test10mb.bin 10485760
+
+ Đo trên Windows 11: nó chạy từ một dấu nhắc thường mà không cần quyền nâng cao, và tệp ra đúng
+ 10485760 byte.
+
+
PowerShell làm được điều tương tự mà không gọi chương trình khác, và hiểu đơn vị:
+ 10MB trong PowerShell nghĩa là 10485760 byte, cùng cách đếm cơ số 1024 mà Explorer
+ dùng, nên hai lệnh ở trên cho cùng một kích thước.
+
+
+
+
+
Linux
+
dd, truncate và fallocate, và sự khác biệt làm người ta vấp
+
dd là lệnh ai cũng biết. Nó thật sự ghi các byte:
+
dd if=/dev/zero of=test10mb.bin bs=1M count=10
+
+ truncate chạy tức thì, và đó là cái bẫy. Đo trên Alpine Linux, tệp báo 10485760 byte và
+ chiếm không khối nào - nó là một tệp thưa. Bất cứ thứ gì đọc
+ nó nhận mười megabyte số không, nhưng đĩa chưa bao giờ nhường chỗ:
+
+
truncate -s 10M test10mb.bin
+
+ Điều đó ổn để kiểm thử giới hạn tải lên và gây hiểu lầm khi kiểm thử hạn ngạch đĩa.
+ fallocate là lệnh nên dùng khi dung lượng phải là thật:
+
+
fallocate -l 10M test10mb.bin
+
Và khi nội dung phải không nén được, để trình nén không thể ép nó nhỏ lại:
+
head -c 10485760 /dev/urandom > test10mb.bin
+
+
+
+
macOS
+
mkfile, không phải tệp thưa, và hai lệnh bạn đã biết
+
+ macOS có sẵn mkfile. Đo trên macOS 26.6.2: 10485760 byte và 20480 khối, nên dung lượng
+ thật sự được cấp phát chứ không chỉ hứa hẹn:
+
+
mkfile 10m test10mb.bin
+
dd và truncate cũng có và hoạt động như trên Linux:
+ Mọi thứ ở trên cho bạn một khối số không. Điều đó đủ khi thứ được kiểm thử chỉ nhìn kích thước -
+ giới hạn tải lên, hạn ngạch, một lần truyền. Nó thôi đủ ngay khi có thứ gì mở
+ tệp.
+
+
+ Đã đo, và đáng để tự làm: tạo tệp 2 MB bằng fsutil, đặt tên photo.png rồi
+ đưa cho một thư viện ảnh. Pillow trả lời cannot identify image file. Nó không phải
+ PNG. Nó chưa bao giờ là - chỉ cái tên nói vậy.
+
+
+ Điều đó quan trọng hơn vẻ ngoài, vì bài kiểm thử sau đó hỏng theo hướng nào.
+ Endpoint tải lên từ chối tệp, bài kiểm thử của bạn xanh và bạn kết luận giới hạn kích thước hoạt
+ động. Nó không từ chối vì kích thước. Nó từ chối vì các byte không phải ảnh, và quy tắc bạn định
+ kiểm thử chưa bao giờ được chạm tới.
+
+
+
bộ phân tích từ chối nó trước khi xét bất kỳ quy tắc kích thước nào
+
bước tạo ảnh thu nhỏ hỏng và lỗi bạn đọc là về ảnh thu nhỏ
+
phần mềm diệt virus hoặc bước kiểm tra nội dung từ chối nó vì lý do thứ ba
+
trình xem không hiện gì, và không ai biết đó có phải lỗi hay không
+
+
+
+
+
Con đường còn lại
+
Một tệp thật của định dạng đó, đúng kích thước bạn đã yêu cầu
+
+ Đây là việc Testing Files Generator làm. Tệp là tệp thật của định dạng - mở được bằng phần mềm của
+ nó - và có đúng số byte bạn đã yêu cầu, chính xác đến từng byte:
+
+ Yêu cầu kích thước mà định dạng không thể đạt và bạn nhận một lỗi nêu mức sàn cùng lý do, không bao
+ giờ là tệp sai kích thước. Trang định dạng liệt kê mỗi định dạng
+ cùng tệp nhỏ nhất nó có thể tạo.
+
+
Và một giới hạn là ba trường hợp kiểm thử chứ không phải một, nên công cụ dựng cả ba:
+
tfg generate --format pdf --boundary 10mb --out ./edges
+
+ Điều đó cho bạn 10485759, 10485760 và 10485761 byte, cùng manifest nói tệp nào hệ thống của bạn nên
+ chấp nhận và tệp nào nên từ chối. Trang trường hợp sử dụng
+ đi qua việc đó và bốn việc khác mà nó được làm ra để giải quyết.
+
Miễn phí, mã nguồn mở, GPL-3.0. Không cần đăng ký. Bản tải cho Windows và macOS đã được ký nên khởi động không cảnh báo.
+
+
+
+
Vậy nên dùng cái nào?
+
+
+
Dùng lệnh của hệ thống
+
+ Khi không có gì mở tệp. Kiểm thử giới hạn kích thước trên endpoint kiểm tra kích thước trước, một
+ lần truyền, một hạn ngạch, tình trạng đầy đĩa. Chỉ một dòng và đã được cài sẵn.
+
+
+
+
Dùng một trình tạo thật
+
+ Khi có thứ gì phân tích, kết xuất, nhập hoặc giải nén tệp - và khi ngày mai bạn cần cùng các fixture
+ đó, trên máy khác, từng byte.
+
+
+
+
+ Cả hai đều có trên trang này vì cả hai đúng trong một phần thời gian. Sai lầm cần tránh là dùng cái
+ đầu ở nơi cần cái sau và coi bài kiểm thử xanh là bằng chứng.
+
+ Một trình kiểm tra chỉ từng được cho xem tệp lành thì chưa thực sự được kiểm thử. Đây là cách có
+ được một tệp cố ý làm hỏng, ra đúng kích thước bạn yêu cầu và mang theo manifest
+ nói hệ thống của bạn phải làm gì với nó.
+
+
+
+
Câu trả lời ngắn
+
+ tfg generate --format png --size 2mb --damage zero-head --out ./out ghi một tệp PNG
+ đúng 2097152 byte với các byte đầu là số không, và manifest bên cạnh ghi rằng hệ thống của bạn
+ phải từ chối nó.
+
+
+
+
+
Cách thường dùng
+
Vì sao tệp làm hỏng bằng tay là một bài kiểm thử tồi
+
+ Cách thường dùng là trình soạn thảo hex, một script đảo vài byte ngẫu nhiên, hoặc cắt ngắn tệp bằng
+ head hay truncate. Dùng được một lần, rồi nó làm bạn tốn công:
+
+
+
+ Mỗi lần một khác. Byte ngẫu nhiên rơi vào chỗ mới ở mỗi lần chạy, nên lỗi hôm thứ
+ Ba có thể không quay lại vào thứ Tư.
+
+
+ Nó đổi kích thước. Tệp bị cắt ngắn nhỏ hơn giới hạn mà nó phải nằm dưới, nên bước
+ kiểm tra kích thước trả lời trước bước kiểm tra nội dung và bài kiểm thử đạt vì lý do sai.
+
+
+ Nó thường không ai nhận ra. Văn bản thuần vẫn đọc được khi đổi một byte ở giữa, và
+ một trình đọc ảnh dễ tính chỉ việc vẽ nó ra, nên tệp lẽ ra phải hỏng lại được chấp nhận.
+
+
+ Nó không nói gì về điều phải xảy ra. Tệp chỉ là các byte, và ai đọc bài kiểm thử
+ sau đó phải đoán xem ý định là chấp nhận hay từ chối.
+
+
+
+
+
+
Bạn nhận được gì
+
Tệp bị hỏng vẫn có kích thước bạn đã yêu cầu
+
+ Tệp được tạo bình thường rồi mới bị làm hỏng, trên đường ghi xuống đĩa. Nó giữ kích thước bạn yêu
+ cầu, và cùng một lệnh ghi lại đúng các byte đó.
+
+ Cài đặt viết sau dấu hai chấm. Tùy chọn có thể lặp lại, và các hỏng hóc được áp dụng theo thứ tự bạn
+ viết. Nó dùng được với từng định dạng trong 26 định dạng.
+
+
+
+
+
Nó làm được gì
+
Có những kiểu hỏng nào?
+
+ Đây là danh sách chương trình in ra, được đọc từ chính nó khi trang này được dựng. tfg
+ damage in ra cùng danh sách đó, và tfg damage <id> cho biết một kiểu
+ nhận những gì.
+
+
+
+
+
+
Hỏng hóc
+
Nó làm gì với các byte
+
Tệp nhỏ nhất
+
Cài đặt
+
+
+
+
+
zero-head
+
Ghi đè các byte đầu của tệp bằng số không, giữ nguyên độ dài. Hầu hết trình đọc nhìn vào đó trước, nên gần như mọi thứ đều nhận ra hỏng hóc này.
+
8
+
bytes
+
+
+
+
+
+ zero-head ghi số không đè lên phần đầu tệp. Hầu hết trình đọc nhìn vào đó trước, vào
+ chữ ký và phần đầu cho biết tệp là gì, nên gần như trình đọc nào cũng nhận ra. Văn bản thuần và
+ nhật ký không có chữ ký và cũng bị từ chối, vì một chuỗi byte không không phải là văn bản. Dưới
+ bốn byte, một số định dạng ra với hỏng hóc mà không trình đọc nào phàn nàn, đó là lý do cài đặt
+ bắt đầu từ bốn.
+
+
+
+
+
Manifest nói gì
+
Một manifest nói điều phải xảy ra
+
+ Mỗi tệp bị hỏng nhận một mục nói rằng hệ thống của bạn phải từ chối nó, với hỏng hóc được ghi bên
+ cạnh:
+
+ Hai yêu cầu bị từ chối trước khi có gì được ghi, vì mỗi yêu cầu sẽ để lại trên đĩa một tệp mà
+ manifest mô tả sai:
+
+
+
một tệp nhỏ hơn mức hỏng hóc cần, sẽ ra mà không bị đổi
+
+ expected: accept cạnh một hỏng hóc, vì không gì có thể đáp ứng được. Viết
+ sanitize nếu hệ thống của bạn phải sửa tệp, hoặc unspecified nếu đó
+ chính là câu hỏi bạn đang đặt ra
+
+
+
+
+
+
Trong một công thức
+
Tệp lành và tệp hỏng trong một lần chạy
+
+ Đặt cả hai vào một công thức, và manifest mang kỳ vọng của từng tệp, nên bài kiểm thử không cần danh
+ sách tệp nào là tệp nào:
+
+ Bài kiểm thử đọc manifest và kiểm tra điều đã xảy ra có đúng như điều đã khai báo. Nó không cần danh
+ sách tên tệp:
+
+
import json, os
+
+directory = "healthy-and-broken"
+manifest = json.load(open(os.path.join(directory, "manifest.json")))
+
+for entry in manifest["files"]:
+ response = upload(os.path.join(directory, entry["path"]))
+ if entry["expected"]["outcome"] == "reject":
+ assert not response.ok
+ else:
+ assert response.ok
+
+ Một lần từ chối tốt là một lần từ chối gọn. Một thông báo nói điều gì sai là câu trả lời bạn muốn.
+ Lỗi máy chủ, treo máy hoặc một tệp lưu dở là khiếm khuyết mà bài kiểm thử này sinh ra để tìm.
+
+
+
+
+
Tiếp theo
+
Đi đâu từ đây
+
+
+ Preset upload-validation hỏi một biểu mẫu hai câu hỏi
+ còn lại, về kích thước và về loại tệp.
+
+ Một fixture nhị phân trong kho mã nằm lại mãi trong lịch sử của nó, không thể review trong diff và
+ trở nên bất khả thi khi tệp lớn. Hãy tạo tệp ngay trong pipeline từ một công thức. Công thức là
+ văn bản, các byte ra giống hệt mỗi lần, và một bước cuối chứng minh không có gì xê dịch.
+
+
+
+
Câu trả lời ngắn
+
+ Cài tfg, chạy tfg generate fixtures.yaml --out ./fixtures trước các bài
+ kiểm thử và tfg verify ./fixtures/manifest.json sau đó. Cả hai bước tự làm bản dựng
+ thất bại, với một mã thoát nói lý do.
+
+
+
+
+
Vì sao không commit
+
Vì sao fixture không nên nằm trong kho mã
+
+
+ Nó ở lại trong lịch sử. Xóa một tệp nhị phân sau này không làm bản clone nhỏ đi, vì
+ mọi phiên bản của nó vẫn còn đó.
+
+
+ Diff không cho thấy cái gì đã đổi. Người review thấy một tệp PDF khác đi và không
+ biết gì thêm. Công thức thì đổi một dòng.
+
+
+ Tệp lớn không vừa. GitHub từ chối một lần push có tệp lớn hơn 100 MB, nên bài kiểm
+ thử giới hạn tải lên 500 MB không có gì để commit.
+
+
+
+ Thứ cần commit là công thức. Cùng công thức và cùng seed ghi ra cùng các byte trên mọi máy, nên tệp
+ tạo trong pipeline chính là tệp bạn có trên laptop.
+
+
+
+
+
Công thức
+
Một công thức nằm cạnh các bài kiểm thử
+
+ Công thức này ghi hai mươi lăm hóa đơn phải được chấp nhận và hai ảnh vượt giới hạn phải bị từ chối,
+ và manifest ghi cả hai kỳ vọng:
+
+ Dòng checksum so sánh tệp lưu trữ với verify-SHA256SUMS.txt của cùng bản phát hành.
+ Phiên bản được ghim cố định, nên một bản phát hành mới không bao giờ đổi một bản dựng bạn chưa
+ đụng tới.
+
+ Mỗi kết cục có mã thoát riêng, nên bước tự thất bại và nhật ký nói là mã nào. Những mã một pipeline
+ gặp:
+
+
+
3 - công thức không hợp lệ. Không có gì được ghi, và mọi vấn đề đều được nêu
+
4 - định dạng không làm được điều được yêu cầu, ví dụ kích thước dưới mức nhỏ nhất của nó
+
6 - không đủ dung lượng đĩa
+
7 - tfg verify tìm thấy một tệp không khớp với manifest của nó
+
8 - lần chạy đã xong, nhưng không phải mọi thứ đều được tạo ra
+
+
+ Lần chạy thất bại không in gì ra đầu ra chuẩn, nên trình phân tích nhật ký không bao giờ nhầm một
+ lỗi là dữ liệu. Cả bảng nằm ở trang tài liệu.
+
+
+
+
+
PowerShell
+
Script PowerShell cần thêm một dòng
+
+ PowerShell không mang mã thoát của một chương trình ra khỏi tệp .ps1. Chạy một script
+ với -File và script trả lời 0 ngay cả khi công cụ bên trong đã từ chối
+ công việc, nên một bản dựng lẽ ra phải đỏ lại thành xanh. Dòng cuối là toàn bộ cách sửa:
+
+ PowerShell hành xử như vậy, không phải điều gì của công cụ này. cmd, bash
+ và zsh không cần thêm gì.
+
+
+
+
+
Nhiều job
+
Chia sẻ fixture giữa các job
+
+ Thường không cần tải chúng lên. Vì cùng công thức ghi cùng các byte, mỗi job có thể chạy tfg
+ generate của riêng nó, nhanh hơn một lần tải lên rồi tải xuống. Khi một job phải nhận tệp
+ từ job khác, hãy chạy tfg verify trên manifest sau khi chuyển, và nó cho biết thứ
+ đến nơi có đúng là thứ đã được ghi không.
+
+ Năm việc xuất hiện trong gần như mọi dự án nhận tệp từ con người, và lệnh làm từng việc. Mỗi ví dụ
+ bên dưới chạy đúng như được viết.
+
+
+
+
Giới hạn tải lên
+
Kiểm thử xem giới hạn kích thước tệp có được áp dụng đúng nơi nó nói không
+
+ Một giới hạn là ba trường hợp kiểm thử chứ không phải một: ngay dưới, đúng bằng và ngay trên. Làm
+ tay thì phải tính số byte và hy vọng không lệch một. Hãy yêu cầu cả bộ:
+
+ Bạn nhận ba PDF thật có 1048575, 1048576 và 1048577 byte, cùng manifest nói hai tệp đầu nên được
+ chấp nhận và tệp thứ ba bị từ chối vì size_limit. Bài kiểm thử của bạn đọc kỳ vọng
+ thay vì bạn viết tay ba câu khẳng định - và khi giới hạn đổi, bạn đổi một con số rồi chạy lại.
+
+
+ Điều tương tự dùng được không cần preset khi bạn muốn một bộ ranh giới đơn ngay trong lệnh:
+
+ Fixture nhị phân lớn làm kho mã clone chậm và khó review, và không ai biết cái gì đã đổi khi thay
+ một tệp. Công thức là vài trăm ký tự YAML dựng lại các tệp giống hệt - từng byte, trên
+ mọi máy - vì mọi tệp đều suy ra từ seed của lần chạy.
+
+
- name: build the fixtures
+ run: tfg generate fixtures.yaml --out ./fixtures
+
+- name: run the tests
+ run: pytest tests/
+
+- name: nothing moved
+ run: tfg verify ./fixtures/manifest.json
+
+ Mỗi kết cục có mã thoát riêng, nên pipeline phân biệt được công thức xấu, đĩa đầy và sai lệch khi
+ xác minh. Lần chạy thất bại không in gì ra đầu ra chuẩn, nhờ vậy trình phân tích nhật ký không
+ đọc lỗi thành dữ liệu.
+
+
+
+
+
Quy mô
+
Tìm hiểu chuyện gì xảy ra khi thư mục lớn
+
+ Quy trình nhập, tác vụ ban đêm và danh sách thư mục hoạt động khác nhau ở mười nghìn tệp so với mười
+ tệp. Kích thước rút từ một khoảng làm bộ trông như lưu lượng thật thay vì mười nghìn tệp giống
+ hệt, và lần rút lấy từ seed, nên bộ ngày mai vẫn như cũ.
+
+ Độ sâu lồng nhau, số mục và kích thước phần bên trong đều là những thứ mà quy trình nhập có ý kiến
+ riêng, và đây là cách bạn biết ý kiến đó là gì.
+
+
+
+
+
Bộ phân tích và trình xem
+
Kiểm tra mã của chính bạn đọc một định dạng như phần mềm thật
+
+ Mỗi định dạng ở đây được kiểm tra bằng trình đọc độc lập trước khi phát hành - PNG được mở và so
+ sánh pixel, DOCX được các thư viện riêng đọc lại, tệp nén được giải nén. Nghĩa là tệp mà bộ phân
+ tích của bạn từ chối là một phát hiện về bộ phân tích của bạn, không phải về trình tạo.
+
+ Trang định dạng liệt kê các thiết lập mỗi định dạng nhận và tệp nhỏ
+ nhất mà mỗi định dạng có thể có.
+
+
+
+
+
Hướng dẫn
+
Hai trong số đó, chi tiết hơn
+
+
+ Tệp kiểm thử bị hỏng - một tệp cố ý làm hỏng, đúng kích
+ thước, với điều phải xảy ra với nó được ghi trong manifest.
+
+
+ Tệp kiểm thử trong CI - một workflow GitHub Actions, một
+ job GitLab và các mã thoát làm bản dựng thất bại.
+
+
+
+
+
+
Dành cho ai
+
+ Kỹ sư QA, tự động hóa kiểm thử và bất kỳ ai có mã đứng sau là biểu mẫu tải lên, quy trình nhập, bộ
+ phân tích cú pháp hoặc hạn ngạch lưu trữ. Nó chạy trên máy hoàn toàn không có mạng, điều quan
+ trọng trong môi trường doanh nghiệp đóng nơi trình tạo chạy trên trình duyệt không phải một lựa
+ chọn.
+
命令行可在 Windows 和 Linux 上运行,支持 Intel 和 ARM,也支持 Apple 芯片的 Mac。桌面窗口提供 Windows(Intel)、Linux(Intel)和 Apple 芯片 Mac 版本。不支持 Intel Mac,也不会为其构建。
+
+
+
+
我需要安装什么吗?
+
+
不需要。下载适合你系统的压缩包,解压后运行二进制文件即可。没有安装程序,没有需要添加的运行时,也没有需要解决的依赖。如果你装有 Go,一条 go install 命令同样可用。
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
为什么在 Windows 上处理数千个文件更慢?
+
+
因为 Windows 对查看的每个路径收取更多开销,而遍历数千个文件的命令要查看数千个路径。在一台有 3000 个 1 kB 文件的机器上实测,verify 在 Windows 上约需 0.9 秒,在容器中的 Linux 上约需 0.2 秒。输出路径更短会让 Windows 的数字变小,因为文件上方的每一级文件夹都属于被查看的内容。
命令列可在 Windows 與 Linux 上執行,支援 Intel 與 ARM,也支援 Apple 晶片的 Mac。桌面視窗提供 Windows(Intel)、Linux(Intel)與 Apple 晶片 Mac 版本。不支援 Intel Mac,也不會為其建置。
+
+
+
+
我需要安裝什麼嗎?
+
+
不需要。下載適合你系統的壓縮檔,解壓縮後執行執行檔即可。沒有安裝程式,沒有需要新增的執行階段,也沒有需要解決的相依套件。如果你裝有 Go,一個 go install 指令同樣可用。
+
go install github.com/donislawdev/TestingFilesGenerator/cmd/tfg@latest
+
+
+
+
為什麼在 Windows 上處理數千個檔案比較慢?
+
+
因為 Windows 對查看的每個路徑收取較多開銷,而走訪數千個檔案的指令要查看數千個路徑。在一台有 3000 個 1 kB 檔案的電腦上實測,verify 在 Windows 上約需 0.9 秒,在容器中的 Linux 上約需 0.2 秒。輸出路徑較短會讓 Windows 的數字變小,因為檔案上方的每一層資料夾都屬於被查看的內容。