mirror of https://github.com/status-im/qzxing.git
Multiple changes in test suite. a) Added tests for ReedSolomonEncoder (current status: failing) b) Added printing of stacktrace upon test missmatch, will work only where supported by backward.hpp code.
This commit is contained in:
parent
588d478b7b
commit
5cd96d1aae
|
@ -13,7 +13,7 @@
|
||||||
namespace zxing {
|
namespace zxing {
|
||||||
namespace tests{
|
namespace tests{
|
||||||
|
|
||||||
EncodeValidator::EncodeValidator()
|
EncodeValidator::EncodeValidator() : TestCase()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ void EncodeValidator::execute()
|
||||||
qrcode::tests::QRCodeTests t3;
|
qrcode::tests::QRCodeTests t3;
|
||||||
t3.execute();
|
t3.execute();
|
||||||
|
|
||||||
ReedSolomonEncoderTests t4;
|
ReedSolomonTests t4;
|
||||||
t4.execute();
|
t4.execute();
|
||||||
|
|
||||||
qrcode::tests::EncoderTests t5;
|
qrcode::tests::EncoderTests t5;
|
||||||
|
|
|
@ -10,6 +10,19 @@ CONFIG -= app_bundle
|
||||||
|
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
DecodeValidator.h \
|
||||||
|
ValidationStats.h \
|
||||||
|
EncodeValidator.h \
|
||||||
|
TestCase.h \
|
||||||
|
zxing/qrcode/encoder/MatrixUtilTests.h \
|
||||||
|
zxing/qrcode/encoder/MaskUtilTests.h \
|
||||||
|
zxing/qrcode/encoder/BitArrayTests.h \
|
||||||
|
zxing/qrcode/encoder/QRCodeTests.h \
|
||||||
|
zxing/qrcode/encoder/EncoderTests.h \
|
||||||
|
zxing/common/reedsolomon/ReedSolomonEncoderTests.h
|
||||||
|
#\backward.hpp
|
||||||
|
|
||||||
SOURCES += main.cpp \
|
SOURCES += main.cpp \
|
||||||
DecodeValidator.cpp \
|
DecodeValidator.cpp \
|
||||||
ValidationStats.cpp \
|
ValidationStats.cpp \
|
||||||
|
@ -19,18 +32,7 @@ SOURCES += main.cpp \
|
||||||
zxing/qrcode/encoder/BitArrayTests.cpp \
|
zxing/qrcode/encoder/BitArrayTests.cpp \
|
||||||
zxing/qrcode/encoder/QRCodeTests.cpp \
|
zxing/qrcode/encoder/QRCodeTests.cpp \
|
||||||
zxing/qrcode/encoder/EncoderTests.cpp \
|
zxing/qrcode/encoder/EncoderTests.cpp \
|
||||||
zxing/common/reedsolomon/ReedSolomonEncoderTests.cpp
|
zxing/common/reedsolomon/ReedSolomonEncoderTests.cpp \
|
||||||
|
TestCase.cpp
|
||||||
HEADERS += \
|
|
||||||
DecodeValidator.h \
|
|
||||||
ValidationStats.h \
|
|
||||||
EncodeValidator.h \
|
|
||||||
zxing/qrcode/encoder/MatrixUtilTests.h \
|
|
||||||
TestCase.h \
|
|
||||||
zxing/qrcode/encoder/MaskUtilTests.h \
|
|
||||||
zxing/qrcode/encoder/BitArrayTests.h \
|
|
||||||
zxing/qrcode/encoder/QRCodeTests.h \
|
|
||||||
zxing/qrcode/encoder/EncoderTests.h \
|
|
||||||
zxing/common/reedsolomon/ReedSolomonEncoderTests.h
|
|
||||||
|
|
||||||
include(../../../src/QZXing.pri)
|
include(../../../src/QZXing.pri)
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "TestCase.h"
|
||||||
|
#include <stdlib.h> /* srand, rand */
|
||||||
|
#include <time.h> /* time */
|
||||||
|
|
||||||
|
void zxing::TestCase::initializeRandom()
|
||||||
|
{
|
||||||
|
srand(time(NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
int zxing::TestCase::generateRandomNumber(int range)
|
||||||
|
{
|
||||||
|
return rand() % range;
|
||||||
|
}
|
|
@ -5,6 +5,8 @@
|
||||||
#include <zxing/Exception.h>
|
#include <zxing/Exception.h>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <zxing/qrcode/decoder/Mode.h>
|
#include <zxing/qrcode/decoder/Mode.h>
|
||||||
|
#include "backward.hpp"
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
namespace zxing{
|
namespace zxing{
|
||||||
|
|
||||||
|
@ -52,6 +54,23 @@ protected:
|
||||||
if(expected != actual) {
|
if(expected != actual) {
|
||||||
QString message = QString("\nExpected: \n[") + itemToString(expected) +
|
QString message = QString("\nExpected: \n[") + itemToString(expected) +
|
||||||
QString("], \nGot: \n[") + itemToString(actual) + QString("]");
|
QString("], \nGot: \n[") + itemToString(actual) + QString("]");
|
||||||
|
|
||||||
|
backward::StackTrace st;
|
||||||
|
st.load_here(32);
|
||||||
|
|
||||||
|
backward::TraceResolver tr;
|
||||||
|
tr.load_stacktrace(st);
|
||||||
|
for (size_t i = 0; i < st.size(); ++i) {
|
||||||
|
backward::ResolvedTrace trace = tr.resolve(st[i]);
|
||||||
|
message += QString::fromStdString("\n#");
|
||||||
|
message += QString::number(i);
|
||||||
|
message += QString::fromStdString(trace.object_filename);
|
||||||
|
message += QString::fromStdString(trace.object_function);
|
||||||
|
message += QString("[");
|
||||||
|
message += QString::number((int)trace.addr);
|
||||||
|
message += QString("]\n");
|
||||||
|
}
|
||||||
|
|
||||||
throw zxing::Exception(message.toStdString().c_str());
|
throw zxing::Exception(message.toStdString().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,6 +96,22 @@ protected:
|
||||||
assertEquals(0, (int)actual);
|
assertEquals(0, (int)actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void assertDataEquals(const std::string &message,
|
||||||
|
const std::vector<int> &expected,
|
||||||
|
const std::vector<int> & received)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < expected.size(); i++) {
|
||||||
|
if (expected[i] != received[i]) {
|
||||||
|
qDebug() << QString::fromStdString(message) << ". Mismatch at " << QString::number(i) /*<< ". Expected " + arrayToString(expected) + ", got " +
|
||||||
|
arrayToString(Arrays.copyOf(received, expected.length)))*/;
|
||||||
|
assertTrue(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initializeRandom();
|
||||||
|
static int generateRandomNumber(int range);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void execute()=0;
|
virtual void execute()=0;
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,16 +1,148 @@
|
||||||
#include "ReedSolomonEncoderTests.h"
|
#include "ReedSolomonEncoderTests.h"
|
||||||
|
#include "zxing/common/reedsolomon/ReedSolomonEncoder.h"
|
||||||
|
#include "zxing/common/reedsolomon/ReedSolomonDecoder.h"
|
||||||
|
|
||||||
namespace zxing{
|
namespace zxing{
|
||||||
namespace tests{
|
namespace tests{
|
||||||
|
|
||||||
ReedSolomonEncoderTests::ReedSolomonEncoderTests()
|
const int ReedSolomonTests::DECODER_RANDOM_TEST_ITERATIONS = 3;
|
||||||
|
const int ReedSolomonTests::DECODER_TEST_ITERATIONS = 10;
|
||||||
|
|
||||||
|
ReedSolomonTests::ReedSolomonTests()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReedSolomonEncoderTests::execute()
|
void ReedSolomonTests::execute()
|
||||||
{
|
{
|
||||||
|
testQRCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReedSolomonTests::testQRCode()
|
||||||
|
{
|
||||||
|
// Test case from example given in ISO 18004, Annex I
|
||||||
|
testEncodeDecode(GenericGF::QR_CODE_FIELD_256, {
|
||||||
|
0x10, 0x20, 0x0C, 0x56, 0x61, 0x80, 0xEC, 0x11,
|
||||||
|
0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11
|
||||||
|
// 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
|
||||||
|
},
|
||||||
|
{0xA5, 0x24, 0xD4, 0xC1, 0xED, 0x36, 0xC7, 0x87,
|
||||||
|
0x2C, 0x55 });
|
||||||
|
testEncodeDecode(GenericGF::QR_CODE_FIELD_256, {
|
||||||
|
0x72, 0x67, 0x2F, 0x77, 0x69, 0x6B, 0x69, 0x2F,
|
||||||
|
0x4D, 0x61, 0x69, 0x6E, 0x5F, 0x50, 0x61, 0x67,
|
||||||
|
0x65, 0x3B, 0x3B, 0x00, 0xEC, 0x11, 0xEC, 0x11,
|
||||||
|
0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11 },
|
||||||
|
{0xD8, 0xB8, 0xEF, 0x14, 0xEC, 0xD0, 0xCC, 0x85,
|
||||||
|
0x73, 0x40, 0x0B, 0xB5, 0x5A, 0xB8, 0x8B, 0x2E,
|
||||||
|
0x08, 0x62 });
|
||||||
|
// real life test cases
|
||||||
|
// synthetic test cases
|
||||||
|
testEncodeDecodeRandom(GenericGF::QR_CODE_FIELD_256, 10, 240);
|
||||||
|
testEncodeDecodeRandom(GenericGF::QR_CODE_FIELD_256, 128, 127);
|
||||||
|
testEncodeDecodeRandom(GenericGF::QR_CODE_FIELD_256, 220, 35);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReedSolomonTests::corrupt(std::vector<int> &received, int howMany, int max)
|
||||||
|
{
|
||||||
|
std::vector<bool> corrupted(false, received.size());
|
||||||
|
for (int j = 0; j < howMany; j++) {
|
||||||
|
int location = generateRandomNumber(received.size());
|
||||||
|
int value = generateRandomNumber(max);
|
||||||
|
if (corrupted[location] || received[location] == value) {
|
||||||
|
j--;
|
||||||
|
} else {
|
||||||
|
corrupted[location] = true;
|
||||||
|
received[location] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReedSolomonTests::testEncodeDecodeRandom(Ref<GenericGF> field, int dataSize, int ecSize)
|
||||||
|
{
|
||||||
|
assertTrue(dataSize > 0 && dataSize <= field->getSize() - 3); /*"Invalid data size for " + field, */
|
||||||
|
assertTrue(ecSize > 0 && ecSize + dataSize <= field->getSize()); /*"Invalid ECC size for " + field, */
|
||||||
|
ReedSolomonEncoder encoder(field);
|
||||||
|
std::vector<int> message;//(dataSize + ecSize);
|
||||||
|
std::vector<int> dataWords(dataSize);
|
||||||
|
std::vector<int> ecWords(ecSize);
|
||||||
|
initializeRandom();
|
||||||
|
int iterations = field->getSize() > 256 ? 1 : DECODER_RANDOM_TEST_ITERATIONS;
|
||||||
|
for (int i = 0; i < iterations; i++) {
|
||||||
|
// generate random data
|
||||||
|
for (int k = 0; k < dataSize; k++) {
|
||||||
|
dataWords[k] = generateRandomNumber(field->getSize());
|
||||||
|
}
|
||||||
|
// generate ECC words
|
||||||
|
message = dataWords;
|
||||||
|
encoder.encode(message, ecWords.size());
|
||||||
|
message.insert(std::end(message), std::begin(ecWords), std::end(ecWords));
|
||||||
|
// check to see if Decoder can fix up to ecWords/2 random errors
|
||||||
|
testDecoder(field, dataWords, ecWords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReedSolomonTests::testEncodeDecode(Ref<GenericGF> field,
|
||||||
|
const std::vector<int> &dataWords,
|
||||||
|
const std::vector<int> & ecWords)
|
||||||
|
{
|
||||||
|
testEncoder(field, dataWords, ecWords);
|
||||||
|
testDecoder(field, dataWords, ecWords);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReedSolomonTests::testEncoder(Ref<GenericGF> field,
|
||||||
|
const std::vector<int> &dataWords,
|
||||||
|
const std::vector<int> & ecWords)
|
||||||
|
{
|
||||||
|
ReedSolomonEncoder encoder(field);
|
||||||
|
std::vector<int> messageExpected;
|
||||||
|
std::vector<int> message;
|
||||||
|
|
||||||
|
messageExpected = dataWords;
|
||||||
|
messageExpected.insert(std::end(messageExpected), std::begin(ecWords), std::end(ecWords));
|
||||||
|
message = dataWords;
|
||||||
|
|
||||||
|
encoder.encode(message, ecWords.size());
|
||||||
|
assertDataEquals("",//"Encode in " + field + " (" + dataWords.size() + ',' + ecWords.size() + ") failed",
|
||||||
|
messageExpected, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReedSolomonTests::testDecoder(Ref<GenericGF> field,
|
||||||
|
const std::vector<int> &dataWords,
|
||||||
|
const std::vector<int> & ecWords) {
|
||||||
|
ReedSolomonDecoder decoder(field);
|
||||||
|
std::vector<int> message;
|
||||||
|
int maxErrors = ecWords.size() / 2;
|
||||||
|
initializeRandom();
|
||||||
|
int iterations = field->getSize() > 256 ? 1 : DECODER_TEST_ITERATIONS;
|
||||||
|
for (int j = 0; j < iterations; j++) {
|
||||||
|
for (int i = 0; i < ecWords.size(); i++) {
|
||||||
|
if (i > 10 && i < ecWords.size() / 2 - 10) {
|
||||||
|
// performance improvement - skip intermediate cases in long-running tests
|
||||||
|
i += ecWords.size() / 10;
|
||||||
|
}
|
||||||
|
message = dataWords;
|
||||||
|
message.insert(std::end(message), std::begin(ecWords), std::end(ecWords));
|
||||||
|
corrupt(message, i, field->getSize());
|
||||||
|
|
||||||
|
ArrayRef<int> messageArrayRef(message.size());
|
||||||
|
for(int i=0; i<message.size(); i++)
|
||||||
|
messageArrayRef[i] = message[i];
|
||||||
|
try {
|
||||||
|
decoder.decode(messageArrayRef, ecWords.size());
|
||||||
|
} catch(zxing::Exception &e) {
|
||||||
|
// fail only if maxErrors exceeded
|
||||||
|
assertTrue(i > maxErrors); /*"Decode in " + field + " (" + dataWords.length + ',' + ecWords.length + ") failed at " + i + " errors: " + e,*/
|
||||||
|
// else stop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < maxErrors) {
|
||||||
|
//"Decode in " + field + " (" + dataWords.size() + ',' + ecWords.size() + ") failed at " + i + " errors"
|
||||||
|
assertDataEquals("",dataWords, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,22 +2,37 @@
|
||||||
#define REEDSOLOMONENCODERTESTS_H
|
#define REEDSOLOMONENCODERTESTS_H
|
||||||
|
|
||||||
#include "TestCase.h"
|
#include "TestCase.h"
|
||||||
#include "zxing/common/reedsolomon/ReedSolomonEncoder.h"
|
#include <zxing/common/reedsolomon/GenericGF.h>
|
||||||
|
|
||||||
namespace zxing{
|
namespace zxing{
|
||||||
namespace tests{
|
namespace tests{
|
||||||
|
|
||||||
class ReedSolomonEncoderTests : public TestCase
|
class ReedSolomonTests : public TestCase
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
static const int DECODER_RANDOM_TEST_ITERATIONS;
|
||||||
|
static const int DECODER_TEST_ITERATIONS;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ReedSolomonEncoderTests();
|
ReedSolomonTests();
|
||||||
|
|
||||||
void execute();
|
void execute();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void testQRCode();
|
||||||
|
|
||||||
// const std::vector<byte>& dataBytes
|
private:
|
||||||
// void testEncoder(Ref<GenericGF> field, int[] dataWords, int[] ecWords);
|
void corrupt(std::vector<int> &received, int howMany, int max);
|
||||||
|
void testEncodeDecodeRandom(Ref<GenericGF> field, int dataSize, int ecSize);
|
||||||
|
void testEncodeDecode(Ref<GenericGF> field,
|
||||||
|
const std::vector<int> &dataWords,
|
||||||
|
const std::vector<int> & ecWords);
|
||||||
|
void testEncoder(Ref<GenericGF> field,
|
||||||
|
const std::vector<int> &dataWords,
|
||||||
|
const std::vector<int> & ecWords);
|
||||||
|
void testDecoder(Ref<GenericGF> field,
|
||||||
|
const std::vector<int> &dataWords,
|
||||||
|
const std::vector<int> & ecWords);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue