Skip to content

Commit 806b5e9

Browse files
authored
Merge pull request #5 from chermehdi/custom-case
Custom user test case command
2 parents 456f3f6 + 3a25145 commit 806b5e9

File tree

6 files changed

+267
-11
lines changed

6 files changed

+267
-11
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
.idea
2+
go.sum

commands/case.go

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package commands
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"github.com/chermehdi/egor/config"
7+
"github.com/fatih/color"
8+
"github.com/urfave/cli/v2"
9+
"os"
10+
"path"
11+
"strconv"
12+
)
13+
14+
// Read from stdin till ctrl D or Command D
15+
func readFromStdin() []string {
16+
scn := bufio.NewScanner(os.Stdin)
17+
var lines []string
18+
for scn.Scan() {
19+
line := scn.Text()
20+
if len(line) == 1 {
21+
if line[0] == '\x1D' {
22+
break
23+
}
24+
}
25+
lines = append(lines, line)
26+
}
27+
return lines
28+
}
29+
30+
// Write given lines to given filename
31+
func writeLinesToFile(filename string, lines []string) error {
32+
f, err := os.Create(filename)
33+
if err != nil {
34+
return err
35+
}
36+
37+
for _, line := range lines {
38+
fmt.Fprintln(f, line)
39+
if err != nil {
40+
return err
41+
}
42+
}
43+
44+
return nil
45+
}
46+
47+
// Create and save user specified custom case input, and update the given egor meta data
48+
func AddNewCaseInput(inputLines []string,
49+
caseName string,
50+
metaData config.EgorMeta) (config.EgorMeta, error) {
51+
52+
inputFileName := caseName + ".in"
53+
err := writeLinesToFile(path.Join("inputs", inputFileName), inputLines)
54+
if err != nil {
55+
return metaData, err
56+
}
57+
inputFile := config.NewIoFile(inputFileName, path.Join("inputs", inputFileName), true)
58+
metaData.Inputs = append(metaData.Inputs, inputFile)
59+
60+
return metaData, nil
61+
}
62+
63+
// Create and save user specified custom csae output, and update the given egor meta data
64+
func AddNewCaseOutput(outputLines []string,
65+
caseName string,
66+
metaData config.EgorMeta) (config.EgorMeta, error) {
67+
68+
outputFileName := caseName + ".ans"
69+
err := writeLinesToFile(path.Join("outputs", outputFileName), outputLines)
70+
if err != nil {
71+
return metaData, err
72+
}
73+
outputFile := config.NewIoFile(outputFileName, path.Join("outputs", outputFileName), true)
74+
metaData.Outputs = append(metaData.Outputs, outputFile)
75+
76+
return metaData, nil
77+
}
78+
79+
// Create a user custom test case
80+
func CustomCaseAction(context *cli.Context) error {
81+
color.Green("Creating Custom Test Case...")
82+
83+
// Load meta data
84+
cwd, err := os.Getwd()
85+
if err != nil {
86+
color.Red("Failed to Generate Custom Case")
87+
return err
88+
}
89+
90+
91+
configuration, err := config.LoadDefaultConfiguration()
92+
if err != nil {
93+
color.Red("Failed to load egor configuration")
94+
return err
95+
}
96+
97+
configFileName := configuration.ConfigFileName
98+
metaData, err := config.LoadMetaFromPath(path.Join(cwd, configFileName))
99+
if err != nil {
100+
color.Red("Failed to load egor MetaData ")
101+
return err
102+
}
103+
104+
caseName := "test-" + strconv.Itoa(len(metaData.Inputs))
105+
color.Green("Provide your input:")
106+
inputLines := readFromStdin()
107+
metaData, err = AddNewCaseInput(inputLines, caseName, metaData)
108+
109+
if err != nil {
110+
color.Red("Failed to add new case input")
111+
return err
112+
}
113+
114+
if !context.Bool("no-output") {
115+
color.Green("Provide your output:")
116+
outputLines := readFromStdin()
117+
metaData, err = AddNewCaseOutput(outputLines, caseName, metaData)
118+
119+
if err != nil {
120+
color.Red("Failed to add new case output")
121+
return err
122+
}
123+
}
124+
125+
metaData.SaveToFile(path.Join(cwd, configFileName))
126+
127+
if err != nil {
128+
color.Red("Failed to save to MetaData")
129+
return err
130+
}
131+
132+
color.Green("Created Custom Test Case")
133+
return nil
134+
}
135+
136+
var CaseCommand = cli.Command{
137+
Name: "case",
138+
Aliases: []string{"tc", "testcase"},
139+
Usage: "Create a custom test case.",
140+
UsageText: "Add custom test cases to egor task.",
141+
Action: CustomCaseAction,
142+
Flags: []cli.Flag{
143+
&cli.BoolFlag{
144+
Name: "no-output",
145+
Usage: "This test case doesnt have output",
146+
Value: false,
147+
},
148+
},
149+
}

