ChatGPT解决这个技术问题 Extra ChatGPT

Is it possible to get the current root of package structure as a string in golang test?

go

I am writing a utility function for my unit tests which is used by unit tests in multiple packages. This utility function must read a particular file (always the same file). Here are three solutions which do not work, to explain what I am looking for and why.

Hardcode the absolute path. This fails because another user who is trying to test the project might have a different prefix on the absolute path. Hardcode a relative path from the path of the file which defines the utility function. This fails because packages which import and use this function are not necessarily at the same level of the file hierarchy as the file that defines the utility function, and relative paths are interpreted relative to the importer, not the imported. Pass in the relative path to the file from every caller relative to the caller's package. This actually works but seems to be very verbose because now every caller must be changed to pass one file.

I see a fourth solution, whereby I can hardcode a path in the utility function which is relative to the root directory of the top-level package. However, I have not been able to find a way to get the root directory in code, although I suspect there is one because imports can be resolved from the root.

Thus, how might I get the sought-after root directory?

I've looked over various Go documents but have so far failed to find a solution. I have also seen this question but the solution there is equivalent to #3 above.

As far as I know, relative paths are interpreted relative to the current working directory, not a particular package.
@thwd, You are correct, but when I'm running go test on a another package, that package's directory is the current working directory. By empirical testing, this is true even if the actual current working directory is a different directory.
oh, now I get it. One other idea: During go test, $GOPATH should be set to the root of the current workspace, so just use a path relative to $GOPATH/src.
@thwd, Thanks for the suggestions. Unfortunately $GOPATH can contain multiple :-delimited paths, and it is not possible for the code to know which of them it belongs to. It seems very hacky to try them all until it finds a file with the name it wants.
One last thought: runtime.GOROOT() returns "the root used during the Go build". As setting a $GOROOT is discouraged, this might be a solution.

O
Oleksiy Chechel

You can also use my method without 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


Best answer. Works for both the root (main) and testing the packages within the application.
You need to replace "=" with ":=" for the code to work.
@thebiggestlebowski, in var section)
During the build, it will persist the current path. Meaning if you will move the build it will try to access persisted path.
Of course. But there is no other way to get that path. On the other hand, the author of the question needs the path during unit tests.
X
Xeoncross

Building on the answer by Oleksiy you can create a sub-package in your project called ./internal/projectpath/projectpath.go and paste in the following:

package projectpath

import (
    "path/filepath"
    "runtime"
)

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

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

Then you can use projectpath.Root in any other package to have the root folder of your project.


D
Dele

Returns the root of the application:

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

func RootDir() string {
    _, b, _, _ := runtime.Caller(0)
    d := path.Join(path.Dir(b))
    return filepath.Dir(d)
}

this does not give root path but the current dir path
P
Petre Sosa

Go directories:

// from Executable Directory
ex, _ := os.Executable()
fmt.Println("Executable DIR:", filepath.Dir(ex))

// Current working directory
dir, _ := os.Getwd()
fmt.Println("CWD:", dir)

// Relative on runtime DIR:
_, b, _, _ := runtime.Caller(0)
d1 := path.Join(path.Dir(b))
fmt.Println("Relative", d1)

A
Abex

Yes, Finding package path is possible:

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
}

All you have to do is copy this file to your project. Keep in mind this comes up with the path for the file, not the caller so you have to copy the function/file to every project you need the function in. Additionally if you put this in a file with other code be sure to respect CGO's import rules.


关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now