initial
This commit is contained in:
35
questions/storage/answer.go
Executable file
35
questions/storage/answer.go
Executable 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
|
||||
}
|
||||
34
questions/storage/answer_test.go
Executable file
34
questions/storage/answer_test.go
Executable 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
7
questions/storage/id.go
Executable 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
115
questions/storage/one.go
Executable 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
83
questions/storage/one_test.go
Executable 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
36
questions/storage/pair.go
Executable 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
19
questions/storage/question.go
Executable 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)
|
||||
}
|
||||
34
questions/storage/question_test.go
Executable file
34
questions/storage/question_test.go
Executable 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user