forked from gophercises/quiz
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Solution with unit tests (gophercises#51)
- Loading branch information
1 parent
617e1ce
commit 2a121d4
Showing
3 changed files
with
203 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
5+5,10 | ||
7+3,10 | ||
1+1,2 | ||
8+3,11 | ||
1+2,3 | ||
8+6,14 | ||
3+1,4 | ||
1+4,5 | ||
5+1,6 | ||
2+3,5 | ||
3+3,6 | ||
2+4,6 | ||
5+2,7 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package quiz | ||
|
||
import ( | ||
"bufio" | ||
"encoding/csv" | ||
"flag" | ||
"fmt" | ||
"io" | ||
"log" | ||
"os" | ||
"strings" | ||
"time" | ||
) | ||
|
||
//Number of Questions to ask | ||
const totalQuestions = 5 | ||
|
||
//Question struct that stores question with answer | ||
type Question struct { | ||
question string | ||
answer string | ||
} | ||
|
||
func main() { | ||
filename, timeLimit := readArguments() | ||
f, err := openFile(filename) | ||
if err != nil { | ||
return | ||
} | ||
questions, err := readCSV(f) | ||
|
||
if err != nil { | ||
// err := fmt.Errorf("Error in Reading Questions") | ||
fmt.Println(err.Error()) | ||
return | ||
} | ||
|
||
if questions == nil { | ||
return | ||
} | ||
score, err := askQuestion(questions, timeLimit) | ||
if err != nil { | ||
fmt.Println(err) | ||
return | ||
} | ||
|
||
fmt.Printf("Your Score %d/%d\n", score, totalQuestions) | ||
} | ||
|
||
func readArguments() (string, int) { | ||
filename := flag.String("filename", "problem.csv", "CSV File that conatins quiz questions") | ||
timeLimit := flag.Int("limit", 30, "Time Limit for each question") | ||
flag.Parse() | ||
return *filename, *timeLimit | ||
} | ||
|
||
func readCSV(f io.Reader) ([]Question, error) { | ||
// defer f.Close() // this needs to be after the err check | ||
allQuestions, err := csv.NewReader(f).ReadAll() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
numOfQues := len(allQuestions) | ||
if numOfQues == 0 { | ||
return nil, fmt.Errorf("No Question in file") | ||
} | ||
|
||
var data []Question | ||
for _, line := range allQuestions { | ||
ques := Question{} | ||
ques.question = line[0] | ||
ques.answer = line[1] | ||
data = append(data, ques) | ||
} | ||
|
||
return data, nil | ||
} | ||
|
||
func openFile(filename string) (io.Reader, error) { | ||
return os.Open(filename) | ||
} | ||
func getInput(input chan string) { | ||
for { | ||
in := bufio.NewReader(os.Stdin) | ||
result, err := in.ReadString('\n') | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
input <- result | ||
} | ||
} | ||
|
||
func askQuestion(questions []Question, timeLimit int) (int, error) { | ||
totalScore := 0 | ||
timer := time.NewTimer(time.Duration(timeLimit) * time.Second) | ||
done := make(chan string) | ||
|
||
go getInput(done) | ||
|
||
for i := range [totalQuestions]int{} { | ||
ans, err := eachQuestion(questions[i].question, questions[i].answer, timer.C, done) | ||
if err != nil && ans == -1 { | ||
return totalScore, nil | ||
} | ||
totalScore += ans | ||
|
||
} | ||
return totalScore, nil | ||
} | ||
|
||
func eachQuestion(Quest string, answer string, timer <-chan time.Time, done <-chan string) (int, error) { | ||
fmt.Printf("%s: ", Quest) | ||
|
||
for { | ||
select { | ||
case <-timer: | ||
return -1, fmt.Errorf("Time out") | ||
case ans := <-done: | ||
score := 0 | ||
if strings.Compare(strings.Trim(strings.ToLower(ans), "\n"), answer) == 0 { | ||
score = 1 | ||
} else { | ||
return 0, fmt.Errorf("Wrong Answer") | ||
} | ||
|
||
return score, nil | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package quiz | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
"time" | ||
|
||
"gotest.tools/assert" | ||
) | ||
|
||
func testEachQuestion(t *testing.T) { | ||
timer := time.NewTimer(time.Duration(2) * time.Second).C | ||
done := make(chan string) | ||
var quest Question | ||
quest.question = "1+1" | ||
quest.answer = "2" | ||
var ans int | ||
var err error | ||
allDone := make(chan bool) | ||
go func() { | ||
ans, err = eachQuestion(quest.question, quest.answer, timer, done) | ||
allDone <- true | ||
}() | ||
done <- "2" | ||
|
||
<-allDone | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
assert.Equal(t, ans, 1) | ||
} | ||
|
||
func testReadCSV(t *testing.T) { | ||
str := "1+1,2\n2+1,3\n9+9,18\n" | ||
quest, err := readCSV(strings.NewReader(str)) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
var que [3]Question | ||
que[0].answer = "2" | ||
que[1].answer = "3" | ||
que[2].answer = "18" | ||
que[0].question = "1+1" | ||
que[1].question = "2+1" | ||
que[2].question = "9+9" | ||
|
||
assert.Equal(t, que[0], quest[0]) | ||
assert.Equal(t, que[1], quest[1]) | ||
assert.Equal(t, que[2], quest[2]) | ||
|
||
} | ||
|
||
func TestEachQuestion(t *testing.T) { | ||
t.Run("test eachQuestion", testEachQuestion) | ||
} | ||
|
||
func TestReadCSV(t *testing.T) { | ||
t.Run("test ReadCSV", testReadCSV) | ||
} |