chore(vertexai): use cross-language tests

Replace the tests for inferFullModelName and inferLocation
with cross-language tests.

These tests are written in YAML so they can be parsed and run
in any language with a suitable implementation.

This is the first use of my new cross-language test design
and implementation, github.com/jba/xltest.
diff --git a/vertexai/genai/client_test.go b/vertexai/genai/client_test.go
index c530737..b0d03e2 100644
--- a/vertexai/genai/client_test.go
+++ b/vertexai/genai/client_test.go
@@ -27,6 +27,7 @@
 	"strings"
 	"testing"
 
+	"github.com/jba/xltest/go/xltest"
 	"google.golang.org/api/iterator"
 )
 
@@ -612,44 +613,19 @@
 }
 
 func TestInferFullModelName(t *testing.T) {
-	for _, test := range []struct {
-		name string
-		want string
-	}{
-		{"xyz", "projects/proj/locations/loc/publishers/google/models/xyz"},
-		{"models/abc", "projects/proj/locations/loc/publishers/google/models/abc"},
-		{"publishers/foo/xyz", "projects/proj/locations/loc/publishers/foo/xyz"},
-		{"x/y/z", "x/y/z"},
-	} {
-		t.Run(test.name, func(t *testing.T) {
-			got := inferFullModelName("proj", "loc", test.name)
-			if got != test.want {
-				t.Errorf("got %q, want %q", got, test.want)
-			}
-		})
+	tst, err := xltest.ReadFile(filepath.Join("testdata", "model_name_test.yaml"))
+	if err != nil {
+		t.Fatal(err)
 	}
+	tst.Run(t, func(s string) string {
+		return inferFullModelName("proj", "loc", s)
+	}, nil)
 }
 
 func TestInferLocation(t *testing.T) {
-	for _, test := range []struct {
-		name                             string
-		arg                              string
-		cloudRegionEnv, cloudMlRegionEnv string
-		want                             string
-	}{
-		{"arg passed", "us-west4", "abc", "def", "us-west4"},
-		{"first env", "", "abc", "", "abc"},
-		{"second env", "", "", "klm", "klm"},
-		{"default", "", "", "", defaultLocation},
-		{"first env precedence", "", "101", "klm", "101"},
-	} {
-		t.Run(test.name, func(t *testing.T) {
-			t.Setenv("GOOGLE_CLOUD_REGION", test.cloudRegionEnv)
-			t.Setenv("CLOUD_ML_REGION", test.cloudMlRegionEnv)
-			got := inferLocation(test.arg)
-			if got != test.want {
-				t.Errorf("got %q, want %q", got, test.want)
-			}
-		})
+	tst, err := xltest.ReadFile(filepath.Join("testdata", "location_test.yaml"))
+	if err != nil {
+		t.Fatal(err)
 	}
+	tst.Run(t, inferLocation, nil)
 }
diff --git a/vertexai/genai/testdata/location_test.yaml b/vertexai/genai/testdata/location_test.yaml
new file mode 100644
index 0000000..5ac002c
--- /dev/null
+++ b/vertexai/genai/testdata/location_test.yaml
@@ -0,0 +1,37 @@
+# This is an xltest file.
+# See github.com/jba/xltest for information about its format
+# and how to interpret it.
+
+# Test function: takes a string, returns a string that is the location
+# to use for the service.
+# Validation: default (equality).
+
+name: location
+description: how a location for the service is determined
+subtests:
+  - name: user provides
+    in: us-west4
+    want: us-west4
+
+  - name: default
+    description: the default location is us-central1
+    in: ''
+    want: us-central1
+
+  - name: env vars
+    env:
+      CLOUD_ML_REGION: cmr
+    subtests:
+      - in: ''
+        want: cmr
+
+      - description: GOOGLE_CLOUD_REGION takes precedence over CLOUD_ML_REGION
+        env:
+          GOOGLE_CLOUD_REGION: gcr
+        in: ''
+        want: gcr
+
+      - description: user input takes precedence over env vars
+        in: us-west4
+        want: us-west4
+        
diff --git a/vertexai/genai/testdata/model_name_test.yaml b/vertexai/genai/testdata/model_name_test.yaml
new file mode 100644
index 0000000..d8d405f
--- /dev/null
+++ b/vertexai/genai/testdata/model_name_test.yaml
@@ -0,0 +1,25 @@
+# This is an xltest file.
+# See github.com/jba/xltest for information about its format
+# and how to interpret it.
+
+# Test function: takes a string, returns a string that is the full
+# model name. Assumes the current project is 'proj' and the current
+# location is 'loc'.
+
+# Validation: default (equality).
+
+name: model name
+description: determining a full model name from a partial one
+subtests:
+  - in: xyz
+    want: projects/proj/locations/loc/publishers/google/models/xyz
+
+  - in: models/abc
+    want: projects/proj/locations/loc/publishers/google/models/abc
+    
+  - in: publishers/foo/xyz
+    want: projects/proj/locations/loc/publishers/foo/xyz
+
+  - in: x/y/z
+    want: x/y/z
+       
diff --git a/vertexai/go.mod b/vertexai/go.mod
index 5db4f2d..f5f30e5 100644
--- a/vertexai/go.mod
+++ b/vertexai/go.mod
@@ -5,6 +5,7 @@
 require (
 	cloud.google.com/go v0.113.0
 	cloud.google.com/go/aiplatform v1.67.0
+	github.com/jba/xltest/go/xltest v0.1.1
 	google.golang.org/api v0.180.0
 	google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda
 	google.golang.org/protobuf v1.34.1
@@ -21,9 +22,11 @@
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/golang/protobuf v1.5.4 // indirect
+	github.com/google/go-cmp v0.6.0 // indirect
 	github.com/google/s2a-go v0.1.7 // indirect
 	github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
 	github.com/googleapis/gax-go/v2 v2.12.4 // indirect
+	github.com/kr/pretty v0.3.1 // indirect
 	go.opencensus.io v0.24.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
@@ -40,4 +43,5 @@
 	google.golang.org/genproto/googleapis/api v0.0.0-20240506185236-b8a5c65736ae // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20240506185236-b8a5c65736ae // indirect
 	google.golang.org/grpc v1.63.2 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/vertexai/go.sum b/vertexai/go.sum
index 1c4d7ba..a28b2f2 100644
--- a/vertexai/go.sum
+++ b/vertexai/go.sum
@@ -17,6 +17,7 @@
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -54,6 +55,7 @@
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
 github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -61,9 +63,18 @@
 github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
 github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg=
 github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI=
+github.com/jba/xltest/go/xltest v0.1.1 h1:HV6454xz+kYvycBw/CHgk4Baj4klInZ0jichK0CaNhs=
+github.com/jba/xltest/go/xltest v0.1.1/go.mod h1:1t1ZLeFuJj14cypt9MzCna/qdRYBwaObid9dP2cpi7Q=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -157,6 +168,7 @@
 google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
 google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=