diff --git a/cop/collection.go b/cop/collection.go index 8a4c980..4f806c5 100644 --- a/cop/collection.go +++ b/cop/collection.go @@ -17,8 +17,8 @@ import ( "gitea.mmo.to/ppForge/ppforge/protocol" ) -// globalCOP is the global variable holding the protocol collections -var globalCOP ProtocolCollectionList +// GlobalCOP is the global variable holding the protocol collections, +var GlobalCOP *ProtocolCollectionList = &ProtocolCollectionList{[]COP{}} // ProtocolCollectionList is a list of all databases, with the most simple interface type ProtocolCollectionList struct { @@ -32,7 +32,7 @@ func (pcl *ProtocolCollectionList) WriteCache() error { if err != nil { return err } - err = os.WriteFile(path.Join(globals.CollectionOfProtocolsDir, globals.COPCacheFileName), data, fs.ModeAppend) + err = os.WriteFile(path.Join(globals.CollectionOfProtocolsDir, globals.COPCacheFileName), data, 0644) return err } @@ -57,19 +57,30 @@ type ProtocolCollectionEntry struct { // Init initializes the databases, opens the default one and checks for others if available func init() { - // initialize main list - globalCOP := ProtocolCollectionList{[]COP{}} + Init() +} + +// Init the global COP +func Init() { // initialize default db fdb := FileCOP{COP{map[string]ProtocolCollectionEntry{}, false}, globals.CollectionOfProtocolsDir} - fdb.Open(globals.CollectionOfProtocolsDir) - fdb.Sync() - globalCOP.PCs = append(globalCOP.PCs, fdb.COP) - log.Printf("Amount of databases available %d", len(globalCOP.PCs)) + err := fdb.Open(globals.CollectionOfProtocolsDir) + if err != nil { + log.Printf("Error opening global COP dir: %v", err) + return + } + err = fdb.Sync() + if err != nil { + log.Printf("Error on initial syncing of the global COP dir: %v", err) + return + } + GlobalCOP.PCs = append(GlobalCOP.PCs, fdb.COP) + log.Printf("Amount of databases available %d", len(GlobalCOP.PCs)) } // GetCOP returns the global collection of Protocols -func GetCOP() ProtocolCollectionList { - return globalCOP +func GetCOP() *ProtocolCollectionList { + return GlobalCOP } // COP represents a Collection of Protocols @@ -102,14 +113,26 @@ type FileCOPFromGitRemote struct { gitRepo git.Repository } +// NewFileCOP returns a new FileCOP instance from a given path +func NewFileCOP(path string) (*FileCOP, error) { + fCOP := &FileCOP{} + err := fCOP.Open(path) + if err != nil { + log.Printf("Error opening file COP at %s: %v", path, err) + return nil, err + } + err = fCOP.Sync() + return fCOP, err +} + // Open the database func (fd *FileCOP) Open(path string) error { fileinfo, err := os.Stat(path) if err == os.ErrNotExist { return err } - if !fileinfo.IsDir() { - return fmt.Errorf("Path %s is not a directory", path) + if fileinfo == nil || !fileinfo.IsDir() { + return fmt.Errorf("Path %s is not a directory or does not exist", path) } fd.Path = path fd.closed = false diff --git a/cop/collection_test.go b/cop/collection_test.go index fadfea7..1e45973 100644 --- a/cop/collection_test.go +++ b/cop/collection_test.go @@ -1,40 +1,93 @@ -package cop +package cop_test import ( + "errors" "fmt" "os" + "os/user" "path" + "runtime" + "strings" "testing" + + "gitea.mmo.to/ppForge/ppforge/cop" + "gitea.mmo.to/ppForge/ppforge/globals" ) +func getCurrentDir() string { + _, filename, _, _ := runtime.Caller(0) + return path.Dir(filename) +} + +func getRepoDir(start string) (string, error) { + var repoPath string + entries, err := os.ReadDir(start) + for _, v := range entries { + if strings.HasSuffix(v.Name(), ".git") { + repoPath = start + } + } + if repoPath == "" { + return getRepoDir(path.Dir(start)) + } + return repoPath, err +} + +func setupSuite(t *testing.T) func(t *testing.T) { + // setup + // setup testing home dir + repo, err := getRepoDir(getCurrentDir()) + if err != nil { + t.Error(err) + } + testUserHome := path.Join(repo, "test", "home") + globals.ConfigDirectoryList = []string{testUserHome, ".config", "ppforge"} + globals.ConfigDirectory = path.Join(globals.ConfigDirectoryList...) + globals.CollectionOfProtocolsDir = path.Join(globals.ConfigDirectory, "cop") + + globals.MockUserCurrent = func() (*user.User, error) { + mu := user.User{} + mu.HomeDir = testUserHome + return &mu, nil + } + + // teardown + return func(t *testing.T) { + globals.MockUserCurrent = user.Current + } +} + func TestOpen(t *testing.T) { - fcop := FileCOP{} - wd, err := os.Getwd() + td := setupSuite(t) + defer td(t) + + fcop := cop.FileCOP{} + wd, err := getRepoDir(getCurrentDir()) if err != nil { fmt.Printf("Os error: %s", err) t.Fail() } - fcop.Open(path.Join(wd, "..", "test", "cop")) + fcop.Open(path.Join(wd, "test", "cop")) l, err := fcop.Protocols() if err != nil { t.Fail() } - for k, v := range fcop.protocols { - fmt.Printf("%s->%s\n", k, v.Path) - } for _, pce := range l { fmt.Printf("%s//%s\n", pce.Path, pce.Protocol.Name) } } func TestClosed(t *testing.T) { - fcop := FileCOP{} - wd, err := os.Getwd() + td := setupSuite(t) + defer td(t) + + fcop := cop.FileCOP{} + wd, err := getRepoDir(getCurrentDir()) if err != nil { fmt.Printf("Os error: %s", err) t.Fail() } - fcop.Open(path.Join(wd, "..", "test", "cop")) + fcop.Open(path.Join(wd, "test", "cop")) fcop.Close() l, err := fcop.Protocols() if err == nil || l != nil { @@ -57,3 +110,53 @@ func TestClosed(t *testing.T) { t.Fail() } } + +func TestGlobalCOP(t *testing.T) { + td := setupSuite(t) + defer td(t) + cop.Init() + gcop := cop.GlobalCOP + pcs := gcop.PCs + fmt.Printf("Length of all Protocol Collections: %d\n", len(pcs)) + if len(pcs) != 1 { + fmt.Println("Length != 1") + t.Fail() + } + wd, _ := getRepoDir(getCurrentDir()) + fcop, err := cop.NewFileCOP(path.Join(wd, "test", "cop")) + if err != nil { + fmt.Println("Error on loading new FileCOP", err) + t.Fail() + } + gcop.PCs = append(gcop.PCs, fcop.COP) + + fmt.Printf("Length of all Protocol Collections: %d\n", len(gcop.PCs)) + if len(gcop.PCs) != 2 { + fmt.Println("Amount of COPs is not 2") + t.Fail() + } +} + +func TestCOPCache(t *testing.T) { + td := setupSuite(t) + defer td(t) + + gcop := cop.GlobalCOP + err := gcop.WriteCache() + if err != nil { + fmt.Println("Writing the cache file failed") + t.Fail() + } + fpath := path.Join(globals.CollectionOfProtocolsDir, globals.COPCacheFileName) + if _, staterr := os.Stat(fpath); errors.Is(staterr, os.ErrNotExist) { + fmt.Println("File not existing ", fpath) + t.Fail() + } + + err = gcop.ReadCache() + if err != nil { + fmt.Println("Reading the cache file failed") + t.Fail() + } + +} diff --git a/globals/globals.go b/globals/globals.go index 65e49d9..bd5c576 100644 --- a/globals/globals.go +++ b/globals/globals.go @@ -1,5 +1,7 @@ package globals +import "os/user" + // Global variables, Mocks, etc. // This package shall not have any dependency towards the application itself! // [impl->dsn~properly-defined-globals~1>>utest] @@ -15,5 +17,9 @@ var ConfigDirectory string // CollectionOfProtocolsDir is the default directory for protocol collections var CollectionOfProtocolsDir string -// COPCacheFileName +// COPCacheFileName is the filename for the cache var COPCacheFileName string = "cop-cache.json" + +// Global Mockings + +var MockUserCurrent = user.Current diff --git a/globals/globals.linux.go b/globals/globals.linux.go index 6c4065f..1e02a95 100644 --- a/globals/globals.linux.go +++ b/globals/globals.linux.go @@ -4,12 +4,11 @@ package globals // This package shall not have any dependency towards the application itself! import ( "log" - "os/user" "path" ) func init() { - user, err := user.Current() + user, err := MockUserCurrent() if err != nil { log.Printf("Current user not obtainable: %s", err) log.Fatal("Impossible to open default database") diff --git a/globals/globals.windows.go b/globals/globals.windows.go index cfd6a80..f8a127b 100644 --- a/globals/globals.windows.go +++ b/globals/globals.windows.go @@ -3,14 +3,20 @@ package globals // Global variables, Mocks, etc. // This package shall not have any dependency towards the application itself! import ( - "os/user" + "log" "path" ) func init() { + user, err := MockUserCurrent() + if err != nil { + log.Printf("Current user not obtainable: %s", err) + log.Fatal("Impossible to open default database") + } + // ConfigDirectoryList Configuration directory list Windows TODO - var ConfigDirectoryList []string = []string{user.HomeDir, TODO!!!} + ConfigDirectoryList = []string{user.HomeDir /*TODO!!!*/} // ConfigDirectory Configuration directory string Windows - var ConfigDirectory string = path.Join(ConfigDirectoryList...) + ConfigDirectory = path.Join(ConfigDirectoryList...) } diff --git a/go.mod b/go.mod index 8eae54b..9c25be1 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,7 @@ require ( github.com/go-text/typesetting v0.0.0-20230905121921-abdbcca6e0eb // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/mock v1.6.0 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect diff --git a/go.sum b/go.sum index 0ac6bf1..d1eccb0 100644 --- a/go.sum +++ b/go.sum @@ -140,6 +140,8 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -598,6 +600,7 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= diff --git a/test/home/.config/ppforge/cop/blabla.protocoljson b/test/home/.config/ppforge/cop/blabla.protocoljson new file mode 100644 index 0000000..022ae3a --- /dev/null +++ b/test/home/.config/ppforge/cop/blabla.protocoljson @@ -0,0 +1,34 @@ +{ + "Metadata": { + "Revision": 2, + "Name": "blabla", + "Version": "", + "TCPIPLayer": 0, + "ExtensionTo": "", + "Description": "", + "RequiredJSFunctions": null, + "LowerLayerIdentification": null + }, + "Structure": [ + { + "Name": "asdfasdf", + "Desc": "", + "Regex": "", + "Size": 8, + "SubFields": null, + "Optional": false, + "Payload": false + }, + { + "Name": "asdfasdfasdf", + "Desc": "test", + "Regex": "", + "Size": 24, + "SubFields": null, + "Optional": false, + "Payload": false + } + ], + "DefaultValues": null, + "JavaScript": "" +} \ No newline at end of file diff --git a/test/home/.config/ppforge/cop/blah.protocoljson b/test/home/.config/ppforge/cop/blah.protocoljson new file mode 100644 index 0000000..13a71f0 --- /dev/null +++ b/test/home/.config/ppforge/cop/blah.protocoljson @@ -0,0 +1,61 @@ +{ + "Metadata": { + "Revision": 1, + "Name": "blah", + "Version": "", + "TCPIPLayer": 0, + "ExtensionTo": "", + "Description": "", + "RequiredJSFunctions": null, + "LowerLayerIdentification": null + }, + "Structure": [ + { + "Name": "test", + "Desc": "", + "Regex": "", + "Size": 32, + "SubFields": null, + "Optional": false, + "Payload": false + }, + { + "Name": "", + "Desc": "", + "Regex": "", + "Size": 32, + "SubFields": null, + "Optional": false, + "Payload": false + }, + { + "Name": "", + "Desc": "", + "Regex": "", + "Size": 8, + "SubFields": null, + "Optional": false, + "Payload": false + }, + { + "Name": "", + "Desc": "", + "Regex": "", + "Size": 4, + "SubFields": null, + "Optional": false, + "Payload": false + }, + { + "Name": "", + "Desc": "", + "Regex": "", + "Size": 20, + "SubFields": null, + "Optional": false, + "Payload": false + } + ], + "DefaultValues": null, + "JavaScript": "" +} \ No newline at end of file diff --git a/test/home/.config/ppforge/cop/test.protocoljson b/test/home/.config/ppforge/cop/test.protocoljson new file mode 100644 index 0000000..06c9f73 --- /dev/null +++ b/test/home/.config/ppforge/cop/test.protocoljson @@ -0,0 +1,25 @@ +{ + "Metadata": { + "Revision": 1, + "Name": "test", + "Version": "", + "TCPIPLayer": 0, + "ExtensionTo": "", + "Description": "test", + "RequiredJSFunctions": null, + "LowerLayerIdentification": null + }, + "Structure": [ + { + "Name": "test", + "Desc": "test", + "Regex": "", + "Size": 128, + "SubFields": null, + "Optional": false, + "Payload": false + } + ], + "DefaultValues": null, + "JavaScript": "" +} \ No newline at end of file diff --git a/test/home/.config/ppforge/cop/testprotocolempty.protocoljson b/test/home/.config/ppforge/cop/testprotocolempty.protocoljson new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/test/home/.config/ppforge/cop/testprotocolempty.protocoljson @@ -0,0 +1 @@ +{} \ No newline at end of file