handle dimension

This commit is contained in:
2024-02-11 15:50:43 +03:00
parent 0c7e94c834
commit e072fcbef5
13 changed files with 479 additions and 27 deletions

View File

@ -0,0 +1,142 @@
package entity
import (
"fmt"
"strconv"
"strings"
)
var DefaultLocale = DimensionLocalRU
type DimensionLocale uint8
const (
DimensionLocalUnspecified DimensionLocale = iota
DimensionLocalRU
dimensionLocalEnd
)
type DimensionKind uint8
func (k DimensionKind) GetPos() float64 {
switch k {
case DimensionKindMilimeter:
return 1
case DimensionKindCentimeter:
return 10
case DimensionKindMeter:
return 1000
default:
return 0
}
}
func (k DimensionKind) String() string {
m := getLocaleKindToStringMap()[DefaultLocale]
return m[k]
}
const (
DimensionKindUnspecified DimensionKind = iota
DimensionKindMilimeter
DimensionKindCentimeter
DimensionKindMeter
)
type Dimension struct {
Value float64
Kind DimensionKind
}
func (d Dimension) MarshalText() ([]byte, error) {
value := strconv.FormatFloat(d.Value, 'f', 4, 64) + " " + d.Kind.String()
return []byte(value), nil
}
func (d *Dimension) UnmarshalText(data []byte) (err error) {
*d, err = ParseDimention(string(data), DefaultLocale)
return err
}
func (d Dimension) AdjustTo(kind DimensionKind) Dimension {
from := d.Kind.GetPos()
to := kind.GetPos()
switch {
case from < to:
mult := to / from
return Dimension{
Kind: kind,
Value: d.Value / float64(mult),
}
case from > to:
mult := from / to
return Dimension{
Kind: kind,
Value: d.Value * float64(mult),
}
}
return d
}
func ParseDimention(value string, locale DimensionLocale) (Dimension, error) {
switch locale {
case DimensionLocalRU:
default:
return Dimension{}, SimpleError("unknown locale for parse")
}
dimensionStrToKind := getLocaleToKindMap()[locale]
lastSpaceIdx := strings.LastIndex(value, " ")
if lastSpaceIdx == -1 {
return Dimension{}, SimpleError("expected 2 values after split for value " + value)
}
var splitted [2]string
splitted[0] = strings.ReplaceAll(value[:lastSpaceIdx], " ", "")
splitted[1] = value[lastSpaceIdx+1:]
var out Dimension
var ok bool
out.Kind, ok = dimensionStrToKind[splitted[1]]
if !ok {
return Dimension{}, SimpleError("dimension map not found for kind " + splitted[1])
}
var err error
out.Value, err = strconv.ParseFloat(splitted[0], 64)
if err != nil {
return Dimension{}, fmt.Errorf("parsing value: %w", err)
}
return out, nil
}
func NewMilimeterDimension(value float64) Dimension {
return Dimension{
Value: value,
Kind: DimensionKindMilimeter,
}
}
func getLocaleToKindMap() map[DimensionLocale]map[string]DimensionKind {
return map[DimensionLocale]map[string]DimensionKind{
DimensionLocalRU: {
"мм": DimensionKindMilimeter,
"см": DimensionKindCentimeter,
"м": DimensionKindMeter,
},
}
}
func getLocaleKindToStringMap() map[DimensionLocale]map[DimensionKind]string {
return map[DimensionLocale]map[DimensionKind]string{
DimensionLocalRU: {
DimensionKindMilimeter: "мм",
DimensionKindCentimeter: "см",
DimensionKindMeter: "м",
},
}
}

View File

@ -0,0 +1,31 @@
package entity
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestLocaleMap(t *testing.T) {
kindToStr := getLocaleKindToStringMap()
strToKind := getLocaleToKindMap()
assert := assert.New(t)
for locale := DimensionLocalUnspecified + 1; locale < dimensionLocalEnd; locale++ {
localeKinds, ok := kindToStr[locale]
assert.True(ok)
localeStrs, ok := strToKind[locale]
assert.True(ok)
assert.Equal(len(localeKinds), len(localeStrs))
for kindKey, kindValue := range localeKinds {
strKey := kindValue
strValue, ok := localeStrs[strKey]
assert.True(ok)
assert.Equal(kindKey, strValue)
assert.Equal(strKey, kindValue)
}
}
}

