github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/names/custom_integration_test.go (about)

     1  package names
     2  
     3  import (
     4  	"encoding/csv"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"path/filepath"
    10  	"testing"
    11  
    12  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
    13  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
    14  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils"
    15  )
    16  
    17  func TestCrudIntegration(t *testing.T) {
    18  	chain := utils.GetTestChain()
    19  	tmpDirPath := filepath.Join(os.TempDir(), "trueblocks")
    20  	if err := os.MkdirAll(tmpDirPath, 0777); err != nil {
    21  		t.Fatal(err)
    22  	}
    23  	defer func() {
    24  		if err := os.RemoveAll(tmpDirPath); err != nil {
    25  			t.Fatal("os.RemoveAll:", err)
    26  		}
    27  	}()
    28  	loadTestDatabase := func() *os.File {
    29  		tempFile, err := os.OpenFile(
    30  			filepath.Join(os.TempDir(), "trueblocks", "names_custom.tab"),
    31  			os.O_RDWR|os.O_CREATE|os.O_TRUNC,
    32  			0777,
    33  		)
    34  		if err != nil {
    35  			t.Fatal(err)
    36  		}
    37  		return tempFile
    38  	}
    39  	tempFile := loadTestDatabase()
    40  	customNames = map[base.Address]types.Name{}
    41  	addrStr := "0x1f9090aae28b8a3dceadf281b0f12828e676c326"
    42  	addr := base.HexToAddress(addrStr)
    43  	expected := types.Name{
    44  		Name:    "test name",
    45  		Address: addr,
    46  	}
    47  
    48  	expected.IsCustom = true
    49  	customNamesMutex.Lock()
    50  	customNames[expected.Address] = expected
    51  	customNamesMutex.Unlock()
    52  	if err := writeCustomNames(tempFile); err != nil {
    53  		t.Fatal(err)
    54  	}
    55  
    56  	tempFile.Seek(0, 0)
    57  	r := csv.NewReader(tempFile)
    58  	r.Comma = '\t'
    59  
    60  	result, err := r.ReadAll()
    61  	if err != nil {
    62  		t.Fatal(err)
    63  	}
    64  
    65  	if value := result[1][1]; value != expected.Address.Hex() {
    66  		t.Fatal("create: wrong address", value)
    67  	}
    68  	if value := result[1][2]; value != expected.Name {
    69  		t.Fatal("create: wrong name", value)
    70  	}
    71  
    72  	// Read
    73  	read := ReadName(DatabaseCustom, chain, addr)
    74  
    75  	if value := read.Address; value != expected.Address {
    76  		t.Fatal("read: wrong address", value)
    77  	}
    78  	if value := read.Name; value != expected.Name {
    79  		t.Fatal("read: wrong name", value)
    80  	}
    81  
    82  	// Update
    83  	updated, err := setIfExists(tempFile, &types.Name{
    84  		Name:    "new name",
    85  		Address: addr,
    86  	})
    87  	if err != nil {
    88  		t.Fatal("update:", err)
    89  	}
    90  	if name := updated.Name; name != "new name" {
    91  		t.Fatal("wrong name", name)
    92  	}
    93  	if addr := updated.Address.Hex(); addr != addrStr {
    94  		t.Fatal("wrong address", addr)
    95  	}
    96  
    97  	// Delete
    98  	deleted, err := changeDeleted(tempFile, addr, true)
    99  	if err != nil {
   100  		t.Fatal("delete:", err)
   101  	}
   102  	if deleted == nil {
   103  		t.Fatal("delete: returned name is nil")
   104  	}
   105  	if !deleted.Deleted {
   106  		t.Fatal("delete: delete flag not set")
   107  	}
   108  
   109  	// Undelete
   110  	undeleted, err := changeDeleted(tempFile, addr, false)
   111  	if err != nil {
   112  		t.Fatal("undelete:", err)
   113  	}
   114  	if undeleted == nil {
   115  		t.Fatal("undelete: returned name is nil")
   116  	}
   117  	if undeleted.Deleted {
   118  		t.Fatal("undelete: delete flag not unset")
   119  	}
   120  
   121  	// Invalid remove
   122  	// Commented out, because C++ doesn't check it
   123  	// _, err = names.RemoveName(names.DatabaseCustom, tempFile, addr)
   124  	// if err == nil {
   125  	// 	t.Fatal("remove: expected error")
   126  	// }
   127  
   128  	// Remove
   129  	// Set flag first
   130  	_, err = changeDeleted(tempFile, addr, true)
   131  	if err != nil {
   132  		t.Fatal("remove: delete:", err)
   133  	}
   134  	removed, err := removeIfExists(tempFile, addr)
   135  	if err != nil {
   136  		t.Fatal("remove:", err)
   137  	}
   138  	if name := removed.Name; name != "new name" {
   139  		t.Fatal("remove: wrong name", name)
   140  	}
   141  	if addr := removed.Address.Hex(); addr != addrStr {
   142  		t.Fatal("remove: wrong address", addr)
   143  	}
   144  
   145  	// Check what was written to the file
   146  	tempFile = loadTestDatabase()
   147  	testDb, err := unmarshallCustomNames(tempFile, nil, types.Custom, &map[base.Address]types.Name{})
   148  	if err != nil && !errors.Is(err, io.EOF) {
   149  		t.Fatal("remove: unmarshallCustomNames:", err)
   150  	}
   151  	if _, ok := testDb[addr]; ok {
   152  		t.Fatal("record was removed, but it is still present")
   153  	}
   154  }
   155  
   156  func setIfExists(output *os.File, name *types.Name) (result *types.Name, err error) {
   157  	if _, ok := customNames[name.Address]; !ok {
   158  		return nil, fmt.Errorf("no custom name for address %s", name.Address.Hex())
   159  	}
   160  
   161  	name.IsCustom = true
   162  	customNamesMutex.Lock()
   163  	defer customNamesMutex.Unlock()
   164  	customNames[name.Address] = *name
   165  	return name, writeCustomNames(output)
   166  }
   167  
   168  func removeIfExists(output *os.File, address base.Address) (name *types.Name, err error) {
   169  	found, ok := customNames[address]
   170  	if !ok {
   171  		return nil, fmt.Errorf("no custom name for address %s", address.Hex())
   172  	}
   173  	customNamesMutex.Lock()
   174  	defer customNamesMutex.Unlock()
   175  
   176  	delete(customNames, address)
   177  	return &found, writeCustomNames(output)
   178  }