mirror of
https://github.com/pdewacht/brlaser
synced 2025-07-13 12:54:22 +02:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
1dcd5b445e | |||
19edb1767b | |||
c3999acbec | |||
9c4336a8df | |||
71bb29a3ca | |||
fa26a6149a | |||
2e37d9d62a | |||
77ce307fdb | |||
7bfe0d2846 | |||
5159844b03 | |||
bb1ba17b4f | |||
cd0e4102b4 | |||
66ea095ede |
9
.gitignore
vendored
9
.gitignore
vendored
@ -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
9
ChangeLog
Normal 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.
|
40
Makefile.am
40
Makefile.am
@ -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
|
||||
|
24
README.md
24
README.md
@ -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
|
||||
---------
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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
63
src/block.h
Normal 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
|
@ -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;
|
||||
|
46
src/job.cc
46
src/job.cc
@ -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
199
test/lest.hpp
Normal 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
54
test/tempfile.h
Normal 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
75
test/test_block.cc
Normal 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
291
test/test_lest.cc
Normal 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
150
test/test_line.cc
Normal 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);
|
||||
}
|
Reference in New Issue
Block a user