123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765 |
- // Copyright 2022 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package template
-
- import (
- "net/url"
- "testing"
-
- "code.gitea.io/gitea/modules/json"
- api "code.gitea.io/gitea/modules/structs"
-
- "github.com/stretchr/testify/require"
- )
-
- func TestValidate(t *testing.T) {
- tests := []struct {
- name string
- filename string
- content string
- want *api.IssueTemplate
- wantErr string
- }{
- {
- name: "miss name",
- content: ``,
- wantErr: "'name' is required",
- },
- {
- name: "miss about",
- content: `
- name: "test"
- `,
- wantErr: "'about' is required",
- },
- {
- name: "miss body",
- content: `
- name: "test"
- about: "this is about"
- `,
- wantErr: "'body' is required",
- },
- {
- name: "markdown miss value",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "markdown"
- `,
- wantErr: "body[0](markdown): 'value' is required",
- },
- {
- name: "markdown invalid value",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "markdown"
- attributes:
- value: true
- `,
- wantErr: "body[0](markdown): 'value' should be a string",
- },
- {
- name: "markdown empty value",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "markdown"
- attributes:
- value: ""
- `,
- wantErr: "body[0](markdown): 'value' is required",
- },
- {
- name: "textarea invalid id",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "textarea"
- id: "?"
- `,
- wantErr: "body[0](textarea): 'id' should contain only alphanumeric, '-' and '_'",
- },
- {
- name: "textarea miss label",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "textarea"
- id: "1"
- `,
- wantErr: "body[0](textarea): 'label' is required",
- },
- {
- name: "textarea conflict id",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "textarea"
- id: "1"
- attributes:
- label: "a"
- - type: "textarea"
- id: "1"
- attributes:
- label: "b"
- `,
- wantErr: "body[1](textarea): 'id' should be unique",
- },
- {
- name: "textarea invalid description",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "textarea"
- id: "1"
- attributes:
- label: "a"
- description: true
- `,
- wantErr: "body[0](textarea): 'description' should be a string",
- },
- {
- name: "textarea invalid required",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "textarea"
- id: "1"
- attributes:
- label: "a"
- validations:
- required: "on"
- `,
- wantErr: "body[0](textarea): 'required' should be a bool",
- },
- {
- name: "input invalid description",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "input"
- id: "1"
- attributes:
- label: "a"
- description: true
- `,
- wantErr: "body[0](input): 'description' should be a string",
- },
- {
- name: "input invalid is_number",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "input"
- id: "1"
- attributes:
- label: "a"
- validations:
- is_number: "yes"
- `,
- wantErr: "body[0](input): 'is_number' should be a bool",
- },
- {
- name: "input invalid regex",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "input"
- id: "1"
- attributes:
- label: "a"
- validations:
- regex: true
- `,
- wantErr: "body[0](input): 'regex' should be a string",
- },
- {
- name: "dropdown invalid description",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "dropdown"
- id: "1"
- attributes:
- label: "a"
- description: true
- `,
- wantErr: "body[0](dropdown): 'description' should be a string",
- },
- {
- name: "dropdown invalid multiple",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "dropdown"
- id: "1"
- attributes:
- label: "a"
- multiple: "on"
- `,
- wantErr: "body[0](dropdown): 'multiple' should be a bool",
- },
- {
- name: "checkboxes invalid description",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "checkboxes"
- id: "1"
- attributes:
- label: "a"
- description: true
- `,
- wantErr: "body[0](checkboxes): 'description' should be a string",
- },
- {
- name: "invalid type",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "video"
- id: "1"
- attributes:
- label: "a"
- `,
- wantErr: "body[0](video): unknown type",
- },
- {
- name: "dropdown miss options",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "dropdown"
- id: "1"
- attributes:
- label: "a"
- `,
- wantErr: "body[0](dropdown): 'options' is required and should be a array",
- },
- {
- name: "dropdown invalid options",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "dropdown"
- id: "1"
- attributes:
- label: "a"
- options:
- - "a"
- - true
- `,
- wantErr: "body[0](dropdown), option[1]: should be a string",
- },
- {
- name: "checkboxes invalid options",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "checkboxes"
- id: "1"
- attributes:
- label: "a"
- options:
- - "a"
- - true
- `,
- wantErr: "body[0](checkboxes), option[0]: should be a dictionary",
- },
- {
- name: "checkboxes option miss label",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "checkboxes"
- id: "1"
- attributes:
- label: "a"
- options:
- - required: true
- `,
- wantErr: "body[0](checkboxes), option[0]: 'label' is required and should be a string",
- },
- {
- name: "checkboxes option invalid required",
- content: `
- name: "test"
- about: "this is about"
- body:
- - type: "checkboxes"
- id: "1"
- attributes:
- label: "a"
- options:
- - label: "a"
- required: "on"
- `,
- wantErr: "body[0](checkboxes), option[0]: 'required' should be a bool",
- },
- {
- name: "valid",
- content: `
- name: Name
- title: Title
- about: About
- labels: ["label1", "label2"]
- ref: Ref
- body:
- - type: markdown
- id: id1
- attributes:
- value: Value of the markdown
- - type: textarea
- id: id2
- attributes:
- label: Label of textarea
- description: Description of textarea
- placeholder: Placeholder of textarea
- value: Value of textarea
- render: bash
- validations:
- required: true
- - type: input
- id: id3
- attributes:
- label: Label of input
- description: Description of input
- placeholder: Placeholder of input
- value: Value of input
- validations:
- required: true
- is_number: true
- regex: "[a-zA-Z0-9]+"
- - type: dropdown
- id: id4
- attributes:
- label: Label of dropdown
- description: Description of dropdown
- multiple: true
- options:
- - Option 1 of dropdown
- - Option 2 of dropdown
- - Option 3 of dropdown
- validations:
- required: true
- - type: checkboxes
- id: id5
- attributes:
- label: Label of checkboxes
- description: Description of checkboxes
- options:
- - label: Option 1 of checkboxes
- required: true
- - label: Option 2 of checkboxes
- required: false
- - label: Option 3 of checkboxes
- required: true
- `,
- want: &api.IssueTemplate{
- Name: "Name",
- Title: "Title",
- About: "About",
- Labels: []string{"label1", "label2"},
- Ref: "Ref",
- Fields: []*api.IssueFormField{
- {
- Type: "markdown",
- ID: "id1",
- Attributes: map[string]interface{}{
- "value": "Value of the markdown",
- },
- },
- {
- Type: "textarea",
- ID: "id2",
- Attributes: map[string]interface{}{
- "label": "Label of textarea",
- "description": "Description of textarea",
- "placeholder": "Placeholder of textarea",
- "value": "Value of textarea",
- "render": "bash",
- },
- Validations: map[string]interface{}{
- "required": true,
- },
- },
- {
- Type: "input",
- ID: "id3",
- Attributes: map[string]interface{}{
- "label": "Label of input",
- "description": "Description of input",
- "placeholder": "Placeholder of input",
- "value": "Value of input",
- },
- Validations: map[string]interface{}{
- "required": true,
- "is_number": true,
- "regex": "[a-zA-Z0-9]+",
- },
- },
- {
- Type: "dropdown",
- ID: "id4",
- Attributes: map[string]interface{}{
- "label": "Label of dropdown",
- "description": "Description of dropdown",
- "multiple": true,
- "options": []interface{}{
- "Option 1 of dropdown",
- "Option 2 of dropdown",
- "Option 3 of dropdown",
- },
- },
- Validations: map[string]interface{}{
- "required": true,
- },
- },
- {
- Type: "checkboxes",
- ID: "id5",
- Attributes: map[string]interface{}{
- "label": "Label of checkboxes",
- "description": "Description of checkboxes",
- "options": []interface{}{
- map[string]interface{}{"label": "Option 1 of checkboxes", "required": true},
- map[string]interface{}{"label": "Option 2 of checkboxes", "required": false},
- map[string]interface{}{"label": "Option 3 of checkboxes", "required": true},
- },
- },
- },
- },
- FileName: "test.yaml",
- },
- wantErr: "",
- },
- {
- name: "single label",
- content: `
- name: Name
- title: Title
- about: About
- labels: label1
- ref: Ref
- body:
- - type: markdown
- id: id1
- attributes:
- value: Value of the markdown
- `,
- want: &api.IssueTemplate{
- Name: "Name",
- Title: "Title",
- About: "About",
- Labels: []string{"label1"},
- Ref: "Ref",
- Fields: []*api.IssueFormField{
- {
- Type: "markdown",
- ID: "id1",
- Attributes: map[string]interface{}{
- "value": "Value of the markdown",
- },
- },
- },
- FileName: "test.yaml",
- },
- wantErr: "",
- },
- {
- name: "comma-delimited labels",
- content: `
- name: Name
- title: Title
- about: About
- labels: label1,label2,,label3 ,,
- ref: Ref
- body:
- - type: markdown
- id: id1
- attributes:
- value: Value of the markdown
- `,
- want: &api.IssueTemplate{
- Name: "Name",
- Title: "Title",
- About: "About",
- Labels: []string{"label1", "label2", "label3"},
- Ref: "Ref",
- Fields: []*api.IssueFormField{
- {
- Type: "markdown",
- ID: "id1",
- Attributes: map[string]interface{}{
- "value": "Value of the markdown",
- },
- },
- },
- FileName: "test.yaml",
- },
- wantErr: "",
- },
- {
- name: "empty string as labels",
- content: `
- name: Name
- title: Title
- about: About
- labels: ''
- ref: Ref
- body:
- - type: markdown
- id: id1
- attributes:
- value: Value of the markdown
- `,
- want: &api.IssueTemplate{
- Name: "Name",
- Title: "Title",
- About: "About",
- Labels: nil,
- Ref: "Ref",
- Fields: []*api.IssueFormField{
- {
- Type: "markdown",
- ID: "id1",
- Attributes: map[string]interface{}{
- "value": "Value of the markdown",
- },
- },
- },
- FileName: "test.yaml",
- },
- wantErr: "",
- },
- {
- name: "comma delimited labels in markdown",
- filename: "test.md",
- content: `---
- name: Name
- title: Title
- about: About
- labels: label1,label2,,label3 ,,
- ref: Ref
- ---
- Content
- `,
- want: &api.IssueTemplate{
- Name: "Name",
- Title: "Title",
- About: "About",
- Labels: []string{"label1", "label2", "label3"},
- Ref: "Ref",
- Fields: nil,
- Content: "Content\n",
- FileName: "test.md",
- },
- wantErr: "",
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- filename := "test.yaml"
- if tt.filename != "" {
- filename = tt.filename
- }
- tmpl, err := unmarshal(filename, []byte(tt.content))
- require.NoError(t, err)
- if tt.wantErr != "" {
- require.EqualError(t, Validate(tmpl), tt.wantErr)
- } else {
- require.NoError(t, Validate(tmpl))
- want, _ := json.Marshal(tt.want)
- got, _ := json.Marshal(tmpl)
- require.JSONEq(t, string(want), string(got))
- }
- })
- }
- }
-
- func TestRenderToMarkdown(t *testing.T) {
- type args struct {
- template string
- values url.Values
- }
- tests := []struct {
- name string
- args args
- want string
- }{
- {
- name: "normal",
- args: args{
- template: `
- name: Name
- title: Title
- about: About
- labels: ["label1", "label2"]
- ref: Ref
- body:
- - type: markdown
- id: id1
- attributes:
- value: Value of the markdown
- - type: textarea
- id: id2
- attributes:
- label: Label of textarea
- description: Description of textarea
- placeholder: Placeholder of textarea
- value: Value of textarea
- render: bash
- validations:
- required: true
- - type: input
- id: id3
- attributes:
- label: Label of input
- description: Description of input
- placeholder: Placeholder of input
- value: Value of input
- hide_label: true
- validations:
- required: true
- is_number: true
- regex: "[a-zA-Z0-9]+"
- - type: dropdown
- id: id4
- attributes:
- label: Label of dropdown
- description: Description of dropdown
- multiple: true
- options:
- - Option 1 of dropdown
- - Option 2 of dropdown
- - Option 3 of dropdown
- validations:
- required: true
- - type: checkboxes
- id: id5
- attributes:
- label: Label of checkboxes
- description: Description of checkboxes
- options:
- - label: Option 1 of checkboxes
- required: true
- - label: Option 2 of checkboxes
- required: false
- - label: Option 3 of checkboxes
- required: true
- `,
- values: map[string][]string{
- "form-field-id2": {"Value of id2"},
- "form-field-id3": {"Value of id3"},
- "form-field-id4": {"0,1"},
- "form-field-id5-0": {"on"},
- "form-field-id5-2": {"on"},
- },
- },
- want: `### Label of textarea
-
- ` + "```bash\nValue of id2\n```" + `
-
- Value of id3
-
- ### Label of dropdown
-
- Option 1 of dropdown, Option 2 of dropdown
-
- ### Label of checkboxes
-
- - [x] Option 1 of checkboxes
- - [ ] Option 2 of checkboxes
- - [x] Option 3 of checkboxes
-
- `,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- template, err := Unmarshal("test.yaml", []byte(tt.args.template))
- if err != nil {
- t.Fatal(err)
- }
- if got := RenderToMarkdown(template, tt.args.values); got != tt.want {
- t.Errorf("RenderToMarkdown() = %v, want %v", got, tt.want)
- }
- })
- }
- }
-
- func Test_minQuotes(t *testing.T) {
- type args struct {
- value string
- }
- tests := []struct {
- name string
- args args
- want string
- }{
- {
- name: "without quote",
- args: args{
- value: "Hello\nWorld",
- },
- want: "```",
- },
- {
- name: "with 1 quote",
- args: args{
- value: "Hello\nWorld\n`text`\n",
- },
- want: "```",
- },
- {
- name: "with 3 quotes",
- args: args{
- value: "Hello\nWorld\n`text`\n```go\ntext\n```\n",
- },
- want: "````",
- },
- {
- name: "with more quotes",
- args: args{
- value: "Hello\nWorld\n`text`\n```go\ntext\n```\n``````````bash\ntext\n``````````\n",
- },
- want: "```````````",
- },
- {
- name: "not leading quotes",
- args: args{
- value: "Hello\nWorld`text````go\ntext`````````````bash\ntext``````````\n",
- },
- want: "```",
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if got := minQuotes(tt.args.value); got != tt.want {
- t.Errorf("minQuotes() = %v, want %v", got, tt.want)
- }
- })
- }
- }
|