Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion bit_matrix.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,4 +389,9 @@ func (b *BitMatrix) ToStringWithLineSeparator(setString, unsetString, lineSepara
return string(result)
}

// public BitMatrix clone()
// Clone returns a deep copy of the BitMatrix.
func (b *BitMatrix) Clone() *BitMatrix {
bits := make([]uint32, len(b.bits))
copy(bits, b.bits)
return &BitMatrix{b.width, b.height, b.rowSize, bits}
}
31 changes: 31 additions & 0 deletions bit_matrix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,3 +449,34 @@ func TestBitMatrix_String(t *testing.T) {
t.Fatalf("String is\n%s\nexpect:\n%s", r, s2)
}
}

func TestBitMatrix_Clone(t *testing.T) {
original, _ := NewBitMatrix(8, 8)
original.Set(0, 0)
original.Set(3, 4)
original.Set(7, 7)

clone := original.Clone()

if clone.GetWidth() != original.GetWidth() || clone.GetHeight() != original.GetHeight() {
t.Fatalf("Clone dimensions %dx%d != original %dx%d",
clone.GetWidth(), clone.GetHeight(), original.GetWidth(), original.GetHeight())
}
for y := 0; y < 8; y++ {
for x := 0; x < 8; x++ {
if clone.Get(x, y) != original.Get(x, y) {
t.Errorf("Clone differs at (%d, %d): got %v, want %v",
x, y, clone.Get(x, y), original.Get(x, y))
}
}
}

clone.Flip(0, 0)
clone.Set(1, 1)
if !original.Get(0, 0) {
t.Error("Mutating clone affected original at (0, 0)")
}
if original.Get(1, 1) {
t.Error("Mutating clone affected original at (1, 1)")
}
}
5 changes: 4 additions & 1 deletion qrcode/decoder/bit_matrix_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ func NewBitMatrixParser(bitMatrix *gozxing.BitMatrix) (*BitMatrixParser, error)
if dimension < 21 || (dimension&0x03) != 1 {
return nil, gozxing.NewFormatException("dimension = %v", dimension)
}
return &BitMatrixParser{bitMatrix: bitMatrix}, nil
// Clone the matrix so that mutations during decoding (UnmaskBitMatrix,
// Remask, Mirror) do not corrupt the shared cached copy returned by
// BinaryBitmap.GetBlackMatrix().
return &BitMatrixParser{bitMatrix: bitMatrix.Clone()}, nil
}

func (this *BitMatrixParser) ReadFormatInformation() (*FormatInformation, error) {
Expand Down
14 changes: 7 additions & 7 deletions qrcode/decoder/bit_matrix_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ func TestNewBitMatrixParser(t *testing.T) {
if e != nil {
t.Fatalf("NewBitMatrixParser(21x21) returns error, %v", e)
}
if p.bitMatrix != img {
t.Fatalf("p.bitMatrix = %p, expect %p", p.bitMatrix, img)
if p.bitMatrix == img {
t.Fatalf("p.bitMatrix must be a clone, not the same pointer")
}
if p.parsedVersion != nil {
t.Fatalf("p.parsedVersion is not nil, %p", p.parsedVersion)
Expand Down Expand Up @@ -313,14 +313,14 @@ func TestBitMatrixParser_Remask(t *testing.T) {
p, _ := NewBitMatrixParser(img)

p.Remask()
compareBitMatrix(t, img, unmasked)
compareBitMatrix(t, p.bitMatrix, unmasked)

p.ReadFormatInformation()
p.Remask()
compareBitMatrix(t, img, masked)
compareBitMatrix(t, p.bitMatrix, masked)

p.Remask()
compareBitMatrix(t, img, unmasked)
compareBitMatrix(t, p.bitMatrix, unmasked)
}

func TestBitMatrixParser_Mirror(t *testing.T) {
Expand Down Expand Up @@ -352,8 +352,8 @@ func TestBitMatrixParser_Mirror(t *testing.T) {
p, _ := NewBitMatrixParser(img)

p.Mirror()
compareBitMatrix(t, img, mirrored)
compareBitMatrix(t, p.bitMatrix, mirrored)

p.Mirror()
compareBitMatrix(t, img, unmirrored)
compareBitMatrix(t, p.bitMatrix, unmirrored)
}
31 changes: 31 additions & 0 deletions qrcode/decoder/decoder_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package decoder

import (
"sync"
"testing"

"github.com/makiuchi-d/gozxing"
Expand Down Expand Up @@ -152,3 +153,33 @@ func TestDecoder_decode(t *testing.T) {
t.Fatalf("decoder result text=\"%v\", expect \"hello\"", r)
}
}

func TestDecoder_ConcurrentDecode(t *testing.T) {
bits, _ := gozxing.ParseStringToBitMatrix(qrstr, "##", " ")

var wg sync.WaitGroup
errs := make(chan error, 10)

for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
decoder := NewDecoder()
result, err := decoder.Decode(bits, nil)
if err != nil {
errs <- err
return
}
if r := result.GetText(); r != "hello" {
errs <- gozxing.NewFormatException("got %q, want %q", r, "hello")
}
}()
}

wg.Wait()
close(errs)

for err := range errs {
t.Errorf("Concurrent decode error: %v", err)
}
}
Loading