// go-qrcode // Copyright 2014 Tom Harwood package qrcode import ( "fmt" "reflect" "testing" bitset "github.com/skip2/go-qrcode/bitset" ) func TestClassifyDataMode(t *testing.T) { type Test struct { } tests := []struct { data []byte actual []segment }{ { []byte{0x30}, []segment{ { dataModeNumeric, []byte{0x30}, }, }, }, { []byte{0x30, 0x41, 0x42, 0x43, 0x20, 0x00, 0xf0, 0xf1, 0xf2, 0x31}, []segment{ { dataModeNumeric, []byte{0x30}, }, { dataModeAlphanumeric, []byte{0x41, 0x42, 0x43, 0x20}, }, { dataModeByte, []byte{0x00, 0xf0, 0xf1, 0xf2}, }, { dataModeNumeric, []byte{0x31}, }, }, }, } for _, test := range tests { encoder := newDataEncoder(dataEncoderType1To9) encoder.encode(test.data) if !reflect.DeepEqual(test.actual, encoder.actual) { t.Errorf("Got %v, expected %v", encoder.actual, test.actual) } } } func TestByteModeLengthCalculations(t *testing.T) { tests := []struct { dataEncoderType dataEncoderType dataMode dataMode numSymbols int expectedLength int }{} for i, test := range tests { encoder := newDataEncoder(test.dataEncoderType) var resultLength int resultLength, err := encoder.encodedLength(test.dataMode, test.numSymbols) if test.expectedLength == -1 { if err == nil { t.Errorf("Test %d: got length %d, expected error", i, resultLength) } } else if resultLength != test.expectedLength { t.Errorf("Test %d: got length %d, expected length %d", i, resultLength, test.expectedLength) } } } func TestSingleModeEncodings(t *testing.T) { tests := []struct { dataEncoderType dataEncoderType dataMode dataMode data string expected *bitset.Bitset }{ { dataEncoderType1To9, dataModeNumeric, "01234567", bitset.NewFromBase2String("0001 0000001000 0000001100 0101011001 1000011"), }, { dataEncoderType1To9, dataModeAlphanumeric, "AC-42", bitset.NewFromBase2String("0010 000000101 00111001110 11100111001 000010"), }, { dataEncoderType1To9, dataModeByte, "123", bitset.NewFromBase2String("0100 00000011 00110001 00110010 00110011"), }, { dataEncoderType10To26, dataModeByte, "123", bitset.NewFromBase2String("0100 00000000 00000011 00110001 00110010 00110011"), }, { dataEncoderType27To40, dataModeByte, "123", bitset.NewFromBase2String("0100 00000000 00000011 00110001 00110010 00110011"), }, } for _, test := range tests { encoder := newDataEncoder(test.dataEncoderType) encoded := bitset.New() encoder.encodeDataRaw([]byte(test.data), test.dataMode, encoded) if !test.expected.Equals(encoded) { t.Errorf("For %s got %s, expected %s", test.data, encoded.String(), test.expected.String()) } } } type testModeSegment struct { dataMode dataMode numChars int } func TestOptimiseEncoding(t *testing.T) { tests := []struct { dataEncoderType dataEncoderType actual []testModeSegment optimised []testModeSegment }{ // Coalescing multiple segments. { dataEncoderType1To9, []testModeSegment{ {dataModeAlphanumeric, 1}, // length = 4 + 9 + 6 = 19 bits {dataModeNumeric, 1}, // length = 4 + 10 + 4 = 18 bits {dataModeAlphanumeric, 1}, // 19 bits. {dataModeNumeric, 1}, // 18 bits. {dataModeAlphanumeric, 1}, // 19 bits. // total = 93 bits. }, []testModeSegment{ {dataModeAlphanumeric, 5}, // length = 4 + 9 + 22 + 6 = 41. }, }, // Coalesing not necessary. { dataEncoderType1To9, []testModeSegment{ {dataModeAlphanumeric, 1}, {dataModeNumeric, 20}, }, []testModeSegment{ {dataModeAlphanumeric, 1}, {dataModeNumeric, 20}, }, }, // Switch to more general dataMode. { dataEncoderType1To9, []testModeSegment{ {dataModeAlphanumeric, 1}, {dataModeByte, 1}, {dataModeNumeric, 1}, }, []testModeSegment{ {dataModeAlphanumeric, 1}, {dataModeByte, 2}, }, }, // https://www.google.com/123 // BBBBBAAABBBABBBBBBABBBANNN { dataEncoderType1To9, []testModeSegment{ {dataModeByte, 5}, {dataModeAlphanumeric, 3}, {dataModeByte, 3}, {dataModeAlphanumeric, 1}, {dataModeByte, 6}, {dataModeAlphanumeric, 1}, {dataModeAlphanumeric, 4}, {dataModeNumeric, 3}, }, []testModeSegment{ {dataModeByte, 23}, {dataModeNumeric, 3}, }, }, // HTTPS://WWW.GOOGLE.COM/123 // AAAAAAAAAAAAAAAAAAAAAAANNN { dataEncoderType1To9, []testModeSegment{ {dataModeAlphanumeric, 23}, {dataModeNumeric, 3}, }, []testModeSegment{ {dataModeAlphanumeric, 26}, }, }, { dataEncoderType27To40, []testModeSegment{ {dataModeByte, 1}, {dataModeNumeric, 1}, {dataModeByte, 1}, {dataModeNumeric, 1}, {dataModeByte, 1}, {dataModeNumeric, 1}, {dataModeByte, 1}, {dataModeNumeric, 1}, }, []testModeSegment{ {dataModeByte, 8}, }, }, } for _, test := range tests { numTotalChars := 0 for _, v := range test.actual { numTotalChars += v.numChars } data := make([]byte, numTotalChars) i := 0 for _, v := range test.actual { for j := 0; j < v.numChars; j++ { switch v.dataMode { case dataModeNumeric: data[i] = '1' case dataModeAlphanumeric: data[i] = 'A' case dataModeByte: data[i] = '#' default: t.Fatal("Unrecognised data mode") } i++ } } encoder := newDataEncoder(test.dataEncoderType) _, err := encoder.encode(data) if err != nil { t.Errorf("Got %s, expected valid encoding", err.Error()) } else { ok := true if len(encoder.optimised) != len(test.optimised) { ok = false } else { for i, s := range test.optimised { if encoder.optimised[i].dataMode != s.dataMode || len(encoder.optimised[i].data) != s.numChars { ok = false break } } } if !ok { t.Errorf("got %s, expected %s", segmentsString(encoder.optimised), testModeSegmentsString(test.optimised)) } } } } func testModeSegmentsString(segments []testModeSegment) string { result := "[" for i, segment := range segments { if i > 0 { result += ", " } result += fmt.Sprintf("%d*%s", segment.numChars, dataModeString(segment.dataMode)) } result += "]" return result } func segmentsString(segments []segment) string { result := "[" for i, segment := range segments { if i > 0 { result += ", " } result += fmt.Sprintf("%d*%s", len(segment.data), dataModeString(segment.dataMode)) } result += "]" return result }