aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/config.go29
-rw-r--r--config/config_test.go43
-rw-r--r--config/game.go2
-rw-r--r--config/menu.go47
-rw-r--r--config/test_data/duplicate_menu.yaml89
-rw-r--r--config/test_data/non_existant_chopts.yaml80
-rw-r--r--config/test_data/non_existant_game.yaml81
-rw-r--r--config/test_data/non_existant_menu.yaml72
-rw-r--r--config/test_data/unreachable_game.yaml90
-rw-r--r--config/test_data/unreachable_menu.yaml87
-rw-r--r--example/complete.yaml8
11 files changed, 604 insertions, 24 deletions
diff --git a/config/config.go b/config/config.go
index fada1ea..1deaf04 100644
--- a/config/config.go
+++ b/config/config.go
@@ -17,38 +17,25 @@ type Config struct {
}
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")
}
- found_anonymous_menu := false
- found_logged_in_menu := false
for k, v := range c.Menus {
if err := v.validate(k); err != nil {
return err
}
- if k == "anonymous" {
- found_anonymous_menu = true
- }
- if k == "logged_in" {
- found_logged_in_menu = true
- }
- }
- if !found_anonymous_menu {
- return errors.New("No anonymous menu declared")
- }
- if !found_logged_in_menu {
- return errors.New("No logged_in menu declared")
}
+ // Games
for k, v := range c.Games {
if err := v.validate(k); err != nil {
return err
}
}
- // TODO menu existence is tested in global config
- // TODO game existence is tested in global config
return nil
}
@@ -64,6 +51,14 @@ func LoadFile(path string) (config Config, err error) {
if err = decoder.Decode(&config); err != nil {
return
}
- err = config.validate()
+ if err = config.validate(); err != nil {
+ return
+ }
+ // If all looks good we validate menu consistency
+ for _, v := range config.Menus {
+ if err = v.validateConsistency(&config); err != nil {
+ return
+ }
+ }
return
}
diff --git a/config/config_test.go b/config/config_test.go
index 1fcc57c..5679d06 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -19,7 +19,6 @@ func TestLoadFile(t *testing.T) {
t.Fatal("invalid_yaml config file failed without error")
}
- // TODO test non existant menu in action menu entries, and duplicate, and that anonymous and logged_in exist
// TODO test non existant game in play actions, and duplicate
//menuEntry = MenuEntry{
//Key: "p",
@@ -31,26 +30,46 @@ func TestLoadFile(t *testing.T) {
//}
t.Cleanup(func() { os.RemoveAll("var/") })
- // Invalid App example
+ // Invalid App
if _, err := LoadFile("test_data/invalid_app.yaml"); err == nil {
t.Fatal("Invalid App entry should fail to load")
}
- // Not enough menus example
+ // 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 example
+ // Invalid Menus
if _, err := LoadFile("test_data/invalid_menus.yaml"); err == nil {
t.Fatal("Invalid menu entry should fail to load")
}
- // no anonymous Menu example
+ // 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 example
+ // 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")
+ }
+ // unreachable game
+ if _, err := LoadFile("test_data/unreachable_game.yaml"); err == nil {
+ t.Fatal("unreachable game should fail to load")
+ }
// Complexe example
config, err := LoadFile("../example/complete.yaml")
@@ -137,6 +156,18 @@ func TestLoadFile(t *testing.T) {
},
},
},
+ "options": Menu{
+ Banner: "Options%n=======",
+ XOffset: 5,
+ YOffset: 2,
+ MenuEntries: []MenuEntry{
+ MenuEntry{
+ Key: "z",
+ Label: "back",
+ Action: "menu logged_in",
+ },
+ },
+ },
},
Games: map[string]Game{
"nethack3.7": Game{
diff --git a/config/game.go b/config/game.go
index 5520659..c34c697 100644
--- a/config/game.go
+++ b/config/game.go
@@ -21,7 +21,7 @@ type Game struct {
Env map[string]string `yaml:"Env"`
}
-func (a *Game) validate(name string) error {
+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)
diff --git a/config/menu.go b/config/menu.go
index 160afa3..004c7fe 100644
--- a/config/menu.go
+++ b/config/menu.go
@@ -2,6 +2,7 @@ package config
import (
"regexp"
+ "strings"
"github.com/pkg/errors"
)
@@ -61,6 +62,52 @@ func (m *Menu) validate(name string) error {
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 := make(map[string]bool)
+ menus["anonymous"] = true
+ menus["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 {
diff --git a/config/test_data/duplicate_menu.yaml b/config/test_data/duplicate_menu.yaml
new file mode 100644
index 0000000..d2a00e2
--- /dev/null
+++ b/config/test_data/duplicate_menu.yaml
@@ -0,0 +1,89 @@
+App:
+ WorkingDirectory: var/
+ MaxUsers: 512
+ AllowRegistration: true
+ MaxNickLen: 15
+ MenuMaxIdleTime: 600
+ PostLoginCommands:
+ - mkdir %w/userdata/%u
+ - mkdir %w/userdata/%u/dumplog
+ - mkdir %w/userdata/%u/ttyrec
+
+Menus:
+ anonymous:
+ Banner: 'Shell Game Launcher - Anonymous access%n======================================'
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: t
+ Label: test
+ Action: menu test
+ - Key: l
+ Label: login
+ Action: login
+ - Key: r
+ Label: register
+ Action: register
+ - Key: w
+ Label: watch
+ Action: watch_menu
+ - Key: q
+ Label: quit
+ Action: quit
+ logged_in:
+ Banner: 'Shell Game Launcher%n==================='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: p
+ Label: play Nethack 3.7
+ Action: play nethack3.7
+ - Key: o
+ Label: edit game options
+ Action: menu options
+ - Key: w
+ Label: watch
+ Action: watch
+ - Key: r
+ Label: replay
+ Action: replay
+ - Key: c
+ Label: change password
+ Action: passwd
+ - Key: m
+ Label: change email
+ Action: chmail
+ - Key: q
+ Label: quit
+ Action: quit
+ test:
+ Banner: 'Shell Game Launcher%n==================='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: p
+ Label: play Nethack 3.7
+ Action: play nethack3.7
+ test:
+ Banner: 'Duplicate Shell Game Launcher%n==================='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: p
+ Label: play Nethack 3.7
+ Action: play nethack3.7
+
+Games:
+ nethack3.7:
+ ChrootPath: /opt/nethack
+ FileMode: "0666"
+ ScoreCommands:
+ - exec /games/nethack -s all
+ - wait
+ Commands:
+ - cp /games/var/save/%u%n.gz /games/var/save/%u%n.gz.bak
+ - exec /games/nethack -u %n
+ Env:
+ NETHACKOPTIONS: "@%ruserdata/%n/%n.nhrc"
+
+
diff --git a/config/test_data/non_existant_chopts.yaml b/config/test_data/non_existant_chopts.yaml
new file mode 100644
index 0000000..d3ec2a5
--- /dev/null
+++ b/config/test_data/non_existant_chopts.yaml
@@ -0,0 +1,80 @@
+App:
+ WorkingDirectory: var/
+ MaxUsers: 512
+ AllowRegistration: true
+ MaxNickLen: 15
+ MenuMaxIdleTime: 600
+ PostLoginCommands:
+ - mkdir %w/userdata/%u
+ - mkdir %w/userdata/%u/dumplog
+ - mkdir %w/userdata/%u/ttyrec
+
+Menus:
+ anonymous:
+ Banner: 'Shell Game Launcher - Anonymous access%n======================================'
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: l
+ Label: login
+ Action: login
+ - Key: r
+ Label: register
+ Action: register
+ - Key: w
+ Label: watch
+ Action: watch_menu
+ - Key: q
+ Label: quit
+ Action: quit
+ logged_in:
+ Banner: 'Shell Game Launcher%n==================='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: p
+ Label: play Nethack 3.7
+ Action: play nethack3.7
+ - Key: o
+ Label: edit game options
+ Action: menu options
+ - Key: w
+ Label: watch
+ Action: watch
+ - Key: r
+ Label: replay
+ Action: replay
+ - Key: c
+ Label: change password
+ Action: passwd
+ - Key: m
+ Label: change email
+ Action: chmail
+ - Key: q
+ Label: quit
+ Action: quit
+ options:
+ Banner: 'Options%n======='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: a
+ Label: edit options for Nethack 3.7
+ Action: chopts invalid
+ - Key: z
+ Label: back
+ Action: menu logged_in
+
+Games:
+ nethack3.7:
+ ChrootPath: /opt/nethack
+ FileMode: "0666"
+ ScoreCommands:
+ - exec /games/nethack -s all
+ - wait
+ Commands:
+ - cp /games/var/save/%u%n.gz /games/var/save/%u%n.gz.bak
+ - exec /games/nethack -u %n
+ Env:
+ NETHACKOPTIONS: "@%ruserdata/%n/%n.nhrc"
+
diff --git a/config/test_data/non_existant_game.yaml b/config/test_data/non_existant_game.yaml
new file mode 100644
index 0000000..c386e1a
--- /dev/null
+++ b/config/test_data/non_existant_game.yaml
@@ -0,0 +1,81 @@
+App:
+ WorkingDirectory: var/
+ MaxUsers: 512
+ AllowRegistration: true
+ MaxNickLen: 15
+ MenuMaxIdleTime: 600
+ PostLoginCommands:
+ - mkdir %w/userdata/%u
+ - mkdir %w/userdata/%u/dumplog
+ - mkdir %w/userdata/%u/ttyrec
+
+Menus:
+ anonymous:
+ Banner: 'Shell Game Launcher - Anonymous access%n======================================'
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: l
+ Label: login
+ Action: login
+ - Key: r
+ Label: register
+ Action: register
+ - Key: w
+ Label: watch
+ Action: watch_menu
+ - Key: q
+ Label: quit
+ Action: quit
+ logged_in:
+ Banner: 'Shell Game Launcher%n==================='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: p
+ Label: play Nethack 3.7
+ Action: play invalid
+ - Key: o
+ Label: edit game options
+ Action: menu options
+ - Key: w
+ Label: watch
+ Action: watch
+ - Key: r
+ Label: replay
+ Action: replay
+ - Key: c
+ Label: change password
+ Action: passwd
+ - Key: m
+ Label: change email
+ Action: chmail
+ - Key: q
+ Label: quit
+ Action: quit
+ options:
+ Banner: 'Options%n======='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: a
+ Label: edit options for Nethack 3.7
+ Action: chopts nethack3.7
+ - Key: z
+ Label: back
+ Action: menu logged_in
+
+Games:
+ nethack3.7:
+ ChrootPath: /opt/nethack
+ FileMode: "0666"
+ ScoreCommands:
+ - exec /games/nethack -s all
+ - wait
+ Commands:
+ - cp /games/var/save/%u%n.gz /games/var/save/%u%n.gz.bak
+ - exec /games/nethack -u %n
+ Env:
+ NETHACKOPTIONS: "@%ruserdata/%n/%n.nhrc"
+
+
diff --git a/config/test_data/non_existant_menu.yaml b/config/test_data/non_existant_menu.yaml
new file mode 100644
index 0000000..2890ee8
--- /dev/null
+++ b/config/test_data/non_existant_menu.yaml
@@ -0,0 +1,72 @@
+App:
+ WorkingDirectory: var/
+ MaxUsers: 512
+ AllowRegistration: true
+ MaxNickLen: 15
+ MenuMaxIdleTime: 600
+ PostLoginCommands:
+ - mkdir %w/userdata/%u
+ - mkdir %w/userdata/%u/dumplog
+ - mkdir %w/userdata/%u/ttyrec
+
+Menus:
+ anonymous:
+ Banner: 'Shell Game Launcher - Anonymous access%n======================================'
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: t
+ Label: test
+ Action: menu test
+ - Key: l
+ Label: login
+ Action: login
+ - Key: r
+ Label: register
+ Action: register
+ - Key: w
+ Label: watch
+ Action: watch_menu
+ - Key: q
+ Label: quit
+ Action: quit
+ logged_in:
+ Banner: 'Shell Game Launcher%n==================='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: p
+ Label: play Nethack 3.7
+ Action: play nethack3.7
+ - Key: o
+ Label: edit game options
+ Action: menu invalid
+ - Key: w
+ Label: watch
+ Action: watch
+ - Key: r
+ Label: replay
+ Action: replay
+ - Key: c
+ Label: change password
+ Action: passwd
+ - Key: m
+ Label: change email
+ Action: chmail
+ - Key: q
+ Label: quit
+ Action: quit
+
+Games:
+ nethack3.7:
+ ChrootPath: /opt/nethack
+ FileMode: "0666"
+ ScoreCommands:
+ - exec /games/nethack -s all
+ - wait
+ Commands:
+ - cp /games/var/save/%u%n.gz /games/var/save/%u%n.gz.bak
+ - exec /games/nethack -u %n
+ Env:
+ NETHACKOPTIONS: "@%ruserdata/%n/%n.nhrc"
+
diff --git a/config/test_data/unreachable_game.yaml b/config/test_data/unreachable_game.yaml
new file mode 100644
index 0000000..a6a8977
--- /dev/null
+++ b/config/test_data/unreachable_game.yaml
@@ -0,0 +1,90 @@
+App:
+ WorkingDirectory: var/
+ MaxUsers: 512
+ AllowRegistration: true
+ MaxNickLen: 15
+ MenuMaxIdleTime: 600
+ PostLoginCommands:
+ - mkdir %w/userdata/%u
+ - mkdir %w/userdata/%u/dumplog
+ - mkdir %w/userdata/%u/ttyrec
+
+Menus:
+ anonymous:
+ Banner: 'Shell Game Launcher - Anonymous access%n======================================'
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: l
+ Label: login
+ Action: login
+ - Key: r
+ Label: register
+ Action: register
+ - Key: w
+ Label: watch
+ Action: watch_menu
+ - Key: q
+ Label: quit
+ Action: quit
+ logged_in:
+ Banner: 'Shell Game Launcher%n==================='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: p
+ Label: play Nethack 3.7
+ Action: play nethack3.7
+ - Key: o
+ Label: edit game options
+ Action: menu options
+ - Key: w
+ Label: watch
+ Action: watch
+ - Key: r
+ Label: replay
+ Action: replay
+ - Key: c
+ Label: change password
+ Action: passwd
+ - Key: m
+ Label: change email
+ Action: chmail
+ - Key: q
+ Label: quit
+ Action: quit
+ options:
+ Banner: 'Options%n======='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: a
+ Label: edit options for Nethack 3.7
+ Action: chopts nethack3.7
+ - Key: z
+ Label: back
+ Action: menu logged_in
+
+Games:
+ nethack3.7:
+ ChrootPath: /opt/nethack
+ FileMode: "0666"
+ ScoreCommands:
+ - exec /games/nethack -s all
+ - wait
+ Commands:
+ - cp /games/var/save/%u%n.gz /games/var/save/%u%n.gz.bak
+ - exec /games/nethack -u %n
+ Env:
+ NETHACKOPTIONS: "@%ruserdata/%n/%n.nhrc"
+ unreachable:
+ ChrootPath: /opt/nethack
+ FileMode: "0666"
+ ScoreCommands:
+ - exec /games/nethack -s all
+ - wait
+ Commands:
+ - cp /games/var/save/%u%n.gz /games/var/save/%u%n.gz.bak
+ - exec /games/nethack -u %n
+ Env:
+ NETHACKOPTIONS: "@%ruserdata/%n/%n.nhrc"
diff --git a/config/test_data/unreachable_menu.yaml b/config/test_data/unreachable_menu.yaml
new file mode 100644
index 0000000..27da191
--- /dev/null
+++ b/config/test_data/unreachable_menu.yaml
@@ -0,0 +1,87 @@
+App:
+ WorkingDirectory: var/
+ MaxUsers: 512
+ AllowRegistration: true
+ MaxNickLen: 15
+ MenuMaxIdleTime: 600
+ PostLoginCommands:
+ - mkdir %w/userdata/%u
+ - mkdir %w/userdata/%u/dumplog
+ - mkdir %w/userdata/%u/ttyrec
+
+Menus:
+ anonymous:
+ Banner: 'Shell Game Launcher - Anonymous access%n======================================'
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: l
+ Label: login
+ Action: login
+ - Key: r
+ Label: register
+ Action: register
+ - Key: w
+ Label: watch
+ Action: watch_menu
+ - Key: q
+ Label: quit
+ Action: quit
+ logged_in:
+ Banner: 'Shell Game Launcher%n==================='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: p
+ Label: play Nethack 3.7
+ Action: play nethack3.7
+ - Key: o
+ Label: edit game options
+ Action: menu options
+ - Key: w
+ Label: watch
+ Action: watch
+ - Key: r
+ Label: replay
+ Action: replay
+ - Key: c
+ Label: change password
+ Action: passwd
+ - Key: m
+ Label: change email
+ Action: chmail
+ - Key: q
+ Label: quit
+ Action: quit
+ options:
+ Banner: 'Options%n======='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: a
+ Label: edit options for Nethack 3.7
+ Action: chopts nethack3.7
+ - Key: z
+ Label: back
+ Action: menu logged_in
+ unreachable:
+ Banner: 'Options%n======='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: a
+ Label: edit options for Nethack 3.7
+ Action: chopts nethack3.7
+
+Games:
+ nethack3.7:
+ ChrootPath: /opt/nethack
+ FileMode: "0666"
+ ScoreCommands:
+ - exec /games/nethack -s all
+ - wait
+ Commands:
+ - cp /games/var/save/%u%n.gz /games/var/save/%u%n.gz.bak
+ - exec /games/nethack -u %n
+ Env:
+ NETHACKOPTIONS: "@%ruserdata/%n/%n.nhrc"
diff --git a/example/complete.yaml b/example/complete.yaml
index e8e36e1..2677285 100644
--- a/example/complete.yaml
+++ b/example/complete.yaml
@@ -53,6 +53,14 @@ Menus:
- Key: q
Label: quit
Action: quit
+ options:
+ Banner: 'Options%n======='
+ XOffset: 5
+ YOffset: 2
+ MenuEntries:
+ - Key: z
+ Label: back
+ Action: menu logged_in
Games:
nethack3.7: