Можно ли получить текущий корень структуры пакета в виде строки в тесте golang?

Я пишу служебную функцию для своих модульных тестов, которая используется модульными тестами в нескольких пакетах. Эта служебная функция должна читать определенный файл (всегда один и тот же файл). Вот три решения, которые не работают, чтобы объяснить, что я ищу и почему.

  • Hardcode - абсолютный путь. Это не удается, потому что другой пользователь, который пытается протестировать проект, может иметь другой префикс на абсолютном пути.

  • Hardcode относительный путь от пути файла, который определяет функцию утилиты. Это терпит неудачу, потому что пакеты, которые импортируют и используют эту функцию, не обязательно находятся на одном уровне иерархии файлов, как файл, который определяет функцию утилиты, а относительные пути интерпретируются относительно импортера, а не импортированы.

  • Передайте относительный путь к файлу от каждого вызывающего абонента относительно пакета вызывающего абонента. Это действительно работает, но кажется очень многословным, потому что теперь каждый вызывающий объект должен быть изменен для передачи одного файла.

Я вижу четвертое решение, в котором я могу жестко указать путь в функции утилиты, который относится к корневому каталогу пакета верхнего уровня. Тем не менее, я не смог найти способ получить корневой каталог в коде, хотя я подозреваю, что есть один, потому что импорт может быть разрешен из корня.

Таким образом, как я могу получить искомый корневой каталог?

Я просмотрел различные документы Go, но пока не нашел решения. Я также видел этот вопрос, но решение там эквивалентно # 3 выше.

Ответ 1

Вы также можете использовать мой метод без C:

package mypackage

import (
    "path/filepath"
    "runtime"
    "fmt"
)

var (
    _, b, _, _ = runtime.Caller(0)
    basepath   = filepath.Dir(b)
)

func PrintMyPath() {
    fmt.Println(basepath)
}

https://play.golang.org/p/ifVRIq7Tx0

Ответ 2

Основываясь на ответе Алексея answer by Oleksiy, вы можете создать в своем проекте подпакет под названием ./internal/projectpath/projectpath.go и вставить следующее:

package projectpath

import (
    "path/filepath"
    "runtime"
)

var (
    _, b, _, _ = runtime.Caller(0)

    // Root folder of this project
    Root = filepath.Join(filepath.Dir(b), "../..")
)

Затем вы можете использовать projectpath.Root в любом другом пакете, чтобы иметь корневую папку вашего проекта.

Ответ 3

Да, поиск пути к папке возможен:

pathfind.go:

package main

/*
const char* GetMyPathFILE = __FILE__;
*/
import "C"
import "path/filepath"

var basepath = ""

//GetMyPath Returns the absolute directory of this(pathfind.go) file
func GetMyPath() string {
    if basepath == "" {
        g := C.GoString(C.GetMyPathFILE)
        basepath = filepath.Dir(g)
    }
    return basepath
}

Все, что вам нужно сделать, это скопировать этот файл в ваш проект. Имейте в виду, что это касается пути к файлу, а не вызывающего, поэтому вам нужно скопировать функцию/файл в каждый проект, в котором вам нужна функция. Кроме того, если вы помещаете это в файл с другим кодом, обязательно соблюдайте CGO правила импорта.