View File

@ -0,0 +1,72 @@
package entity_test
import (
"errors"
"testing"
"git.loyso.art/frx/eway/internal/entity"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDimension_AdjustTo(t *testing.T) {
// Test adjusting from smaller dimension to larger one
d := entity.Dimension{Value: 5.0, Kind: entity.DimensionKindCentimeter}
expected := entity.Dimension{Value: 0.05, Kind: entity.DimensionKindMeter}
actual := d.AdjustTo(entity.DimensionKindMeter)
assert.EqualValues(t, expected.Value, actual.Value)
assert.Equal(t, expected.Kind, actual.Kind)
// Test adjusting from larger dimension to smaller one
d = entity.Dimension{Value: 0.05, Kind: entity.DimensionKindMeter}
expected = entity.Dimension{Value: 50.0, Kind: entity.DimensionKindMilimeter}
actual = d.AdjustTo(entity.DimensionKindMilimeter)
assert.EqualValues(t, expected.Value, actual.Value)
assert.Equal(t, expected.Kind, actual.Kind)
}
func TestParseDimension_Success(t *testing.T) {
// Test parsing a valid dimension string with RU locale
input := "10 см"
expected := entity.Dimension{Value: 10.0, Kind: entity.DimensionKindCentimeter}
actual, err := entity.ParseDimention(input, entity.DimensionLocalRU)
require.NoError(t, err)
assert.EqualValues(t, expected.Value, actual.Value)
assert.Equal(t, expected.Kind, actual.Kind)
}
func TestParseDimensionComplex_Success(t *testing.T) {
// Test parsing a valid dimension string with RU locale
input := "10 256.20 см"
expected := entity.Dimension{Value: 10256.20, Kind: entity.DimensionKindCentimeter}
actual, err := entity.ParseDimention(input, entity.DimensionLocalRU)
require.NoError(t, err)
assert.EqualValues(t, expected.Value, actual.Value)
assert.Equal(t, expected.Kind, actual.Kind)
}
func TestParseDimension_InvalidInputFormat(t *testing.T) {
// Test parsing an invalid dimension string with RU locale
input := "invalid value 2"
expectedErr := errors.New("expected 2 values after split for value invalid value 2")
_, err := entity.ParseDimention(input, entity.DimensionLocalRU)
assert.Error(t, err)
assert.EqualError(t, err, expectedErr.Error())
}
func TestParseDimension_InvalidLocale(t *testing.T) {
// Test parsing a dimension string with an unsupported locale
input := "10 мм"
expectedErr := errors.New("unknown locale for parse")
_, err := entity.ParseDimention(input, 3) // An invalid locale value is used here for demonstration purposes
assert.EqualError(t, err, expectedErr.Error())
}

3
internal/entity/empty.go Normal file
View File

@ -0,0 +1,3 @@
package entity
type Empty struct{}

View File

@ -8,6 +8,26 @@ import (
"unicode"
)
type GoodsItemSize struct {
Width Dimension
Height Dimension
Length Dimension
}
func (s GoodsItemSize) GetSum(kind DimensionKind) float64 {
var value float64
sum := func(ds ...Dimension) {
for _, d := range ds {
value += d.AdjustTo(kind).Value
}
}
sum(s.Height, s.Length, s.Length)
return value
}
type GoodsItem struct {
Articul string `json:"sku"`
PhotoURLs []string `json:"photo"`
@ -22,6 +42,7 @@ type GoodsItem struct {
TariffPrice float64 `json:"tariff_price"`
Cart int64 `json:"cart"`
Stock int `json:"stock"`
Sizes GoodsItemSize `json:"sizes"`
Parameters map[string]string `json:"parameters"`
CreatedAt time.Time `json:"created_at"`
}