This commit is contained in:
Bel LaPointe
2020-05-18 14:40:14 -06:00
commit 4b53c15896
77 changed files with 1952 additions and 0 deletions

35
questions/storage/answer.go Executable file
View File

@@ -0,0 +1,35 @@
package storage
import (
"encoding/json"
"strings"
"github.com/buger/jsonparser"
)
const prefix_answer = "answer_"
type Answer struct {
Pair
Right bool `json:"right"`
}
func NewAnswer(text string) Answer {
return Answer{Pair: New(prefix_answer+NewID(), text)}
}
func IsAnswer(ID string) bool {
return strings.HasPrefix(ID, prefix_answer)
}
func (a *Answer) UnmarshalJSON(b []byte) error {
if err := json.Unmarshal(b, &a.Pair); err != nil {
return err
}
if right, err := jsonparser.GetBoolean(b, "right"); err != nil && err != jsonparser.KeyPathNotFoundError {
return err
} else {
a.Right = right
}
return nil
}

View File

@@ -0,0 +1,34 @@
package storage
import (
"encoding/json"
"testing"
)
func TestUnmarshalAnswerObject(t *testing.T) {
raw := `{"text":"text here", "id":"id here"}`
var a Answer
if err := json.Unmarshal([]byte(raw), &a); err != nil {
t.Fatal(err)
}
if a.Text != "text here" {
t.Fatal(a.Text)
}
if a.ID != "id here" {
t.Fatal(a.ID)
}
}
func TestUnmarshalAnswerString(t *testing.T) {
raw := `"text here"`
var a Answer
if err := json.Unmarshal([]byte(raw), &a); err != nil {
t.Fatal(err)
}
if a.ID != "text here" {
t.Fatal(a.ID)
}
if a.Text != "" {
t.Fatal(a.Text)
}
}

7
questions/storage/id.go Executable file
View File

@@ -0,0 +1,7 @@
package storage
import "github.com/google/uuid"
func NewID() string {
return uuid.New().String()
}

115
questions/storage/one.go Executable file
View File

@@ -0,0 +1,115 @@
package storage
import (
"encoding/json"
"fmt"
"log"
"github.com/buger/jsonparser"
)
type One struct {
ID string `json:"id"`
Question Question `json:"q"`
Answers []Answer `json:"a"`
}
func (one *One) UnmarshalJSON(b []byte) error {
if b, _, _, err := jsonparser.Get(b, "q"); err == jsonparser.KeyPathNotFoundError {
} else if err != nil {
return fmt.Errorf("failed to find question: %v: %q", err, b)
} else if err := json.Unmarshal(b, &one.Question); err != nil {
if err := json.Unmarshal([]byte(fmt.Sprintf("%q", b)), &one.Question); err != nil {
return fmt.Errorf("failed to parse question from obj: %v: %q", err, b)
}
}
if b, _, _, err := jsonparser.Get(b, "a"); err == jsonparser.KeyPathNotFoundError {
} else if err != nil {
return fmt.Errorf("failed to find answers: %v: %q", err, b)
} else if err := json.Unmarshal(b, &one.Answers); err != nil {
return fmt.Errorf("failed to parse answers: %v: %q", err, b)
}
if id, err := jsonparser.GetString(b, "id"); err != nil && err != jsonparser.KeyPathNotFoundError {
return fmt.Errorf("failed to parse id: %v: %q", err, b)
} else {
one.ID = id
}
return nil
}
func (one *One) FillIDs() {
if one.ID == "" {
one.ID = NewID()
}
if one.Question.ID == "" {
one.Question.ID = NewID()
}
for i := range one.Answers {
if one.Answers[i].ID == "" {
one.Answers[i].ID = NewID()
}
}
}
func (one One) Check(two One) bool {
if !one.CheckQuestion(two) {
log.Println("question mismatch")
return false
}
if !one.CheckAnswers(two) {
log.Println("answer mismatch")
return false
}
return true
}
func (one One) CheckQuestion(two One) bool {
log.Println(one.Question)
log.Println(two.Question)
log.Println(one.Question == (Question{}))
log.Println(two.Question == (Question{}))
log.Println(one.Question.Equals(two.Question.Pair))
return one.Question == (Question{}) || two.Question == (Question{}) || one.Question.Equals(two.Question.Pair)
}
func (one One) CheckAnswers(two One) bool {
log.Println(len(one.Answers), one.Answers)
log.Println(len(two.Answers), two.Answers)
if len(two.Answers) == 0 {
return false
}
for _, answer := range two.Answers {
log.Printf("%+v %s %v", answer, "with id", answer.ID)
oanswer := one.GetAnswer(answer.ID)
log.Println(" ", oanswer)
if oanswer == (Answer{}) {
return false
}
if !oanswer.Right {
return false
}
}
return true
}
func (one One) GetAnswer(id string) Answer {
for _, answer := range one.Answers {
log.Println(" ", answer, "==", id)
if answer.ID == id {
return answer
}
}
return Answer{}
}
func (one One) HasSolution() bool {
for i := range one.Answers {
if one.Answers[i].Right {
return true
}
}
return false
}

