diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 758b3dfd..56a75e4a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest env: GO_VERSION: 1.15 - GOLANGCI_LINT_VERSION: v1.33.0 + GOLANGCI_LINT_VERSION: v1.34.0 HUGO_VERSION: 0.54.0 SEIHON_VERSION: v0.5.1 CGO_ENABLED: 0 diff --git a/.golangci.toml b/.golangci.toml index 01764647..2c62819e 100644 --- a/.golangci.toml +++ b/.golangci.toml @@ -43,6 +43,8 @@ "tparallel", # not relevant "paralleltest", # not relevant "exhaustivestruct", # too many false-positive + "makezero", # not relevant + "forbidigo", # not relevant ] [issues] diff --git a/providers/dns/checkdomain/client_test.go b/providers/dns/checkdomain/client_test.go index 8a7cb05a..3d470241 100644 --- a/providers/dns/checkdomain/client_test.go +++ b/providers/dns/checkdomain/client_test.go @@ -15,10 +15,14 @@ import ( "github.com/stretchr/testify/require" ) -func setupTestProvider(t *testing.T) (*DNSProvider, *http.ServeMux, func()) { +func setupTestProvider(t *testing.T) (*DNSProvider, *http.ServeMux) { + t.Helper() + handler := http.NewServeMux() svr := httptest.NewServer(handler) + t.Cleanup(svr.Close) + config := NewDefaultConfig() config.Endpoint, _ = url.Parse(svr.URL) config.Token = "secret" @@ -26,12 +30,11 @@ func setupTestProvider(t *testing.T) (*DNSProvider, *http.ServeMux, func()) { prd, err := NewDNSProviderConfig(config) require.NoError(t, err) - return prd, handler, svr.Close + return prd, handler } func Test_getDomainIDByName(t *testing.T) { - prd, handler, tearDown := setupTestProvider(t) - defer tearDown() + prd, handler := setupTestProvider(t) handler.HandleFunc("/v1/domains", func(rw http.ResponseWriter, req *http.Request) { if req.Method != http.MethodGet { @@ -59,8 +62,7 @@ func Test_getDomainIDByName(t *testing.T) { } func Test_checkNameservers(t *testing.T) { - prd, handler, tearDown := setupTestProvider(t) - defer tearDown() + prd, handler := setupTestProvider(t) handler.HandleFunc("/v1/domains/1/nameservers", func(rw http.ResponseWriter, req *http.Request) { if req.Method != http.MethodGet { @@ -87,8 +89,7 @@ func Test_checkNameservers(t *testing.T) { } func Test_createRecord(t *testing.T) { - prd, handler, tearDown := setupTestProvider(t) - defer tearDown() + prd, handler := setupTestProvider(t) handler.HandleFunc("/v1/domains/1/nameservers/records", func(rw http.ResponseWriter, req *http.Request) { if req.Method != http.MethodPost { @@ -119,8 +120,7 @@ func Test_createRecord(t *testing.T) { } func Test_deleteTXTRecord(t *testing.T) { - prd, handler, tearDown := setupTestProvider(t) - defer tearDown() + prd, handler := setupTestProvider(t) domainName := "lego.test" recordValue := "test" diff --git a/providers/dns/designate/designate_test.go b/providers/dns/designate/designate_test.go index 5cf276b3..4a68d245 100644 --- a/providers/dns/designate/designate_test.go +++ b/providers/dns/designate/designate_test.go @@ -31,7 +31,7 @@ var envTest = tester.NewEnvTest( WithDomain(envDomain) func TestNewDNSProvider_fromEnv(t *testing.T) { - server := getServer(t) + serverURL := setupTestProvider(t) testCases := []struct { desc string @@ -41,7 +41,7 @@ func TestNewDNSProvider_fromEnv(t *testing.T) { { desc: "success", envVars: map[string]string{ - EnvAuthURL: server.URL + "/v2.0/", + EnvAuthURL: serverURL + "/v2.0/", EnvUsername: "B", EnvPassword: "C", EnvRegionName: "D", @@ -71,7 +71,7 @@ func TestNewDNSProvider_fromEnv(t *testing.T) { { desc: "missing username", envVars: map[string]string{ - EnvAuthURL: server.URL + "/v2.0/", + EnvAuthURL: serverURL + "/v2.0/", EnvUsername: "", EnvPassword: "C", EnvRegionName: "D", @@ -81,7 +81,7 @@ func TestNewDNSProvider_fromEnv(t *testing.T) { { desc: "missing password", envVars: map[string]string{ - EnvAuthURL: server.URL + "/v2.0/", + EnvAuthURL: serverURL + "/v2.0/", EnvUsername: "B", EnvPassword: "", EnvRegionName: "D", @@ -91,7 +91,7 @@ func TestNewDNSProvider_fromEnv(t *testing.T) { { desc: "missing region name", envVars: map[string]string{ - EnvAuthURL: server.URL + "/v2.0/", + EnvAuthURL: serverURL + "/v2.0/", EnvUsername: "B", EnvPassword: "C", EnvRegionName: "", @@ -121,7 +121,7 @@ func TestNewDNSProvider_fromEnv(t *testing.T) { } func TestNewDNSProvider_fromCloud(t *testing.T) { - server := getServer(t) + serverURL := setupTestProvider(t) testCases := []struct { desc string @@ -134,7 +134,7 @@ func TestNewDNSProvider_fromCloud(t *testing.T) { osCloud: "good_cloud", cloud: clientconfig.Cloud{ AuthInfo: &clientconfig.AuthInfo{ - AuthURL: server.URL + "/v2.0/", + AuthURL: serverURL + "/v2.0/", Username: "B", Password: "C", ProjectName: "E", @@ -162,7 +162,7 @@ func TestNewDNSProvider_fromCloud(t *testing.T) { osCloud: "missing_username", cloud: clientconfig.Cloud{ AuthInfo: &clientconfig.AuthInfo{ - AuthURL: server.URL + "/v2.0/", + AuthURL: serverURL + "/v2.0/", Password: "C", ProjectName: "E", ProjectID: "F", @@ -176,7 +176,7 @@ func TestNewDNSProvider_fromCloud(t *testing.T) { osCloud: "missing_auth_url", cloud: clientconfig.Cloud{ AuthInfo: &clientconfig.AuthInfo{ - AuthURL: server.URL + "/v2.0/", + AuthURL: serverURL + "/v2.0/", Username: "B", ProjectName: "E", ProjectID: "F", @@ -211,7 +211,7 @@ func TestNewDNSProvider_fromCloud(t *testing.T) { } func TestNewDNSProviderConfig(t *testing.T) { - server := getServer(t) + serverURL := setupTestProvider(t) testCases := []struct { desc string @@ -226,15 +226,15 @@ func TestNewDNSProviderConfig(t *testing.T) { tenantName: "A", password: "B", userName: "C", - authURL: server.URL + "/v2.0/", + authURL: serverURL + "/v2.0/", }, { desc: "wrong auth url", tenantName: "A", password: "B", userName: "C", - authURL: server.URL, - expected: "designate: failed to authenticate: No supported version available from endpoint " + server.URL + "/", + authURL: serverURL, + expected: "designate: failed to authenticate: No supported version available from endpoint " + serverURL + "/", }, } @@ -261,6 +261,8 @@ func TestNewDNSProviderConfig(t *testing.T) { // createCloudsYaml creates a temporary cloud file for testing purpose. func createCloudsYaml(t *testing.T, cloudName string, cloud clientconfig.Cloud) string { + t.Helper() + file, err := ioutil.TempFile("", "lego_test") require.NoError(t, err) @@ -278,7 +280,9 @@ func createCloudsYaml(t *testing.T, cloudName string, cloud clientconfig.Cloud) return file.Name() } -func getServer(t *testing.T) *httptest.Server { +func setupTestProvider(t *testing.T) string { + t.Helper() + mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte(`{ @@ -317,7 +321,7 @@ func getServer(t *testing.T) *httptest.Server { t.Cleanup(server.Close) - return server + return server.URL } func TestLivePresent(t *testing.T) { diff --git a/providers/dns/hyperone/internal/client_test.go b/providers/dns/hyperone/internal/client_test.go index f411bfa7..e1844eba 100644 --- a/providers/dns/hyperone/internal/client_test.go +++ b/providers/dns/hyperone/internal/client_test.go @@ -146,6 +146,8 @@ func TestClient_GetZones(t *testing.T) { } func setupTest(t *testing.T, method, path string, handlers ...assertHandler) *Client { + t.Helper() + mux := http.NewServeMux() server := httptest.NewServer(mux) diff --git a/providers/dns/infomaniak/internal/client_test.go b/providers/dns/infomaniak/internal/client_test.go index 73a8ce7c..21c1c97a 100644 --- a/providers/dns/infomaniak/internal/client_test.go +++ b/providers/dns/infomaniak/internal/client_test.go @@ -12,6 +12,8 @@ import ( ) func setupTest(t *testing.T) (*Client, *http.ServeMux) { + t.Helper() + mux := http.NewServeMux() server := httptest.NewServer(mux) t.Cleanup(server.Close) diff --git a/providers/dns/joker/internal/dmapi/client_test.go b/providers/dns/joker/internal/dmapi/client_test.go index d67984bb..b2835498 100644 --- a/providers/dns/joker/internal/dmapi/client_test.go +++ b/providers/dns/joker/internal/dmapi/client_test.go @@ -24,6 +24,8 @@ const ( ) func setup(t *testing.T) (*http.ServeMux, string) { + t.Helper() + mux := http.NewServeMux() server := httptest.NewServer(mux) diff --git a/providers/dns/lightsail/lightsail_test.go b/providers/dns/lightsail/lightsail_test.go index 1bdcd2d1..f385745a 100644 --- a/providers/dns/lightsail/lightsail_test.go +++ b/providers/dns/lightsail/lightsail_test.go @@ -1,7 +1,6 @@ package lightsail import ( - "net/http/httptest" "os" "testing" @@ -30,10 +29,10 @@ var envTest = tester.NewEnvTest( WithDomain(EnvDNSZone). WithLiveTestRequirements(envAwsAccessKeyID, envAwsSecretAccessKey, EnvDNSZone) -func makeProvider(ts *httptest.Server) (*DNSProvider, error) { +func makeProvider(serverURL string) (*DNSProvider, error) { config := &aws.Config{ Credentials: credentials.NewStaticCredentials("abc", "123", " "), - Endpoint: aws.String(ts.URL), + Endpoint: aws.String(serverURL), Region: aws.String("mock-region"), MaxRetries: aws.Int(1), } @@ -53,9 +52,9 @@ func TestCredentialsFromEnv(t *testing.T) { defer envTest.RestoreEnv() envTest.ClearEnv() - os.Setenv(envAwsAccessKeyID, "123") - os.Setenv(envAwsSecretAccessKey, "123") - os.Setenv(envAwsRegion, "us-east-1") + _ = os.Setenv(envAwsAccessKeyID, "123") + _ = os.Setenv(envAwsSecretAccessKey, "123") + _ = os.Setenv(envAwsRegion, "us-east-1") config := &aws.Config{ CredentialsChainVerboseErrors: aws.Bool(true), @@ -73,10 +72,9 @@ func TestDNSProvider_Present(t *testing.T) { "/": {StatusCode: 200, Body: ""}, } - ts := newMockServer(t, mockResponses) - defer ts.Close() + serverURL := newMockServer(t, mockResponses) - provider, err := makeProvider(ts) + provider, err := makeProvider(serverURL) require.NoError(t, err) domain := "example.com" diff --git a/providers/dns/lightsail/mock_server_test.go b/providers/dns/lightsail/mock_server_test.go index da1b12f3..385c8085 100644 --- a/providers/dns/lightsail/mock_server_test.go +++ b/providers/dns/lightsail/mock_server_test.go @@ -16,8 +16,10 @@ type MockResponse struct { Body string } -func newMockServer(t *testing.T, responses map[string]MockResponse) *httptest.Server { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +func newMockServer(t *testing.T, responses map[string]MockResponse) string { + t.Helper() + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { path := r.URL.Path resp, ok := responses[path] if !ok { @@ -34,6 +36,9 @@ func newMockServer(t *testing.T, responses map[string]MockResponse) *httptest.Se } })) + t.Cleanup(server.Close) + time.Sleep(100 * time.Millisecond) - return ts + + return server.URL } diff --git a/providers/dns/loopia/internal/client_test.go b/providers/dns/loopia/internal/client_test.go index 9eb4b259..a283242b 100644 --- a/providers/dns/loopia/internal/client_test.go +++ b/providers/dns/loopia/internal/client_test.go @@ -20,7 +20,7 @@ func TestClient_AddZoneRecord(t *testing.T) { addZoneRecordEmptyResponse: "", } - server := createFakeServer(t, serverResponses) + serverURL := createFakeServer(t, serverResponses) testCases := []struct { desc string @@ -56,8 +56,7 @@ func TestClient_AddZoneRecord(t *testing.T) { for _, test := range testCases { t.Run(test.desc, func(t *testing.T) { client := NewClient("apiuser", test.password) - client.BaseURL = server.URL + "/" - client.HTTPClient = server.Client() + client.BaseURL = serverURL + "/" err := client.AddTXTRecord(test.domain, exampleSubDomain, 123, "TXTrecord") if len(test.err) == 0 { @@ -78,7 +77,7 @@ func TestClient_RemoveSubdomain(t *testing.T) { removeSubdomainEmptyResponse: "", } - server := createFakeServer(t, serverResponses) + serverURL := createFakeServer(t, serverResponses) testCases := []struct { desc string @@ -114,8 +113,7 @@ func TestClient_RemoveSubdomain(t *testing.T) { for _, test := range testCases { t.Run(test.desc, func(t *testing.T) { client := NewClient("apiuser", test.password) - client.BaseURL = server.URL + "/" - client.HTTPClient = server.Client() + client.BaseURL = serverURL + "/" err := client.RemoveSubdomain(test.domain, exampleSubDomain) if len(test.err) == 0 { @@ -136,7 +134,7 @@ func TestClient_RemoveZoneRecord(t *testing.T) { removeRecordEmptyResponse: "", } - server := createFakeServer(t, serverResponses) + serverURL := createFakeServer(t, serverResponses) testCases := []struct { desc string @@ -172,8 +170,7 @@ func TestClient_RemoveZoneRecord(t *testing.T) { for _, test := range testCases { t.Run(test.desc, func(t *testing.T) { client := NewClient("apiuser", test.password) - client.BaseURL = server.URL + "/" - client.HTTPClient = server.Client() + client.BaseURL = serverURL + "/" err := client.RemoveTXTRecord(test.domain, exampleSubDomain, 12345678) if len(test.err) == 0 { @@ -191,11 +188,10 @@ func TestClient_GetZoneRecord(t *testing.T) { getZoneRecords: getZoneRecordsResponse, } - server := createFakeServer(t, serverResponses) + serverURL := createFakeServer(t, serverResponses) client := NewClient("apiuser", "goodpassword") - client.BaseURL = server.URL + "/" - client.HTTPClient = server.Client() + client.BaseURL = serverURL + "/" recordObjs, err := client.GetTXTRecords(exampleDomain, exampleSubDomain) require.NoError(t, err) @@ -240,7 +236,6 @@ func TestClient_rpcCall_404(t *testing.T) { client := NewClient("apiuser", "apipassword") client.BaseURL = server.URL + "/" - client.HTTPClient = server.Client() err := client.rpcCall(call, &responseString{}) assert.EqualError(t, err, "HTTP Post Error: 404") @@ -272,7 +267,6 @@ func TestClient_rpcCall_RPCError(t *testing.T) { client := NewClient("apiuser", "apipassword") client.BaseURL = server.URL + "/" - client.HTTPClient = server.Client() err := client.rpcCall(call, &responseString{}) assert.EqualError(t, err, "RPC Error: (201) Method signature error: 42") @@ -307,7 +301,9 @@ func TestUnmarshallFaultyRecordObject(t *testing.T) { } } -func createFakeServer(t *testing.T, serverResponses map[string]string) *httptest.Server { +func createFakeServer(t *testing.T, serverResponses map[string]string) string { + t.Helper() + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Content-Type") != "text/xml" { http.Error(w, fmt.Sprintf("invalid content type: %s", r.Header.Get("Content-Type")), http.StatusBadRequest) @@ -335,5 +331,5 @@ func createFakeServer(t *testing.T, serverResponses map[string]string) *httptest t.Cleanup(server.Close) - return server + return server.URL } diff --git a/providers/dns/namecheap/namecheap_test.go b/providers/dns/namecheap/namecheap_test.go index 015195d9..2d0e3481 100644 --- a/providers/dns/namecheap/namecheap_test.go +++ b/providers/dns/namecheap/namecheap_test.go @@ -21,10 +21,9 @@ const ( func TestDNSProvider_getHosts(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - mock := httptest.NewServer(mockServer(&test, t)) - defer mock.Close() + serverURL := mockServer(t, &test) - provider := mockDNSProvider(mock.URL) + provider := mockDNSProvider(serverURL) ch, err := newChallenge(test.domain, "") require.NoError(t, err) @@ -62,10 +61,9 @@ func TestDNSProvider_getHosts(t *testing.T) { func TestDNSProvider_setHosts(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - mock := httptest.NewServer(mockServer(&test, t)) - defer mock.Close() + serverURL := mockServer(t, &test) - prov := mockDNSProvider(mock.URL) + prov := mockDNSProvider(serverURL) ch, err := newChallenge(test.domain, "") require.NoError(t, err) @@ -89,10 +87,9 @@ func TestDNSProvider_setHosts(t *testing.T) { func TestDNSProvider_Present(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - mock := httptest.NewServer(mockServer(&test, t)) - defer mock.Close() + serverURL := mockServer(t, &test) - prov := mockDNSProvider(mock.URL) + prov := mockDNSProvider(serverURL) err := prov.Present(test.domain, "", "dummyKey") if test.errString != "" { assert.EqualError(t, err, "namecheap: "+test.errString) @@ -106,10 +103,9 @@ func TestDNSProvider_Present(t *testing.T) { func TestDNSProvider_CleanUp(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - mock := httptest.NewServer(mockServer(&test, t)) - defer mock.Close() + serverURL := mockServer(t, &test) - prov := mockDNSProvider(mock.URL) + prov := mockDNSProvider(serverURL) err := prov.CleanUp(test.domain, "", "dummyKey") if test.errString != "" { assert.EqualError(t, err, "namecheap: "+test.errString) @@ -171,7 +167,7 @@ func TestDomainSplit(t *testing.T) { } } -func assertHdr(tc *testCase, t *testing.T, values *url.Values) { +func assertHdr(t *testing.T, tc *testCase, values *url.Values) { t.Helper() ch, _ := newChallenge(tc.domain, "") @@ -183,15 +179,17 @@ func assertHdr(tc *testCase, t *testing.T, values *url.Values) { assert.Equal(t, ch.tld, values.Get("TLD"), "TLD") } -func mockServer(tc *testCase, t *testing.T) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +func mockServer(t *testing.T, tc *testCase) string { + t.Helper() + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: values := r.URL.Query() cmd := values.Get("Command") switch cmd { case "namecheap.domains.dns.getHosts": - assertHdr(tc, t, &values) + assertHdr(t, tc, &values) w.WriteHeader(http.StatusOK) fmt.Fprint(w, tc.getHostsResponse) default: @@ -208,7 +206,7 @@ func mockServer(tc *testCase, t *testing.T) http.Handler { cmd := values.Get("Command") switch cmd { case "namecheap.domains.dns.setHosts": - assertHdr(tc, t, &values) + assertHdr(t, tc, &values) w.WriteHeader(http.StatusOK) fmt.Fprint(w, tc.setHostsResponse) default: @@ -218,7 +216,11 @@ func mockServer(tc *testCase, t *testing.T) http.Handler { default: t.Errorf("Unexpected http method: %s", r.Method) } - }) + })) + + t.Cleanup(server.Close) + + return server.URL } func mockDNSProvider(url string) *DNSProvider { diff --git a/providers/dns/otc/mock_test.go b/providers/dns/otc/mock_test.go index 9a8ad4e3..7832f455 100644 --- a/providers/dns/otc/mock_test.go +++ b/providers/dns/otc/mock_test.go @@ -21,6 +21,8 @@ type DNSServerMock struct { // NewDNSServerMock create a new DNSServerMock. func NewDNSServerMock(t *testing.T) *DNSServerMock { + t.Helper() + mux := http.NewServeMux() return &DNSServerMock{ diff --git a/providers/dns/route53/mock_test.go b/providers/dns/route53/mock_test.go index 0ae0d4ae..3a1370e2 100644 --- a/providers/dns/route53/mock_test.go +++ b/providers/dns/route53/mock_test.go @@ -19,8 +19,10 @@ type MockResponse struct { // MockResponseMap maps request paths to responses. type MockResponseMap map[string]MockResponse -func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +func newMockServer(t *testing.T, responses MockResponseMap) string { + t.Helper() + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { path := r.URL.Path resp, ok := responses[path] if !ok { @@ -40,6 +42,9 @@ func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server { } })) + t.Cleanup(server.Close) + time.Sleep(100 * time.Millisecond) - return ts + + return server.URL } diff --git a/providers/dns/route53/route53_test.go b/providers/dns/route53/route53_test.go index ac963f3b..ee040e3a 100644 --- a/providers/dns/route53/route53_test.go +++ b/providers/dns/route53/route53_test.go @@ -1,7 +1,6 @@ package route53 import ( - "net/http/httptest" "os" "testing" "time" @@ -29,10 +28,10 @@ var envTest = tester.NewEnvTest( WithDomain(envDomain). WithLiveTestRequirements(EnvAccessKeyID, EnvSecretAccessKey, EnvRegion, envDomain) -func makeTestProvider(ts *httptest.Server) *DNSProvider { +func makeTestProvider(serverURL string) *DNSProvider { config := &aws.Config{ Credentials: credentials.NewStaticCredentials("abc", "123", " "), - Endpoint: aws.String(ts.URL), + Endpoint: aws.String(serverURL), Region: aws.String("mock-region"), MaxRetries: aws.Int(1), } @@ -41,18 +40,20 @@ func makeTestProvider(ts *httptest.Server) *DNSProvider { if err != nil { panic(err) } - client := route53.New(sess) - cfg := NewDefaultConfig() - return &DNSProvider{client: client, config: cfg} + + return &DNSProvider{ + client: route53.New(sess), + config: NewDefaultConfig(), + } } func Test_loadCredentials_FromEnv(t *testing.T) { defer envTest.RestoreEnv() envTest.ClearEnv() - os.Setenv(EnvAccessKeyID, "123") - os.Setenv(EnvSecretAccessKey, "456") - os.Setenv(EnvRegion, "us-east-1") + _ = os.Setenv(EnvAccessKeyID, "123") + _ = os.Setenv(EnvSecretAccessKey, "456") + _ = os.Setenv(EnvRegion, "us-east-1") config := &aws.Config{ CredentialsChainVerboseErrors: aws.Bool(true), @@ -164,12 +165,11 @@ func TestDNSProvider_Present(t *testing.T) { }, } - ts := newMockServer(t, mockResponses) - defer ts.Close() + serverURL := newMockServer(t, mockResponses) defer envTest.RestoreEnv() envTest.ClearEnv() - provider := makeTestProvider(ts) + provider := makeTestProvider(serverURL) domain := "example.com" keyAuth := "123456d=="