Решение на Concurrent Tasks от Андон Мицов

Обратно към всички решения

Към профила на Андон Мицов

Резултати

  • 3 точки от тестове
  • 0 бонус точки
  • 3 точки общо
  • 3 успешни тест(а)
  • 7 неуспешни тест(а)

Код

package main
import (
"encoding/json"
"encoding/xml"
"fmt"
"sync"
)
type Library interface {
AddBookJSON(data []byte) (int, error)
AddBookXML(data []byte) (int, error)
Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
}
type LibraryRequest interface {
GetType() int
GetISBN() string
}
type LibraryResponse interface {
GetBook() (fmt.Stringer, error)
GetAvailability() (int,int)
}
type Author struct {
FirstName string
LastName string
}
type Book struct {
isbn string
title string
author Author
genre string
pages int
ratings []float64
}
func (a *Author) UnmarshalJSON(data []byte) error {
var jsonData struct{ first_name, last_name string }
if err := json.Unmarshal(data, jsonData); err != nil {
return err
}
a.FirstName = jsonData.first_name
a.LastName = jsonData.last_name
return nil
}
func (b *Book) UnmarshalJSON(rawData []byte) error {
var jsonData struct {
isbn, title, author, genre string
pages int
ratings []float64
}
if err := json.Unmarshal(rawData, jsonData); err != nil {
return err
}
if err := json.Unmarshal([]byte(jsonData.author), b.author); err != nil {
return err
}
b.isbn = jsonData.isbn
b.title = jsonData.title
b.genre = jsonData.genre
b.pages = jsonData.pages
b.ratings = jsonData.ratings
return nil
}
func (a *Author) UnmarshalXML(data []byte) error {
var xmlData struct{ first_name, last_name string }
if err := xml.Unmarshal(data, xmlData); err != nil {
return err
}
a.FirstName = xmlData.first_name
a.LastName = xmlData.last_name
return nil
}
func (b *Book) UnmarshalXML(rawData []byte) error {
var xmlData struct {
isbn, title, author, genre string
pages int
ratings []float64
}
if err := xml.Unmarshal(rawData, xmlData); err != nil {
return err
}
if err := xml.Unmarshal([]byte(xmlData.author), b.author); err != nil {
return err
}
b.isbn = xmlData.isbn
b.title = xmlData.title
b.genre = xmlData.genre
b.pages = xmlData.pages
b.ratings = xmlData.ratings
return nil
}
func (b *Book) String() string {
return fmt.Sprintf("[%s] %s от %s", b.isbn, b.title, b.author)
}
type LibError struct {
errorMessage string
}
func (e LibError) Error() string {
return e.errorMessage
}
type LibraryRecord struct {
b Book
available int
total int
}
type PublicLibrary struct {
bookMutex *sync.Mutex
libMutex *sync.Mutex
workingLibrarians int
maxLibrarians int
books map[string]LibraryRecord
}
type PublicLibraryResponse struct {
book *Book
err *LibError
available int
registered int
}
func (resp PublicLibraryResponse) GetBook() (fmt.Stringer, error) {
return fmt.Stringer(resp.book), resp.err
}
func (resp PublicLibraryResponse) GetAvailability() (average int, registered int) {
return resp.available, resp.registered
}
func (l *PublicLibrary) AddBookJSON(data []byte) (int, error) {
var book Book
var total int = 0
if err := json.Unmarshal(data, book); err != nil {
return 0, err
}
bookRecord, ok := l.books[book.isbn]
if !ok {
newB := &LibraryRecord{b: book, available: 1, total: 1}
l.books[book.isbn] = *newB
total = newB.total
} else {
if bookRecord.total >= 4 {
var err LibError = LibError{errorMessage: fmt.Sprintf("Има 4 копия на книга %s", book.isbn)}
total = 4
return total, error(err)
} else {
bookRecord.available++
bookRecord.total++
l.books[book.isbn] = bookRecord
total = bookRecord.total
}
}
return total, nil
}
func (l *PublicLibrary) AddBookXML(data []byte) (int, error) {
var book Book
var total int = 0
if err := xml.Unmarshal(data, book); err != nil {
return 0, error(err)
}
bookRecord, ok := l.books[book.isbn]
if !ok {
newB := &LibraryRecord{b: book, available: 1, total: 1}
l.books[book.isbn] = *newB
total = newB.total
} else {
if bookRecord.total >= 4 {
var err LibError = LibError{errorMessage: fmt.Sprintf("Има 4 копия на книга %s", book.isbn)}
total = 4
return total, error(err)
} else {
bookRecord.available++
bookRecord.total++
l.books[book.isbn] = bookRecord
total = bookRecord.total
}
}
return total, nil
}
func (l *PublicLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
var reqChanel chan LibraryRequest = make(chan LibraryRequest, 5)
var respChanel chan LibraryResponse = make(chan LibraryResponse, 5)
if l.workingLibrarians == l.maxLibrarians {
for l.workingLibrarians == l.maxLibrarians {
}
}
go func() {
l.libMutex.Lock()
l.workingLibrarians++
l.libMutex.Unlock()
for request := range reqChanel {
l.bookMutex.Lock()
b, ok := l.books[request.GetISBN()]
if !ok {
e := &LibError{fmt.Sprintf("Непозната книга %s", request.GetISBN())}
var resp PublicLibraryResponse = PublicLibraryResponse{ nil, e, 0, 0}
respChanel <- resp
} else {
switch request.GetType() {
case 1:
{
if b.available == 0 {
e := &LibError{fmt.Sprintf("Няма в наличност от книга %s", request.GetISBN())}
var resp PublicLibraryResponse = PublicLibraryResponse{ &b.b, e, 0, b.total}
respChanel <- resp
} else {
b.available--
var resp PublicLibraryResponse = PublicLibraryResponse{ &b.b,nil,b.available,b.total}
respChanel <- resp
l.books[request.GetISBN()] = b
}
}
case 2:
{
if b.available == b.total {
e := &LibError{fmt.Sprintf("Всички копия са налични %s", request.GetISBN())}
var resp PublicLibraryResponse = PublicLibraryResponse{&(b.b), e, b.available,b.total}
respChanel <- resp
} else {
b.available++
l.books[request.GetISBN()] = b
var resp PublicLibraryResponse = PublicLibraryResponse{&(b.b),nil,b.available,b.total}
respChanel <- resp
}
}
case 3:
{
var resp PublicLibraryResponse = PublicLibraryResponse{&(b.b),nil,b.available,b.total}
respChanel <- resp
}
}
}
l.bookMutex.Unlock()
}
close(respChanel)
l.libMutex.Lock()
l.workingLibrarians--
l.libMutex.Unlock()
}()
return reqChanel, respChanel
}
func NewLibrary(librarians int) Library {
libM := new(sync.Mutex)
bookM := new(sync.Mutex)
lib := &PublicLibrary{bookMutex: bookM, libMutex: libM, workingLibrarians: 0, maxLibrarians: librarians, books: make(map[string]LibraryRecord)}
return lib
}

