github.com/josephspurrier/go-swagger@v0.2.1-0.20221129144919-1f672a142a00/codescan/parser_test.go (about)

     1  package codescan
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"regexp"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/go-openapi/spec"
    11  	"github.com/stretchr/testify/assert"
    12  )
    13  
    14  // only used within this group of tests but never used within actual code base.
    15  func newSchemaAnnotationParser(goName string) *schemaAnnotationParser {
    16  	return &schemaAnnotationParser{GoName: goName, rx: rxModelOverride}
    17  }
    18  
    19  type schemaAnnotationParser struct {
    20  	GoName string
    21  	Name   string
    22  	rx     *regexp.Regexp
    23  }
    24  
    25  func (sap *schemaAnnotationParser) Matches(line string) bool {
    26  	return sap.rx.MatchString(line)
    27  }
    28  
    29  func (sap *schemaAnnotationParser) Parse(lines []string) error {
    30  	if sap.Name != "" {
    31  		return nil
    32  	}
    33  
    34  	if len(lines) > 0 {
    35  		for _, line := range lines {
    36  			matches := sap.rx.FindStringSubmatch(line)
    37  			if len(matches) > 1 && len(matches[1]) > 0 {
    38  				sap.Name = matches[1]
    39  				return nil
    40  			}
    41  		}
    42  	}
    43  	return nil
    44  }
    45  
    46  func TestSectionedParser_TitleDescription(t *testing.T) {
    47  	text := `This has a title, separated by a whitespace line
    48  
    49  In this example the punctuation for the title should not matter for swagger.
    50  For go it will still make a difference though.
    51  `
    52  	text2 := `This has a title without whitespace.
    53  The punctuation here does indeed matter. But it won't for go.
    54  `
    55  
    56  	text3 := `This has a title, and markdown in the description
    57  
    58  See how markdown works now, we can have lists:
    59  
    60  + first item
    61  + second item
    62  + third item
    63  
    64  [Links works too](http://localhost)
    65  `
    66  
    67  	text4 := `This has whitespace sensitive markdown in the description
    68  
    69  |+ first item
    70  |    + nested item
    71  |    + also nested item
    72  
    73  Sample code block:
    74  
    75  |    fmt.Println("Hello World!")
    76  
    77  `
    78  
    79  	var err error
    80  
    81  	st := &sectionedParser{}
    82  	st.setTitle = func(lines []string) {}
    83  	err = st.Parse(ascg(text))
    84  	assert.NoError(t, err)
    85  
    86  	assert.EqualValues(t, []string{"This has a title, separated by a whitespace line"}, st.Title())
    87  	assert.EqualValues(t, []string{"In this example the punctuation for the title should not matter for swagger.", "For go it will still make a difference though."}, st.Description())
    88  
    89  	st = &sectionedParser{}
    90  	st.setTitle = func(lines []string) {}
    91  	err = st.Parse(ascg(text2))
    92  	assert.NoError(t, err)
    93  
    94  	assert.EqualValues(t, []string{"This has a title without whitespace."}, st.Title())
    95  	assert.EqualValues(t, []string{"The punctuation here does indeed matter. But it won't for go."}, st.Description())
    96  
    97  	st = &sectionedParser{}
    98  	st.setTitle = func(lines []string) {}
    99  	err = st.Parse(ascg(text3))
   100  	assert.NoError(t, err)
   101  
   102  	assert.EqualValues(t, []string{"This has a title, and markdown in the description"}, st.Title())
   103  	assert.EqualValues(t, []string{"See how markdown works now, we can have lists:", "", "+ first item", "+ second item", "+ third item", "", "[Links works too](http://localhost)"}, st.Description())
   104  
   105  	st = &sectionedParser{}
   106  	st.setTitle = func(lines []string) {}
   107  	err = st.Parse(ascg(text4))
   108  	assert.NoError(t, err)
   109  
   110  	assert.EqualValues(t, []string{"This has whitespace sensitive markdown in the description"}, st.Title())
   111  	assert.EqualValues(t, []string{"+ first item", "    + nested item", "    + also nested item", "", "Sample code block:", "", "    fmt.Println(\"Hello World!\")"}, st.Description())
   112  
   113  }
   114  
   115  func dummyBuilder() schemaValidations {
   116  	return schemaValidations{new(spec.Schema)}
   117  }
   118  
   119  func TestSectionedParser_TagsDescription(t *testing.T) {
   120  	block := `This has a title without whitespace.
   121  The punctuation here does indeed matter. But it won't for go.
   122  minimum: 10
   123  maximum: 20
   124  `
   125  	block2 := `This has a title without whitespace.
   126  The punctuation here does indeed matter. But it won't for go.
   127  
   128  minimum: 10
   129  maximum: 20
   130  `
   131  
   132  	var err error
   133  
   134  	st := &sectionedParser{}
   135  	st.setTitle = func(lines []string) {}
   136  	st.taggers = []tagParser{
   137  		{"Maximum", false, false, nil, &setMaximum{dummyBuilder(), regexp.MustCompile(fmt.Sprintf(rxMaximumFmt, ""))}},
   138  		{"Minimum", false, false, nil, &setMinimum{dummyBuilder(), regexp.MustCompile(fmt.Sprintf(rxMinimumFmt, ""))}},
   139  		{"MultipleOf", false, false, nil, &setMultipleOf{dummyBuilder(), regexp.MustCompile(fmt.Sprintf(rxMultipleOfFmt, ""))}},
   140  	}
   141  
   142  	err = st.Parse(ascg(block))
   143  	assert.NoError(t, err)
   144  	assert.EqualValues(t, []string{"This has a title without whitespace."}, st.Title())
   145  	assert.EqualValues(t, []string{"The punctuation here does indeed matter. But it won't for go."}, st.Description())
   146  	assert.Len(t, st.matched, 2)
   147  	_, ok := st.matched["Maximum"]
   148  	assert.True(t, ok)
   149  	_, ok = st.matched["Minimum"]
   150  	assert.True(t, ok)
   151  
   152  	st = &sectionedParser{}
   153  	st.setTitle = func(lines []string) {}
   154  	st.taggers = []tagParser{
   155  		{"Maximum", false, false, nil, &setMaximum{dummyBuilder(), regexp.MustCompile(fmt.Sprintf(rxMaximumFmt, ""))}},
   156  		{"Minimum", false, false, nil, &setMinimum{dummyBuilder(), regexp.MustCompile(fmt.Sprintf(rxMinimumFmt, ""))}},
   157  		{"MultipleOf", false, false, nil, &setMultipleOf{dummyBuilder(), regexp.MustCompile(fmt.Sprintf(rxMultipleOfFmt, ""))}},
   158  	}
   159  
   160  	err = st.Parse(ascg(block2))
   161  	assert.NoError(t, err)
   162  	assert.EqualValues(t, []string{"This has a title without whitespace."}, st.Title())
   163  	assert.EqualValues(t, []string{"The punctuation here does indeed matter. But it won't for go."}, st.Description())
   164  	assert.Len(t, st.matched, 2)
   165  	_, ok = st.matched["Maximum"]
   166  	assert.True(t, ok)
   167  	_, ok = st.matched["Minimum"]
   168  	assert.True(t, ok)
   169  }
   170  
   171  func TestSectionedParser_Empty(t *testing.T) {
   172  	block := `swagger:response someResponse`
   173  
   174  	var err error
   175  
   176  	st := &sectionedParser{}
   177  	st.setTitle = func(lines []string) {}
   178  	ap := newSchemaAnnotationParser("SomeResponse")
   179  	ap.rx = rxResponseOverride
   180  	st.annotation = ap
   181  
   182  	err = st.Parse(ascg(block))
   183  	assert.NoError(t, err)
   184  	assert.Empty(t, st.Title())
   185  	assert.Empty(t, st.Description())
   186  	assert.Empty(t, st.taggers)
   187  	assert.Equal(t, "SomeResponse", ap.GoName)
   188  	assert.Equal(t, "someResponse", ap.Name)
   189  }
   190  
   191  func TestSectionedParser_SkipSectionAnnotation(t *testing.T) {
   192  	block := `swagger:model someModel
   193  
   194  This has a title without whitespace.
   195  The punctuation here does indeed matter. But it won't for go.
   196  
   197  minimum: 10
   198  maximum: 20
   199  `
   200  	var err error
   201  
   202  	st := &sectionedParser{}
   203  	st.setTitle = func(lines []string) {}
   204  	ap := newSchemaAnnotationParser("SomeModel")
   205  	st.annotation = ap
   206  	st.taggers = []tagParser{
   207  		{"Maximum", false, false, nil, &setMaximum{dummyBuilder(), regexp.MustCompile(fmt.Sprintf(rxMaximumFmt, ""))}},
   208  		{"Minimum", false, false, nil, &setMinimum{dummyBuilder(), regexp.MustCompile(fmt.Sprintf(rxMinimumFmt, ""))}},
   209  		{"MultipleOf", false, false, nil, &setMultipleOf{dummyBuilder(), regexp.MustCompile(fmt.Sprintf(rxMultipleOfFmt, ""))}},
   210  	}
   211  
   212  	err = st.Parse(ascg(block))
   213  	assert.NoError(t, err)
   214  	assert.EqualValues(t, []string{"This has a title without whitespace."}, st.Title())
   215  	assert.EqualValues(t, []string{"The punctuation here does indeed matter. But it won't for go."}, st.Description())
   216  	assert.Len(t, st.matched, 2)
   217  	_, ok := st.matched["Maximum"]
   218  	assert.True(t, ok)
   219  	_, ok = st.matched["Minimum"]
   220  	assert.True(t, ok)
   221  	assert.Equal(t, "SomeModel", ap.GoName)
   222  	assert.Equal(t, "someModel", ap.Name)
   223  }
   224  
   225  func TestSectionedParser_TerminateOnNewAnnotation(t *testing.T) {
   226  	block := `swagger:model someModel
   227  
   228  This has a title without whitespace.
   229  The punctuation here does indeed matter. But it won't for go.
   230  
   231  minimum: 10
   232  swagger:meta
   233  maximum: 20
   234  `
   235  	var err error
   236  
   237  	st := &sectionedParser{}
   238  	st.setTitle = func(lines []string) {}
   239  	ap := newSchemaAnnotationParser("SomeModel")
   240  	st.annotation = ap
   241  	st.taggers = []tagParser{
   242  		{"Maximum", false, false, nil, &setMaximum{dummyBuilder(), regexp.MustCompile(fmt.Sprintf(rxMaximumFmt, ""))}},
   243  		{"Minimum", false, false, nil, &setMinimum{dummyBuilder(), regexp.MustCompile(fmt.Sprintf(rxMinimumFmt, ""))}},
   244  		{"MultipleOf", false, false, nil, &setMultipleOf{dummyBuilder(), regexp.MustCompile(fmt.Sprintf(rxMultipleOfFmt, ""))}},
   245  	}
   246  
   247  	err = st.Parse(ascg(block))
   248  	assert.NoError(t, err)
   249  	assert.EqualValues(t, []string{"This has a title without whitespace."}, st.Title())
   250  	assert.EqualValues(t, []string{"The punctuation here does indeed matter. But it won't for go."}, st.Description())
   251  	assert.Len(t, st.matched, 1)
   252  	_, ok := st.matched["Maximum"]
   253  	assert.False(t, ok)
   254  	_, ok = st.matched["Minimum"]
   255  	assert.True(t, ok)
   256  	assert.Equal(t, "SomeModel", ap.GoName)
   257  	assert.Equal(t, "someModel", ap.Name)
   258  }
   259  
   260  func ascg(txt string) *ast.CommentGroup {
   261  	var cg ast.CommentGroup
   262  	for _, line := range strings.Split(txt, "\n") {
   263  		var cmt ast.Comment
   264  		cmt.Text = "// " + line
   265  		cg.List = append(cg.List, &cmt)
   266  	}
   267  	return &cg
   268  }
   269  
   270  func TestShouldAcceptTag(t *testing.T) {
   271  	var tagTests = []struct {
   272  		tags        []string
   273  		includeTags map[string]bool
   274  		excludeTags map[string]bool
   275  		expected    bool
   276  	}{
   277  		{nil, nil, nil, true},
   278  		{[]string{"app"}, map[string]bool{"app": true}, nil, true},
   279  		{[]string{"app"}, nil, map[string]bool{"app": true}, false},
   280  	}
   281  	for _, tt := range tagTests {
   282  		actual := shouldAcceptTag(tt.tags, tt.includeTags, tt.excludeTags)
   283  		assert.Equal(t, tt.expected, actual)
   284  	}
   285  }
   286  
   287  func TestShouldAcceptPkg(t *testing.T) {
   288  	var pkgTests = []struct {
   289  		path        string
   290  		includePkgs []string
   291  		excludePkgs []string
   292  		expected    bool
   293  	}{
   294  		{"", nil, nil, true},
   295  		{"", nil, []string{"app"}, true},
   296  		{"", []string{"app"}, nil, false},
   297  		{"app", []string{"app"}, nil, true},
   298  		{"app", nil, []string{"app"}, false},
   299  		{"vendor/app", []string{"app"}, nil, true},
   300  		{"vendor/app", nil, []string{"app"}, false},
   301  	}
   302  	for _, tt := range pkgTests {
   303  		actual := shouldAcceptPkg(tt.path, tt.includePkgs, tt.excludePkgs)
   304  		assert.Equal(t, tt.expected, actual)
   305  	}
   306  }