nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: danielgtaylor/huma
Pull request #788 (2025-04-04 13:54:16)

Add WithIndex to PathBuffer
Same as `With()`, but takes and int, calls `PushIndex`, converts to a string, then pops.

Found myself wishing for this functionality today, but not a deal breaker if it doesn't make it in. Just a little more convenient.

I did not see any tests for pathbuffer itself, but since this method wouldn't be covered elsewhere I added a test for it.


Patch:
diff --git a/validate.go b/validate.go
index 336817c..591adc0 100644
--- a/validate.go
+++ b/validate.go
@@ -129,6 +129,18 @@ func (b *PathBuffer) With(s string) string {
 	return tmp
 }
 
+// WithIndex is short for push index, convert to string, and pop. This is useful
+// when you want the location of the index given a path buffer as a prefix.
+//
+//	pb.Push("foo")
+//	pb.WithIndex(1) // return foo[1]
+func (b *PathBuffer) WithIndex(i int) string {
+	b.PushIndex(i)
+	tmp := b.String()
+	b.Pop()
+	return tmp
+}
+
 // Len returns the length of the current path.
 func (b *PathBuffer) Len() int {
 	return b.off


Test patch:
diff --git a/validate_test.go b/validate_test.go
index 60b3c33..c0ab25a 100644
--- a/validate_test.go
+++ b/validate_test.go
@@ -1693,3 +1693,10 @@ func Test_validateWithDiscriminator(t *testing.T) {
 		})
 	}
 }
+
+func TestPathBuffer_WithIndex_ReturnsExpectedString(t *testing.T) {
+	pb := huma.NewPathBuffer([]byte(""), 0)
+	pb.Push("prefix")
+
+	assert.Equal(t, "prefix[1]", pb.WithIndex(1))
+}
Repository: danielgtaylor/huma
Pull request #807 (2025-04-22 15:05:45)

Allow empty path in group operations
Hello! I recently found out the validation of the `path` parameter prevented the use of an empty string in the path.

In my use case I found myself in this situation:
- I wanted to create a `/resource` API Group, with CRUD for `resource`, plus some sets of endpoints for sub-resources (ie: `/resource/:id/stuff`)
- I got a `StripSlashes` middleware (required to handle legacy clients), which trims any `/` from incoming requests
- Since I have `StripSlashes`, If I want to add a  `POST /resource/` I need to actually define the route as `POST /resource`
- The above is not possible because of the strict validation done in `Register`
   https://github.com/danielgtaylor/huma/blob/6bfeebae55ed05e1e909041c5e3692dc168cd066/huma.go#L625-L626

With this PR I relaxed the validation of the `Path` parameter, allowing the empty string in the case of operations defined for a Group with at least a prefix defined




