6 changed files with 784 additions and 0 deletions
@ -0,0 +1,197 @@ |
|||||||
|
// 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( 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
|
||||||
@ -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
|
||||||
@ -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); |
||||||
|
} |
||||||
@ -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
|
||||||
|
|
||||||
@ -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); |
||||||
|
} |
||||||
Loading…
Reference in new issue