1
0
mirror of https://github.com/pdewacht/brlaser synced 2025-07-13 12:54:22 +02:00

13 Commits
v1 ... v3

Author SHA1 Message Date
1dcd5b445e Fix lest.hpp dependency for the tests. 2014-07-07 13:05:01 +02:00
19edb1767b Kill a harmless dead store
Just because clang's scan-build complained about it.
2014-07-07 13:03:57 +02:00
c3999acbec Version 3 2014-07-07 12:55:16 +02:00
9c4336a8df Updated README 2014-06-30 22:21:22 +02:00
71bb29a3ca Add Brother DCP-7065DN 2014-06-30 22:19:49 +02:00
fa26a6149a Version 2 2014-06-29 11:52:28 +02:00
2e37d9d62a Import lest v1.8.0 2014-06-29 11:50:18 +02:00
77ce307fdb Update gitignore 2014-02-04 22:29:34 +01:00
7bfe0d2846 Reorganize makefile a bit 2014-02-04 22:29:34 +01:00
5159844b03 Add some basic tests 2014-02-04 22:29:27 +01:00
bb1ba17b4f Split out block.h 2014-02-04 21:50:11 +01:00
cd0e4102b4 Distribute the readme file 2014-01-26 20:52:22 +01:00
66ea095ede Changes to support GCC 4.6
GCC 4.6 is the oldest release that can compile this code without significant
changes.
2014-01-26 15:07:53 +01:00
14 changed files with 904 additions and 71 deletions

9
.gitignore vendored
View File

@ -11,11 +11,16 @@
/stamp-*
.deps/
.dirstamp
*.log
*.trs
#
# Binaries
#
/rastertobrlaser
/brdecode
/src/rastertobrlaser
/src/brdecode
/test/test_lest
/test/test_line
/test/test_block
/brlaser.drv
*.o

9
ChangeLog Normal file
View File

@ -0,0 +1,9 @@
brlaser v3 (2014-07-07)
Added DCP-7065DN description.
brlaser v2 (2014-06-29)
Suppport compilation with GCC 4.6.
Add a basic test suite.
brlaser v1 (2013-12-30)
Initial release.

View File

@ -1,24 +1,50 @@
ACLOCAL_AMFLAGS = -I m4
AM_CXXFLAGS = $(CUPS_CFLAGS)
TESTS = $(check_PROGRAMS)
filter_PROGRAMS = rastertobrlaser
filterdir = $(CUPS_SERVERBIN)/filter
dist_doc_DATA = README.md
drv_DATA = brlaser.drv
drvdir = $(CUPS_DATADIR)/drv
noinst_PROGRAMS = brdecode
filter_PROGRAMS = src/rastertobrlaser
filterdir = $(CUPS_SERVERBIN)/filter
noinst_PROGRAMS = src/brdecode
check_PROGRAMS = \
test/test_lest \
test/test_line \
test/test_block
rastertobrlaser_SOURCES = \
src_rastertobrlaser_SOURCES = \
src/main.cc \
src/debug.h \
src/debug.cc \
src/job.h \
src/job.cc \
src/block.h \
src/line.h \
src/line.cc
rastertobrlaser_CPPFLAGS = $(CUPS_CFLAGS)
rastertobrlaser_LDADD = $(CUPS_LIBS)
src_rastertobrlaser_LDADD = $(CUPS_LIBS)
brdecode_SOURCES = \
src_brdecode_SOURCES = \
src/brdecode.cc
test_test_lest_SOURCES = \
test/test_lest.cc \
test/lest.hpp
test_test_line_SOURCES = \
test/test_line.cc \
src/line.h \
src/line.cc \
test/lest.hpp
test_test_block_SOURCES = \
test/test_block.cc \
src/block.h \
test/tempfile.h \
test/lest.hpp

View File

@ -1,23 +1,15 @@
"brlaser" Brother DCP-7030 printer driver
Driver for (some) Brother laster printers
=========================================
This is a driver for the Brother DCP-7030 laser printer. It might also
be worth trying if you have some other old Brother monochrome laser
printer.
Most Brother printers support a standard printer language such as PCL
or PostScript, but not all do. If you have a monochrome Brother laser
printer (or multi-function device) and the other open source drivers
don't work, this one might help.
Currently this printer is not supported by other free software
drivers. Ghostscript's hl1250 driver almost works, but has glitches
with some fonts. (That driver tries to use PCL emulation, but that
seems to be buggy on this printer. The proprietary driver never uses
that mode.)
It is known to support these printers:
Brother provides a non-free x86-only driver.
Requirements
------------
* CUPS: tested with version 1.6.
* A C++11 compiler. A recent version of GCC or Clang will work.
* Brother DCP-7030
* Brother DCP-7065DN
Copyright
---------

