aboutsummaryrefslogtreecommitdiff
path: root/config
diff options
context:
space:
mode:
authorJulien Dessaux2021-11-17 10:13:06 +0100
committerJulien Dessaux2021-11-17 10:13:06 +0100
commitc3263c03776401ad1263a9fb8f5a44a8ed44d61b (patch)
tree7dac91753cb4428ede2ba72fb09eca9ba6c2daab /config
parentUpdated dependencies (diff)
downloadshell-game-launcher-c3263c03776401ad1263a9fb8f5a44a8ed44d61b.tar.gz
shell-game-launcher-c3263c03776401ad1263a9fb8f5a44a8ed44d61b.tar.bz2
shell-game-launcher-c3263c03776401ad1263a9fb8f5a44a8ed44d61b.zip
Refactored package structure
Diffstat (limited to 'config')
-rw-r--r--config/action.go54
-rw-r--r--config/action_test.go105
-rw-r--r--config/app.go54
-rw-r--r--config/app_test.go90
-rw-r--r--config/command.go32
-rw-r--r--config/command_test.go51
-rw-r--r--config/config.go64
-rw-r--r--config/config_test.go221
-rw-r--r--config/game.go63
-rw-r--r--config/game_test.go107
-rw-r--r--config/menu.go113
-rw-r--r--config/menu_test.go71
-rw-r--r--config/test_data/duplicate_game.yaml30
-rw-r--r--config/test_data/duplicate_menu.yaml28
-rw-r--r--config/test_data/fake_nethack_directory/.keep0
-rw-r--r--config/test_data/invalid_app.yaml11
-rw-r--r--config/test_data/invalid_game.yaml21
-rw-r--r--config/test_data/invalid_menus.yaml19
-rw-r--r--config/test_data/invalid_yaml1
-rw-r--r--config/test_data/minimal.yaml18
-rw-r--r--config/test_data/no_anonymous_menu.yaml18
-rw-r--r--config/test_data/no_logged_in_menu.yaml18
-rw-r--r--config/test_data/non_existant_chopts.yaml18
-rw-r--r--config/test_data/non_existant_game.yaml18
-rw-r--r--config/test_data/non_existant_menu.yaml18
-rw-r--r--config/test_data/not_enough_menus.yaml13
-rw-r--r--config/test_data/unreachable_game.yaml25
-rw-r--r--config/test_data/unreachable_menu.yaml23
28 files changed, 0 insertions, 1304 deletions
diff --git a/config/action.go b/config/action.go
deleted file mode 100644
index c63308e..0000000
--- a/config/action.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package config
-
-import (
- "strings"
-
- "github.com/pkg/errors"
-)
-
-func validateAction(action string) error {
- tokens := strings.Split(action, " ")
- switch tokens[0] {
- case "chmail":
- if len(tokens) != 1 {
- return errors.New("chmail action takes no arguments")
- }
- case "login":
- if len(tokens) != 1 {
- return errors.New("login action takes no arguments")
- }
- case "menu":
- if len(tokens) != 2 {
- return errors.New("menu action takes exactly one argument")
- }
- // menu existence is tested in global config
- case "passwd":
- if len(tokens) != 1 {
- return errors.New("passwd action takes no arguments")
- }
- case "play":
- if len(tokens) != 2 {
- return errors.New("play action takes exactly one argument")
- }
- // game existence is tested in global config
- case "register":
- if len(tokens) != 1 {
- return errors.New("register action takes no arguments")
- }
- case "replay":
- if len(tokens) != 1 {
- return errors.New("replay action takes no arguments")
- }
- case "watch":
- if len(tokens) != 1 {
- return errors.New("watch action takes no arguments")
- }
- case "quit":
- if len(tokens) != 1 {
- return errors.New("quit action takes no arguments")
- }
- default:
- return errors.New("Invalid action : " + tokens[0])
- }
- return nil
-}
diff --git a/config/action_test.go b/config/action_test.go
deleted file mode 100644
index dbc6ae3..0000000
--- a/config/action_test.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package config
-
-import "testing"
-
-func TestActionValidate(t *testing.T) {
- // Empty action
- menuEntry := MenuEntry{Key: "l", Label: "label", Action: ""}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("An action cannot be empty")
- }
- // Invalid action
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "invalid"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("An action must be valid")
- }
- // chmail
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "chmail a"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("chmail action does not take arguments")
- }
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "chmail"}
- if err := menuEntry.validate(); err != nil {
- t.Fatalf("chmail action without arguments is valid\nerror: +%v", err)
- }
- // login
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "login a"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("login action does not take arguments")
- }
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "login"}
- if err := menuEntry.validate(); err != nil {
- t.Fatalf("login action without arguments is valid\nerror: +%v", err)
- }
- // menu
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "menu"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("menu action takes exactly one argument")
- }
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "menu test plop"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("menu action takes exactly one argument")
- }
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "menu test"}
- if err := menuEntry.validate(); err != nil {
- t.Fatalf("menu action with one argument is valid\nerror: +%v", err)
- }
- // passwd
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "passwd a"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("passwd action does not take arguments")
- }
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "passwd"}
- if err := menuEntry.validate(); err != nil {
- t.Fatalf("passwd action without arguments is valid\nerror: +%v", err)
- }
- // play
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "play"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("play action takes exactly one argument")
- }
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "play test plop"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("play action takes exactly one argument")
- }
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "play test"}
- if err := menuEntry.validate(); err != nil {
- t.Fatalf("play action with one argument is valid\nerror: +%v", err)
- }
- // register
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "register a"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("register action does not take arguments")
- }
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "register"}
- if err := menuEntry.validate(); err != nil {
- t.Fatalf("register action without arguments is valid\nerror: +%v", err)
- }
- // replay
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "replay a"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("replay action does not take arguments")
- }
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "replay"}
- if err := menuEntry.validate(); err != nil {
- t.Fatalf("replay action without arguments is valid\nerror: +%v", err)
- }
- // watch
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "watch a"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("watch action does not take arguments")
- }
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "watch"}
- if err := menuEntry.validate(); err != nil {
- t.Fatalf("watch action without arguments is valid\nerror: +%v", err)
- }
- // quit
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "quit a"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("quit action does not take arguments")
- }
- menuEntry = MenuEntry{Key: "l", Label: "label", Action: "quit"}
- if err := menuEntry.validate(); err != nil {
- t.Fatalf("quit action without arguments is valid\nerror: +%v", err)
- }
-}
diff --git a/config/app.go b/config/app.go
deleted file mode 100644
index 2eefb98..0000000
--- a/config/app.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package config
-
-import (
- "os"
-
- "github.com/pkg/errors"
- "golang.org/x/sys/unix"
-)
-
-// App struct contains the configuration for this application
-type App struct {
- // WorkingDirectory is the program working directory where the user data, save files and scores are stored
- WorkingDirectory string `yaml:"WorkingDirectory"`
- // MaxUsers is the maximum amount of registered users to allow
- MaxUsers int `yaml:"MaxUsers"`
- // AllowRegistration allows registration of new users
- AllowRegistration bool `yaml:"AllowRegistration"`
- // MaxNickLen Maximum length for a nickname
- MaxNickLen int `yaml:"MaxNickLen"`
- // MenuMaxIdleTime is the maximum number of seconds a user can be idle on the menu before the program exits
- MenuMaxIdleTime int `yaml:"MenuMaxIdleTime"`
- // PostLoginCommands is the list of commands to execute upon login, like creating save directories for games
- PostLoginCommands []string `yaml:"PostLoginCommands"`
-}
-
-func (a *App) validate() error {
- // WorkingDirectory
- if err := os.MkdirAll(a.WorkingDirectory, 0700); err != nil {
- return errors.Wrapf(err, "Invalid WorkingDirectory : %s", a.WorkingDirectory)
- }
- if err := unix.Access(a.WorkingDirectory, unix.W_OK|unix.R_OK|unix.X_OK); err != nil {
- return errors.Wrapf(err, "invalid WorkingDirectory : %s", a.WorkingDirectory)
- }
- // MaxUsers
- if a.MaxUsers <= 0 {
- return errors.New("MaxUsers must be a positive integer")
- }
- // AllowRegistration is just a bool, nothing to validate
- // MaxNickLen
- if a.MaxNickLen <= 0 {
- return errors.New("MaxNickLen must be a positive integer")
- }
- // MenuMaxIdleTime
- if a.MenuMaxIdleTime <= 0 {
- return errors.New("MenuMaxIdleTime must be a positive integer")
- }
- // PostLoginCommands
- for i := 0; i < len(a.PostLoginCommands); i++ {
- if err := validateCommand(a.PostLoginCommands[i]); err != nil {
- return errors.Wrap(err, "Failed to validate PostLoginCommands")
- }
- }
- return nil
-}
diff --git a/config/app_test.go b/config/app_test.go
deleted file mode 100644
index 5a6cf41..0000000
--- a/config/app_test.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package config
-
-import (
- "os"
- "testing"
-)
-
-func TestAppvalidate(t *testing.T) {
- // WorkingDirectory
- t.Cleanup(func() { os.RemoveAll("no_permission/") })
- if err := os.Mkdir("no_permission/", 0000); err != nil {
- t.Fatal("Could not create test directory")
- }
- app := App{WorkingDirectory: "no_permission/cannot_work"}
- if err := app.validate(); err == nil {
- t.Fatal("no_permission/cannot_wor/k should not be a valid working directory")
- }
- app = App{WorkingDirectory: "no_permission/"}
- if err := app.validate(); err == nil {
- t.Fatal("no_permission/ should not be a valid working directory")
- }
-
- // MaxUsers
- t.Cleanup(func() { os.RemoveAll("var/") })
- app = App{
- WorkingDirectory: "var/",
- MaxUsers: 0,
- }
- if err := app.validate(); err == nil {
- t.Fatal("Negative MaxUsers should not be valid")
- }
-
- // AllowRegistration is just a bool, nothing to test
-
- // MaxNickLen
- t.Cleanup(func() { os.RemoveAll("var/") })
- app = App{
- WorkingDirectory: "var/",
- MaxUsers: 1,
- MaxNickLen: 0,
- }
- if err := app.validate(); err == nil {
- t.Fatal("Negative or zero MaxNickLen should not be valid.")
- }
-
- //MenuMaxIdleTime
- t.Cleanup(func() { os.RemoveAll("var/") })
- app = App{
- WorkingDirectory: "var/",
- MaxUsers: 512,
- MaxNickLen: 15,
- MenuMaxIdleTime: 0,
- }
- if err := app.validate(); err == nil {
- t.Fatal("Negative or zero MenuMaxIdleTime should not be valid.")
- }
-
- //PostLoginCommands are mostly tested from command_test.go
- app = App{
- WorkingDirectory: "var/",
- MaxUsers: 512,
- MaxNickLen: 15,
- MenuMaxIdleTime: 60,
- }
- if err := app.validate(); err != nil {
- t.Fatal("Empty PostLoginCommands list should be valid")
- }
- app = App{
- WorkingDirectory: "var/",
- MaxUsers: 512,
- MaxNickLen: 15,
- MenuMaxIdleTime: 60,
- PostLoginCommands: []string{"invalid"},
- }
- if err := app.validate(); err == nil {
- t.Fatal("Invalid command in PostLoginCommands should not be valid")
- }
-
- // A valid App
- app = App{
- WorkingDirectory: "var/",
- MaxUsers: 512,
- MaxNickLen: 15,
- MenuMaxIdleTime: 60,
- PostLoginCommands: []string{"wait"},
- }
- if err := app.validate(); err != nil {
- t.Fatal("A valid app should pass")
- }
-}
diff --git a/config/command.go b/config/command.go
deleted file mode 100644
index 34142cd..0000000
--- a/config/command.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package config
-
-import (
- "strings"
-
- "github.com/pkg/errors"
-)
-
-func validateCommand(cmd string) error {
- tokens := strings.Split(cmd, " ")
- switch tokens[0] {
- case "cp":
- if len(tokens) != 3 {
- return errors.New("cp command takes exactly two arguments")
- }
- case "exec":
- if len(tokens) <= 1 {
- return errors.New("exec command needs arguments")
- }
- case "mkdir":
- if len(tokens) != 2 {
- return errors.New("mkdir command takes exactly one argument")
- }
- case "wait":
- if len(tokens) != 1 {
- return errors.New("wait command takes no arguments")
- }
- default:
- return errors.New("Invalid command : " + tokens[0])
- }
- return nil
-}
diff --git a/config/command_test.go b/config/command_test.go
deleted file mode 100644
index 7e07956..0000000
--- a/config/command_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package config
-
-import "testing"
-
-func TestCommandValidate(t *testing.T) {
- // Empty command
- if err := validateCommand(""); err == nil {
- t.Fatal("An command cannot be empty")
- }
- // invalid command
- if err := validateCommand("invalid"); err == nil {
- t.Fatal("An command cannot be empty")
- }
- // cp
- if err := validateCommand("cp"); err == nil {
- t.Fatal("cp command needs arguments")
- }
- if err := validateCommand("cp test"); err == nil {
- t.Fatal("cp command needs exactly 2 arguments")
- }
- if err := validateCommand("cp test test test"); err == nil {
- t.Fatal("cp command needs exactly 2 arguments")
- }
- if err := validateCommand("exec test test"); err != nil {
- t.Fatal("valid exec command should be accepted")
- }
- // exec
- if err := validateCommand("exec"); err == nil {
- t.Fatal("exec command needs arguments")
- }
- if err := validateCommand("exec test"); err != nil {
- t.Fatal("valid exec command should be accepted")
- }
- // mkdir
- if err := validateCommand("mkdir"); err == nil {
- t.Fatal("mkdir command needs exactly 1 argument")
- }
- if err := validateCommand("mkdir testtest "); err == nil {
- t.Fatal("mkdir command needs exactly 1 argument")
- }
- if err := validateCommand("mkdir test"); err != nil {
- t.Fatal("valid mkdir command should be accepted")
- }
- // wait
- if err := validateCommand("wait test"); err == nil {
- t.Fatal("wait command needs no arguments")
- }
- if err := validateCommand("wait"); err != nil {
- t.Fatal("valid wait command should be accepted")
- }
-}
diff --git a/config/config.go b/config/config.go
deleted file mode 100644
index b68a26a..0000000
--- a/config/config.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package config
-
-import (
- "os"
-
- "github.com/pkg/errors"
- "gopkg.in/yaml.v3"
-)
-
-type Config struct {
- // AppConfig is the application level configuration entries
- App App `yaml:"App"`
- // Menus is the list of menus. The first one is the default menu for an anonymous user, the second one is the default menu for an authenticated user
- Menus map[string]Menu `yaml:"Menus"`
- // Games is the list of games.
- Games map[string]Game `yaml:"Games"`
-}
-
-func (c *Config) validate() error {
- // App
- if err := c.App.validate(); err != nil {
- return err
- }
- // Menus
- if len(c.Menus) < 2 {
- return errors.New("A valid configuration needs at least two menu entries named anonymous and logged_in")
- }
- for k, v := range c.Menus {
- if err := v.validate(k); err != nil {
- return err
- }
- }
- // Games
- for k, v := range c.Games {
- if err := v.validate(k); err != nil {
- return err
- }
- }
- return nil
-}
-
-// LoadFile loads the c from a given file
-func LoadFile(path string) (*Config, error) {
- var c *Config
- f, errOpen := os.Open(path)
- if errOpen != nil {
- return nil, errors.Wrapf(errOpen, "Failed to open configuration file %s", path)
- }
- defer f.Close()
- decoder := yaml.NewDecoder(f)
- if err := decoder.Decode(&c); err != nil {
- return nil, errors.Wrap(err, "Failed to decode configuration file")
- }
- if err := c.validate(); err != nil {
- return nil, errors.Wrap(err, "Failed to validate configuration")
- }
- // If all looks good we validate menu consistency
- for _, v := range c.Menus {
- if err := v.validateConsistency(c); err != nil {
- return nil, errors.Wrap(err, "Failed menu consistency checks")
- }
- }
- return c, nil
-}
diff --git a/config/config_test.go b/config/config_test.go
deleted file mode 100644
index dfa8237..0000000
--- a/config/config_test.go
+++ /dev/null
@@ -1,221 +0,0 @@
-package config
-
-import (
- "os"
- "reflect"
- "testing"
-)
-
-func TestLoadFile(t *testing.T) {
- // Non existant file
- _, err := LoadFile("test_data/non-existant")
- if err == nil {
- t.Fatal("non-existant config file failed without error")
- }
-
- // Invalid yaml file
- _, err = LoadFile("test_data/invalid_yaml")
- if err == nil {
- t.Fatal("invalid_yaml config file failed without error")
- }
-
- // Minimal yaml file
- want := Config{
- App: App{
- WorkingDirectory: "var/",
- MaxUsers: 1,
- AllowRegistration: true,
- MaxNickLen: 15,
- MenuMaxIdleTime: 600,
- },
- Menus: map[string]Menu{
- "anonymous": Menu{
- MenuEntries: []MenuEntry{
- MenuEntry{
- Key: "q",
- Label: "quit",
- Action: "quit",
- },
- },
- },
- "logged_in": Menu{
- MenuEntries: []MenuEntry{
- MenuEntry{
- Key: "q",
- Label: "quit",
- Action: "quit",
- },
- },
- },
- },
- }
- config, err := LoadFile("test_data/minimal.yaml")
- if err != nil {
- t.Fatalf("minimal example failed with error : %v", err)
- }
- if config != nil && !reflect.DeepEqual(want, *config) {
- t.Fatalf("minimal example failed:\nwant:%+v\ngot: %+v", want, *config)
- }
- t.Cleanup(func() { os.RemoveAll("var/") })
- // Invalid App
- if _, err := LoadFile("test_data/invalid_app.yaml"); err == nil {
- t.Fatal("Invalid App entry should fail to load")
- }
- // Not enough menus
- if _, err := LoadFile("test_data/not_enough_menus.yaml"); err == nil {
- t.Fatal("not enough menu entries should fail to load")
- }
- // Invalid Menus
- if _, err := LoadFile("test_data/invalid_menus.yaml"); err == nil {
- t.Fatal("Invalid menu entry should fail to load")
- }
- // no anonymous Menu
- if _, err := LoadFile("test_data/no_anonymous_menu.yaml"); err == nil {
- t.Fatal("Invalid menu entry should fail to load")
- }
- // no logged_in Menu
- if _, err := LoadFile("test_data/no_logged_in_menu.yaml"); err == nil {
- t.Fatal("Invalid menu entry should fail to load")
- }
- // duplicate menu
- if _, err := LoadFile("test_data/duplicate_menu.yaml"); err == nil {
- t.Fatal("duplicate menu should fail to load")
- }
- // non existant menu action referenced
- if _, err := LoadFile("test_data/non_existant_menu.yaml"); err == nil {
- t.Fatal("menu entry referencing a non existant menu should fail to load")
- }
- // non existant game referenced in play action
- if _, err := LoadFile("test_data/non_existant_game.yaml"); err == nil {
- t.Fatal("menu entry referencing a non existant play action should fail to load")
- }
- // unreachable menu
- if _, err := LoadFile("test_data/unreachable_menu.yaml"); err == nil {
- t.Fatal("unreachable menu should fail to load")
- }
- // invalid game
- if _, err := LoadFile("test_data/invalid_game.yaml"); err == nil {
- t.Fatal("invalid game should fail to load")
- }
- // unreachable game
- if _, err := LoadFile("test_data/unreachable_game.yaml"); err == nil {
- t.Fatal("unreachable game should fail to load")
- }
- // duplicate game
- if _, err := LoadFile("test_data/duplicate_game.yaml"); err == nil {
- t.Fatal("unreachable game should fail to load")
- }
-
- // Complexe example
- want = Config{
- App: App{
- WorkingDirectory: "var/",
- MaxUsers: 512,
- AllowRegistration: true,
- MaxNickLen: 15,
- MenuMaxIdleTime: 600,
- PostLoginCommands: []string{
- "mkdir %w/userdata/%u",
- "mkdir %w/userdata/%u/dumplog",
- "mkdir %w/userdata/%u/ttyrec",
- },
- },
- Menus: map[string]Menu{
- "anonymous": Menu{
- Banner: "Shell Game Launcher - Anonymous access%n======================================",
- MenuEntries: []MenuEntry{
- MenuEntry{
- Key: "l",
- Label: "login",
- Action: "login",
- },
- MenuEntry{
- Key: "r",
- Label: "register",
- Action: "register",
- },
- MenuEntry{
- Key: "w",
- Label: "watch",
- Action: "watch_menu",
- },
- MenuEntry{
- Key: "q",
- Label: "quit",
- Action: "quit",
- },
- },
- },
- "logged_in": Menu{
- Banner: "Shell Game Launcher%n===================",
- MenuEntries: []MenuEntry{
- MenuEntry{
- Key: "p",
- Label: "play Nethack 3.7",
- Action: "play nethack3.7",
- },
- MenuEntry{
- Key: "o",
- Label: "edit game options",
- Action: "menu options",
- },
- MenuEntry{
- Key: "w",
- Label: "watch",
- Action: "watch",
- },
- MenuEntry{
- Key: "r",
- Label: "replay",
- Action: "replay",
- },
- MenuEntry{
- Key: "c",
- Label: "change password",
- Action: "passwd",
- },
- MenuEntry{
- Key: "m",
- Label: "change email",
- Action: "chmail",
- },
- MenuEntry{
- Key: "q",
- Label: "quit",
- Action: "quit",
- },
- },
- },
- "options": Menu{
- Banner: "Options%n=======",
- MenuEntries: []MenuEntry{
- MenuEntry{
- Key: "z",
- Label: "back",
- Action: "menu logged_in",
- },
- },
- },
- },
- Games: map[string]Game{
- "nethack3.7": Game{
- ChrootPath: "test_data/fake_nethack_directory",
- FileMode: "0666",
- Commands: []string{
- "cp /games/var/save/%u%n.gz /games/var/save/%u%n.gz.bak",
- "exec /games/nethack -u %n",
- },
- Env: map[string]string{
- "NETHACKOPTIONS": "@%ruserdata/%n/%n.nhrc",
- },
- },
- },
- }
- config, err = LoadFile("../example/complete.yaml")
- if err != nil {
- t.Fatalf("complete example failed with error : %v", err)
- }
- if config != nil && !reflect.DeepEqual(want, *config) {
- t.Fatalf("complete example failed:\nwant:%+v\ngot: %+v", want, *config)
- }
-}
diff --git a/config/game.go b/config/game.go
deleted file mode 100644
index b5f4d39..0000000
--- a/config/game.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package config
-
-import (
- "regexp"
-
- "github.com/pkg/errors"
- "golang.org/x/sys/unix"
-)
-
-var reValidGameName = regexp.MustCompile(`^[\w\._]+$`)
-var reValidFileMode = regexp.MustCompile(`^0[\d]{3}$`)
-var reSpace = regexp.MustCompile(`^\s$`)
-
-// Game struct containers the configuration for a game
-type Game struct {
- // ChrootPath is the chroot path for the game
- ChrootPath string `yaml:"ChrootPath"`
- // FileMode is the file mode to use when copying files
- FileMode string `yaml:"FileMode"`
- // Commands is the command list
- Commands []string `yaml:"Commands"`
- // Env is the environment in which to exec the commands
- Env map[string]string `yaml:"Env"`
-}
-
-func (g *Game) validate(name string) error {
- // Game name
- if ok := reValidGameName.MatchString(name); !ok {
- return errors.New("Invalid Game name, must match regex `^[\\w\\._]+$` : " + name)
- }
- // ChrootPath TODO
- if err := unix.Access(g.ChrootPath, unix.R_OK|unix.X_OK); err != nil {
- return errors.Wrapf(err, "Invalid ChrootPath : %s", g.ChrootPath)
- }
- // FileMode
- if ok := reValidFileMode.MatchString(g.FileMode); !ok {
- return errors.New("Invalid File Mode, must match regex `^0[\\d]{3}$` : " + name)
- }
- // Commands
- if len(g.Commands) == 0 {
- return errors.New("Invalid game " + name + " has no commands")
- }
- for i := 0; i < len(g.Commands); i++ {
- if err := validateCommand(g.Commands[i]); err != nil {
- return errors.Wrapf(err, "Failed to validate Commands for game %s", name)
- }
- }
- // Env
- for k, _ := range g.Env {
- for _, c := range k {
- switch c {
- case '=':
- return errors.New("Environment variable key must not contain equal sign")
- case '\000':
- return errors.New("Environment variable key must not contain null character")
- }
- if reSpace.MatchString(string(c)) {
- return errors.New("Environment variable key must not contain spaces")
- }
- }
- }
- return nil
-}
diff --git a/config/game_test.go b/config/game_test.go
deleted file mode 100644
index b3bf107..0000000
--- a/config/game_test.go
+++ /dev/null
@@ -1,107 +0,0 @@
-package config
-
-import "testing"
-
-func TestGameValidate(t *testing.T) {
- // Game name
- game := Game{}
- if err := game.validate("invalid game name because of spaces"); err == nil {
- t.Fatal("game name with spaces should not be valid")
- }
- // ChrootPath
- game = Game{ChrootPath: "test_data/non_existant"}
- if err := game.validate("test"); err == nil {
- t.Fatal("non_existant ChrootPath should not be valid")
- }
- // FileMode
- game = Game{
- ChrootPath: "test_data/fake_nethack_directory",
- }
- if err := game.validate("test"); err == nil {
- t.Fatal("Invalid FileMode should not be valid")
- }
- game = Game{
- ChrootPath: "test_data/fake_nethack_directory",
- FileMode: "abcd",
- }
- if err := game.validate("test"); err == nil {
- t.Fatal("Invalid FileMode should not be valid")
- }
- game = Game{
- ChrootPath: "test_data/fake_nethack_directory",
- FileMode: "777",
- }
- if err := game.validate("test"); err == nil {
- t.Fatal("Invalid FileMode should not be valid")
- }
- // Commands are mostly tested from command_test.go
- game = Game{
- ChrootPath: "test_data/fake_nethack_directory",
- FileMode: "0777",
- }
- if err := game.validate("test"); err == nil {
- t.Fatal("Empty Commands list should not be valid")
- }
- game = Game{
- ChrootPath: "test_data/fake_nethack_directory",
- FileMode: "0777",
- Commands: []string{"invalid"},
- }
- if err := game.validate("test"); err == nil {
- t.Fatal("Invalid command in Commands should not be valid")
- }
- // Env
- game = Game{
- ChrootPath: "test_data/fake_nethack_directory",
- FileMode: "0777",
- Commands: []string{"wait"},
- }
- if err := game.validate("test"); err != nil {
- t.Fatal("Empty env list should be valid")
- }
- game = Game{
- ChrootPath: "test_data/fake_nethack_directory",
- FileMode: "0777",
- Commands: []string{"wait"},
- Env: map[string]string{
- "test invalid": "test",
- },
- }
- if err := game.validate("test"); err == nil {
- t.Fatal("Spaces in environnement variable name are invalid")
- }
- game = Game{
- ChrootPath: "test_data/fake_nethack_directory",
- FileMode: "0777",
- Commands: []string{"wait"},
- Env: map[string]string{
- "test\000invalid": "test",
- },
- }
- if err := game.validate("test"); err == nil {
- t.Fatal("null character in environnement variable name are invalid")
- }
- game = Game{
- ChrootPath: "test_data/fake_nethack_directory",
- FileMode: "0777",
- Commands: []string{"wait"},
- Env: map[string]string{
- "test=invalid": "test",
- },
- }
- if err := game.validate("test"); err == nil {
- t.Fatal("equals symbol in environnement variable name are invalid")
- }
- // Valid Game entry
- game = Game{
- ChrootPath: "test_data/fake_nethack_directory",
- FileMode: "0777",
- Commands: []string{"wait"},
- Env: map[string]string{
- "test": "test",
- },
- }
- if err := game.validate("test"); err != nil {
- t.Fatalf("Valid game entry should pass but got error %s", err)
- }
-}
diff --git a/config/menu.go b/config/menu.go
deleted file mode 100644
index 7321c7b..0000000
--- a/config/menu.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package config
-
-import (
- "regexp"
- "strings"
-
- "github.com/pkg/errors"
-)
-
-var reValidMenuName = regexp.MustCompile(`^[\w\._]+$`)
-var reValidKey = regexp.MustCompile(`^\w$`)
-
-// Menu struct describes a screen menu
-type Menu struct {
- // Banner is the banner to display before the menu
- Banner string `yaml:"Banner"`
- // Commands is the list of commands in the menu
- MenuEntries []MenuEntry `yaml:"MenuEntries"`
-}
-
-// MenuEntry struct describes a menu entry
-type MenuEntry struct {
- // Key is the key associated with the action. We need to store it as a string because of how yaml unmarshal works
- Key string `yaml:"Key"`
- // Label is the text displayed on the menu
- Label string `yaml:"Label"`
- // Action is the action executed when the menu entry is selected
- Action string `yaml:"Action"`
-}
-
-func (m *Menu) validate(name string) error {
- // validate name
- if ok := reValidMenuName.MatchString(name); !ok {
- return errors.New("Invalid menu name, must be an alphanumeric word and match regex `^[\\w\\._]+$` : " + name)
- }
- // Banner is just any string, nothing to validate
- // MenuEntries
- if len(m.MenuEntries) == 0 {
- return errors.New("A Menu needs MenuEntries to be valid")
- }
- // Duplicate detection is natively handled by the yaml parser
- for i := 0; i < len(m.MenuEntries); i++ {
- m.MenuEntries[i].validate()
- if m.MenuEntries[i].Action == "menu "+name {
- return errors.New("A menu shall not loop on itself")
- }
- }
- // Loop test
- return nil
-}
-
-func (m *Menu) validateConsistency(c *Config) error {
- // Necessary menus
- if _, ok := c.Menus["anonymous"]; !ok {
- return errors.New("No anonymous menu declared")
- }
- if _, ok := c.Menus["logged_in"]; !ok {
- return errors.New("No logged_in menu declared")
- }
- // Validate actions
- menus := map[string]bool{
- "anonymous": true,
- "logged_in": true,
- }
- playable := make(map[string]bool)
- for k, v := range c.Menus {
- for _, e := range v.MenuEntries {
- tokens := strings.Split(e.Action, " ")
- switch tokens[0] {
- case "menu":
- if _, ok := c.Menus[tokens[1]]; ok {
- menus[tokens[1]] = true
- } else {
- return errors.New("menu action " + tokens[1] + " in menu " + k + " does not exist")
- }
- case "play":
- if _, ok := c.Games[tokens[1]]; ok {
- playable[tokens[1]] = true
- } else {
- return errors.New("play action " + tokens[1] + " in menu " + k + " does not exist")
- }
- }
- }
- }
- // Check for unreachables
- for k, _ := range c.Menus {
- if _, ok := menus[k]; !ok {
- return errors.New("unreachable menu : " + k)
- }
- }
- for k, _ := range c.Games {
- if _, ok := playable[k]; !ok {
- return errors.New("unplayable game : " + k)
- }
- }
- return nil
-}
-
-func (m *MenuEntry) validate() error {
- // Key
- if ok := reValidKey.MatchString(m.Key); !ok {
- return errors.New("Invalid Key, must be exactly one alphanumeric character and match regex `^\\w$` : " + m.Key)
- }
- // Label
- if len(m.Label) <= 0 {
- return errors.New("Invalid Label, cannot be empty")
- }
- // Action
- if err := validateAction(m.Action); err != nil {
- return errors.Wrap(err, "Invalid Action in MenuEntry")
- }
- return nil
-}
diff --git a/config/menu_test.go b/config/menu_test.go
deleted file mode 100644
index e9abef1..0000000
--- a/config/menu_test.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package config
-
-import "testing"
-
-func TestMenuValidate(t *testing.T) {
- // menu name
- menu := Menu{}
- if err := menu.validate(""); err == nil {
- t.Fatal("Empty menu name is not valid")
- }
- if err := menu.validate("test test"); err == nil {
- t.Fatal("non alphanumeric menu name is not valid")
- }
- // Banner is just any string, nothing to validate
- // MenuEntries are mostly tested bellow
- menu = Menu{}
- if err := menu.validate("test"); err == nil {
- t.Fatal("A menu without menu entries should not be valid")
- }
- // loop menu
- menu = Menu{
- MenuEntries: []MenuEntry{
- MenuEntry{
- Key: "a",
- Label: "test",
- Action: "menu test",
- },
- },
- }
- if err := menu.validate("test"); err == nil {
- t.Fatal("A menu should not be able to loop on itself")
- }
- // A valid menu
- menu = Menu{
- MenuEntries: []MenuEntry{
- MenuEntry{
- Key: "a",
- Label: "test",
- Action: "quit",
- },
- },
- }
- if err := menu.validate("test"); err != nil {
- t.Fatal("A valid menu should pass")
- }
-}
-
-func TestMenuEntryValidate(t *testing.T) {
- // Key
- menuEntry := MenuEntry{}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("A Key cannot be empty")
- }
- menuEntry = MenuEntry{Key: "ab"}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("A Key should be only one character")
- }
- menuEntry = MenuEntry{Key: " "}
- if err := menuEntry.validate(); err == nil {
- t.Fatal("A Key should be a printable character")
- }
- // Label
- menuEntry = MenuEntry{
- Key: "l",
- Label: "",
- }
- if err := menuEntry.validate(); err == nil {
- t.Fatal("A Label cannot be empty")
- }
- // Actions are tested in action_test.go
-}
diff --git a/config/test_data/duplicate_game.yaml b/config/test_data/duplicate_game.yaml
deleted file mode 100644
index f01a017..0000000
--- a/config/test_data/duplicate_game.yaml
+++ /dev/null
@@ -1,30 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- anonymous:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- logged_in:
- MenuEntries:
- - Key: p
- Label: play
- Action: play test
-
-Games:
- test:
- ChrootPath: test_data/fake_nethack_directory
- FileMode: 0777
- Commands:
- - wait
- test:
- ChrootPath: test_data/fake_nethack_directory
- FileMode: 0777
- Commands:
- - wait
diff --git a/config/test_data/duplicate_menu.yaml b/config/test_data/duplicate_menu.yaml
deleted file mode 100644
index 3dbefb7..0000000
--- a/config/test_data/duplicate_menu.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- anonymous:
- MenuEntries:
- - Key: t
- Label: test
- Action: menu test
- logged_in:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- test:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- test:
- MenuEntries:
- - Key: a
- Label: login
- Action: login
diff --git a/config/test_data/fake_nethack_directory/.keep b/config/test_data/fake_nethack_directory/.keep
deleted file mode 100644
index e69de29..0000000
--- a/config/test_data/fake_nethack_directory/.keep
+++ /dev/null
diff --git a/config/test_data/invalid_app.yaml b/config/test_data/invalid_app.yaml
deleted file mode 100644
index ed236ea..0000000
--- a/config/test_data/invalid_app.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-Menus:
- anonymous:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- logged_in:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
diff --git a/config/test_data/invalid_game.yaml b/config/test_data/invalid_game.yaml
deleted file mode 100644
index d58c3ee..0000000
--- a/config/test_data/invalid_game.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- anonymous:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- logged_in:
- MenuEntries:
- - Key: p
- Label: play
- Action: play test
-
-Games:
- test:
diff --git a/config/test_data/invalid_menus.yaml b/config/test_data/invalid_menus.yaml
deleted file mode 100644
index 1df5fbf..0000000
--- a/config/test_data/invalid_menus.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- anonymous:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- logged_in:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- test:
diff --git a/config/test_data/invalid_yaml b/config/test_data/invalid_yaml
deleted file mode 100644
index db1ddad..0000000
--- a/config/test_data/invalid_yaml
+++ /dev/null
@@ -1 +0,0 @@
-blargh(ads)
diff --git a/config/test_data/minimal.yaml b/config/test_data/minimal.yaml
deleted file mode 100644
index 22a0a6c..0000000
--- a/config/test_data/minimal.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- anonymous:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- logged_in:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
diff --git a/config/test_data/no_anonymous_menu.yaml b/config/test_data/no_anonymous_menu.yaml
deleted file mode 100644
index a015160..0000000
--- a/config/test_data/no_anonymous_menu.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- test:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- logged_in:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
diff --git a/config/test_data/no_logged_in_menu.yaml b/config/test_data/no_logged_in_menu.yaml
deleted file mode 100644
index 43d0054..0000000
--- a/config/test_data/no_logged_in_menu.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- anonymous:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- test:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
diff --git a/config/test_data/non_existant_chopts.yaml b/config/test_data/non_existant_chopts.yaml
deleted file mode 100644
index d3f796d..0000000
--- a/config/test_data/non_existant_chopts.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- anonymous:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- logged_in:
- MenuEntries:
- - Key: t
- Label: test
- Action: chopts invalid
diff --git a/config/test_data/non_existant_game.yaml b/config/test_data/non_existant_game.yaml
deleted file mode 100644
index 9bf6a38..0000000
--- a/config/test_data/non_existant_game.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- anonymous:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- logged_in:
- MenuEntries:
- - Key: t
- Label: test
- Action: play invalid
diff --git a/config/test_data/non_existant_menu.yaml b/config/test_data/non_existant_menu.yaml
deleted file mode 100644
index f0f30a3..0000000
--- a/config/test_data/non_existant_menu.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- anonymous:
- MenuEntries:
- - Key: t
- Label: test
- Action: menu invalid
- logged_in:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
diff --git a/config/test_data/not_enough_menus.yaml b/config/test_data/not_enough_menus.yaml
deleted file mode 100644
index f585f44..0000000
--- a/config/test_data/not_enough_menus.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- test:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
diff --git a/config/test_data/unreachable_game.yaml b/config/test_data/unreachable_game.yaml
deleted file mode 100644
index f2f22e2..0000000
--- a/config/test_data/unreachable_game.yaml
+++ /dev/null
@@ -1,25 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- anonymous:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- logged_in:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
-
-Games:
- unreachable:
- ChrootPath: test_data/fake_nethack_directory
- FileMode: 0777
- Commands:
- - wait
diff --git a/config/test_data/unreachable_menu.yaml b/config/test_data/unreachable_menu.yaml
deleted file mode 100644
index f947cf7..0000000
--- a/config/test_data/unreachable_menu.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-App:
- WorkingDirectory: var/
- MaxUsers: 1
- AllowRegistration: true
- MaxNickLen: 15
- MenuMaxIdleTime: 600
-
-Menus:
- anonymous:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- logged_in:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit
- test:
- MenuEntries:
- - Key: q
- Label: quit
- Action: quit