kopia lustrzana https://gitlab.com/sane-project/backends
brother_mfp: first set of unit tests for decoder.
Looks like we found the rare lost data issue in gray decoding. Yayy! for unit tests.brother_mfp_backend
rodzic
6eb9e1cc43
commit
22d8ab2b49
|
@ -400,7 +400,7 @@ libsane_brother_mfp_la_LIBADD = $(COMMON_LIBS) libbrother_mfp.la \
|
|||
../sanei/sanei_usb.lo \
|
||||
../sanei/sanei_config.lo \
|
||||
sane_strstatus.lo \
|
||||
$(USB_LIBS) $(JPEG_LIBS)
|
||||
$(USB_LIBS) $(JPEG_LIBS)
|
||||
EXTRA_DIST += brother_mfp.conf.in
|
||||
|
||||
|
||||
|
|
|
@ -182,6 +182,12 @@ SANE_Status BrotherEncoderFamily4::DecodeSessionResp (const SANE_Byte *data, siz
|
|||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* Supply a buffer that is at least 1 char longer than is necessary
|
||||
* as snprintf() will require space for a terminating NUL.
|
||||
*
|
||||
*/
|
||||
SANE_Status BrotherEncoderFamily4::EncodeBasicParameterBlock (SANE_Byte *data, size_t data_len,
|
||||
size_t *length)
|
||||
{
|
||||
|
@ -229,15 +235,6 @@ SANE_Status BrotherEncoderFamily4::DecodeBasicParameterBlockResp (const SANE_Byt
|
|||
|
||||
SANE_Status BrotherEncoderFamily4::EncodeADFBlock (SANE_Byte *data, size_t data_len, size_t *length)
|
||||
{
|
||||
const char *mode_text = ScanModeToText (scan_params.param_scan_mode);
|
||||
if (nullptr == mode_text)
|
||||
{
|
||||
DBG (DBG_SERIOUS,
|
||||
"BrotherEncoderFamily4::EncodeBasicParameterBlock: failed to get scan mode text for mode %d\n",
|
||||
scan_params.param_scan_mode);
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
|
||||
*length = snprintf ((char*) data, data_len, "\x1b" "D\nADF\n" "\x80");
|
||||
|
||||
if (*length > data_len)
|
||||
|
@ -289,7 +286,7 @@ SANE_Status BrotherEncoderFamily4::EncodeParameterBlock (SANE_Byte *data, size_t
|
|||
(unsigned int) scan_params.param_y_res,
|
||||
mode_text,
|
||||
(scan_params.param_scan_mode == BROTHER_SCAN_MODE_COLOR) ?
|
||||
"C=JPEG\nJ=MID\n" : "C=RLENGTH\n",
|
||||
"C=JPEG\nJ=MID" : "C=RLENGTH",
|
||||
(unsigned int) (scan_params.param_brightness + 50),
|
||||
(unsigned int) (scan_params.param_contrast + 50),
|
||||
(unsigned int) (scan_params.param_pixel_x_offset),
|
||||
|
@ -601,7 +598,13 @@ DecodeStatus BrotherGrayRLengthDecoder::DecodeScanData (const SANE_Byte *in_buff
|
|||
size_t in_buffer_len_start = in_buffer_len;
|
||||
size_t out_buffer_len_start = out_buffer_len;
|
||||
|
||||
while (in_buffer_len && out_buffer_len)
|
||||
/*
|
||||
* Notice that we do the check for in and out space at the bottom, not here:
|
||||
* We might not have any additional src, but we might still be able to progress the decode,
|
||||
* especially in the case of an in-progress decompression.
|
||||
*
|
||||
*/
|
||||
do
|
||||
{
|
||||
/*
|
||||
* Check the current state to see what we should do.
|
||||
|
@ -690,7 +693,7 @@ DecodeStatus BrotherGrayRLengthDecoder::DecodeScanData (const SANE_Byte *in_buff
|
|||
decode_state = BROTHER_DECODE_RLEN_INIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (in_buffer_len && out_buffer_len);
|
||||
|
||||
if (!in_buffer_len || !out_buffer_len)
|
||||
{
|
||||
|
|
|
@ -91,8 +91,8 @@ struct BrotherSessionResponse
|
|||
struct BrotherParameters
|
||||
{
|
||||
BrotherParameters():
|
||||
param_brightness (50),
|
||||
param_contrast (50),
|
||||
param_brightness (0),
|
||||
param_contrast (0),
|
||||
param_pixel_x_offset (0),
|
||||
param_pixel_x_width (0),
|
||||
param_pixel_y_offset (0),
|
||||
|
|
|
@ -11,14 +11,19 @@ TEST_LDADD = \
|
|||
../../../lib/liblib.la \
|
||||
../../../backend/libbrother_mfp.la \
|
||||
../../../backend/sane_strstatus.lo \
|
||||
$(USB_LIBS) $(XML_LIBS) $(PTHREAD_LIBS)
|
||||
$(USB_LIBS) $(XML_LIBS) $(PTHREAD_LIBS) $(JPEG_LIBS)
|
||||
|
||||
check_PROGRAMS = brother_mfp_unit_tests
|
||||
check_PROGRAMS = brother_mfp_unit_tests
|
||||
TESTS = brother_mfp_unit_tests
|
||||
|
||||
AM_CPPFLAGS += -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include $(USB_CFLAGS) \
|
||||
-DBACKEND_NAME=brother_mfp -DTESTSUITE_BACKEND_BROTHER_MFP_SRCDIR=$(srcdir)
|
||||
|
||||
brother_mfp_unit_tests_SOURCES = brother_mfp_tests.cpp brother_mfp_tests.h
|
||||
brother_mfp_unit_tests_SOURCES = \
|
||||
brother_mfp_tests.cpp \
|
||||
brother_mfp_tests.h \
|
||||
brother_mfp_tests_family4.cpp \
|
||||
brother_mfp_tests_gray_rlength.cpp \
|
||||
../genesys/minigtest.cpp
|
||||
|
||||
brother_mfp_unit_tests_LDADD = $(TEST_LDADD)
|
||||
|
|
|
@ -18,14 +18,17 @@
|
|||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define DEBUG_DECLARE_ONLY
|
||||
#define DEBUG_NOT_STATIC
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../../include/sane/sanei_debug.h"
|
||||
#include "../genesys/minigtest.h"
|
||||
#include "brother_mfp_tests.h"
|
||||
|
||||
int main()
|
||||
int main ()
|
||||
{
|
||||
printf("Brother MFP tests.\n");
|
||||
DBG_INIT ();
|
||||
|
||||
return 0;
|
||||
test_family4 ();
|
||||
test_gray_rlength ();
|
||||
return finish_tests ();
|
||||
}
|
||||
|
|
|
@ -19,3 +19,6 @@
|
|||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern void test_family4();
|
||||
extern void test_gray_rlength();
|
||||
|
|
|
@ -0,0 +1,406 @@
|
|||
/* sane - Scanner Access Now Easy.
|
||||
|
||||
Copyright (C) 2022 Ralph Little <skelband@gmail.com>
|
||||
|
||||
This file is part of the SANE package.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define DEBUG_DECLARE_ONLY
|
||||
|
||||
#include "brother_mfp_tests.h"
|
||||
#include "../../backend/brother_mfp/brother_mfp-encoder.h"
|
||||
#include "../genesys/minigtest.h"
|
||||
|
||||
/*
|
||||
* TEST: DecodeSessionResp()
|
||||
*
|
||||
*/
|
||||
static void test_family4_decode_session_resp()
|
||||
{
|
||||
SANE_Status sane_resp;
|
||||
BrotherSessionResponse sess_resp;
|
||||
|
||||
BrotherEncoderFamily4 encoder;
|
||||
|
||||
// SUCCESS status
|
||||
const SANE_Byte *data = (const SANE_Byte *)"\x05" "\x10" "\x01" "\x02" "\x00";
|
||||
|
||||
sane_resp = encoder.DecodeSessionResp (data, 5, sess_resp);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
ASSERT_TRUE(sess_resp.ready);
|
||||
|
||||
// BUSY status
|
||||
data = (const SANE_Byte *)"\x05" "\x10" "\x01" "\x02" "\x20";
|
||||
|
||||
sane_resp = encoder.DecodeSessionResp (data, 5, sess_resp);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
ASSERT_FALSE(sess_resp.ready);
|
||||
|
||||
// Length issues
|
||||
data = (const SANE_Byte *)"\x05" "\x10" "\x01" "\x02" "\x20" "\x32";
|
||||
|
||||
sane_resp = encoder.DecodeSessionResp (data, 6, sess_resp);
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_IO_ERROR);
|
||||
|
||||
sane_resp = encoder.DecodeSessionResp (data, 4, sess_resp);
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_IO_ERROR);
|
||||
|
||||
sane_resp = encoder.DecodeSessionResp (data, 0, sess_resp);
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_IO_ERROR);
|
||||
|
||||
// Content problems.
|
||||
const char *content_problems[] = {
|
||||
"\x32" "\x10" "\x01" "\x02" "\x20",
|
||||
"\x06" "\x32" "\x01" "\x02" "\x20",
|
||||
"\x06" "\x10" "\x32" "\x02" "\x20",
|
||||
"\x06" "\x10" "\x01" "\x32" "\x20",
|
||||
"\x06" "\x10" "\x01" "\x02" "\x32",
|
||||
nullptr
|
||||
};
|
||||
|
||||
for (size_t test = 0; test; test++)
|
||||
{
|
||||
sane_resp = encoder.DecodeSessionResp ((const SANE_Byte *)content_problems[test], 5, sess_resp);
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_IO_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: DecodeBasicParameterBlockResp()
|
||||
*
|
||||
*/
|
||||
static void test_family4_decode_basic_param_resp()
|
||||
{
|
||||
/*
|
||||
* TODO: Nothing to do here yet.
|
||||
* We don't decode anything from this block.
|
||||
* Watch this space.
|
||||
*
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: DecodeADFBlockResp()
|
||||
*
|
||||
*/
|
||||
static void test_family4_decode_adf_resp()
|
||||
{
|
||||
SANE_Status sane_resp;
|
||||
BrotherADFResponse adf_resp;
|
||||
|
||||
BrotherEncoderFamily4 encoder;
|
||||
|
||||
// SUCCESS status
|
||||
const SANE_Byte *data = (const SANE_Byte *)"\xc2";
|
||||
|
||||
sane_resp = encoder.DecodeADFBlockResp (data, 1, adf_resp);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
ASSERT_EQ(adf_resp.resp_code, (SANE_Byte)0xc2);
|
||||
|
||||
// Wrong length.
|
||||
sane_resp = encoder.DecodeADFBlockResp (data, 0, adf_resp);
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_IO_ERROR);
|
||||
ASSERT_EQ(adf_resp.resp_code, (SANE_Byte)0xc2);
|
||||
|
||||
sane_resp = encoder.DecodeADFBlockResp (data, 20, adf_resp);
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_IO_ERROR);
|
||||
ASSERT_EQ(adf_resp.resp_code, (SANE_Byte)0xc2);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: EncodeBasicParameterBlock()
|
||||
*
|
||||
*/
|
||||
static void test_family4_encode_basic_param()
|
||||
{
|
||||
SANE_Status sane_resp;
|
||||
SANE_Byte data_buffer[1024];
|
||||
size_t ret_length;
|
||||
|
||||
BrotherEncoderFamily4 encoder;
|
||||
|
||||
// All defaults.
|
||||
sane_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=100,100\nM=CGRAY\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t)22);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Different resolutions.
|
||||
encoder.SetRes(200,300);
|
||||
|
||||
sane_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=CGRAY\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t)22);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// GRAY mode.
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY);
|
||||
sane_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=GRAY64\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )23);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// COLOR mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_COLOR);
|
||||
sane_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=CGRAY\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )22);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// GRAY DITHERED mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY_DITHERED);
|
||||
sane_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=ERRDIF\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )23);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// TEXT mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_TEXT);
|
||||
sane_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=TEXT\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )21);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Buffer too short.
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_TEXT);
|
||||
sane_resp = encoder.EncodeBasicParameterBlock (data_buffer, 15, &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_INVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: EncodeParameterBlock()
|
||||
*
|
||||
*/
|
||||
static void test_family4_encode_param()
|
||||
{
|
||||
SANE_Status sane_resp;
|
||||
SANE_Byte data_buffer[1024];
|
||||
size_t ret_length;
|
||||
|
||||
BrotherEncoderFamily4 encoder;
|
||||
|
||||
// All defaults.
|
||||
sane_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=100,100\nM=CGRAY\nC=JPEG\nJ=MID\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Different resolutions.
|
||||
encoder.SetRes(200,300);
|
||||
|
||||
sane_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=CGRAY\nC=JPEG\nJ=MID\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Different modes:
|
||||
// GRAY mode.
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY);
|
||||
sane_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=GRAY64\nC=RLENGTH\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// COLOR mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_COLOR);
|
||||
sane_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=CGRAY\nC=JPEG\nJ=MID\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// GRAY DITHERED mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY_DITHERED);
|
||||
sane_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=ERRDIF\nC=RLENGTH\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// TEXT mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_TEXT);
|
||||
sane_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Different brightness and contrast, positive and negative.
|
||||
encoder.SetBrightness (-20);
|
||||
encoder.SetContrast (-30);
|
||||
sane_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=30\nN=20\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
encoder.SetBrightness (50);
|
||||
encoder.SetContrast (40);
|
||||
sane_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=100\nN=90\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Different dimensions
|
||||
encoder.SetScanDimensions (0, 10, 50, 100);
|
||||
sane_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=100\nN=90\nA=0,50,10,150\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Buffer too short.
|
||||
sane_resp = encoder.EncodeParameterBlock (data_buffer, 15, &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_INVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: EncodeADFBlock()
|
||||
*
|
||||
*/
|
||||
static void test_family4_encode_adf()
|
||||
{
|
||||
SANE_Status sane_resp;
|
||||
SANE_Byte data_buffer[1024];
|
||||
size_t ret_length;
|
||||
|
||||
BrotherEncoderFamily4 encoder;
|
||||
|
||||
// Standard call.
|
||||
sane_resp = encoder.EncodeADFBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "D\nADF\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Buffer too short.
|
||||
sane_resp = encoder.EncodeADFBlock (data_buffer, 5, &ret_length);
|
||||
ASSERT_EQ(sane_resp, SANE_STATUS_INVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run all the tests.
|
||||
*
|
||||
*/
|
||||
void test_family4 ()
|
||||
{
|
||||
// Decodes.
|
||||
test_family4_decode_session_resp();
|
||||
test_family4_decode_basic_param_resp();
|
||||
test_family4_decode_adf_resp();
|
||||
|
||||
// Encodes.
|
||||
test_family4_encode_basic_param();
|
||||
test_family4_encode_param();
|
||||
test_family4_encode_adf();
|
||||
}
|
|
@ -0,0 +1,421 @@
|
|||
/* sane - Scanner Access Now Easy.
|
||||
|
||||
Copyright (C) 2022 Ralph Little <skelband@gmail.com>
|
||||
|
||||
This file is part of the SANE package.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define DEBUG_DECLARE_ONLY
|
||||
|
||||
#include "../../include/sane/sanei_debug.h"
|
||||
#include "brother_mfp_tests.h"
|
||||
#include "../../backend/brother_mfp/brother_mfp-encoder.h"
|
||||
#include "../genesys/minigtest.h"
|
||||
|
||||
/*
|
||||
* TEST: BrotherGrayRLengthDecoder()
|
||||
*
|
||||
*/
|
||||
static void test_gray_rlength_no_compress()
|
||||
{
|
||||
BrotherGrayRLengthDecoder decoder;
|
||||
const SANE_Byte *src_data;
|
||||
SANE_Byte dest_data[1024];
|
||||
DecodeStatus res_code;
|
||||
size_t src_data_consumed;
|
||||
size_t dest_data_written;
|
||||
|
||||
/*
|
||||
* Normal decode.
|
||||
*
|
||||
*/
|
||||
src_data = (const SANE_Byte *)"\x04" "ABCDE";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)6);
|
||||
ASSERT_EQ(dest_data_written, (size_t)5);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "ABCDE", 5), 0);
|
||||
|
||||
// Boundary condition: 1 character only.
|
||||
src_data = (const SANE_Byte *)"\x00" "X";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
2,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)1);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "X", 1), 0);
|
||||
|
||||
/*
|
||||
* Decodes broken through src exhaustion (fragmentation of input).
|
||||
*
|
||||
*/
|
||||
// Break after length: can decode the length but nothing else.
|
||||
src_data = (const SANE_Byte *)"\x04";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
1,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)1);
|
||||
ASSERT_EQ(dest_data_written, (size_t)0);
|
||||
|
||||
src_data = (const SANE_Byte *)"MNOPQ";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
5,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)5);
|
||||
ASSERT_EQ(dest_data_written, (size_t)5);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "MNOPQ", 5), 0);
|
||||
|
||||
// BREAK part way through the data portion.
|
||||
src_data = (const SANE_Byte *)"\x05" "ABC";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
4,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)4);
|
||||
ASSERT_EQ(dest_data_written, (size_t)3);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "ABC", 3), 0);
|
||||
|
||||
src_data = (const SANE_Byte *)"DEF";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
3,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)3);
|
||||
ASSERT_EQ(dest_data_written, (size_t)3);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "DEF", 3), 0);
|
||||
|
||||
/*
|
||||
* Decodes broken by exhausted output buffer.
|
||||
*
|
||||
*/
|
||||
// BREAK part way through the data portion.
|
||||
src_data = (const SANE_Byte *)"\x05" "MNOPQR";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
7,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
1,
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)1);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "M", 1), 0);
|
||||
|
||||
src_data = (const SANE_Byte *)"NOPQR";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
5,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
2,
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)2);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "NO", 1), 0);
|
||||
|
||||
src_data = (const SANE_Byte *)"PQR";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
3,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
3,
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)3);
|
||||
ASSERT_EQ(dest_data_written, (size_t)3);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "PQR", 3), 0);
|
||||
|
||||
/*
|
||||
* Test reset by page.
|
||||
* This should reset the state of the decoder.
|
||||
*
|
||||
*/
|
||||
src_data = (const SANE_Byte *)"\x04" "ABCDE";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
3,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)3);
|
||||
ASSERT_EQ(dest_data_written, (size_t)2);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "AB", 2), 0);
|
||||
|
||||
// Partial decode should be flushed.
|
||||
decoder.NewPage();
|
||||
|
||||
src_data = (const SANE_Byte *)"\x04" "GHIJK";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
6,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)6);
|
||||
ASSERT_EQ(dest_data_written, (size_t)5);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "GHIJK", 5), 0);
|
||||
|
||||
/*
|
||||
* Test reset by block.
|
||||
* This should reset the state of the decoder.
|
||||
*
|
||||
*/
|
||||
src_data = (const SANE_Byte *)"\x04" "ABCDE";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
3,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)3);
|
||||
ASSERT_EQ(dest_data_written, (size_t)2);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "AB", 2), 0);
|
||||
|
||||
// Partial decode should be flushed.
|
||||
decoder.NewBlock();
|
||||
|
||||
src_data = (const SANE_Byte *)"\x04" "GHIJK";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
6,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)6);
|
||||
ASSERT_EQ(dest_data_written, (size_t)5);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "GHIJK", 5), 0);
|
||||
}
|
||||
|
||||
static void test_gray_rlength_compression()
|
||||
{
|
||||
BrotherGrayRLengthDecoder decoder;
|
||||
const SANE_Byte *src_data;
|
||||
SANE_Byte dest_data[1024];
|
||||
DecodeStatus res_code;
|
||||
size_t src_data_consumed;
|
||||
size_t dest_data_written;
|
||||
|
||||
/*
|
||||
* Normal decode.
|
||||
*
|
||||
*/
|
||||
src_data = (const SANE_Byte *)"\xfd" "A";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)4);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "AAAA", 4), 0);
|
||||
|
||||
// Boundary check: minimal compression: 2 chars
|
||||
src_data = (const SANE_Byte *)"\xff" "X";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)2);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "XX", 2), 0);
|
||||
|
||||
// Upper limit of compression: 0x80 (gives 129 bytes of output)
|
||||
src_data = (const SANE_Byte *)"\x80" "Y";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)129);
|
||||
|
||||
ASSERT_EQ(strrchr((const char *)dest_data, 'Y'), (const char *)&dest_data[128]);
|
||||
|
||||
/*
|
||||
* Fragmentation due to dest exhaustion.
|
||||
*
|
||||
*/
|
||||
src_data = (const SANE_Byte *)"\xfd" "Z";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
1,
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)1);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "Z", 1), 0);
|
||||
|
||||
src_data = (const SANE_Byte *)"\xfd" "Z";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
/*
|
||||
* Can decode, but we haven't any additional src data.
|
||||
* This is a special case of decompression where we do not require
|
||||
* additional input from the src; just some output space.
|
||||
*
|
||||
*/
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
0,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
3,
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)0);
|
||||
ASSERT_EQ(dest_data_written, (size_t)3);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "ZZZ", 3), 0);
|
||||
|
||||
/*
|
||||
* Fragmentation due to src exhaustion.
|
||||
* The only case here is that we see the length, but not the
|
||||
* following character so we cannot actually do anything.
|
||||
*
|
||||
*/
|
||||
src_data = (const SANE_Byte *)"\xfd" "A";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
1,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)0);
|
||||
ASSERT_EQ(dest_data_written, (size_t)0);
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
2,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)4);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "AAAA", 4), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run all the tests.
|
||||
*
|
||||
*/
|
||||
void test_gray_rlength()
|
||||
{
|
||||
test_gray_rlength_no_compress();
|
||||
test_gray_rlength_compression();
|
||||
}
|
Ładowanie…
Reference in New Issue