6 Commits

Author SHA1 Message Date
irlndts
14a62aa3f7 update vendor 2020-06-01 10:07:19 +03:00
Artem Piskun
9e62844f82 Move to interfaces 2020-06-01 10:03:01 +03:00
Artem Piskun
aa374638bf Minor improvements (#39) 2020-03-24 13:11:44 +03:00
Artem Piskun
d9deca7e18 Create LICENSE.txt 2020-03-24 12:50:36 +03:00
irlndts
417d6d51e6 Removed vendor 2020-03-02 12:03:22 +03:00
irlndts
54c186c94e Travis go version updated 2020-02-28 14:56:52 +03:00
18 changed files with 177 additions and 120 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
examples/

View File

@@ -1,3 +1,3 @@
language: go language: go
go: go:
- "1.12.5" - "1.14"

21
LICENSE.txt Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Artem Piskun
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -4,6 +4,8 @@
go-discogs is a Go client library for the [Discogs API](https://www.discogs.com/developers/). Check the usage section to see how to access the Discogs API. go-discogs is a Go client library for the [Discogs API](https://www.discogs.com/developers/). Check the usage section to see how to access the Discogs API.
The lib is under MIT but be sure you are familiar with [Discogs API Terms of Use](https://support.discogs.com/hc/en-us/articles/360009334593-API-Terms-of-Use).
### Feauteres ### Feauteres
* Database * Database
* [Releases](#releases) * [Releases](#releases)
@@ -18,7 +20,7 @@ go-discogs is a Go client library for the [Discogs API](https://www.discogs.com/
Install Install
-------- --------
go get -u github.com/irlndts/go-discogs go get github.com/irlndts/go-discogs
Usage Usage
--------- ---------
@@ -29,18 +31,19 @@ import "github.com/irlndts/go-discogs"
``` ```
Some requests require authentification (as any user). According to [Discogs](https://www.discogs.com/developers/#page:authentication,header:authentication-discogs-auth-flow), to send requests with Discogs Auth, you have two options: sending your credentials in the query string with key and secret parameters or a [token parameter](https://www.discogs.com/settings/developers). Some requests require authentification (as any user). According to [Discogs](https://www.discogs.com/developers/#page:authentication,header:authentication-discogs-auth-flow), to send requests with Discogs Auth, you have two options: sending your credentials in the query string with key and secret parameters or a [token parameter](https://www.discogs.com/settings/developers).
This is token way example:
```go ```go
client, err := discogs.NewClient(&discogs.Options{ client, err := discogs.New(&discogs.Options{
UserAgent: "Some Name", UserAgent: "Some Name",
Currency: "EUR", // optional, "USD" (default), "GBP", "EUR", "CAD", "AUD", "JPY", "CHF", "MXN", "BRL", "NZD", "SEK", "ZAR" are allowed Currency: "EUR", // optional, "USD" (default), "GBP", "EUR", "CAD", "AUD", "JPY", "CHF", "MXN", "BRL", "NZD", "SEK", "ZAR" are allowed
Token: "Some Token", // optional Token: "Some Token", // optional
URL: "https://api.discogs.com", // optional
}) })
``` ```
#### Releases #### Releases
```go ```go
release, _ := client.Database.Release(9893847) release, _ := client.Release(9893847)
fmt.Println(release.Artists[0].Name, " - ", release.Title) fmt.Println(release.Artists[0].Name, " - ", release.Title)
// St. Petersburg Ska-Jazz Review - Elephant Riddim // St. Petersburg Ska-Jazz Review - Elephant Riddim
``` ```
@@ -72,18 +75,16 @@ type SearchRequest struct {
Contributer string // search contributor usernames (optional) Contributer string // search contributor usernames (optional)
Page int // optional Page int // optional
PerPage int // optional PerPage int // optional
} }
``` ```
Example Example
```go ```go
request := discogs.SearchRequest{Artist: "reggaenauts", ReleaseTitle: "river rock", Page: 0, PerPage: 1} request := discogs.SearchRequest{Artist: "reggaenauts", ReleaseTitle: "river rock", Page: 0, PerPage: 1}
search, _ := client.Search.Search(request) search, _ := client.Search(request)
for _, r := range search.Results { for _, r := range search.Results {
fmt.Println(r.Title) fmt.Println(r.Title)
} }
``` ```
etc.

View File

@@ -12,20 +12,39 @@ const (
mastersURI = "/masters/" mastersURI = "/masters/"
) )
// DatabaseService ... // DatabaseService is an interface to work with database.
type DatabaseService struct { type DatabaseService interface {
// Artist represents a person in the discogs database.
Artist(artistID int) (*Artist, error)
// ArtistReleases returns a list of releases and masters associated with the artist.
ArtistReleases(artistID int, pagination *Pagination) (*ArtistReleases, error)
// Label returns a label.
Label(labelID int) (*Label, error)
// LabelReleases returns a list of Releases associated with the label.
LabelReleases(labelID int, pagination *Pagination) (*LabelReleases, error)
// Master returns a master release.
Master(masterID int) (*Master, error)
// MasterVersions retrieves a list of all Releases that are versions of this master.
MasterVersions(masterID int, pagination *Pagination) (*MasterVersions, error)
// Release returns release by release's ID.
Release(releaseID int) (*Release, error)
// ReleaseRating retruns community release rating.
ReleaseRating(releaseID int) (*ReleaseRating, error)
}
type databaseService struct {
url string url string
currency string currency string
} }
func newDatabaseService(url string, currency string) *DatabaseService { func newDatabaseService(url string, currency string) DatabaseService {
return &DatabaseService{ return &databaseService{
url: url, url: url,
currency: currency, currency: currency,
} }
} }
// Release serves relesase response from discogs // Release serves relesase response from discogs.
type Release struct { type Release struct {
Title string `json:"title"` Title string `json:"title"`
ID int `json:"id"` ID int `json:"id"`
@@ -63,8 +82,7 @@ type Release struct {
Year int `json:"year"` Year int `json:"year"`
} }
// Release returns release by release's ID func (s *databaseService) Release(releaseID int) (*Release, error) {
func (s *DatabaseService) Release(releaseID int) (*Release, error) {
params := url.Values{} params := url.Values{}
params.Set("curr_abbr", s.currency) params.Set("curr_abbr", s.currency)
@@ -73,14 +91,13 @@ func (s *DatabaseService) Release(releaseID int) (*Release, error) {
return release, err return release, err
} }
// ReleaseRating serves response for community release rating request // ReleaseRating serves response for community release rating request.
type ReleaseRating struct { type ReleaseRating struct {
ID int `json:"release_id"` ID int `json:"release_id"`
Rating Rating `json:"rating"` Rating Rating `json:"rating"`
} }
// ReleaseRating retruns community release rating func (s *databaseService) ReleaseRating(releaseID int) (*ReleaseRating, error) {
func (s *DatabaseService) ReleaseRating(releaseID int) (*ReleaseRating, error) {
var rating *ReleaseRating var rating *ReleaseRating
err := request(s.url+releasesURI+strconv.Itoa(releaseID)+"/rating", nil, &rating) err := request(s.url+releasesURI+strconv.Itoa(releaseID)+"/rating", nil, &rating)
return rating, err return rating, err
@@ -105,8 +122,7 @@ type Artist struct {
DataQuality string `json:"data_quality"` DataQuality string `json:"data_quality"`
} }
// Artist represents a person in the discogs database func (s *databaseService) Artist(artistID int) (*Artist, error) {
func (s *DatabaseService) Artist(artistID int) (*Artist, error) {
var artist *Artist var artist *Artist
err := request(s.url+artistsURI+strconv.Itoa(artistID), nil, &artist) err := request(s.url+artistsURI+strconv.Itoa(artistID), nil, &artist)
return artist, err return artist, err
@@ -118,8 +134,7 @@ type ArtistReleases struct {
Releases []ReleaseSource `json:"releases"` Releases []ReleaseSource `json:"releases"`
} }
// ArtistReleases returns a list of releases and masters associated with the artist. func (s *databaseService) ArtistReleases(artistID int, pagination *Pagination) (*ArtistReleases, error) {
func (s *DatabaseService) ArtistReleases(artistID int, pagination *Pagination) (*ArtistReleases, error) {
var releases *ArtistReleases var releases *ArtistReleases
err := request(s.url+artistsURI+strconv.Itoa(artistID)+"/releases", pagination.params(), &releases) err := request(s.url+artistsURI+strconv.Itoa(artistID)+"/releases", pagination.params(), &releases)
return releases, err return releases, err
@@ -141,8 +156,7 @@ type Label struct {
DataQuality string `json:"data_quality"` DataQuality string `json:"data_quality"`
} }
// Label returns a label. func (s *databaseService) Label(labelID int) (*Label, error) {
func (s *DatabaseService) Label(labelID int) (*Label, error) {
var label *Label var label *Label
err := request(s.url+labelsURI+strconv.Itoa(labelID), nil, &label) err := request(s.url+labelsURI+strconv.Itoa(labelID), nil, &label)
return label, err return label, err
@@ -154,8 +168,7 @@ type LabelReleases struct {
Releases []ReleaseSource `json:"releases"` Releases []ReleaseSource `json:"releases"`
} }
// LabelReleases returns a list of Releases associated with the label. func (s *databaseService) LabelReleases(labelID int, pagination *Pagination) (*LabelReleases, error) {
func (s *DatabaseService) LabelReleases(labelID int, pagination *Pagination) (*LabelReleases, error) {
var releases *LabelReleases var releases *LabelReleases
err := request(s.url+labelsURI+strconv.Itoa(labelID)+"/releases", pagination.params(), &releases) err := request(s.url+labelsURI+strconv.Itoa(labelID)+"/releases", pagination.params(), &releases)
return releases, err return releases, err
@@ -187,8 +200,7 @@ type Master struct {
DataQuality string `json:"data_quality"` DataQuality string `json:"data_quality"`
} }
// Master returns a master release func (s *databaseService) Master(masterID int) (*Master, error) {
func (s *DatabaseService) Master(masterID int) (*Master, error) {
var master *Master var master *Master
err := request(s.url+mastersURI+strconv.Itoa(masterID), nil, &master) err := request(s.url+mastersURI+strconv.Itoa(masterID), nil, &master)
return master, err return master, err
@@ -200,8 +212,7 @@ type MasterVersions struct {
Versions []Version `json:"versions"` Versions []Version `json:"versions"`
} }
// MasterVersions retrieves a list of all Releases that are versions of this master func (s *databaseService) MasterVersions(masterID int, pagination *Pagination) (*MasterVersions, error) {
func (s *DatabaseService) MasterVersions(masterID int, pagination *Pagination) (*MasterVersions, error) {
var versions *MasterVersions var versions *MasterVersions
err := request(s.url+mastersURI+strconv.Itoa(masterID)+"/versions", pagination.params(), &versions) err := request(s.url+mastersURI+strconv.Itoa(masterID)+"/versions", pagination.params(), &versions)
return versions, err return versions, err

View File

@@ -60,7 +60,7 @@ func TestDatabaseServiceRelease(t *testing.T) {
defer ts.Close() defer ts.Close()
d := initDiscogsClient(t, &Options{URL: ts.URL}) d := initDiscogsClient(t, &Options{URL: ts.URL})
release, err := d.Database.Release(8138518) release, err := d.Release(8138518)
if err != nil { if err != nil {
t.Fatalf("failed to get release: %s", err) t.Fatalf("failed to get release: %s", err)
} }
@@ -78,7 +78,7 @@ func TestDatabaseServiceMaster(t *testing.T) {
defer ts.Close() defer ts.Close()
d := initDiscogsClient(t, &Options{URL: ts.URL}) d := initDiscogsClient(t, &Options{URL: ts.URL})
master, err := d.Database.Master(718441) master, err := d.Master(718441)
if err != nil { if err != nil {
t.Fatalf("failed to get master: %s", err) t.Fatalf("failed to get master: %s", err)
} }
@@ -95,7 +95,7 @@ func TestDatabaseServiceArtist(t *testing.T) {
defer ts.Close() defer ts.Close()
d := initDiscogsClient(t, &Options{URL: ts.URL}) d := initDiscogsClient(t, &Options{URL: ts.URL})
artist, err := d.Database.Artist(38661) artist, err := d.Artist(38661)
if err != nil { if err != nil {
t.Fatalf("failed to get master: %s", err) t.Fatalf("failed to get master: %s", err)
} }

View File

@@ -14,22 +14,31 @@ const (
// Options is a set of options to use discogs API client // Options is a set of options to use discogs API client
type Options struct { type Options struct {
URL string // Discogs API endpoint (optional).
Currency string URL string
// Currency to use (optional, default is USD).
Currency string
// UserAgent to to call discogs api with.
UserAgent string UserAgent string
Token string // Token provided by discogs (optional).
Token string
} }
// Client is a Discogs client for making Discogs API requests. // Discogs is an interface for making Discogs API requests.
type Client struct { type Discogs interface {
Database *DatabaseService DatabaseService
Search *SearchService SearchService
}
type discogs struct {
DatabaseService
SearchService
} }
var header *http.Header var header *http.Header
// NewClient returns a new Client. // New returns a new discogs API client.
func NewClient(o *Options) (*Client, error) { func New(o *Options) (Discogs, error) {
header = &http.Header{} header = &http.Header{}
if o == nil || o.UserAgent == "" { if o == nil || o.UserAgent == "" {
@@ -52,9 +61,9 @@ func NewClient(o *Options) (*Client, error) {
o.URL = discogsAPI o.URL = discogsAPI
} }
return &Client{ return discogs{
Database: newDatabaseService(o.URL, cur), newDatabaseService(o.URL, cur),
Search: newSearchService(o.URL + "/database/search"), newSearchService(o.URL + "/database/search"),
}, nil }, nil
} }

View File

@@ -5,11 +5,11 @@ import (
) )
const ( const (
testUserAgent = "UnitTestClient/0.0.2 +https://github.com/irlndts/go-discogs" testUserAgent = "UnitTestClient/0.0.2"
testToken = "" testToken = ""
) )
func initDiscogsClient(t *testing.T, options *Options) *Client { func initDiscogsClient(t *testing.T, options *Options) Discogs {
if options == nil { if options == nil {
options = &Options{ options = &Options{
UserAgent: testUserAgent, UserAgent: testUserAgent,
@@ -22,7 +22,7 @@ func initDiscogsClient(t *testing.T, options *Options) *Client {
options.UserAgent = testUserAgent options.UserAgent = testUserAgent
} }
client, err := NewClient(options) client, err := New(options)
if err != nil { if err != nil {
t.Fatalf("failed to create client: %s", err) t.Fatalf("failed to create client: %s", err)
} }
@@ -30,7 +30,7 @@ func initDiscogsClient(t *testing.T, options *Options) *Client {
return client return client
} }
func TestNewClient(t *testing.T) { func TestNew(t *testing.T) {
tests := map[string]struct { tests := map[string]struct {
options *Options options *Options
err error err error
@@ -53,7 +53,7 @@ func TestNewClient(t *testing.T) {
for name := range tests { for name := range tests {
tt := tests[name] tt := tests[name]
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
if _, err := NewClient(tt.options); err != tt.err { if _, err := New(tt.options); err != tt.err {
t.Errorf("err got=%s; want=%s", err, tt.err) t.Errorf("err got=%s; want=%s", err, tt.err)
} }
}) })
@@ -66,19 +66,19 @@ func TestCurrency(t *testing.T) {
want string want string
err error err error
}{ }{
{currency: "", want: "USD", err: nil}, {currency: "", want: "USD"},
{currency: "USD", want: "USD", err: nil}, {currency: "USD", want: "USD"},
{currency: "GBP", want: "GBP", err: nil}, {currency: "GBP", want: "GBP"},
{currency: "EUR", want: "EUR", err: nil}, {currency: "EUR", want: "EUR"},
{currency: "CAD", want: "CAD", err: nil}, {currency: "CAD", want: "CAD"},
{currency: "AUD", want: "AUD", err: nil}, {currency: "AUD", want: "AUD"},
{currency: "JPY", want: "JPY", err: nil}, {currency: "JPY", want: "JPY"},
{currency: "CHF", want: "CHF", err: nil}, {currency: "CHF", want: "CHF"},
{currency: "MXN", want: "MXN", err: nil}, {currency: "MXN", want: "MXN"},
{currency: "BRL", want: "BRL", err: nil}, {currency: "BRL", want: "BRL"},
{currency: "NZD", want: "NZD", err: nil}, {currency: "NZD", want: "NZD"},
{currency: "SEK", want: "SEK", err: nil}, {currency: "SEK", want: "SEK"},
{currency: "ZAR", want: "ZAR", err: nil}, {currency: "ZAR", want: "ZAR"},
{currency: "RUR", want: "", err: ErrCurrencyNotSupported}, {currency: "RUR", want: "", err: ErrCurrencyNotSupported},
} }
for i, tt := range tests { for i, tt := range tests {

21
doc.go Normal file
View File

@@ -0,0 +1,21 @@
/*
Package discogs is a Go client library for the Discogs API.
The discogs package provides a client for accessing the Discogs API.
First of all import library and init client variable.
According to discogs api documentation you must provide your user-agent.
Some requests require authentification (as any user).
According to Discogs, to send requests with Discogs Auth, you have two options:
sending your credentials in the query string with key and secret parameters or
a token parameter. This is token way example:
client, err := discogs.New(&discogs.Options{
UserAgent: "Some Name",
Currency: "EUR", // optional, "USD" (default), "GBP", "EUR", "CAD", "AUD", "JPY", "CHF", "MXN", "BRL", "NZD", "SEK", "ZAR" are allowed
Token: "Some Token", // optional
URL: "https://api.discogs.com", // optional
})
*/
package discogs

View File

@@ -1,26 +0,0 @@
package main
import (
"fmt"
"github.com/irlndts/go-discogs"
)
func main() {
d, err := discogs.NewClient(&discogs.Options{
UserAgent: "TestDiscogsClient/0.0.1 +http://example.com",
Currency: "USD",
Token: "",
})
if err != nil {
fmt.Println(err)
return
}
master, err := d.Database.Master(718441)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", master)
}

2
go.mod
View File

@@ -2,4 +2,4 @@ module github.com/irlndts/go-discogs
go 1.14 go 1.14
require github.com/google/go-cmp v0.4.0 require github.com/google/go-cmp v0.4.1

4
go.sum
View File

@@ -1,4 +1,4 @@
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -5,13 +5,22 @@ import (
"strconv" "strconv"
) )
// SearchService ... // SearchService is an interface to work with search.
type SearchService struct { type SearchService interface {
// Search makes search request to discogs.
// Issue a search query to database. This endpoint accepts pagination parameters.
// Authentication (as any user) is required.
// https://www.discogs.com/developers/#page:database,header:database-search
Search(req SearchRequest) (*Search, error)
}
// searchService ...
type searchService struct {
url string url string
} }
func newSearchService(url string) *SearchService { func newSearchService(url string) SearchService {
return &SearchService{ return &searchService{
url: url, url: url,
} }
} }
@@ -136,11 +145,7 @@ type Result struct {
MasterID int `json:"master_id,omitempty"` MasterID int `json:"master_id,omitempty"`
} }
// Search makes search request to discogs. func (s *searchService) Search(req SearchRequest) (*Search, error) {
// Issue a search query to our database. This endpoint accepts pagination parameters.
// Authentication (as any user) is required.
// https://www.discogs.com/developers/#page:database,header:database-search
func (s *SearchService) Search(req SearchRequest) (*Search, error) {
var search *Search var search *Search
err := request(s.url, req.params(), &search) err := request(s.url, req.params(), &search)
return search, err return search, err

View File

@@ -6,6 +6,10 @@
// //
// This package is intended to be a more powerful and safer alternative to // This package is intended to be a more powerful and safer alternative to
// reflect.DeepEqual for comparing whether two values are semantically equal. // reflect.DeepEqual for comparing whether two values are semantically equal.
// It is intended to only be used in tests, as performance is not a goal and
// it may panic if it cannot compare the values. Its propensity towards
// panicking means that its unsuitable for production environments where a
// spurious panic may be fatal.
// //
// The primary features of cmp are: // The primary features of cmp are:
// //

View File

@@ -81,14 +81,19 @@ func (opts formatOptions) FormatDiff(v *valueNode) textNode {
return opts.FormatDiffSlice(v) return opts.FormatDiffSlice(v)
} }
var withinSlice bool
if v.parent != nil && (v.parent.Type.Kind() == reflect.Slice || v.parent.Type.Kind() == reflect.Array) {
withinSlice = true
}
// For leaf nodes, format the value based on the reflect.Values alone. // For leaf nodes, format the value based on the reflect.Values alone.
if v.MaxDepth == 0 { if v.MaxDepth == 0 {
switch opts.DiffMode { switch opts.DiffMode {
case diffUnknown, diffIdentical: case diffUnknown, diffIdentical:
// Format Equal. // Format Equal.
if v.NumDiff == 0 { if v.NumDiff == 0 {
outx := opts.FormatValue(v.ValueX, visitedPointers{}) outx := opts.FormatValue(v.ValueX, withinSlice, visitedPointers{})
outy := opts.FormatValue(v.ValueY, visitedPointers{}) outy := opts.FormatValue(v.ValueY, withinSlice, visitedPointers{})
if v.NumIgnored > 0 && v.NumSame == 0 { if v.NumIgnored > 0 && v.NumSame == 0 {
return textEllipsis return textEllipsis
} else if outx.Len() < outy.Len() { } else if outx.Len() < outy.Len() {
@@ -101,8 +106,8 @@ func (opts formatOptions) FormatDiff(v *valueNode) textNode {
// Format unequal. // Format unequal.
assert(opts.DiffMode == diffUnknown) assert(opts.DiffMode == diffUnknown)
var list textList var list textList
outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, visitedPointers{}) outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, withinSlice, visitedPointers{})
outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, visitedPointers{}) outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, withinSlice, visitedPointers{})
if outx != nil { if outx != nil {
list = append(list, textRecord{Diff: '-', Value: outx}) list = append(list, textRecord{Diff: '-', Value: outx})
} }
@@ -111,9 +116,9 @@ func (opts formatOptions) FormatDiff(v *valueNode) textNode {
} }
return opts.WithTypeMode(emitType).FormatType(v.Type, list) return opts.WithTypeMode(emitType).FormatType(v.Type, list)
case diffRemoved: case diffRemoved:
return opts.FormatValue(v.ValueX, visitedPointers{}) return opts.FormatValue(v.ValueX, withinSlice, visitedPointers{})
case diffInserted: case diffInserted:
return opts.FormatValue(v.ValueY, visitedPointers{}) return opts.FormatValue(v.ValueY, withinSlice, visitedPointers{})
default: default:
panic("invalid diff mode") panic("invalid diff mode")
} }

View File

@@ -74,7 +74,7 @@ func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode {
// FormatValue prints the reflect.Value, taking extra care to avoid descending // FormatValue prints the reflect.Value, taking extra care to avoid descending
// into pointers already in m. As pointers are visited, m is also updated. // into pointers already in m. As pointers are visited, m is also updated.
func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out textNode) { func (opts formatOptions) FormatValue(v reflect.Value, withinSlice bool, m visitedPointers) (out textNode) {
if !v.IsValid() { if !v.IsValid() {
return nil return nil
} }
@@ -108,12 +108,15 @@ func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out t
return textLine(fmt.Sprint(v.Bool())) return textLine(fmt.Sprint(v.Bool()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return textLine(fmt.Sprint(v.Int())) return textLine(fmt.Sprint(v.Int()))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
// Unnamed uints are usually bytes or words, so use hexadecimal. return textLine(fmt.Sprint(v.Uint()))
if t.PkgPath() == "" || t.Kind() == reflect.Uintptr { case reflect.Uint8:
if withinSlice {
return textLine(formatHex(v.Uint())) return textLine(formatHex(v.Uint()))
} }
return textLine(fmt.Sprint(v.Uint())) return textLine(fmt.Sprint(v.Uint()))
case reflect.Uintptr:
return textLine(formatHex(v.Uint()))
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
return textLine(fmt.Sprint(v.Float())) return textLine(fmt.Sprint(v.Float()))
case reflect.Complex64, reflect.Complex128: case reflect.Complex64, reflect.Complex128:
@@ -129,7 +132,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out t
if value.IsZero(vv) { if value.IsZero(vv) {
continue // Elide fields with zero values continue // Elide fields with zero values
} }
s := opts.WithTypeMode(autoType).FormatValue(vv, m) s := opts.WithTypeMode(autoType).FormatValue(vv, false, m)
list = append(list, textRecord{Key: t.Field(i).Name, Value: s}) list = append(list, textRecord{Key: t.Field(i).Name, Value: s})
} }
return textWrap{"{", list, "}"} return textWrap{"{", list, "}"}
@@ -156,7 +159,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out t
continue continue
} }
} }
s := opts.WithTypeMode(elideType).FormatValue(vi, m) s := opts.WithTypeMode(elideType).FormatValue(vi, true, m)
list = append(list, textRecord{Value: s}) list = append(list, textRecord{Value: s})
} }
return textWrap{ptr + "{", list, "}"} return textWrap{ptr + "{", list, "}"}
@@ -171,7 +174,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out t
var list textList var list textList
for _, k := range value.SortKeys(v.MapKeys()) { for _, k := range value.SortKeys(v.MapKeys()) {
sk := formatMapKey(k) sk := formatMapKey(k)
sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), m) sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), false, m)
list = append(list, textRecord{Key: sk, Value: sv}) list = append(list, textRecord{Key: sk, Value: sv})
} }
if opts.PrintAddresses { if opts.PrintAddresses {
@@ -189,7 +192,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out t
ptr = formatPointer(v) ptr = formatPointer(v)
} }
skipType = true // Let the underlying value print the type instead skipType = true // Let the underlying value print the type instead
return textWrap{"&" + ptr, opts.FormatValue(v.Elem(), m), ""} return textWrap{"&" + ptr, opts.FormatValue(v.Elem(), false, m), ""}
case reflect.Interface: case reflect.Interface:
if v.IsNil() { if v.IsNil() {
return textNil return textNil
@@ -197,7 +200,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out t
// Interfaces accept different concrete types, // Interfaces accept different concrete types,
// so configure the underlying value to explicitly print the type. // so configure the underlying value to explicitly print the type.
skipType = true // Print the concrete type instead skipType = true // Print the concrete type instead
return opts.WithTypeMode(emitType).FormatValue(v.Elem(), m) return opts.WithTypeMode(emitType).FormatValue(v.Elem(), false, m)
default: default:
panic(fmt.Sprintf("%v kind not handled", v.Kind())) panic(fmt.Sprintf("%v kind not handled", v.Kind()))
} }
@@ -209,7 +212,7 @@ func formatMapKey(v reflect.Value) string {
var opts formatOptions var opts formatOptions
opts.TypeMode = elideType opts.TypeMode = elideType
opts.ShallowPointers = true opts.ShallowPointers = true
s := opts.FormatValue(v, visitedPointers{}).String() s := opts.FormatValue(v, false, visitedPointers{}).String()
return strings.TrimSpace(s) return strings.TrimSpace(s)
} }

View File

@@ -172,7 +172,9 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
switch t.Elem().Kind() { switch t.Elem().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
ss = append(ss, fmt.Sprint(v.Index(i).Int())) ss = append(ss, fmt.Sprint(v.Index(i).Int()))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
ss = append(ss, fmt.Sprint(v.Index(i).Uint()))
case reflect.Uint8, reflect.Uintptr:
ss = append(ss, formatHex(v.Index(i).Uint())) ss = append(ss, formatHex(v.Index(i).Uint()))
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
ss = append(ss, fmt.Sprint(v.Index(i).Interface())) ss = append(ss, fmt.Sprint(v.Index(i).Interface()))

2
vendor/modules.txt vendored
View File

@@ -1,4 +1,4 @@
# github.com/google/go-cmp v0.4.0 # github.com/google/go-cmp v0.4.1
## explicit ## explicit
github.com/google/go-cmp/cmp github.com/google/go-cmp/cmp
github.com/google/go-cmp/cmp/internal/diff github.com/google/go-cmp/cmp/internal/diff