repochecker: Test number step are in phase with response precision
Closes: https://gitlab.cri.epita.fr/ing/majeures/srs/fic/server/-/issues/36
This commit is contained in:
parent
04e938ff73
commit
954cf84f0f
@ -3,6 +3,7 @@ package sync
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
"go.uber.org/multierr"
|
"go.uber.org/multierr"
|
||||||
@ -78,6 +79,41 @@ func (f ExerciceFlag) RawString() []string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f ExerciceFlag) RawNumber() ([]float64, error) {
|
||||||
|
switch f.Raw.(type) {
|
||||||
|
case float64:
|
||||||
|
return []float64{f.Raw.(float64)}, nil
|
||||||
|
case []float64:
|
||||||
|
return f.Raw.([]float64), nil
|
||||||
|
case int64:
|
||||||
|
return []float64{float64(f.Raw.(int64))}, nil
|
||||||
|
case []int64:
|
||||||
|
var res []float64
|
||||||
|
for _, raw := range f.Raw.([]int64) {
|
||||||
|
res = append(res, float64(raw))
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
case string:
|
||||||
|
if v, err := strconv.ParseFloat(f.Raw.(string), 64); err == nil {
|
||||||
|
return []float64{v}, nil
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case []string:
|
||||||
|
var res []float64
|
||||||
|
for _, raw := range f.Raw.([]string) {
|
||||||
|
if v, err := strconv.ParseFloat(raw, 64); err == nil {
|
||||||
|
res = append(res, v)
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid raw type: %T", f.Raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ExerciceFlagChoice holds informations about a choice (for MCQ and UCQ).
|
// ExerciceFlagChoice holds informations about a choice (for MCQ and UCQ).
|
||||||
type ExerciceFlagChoice struct {
|
type ExerciceFlagChoice struct {
|
||||||
ExerciceFlag
|
ExerciceFlag
|
||||||
|
@ -2,6 +2,7 @@ package sync
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
@ -286,17 +287,19 @@ type importFlag struct {
|
|||||||
FlagsDeps []int64
|
FlagsDeps []int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func iface2Number(input interface{}, output *string) error {
|
func iface2Number(input interface{}, output *string) (norm float64, err error) {
|
||||||
if input != nil {
|
if input != nil {
|
||||||
if v, ok := input.(int64); ok {
|
if v, ok := input.(int64); ok {
|
||||||
*output = fmt.Sprintf("%d", v)
|
*output = fmt.Sprintf("%d", v)
|
||||||
|
norm = float64(v)
|
||||||
} else if v, ok := input.(float64); ok {
|
} else if v, ok := input.(float64); ok {
|
||||||
*output = strconv.FormatFloat(v, 'f', -1, 64)
|
*output = strconv.FormatFloat(v, 'f', -1, 64)
|
||||||
|
norm = v
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("has an invalid type: expected int or float, got %T", input)
|
err = fmt.Errorf("has an invalid type: expected int or float, got %T", input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildExerciceFlag read challenge.txt and extract all flags.
|
// buildExerciceFlag read challenge.txt and extract all flags.
|
||||||
@ -310,20 +313,33 @@ func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nl
|
|||||||
flag.Type = "key"
|
flag.Type = "key"
|
||||||
case "number":
|
case "number":
|
||||||
var smin, smax, sstep string
|
var smin, smax, sstep string
|
||||||
err := iface2Number(flag.NumberMin, &smin)
|
fstep, err := iface2Number(flag.NumberStep, &sstep)
|
||||||
|
if err != nil {
|
||||||
|
errs = multierr.Append(errs, NewFlagError(exercice, &flag, nline+1, fmt.Errorf("step %w", err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = iface2Number(flag.NumberMin, &smin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = multierr.Append(errs, NewFlagError(exercice, &flag, nline+1, fmt.Errorf("min %w", err)))
|
errs = multierr.Append(errs, NewFlagError(exercice, &flag, nline+1, fmt.Errorf("min %w", err)))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = iface2Number(flag.NumberMax, &smax)
|
_, err = iface2Number(flag.NumberMax, &smax)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = multierr.Append(errs, NewFlagError(exercice, &flag, nline+1, fmt.Errorf("max %w", err)))
|
errs = multierr.Append(errs, NewFlagError(exercice, &flag, nline+1, fmt.Errorf("max %w", err)))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = iface2Number(flag.NumberStep, &sstep)
|
// Ensure step permit validating the flag
|
||||||
if err != nil {
|
if rns, err := flag.RawNumber(); err != nil {
|
||||||
errs = multierr.Append(errs, NewFlagError(exercice, &flag, nline+1, fmt.Errorf("step %w", err)))
|
errs = multierr.Append(errs, NewFlagError(exercice, &flag, nline+1, fmt.Errorf("raw %w", err)))
|
||||||
|
} else {
|
||||||
|
for _, rn := range rns {
|
||||||
|
v := math.Abs(rn) / fstep
|
||||||
|
if float64(int(v)) != v {
|
||||||
|
errs = multierr.Append(errs, NewFlagError(exercice, &flag, nline+1, fmt.Errorf("choosen step=%f doesn't include response=%f", fstep, rn)))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flag.Type = fmt.Sprintf("number,%s,%s,%s", smin, smax, sstep)
|
flag.Type = fmt.Sprintf("number,%s,%s,%s", smin, smax, sstep)
|
||||||
case "text":
|
case "text":
|
||||||
flag.Type = "text"
|
flag.Type = "text"
|
||||||
|
Loading…
Reference in New Issue
Block a user