You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: oauth_test.go
    path of file: ./repos/Cloudreve/pkg/filesystem/driver/onedrive
    
    the code of the file until where you have to start completion: package onedrive

import (
	"context"
	"database/sql"
	"errors"
	"github.com/cloudreve/Cloudreve/v3/pkg/mocks/controllermock"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"testing"
	"time"

	"github.com/DATA-DOG/go-sqlmock"
	model "github.com/cloudreve/Cloudreve/v3/models"
	"github.com/cloudreve/Cloudreve/v3/pkg/cache"
	"github.com/cloudreve/Cloudreve/v3/pkg/request"
	"github.com/jinzhu/gorm"
	"github.com/stretchr/testify/assert"
	testMock "github.com/stretchr/testify/mock"
)

var mock sqlmock.Sqlmock

// TestMain 初始化数据库Mock
func TestMain(m *testing.M) {
	var db *sql.DB
	var err error
	db, mock, err = sqlmock.New()
	if err != nil {
		panic("An error was not expected when opening a stub database connection")
	}
	model.DB, _ = gorm.Open("mysql", db)
	defer db.Close()
	m.Run()
}

func TestGetOAuthEndpoint(t *testing.T) {
	asserts := assert.New(t)

	// URL解析失败
	{
		client := Client{
			Endpoints: &Endpoints{
				OAuthURL: string([]byte{0x7f}),
			},
		}
		res := client.getOAuthEndpoint()
		asserts.Nil(res)
	}

	{
		testCase := []struct {
			OAuthURL string
			token    string
			auth     string
			isChina  bool
		}{
			{
				OAuthURL: "http://login.live.com",
				token:    "https://login.live.com/oauth20_token.srf",
				auth:     "https://login.live.com/oauth20_authorize.srf",
				isChina:  false,
			},
			{
				OAuthURL: "http://login.chinacloudapi.cn",
				token:    "https://login.chinacloudapi.cn/common/oauth2/v2.0/token",
				auth:     "https://login.chinacloudapi.cn/common/oauth2/v2.0/authorize",
				isChina:  true,
			},
			{
				OAuthURL: "other",
				token:    "https://login.microsoftonline.com/common/oauth2/v2.0/token",
				auth:     "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
				isChina:  false,
			},
		}

		for i, testCase := range testCase {
			client := Client{
				Endpoints: &Endpoints{
					OAuthURL: testCase.OAuthURL,
				},
			}
			res := client.getOAuthEndpoint()
			asserts.Equal(testCase.token, res.token.String(), "Test Case #%d", i)
			asserts.Equal(testCase.auth, res.authorize.String(), "Test Case #%d", i)
			asserts.Equal(testCase.isChina, client.Endpoints.isInChina, "Test Case #%d", i)
		}
	}
}

func TestClient_OAuthURL(t *testing.T) {
	asserts := assert.New(t)

	client := Client{
		ClientID:  "client_id",
		Redirect:  "http://cloudreve.org/callback",
		Endpoints: &Endpoints{},
	}
	client.Endpoints.OAuthEndpoints = client.getOAuthEndpoint()
	res, err := ur
    
func TestClient_ObtainToken(t *testing.T) {
	asserts := assert.New(t)

	client := Client{
		Endpoints:    &Endpoints{},
		ClientID:     "ClientID",
		ClientSecret: "ClientSecret",
		Redirect:     "Redirect",
	}
	client.Endpoints.OAuthEndpoints = client.getOAuthEndpoint()

	// 刷新Token 成功
	{
		clientMock := ClientMock{}
		clientMock.On(
			"Request",
			"POST",
			client.Endpoints.OAuthEndpoints.token.String(),
			testMock.Anything,
			testMock.Anything,
		).Return(&request.Response{
			Err: nil,
			Response: &http.Response{
				StatusCode: 200,
				Body:       ioutil.NopCloser(strings.NewReader(`{"access_token":"i am token"}`)),
			},
		})
		client.Request = clientMock

		res, err := client.ObtainToken(context.Background())
		clientMock.AssertExpectations(t)
		asserts.NoError(err)
		asserts.NotNil(res)
		asserts.Equal("i am token", res.AccessToken)
	}

	// 重新获取 无法发送请求
	{
		clientMock := ClientMock{}
		clientMock.On(
			"Request",
			"POST",
			client.Endpoints.OAuthEndpoints.token.String(),
			testMock.Anything,
			testMock.Anything,
		).Return(&request.Response{
			Err: errors.New("error"),
		})
		client.Request = clientMock

		res, err := client.ObtainToken(context.Background(), WithCode("code"))
		clientMock.AssertExpectations(t)
		asserts.Error(err)
		asserts.Nil(res)
	}

	// 刷新Token 无法获取响应正文
	{
		clientMock := ClientMock{}
		clientMock.On(
			"Request",
			"POST",
			client.Endpoints.OAuthEndpoints.token.String(),
			testMock.Anything,
			testMock.Anything,
		).Return(&request.Response{
			Err: nil,
			Response: &http.Response{
				StatusCode: 200,
				Body:       ioutil.NopCloser(mockReader("")),
			},
		})
		client.Request = clientMock

		res, err := client.ObtainToken(context.Background())
		clientMock.AssertExpectations(t)
		asserts.Error(err)
		asserts.Nil(res)
		asserts.Equal("read error", err.Error())
	}

	// 刷新Token OneDrive返回错误
	{
		clientMock := ClientMock{}
		clientMock.On(
			"Request",
			"POST",
			client.Endpoints.OAuthEndpoints.token.String(),
			testMock.Anything,
			testMock.Anything,
		).Return(&request.Response{
			Err: nil,
			Response: &http.Response{
				StatusCode: 400,
				Body:       ioutil.NopCloser(strings.NewReader(`{"error":"i am error"}`)),
			},
		})
		client.Request = clientMock

		res, err := client.ObtainToken(context.Background())
		clientMock.AssertExpectations(t)
		asserts.Error(err)
		asserts.Nil(res)
		asserts.Equal("", err.Error())
	}

	// 刷新Token OneDrive未知响应
	{
		clientMock := ClientMock{}
		clientMock.On(
			"Request",
			"POST",
			client.Endpoints.OAuthEndpoints.token.String(),
			testMock.Anything,
			testMock.Anything,
		).Return(&request.Response{
			Err: nil,
			Response: &http.Response{
				StatusCode: 400,
				Body:       ioutil.NopCloser(strings.NewReader(`？？？`)),
			},
		})
		client.Request = clientMock

		res, err := client.ObtainToken(context.Background())
		clientMock.AssertExpectations(t)
		asserts.Error(err)
		asserts.Nil(res)
	}
}