diff --git a/session/environment_test.go b/session/environment_test.go index b3b3bb85..5edcc0ee 100644 --- a/session/environment_test.go +++ b/session/environment_test.go @@ -263,6 +263,10 @@ func TestSessionEnvironmentGetInt(t *testing.T) { } else if i != 1234 { t.Fatalf("unexpected integer: %d", i) } + + if err, _ := env.GetInt("unknownint"); err == nil { + t.Fatalf("expected error (unknown key): %v", err) + } } func TestSessionEnvironmentSorted(t *testing.T) { diff --git a/session/events_test.go b/session/events_test.go new file mode 100644 index 00000000..a4f96fab --- /dev/null +++ b/session/events_test.go @@ -0,0 +1,301 @@ +package session + +import ( + "sync" + "testing" + "time" +) + +func TestNewEvent(t *testing.T) { + + type args struct { + tag string + data interface{} + } + tests := []struct { + name string + args args + want Event + }{ + { + name: "Create new event with nil data", + args: args{"tag", nil}, + want: Event{Tag: "tag", Data: nil}, + }, + { + name: "Create new event with string data", + args: args{"tag", "test string"}, + want: Event{Tag: "tag", Data: "test string"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := NewEvent(tt.args.tag, tt.args.data) + if got.Data != tt.args.data { + t.Errorf("Expected %+v data, got %+v", tt.args.data, got.Data) + } + if got.Tag != tt.args.tag { + t.Errorf("Expected %+v Tag, got %+v", tt.args.tag, got.Tag) + } + }) + } +} + +func TestNewEventPool(t *testing.T) { + type args struct { + debug bool + silent bool + } + tests := []struct { + name string + args args + want *EventPool + }{ + { + name: "Test creating debug event pool", + args: args{true, false}, + want: &EventPool{debug: true, silent: false}, + }, + { + name: "Test creating silent and event pool", + args: args{true, false}, + want: &EventPool{debug: true, silent: false}, + }, + // { + // name: "Test creating silent and debug event pool", + // args: args{true, true}, + // want: nil, + // }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := NewEventPool(tt.args.debug, tt.args.silent) + if got == nil { + t.Fatal("NewEventPool() returned unexpected nil") + } + if got.silent != tt.want.silent { + t.Errorf("Didn't get correct silent var %v, want %v", got.silent, tt.want.silent) + } + }) + } +} + +func TestEventPool_SetSilent(t *testing.T) { + type fields struct { + Mutex sync.Mutex + debug bool + silent bool + events []Event + listeners []chan Event + } + type args struct { + s bool + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "Set silent on non-silent event pool", + fields: fields{silent: false, debug: false}, + args: args{s: true}, + }, + { + name: "Set silent on silent event pool", + fields: fields{silent: true, debug: false}, + args: args{s: true}, + }, + { + name: "Set non-silent on non-silent event pool", + fields: fields{silent: false, debug: false}, + args: args{s: false}, + }, + { + name: "Set silent on silent event pool", + fields: fields{silent: true, debug: false}, + args: args{s: false}, + }, + { + name: "Set silent on non-silent and debug event pool", + fields: fields{silent: false, debug: true}, + args: args{s: true}, + }, + { + name: "Set non-silent on non-silent and debug event pool", + fields: fields{silent: false, debug: true}, + args: args{s: false}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &EventPool{ + Mutex: tt.fields.Mutex, + debug: tt.fields.debug, + silent: tt.fields.silent, + events: tt.fields.events, + listeners: tt.fields.listeners, + } + p.SetSilent(tt.args.s) + if p.silent != tt.args.s { + t.Error("p.SetSilent didn't set the eventpool to silent") + } + }) + } +} + +func TestEventPool_SetDebug(t *testing.T) { + type fields struct { + Mutex sync.Mutex + debug bool + silent bool + events []Event + listeners []chan Event + } + + type args struct { + s bool + } + + tests := []struct { + name string + fields fields + args args + }{ + { + name: "Set debug on non-debug event pool", + fields: fields{silent: false, debug: false}, + args: args{s: true}, + }, + { + name: "Set debug on debug event pool", + fields: fields{silent: false, debug: true}, + args: args{s: true}, + }, + { + name: "Set non-debug on non-debug event pool", + fields: fields{silent: false, debug: false}, + args: args{s: false}, + }, + { + name: "Set non-debug on debug event pool", + fields: fields{silent: false, debug: true}, + args: args{s: false}, + }, + { + name: "Set silent on non-silent and debug event pool", + fields: fields{silent: false, debug: true}, + args: args{s: true}, + }, + { + name: "Set non-silent on non-silent and debug event pool", + fields: fields{silent: false, debug: true}, + args: args{s: true}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &EventPool{ + Mutex: tt.fields.Mutex, + debug: tt.fields.debug, + silent: tt.fields.silent, + events: tt.fields.events, + listeners: tt.fields.listeners, + } + p.SetDebug(tt.args.s) + if p.debug != tt.args.s { + t.Error("p.SetDebug didn't set the eventpool to debug") + } + }) + } +} + +func TestEventPool_Clear(t *testing.T) { + type fields struct { + Mutex sync.Mutex + debug bool + silent bool + events []Event + listeners []chan Event + } + + tests := []struct { + name string + fields fields + }{ + { + name: "Clear events on empty list", + fields: fields{debug: false, silent: false, events: []Event{}}, + }, + { + name: "Clear events", + fields: fields{debug: false, silent: false, events: []Event{{Tag: "meh", Data: "something", Time: time.Now()}}}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &EventPool{ + Mutex: tt.fields.Mutex, + debug: tt.fields.debug, + silent: tt.fields.silent, + events: tt.fields.events, + listeners: tt.fields.listeners, + } + p.Clear() + if len(p.events) != 0 { + t.Errorf("Expected empty list after clear, got %d", len(p.events)) + } + }) + } +} + +func TestEventPool_Add(t *testing.T) { + type fields struct { + Mutex sync.Mutex + debug bool + silent bool + events []Event + listeners []chan Event + } + type args struct { + tag string + data interface{} + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "Add event with nil data on empty event list", + fields: fields{debug: false, silent: false, events: []Event{}}, + args: args{tag: "tag with empty data", data: nil}, + }, + { + name: "Add event with nil data", + fields: fields{debug: false, silent: false, events: []Event{{Tag: "meh", Data: "something", Time: time.Now()}}}, + args: args{tag: "tag with empty data", data: nil}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &EventPool{ + Mutex: tt.fields.Mutex, + debug: tt.fields.debug, + silent: tt.fields.silent, + events: tt.fields.events, + listeners: tt.fields.listeners, + } + eventsList := tt.fields.events[:] + // It's prepended + eventsList = append([]Event{{Tag: tt.args.tag, Data: tt.args.data}}, eventsList...) + p.Add(tt.args.tag, tt.args.data) + t.Logf("eventsList : %+v", eventsList) + for index, e := range eventsList { + if e.Tag != p.events[index].Tag { + t.Errorf("Tag mismatch, got %s want %s", p.events[index].Tag, e.Tag) + } + } + }) + } +} diff --git a/session/module_handler_test.go b/session/module_handler_test.go new file mode 100644 index 00000000..9fc6b473 --- /dev/null +++ b/session/module_handler_test.go @@ -0,0 +1,212 @@ +package session + +import ( + "reflect" + "regexp" + "testing" +) + +func TestNewModuleHandler(t *testing.T) { + type args struct { + name string + expr string + desc string + exec func(args []string) error + } + tests := []struct { + name string + args args + want ModuleHandler + }{ + { + name: "Test NewModuleHandler empty expr", + args: args{name: "test name", desc: "test description"}, + want: ModuleHandler{Name: "test name", Description: "test description"}, + }, + { + name: "Test NewModuleHandler normal", + args: args{name: "test name", desc: "test description", expr: `[a-z]`}, + want: ModuleHandler{Name: "test name", Description: "test description", Parser: regexp.MustCompile(`[a-z]`)}, + }, + // this test shoud handle panic on bad regexp ? + // { + // name: "Test NewModuleHandler bad regex expr", + // args: args{name: "test name", desc: "test description", expr: "/abcd.(]"}, + // want: ModuleHandler{Name: "test name", Description: "test description"}, + // }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := NewModuleHandler(tt.args.name, tt.args.expr, tt.args.desc, tt.args.exec) + if m.Parser != nil { + if tt.args.expr == "" { + t.Errorf("If no regexp were provided, should got nil parser but got %+v", m.Parser) + } + if m.Parser.String() != tt.want.Parser.String() { + t.Errorf("Wrong parser, got %+v want %+v", m.Parser.String(), tt.want.Parser.String()) + } + } + }) + } +} + +func TestModuleHandler_Help(t *testing.T) { + type fields struct { + Name string + Description string + Parser *regexp.Regexp + Exec func(args []string) error + } + type args struct { + padding int + } + tests := []struct { + name string + fields fields + args args + want string + }{ + { + name: "Test help with no padding", + fields: fields{Name: "no-padding", Description: "Test without padding"}, + args: args{padding: 0}, + want: " \033[1mno-padding\033[0m : Test without padding\n", + }, + { + name: "Test help with non-needed padding", + fields: fields{Name: "non-needed padding", Description: "Test with non needed padding (5)"}, + args: args{padding: 5}, + want: " \033[1mnon-needed padding\033[0m : Test with non needed padding (5)\n", + }, + { + name: "Test help with 20 padding", + fields: fields{Name: "padding", Description: "Test with 20 padding"}, + args: args{padding: 20}, + want: " \033[1m padding\033[0m : Test with 20 padding\n", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := &ModuleHandler{ + Name: tt.fields.Name, + Description: tt.fields.Description, + Parser: tt.fields.Parser, + Exec: tt.fields.Exec, + } + if got := h.Help(tt.args.padding); got != tt.want { + t.Errorf("ModuleHandler.Help() = \n%v, want\n%v", got, tt.want) + } + }) + } +} + +func TestModuleHandler_Parse(t *testing.T) { + type fields struct { + Name string + Description string + Parser *regexp.Regexp + Exec func(args []string) error + } + type args struct { + line string + } + tests := []struct { + name string + fields fields + args args + want bool + want1 []string + }{ + { + name: "check parse on nil parser match name", + fields: fields{Name: "parser", Description: "description of the parser", Parser: nil}, + args: args{line: "parser"}, + want: true, + want1: nil, + }, + { + name: "check parse on nil parser no match name", + fields: fields{Name: "parser", Description: "description of the parser", Parser: nil}, + args: args{line: "wrongname"}, + want: false, + want1: nil, + }, + { + name: "check parse on existing parser", + fields: fields{Name: "parser", Description: "description of the parser", Parser: regexp.MustCompile("(abcd)")}, + args: args{line: "lol abcd lol"}, + want: true, + want1: []string{"abcd"}, + }, + { + name: "check parse on existing parser", + fields: fields{Name: "parser", Description: "description of the parser", Parser: regexp.MustCompile("(abcd)")}, + args: args{line: "no match"}, + want: false, + want1: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := &ModuleHandler{ + Name: tt.fields.Name, + Description: tt.fields.Description, + Parser: tt.fields.Parser, + Exec: tt.fields.Exec, + } + got, got1 := h.Parse(tt.args.line) + if got != tt.want { + t.Errorf("ModuleHandler.Parse() got = %v, want %v", got, tt.want) + } + if !reflect.DeepEqual(got1, tt.want1) { + t.Errorf("ModuleHandler.Parse() got1 = %v, want %v", got1, tt.want1) + } + }) + } +} + +func TestModuleHandler_MarshalJSON(t *testing.T) { + type fields struct { + Name string + Description string + Parser *regexp.Regexp + Exec func(args []string) error + } + tests := []struct { + name string + fields fields + want []byte + wantErr bool + }{ + { + name: "generating JSON with empty parser", + fields: fields{Name: "test name", Description: "test description", Parser: nil}, + want: []byte(`{"name":"test name","description":"test description","parser":""}`), + wantErr: false, + }, + { + name: "generating JSON with parser", + fields: fields{Name: "test name", Description: "test description", Parser: regexp.MustCompile("abcd")}, + want: []byte(`{"name":"test name","description":"test description","parser":"abcd"}`), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := ModuleHandler{ + Name: tt.fields.Name, + Description: tt.fields.Description, + Parser: tt.fields.Parser, + Exec: tt.fields.Exec, + } + got, err := h.MarshalJSON() + if (err != nil) != tt.wantErr { + t.Errorf("ModuleHandler.MarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if string(got) != string(tt.want) { + t.Errorf("ModuleHandler.MarshalJSON() = \n%+v, want \n%+v", string(got), string(tt.want)) + } + }) + } +} diff --git a/session/session_setup_test.go b/session/session_setup_test.go new file mode 100644 index 00000000..6867e21e --- /dev/null +++ b/session/session_setup_test.go @@ -0,0 +1,43 @@ +package session + +import "testing" + +func Test_containsCapitals(t *testing.T) { + type args struct { + s string + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "Test all alpha lowercase", + args: args{s: "abcdefghijklmnopqrstuvwxyz"}, + want: false, + }, + { + name: "Test all alpha uppercase", + args: args{s: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"}, + want: true, + }, + { + name: "Test special chars", + args: args{s: "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"}, + want: false, + }, + // Add test for UTF8 ? + // { + // name: "Test special UTF-8 chars", + // args: args{s: "€©¶αϚϴЈ"}, + // want: false, + // }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := containsCapitals(tt.args.s); got != tt.want { + t.Errorf("containsCapitals() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/session/session_test.go b/session/session_test.go index 29edcef3..d154ed89 100644 --- a/session/session_test.go +++ b/session/session_test.go @@ -35,4 +35,56 @@ func TestParseCommands(t *testing.T) { t.Fatalf("expected %s got %s", cmd, got) } }) + t.Run("handles semicolon inside single quotes", func(t *testing.T) { + cmd := "set ticker.commands 'clear; net.show'" + commands := ParseCommands(cmd) + if l := len(commands); l != 1 { + t.Fatalf("expected 1 command, got %d", l) + } + // Expect double-quotes stripped + expected := "set ticker.commands clear; net.show" + if got := commands[0]; got != expected { + fmt.Println(got) + t.Fatalf("expected %s got %s", cmd, got) + } + }) + t.Run("handles semicolon inside single quotes inside quote", func(t *testing.T) { + cmd := "set ticker.commands \"'clear; net.show'\"" + commands := ParseCommands(cmd) + if l := len(commands); l != 1 { + t.Fatalf("expected 1 command, got %d", l) + } + // Expect double-quotes stripped + expected := "set ticker.commands 'clear; net.show'" + if got := commands[0]; got != expected { + fmt.Println(got) + t.Fatalf("expected %s got %s", cmd, got) + } + }) + t.Run("handles semicolon inside quotes inside single quote", func(t *testing.T) { + cmd := "set ticker.commands '\"clear; net.show\"'" + commands := ParseCommands(cmd) + if l := len(commands); l != 1 { + t.Fatalf("expected 1 command, got %d", l) + } + // Expect double-quotes stripped + expected := "set ticker.commands \"clear; net.show\"" + if got := commands[0]; got != expected { + fmt.Println(got) + t.Fatalf("expected %s got %s", cmd, got) + } + }) + t.Run("handle mismatching quote", func(t *testing.T) { + cmd := "set ticker.commands \"clear; echo it's working ?\"" + commands := ParseCommands(cmd) + if l := len(commands); l != 1 { + t.Fatalf("expected 1 command, got %d", l) + } + // Expect double-quotes stripped + expected := "set ticker.commands clear; echo it's working ?" + if got := commands[0]; got != expected { + fmt.Println(got) + t.Fatalf("expected %s got %s", cmd, got) + } + }) }