83
questions/storage/one_test.go Executable file
View File

@@ -0,0 +1,83 @@
package storage
import (
"encoding/json"
"testing"
)
func TestOneStrings(t *testing.T) {
raw := `{
"id":"my id",
"q":"my question",
"a":[
"my answer 0",
"my answer 1"
]
}`
var one One
if err := json.Unmarshal([]byte(raw), &one); err != nil {
t.Fatal(err)
}
if one.ID != "my id" {
t.Fatal(one.ID)
}
if one.Question.ID != "my question" {
t.Fatal(one.ID)
}
if len(one.Answers) != 2 {
t.Fatal(one.Answers)
}
if one.Answers[0].ID != "my answer 0" {
t.Fatal(one.Answers[0])
}
if one.Answers[1].ID != "my answer 1" {
t.Fatal(one.Answers[1])
}
}
func TestOneObj(t *testing.T) {
raw := `{
"id":"my id",
"q":{
"text": "my question"
},
"a":[
{"text": "my answer 0"},
{"text": "my answer 1"}
]
}`
var one One
if err := json.Unmarshal([]byte(raw), &one); err != nil {
t.Fatal(err)
}
if one.ID != "my id" {
t.Fatal(one.ID)
}
if one.Question.Text != "my question" {
t.Fatal(one.Question)
}
if len(one.Answers) != 2 {
t.Fatal(one.Answers)
}
if one.Answers[0].Text != "my answer 0" {
t.Fatal(one.Answers[0])
}
if one.Answers[1].Text != "my answer 1" {
t.Fatal(one.Answers[1])
}
}
func TestOneNonObj(t *testing.T) {
raw := `{
"id":"my id",
"q": [],
"a":[
[],
{}
]
}`
var one One
if err := json.Unmarshal([]byte(raw), &one); err == nil {
t.Fatal(err, one)
}
}

36
questions/storage/pair.go Executable file
View File

@@ -0,0 +1,36 @@
package storage
import (
"github.com/buger/jsonparser"
)
type Pair struct {
ID string `json:"id"`
Text string `json:"text"`
}
func New(id, text string) Pair {
return Pair{
Text: text,
ID: id,
}
}
func (p *Pair) UnmarshalJSON(b []byte) error {
var err error
if s, err := jsonparser.GetString(b); err == nil {
p.ID = s
return nil
}
if p.Text, err = jsonparser.GetString(b, "text"); err != nil {
return err
}
if p.ID, err = jsonparser.GetString(b, "id"); err != nil && err != jsonparser.KeyPathNotFoundError {
return err
}
return nil
}
func (p Pair) Equals(o Pair) bool {
return p == o
}

19
questions/storage/question.go Executable file
View File

@@ -0,0 +1,19 @@
package storage
import (
"strings"
)
const prefix_question = "question_"
type Question struct {
Pair
}
func NewQuestion(text string) Question {
return Question{New(prefix_question+NewID(), text)}
}
func IsQuestion(ID string) bool {
return strings.HasPrefix(ID, prefix_question)
}

View File

@@ -0,0 +1,34 @@
package storage
import (
"encoding/json"
"testing"
)
func TestUnmarshalQuestionObject(t *testing.T) {
raw := `{"text":"text here", "id":"id here"}`
var a Question
if err := json.Unmarshal([]byte(raw), &a); err != nil {
t.Fatal(err)
}
if a.Text != "text here" {
t.Fatal(a.Text)
}
if a.ID != "id here" {
t.Fatal(a.ID)
}
}
func TestUnmarshalQuestionString(t *testing.T) {
raw := `"text here"`
var a Question
if err := json.Unmarshal([]byte(raw), &a); err != nil {
t.Fatal(err)
}
if a.ID != "text here" {
t.Fatal(a.ID)
}
if a.Text != "" {
t.Fatal(a.Text)
}
}