Skip to content

Commit

Permalink
Adding tree methods including example and unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
0x19 committed Jun 20, 2023
1 parent ec9f9d4 commit 5408482
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 0 deletions.
39 changes: 39 additions & 0 deletions examples/get_files.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package examples

import (
"fmt"
"net/http"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/txpull/sourcify-go"
)

func Example_GetFiles() {
// Create a custom HTTP client with timeout
httpClient := &http.Client{
Timeout: 30 * time.Second,
}

// Create a new Sourcify client with custom options
client := sourcify.NewClient(
sourcify.WithHTTPClient(httpClient),
sourcify.WithBaseURL("https://sourcify.dev/server"),
sourcify.WithRetryOptions(
sourcify.WithMaxRetries(3),
sourcify.WithDelay(2*time.Second),
),
)

// Get files for the Binance Smart Chain with the address of the R3T contract
files, err := sourcify.GetContractFiles(client, 56, common.HexToAddress("0x054B2223509D430269a31De4AE2f335890be5C8F"), sourcify.MethodMatchTypeAny)
if err != nil {
panic(err)
}

fmt.Printf("Status: %+v\n", files.Status)

for _, file := range files.Files {
fmt.Printf("Path: %+v\n", file)
}
}
62 changes: 62 additions & 0 deletions methods_tree.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
package sourcify

import (
"encoding/json"
"fmt"
"net/http"

"github.com/ethereum/go-ethereum/common"
)

var (
// MethodGetFileTreeFullOrPartialMatch represents the API endpoint for getting the file tree with full or partial match in the Sourcify service.
// It includes the name, the HTTP method, the URI, and the parameters necessary for the request.
Expand Down Expand Up @@ -47,3 +55,57 @@ var (
},
}
)

// FileTree represents the file tree response from the Sourcify service.
type FileTree struct {
Status string `json:"status"`
Files []string `json:"files"`
}

// GetContractFiles retrieves the repository URLs for every file in the source tree for the given chain ID and contract address.
// The matchType parameter determines whether to search for full matches, partial matches, or any matches.
// It returns the FileTree object containing the status and file URLs, or an error if any.
func GetContractFiles(client *Client, chainId int, contract common.Address, matchType MethodMatchType) (*FileTree, error) {
var method Method

switch matchType {
case MethodMatchTypeFull:
method = MethodGetFileTreeFullMatch
case MethodMatchTypePartial:
method = MethodGetFileTreeFullOrPartialMatch
case MethodMatchTypeAny:
method = MethodGetFileTreeFullOrPartialMatch
default:
return nil, fmt.Errorf("invalid match type: %s", matchType)
}

method.SetParams(
MethodParam{Key: ":chain", Value: chainId},
MethodParam{Key: ":address", Value: contract.Hex()},
)

if err := method.Verify(); err != nil {
return nil, err
}

response, statusCode, err := client.CallMethod(method)
if err != nil {
return nil, err
}

// Close the io.ReadCloser interface.
// This is important as CallMethod is NOT closing the response body!
// You'll have memory leaks if you don't do this!
defer response.Close()

if statusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status code: %d", statusCode)
}

var toReturn *FileTree
if err := json.NewDecoder(response).Decode(&toReturn); err != nil {
return nil, err
}

return toReturn, nil
}
74 changes: 74 additions & 0 deletions methods_tree_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package sourcify

import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
)

func TestGetContractFiles(t *testing.T) {
// Create a mock HTTP server
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/files/tree/any/1/0x0000000000000000000000001234567890aBcdEF" {
// Simulate a successful response with sample file tree
fileTree := &FileTree{
Status: "success",
Files: []string{"/path/to/file1.sol", "/path/to/file2.sol"},
}

err := json.NewEncoder(w).Encode(fileTree)
if err != nil {
t.Errorf("failed to encode mock file tree: %v", err)
}
} else {
http.NotFound(w, r)
}
}))
defer mockServer.Close()

// Create a client for the mock server
client := NewClient(WithBaseURL(mockServer.URL))

// Define test data
chainID := 1
contractAddress := common.HexToAddress("0x1234567890abcdef")
matchType := MethodMatchTypeAny

// Call the function to get contract files
fileTree, err := GetContractFiles(client, chainID, contractAddress, matchType)

// Verify the results
assert.NoError(t, err, "GetContractFiles returned an error")

expectedFileTree := &FileTree{
Status: "success",
Files: []string{"/path/to/file1.sol", "/path/to/file2.sol"},
}

assert.Equal(t, expectedFileTree, fileTree, "GetContractFiles returned unexpected file tree")
}

func TestGetContractFiles_Error(t *testing.T) {
// Create a mock HTTP server that always returns 404 Not Found
mockServer := httptest.NewServer(http.NotFoundHandler())
defer mockServer.Close()

// Create a client for the mock server
client := NewClient(WithBaseURL(mockServer.URL))

// Define test data
chainID := 1
contractAddress := common.HexToAddress("0x1234567890abcdef")
matchType := MethodMatchTypeAny

// Call the function to get contract files
fileTree, err := GetContractFiles(client, chainID, contractAddress, matchType)

// Verify the results
assert.Error(t, err, "GetContractFiles should return an error")
assert.Nil(t, fileTree, "File tree should be nil")
}

0 comments on commit 5408482

Please sign in to comment.