Лог от изпълнението

PASS
ok  	_/tmp/d20151207-5667-1btg02v	0.003s
--- FAIL: TestAddBookJSON (0.00s)
	solution_test.go:82: [solution_test.go:106] Expected:
		<nil>
		Got:
		json: Unmarshal(non-pointer main.Book)
		Context: Error when adding a valid book
	solution_test.go:82: [solution_test.go:107] Expected:
		1
		Got:
		0
		Context: first book added
	solution_test.go:82: [solution_test.go:110] Expected:
		2
		Got:
		0
		Context: first book added 2nd time
	solution_test.go:82: [solution_test.go:113] Expected:
		3
		Got:
		0
		Context: first book added 3rd time
	solution_test.go:82: [solution_test.go:116] Expected:
		4
		Got:
		0
		Context: first book added 4th time
	solution_test.go:82: [solution_test.go:119] Expected:
		Има 4 копия на книга 0954540018
		Got:
		<nil>
		Context: Error when adding a book for 5th time
	solution_test.go:82: [solution_test.go:129] Expected:
		<nil>
		Got:
		Непозната книга 0954540018
		Context: Error when getting a valid book
FAIL
exit status 1
FAIL	_/tmp/d20151207-5667-1btg02v	0.004s
--- FAIL: TestAddBookXML (0.00s)
	solution_test.go:82: [solution_test.go:136] Expected:
		<nil>
		Got:
		non-pointer passed to Unmarshal
		Context: Error when adding a valid book
	solution_test.go:82: [solution_test.go:137] Expected:
		1
		Got:
		0
		Context: first book added
	solution_test.go:82: [solution_test.go:140] Expected:
		2
		Got:
		0
		Context: first book added 2nd time
	solution_test.go:82: [solution_test.go:143] Expected:
		3
		Got:
		0
		Context: first book added 3rd time
	solution_test.go:82: [solution_test.go:146] Expected:
		4
		Got:
		0
		Context: first book added 4th time
	solution_test.go:82: [solution_test.go:149] Expected:
		Има 4 копия на книга 0954540018
		Got:
		<nil>
		Context: Error when adding a book for 5th time
	solution_test.go:82: [solution_test.go:159] Expected:
		<nil>
		Got:
		Непозната книга 0954540018
		Context: Error when getting a valid book
