...

Source file src/github.com/google/go-github/v33/test/fields/fields.go

Documentation: github.com/google/go-github/v33/test/fields

     1  // Copyright 2014 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  // This tool tests for the JSON mappings in the go-github data types. It will
     7  // identify fields that are returned by the live GitHub API, but that are not
     8  // currently mapped into a struct field of the relevant go-github type. This
     9  // helps to ensure that all relevant data returned by the API is being made
    10  // accessible, particularly new fields that are periodically (and sometimes
    11  // quietly) added to the API over time.
    12  //
    13  // These tests simply aid in identifying which fields aren't being mapped; it
    14  // is not necessarily true that every one of them should always be mapped.
    15  // Some fields may be undocumented for a reason, either because they aren't
    16  // actually used yet or should not be relied upon.
    17  package main
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"flag"
    23  	"fmt"
    24  	"os"
    25  	"reflect"
    26  	"strings"
    27  
    28  	"github.com/google/go-github/v33/github"
    29  	"golang.org/x/oauth2"
    30  )
    31  
    32  var (
    33  	client *github.Client
    34  
    35  	// auth indicates whether tests are being run with an OAuth token.
    36  	// Tests can use this flag to skip certain tests when run without auth.
    37  	auth bool
    38  
    39  	skipURLs = flag.Bool("skip_urls", false, "skip url fields")
    40  )
    41  
    42  func main() {
    43  	flag.Parse()
    44  
    45  	token := os.Getenv("GITHUB_AUTH_TOKEN")
    46  	if token == "" {
    47  		print("!!! No OAuth token. Some tests won't run. !!!\n\n")
    48  		client = github.NewClient(nil)
    49  	} else {
    50  		tc := oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(
    51  			&oauth2.Token{AccessToken: token},
    52  		))
    53  		client = github.NewClient(tc)
    54  		auth = true
    55  	}
    56  
    57  	for _, tt := range []struct {
    58  		url string
    59  		typ interface{}
    60  	}{
    61  		//{"rate_limit", &github.RateLimits{}},
    62  		{"users/octocat", &github.User{}},
    63  		{"user", &github.User{}},
    64  		{"users/willnorris/keys", &[]github.Key{}},
    65  		{"orgs/google-test", &github.Organization{}},
    66  		{"repos/google/go-github", &github.Repository{}},
    67  		{"repos/google/go-github/issues/1", &github.Issue{}},
    68  		{"/gists/9257657", &github.Gist{}},
    69  	} {
    70  		err := testType(tt.url, tt.typ)
    71  		if err != nil {
    72  			fmt.Printf("error: %v\n", err)
    73  		}
    74  	}
    75  }
    76  
    77  // testType fetches the JSON resource at urlStr and compares its keys to the
    78  // struct fields of typ.
    79  func testType(urlStr string, typ interface{}) error {
    80  	slice := reflect.Indirect(reflect.ValueOf(typ)).Kind() == reflect.Slice
    81  
    82  	req, err := client.NewRequest("GET", urlStr, nil)
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	// start with a json.RawMessage so we can decode multiple ways below
    88  	raw := new(json.RawMessage)
    89  	_, err = client.Do(context.Background(), req, raw)
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	// unmarshal directly to a map
    95  	var m1 map[string]interface{}
    96  	if slice {
    97  		var s []map[string]interface{}
    98  		err = json.Unmarshal(*raw, &s)
    99  		if err != nil {
   100  			return err
   101  		}
   102  		m1 = s[0]
   103  	} else {
   104  		err = json.Unmarshal(*raw, &m1)
   105  		if err != nil {
   106  			return err
   107  		}
   108  	}
   109  
   110  	// unmarshal to typ first, then re-marshal and unmarshal to a map
   111  	err = json.Unmarshal(*raw, typ)
   112  	if err != nil {
   113  		return err
   114  	}
   115  
   116  	var byt []byte
   117  	if slice {
   118  		// use first item in slice
   119  		v := reflect.Indirect(reflect.ValueOf(typ))
   120  		byt, err = json.Marshal(v.Index(0).Interface())
   121  		if err != nil {
   122  			return err
   123  		}
   124  	} else {
   125  		byt, err = json.Marshal(typ)
   126  		if err != nil {
   127  			return err
   128  		}
   129  	}
   130  
   131  	var m2 map[string]interface{}
   132  	err = json.Unmarshal(byt, &m2)
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	// now compare the two maps
   138  	for k, v := range m1 {
   139  		if *skipURLs && strings.HasSuffix(k, "_url") {
   140  			continue
   141  		}
   142  		if _, ok := m2[k]; !ok {
   143  			fmt.Printf("%v missing field for key: %v (example value: %v)\n", reflect.TypeOf(typ), k, v)
   144  		}
   145  	}
   146  
   147  	return nil
   148  }
   149  

View as plain text