// MultipleChoice computes the score of a multiple choice exercise // with student answers provided in fileName, and the answers provided // in the answerKey object. The function requires a Score object, and // will produce both string output and JSON output. func MultipleChoice(t *testing.T, sc *score.Score, fileName string, answers Choices) { defer sc.WriteString(os.Stdout) defer sc.WriteJSON(os.Stdout) // Read the whole file bytes, err := ioutil.ReadFile(fileName) if err != nil { sc.Score = 0 t.Fatalf(fmt.Sprintf("%v: error reading the file: %v", fileName, err)) return } for i := range answers { // Find the user's answer to the corresponding question number regexStr := "\n" + strconv.Itoa(answers[i].Number) + "[.)]*[ \t\v\r\n\f]*[A-Za-z]*" regex := regexp.MustCompile(regexStr) userAnswer := regex.Find(bytes) if userAnswer == nil { t.Errorf("%v %d: Answer not found.\n", sc.TestName, answers[i].Number) sc.Dec() } else { r, _ := utf8.DecodeLastRune(userAnswer) got, _ := utf8.DecodeLastRuneInString(strings.ToUpper(string(r))) if got != answers[i].Want { t.Errorf("%v %d: %q is incorrect.\n", sc.TestName, answers[i].Number, got) sc.Dec() } } } }
func logOutput(s string, l *BuildResult, opt DaemonOptions) { if !utf8.ValidString(s) { v := make([]rune, 0, len(s)) for i, r := range s { if r == utf8.RuneError { _, size := utf8.DecodeRuneInString(s[i:]) if size == 1 { continue } } v = append(v, r) } s = string(v) } s = strings.Trim(s, string(0)) s = strings.TrimSpace(s) //TODO: Move this code to a new function in kit/score package? Reason: easier to test. if strings.Contains(s, opt.Secret) { // TODO: must be a better way of detecting JSON data! TODO: Hein@Heine: Why? var testscore score.Score err := json.Unmarshal([]byte(s), &testscore) if err == nil { if testscore.Secret == opt.Secret { testscore.Secret = "Sanitized" l.TestScores = append(l.TestScores, testscore) } return } // ensure that the error message does not reveal the secret token es := strings.Replace(err.Error(), opt.Secret, "Sanitized", -1) log.Printf("Parse error: %s\n", es) } s = strings.Replace(s, opt.Secret, "Sanitized", -1) s = strings.Replace(s, opt.AdminToken, "Sanitized", -1) l.Log = append(l.Log, strings.TrimSpace(s)) fmt.Println(s) }
// CommandLine computes the score for a set of command line exercises // that students provided. The function requires the list of commands // and their expected answers, and a Score object. The function // will produce both string output and JSON output. func CommandLine(t *testing.T, sc *score.Score, answers Commands) { defer sc.WriteString(os.Stdout) defer sc.WriteJSON(os.Stdout) for i := range answers { cmdArgs := strings.Split(answers[i].Command, " ") cmd := exec.Command(cmdArgs[0]) cmd.Args = cmdArgs var sout, serr bytes.Buffer cmd.Stdout, cmd.Stderr = &sout, &serr err := cmd.Run() if err != nil { t.Errorf("%v\n%v: %v.\n", sc.TestName, err, serr.String()) sc.Dec() continue } outStr := sout.String() // Compare output with expected output switch answers[i].Search { case ResultEquals: if outStr != answers[i].Result { t.Errorf("%v: \ngot: %v \nwant: %v \nfor command: %v\n", sc.TestName, outStr, answers[i].Result, answers[i].Command) sc.Dec() } case ResultContains: if !strings.Contains(outStr, answers[i].Result) { t.Errorf("%v: \nResult does not contain: %v \nfor command: %v\n", sc.TestName, answers[i].Result, answers[i].Command) sc.Dec() } case ResultDoesNotContain: if strings.Contains(outStr, answers[i].Result) { t.Errorf("%v: \nResult contains: %v \nfor command: %v\n", sc.TestName, answers[i].Result, answers[i].Command) sc.Dec() } } } }