FAIL
exit status 1
FAIL	_/tmp/d20151207-5667-1btg02v	0.003s
--- FAIL: TestAddBookCombined (0.00s)
	solution_test.go:82: [solution_test.go:167] Expected:
		<nil>
		Got:
		non-pointer passed to Unmarshal
		Context: Error when adding a valid book
	solution_test.go:82: [solution_test.go:168] Expected:
		1
		Got:
		0
		Context: first book added
	solution_test.go:82: [solution_test.go:171] Expected:
		<nil>
		Got:
		json: Unmarshal(non-pointer main.Book)
		Context: Error when adding a valid book
	solution_test.go:82: [solution_test.go:172] Expected:
		2
		Got:
		0
		Context: first book added 2nd time
	solution_test.go:82: [solution_test.go:175] Expected:
		3
		Got:
		0
		Context: first book added 3rd time
	solution_test.go:82: [solution_test.go:176] Expected:
		<nil>
		Got:
		non-pointer passed to Unmarshal
		Context: Error when adding a valid book
	solution_test.go:82: [solution_test.go:179] Expected:
		4
		Got:
		0
		Context: first book added 4th time
	solution_test.go:82: [solution_test.go:180] Expected:
		<nil>
		Got:
		json: Unmarshal(non-pointer main.Book)
		Context: Error when adding a valid book
	solution_test.go:82: [solution_test.go:183] Expected:
		<nil>
		Got:
		non-pointer passed to Unmarshal
		Context: Error when adding a book for 5th time
	solution_test.go:82: [solution_test.go:193] Expected:
		<nil>
		Got:
		Непозната книга 0954540018
		Context: Error when getting a valid book
FAIL
exit status 1
FAIL	_/tmp/d20151207-5667-1btg02v	0.004s
--- FAIL: TestBookAvailability (0.00s)
	solution_test.go:82: [solution_test.go:202] Expected:
		<nil>
		Got:
		json: Unmarshal(non-pointer main.Book)
		Context: error when adding a valid book
	solution_test.go:82: [solution_test.go:203] Expected:
		1
		Got:
		0
		Context: first book added 1st time
	solution_test.go:82: [solution_test.go:206] Expected:
		<nil>
		Got:
		json: Unmarshal(non-pointer main.Book)
		Context: error when adding a valid book
	solution_test.go:82: [solution_test.go:207] Expected:
		2
		Got:
		0
		Context: first book added 2nd time
	solution_test.go:82: [solution_test.go:216] Expected:
		2
		Got:
		0
		Context: we have registered 2 copies
	solution_test.go:82: [solution_test.go:217] Expected:
		2
		Got:
		0
		Context: should have 2 copies available
FAIL
exit status 1
FAIL	_/tmp/d20151207-5667-1btg02v	0.003s
--- FAIL: TestTakeBookRequest (0.00s)
	solution_test.go:82: [solution_test.go:258] Expected:
		Няма наличност на книга 0954540018
		Got:
		Непозната книга 0954540018
		Context: should get error when getting a book that is unavailable
FAIL
exit status 1
FAIL	_/tmp/d20151207-5667-1btg02v	0.003s
--- FAIL: TestBookStringer (0.00s)
	solution_test.go:278: Expected nil but got error Непозната книга 0954540018