commands/case_test.go

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package commands
2+
3+
import (
4+
"github.com/chermehdi/egor/config"
5+
"github.com/stretchr/testify/assert"
6+
"os"
7+
"testing"
8+
)
9+
10+
11+
func createDummyMetaData() (config.EgorMeta) {
12+
meteData := config.EgorMeta {
13+
TaskName: "Dummy Task",
14+
TaskLang: "cpp",
15+
Inputs: []config.IoFile {
16+
config.IoFile {
17+
Name: "test-0",
18+
Path: "inputs/test-0.in",
19+
Custom: false,
20+
},
21+
config.IoFile {
22+
Name: "test-1",
23+
Path: "inputs/test-1.in",
24+
Custom: true,
25+
},
26+
},
27+
Outputs: []config.IoFile {
28+
config.IoFile {
29+
Name: "test-0",
30+
Path: "outputs/test-0.ans",
31+
Custom: false,
32+
},
33+
},
34+
}
35+
36+
return meteData
37+
}
38+
39+
40+
func TestAddNewCaseInput(t *testing.T) {
41+
meteData := createDummyMetaData()
42+
43+
// create temp inputs directory
44+
_ = os.Mkdir("inputs", 0777)
45+
defer DeleteDir("inputs")
46+
47+
inputLines := []string{"Hello", "World"}
48+
caseName := "test-2"
49+
meteData, err := AddNewCaseInput(inputLines, caseName, meteData)
50+
51+
assert.Equal(t, err, nil)
52+
assert.Equal(t, len(meteData.Inputs), 3)
53+
assert.Equal(t, meteData.Inputs[2].Name, caseName + ".in")
54+
assert.Equal(t, meteData.Inputs[2].Custom, true)
55+
56+
}
57+
58+
59+
func TestAddNewCaseOutput(t *testing.T) {
60+
meteData := createDummyMetaData()
61+
62+
// create temp outputs directory
63+
_ = os.Mkdir("outputs", 0777)
64+
defer DeleteDir("outputs")
65+
66+
outputLines := []string{"Hello", "World"}
67+
caseName := "test-2"
68+
meteData, err := AddNewCaseOutput(outputLines, caseName, meteData)
69+
70+
assert.Equal(t, err, nil)
71+
assert.Equal(t, len(meteData.Outputs), 2)
72+
assert.Equal(t, meteData.Outputs[1].Name, caseName + ".ans")
73+
assert.Equal(t, meteData.Outputs[1].Custom, true)
74+
75+
}

commands/parse.go

-3
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ func SerializeTask(meta EgorMeta) (string, error) {
3030
return buffer.String(), nil
3131
}
3232

33-
func CreateFile(filePath string) (*os.File, error) {
34-
return os.OpenFile(filePath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0777)
35-
}
3633

3734
func CreateDirectoryStructure(task Task, config Config, rootDir string) (string, error) {
3835
taskDir := path.Join(rootDir, task.Name)

config/meta.go

+41-7
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,21 @@ import (
66
"errors"
77
"fmt"
88
"io"
9+
"os"
910
"path"
1011
)
1112

1213
type IoFile struct {
13-
Name string
14-
Path string
14+
Name string
15+
Path string
16+
Custom bool
1517
}
1618

17-
func NewIoFile(fileName, filePath string) IoFile {
19+
func NewIoFile(fileName, filePath string, customCase bool) IoFile {
1820
return IoFile{
19-
Name: fileName,
20-
Path: filePath,
21+
Name: fileName,
22+
Path: filePath,
23+
Custom: customCase,
2124
}
2225
}
2326

@@ -53,8 +56,8 @@ func NewEgorMeta(task Task, config Config) EgorMeta {
5356
outputs := make([]IoFile, testCount)
5457
for i := 0; i < testCount; i++ {
5558
fileName := fmt.Sprintf("test-%d", i)
56-
inputs[i] = NewIoFile(fileName, path.Join("inputs", fileName+".in"))
57-
outputs[i] = NewIoFile(fileName, path.Join("outputs", fileName+".ans"))
59+
inputs[i] = NewIoFile(fileName, path.Join("inputs", fileName+".in"), false)
60+
outputs[i] = NewIoFile(fileName, path.Join("outputs", fileName+".ans"), false)
5861
}
5962
taskFile, err := GetTaskName(config)
6063
if err != nil {
@@ -86,9 +89,40 @@ func (egor *EgorMeta) Save(w io.Writer) error {
8689
return err
8790
}
8891

92+
func (egor *EgorMeta) SaveToFile(filePath string) error {
93+
file, _ := CreateFile(filePath)
94+
return egor.Save(file)
95+
}
96+
8997
// TODO(chermehdi): probably this should't be a member function
9098
func (egor *EgorMeta) Load(r io.Reader) error {
9199
decoder := json2.NewDecoder(r)
92100
err := decoder.Decode(egor)
93101
return err
94102
}
103+
104+
// Load egor meta data from a given reader
105+
func LoadMeta(r io.Reader) (EgorMeta, error) {
106+
var egor_meta EgorMeta
107+
decoder := json2.NewDecoder(r)
108+
err := decoder.Decode(&egor_meta)
109+
return egor_meta, err
110+
}
111+
112+
// Load egor meta data form a filepath
113+
func LoadMetaFromPath(filePath string) (EgorMeta, error) {
114+
file, _ := OpenFileFromPath(filePath)
115+
return LoadMeta(file)
116+
}
117+
118+
// TODO(Eroui): this is a duplicate function from parse.go
119+
// consider moving this somewhere common or use the other one
120+
func CreateFile(filePath string) (*os.File, error) {
121+
return os.OpenFile(filePath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0777)
122+
}
123+
124+
// Open file with a given file path
125+
func OpenFileFromPath(filePath string) (*os.File, error) {
126+
file, err := os.Open(filePath)
127+
return file, err
128+
}

main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"html/template"
66
"log"
77
"os"
8-
98
"github.com/chermehdi/egor/commands"
109
"github.com/chermehdi/egor/config"
1110
"github.com/urfave/cli/v2"
@@ -44,6 +43,7 @@ func main() {
4443
Commands: []*cli.Command{
4544
&commands.ParseCommand,
4645
&commands.ConfigCommand,
46+
&commands.CaseCommand,
4747
},
4848
}
4949

0 commit comments

Comments
 (0)