Написал недостающие юнит тесты.

This commit is contained in:
Andrey Ivanov 2020-10-30 17:27:07 +03:00 committed by Andrey Ivanov
parent 676d7e2bd9
commit e87099550a
3 changed files with 245 additions and 11 deletions

View File

@ -0,0 +1,57 @@
package application
import (
"github.com/stretchr/testify/require"
"net/url"
"testing"
)
func TestBuildQuery(t *testing.T) {
urlParcer := func(u string) *url.URL {
res, _ := url.Parse(u)
return res
}
table := []struct {
url *url.URL
expWidth int
expHeight int
expURL *url.URL
err bool
msg string
}{
{
url: urlParcer("/fill/10/10/domain.me/some/pic.jpg"), expWidth: 10, expHeight: 10, expURL: urlParcer("http://domain.me/some/pic.jpg"), err: false, msg: "Normal request",
},
{
url: urlParcer("/fill/10/10/pic.jpg"), expWidth: 10, expHeight: 10, expURL: urlParcer("http://pic.jpg"), err: false, msg: "Short URL",
},
{
url: urlParcer("/fill/10"), expWidth: 0, expHeight: 0, expURL: nil, err: true, msg: "Only width",
},
{
url: urlParcer("/fill/10/10"), expWidth: 0, expHeight: 0, expURL: nil, err: true, msg: "Only dimensions",
},
{
url: urlParcer("/fill/qwew/qwew/domain.me/some/pic.jpg"), expWidth: 0, expHeight: 0, expURL: nil, err: true, msg: "Strings in dimensions",
},
{
url: urlParcer("/fill/domain.me/some/pic.jpg"), expWidth: 0, expHeight: 0, expURL: nil, err: true, msg: "No dimensions",
},
}
for _, dat := range table {
t.Run(dat.msg, func(t *testing.T) {
i := false
query, err := buildQuery(dat.url)
if err != nil {
i = true
}
require.Equal(t, dat.err, i, dat.msg)
require.Equal(t, dat.expWidth, query.Width, dat.msg)
require.Equal(t, dat.expHeight, query.Height, dat.msg)
require.Equal(t, dat.expURL, query.URL, dat.msg)
})
}
}

View File

