package generators import ( "io" "strings" "testing" "github.com/pkg/errors" "github.com/projectdiscovery/nuclei/v3/pkg/catalog" "github.com/projectdiscovery/nuclei/v3/pkg/types" ) type fakeCatalog struct{ catalog.Catalog } func (f *fakeCatalog) OpenFile(filename string) (io.ReadCloser, error) { return nil, errors.New("not used") } func (f *fakeCatalog) GetTemplatePath(target string) ([]string, error) { return nil, nil } func (f *fakeCatalog) GetTemplatesPath(definitions []string) ([]string, map[string]error) { return nil, nil } func (f *fakeCatalog) ResolvePath(templateName, second string) (string, error) { return templateName, nil } func newTestGenerator() *PayloadGenerator { opts := types.DefaultOptions() // inject helper loader function opts.LoadHelperFileFunction = func(path, templatePath string, _ catalog.Catalog) (io.ReadCloser, error) { switch path { case "fileA.txt": return io.NopCloser(strings.NewReader("one\n two\n\nthree\n")), nil default: return io.NopCloser(strings.NewReader("x\ny\nz\n")), nil } } return &PayloadGenerator{options: opts, catalog: &fakeCatalog{}} } func TestLoadPayloads_FastPathFile(t *testing.T) { g := newTestGenerator() out, err := g.loadPayloads(map[string]interface{}{"A": "fileA.txt"}, "") if err != nil { t.Fatalf("err: %v", err) } got := out["A"] if len(got) != 3 || got[0] != "one" || got[1] != " two" || got[2] != "three" { t.Fatalf("unexpected: %#v", got) } } func TestLoadPayloads_InlineMultiline(t *testing.T) { g := newTestGenerator() inline := "a\nb\n" out, err := g.loadPayloads(map[string]interface{}{"B": inline}, "") if err != nil { t.Fatalf("err: %v", err) } got := out["B"] if len(got) != 3 || got[0] != "a" || got[1] != "b" || got[2] != "" { t.Fatalf("unexpected: %#v", got) } } func TestLoadPayloads_SingleLineFallsBackToFile(t *testing.T) { g := newTestGenerator() inline := "fileA.txt" // single line, should be treated as file path out, err := g.loadPayloads(map[string]interface{}{"C": inline}, "") if err != nil { t.Fatalf("err: %v", err) } got := out["C"] if len(got) != 3 { t.Fatalf("unexpected len: %d", len(got)) } } func TestLoadPayloads_InterfaceSlice(t *testing.T) { g := newTestGenerator() out, err := g.loadPayloads(map[string]interface{}{"D": []interface{}{"p", "q"}}, "") if err != nil { t.Fatalf("err: %v", err) } got := out["D"] if len(got) != 2 || got[0] != "p" || got[1] != "q" { t.Fatalf("unexpected: %#v", got) } } func TestLoadPayloadsFromFile_SkipsEmpty(t *testing.T) { g := newTestGenerator() rc := io.NopCloser(strings.NewReader("a\n\n\n b \n")) lines, err := g.loadPayloadsFromFile(rc) if err != nil { t.Fatalf("err: %v", err) } if len(lines) != 2 || lines[0] != "a" || lines[1] != " b " { t.Fatalf("unexpected: %#v", lines) } } func TestValidate_AllowsInlineMultiline(t *testing.T) { g := newTestGenerator() inline := "x\ny\n" if err := g.validate(map[string]interface{}{"E": inline}, ""); err != nil { t.Fatalf("validate rejected inline multiline: %v", err) } }