View File

@ -81,3 +81,10 @@ Option "brlaserEconomode/Toner save mode" Boolean AnySetup 10
Attribute "1284DeviceID" "" "MFG:Brother;CMD:PJL,HBP;MDL:DCP-7030;CLS:PRINTER;"
PCFileName "br7030.ppd"
}
{
ModelName "DCP-7065DN"
Attribute "NickName" "" "Brother DCP-7065DN, using @PACKAGE@ v@VERSION@"
Attribute "1284DeviceID" "" "MFG:Brother;CMD:PJL,HBP;MDL:DCP-7065DN;CLS:PRINTER;CID:Brother Laser Type1;"
PCFileName "br7065dn.ppd"
}

View File

@ -16,7 +16,7 @@
# along with brlaser. If not, see <http:#www.gnu.org/licenses/>.
AC_PREREQ(2.68)
AC_INIT([brlaser], [1], [pdewacht@gmail.com], [brlaser],
AC_INIT([brlaser], [3], [pdewacht@gmail.com], [brlaser],
[https://github.com/pdewacht/brlaser])
AC_CONFIG_SRCDIR([src/line.cc])

63
src/block.h Normal file
View File

@ -0,0 +1,63 @@
// This file is part of the brlaser printer driver.
//
// Copyright 2013 Peter De Wachter
//
// brlaser 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.
//
// brlaser 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 brlaser. If not, see <http://www.gnu.org/licenses/>.
#ifndef BLOCK_H
#define BLOCK_H
#include <assert.h>
#include <stdio.h>
#include <vector>
class block {
public:
block(): line_bytes_(0) {
}
void add_line(std::vector<uint8_t> &&line) {
assert(!line.empty());
assert(line_fits(line.size()));
line_bytes_ += line.size();
lines_.push_back(line);
}
bool line_fits(unsigned size) {
return lines_.size() != max_lines_per_block_
&& line_bytes_ + size < max_block_size_;
}
void flush(FILE *f) {
if (line_bytes_) {
fprintf(f, "%dw%c%c",
line_bytes_ + 2, 0,
static_cast<int>(lines_.size()));
for (auto &line : lines_) {
fwrite(line.data(), 1, line.size(), f);
}
line_bytes_ = 0;
lines_.clear();
}
}
private:
static const unsigned max_block_size_ = 16350;
static const unsigned max_lines_per_block_ = 128;
std::vector<std::vector<uint8_t>> lines_;
int line_bytes_;
};
#endif // BLOCK_H

View File

@ -16,6 +16,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <algorithm>
#include <exception>
@ -127,9 +128,9 @@ void read_line() {
}
void read_block() {
uint8_t count = get();
unsigned count = get();
count = count * 256 + get();
for (int i = 0; i < count; ++i) {
for (unsigned i = 0; i < count; ++i) {
read_line();
}
}
@ -142,7 +143,6 @@ bool read_page() {
line.clear();
while ((ch = getc(in_file)) >= 0) {
if (ch == '\f') {
in_esc = false;
break;
} else if (ch == 033) {
in_esc = true;

View File

@ -20,46 +20,8 @@
#include <algorithm>
#include <vector>
#include "line.h"
#include "block.h"
using std::vector;
namespace {
class block {
public:
void add_line(vector<uint8_t> &&line) {
assert(!line.empty());
line_bytes_ += line.size();
lines_.push_back(line);
}
bool line_fits(unsigned size) {
return lines_.size() != max_lines_per_block_
&& line_bytes_ + size < max_block_size_;
}
void flush(FILE *f) {
if (line_bytes_) {
fprintf(f, "%dw%c%c",
line_bytes_ + 2, 0,
static_cast<int>(lines_.size()));
for (auto &line : lines_) {
fwrite(line.data(), 1, line.size(), f);
}
line_bytes_ = 0;
lines_.clear();
}
}
private:
const unsigned max_block_size_ = 16350;
const unsigned max_lines_per_block_ = 128;
vector<vector<uint8_t>> lines_;
int line_bytes_ = 0;
};
} // namespace
job::job(FILE *out, const std::string &job_name)
: out_(out),
@ -123,8 +85,8 @@ void job::encode_page(const page_params &page_params,
write_page_header();
}
vector<uint8_t> line(linesize);
vector<uint8_t> reference(linesize);
std::vector<uint8_t> line(linesize);
std::vector<uint8_t> reference(linesize);
block block;
if (!nextline(line.data())) {
@ -138,7 +100,7 @@ void job::encode_page(const page_params &page_params,
fputs("\033*b1030m", out_);
for (int i = 1; i < lines && nextline(line.data()); ++i) {
vector<uint8_t> encoded = encode_line(line, reference);
std::vector<uint8_t> encoded = encode_line(line, reference);
if (!block.line_fits(encoded.size())) {
block.flush(out_);
}

199
test/lest.hpp Normal file
View File

@ -0,0 +1,199 @@
// Copyright 2013 by Martin Moene
//
// lest is based on ideas by Kevlin Henney, see video at
// http://skillsmatter.com/podcast/agile-testing/kevlin-henney-rethinking-unit-testing-in-c-plus-plus
//
// Distributed under the Boost Software License, Version 1.0:
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#ifndef LEST_LEST_H_INCLUDED
#define LEST_LEST_H_INCLUDED
#include <functional>
#include <iostream>
#include <stdexcept>
#include <string>
#include <cstddef>
#ifndef lest_NO_SHORT_ASSERTION_NAMES
# define EXPECT lest_EXPECT
# define EXPECT_THROWS lest_EXPECT_THROWS
# define EXPECT_THROWS_AS lest_EXPECT_THROWS_AS
#endif
#define lest_EXPECT( expr ) \
try \
{ \
if ( ! (expr) ) \
throw lest::failure{ lest_LOCATION, #expr }; \
} \
catch( lest::failure const & ) \
{ \
throw ; \
} \
catch( std::exception const & e ) \
{ \
throw lest::unexpected{ lest_LOCATION, #expr, lest::with_message( e.what() ) }; \
} \
catch(...) \
{ \
throw lest::unexpected{ lest_LOCATION, #expr, "of unknown type" }; \
}
#define lest_EXPECT_THROWS( expr ) \
for (;;) \
{ \
try { lest::serum( expr ); } catch (...) { break; } \
throw lest::expected{ lest_LOCATION, #expr }; \
}
#define lest_EXPECT_THROWS_AS( expr, excpt ) \
for (;;) \
{ \
try { lest::serum( expr ); } catch ( excpt & ) { break; } catch (...) {} \
throw lest::expected{ lest_LOCATION, #expr, lest::of_type( #excpt ) }; \
}
#define lest_LOCATION lest::location{__FILE__, __LINE__}
namespace lest {
struct test
{
const std::string name;
const std::function<void()> behaviour;
};
struct location
{
const std::string file;
const int line;
location( std::string file, int line )
: file{ file }, line{ line } {}
};
struct comment
{
const std::string text;
comment( std::string text ) : text{ text } {}
explicit operator bool() { return ! text.empty(); }
};
struct message : std::runtime_error
{
const std::string kind;
const location where;
const comment note;
~message() throw() {} // GCC 4.6
message( std::string kind, location where, std::string expr, std::string note = "" )
: std::runtime_error{ expr }, kind{ kind }, where{ where }, note{ note } {}
};
struct failure : message
{
failure( location where, std::string expr )
: message{ "failed", where, expr } {}
};
struct expected : message
{
expected( location where, std::string expr, std::string excpt = "" )
: message{ "failed: didn't get exception", where, expr, excpt } {}
};
struct unexpected : message
{
unexpected( location where, std::string expr, std::string note )
: message{ "failed: got unexpected exception", where, expr, note } {}
};
inline bool serum( bool verum ) { return verum; }
inline std::string with_message( std::string text )
{
return "with message \"" + text + "\"";
}
inline std::string of_type( std::string text )
{
return "of type " + text;
}
inline std::string pluralise( int n, std::string text )
{
return n == 1 ? text : text + "s";
}
inline std::ostream & operator<<( std::ostream & os, comment note )
{
return os << (note ? " " + note.text : "" );
}
inline std::ostream & operator<<( std::ostream & os, location where )
{
#ifdef __GNUG__
return os << where.file << ":" << where.line;
#else
return os << where.file << "(" << where.line << ")";
#endif
}
inline void report( std::ostream & os, message const & e, std::string test )
{
os << e.where << ": " << e.kind << e.note << ": " << test << ": " << e.what() << std::endl;
}
template<std::size_t N>
int run( test const (&specification)[N], std::ostream & os = std::cout )
{
int failures = 0;
for ( auto & testing : specification )
{
try
{
testing.behaviour();
}
catch( message const & e )
{
++failures;
report( os, e, testing.name );
}
}
if ( failures > 0 )
{
os << failures << " out of " << N << " " << pluralise(N, "test") << " failed." << std::endl;
}
return failures;
}
} // namespace lest
#endif // LEST_LEST_H_INCLUDED

54
test/tempfile.h Normal file
View File

@ -0,0 +1,54 @@
// This file is part of the brlaser printer driver.
//
// Copyright 2014 Peter De Wachter
//
// brlaser 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.
//
// brlaser 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 brlaser. If not, see <http://www.gnu.org/licenses/>.
#ifndef TEMPFILE_H
#define TEMPFILE_H
#include <stdio.h>
#include <stdlib.h>
#include <vector>
class tempfile {
public:
explicit tempfile()
: ptr_(0),
size_(0),
file_(open_memstream(&ptr_, &size_)) {
}
~tempfile() {
fclose(file_);
free(ptr_);
}
FILE *file() {
return file_;
}
std::vector<uint8_t> data() {
if (fflush(file_))
return std::vector<uint8_t>();
return std::vector<uint8_t>(ptr_, ptr_ + size_);
}
private:
char *ptr_;
size_t size_;
FILE *file_;
};
#endif // TEMPFILE_H

75
test/test_block.cc Normal file
View File

@ -0,0 +1,75 @@
// This file is part of the brlaser printer driver.
//
// Copyright 2014 Peter De Wachter
//
// brlaser 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.
//
// brlaser 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 brlaser. If not, see <http://www.gnu.org/licenses/>.
#include "lest.hpp"
#include <stdint.h>
#include <vector>
#include "tempfile.h"
#include "src/block.h"
typedef std::vector<uint8_t> vec;
const lest::test specification[] = {
"Block line limit",
[] {
block b;
for (int i = 0; i < 128; ++i) {
EXPECT(b.line_fits(1));
b.add_line(vec(1));
}
EXPECT(!b.line_fits(1));
},
"Block size limit",
[] {
block b;
for (int i = 0; i < 16; ++i) {
EXPECT(b.line_fits(1000));
b.add_line(vec(1000));
}
EXPECT(!b.line_fits(400));
},
"Flush",
[] {
block b;
{
tempfile f;
b.flush(f.file());
EXPECT(f.data().empty());
}
for (uint8_t n = 0; n < 10; n += 2) {
vec line = {n, static_cast<uint8_t>(n+1)};
EXPECT(b.line_fits(line.size()));
b.add_line(std::move(line));
}
{
tempfile f;
b.flush(f.file());
EXPECT(( f.data() == vec{'1','2','w',0,5,0,1,2,3,4,5,6,7,8,9} ));
}
{
tempfile f;
b.flush(f.file());
EXPECT(f.data().empty());
}
},
};
int main() {
return lest::run(specification);
}

291
test/test_lest.cc Normal file
View File

@ -0,0 +1,291 @@
// Copyright 2013 by Martin Moene
//
// Distributed under the Boost Software License, Version 1.0:
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#include "lest.hpp"
#include <sstream>
using namespace lest;
const lest::test specification[] =
{
"Function to suppress warning \"expression has no effect\" acts as identity function", []
{
EXPECT( false == serum( false ) );
EXPECT( true == serum( true ) );
},
"Function with_message() returns correct string", []
{
std::string msg = "Let writing tests become irresistibly easy and attractive.";
EXPECT( "with message \"" + msg + "\"" == with_message( msg ) );
},
"Function of_type() returns correct string", []
{
std::string msg = "this_type";
EXPECT( "of type " + msg == of_type( msg ) );
},
"Function pluralise() adds 's' except for 1 item", []
{
std::string word = "hammer";
EXPECT( word == pluralise( 1, word ) );
for ( auto i : {0,2,3,4,5,6,7,8,9,10,11,12} )
EXPECT( word + "s" == pluralise( i, word ) );
},
"Location constructs properly", []
{
char const * file = __FILE__; int line = __LINE__;
location where{ file, line };
EXPECT( file == where.file );
EXPECT( line == where.line );
},
"Comment constructs properly", []
{
std::string text = __FILE__;
comment note = text;
EXPECT( text == note.text );
},
"Comment converted to bool indicates absence or presence of comment", []
{
EXPECT( false == bool( comment( "") ) );
EXPECT( true == bool( comment("x") ) );
},
"Failure exception type constructs and prints properly", []
{
std::string name = "test-name";
failure msg( location{"filename.cpp", 765}, "expression" );
std::ostringstream os;
report( os, msg, name );
#ifndef __GNUG__
EXPECT( os.str() == "filename.cpp(765): failed: test-name: expression\n" );
#else
EXPECT( os.str() == "filename.cpp:765: failed: test-name: expression\n" );
#endif
},
"Expected exception type constructs and prints properly", []
{
std::string name = "test-name";
expected msg( location{"filename.cpp", 765}, "expression" );
std::ostringstream os;
report( os, msg, name );
#ifndef __GNUG__
EXPECT( os.str() == "filename.cpp(765): failed: didn't get exception: test-name: expression\n" );
#else
EXPECT( os.str() == "filename.cpp:765: failed: didn't get exception: test-name: expression\n" );
#endif
},
"Unexpected exception type constructs and prints properly", []
{
std::string name = "test-name";
unexpected msg( location{"filename.cpp", 765}, "expression", "exception-type" );
std::ostringstream os;
report( os, msg, name );
#ifndef __GNUG__
EXPECT( os.str() == "filename.cpp(765): failed: got unexpected exception exception-type: test-name: expression\n" );
#else
EXPECT( os.str() == "filename.cpp:765: failed: got unexpected exception exception-type: test-name: expression\n" );
#endif
},
"Expect generates no message exception for a succeeding test", []
{
test pass = { "P", [] { EXPECT( true ); } };
try { pass.behaviour(); }
catch(...) { throw failure(location{__FILE__,__LINE__}, "unexpected error generated"); }
},
"Expect generates a message exception for a failing test", []
{
test fail = { "F", [] { EXPECT( false ); } };
for (;;)
{
try { fail.behaviour(); } catch ( message & ) { break; }
throw failure(location{__FILE__,__LINE__}, "no error generated");
}
},
"Expect succeeds for success (true) and failure (false)", []
{
test pass[] = {{ "P", [] { EXPECT( true ); } }};
test fail[] = {{ "F", [] { EXPECT( false ); } }};
std::ostringstream os;
EXPECT( 0 == run( pass, os ) );
EXPECT( 1 == run( fail, os ) );
},
"Expect succeeds for integer comparation", []
{
test pass [] = {{ "P" , [] { EXPECT( 7 == 7 ); EXPECT( 7 != 8 );
EXPECT( 7 >= 6 ); EXPECT( 7 <= 8 );
EXPECT( 7 > 6 ); EXPECT( 7 < 8 ); } }};
test fail_1[] = {{ "F1", [] { EXPECT( 7 == 8 ); } }};
test fail_2[] = {{ "F2", [] { EXPECT( 7 != 7 ); } }};
test fail_3[] = {{ "F3", [] { EXPECT( 7 <= 6 ); } }};
test fail_4[] = {{ "F4", [] { EXPECT( 7 >= 8 ); } }};
test fail_5[] = {{ "F5", [] { EXPECT( 7 < 6 ); } }};
test fail_6[] = {{ "F6", [] { EXPECT( 7 > 8 ); } }};
std::ostringstream os;
EXPECT( 0 == run( pass , os ) );
EXPECT( 1 == run( fail_1, os ) );
EXPECT( 1 == run( fail_2, os ) );
EXPECT( 1 == run( fail_3, os ) );
EXPECT( 1 == run( fail_4, os ) );
EXPECT( 1 == run( fail_5, os ) );
EXPECT( 1 == run( fail_6, os ) );
},
"Expect succeeds for string comparation", []
{
std::string a("a"); std::string b("b");
test pass [] = {{ "P" , [=]() { EXPECT( a == a ); EXPECT( a != b );
EXPECT( b >= a ); EXPECT( a <= b );
EXPECT( b > a ); EXPECT( a < b ); } }};
test fail_1[] = {{ "F1", [=]() { EXPECT( a == b ); } }};
test fail_2[] = {{ "F2", [=]() { EXPECT( a != a ); } }};
test fail_3[] = {{ "F3", [=]() { EXPECT( b <= a ); } }};
test fail_4[] = {{ "F4", [=]() { EXPECT( a >= b ); } }};
test fail_5[] = {{ "F5", [=]() { EXPECT( b < a ); } }};
test fail_6[] = {{ "F6", [=]() { EXPECT( a > b ); } }};
std::ostringstream os;
EXPECT( 0 == run( pass , os ) );
EXPECT( 1 == run( fail_1, os ) );
EXPECT( 1 == run( fail_2, os ) );
EXPECT( 1 == run( fail_3, os ) );
EXPECT( 1 == run( fail_4, os ) );
EXPECT( 1 == run( fail_5, os ) );
EXPECT( 1 == run( fail_6, os ) );
},
"Function run() returns the right failure count", []
{
test pass [] = {{ "P" , [] { EXPECT( 1==1 ); } }};
test fail_1[] = {{ "F1", [] { EXPECT( 0==1 ); } }};
test fail_3[] = {{ "F1", [] { EXPECT( 0==1 ); } },
{ "F2", [] { EXPECT( 0==1 ); } },
{ "F3", [] { EXPECT( 0==1 ); } },};
std::ostringstream os;
EXPECT( 0 == run( pass , os ) );
EXPECT( 1 == run( fail_1, os ) );
EXPECT( 3 == run( fail_3, os ) );
},
"Expect succeeds with an unexpected standard exception", []
{
std::string text = "hello-world";
test pass[] = {{ "P", [=]() { EXPECT( (throw std::runtime_error(text), true) ); } }};
std::ostringstream os;
EXPECT( 1 == run( pass, os ) );
EXPECT( std::string::npos != os.str().find(text) );
},
"Expect succeeds with an unexpected non-standard exception", []
{
test pass[] = {{ "P", [] { EXPECT( (throw 77, true) ); } }};
std::ostringstream os;
EXPECT( 1 == run( pass, os ) );
},
"Expect_throws succeeds with an expected standard exception", []
{
std::string text = "hello-world";
test pass[] = {{ "P", [=]() { EXPECT_THROWS( (throw std::runtime_error(text), true) ); } }};
test fail[] = {{ "F", [ ]() { EXPECT_THROWS( true ); } }};
std::ostringstream os;
EXPECT( 0 == run( pass, os ) );
EXPECT( 1 == run( fail, os ) );
},
"Expect_throws succeeds with an expected non-standard exception", []
{
test pass[] = {{ "P", [] { EXPECT_THROWS( (throw 77, true) ); } }};
test fail[] = {{ "F", [] { EXPECT_THROWS( true ); } }};
std::ostringstream os;
EXPECT( 0 == run( pass, os ) );
EXPECT( 1 == run( fail, os ) );
},
"Expect_throws_as succeeds with a specific expected standard exception", []
{
test pass[] = {{ "P", [] { EXPECT_THROWS_AS( (throw std::bad_alloc(), true), std::bad_alloc ); } }};
test fail[] = {{ "F", [] { EXPECT_THROWS_AS( (throw std::bad_alloc(), true), std::runtime_error ); } }};
std::ostringstream os;
EXPECT( 0 == run( pass, os ) );
EXPECT( 1 == run( fail, os ) );
},
"Expect_throws_as succeeds with a specific expected non-standard exception", []
{
test pass[] = {{ "P", [] { EXPECT_THROWS_AS( (throw 77, true), int ); } }};
test fail[] = {{ "F", [] { EXPECT_THROWS_AS( (throw 77, true), std::runtime_error ); } }};
std::ostringstream os;
EXPECT( 0 == run( pass, os ) );
EXPECT( 1 == run( fail, os ) );
},
};
int main()
{
return lest::run( specification );
}
// cl -nologo -Wall -EHsc test_lest.cpp && test_lest
// g++ -Wall -Wextra -Weffc++ -std=c++11 -o test_lest.exe test_lest.cpp && test_lest

150
test/test_line.cc Normal file
View File

@ -0,0 +1,150 @@
// This file is part of the brlaser printer driver.
//
// Copyright 2014 Peter De Wachter
//
// brlaser 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.
//
// brlaser 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 brlaser. If not, see <http://www.gnu.org/licenses/>.
#include "lest.hpp"
#include <assert.h>
#include <stdint.h>
#include <vector>
#include "src/line.h"
typedef std::vector<uint8_t> vec;
uint8_t sub(uint8_t offset, uint8_t count) {
assert(offset < 16);
assert(count < 8);
return (offset << 3) | count;
}
uint8_t rep(uint8_t offset, uint8_t count) {
assert(offset < 4);
assert(count < 32);
return 128 | (offset << 5) | count;
}
const lest::test specification[] = {
"Don't crash on zero-length lines",
[] {
EXPECT(( encode_line(vec{}) == vec{0xFF} ));
EXPECT(( encode_line(vec{}, vec{}) == vec{0xFF} ));
},
"Encoding an initial blank line",
[] {
EXPECT(( encode_line(vec{0,0,0}) == vec{0xFF} ));
},
"Encoding an initial non-blank line",
[] {
EXPECT(( encode_line(vec{1,2,3}) == (vec{1,sub(0,2),1,2,3}) ));
},
"Encoding a (non-initial) blank line",
[] {
EXPECT(( encode_line(vec{0,0,0}, vec{1,2,3}) == vec{0xFF} ));
},
"Encoding a repeated line",
[] {
EXPECT(( encode_line(vec{1,2,3}, vec{1,2,3}) == vec{0} ));
},
"Using a subsitute command",
[] {
EXPECT(( encode_line(vec{0,0,1,2,3,0,0}, vec(7)) == vec{1,sub(2,2),1,2,3} ));
},
"Using a repeat command",
[] {
EXPECT(( encode_line(vec{0,0,1,1,0,0}, vec(6)) == vec{1,rep(2,0),1} ));
},
"Repeat command followed by substitute command",
[] {
EXPECT(( encode_line(vec{1,1,1,2,3}, vec(5)) == vec{2,rep(0,1),1,sub(0,1),2,3} ));
},
"Substitute comand followed by repeat command",
[] {
EXPECT(( encode_line(vec{3,2,1,1,1}, vec(5)) == vec{2,sub(0,1),3,2,rep(0,1),1} ));
},
"Substitute with an unmodified byte in the middle",
[] {
EXPECT(( encode_line(vec{1,2,3,0,1,2,3}, vec(7)) == vec{1,sub(0,6),1,2,3,0,1,2,3} ));
},
"Substitue with two unmodified bytes in the middle",
[] {
EXPECT(( encode_line(vec{1,2,3,0,0,1,2,3}, vec(8)) == vec{2,sub(0,2),1,2,3,sub(2,2),1,2,3} ));
},
"Repeat with an unmodified byte in the middle",
[] {
EXPECT(( encode_line(vec{1,1,1,0,1,1,1}, vec(7)) == vec{2,rep(0,1),1,rep(1,1),1} ));
},
"254 edits needed for a single line",
[] {
vec line, result;
for (int i = 0; i < 254; ++i)
line.insert(line.end(), {0,0,1});
result.push_back(254);
for (int i = 0; i < 254; ++i)
result.insert(result.end(), {sub(2,0),1});
EXPECT(( encode_line(line, vec(line.size())) == result ));
},
"Give up if more than 254 edits needed...",
[] {
vec line, result;
for (int i = 0; i < 255; ++i)
line.insert(line.end(), {0,0,1});
result.push_back(254);
for (int i = 0; i < 253; ++i)
result.insert(result.end(), {sub(2,0),1});
result.insert(result.end(), {sub(2,3),1,0,0,1});
EXPECT(( encode_line(line, vec(line.size())) == result ));
},
"Repeat command with overflow bytes",
[] {
vec line(3, 0);
line.insert(line.end(), 512, 1);
vec ref(line.size(), 0);
vec expected{1,rep(3,31),0,255,224,1};
EXPECT(encode_line(line, ref) == expected);
},
"Substitute command with overflow bytes",
[] {
vec expected{1,sub(15,7),255,0,255,237};
vec line(270, 0);
for (int i = 0; i < 250; ++i) {
expected.insert(expected.end(), {1,2});
line.insert(line.end(), {1,2});
}
vec ref(line.size(), 0);
EXPECT(encode_line(line, ref) == expected);
},
};
int main() {
return lest::run(specification);
}