FAIL
exit status 1
FAIL	_/tmp/d20151207-5667-1btg02v	0.003s
PASS
ok  	_/tmp/d20151207-5667-1btg02v	0.003s
--- FAIL: TestReturnSomeBooks (0.00s)
	solution_test.go:82: [solution_test.go:353] Expected:
		Всички копия са налични 0954540018
		Got:
		Непозната книга 0954540018
		Context: Error when returning too much copies
FAIL
exit status 1
FAIL	_/tmp/d20151207-5667-1btg02v	0.003s
PASS
ok  	_/tmp/d20151207-5667-1btg02v	0.003s

История (1 версия и 0 коментара)

Андон обнови решението на 06.12.2015 17:58 (преди над 2 години)

+package main
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "sync"
+)
+
+type Library interface {
+ AddBookJSON(data []byte) (int, error)
+
+ AddBookXML(data []byte) (int, error)
+
+ Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
+}
+
+type LibraryRequest interface {
+ GetType() int
+
+ GetISBN() string
+}
+
+type LibraryResponse interface {
+ GetBook() (fmt.Stringer, error)
+
+ GetAvailability() (int,int)
+}
+
+type Author struct {
+ FirstName string
+ LastName string
+}
+
+type Book struct {
+ isbn string
+ title string
+ author Author
+ genre string
+ pages int
+ ratings []float64
+}
+
+func (a *Author) UnmarshalJSON(data []byte) error {
+ var jsonData struct{ first_name, last_name string }
+
+ if err := json.Unmarshal(data, jsonData); err != nil {
+ return err
+ }
+
+ a.FirstName = jsonData.first_name
+ a.LastName = jsonData.last_name
+
+ return nil
+}
+
+func (b *Book) UnmarshalJSON(rawData []byte) error {
+ var jsonData struct {
+ isbn, title, author, genre string
+ pages int
+ ratings []float64
+ }
+
+ if err := json.Unmarshal(rawData, jsonData); err != nil {
+ return err
+ }
+
+ if err := json.Unmarshal([]byte(jsonData.author), b.author); err != nil {
+ return err
+ }
+
+ b.isbn = jsonData.isbn
+ b.title = jsonData.title
+ b.genre = jsonData.genre
+ b.pages = jsonData.pages
+ b.ratings = jsonData.ratings
+ return nil
+}
+
+func (a *Author) UnmarshalXML(data []byte) error {
+ var xmlData struct{ first_name, last_name string }
+
+ if err := xml.Unmarshal(data, xmlData); err != nil {
+ return err
+ }
+
+ a.FirstName = xmlData.first_name
+ a.LastName = xmlData.last_name
+
+ return nil
+}
+
+func (b *Book) UnmarshalXML(rawData []byte) error {
+ var xmlData struct {
+ isbn, title, author, genre string
+ pages int
+ ratings []float64
+ }
+
+ if err := xml.Unmarshal(rawData, xmlData); err != nil {
+ return err
+ }
+
+ if err := xml.Unmarshal([]byte(xmlData.author), b.author); err != nil {
+ return err
+ }
+
+ b.isbn = xmlData.isbn
+ b.title = xmlData.title
+ b.genre = xmlData.genre
+ b.pages = xmlData.pages
+ b.ratings = xmlData.ratings
+ return nil
+}
+
+func (b *Book) String() string {
+ return fmt.Sprintf("[%s] %s от %s", b.isbn, b.title, b.author)
+}
+
+type LibError struct {
+ errorMessage string
+}
+
+func (e LibError) Error() string {
+ return e.errorMessage
+}
+
+type LibraryRecord struct {
+ b Book
+ available int
+ total int
+}
+
+type PublicLibrary struct {
+ bookMutex *sync.Mutex
+ libMutex *sync.Mutex
+ workingLibrarians int
+ maxLibrarians int
+ books map[string]LibraryRecord
+}
+
+type PublicLibraryResponse struct {
+ book *Book
+ err *LibError
+
+ available int
+ registered int
+}
+
+func (resp PublicLibraryResponse) GetBook() (fmt.Stringer, error) {
+ return fmt.Stringer(resp.book), resp.err
+}
+
+func (resp PublicLibraryResponse) GetAvailability() (average int, registered int) {
+ return resp.available, resp.registered
+}
+
+func (l *PublicLibrary) AddBookJSON(data []byte) (int, error) {
+ var book Book
+ var total int = 0
+ if err := json.Unmarshal(data, book); err != nil {
+ return 0, err
+ }
+
+ bookRecord, ok := l.books[book.isbn]
+
+ if !ok {
+ newB := &LibraryRecord{b: book, available: 1, total: 1}
+ l.books[book.isbn] = *newB
+ total = newB.total
+ } else {
+ if bookRecord.total >= 4 {
+ var err LibError = LibError{errorMessage: fmt.Sprintf("Има 4 копия на книга %s", book.isbn)}
+ total = 4
+ return total, error(err)
+ } else {
+ bookRecord.available++
+ bookRecord.total++
+ l.books[book.isbn] = bookRecord
+ total = bookRecord.total
+ }
+ }
+
+ return total, nil
+}
+
+func (l *PublicLibrary) AddBookXML(data []byte) (int, error) {
+ var book Book
+ var total int = 0
+ if err := xml.Unmarshal(data, book); err != nil {
+ return 0, error(err)
+ }
+
+ bookRecord, ok := l.books[book.isbn]
+
+ if !ok {
+ newB := &LibraryRecord{b: book, available: 1, total: 1}
+ l.books[book.isbn] = *newB
+ total = newB.total
+ } else {
+ if bookRecord.total >= 4 {
+ var err LibError = LibError{errorMessage: fmt.Sprintf("Има 4 копия на книга %s", book.isbn)}
+ total = 4
+ return total, error(err)
+ } else {
+ bookRecord.available++
+ bookRecord.total++
+ l.books[book.isbn] = bookRecord
+ total = bookRecord.total
+ }
+ }
+
+ return total, nil
+}
+
+func (l *PublicLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+ var reqChanel chan LibraryRequest = make(chan LibraryRequest, 5)
+ var respChanel chan LibraryResponse = make(chan LibraryResponse, 5)
+
+ if l.workingLibrarians == l.maxLibrarians {
+ for l.workingLibrarians == l.maxLibrarians {
+ }
+ }
+
+ go func() {
+ l.libMutex.Lock()
+ l.workingLibrarians++
+ l.libMutex.Unlock()
+
+ for request := range reqChanel {
+ l.bookMutex.Lock()
+ b, ok := l.books[request.GetISBN()]
+ if !ok {
+ e := &LibError{fmt.Sprintf("Непозната книга %s", request.GetISBN())}
+ var resp PublicLibraryResponse = PublicLibraryResponse{ nil, e, 0, 0}
+ respChanel <- resp
+ } else {
+ switch request.GetType() {
+ case 1:
+ {
+ if b.available == 0 {
+ e := &LibError{fmt.Sprintf("Няма в наличност от книга %s", request.GetISBN())}
+ var resp PublicLibraryResponse = PublicLibraryResponse{ &b.b, e, 0, b.total}
+ respChanel <- resp
+ } else {
+ b.available--
+ var resp PublicLibraryResponse = PublicLibraryResponse{ &b.b,nil,b.available,b.total}
+ respChanel <- resp
+ l.books[request.GetISBN()] = b
+ }
+
+ }
+ case 2:
+ {
+ if b.available == b.total {
+ e := &LibError{fmt.Sprintf("Всички копия са налични %s", request.GetISBN())}
+ var resp PublicLibraryResponse = PublicLibraryResponse{&(b.b), e, b.available,b.total}
+ respChanel <- resp
+ } else {
+ b.available++
+ l.books[request.GetISBN()] = b
+ var resp PublicLibraryResponse = PublicLibraryResponse{&(b.b),nil,b.available,b.total}
+ respChanel <- resp
+ }
+
+ }
+ case 3:
+ {
+ var resp PublicLibraryResponse = PublicLibraryResponse{&(b.b),nil,b.available,b.total}
+ respChanel <- resp
+ }
+ }
+ }
+ l.bookMutex.Unlock()
+ }
+
+ close(respChanel)
+
+ l.libMutex.Lock()
+ l.workingLibrarians--
+ l.libMutex.Unlock()
+ }()
+
+ return reqChanel, respChanel
+}
+
+func NewLibrary(librarians int) Library {
+ libM := new(sync.Mutex)
+ bookM := new(sync.Mutex)
+ lib := &PublicLibrary{bookMutex: bookM, libMutex: libM, workingLibrarians: 0, maxLibrarians: librarians, books: make(map[string]LibraryRecord)}
+ return lib
+}