Patch:
diff --git a/huma.go b/huma.go
index 54e932c..709e1a7 100644
--- a/huma.go
+++ b/huma.go
@@ -622,8 +622,13 @@ func Register[I, O any](api API, op Operation, handler func(context.Context, *I)
 	oapi := api.OpenAPI()
 	registry := oapi.Components.Schemas
 
-	if op.Method == "" || op.Path == "" {
-		panic("method and path must be specified in operation")
+	if op.Method == "" {
+		panic("method must be specified in operation")
+	}
+	if op.Path == "" {
+		if grp, ok := api.(*Group); !ok || len(grp.prefixes) == 0 {
+			panic("path must be specified in operation")
+		}
 	}
 	initResponses(&op)
 


Test patch:
diff --git a/group_test.go b/group_test.go
index 9057f14..a6bc594 100644
--- a/group_test.go
+++ b/group_test.go
@@ -26,6 +26,24 @@ func TestGroupNoPrefix(t *testing.T) {
 	assert.Equal(t, http.StatusNoContent, resp.Result().StatusCode)
 }
 
+func TestGroupEmptyPath(t *testing.T) {
+	_, api := humatest.New(t)
+
+	grp := huma.NewGroup(api, "/users")
+
+	huma.Get(grp, "", func(ctx context.Context, input *struct{}) (*struct{}, error) {
+		return nil, nil
+	})
+
+	assert.Nil(t, api.OpenAPI().Paths["/"])
+	assert.Nil(t, api.OpenAPI().Paths[""])
+	assert.NotNil(t, api.OpenAPI().Paths["/users"])
+
+	resp := api.Get("/users")
+	assert.Equal(t, http.StatusNoContent, resp.Result().StatusCode)
+
+}
+
 func TestGroupMultiPrefix(t *testing.T) {
 	_, api := humatest.New(t)
Repository: danielgtaylor/restish
Pull request #14 (2020-10-09 03:24:53)

fix: show error on auth hook failure
Previously we swallowed the error and something non-obvious would fail. This panics and stops execution immediately with a better error.


Patch:
diff --git a/cli/request.go b/cli/request.go
index 39464d3..f187f1b 100644
--- a/cli/request.go
+++ b/cli/request.go
@@ -86,7 +86,10 @@ func MakeRequest(req *http.Request, options ...requestOption) (*http.Response, e
 	if profile.Auth != nil && profile.Auth.Name != "" {
 		auth, ok := authHandlers[profile.Auth.Name]
 		if ok {
-			auth.OnRequest(req, name+":"+viper.GetString("rsh-profile"), profile.Auth.Params)
+			err := auth.OnRequest(req, name+":"+viper.GetString("rsh-profile"), profile.Auth.Params)
+			if err != nil {
+				panic(err)
+			}
 		}
 	}
 


Test patch:
diff --git a/cli/request_test.go b/cli/request_test.go
index 6587f8f..39a9dc0 100644
--- a/cli/request_test.go
+++ b/cli/request_test.go
@@ -1,6 +1,7 @@
 package cli
 
 import (
+	"errors"
 	"net/http"
 	"testing"
 
@@ -55,3 +56,32 @@ func TestRequestPagination(t *testing.T) {
 	// Response body should be a concatenation of all pages.
 	assert.Equal(t, []interface{}{1.0, 2.0, 3.0, 4.0, 5.0, 6.0}, resp.Body)
 }
+
+type authHookFailure struct{}
+
+func (a *authHookFailure) Parameters() []AuthParam {
+	return []AuthParam{}
+}
+
+func (a *authHookFailure) OnRequest(req *http.Request, key string, params map[string]string) error {
+	return errors.New("some-error")
+}
+
+func TestAuthHookFailure(t *testing.T) {
+	configs["auth-hook-fail"] = &APIConfig{
+		Profiles: map[string]*APIProfile{
+			"default": {
+				Auth: &APIAuth{
+					Name: "hook-fail",
+				},
+			},
+		},
+	}
+
+	authHandlers["hook-fail"] = &authHookFailure{}
+
+	r, _ := http.NewRequest(http.MethodGet, "/test", nil)
+	assert.PanicsWithError(t, "some-error", func() {
+		MakeRequest(r)
+	})
+}
Repository: danielgtaylor/restish
Pull request #106 (2022-04-20 19:15:04)

fix: do not panic on empty image
Fixes a bug where a response may have an image content type but zero byte body, which resulted in a crash due to:

> `ERROR: Caught error: interface conversion: interface {} is nil, not []uint8`

Now it will just skip trying to write out an image if the body is `nil`.


Patch:
diff --git a/cli/formatter.go b/cli/formatter.go
index a91fddb..84d01be 100644
--- a/cli/formatter.go
+++ b/cli/formatter.go
@@ -293,7 +293,7 @@ func (f *DefaultFormatter) Format(resp Response) error {
 			var e []byte
 
 			ct := resp.Headers["Content-Type"]
-			if ct == "image/png" || ct == "image/jpeg" || ct == "image/webp" || ct == "image/gif" {
+			if resp.Body != nil && (ct == "image/png" || ct == "image/jpeg" || ct == "image/webp" || ct == "image/gif") {
 				// This is likely an image. Let's display it if we can! Get the window
 				// size, read and scale the image, and display it using unicode.
 				w, h, err := terminal.GetSize(0)


Test patch:
diff --git a/cli/formatter_test.go b/cli/formatter_test.go
index 2f29126..2756623 100644
--- a/cli/formatter_test.go
+++ b/cli/formatter_test.go
@@ -65,3 +65,20 @@ func TestRawLargeJSONNumbers(t *testing.T) {
 	})
 	assert.Equal(t, "null\n1000000000000000\n120000\n1.234\n5e-14\n", buf.String())
 }
+
+func TestFormatEmptyImage(t *testing.T) {
+	formatter := NewDefaultFormatter(false)
+	buf := &bytes.Buffer{}
+	Stdout = buf
+	viper.Set("rsh-raw", false)
+	viper.Set("rsh-filter", "")
+
+	// This should not panic!
+	formatter.Format(Response{
+		Headers: map[string]string{
+			"Content-Type":   "image/jpeg",
+			"Content-Length": "0",
+		},
+		Body: nil,
+	})
+}
Repository: danielgtaylor/restish
Pull request #107 (2022-04-20 19:22:59)

fix: prevent escaping JSON for browsers
Prevents escaping `<`, `>`, and `&` in the JSON (which exists to support some legacy browsers). See also https://stackoverflow.com/a/28596225/164268


Patch:
diff --git a/cli/formatter.go b/cli/formatter.go
index 84d01be..db147ed 100644
--- a/cli/formatter.go
+++ b/cli/formatter.go
@@ -366,11 +366,19 @@ func (f *DefaultFormatter) Format(resp Response) error {
 			lexer = "yaml"
 		} else {
 			data = makeJSONSafe(data, false)
-			encoded, err = json.MarshalIndent(data, "", "  ")
 
-			if err != nil {
+			// The default encoder escapes '<', '>', and '&' which we don't want
+			// since we are not a browser. Disable this with an encoder instance.
+			// See https://stackoverflow.com/a/28596225/164268
+			buf := &bytes.Buffer{}
+			enc := json.NewEncoder(buf)
+			enc.SetEscapeHTML(false)
+			enc.SetIndent("", "  ")
+
+			if err := enc.Encode(data); err != nil {
 				return err
 			}
+			encoded = buf.Bytes()
 
 			lexer = "json"
 		}


Test patch:
diff --git a/cli/formatter_test.go b/cli/formatter_test.go
index 2756623..9d2641a 100644
--- a/cli/formatter_test.go
+++ b/cli/formatter_test.go
@@ -82,3 +82,24 @@ func TestFormatEmptyImage(t *testing.T) {
 		Body: nil,
 	})
 }
+
+func TestJSONEscape(t *testing.T) {
+	formatter := NewDefaultFormatter(false)
+	buf := &bytes.Buffer{}
+	Stdout = buf
+	viper.Set("rsh-raw", false)
+	viper.Set("rsh-filter", "")
+	viper.Set("rsh-output-format", "json")
+	defer func() { viper.Set("rsh-output_format", "auto") }()
+
+	formatter.Format(Response{
+		Headers: map[string]string{
+			"Content-Type": "application/json",
+		},
+		Body: map[string]string{
+			"test": "<em> and & shouldn't get escaped",
+		},
+	})
+
+	assert.Contains(t, buf.String(), "<em> and & shouldn't get escaped")
+}
Repository: danielgtaylor/restish
Pull request #108 (2022-04-20 19:44:07)

fix: find HAL links in array responses
This makes sure that arrays of objects (e.g. list operations) can have parsed links as well.


Patch:
diff --git a/cli/links.go b/cli/links.go
index ea28347..251aefc 100644
--- a/cli/links.go
+++ b/cli/links.go
@@ -91,18 +91,27 @@ type HALParser struct{}
 
 // ParseLinks processes the links in a parsed response.
 func (h HALParser) ParseLinks(resp *Response) error {
-	hal := halBody{}
-	if err := mapstructure.Decode(resp.Body, &hal); err == nil {
-		for rel, link := range hal.Links {
-			if rel == "curies" {
-				// TODO: handle curies at some point?
-				continue
-			}
+	entries := []interface{}{}
+	if l, ok := resp.Body.([]interface{}); ok {
+		entries = l
+	} else {
+		entries = append(entries, resp.Body)
+	}
 
-			resp.Links[rel] = append(resp.Links[rel], &Link{
-				Rel: rel,
-				URI: link.Href,
-			})
+	for _, entry := range entries {
+		hal := halBody{}
+		if err := mapstructure.Decode(entry, &hal); err == nil {
+			for rel, link := range hal.Links {
+				if rel == "curies" {
+					// TODO: handle curies at some point?
+					continue
+				}
+
+				resp.Links[rel] = append(resp.Links[rel], &Link{
+					Rel: rel,
+					URI: link.Href,
+				})
+			}
 		}
 	}
 


Test patch:
diff --git a/cli/links_test.go b/cli/links_test.go
index 75bda9a..716391a 100644
--- a/cli/links_test.go
+++ b/cli/links_test.go
@@ -70,6 +70,34 @@ func TestHALParser(t *testing.T) {
 	assert.Equal(t, r.Links["item"][0].URI, "/item")
 }
 
+func TestHALParserArray(t *testing.T) {
+	r := &Response{
+		Links: Links{},
+		Body: []interface{}{
+			map[string]interface{}{
+				"_links": map[string]interface{}{
+					"self": map[string]interface{}{
+						"href": "/one",
+					},
+				},
+			},
+			map[string]interface{}{
+				"_links": map[string]interface{}{
+					"self": map[string]interface{}{
+						"href": "/two",
+					},
+				},
+			},
+		},
+	}
+
+	p := HALParser{}
+	err := p.ParseLinks(r)
+	assert.NoError(t, err)
+	assert.Equal(t, r.Links["self"][0].URI, "/one")
+	assert.Equal(t, r.Links["self"][1].URI, "/two")
+}
+
 func TestTerrificallySimpleJSONParser(t *testing.T) {
 	r := &Response{
 		Links: Links{},
Repository: danielgtaylor/restish
Pull request #110 (2022-04-24 23:11:44)

fix: formatting, simplify dates
Fixes a formatting bug where `.` was matching too many chars instead of a literal `.` and simplifies the human-readable representation of dates where the time component is empty.


Patch:
diff --git a/cli/lexer.go b/cli/lexer.go
index 7badac2..f071356 100644
--- a/cli/lexer.go
+++ b/cli/lexer.go
@@ -19,7 +19,7 @@ var ReadableLexer = lexers.Register(chroma.MustNewLexer(
 		},
 		"scalar": {
 			{`(true|false|null)\b`, chroma.KeywordConstant, nil},
-			{`"?0x[0-9a-f]+(...)?"?`, chroma.LiteralNumberHex, nil},
+			{`"?0x[0-9a-f]+(\\.\\.\\.)?"?`, chroma.LiteralNumberHex, nil},
 			{`"?[0-9]{4}-[0-9]{2}-[0-9]{2}(T[0-9:+-.]+Z?)?"?`, chroma.LiteralDate, nil},
 			{`-?(0|[1-9]\d*)(\.\d+[eE](\+|-)?\d+|[eE](\+|-)?\d+|\.\d+)`, chroma.LiteralNumberFloat, nil},
 			{`-?(0|[1-9]\d*)`, chroma.LiteralNumberInteger, nil},
diff --git a/cli/readable.go b/cli/readable.go
index d710c30..c4c27b1 100644
--- a/cli/readable.go
+++ b/cli/readable.go
@@ -148,6 +148,10 @@ func marshalReadable(indent string, v interface{}) ([]byte, error) {
 		return []byte(m), nil
 	case reflect.Struct:
 		if t, ok := v.(time.Time); ok {
+			if t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 && t.Nanosecond() == 0 {
+				// Special case: date only
+				return []byte(t.UTC().Format("2006-01-02")), nil
+			}
 			return []byte(t.UTC().Format(time.RFC3339Nano)), nil
 		}
 


Test patch:
diff --git a/cli/readable_test.go b/cli/readable_test.go
index a95f0f3..1d7aa38 100644
--- a/cli/readable_test.go
+++ b/cli/readable_test.go
@@ -8,9 +8,11 @@ import (
 )
 
 func TestReadableMarshal(t *testing.T) {
+	created, _ := time.Parse(time.RFC3339, "2020-01-01T12:34:56Z")
 	data := map[string]interface{}{
 		"binary":     []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
-		"created":    time.Time{},
+		"created":    created,
+		"date":       created.Truncate(24 * time.Hour),
 		"id":         "test",
 		"emptyMap":   map[string]interface{}{},
 		"emptyArray": []string{},
@@ -28,7 +30,8 @@ func TestReadableMarshal(t *testing.T) {
 	assert.NoError(t, err)
 	assert.Equal(t, `{
   binary: 0x00010203040506070809...
-  created: 0001-01-01T00:00:00Z
+  created: 2020-01-01T12:34:56Z
+  date: 2020-01-01
   emptyArray: []
   emptyMap: {}
   float: 1.2
Repository: danielgtaylor/restish
Pull request #165 (2023-01-14 18:33:14)

fix: properly support commas in headers
Previously commas would break the headers, e.g. sending a `Date` or `Last-Modified` or `If-Unmodified-Since` header. That was because the flags parser was splitting on commas, which is now disabled with this fix. The custom logic splitting on commas on environment variables is left in for now to support multiple headers set via the environment.


Patch:
diff --git a/cli/cli.go b/cli/cli.go
index 12fbd0a..b0f7e12 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -728,10 +728,10 @@ func Run() error {
 	if caCert, _ := GlobalFlags.GetString("rsh-ca-cert"); caCert != "" {
 		viper.Set("rsh-ca-cert", caCert)
 	}
-	if query, _ := GlobalFlags.GetStringSlice("rsh-query"); len(query) > 0 {
+	if query, _ := GlobalFlags.GetStringArray("rsh-query"); len(query) > 0 {
 		viper.Set("rsh-query", query)
 	}
-	if headers, _ := GlobalFlags.GetStringSlice("rsh-header"); len(headers) > 0 {
+	if headers, _ := GlobalFlags.GetStringArray("rsh-header"); len(headers) > 0 {
 		viper.Set("rsh-header", headers)
 	}
 	profile, _ := GlobalFlags.GetString("rsh-profile")
diff --git a/cli/flag.go b/cli/flag.go
index 721d4b9..ebbbdae 100644
--- a/cli/flag.go
+++ b/cli/flag.go
@@ -44,8 +44,8 @@ func AddGlobalFlag(name, short, description string, defaultValue interface{}, mu
 				v = strings.Split(s, ",")
 				viper.Set(name, v)
 			}
-			flags.StringSliceP(name, short, v.([]string), description)
-			GlobalFlags.StringSliceP(name, short, v.([]string), description)
+			flags.StringArrayP(name, short, v.([]string), description)
+			GlobalFlags.StringArrayP(name, short, v.([]string), description)
 		} else {
 			flags.StringP(name, short, fmt.Sprintf("%v", viper.Get(name)), description)
 			GlobalFlags.StringP(name, short, fmt.Sprintf("%v", viper.Get(name)), description)


Test patch:
diff --git a/cli/cli_test.go b/cli/cli_test.go
index fc1ba1a..4bf554f 100644
--- a/cli/cli_test.go
+++ b/cli/cli_test.go
@@ -91,6 +91,15 @@ func TestPutURI400(t *testing.T) {
 	}`)
 }
 
+func TestHeaderWithComma(t *testing.T) {
+	defer gock.Off()
+
+	gock.New("http://example.com").Get("/").MatchHeader("Foo", "a,b,c").Reply(204)
+
+	out := run("http://example.com/ -H Foo:a,b,c")
+	assert.Contains(t, out, "204 No Content")
+}
+
 type TestAuth struct{}
 
 // Parameters returns a list of OAuth2 Authorization Code inputs.
Repository: danielgtaylor/restish
Pull request #206 (2023-07-30 17:20:47)

finished last bit of the gron outputter implementation
also updated the test to show it's handling the pesky `<`, `>`, `&` chars.


Patch:
diff --git a/cli/content.go b/cli/content.go
index 42f9d5e..308aeb3 100644
--- a/cli/content.go
+++ b/cli/content.go
@@ -251,8 +251,13 @@ func setTable(data []interface{}) ([]byte, error) {
 // available as a built-in Restish output option.
 type Gron struct{}
 
-// Detect if the content type is gron.
+// Detect if the content type is gron-able.
 func (t Gron) Detect(contentType string) bool {
+	first := strings.Split(contentType, ";")[0]
+	if first == "application/json" || strings.HasSuffix(first, "+json") {
+		return true
+	}
+
 	return false
 }
 
@@ -265,7 +270,7 @@ func (t Gron) Marshal(value interface{}) ([]byte, error) {
 
 // Unmarshal the value from a gron string.
 func (t Gron) Unmarshal(data []byte, value interface{}) error {
-	return fmt.Errorf("unimplemented")
+	return json.Unmarshal(data, value)
 }
 
 // JSON describes content types like `application/json` or
diff --git a/cli/gron.go b/cli/gron.go
index c4673b8..edc2b8a 100644
--- a/cli/gron.go
+++ b/cli/gron.go
@@ -1,6 +1,7 @@
 package cli
 
 import (
+	"bytes"
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
@@ -175,11 +176,18 @@ func marshalGron(pb *PathBuffer, data any, isAnon bool, out []byte) ([]byte, err
 		}
 	default:
 		// This is a primitive type, just take the JSON representation.
-		v, err := json.Marshal(data)
-		if err != nil {
+		// The default encoder escapes '<', '>', and '&' which we don't want
+		// since we are not a browser. Disable this with an encoder instance.
+		// See https://stackoverflow.com/a/28596225/164268
+		buf := &bytes.Buffer{}
+		enc := json.NewEncoder(buf)
+		enc.SetEscapeHTML(false)
+		if err := enc.Encode(makeJSONSafe(data)); err != nil {
 			return nil, err
 		}
-		out = apnd(out, pb.Bytes(), " = ", v, ";\n")
+		// Note: encoder adds it's own ending newline we need to strip out.
+		b := bytes.TrimSuffix(buf.Bytes(), []byte("\n"))
+		out = apnd(out, pb.Bytes(), " = ", b, ";\n")
 	}
 
 	return out, nil


Test patch:
diff --git a/cli/gron_test.go b/cli/gron_test.go
index f88881c..508683c 100644
--- a/cli/gron_test.go
+++ b/cli/gron_test.go
@@ -26,7 +26,7 @@ func TestGronMarshal(t *testing.T) {
 		B: 42,
 		C: true,
 		D: D{[]map[string]any{
-			{"e": "world"},
+			{"e": "world & i <3 restish"},
 			{"f": []any{1, 2}, "g": time.Time{}, "h": []byte("foo")},
 			{"for": map[int]int{1: 2}},
 		}},
@@ -42,7 +42,7 @@ body.b = 42;
 body.c = true;
 body.d = [];
 body.d[0] = {};
-body.d[0].e = "world";
+body.d[0].e = "world & i <3 restish";
 body.d[1] = {};
 body.d[1].f = [];
 body.d[1].f[0] = 1;
Repository: danielgtaylor/restish
Pull request #234 (2023-12-15 23:33:09)

feat: add command to clear auth token cache
This adds a basic profile-aware command to clear the auth token cache, so you don't have to try and find the `cache.json` file, find the right line, and delete it in order to force e.g. OAuth2 re-auth. Now it's a simple:

```sh
$ restish api clear-auth-cache $NAME`
```

Pass `--rsh-profile=$PROFILE` or `-p $PROFILE` to clear the cache for a specific profile instead of `default`.


Patch:
diff --git a/cli/apiconfig.go b/cli/apiconfig.go
index 30cfae4..e9ecfdc 100644
--- a/cli/apiconfig.go
+++ b/cli/apiconfig.go
@@ -170,6 +170,27 @@ func initAPIConfig() {
 		Run:   func(cmd *cobra.Command, args []string) { editAPIs(os.Exit) },
 	})
 
+	apiCommand.AddCommand(&cobra.Command{
+		Use:   "clear-auth-cache short-name",
+		Short: "Clear API auth token cache",
+		Long:  "Clear the API auth token cache for the current profile. This will force a re-authentication the next time you make a request.",
+		Args:  cobra.ExactArgs(1),
+		Run: func(cmd *cobra.Command, args []string) {
+			apiName := args[0]
+			api := configs[apiName]
+			if api == nil {
+				panic("API " + apiName + " not found")
+			}
+
+			// Remove the cache entry.
+			Cache.Set(apiName+":"+viper.GetString("rsh-profile"), "")
+
+			if err := Cache.WriteConfig(); err != nil {
+				panic(fmt.Errorf("Unable to write cache file: %w", err))
+			}
+		},
+	})
+
 	apiCommand.AddCommand(&cobra.Command{
 		Use:   "show short-name",
 		Short: "Show API config",


Test patch:
diff --git a/cli/apiconfig_test.go b/cli/apiconfig_test.go
index be1b0c6..ba22ff9 100644
--- a/cli/apiconfig_test.go
+++ b/cli/apiconfig_test.go
@@ -24,6 +24,43 @@ func TestAPIShow(t *testing.T) {
 	assert.Equal(t, captured, "\x1b[38;5;247m{\x1b[0m\n  \x1b[38;5;74m\"base\"\x1b[0m\x1b[38;5;247m:\x1b[0m \x1b[38;5;150m\"https://api.example.com\"\x1b[0m\n\x1b[38;5;247m}\x1b[0m\n")
 }
 
+func TestAPIClearCache(t *testing.T) {
+	reset(false)
+
+	configs["test"] = &APIConfig{
+		name: "test",
+		Base: "https://api.example.com",
+	}
+	Cache.Set("test:default.token", "abc123")
+
+	runNoReset("api clear-auth-cache test")
+
+	assert.Equal(t, "", Cache.GetString("test:default.token"))
+}
+
+func TestAPIClearCacheProfile(t *testing.T) {
+	reset(false)
+
+	configs["test"] = &APIConfig{
+		name: "test",
+		Base: "https://api.example.com",
+	}
+	Cache.Set("test:default.token", "abc123")
+	Cache.Set("test:other.token", "def456")
+
+	runNoReset("api clear-auth-cache test -p other")
+
+	assert.Equal(t, "abc123", Cache.GetString("test:default.token"))
+	assert.Equal(t, "", Cache.GetString("test:other.token"))
+}
+
+func TestAPIClearCacheMissing(t *testing.T) {
+	reset(false)
+
+	captured := runNoReset("api clear-auth-cache missing-api")
+	assert.Contains(t, captured, "API missing-api not found")
+}
+
 func TestEditAPIsMissingEditor(t *testing.T) {
 	os.Setenv("EDITOR", "")
 	os.Setenv("VISUAL", "")
Repository: exercism/xgo
Pull request #491 (2017-02-06 14:37:12)

vlq: add test versioning (#470)


Patch:
diff --git a/exercises/variable-length-quantity/example.go b/exercises/variable-length-quantity/example.go
index 945c4966..906a28fb 100644
--- a/exercises/variable-length-quantity/example.go
+++ b/exercises/variable-length-quantity/example.go
@@ -1,5 +1,7 @@
 package variablelengthquantity
 
+const testVersion = 1
+
 // EncodeVarint returns the varint encoding of x.
 func EncodeVarint(x uint32) []byte {
 	if x>>7 == 0 {


Test patch:
diff --git a/exercises/variable-length-quantity/variable_length_quantity_test.go b/exercises/variable-length-quantity/variable_length_quantity_test.go
index 0118eeac..23148c88 100644
--- a/exercises/variable-length-quantity/variable_length_quantity_test.go
+++ b/exercises/variable-length-quantity/variable_length_quantity_test.go
@@ -5,6 +5,8 @@ import (
 	"testing"
 )
 
+const targetTestVersion = 1
+
 var testCases = []struct {
 	input  []byte
 	output uint32
@@ -23,6 +25,12 @@ var testCases = []struct {
 	10: {[]byte{0x81, 0x10}, 144, 1},
 }
 
+func TestTestVersion(t *testing.T) {
+	if testVersion != targetTestVersion {
+		t.Fatalf("Found testVersion = %v, want %v.", testVersion, targetTestVersion)
+	}
+}
+
 func TestDecodeVarint(t *testing.T) {
 	for i, tc := range testCases {
 		o, size := DecodeVarint(tc.input)