@ -9,12 +9,14 @@ import (
"image/jpeg"
"image/png"
"net/http"
"sync"
"github.com/nfnt/resize"
)
type Image struct {
image.Image
mx sync.Mutex
}
func SelectType(width int, height int, b []byte) ([]byte, error) {
@ -64,13 +66,17 @@ func SelectType(width int, height int, b []byte) ([]byte, error) {
if err != nil {
return nil, err
}
m := Image{i}
m := NewImage(i)
if err = m.convert(width, height); err != nil {
return nil, err
}
return encode(m.Image)
}
func NewImage(img image.Image) Image {
return Image{img, sync.Mutex{}}
}
func (img *Image) convert(width int, height int) error {
widthOrig := img.Bounds().Max.X
heightOrig := img.Bounds().Max.Y
@ -79,19 +85,22 @@ func (img *Image) convert(width int, height int) error {
switch {
case sfOriginal > sfNew:
// Ресайз по одной высоте и кроп по ширине следом
// Определение ширины кропа.
calcWidth := int(float64(height) * sfOriginal)
img.resize(calcWidth, height)
if err := img.resize(calcWidth, height); err != nil {
return err
}
if err := img.crop(image.Point{X: (calcWidth - width) / 2, Y: 0}, image.Point{X: (calcWidth-width)/2 + width, Y: height}); err != nil {
return err
}
case sfOriginal == sfNew:
img.resize(width, height)
if err := img.resize(width, height); err != nil {
return err
}
case sfOriginal < sfNew:
// Ресайз по одной ширине и кроп по высоте следом
calcHeight := int(float64(width) / sfOriginal)
img.resize(width, calcHeight)
if err := img.resize(width, calcHeight); err != nil {
return err
}
if err := img.crop(image.Point{X: 0, Y: (calcHeight - height) / 2}, image.Point{X: width, Y: (calcHeight-height)/2 + height}); err != nil {
return err
}
@ -99,15 +108,24 @@ func (img *Image) convert(width int, height int) error {
return nil
}
func (img *Image) resize(width, height int) {
img.Image = resize.Resize(uint(width), uint(height), img, resize.Bicubic)
func (img *Image) resize(width, height int) error {
img.mx.Lock()
defer img.mx.Unlock()
if width <= 0 || height <= 0 {
return errors.New("can't resize to zero or negative value")
}
tmpImg := resize.Resize(uint(width), uint(height), img, resize.Bicubic)
img.Image = tmpImg
return nil
}
func (img *Image) crop(p1 image.Point, p2 image.Point) error {
if img == nil {
img.mx.Lock()
defer img.mx.Unlock()
if img.Image == nil {
return errors.New("corrupted image")
}
if p1.X < 0 || p1.Y < 0 || p2.X < 0 || p2.Y < 0 {
if p1.X < 0 || p1.Y < 0 || p2.X > img.Image.Bounds().Max.X || p2.Y > img.Image.Bounds().Max.Y {
return errors.New("not valid corner points")
}
b := image.Rect(0, 0, p2.X-p1.X, p2.Y-p1.Y)

View File

@ -0,0 +1,159 @@
package converter
import (
"github.com/stretchr/testify/require"
"image"
"image/color"
"testing"
)
func TestResize(t *testing.T) {
table := []struct {
width int
height int
expectedX int
expectedY int
err bool
msg string
}{
{
width: 300, height: 200, expectedX: 300, expectedY: 200, err: false, msg: "Reducing the image size",
},
{
width: 1600, height: 1200, expectedX: 1600, expectedY: 1200, err: false, msg: "Increasing the image size",
},
{
width: 0, height: 0, expectedX: 800, expectedY: 600, err: true, msg: "Resize to zero",
},
{
width: -1000, height: -1200, expectedX: 800, expectedY: 600, err: true, msg: "Use negative values",
},
}
for _, dat := range table {
t.Run(dat.msg, func(t *testing.T) {
img := Image{Image: createImage(800, 600)}
i := false
err := img.resize(dat.width, dat.height)
if err != nil {
i = true
}
require.Equal(t, dat.err, i, dat.msg)
require.Equal(t, dat.expectedX, img.Bounds().Max.X, dat.msg)
require.Equal(t, dat.expectedY, img.Bounds().Max.Y, dat.msg)
})
}
}
func TestCrop(t *testing.T) {
table := []struct {
topLeft image.Point
bottomRight image.Point
expectedX int
expectedY int
err bool
msg string
}{
{
topLeft: image.Point{X: 400, Y: 0}, bottomRight: image.Point{X: 600, Y: 1000}, expectedX: 200, expectedY: 1000, err: false, msg: "Vertical crop",
},
{
topLeft: image.Point{X: 0, Y: 400}, bottomRight: image.Point{X: 1000, Y: 600}, expectedX: 1000, expectedY: 200, err: false, msg: "Horizontal crop",
},
{
topLeft: image.Point{X: 100, Y: 100}, bottomRight: image.Point{X: 900, Y: 900}, expectedX: 800, expectedY: 800, err: false, msg: "Square crop",
},
{
topLeft: image.Point{X: -100, Y: 0}, bottomRight: image.Point{X: 2000, Y: 1000}, expectedX: 1000, expectedY: 1000, err: true, msg: "Too wide crop with negative offset",
},
{
topLeft: image.Point{X: 0, Y: -100}, bottomRight: image.Point{X: 1000, Y: 2000}, expectedX: 1000, expectedY: 1000, err: true, msg: "Too tall crop with negative offset",
},
{
topLeft: image.Point{X: 100, Y: 0}, bottomRight: image.Point{X: 2000, Y: 1000}, expectedX: 1000, expectedY: 1000, err: true, msg: "Too wide crop with positive offset",
},
{
topLeft: image.Point{X: 0, Y: 100}, bottomRight: image.Point{X: 1000, Y: 2000}, expectedX: 1000, expectedY: 1000, err: true, msg: "Too tall crop with positive offset",
},
}
for _, dat := range table {
t.Run(dat.msg, func(t *testing.T) {
img := Image{Image: createImage(1000, 1000)}
i := false
err := img.crop(dat.topLeft, dat.bottomRight)
if err != nil {
i = true
}
require.Equal(t, dat.err, i, dat.msg)
require.Equal(t, dat.expectedX, img.Image.Bounds().Max.X, dat.msg)
require.Equal(t, dat.expectedY, img.Image.Bounds().Max.Y, dat.msg)
})
}
}
/*
func TestConvert(t *testing.T) {
originalAspect := 800.0 / 600.0
releasedValue := 3000
table := []struct {
width int
height int
expectedX int
expectedY int
err bool
msg string
}{
{
width: 400, height: 600, expectedX: 400, expectedY: int(400 / originalAspect), err: false, msg: "Reducing the image size by horizontal",
},
{
width: 800, height: 400, expectedX: int(400 * originalAspect), expectedY: 400, err: false, msg: "Reducing the image size by vertical",
},
{
width: 400, height: int(400 / originalAspect), expectedX: 400, expectedY: int(400 / originalAspect), err: false, msg: "Resize to original aspect ratio",
},
{
width: 1000, height: releasedValue, expectedX: 1000, expectedY: int(1000 / originalAspect), err: false, msg: "Increasing the image size by horizontal",
},
{
width: releasedValue, height: 1000, expectedX: int(1000 * originalAspect), expectedY: 1000, err: false, msg: "Increasing the image size by vertical",
},
{
width: 0, height: 0, expectedX: 800, expectedY: 600, err: true, msg: "Resize to zero",
},
{
width: -1000, height: -1200, expectedX: 800, expectedY: 600, err: true, msg: "Use negative values",
},
}
for _, dat := range table {
t.Run(dat.msg, func(t *testing.T) {
img := Image{Image: createImage(800, 600)}
i := false
err := img.convert(dat.width, dat.height)
if err != nil {
i = true
}
require.Equal(t, dat.err, i, dat.msg)
require.Equal(t, dat.expectedX, img.Image.Bounds().Max.X, dat.msg)
require.Equal(t, dat.expectedY, img.Image.Bounds().Max.Y, dat.msg)
})
}
}
*/
func createImage(w, h int) image.Image {
res := image.NewRGBA(image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: w, Y: h}})
for x := 0; x < w; x++ {
for y := 0; y < h; y++ {
switch {
case x%10 == 0 || y%10 == 00: // upper left quadrant
res.Set(x, y, color.Black)
default:
res.Set(x, y, color.White)
}
}
}
return res
}