...

Source file src/github.com/vektah/gqlparser/validator/imported_test.go

Documentation: github.com/vektah/gqlparser/validator

     1  package validator_test
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"regexp"
     9  	"sort"
    10  	"strconv"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/stretchr/testify/require"
    15  	"github.com/vektah/gqlparser"
    16  	"github.com/vektah/gqlparser/ast"
    17  	"github.com/vektah/gqlparser/gqlerror"
    18  	"gopkg.in/yaml.v2"
    19  )
    20  
    21  type Spec struct {
    22  	Name   string
    23  	Rule   string
    24  	Schema string
    25  	Query  string
    26  	Errors gqlerror.List
    27  }
    28  
    29  type Deviation struct {
    30  	Rule   string
    31  	Errors []*gqlerror.Error
    32  	Skip   string
    33  
    34  	pattern *regexp.Regexp
    35  }
    36  
    37  func TestValidation(t *testing.T) {
    38  	var rawSchemas []string
    39  	readYaml("./imported/spec/schemas.yml", &rawSchemas)
    40  
    41  	var deviations []*Deviation
    42  	readYaml("./imported/deviations.yml", &deviations)
    43  	for _, d := range deviations {
    44  		d.pattern = regexp.MustCompile("^" + d.Rule + "$")
    45  	}
    46  
    47  	var schemas []*ast.Schema
    48  	for i, schema := range rawSchemas {
    49  		schema, err := gqlparser.LoadSchema(&ast.Source{Input: schema, Name: fmt.Sprintf("schemas.yml[%d]", i)})
    50  		if err != nil {
    51  			panic(err)
    52  		}
    53  		schemas = append(schemas, schema)
    54  	}
    55  
    56  	err := filepath.Walk("./", func(path string, info os.FileInfo, err error) error {
    57  		if info.IsDir() || !strings.HasSuffix(path, ".spec.yml") {
    58  			return nil
    59  		}
    60  
    61  		runSpec(t, schemas, deviations, path)
    62  		return nil
    63  	})
    64  	require.NoError(t, err)
    65  }
    66  
    67  func runSpec(t *testing.T, schemas []*ast.Schema, deviations []*Deviation, filename string) {
    68  	ruleName := strings.TrimSuffix(filepath.Base(filename), ".spec.yml")
    69  
    70  	var specs []Spec
    71  	readYaml(filename, &specs)
    72  	t.Run(ruleName, func(t *testing.T) {
    73  		for _, spec := range specs {
    74  			if len(spec.Errors) == 0 {
    75  				spec.Errors = nil
    76  			}
    77  			t.Run(spec.Name, func(t *testing.T) {
    78  				for _, deviation := range deviations {
    79  					if deviation.pattern.MatchString(ruleName + "/" + spec.Name) {
    80  						if deviation.Skip != "" {
    81  							t.Skip(deviation.Skip)
    82  						}
    83  						if deviation.Errors != nil {
    84  							spec.Errors = deviation.Errors
    85  						}
    86  					}
    87  				}
    88  
    89  				// idx := spec.Schema
    90  				var schema *ast.Schema
    91  				if idx, err := strconv.Atoi(spec.Schema); err != nil {
    92  					var gqlErr *gqlerror.Error
    93  					schema, gqlErr = gqlparser.LoadSchema(&ast.Source{Input: spec.Schema, Name: spec.Name})
    94  					if gqlErr != nil {
    95  						t.Fatal(err)
    96  					}
    97  				} else {
    98  					schema = schemas[idx]
    99  				}
   100  				_, err := gqlparser.LoadQuery(schema, spec.Query)
   101  				var finalErrors gqlerror.List
   102  				for _, err := range err {
   103  					// ignore errors from other rules
   104  					if spec.Rule != "" && err.Rule != spec.Rule {
   105  						continue
   106  					}
   107  					finalErrors = append(finalErrors, err)
   108  				}
   109  
   110  				for i := range spec.Errors {
   111  					spec.Errors[i].Rule = spec.Rule
   112  
   113  					// remove inconsistent use of ;
   114  					spec.Errors[i].Message = strings.Replace(spec.Errors[i].Message, "; Did you mean", ". Did you mean", -1)
   115  				}
   116  				sort.Slice(spec.Errors, func(i, j int) bool {
   117  					return strings.Compare(spec.Errors[i].Message, spec.Errors[j].Message) > 0
   118  				})
   119  				sort.Slice(finalErrors, func(i, j int) bool {
   120  					return strings.Compare(finalErrors[i].Message, finalErrors[j].Message) > 0
   121  				})
   122  
   123  				if len(finalErrors) != len(spec.Errors) {
   124  					t.Errorf("wrong number of errors returned\ngot:\n%s\nwant:\n%s", finalErrors.Error(), spec.Errors)
   125  				} else {
   126  					for i := range spec.Errors {
   127  						expected := spec.Errors[i]
   128  						actual := finalErrors[i]
   129  						if actual.Rule != spec.Rule {
   130  							continue
   131  						}
   132  						var errLocs []string
   133  						if expected.Message != actual.Message {
   134  							errLocs = append(errLocs, "message mismatch")
   135  						}
   136  						if len(expected.Locations) > 0 && len(actual.Locations) == 0 {
   137  							errLocs = append(errLocs, "missing location")
   138  						}
   139  						if len(expected.Locations) > 0 && len(actual.Locations) > 0 {
   140  							found := false
   141  							for _, loc := range expected.Locations {
   142  								if actual.Locations[0].Line == loc.Line {
   143  									found = true
   144  									break
   145  								}
   146  							}
   147  
   148  							if !found {
   149  								errLocs = append(errLocs, "line")
   150  							}
   151  						}
   152  
   153  						if len(errLocs) > 0 {
   154  							t.Errorf("%s\ngot:  %s\nwant: %s", strings.Join(errLocs, ", "), finalErrors[i].Error(), spec.Errors[i].Error())
   155  						}
   156  					}
   157  				}
   158  
   159  				if t.Failed() {
   160  					t.Logf("name: '%s'", spec.Name)
   161  					t.Log("\nquery:", spec.Query)
   162  				}
   163  			})
   164  		}
   165  	})
   166  }
   167  
   168  func readYaml(filename string, result interface{}) {
   169  	b, err := ioutil.ReadFile(filename)
   170  	if err != nil {
   171  		panic(err)
   172  	}
   173  	err = yaml.Unmarshal(b, result)
   174  	if err != nil {
   175  		panic(fmt.Errorf("unable to load %s: %s", filename, err.Error()))
   176  	}
   177  }
   178  

View as plain text