Sexpr/QA: Split out the sexpr classes into a reusable lib and test

The SEXPR class is a useful general-purpose S-Expression library
class and can (maybe) be used else where. It also should get
test coverage, as even if noone else uses it, it's critical for the
kicad2step exporter.

Also add some test coverage for some kicad2step routines. For now,
they're not useful outside kicad2step, but they are at least a useful
reference for S-Expression parsing.
This commit is contained in:
John Beard 2019-04-15 18:09:27 +01:00
parent 2a00fc962b
commit 03214b5dea
28 changed files with 1068 additions and 38 deletions

View File

@ -931,6 +931,7 @@ endif()
# Binaries ( CMake targets ) # Binaries ( CMake targets )
add_subdirectory( bitmaps_png ) add_subdirectory( bitmaps_png )
add_subdirectory( libs )
add_subdirectory( common ) add_subdirectory( common )
add_subdirectory( 3d-viewer ) add_subdirectory( 3d-viewer )
add_subdirectory( cvpcb ) add_subdirectory( cvpcb )

26
libs/CMakeLists.txt Normal file
View File

@ -0,0 +1,26 @@
#
# This program source code file is part of KICAD, a free EDA CAD application.
#
# Copyright (C) 2019 Kicad Developers, see AUTHORS.txt for contributors.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you may find one here:
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# or you may search the http://www.gnu.org website for the version 2 license,
# or you may write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
# Build file for generic re-useable libraries
add_subdirectory( sexpr )

45
libs/sexpr/CMakeLists.txt Normal file
View File

@ -0,0 +1,45 @@
#
# This program source code file is part of KICAD, a free EDA CAD application.
#
# Copyright (C) 2019 Kicad Developers, see AUTHORS.txt for contributors.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you may find one here:
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# or you may search the http://www.gnu.org website for the version 2 license,
# or you may write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
# Build file for the S-Expression library
set( SEXPR_LIB_FILES
sexpr.cpp
sexpr_parser.cpp
)
add_library( sexpr ${SEXPR_LIB_FILES} )
target_include_directories( sexpr PUBLIC
include
)
# the s-exp parser has a dep on the wxFile methods
target_link_libraries( sexpr
${wxWidgets_LIBRARIES}
)
# TODO get deps from here out of common
target_include_directories( sexpr PRIVATE
${CMAKE_SOURCE_DIR}/include
)

View File

@ -67,7 +67,7 @@ namespace SEXPR
std::string const & GetString() const; std::string const & GetString() const;
std::string const & GetSymbol() const; std::string const & GetSymbol() const;
SEXPR_LIST* GetList(); SEXPR_LIST* GetList();
std::string AsString( size_t aLevel = 0); std::string AsString( size_t aLevel = 0) const;
size_t GetLineNumber() { return m_lineNumber; } size_t GetLineNumber() { return m_lineNumber; }
}; };
@ -293,6 +293,7 @@ namespace SEXPR
size_t doScan( const SEXPR_SCAN_ARG *args, size_t num_args ); size_t doScan( const SEXPR_SCAN_ARG *args, size_t num_args );
void doAddChildren( const SEXPR_CHILDREN_ARG *args, size_t num_args ); void doAddChildren( const SEXPR_CHILDREN_ARG *args, size_t num_args );
}; };
}
} // namespace SEXPR
#endif #endif

View File

@ -145,7 +145,7 @@ namespace SEXPR
return static_cast< SEXPR_LIST* >(this); return static_cast< SEXPR_LIST* >(this);
} }
std::string SEXPR::AsString( size_t aLevel ) std::string SEXPR::AsString( size_t aLevel ) const
{ {
std::string result; std::string result;

View File

@ -22,6 +22,9 @@ add_subdirectory( common )
add_subdirectory( pcbnew ) add_subdirectory( pcbnew )
add_subdirectory( eeschema ) add_subdirectory( eeschema )
add_subdirectory( libs )
add_subdirectory( utils/kicad2step )
# Utility/debugging/profiling programs # Utility/debugging/profiling programs
add_subdirectory( common_tools ) add_subdirectory( common_tools )
add_subdirectory( pcbnew_tools ) add_subdirectory( pcbnew_tools )

24
qa/libs/CMakeLists.txt Normal file
View File

@ -0,0 +1,24 @@
# This program source code file is part of KiCad, a free EDA CAD application.
#
# Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you may find one here:
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# or you may search the http://www.gnu.org website for the version 2 license,
# or you may write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# QA tests and tools for common libraries
add_subdirectory( sexpr )

View File

@ -0,0 +1,46 @@
# This program source code file is part of KiCad, a free EDA CAD application.
#
# Copyright (C) 2019 KiCad Developers, see AUTHORS.TXT for contributors.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you may find one here:
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# or you may search the http://www.gnu.org website for the version 2 license,
# or you may write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
# Unit tests for s-expr handling routines
set( SEXPR_SRCS
test_module.cpp
test_sexpr.cpp
test_sexpr_parser.cpp
)
add_executable( qa_sexpr ${SEXPR_SRCS} )
target_link_libraries( qa_sexpr
sexpr
unit_test_utils
${wxWidgets_LIBRARIES}
)
target_include_directories( qa_sexpr PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)
add_test( NAME sexpr
COMMAND qa_sexpr
)

View File

@ -0,0 +1,244 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef TEST_SEXPR_TEST_UTILS__H
#define TEST_SEXPR_TEST_UTILS__H
#include <sexpr/sexpr.h>
#include <unit_test_utils/unit_test_utils.h>
namespace KI_TEST
{
/**
* Get the type of the s-expression.
*/
inline SEXPR::SEXPR_TYPE getType( const SEXPR::SEXPR& aSexpr )
{
if( aSexpr.IsList() )
return SEXPR::SEXPR_TYPE::SEXPR_TYPE_LIST;
else if( aSexpr.IsSymbol() )
return SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_SYMBOL;
else if( aSexpr.IsString() )
return SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_STRING;
else if( aSexpr.IsDouble() )
return SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_DOUBLE;
else if( aSexpr.IsInteger() )
return SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_INTEGER;
throw( std::invalid_argument( "<Unknown S-Expression Type!>" ) );
}
/**
* Get a debug-friendly string for a given s-expr type
*/
inline std::string getDebugType( SEXPR::SEXPR_TYPE aType )
{
switch( aType )
{
case SEXPR::SEXPR_TYPE::SEXPR_TYPE_LIST:
return "List";
case SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_SYMBOL:
return "Symbol";
case SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_STRING:
return "String";
case SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_DOUBLE:
return "Double";
case SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_INTEGER:
return "Integer";
}
return "<Unknown S-Expression Type!>";
}
inline std::string GetSexprDebugType( const SEXPR::SEXPR& aSexpr )
{
return getDebugType( getType( aSexpr ) );
}
inline bool IsSexprOfType( const SEXPR::SEXPR& aSexpr, SEXPR::SEXPR_TYPE aType )
{
if( getType( aSexpr ) != aType )
{
BOOST_TEST_MESSAGE( "Sexpr is not of type: " << getDebugType( aType ) );
return false;
}
return true;
}
/**
* Predicate to check two s-expr values (of the same type) are equal
*
* @return false if not equal (and output logging)
*/
template <typename VAL_T>
bool IsSexprValueEqual( const VAL_T& aGot, const VAL_T& aExpected )
{
if( aGot != aExpected )
{
BOOST_TEST_MESSAGE( "Sexpr value not equal: got " << aGot << ", expected " << aExpected );
return false;
}
return true;
}
/**
* Test predicate: is the s-expression a symbol?
*/
inline bool SexprIsSymbol( const SEXPR::SEXPR& aSexpr )
{
return IsSexprOfType( aSexpr, SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_SYMBOL );
}
/**
* Test predicate: is the s-expression a symbol with the given value?
*/
inline bool SexprIsSymbolWithValue( const SEXPR::SEXPR& aSexpr, const std::string& aVal )
{
return IsSexprOfType( aSexpr, SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_SYMBOL )
&& IsSexprValueEqual( aSexpr.GetSymbol(), aVal );
}
/**
* Test predicate: is the s-expression a string?
*/
inline bool SexprIsString( const SEXPR::SEXPR& aSexpr )
{
return IsSexprOfType( aSexpr, SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_STRING );
}
/**
* Test predicate: is the s-expression a string with the given value?
*/
inline bool SexprIsStringWithValue( const SEXPR::SEXPR& aSexpr, const std::string& aVal )
{
return IsSexprOfType( aSexpr, SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_STRING )
&& IsSexprValueEqual( aSexpr.GetString(), aVal );
}
/**
* Test predicate: is the s-expression an integer?
*/
inline bool SexprIsInteger( const SEXPR::SEXPR& aSexpr )
{
return IsSexprOfType( aSexpr, SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_INTEGER );
}
/**
* Test predicate: is the s-expression an integer with the given value?
*/
inline bool SexprIsIntegerWithValue( const SEXPR::SEXPR& aSexpr, std::int64_t aVal )
{
return IsSexprOfType( aSexpr, SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_INTEGER )
&& IsSexprValueEqual( aSexpr.GetLongInteger(), aVal );
}
/**
* Test predicate: is the s-expression a double?
*/
inline bool SexprIsDouble( const SEXPR::SEXPR& aSexpr )
{
return IsSexprOfType( aSexpr, SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_DOUBLE );
}
/**
* Test predicate: is the s-expression a double with the given value?
*/
inline bool SexprIsDoubleWithValue( const SEXPR::SEXPR& aSexpr, double aVal )
{
return IsSexprOfType( aSexpr, SEXPR::SEXPR_TYPE::SEXPR_TYPE_ATOM_DOUBLE )
&& IsSexprValueEqual( aSexpr.GetDouble(), aVal );
}
/**
* Test predicate: is the s-expression a double?
*/
inline bool SexprIsList( const SEXPR::SEXPR& aSexpr )
{
return IsSexprOfType( aSexpr, SEXPR::SEXPR_TYPE::SEXPR_TYPE_LIST );
}
/**
* Test predicate: is the s-expression a list with the given length?
*/
inline bool SexprIsListOfLength( const SEXPR::SEXPR& aSexpr, size_t aExpectedLength )
{
if( !IsSexprOfType( aSexpr, SEXPR::SEXPR_TYPE::SEXPR_TYPE_LIST ) )
return false;
if( aSexpr.GetNumberOfChildren() != aExpectedLength )
{
BOOST_TEST_MESSAGE( "List is wrong length: got " << aSexpr.GetNumberOfChildren()
<< ", expected " << aExpectedLength );
return false;
}
return true;
}
/**
* Predicate to check an SEXPR object converts to the expected string.
* @param aSexpr s-expression
* @param aExpStr expected string
* @return true if match
*/
inline bool SexprConvertsToString( const SEXPR::SEXPR& aSexpr, const std::string& aExpStr )
{
const std::string converted = aSexpr.AsString();
bool ok = true;
if( converted != aExpStr )
{
BOOST_TEST_INFO( "Sexpr string conversion mismatch: got '" << converted << "', expected '"
<< aExpStr << "'" );
ok = false;
}
return ok;
}
} // namespace KI_TEST
BOOST_TEST_PRINT_NAMESPACE_OPEN
{
/**
* Boost print helper for SEXPR objects
*/
template <>
struct print_log_value<SEXPR::SEXPR>
{
inline void operator()( std::ostream& os, const SEXPR::SEXPR& aSexpr )
{
os << "SEXPR [ " << KI_TEST::GetSexprDebugType( aSexpr ) << " ]\n " << aSexpr.AsString();
}
};
}
BOOST_TEST_PRINT_NAMESPACE_CLOSE
#endif // TEST_SEXPR_TEST_UTILS__H

View File

@ -0,0 +1,28 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* Main file for the Sexpr tests
*/
#define BOOST_TEST_MODULE Sexpr
#include <boost/test/unit_test.hpp>

View File

@ -0,0 +1,109 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file
* Test suite for SEXPR::PARSER
*/
#include <unit_test_utils/unit_test_utils.h>
// Code under test
#include <sexpr/sexpr.h>
#include "sexpr_test_utils.h"
/**
* Declare the test suite
*/
BOOST_AUTO_TEST_SUITE( Sexpr )
BOOST_AUTO_TEST_CASE( BasicConstruction )
{
SEXPR::SEXPR_INTEGER s_int{ 1 };
// not sure why cast is needed, but boost doesn't like it without
BOOST_CHECK_PREDICATE( KI_TEST::SexprIsIntegerWithValue, ( (SEXPR::SEXPR&) s_int )( 1 ) );
SEXPR::SEXPR_DOUBLE s_double{ 3.14 };
BOOST_CHECK_PREDICATE( KI_TEST::SexprIsDoubleWithValue, ( (SEXPR::SEXPR&) s_double )( 3.14 ) );
SEXPR::SEXPR_STRING s_string{ "string" };
BOOST_CHECK_PREDICATE(
KI_TEST::SexprIsStringWithValue, ( (SEXPR::SEXPR&) s_string )( "string" ) );
SEXPR::SEXPR_STRING s_symbol{ "symbol" };
BOOST_CHECK_PREDICATE(
KI_TEST::SexprIsStringWithValue, ( (SEXPR::SEXPR&) s_symbol )( "symbol" ) );
}
BOOST_AUTO_TEST_CASE( AsStringInt )
{
SEXPR::SEXPR_INTEGER s{ 1 };
// not sure why cast is needed, but boost doesn't like it without
BOOST_CHECK_PREDICATE( KI_TEST::SexprConvertsToString, ( (SEXPR::SEXPR&) s )( "1" ) );
}
BOOST_AUTO_TEST_CASE( AsStringDouble )
{
SEXPR::SEXPR_DOUBLE s{ 3.14 };
BOOST_CHECK_PREDICATE( KI_TEST::SexprConvertsToString, ( (SEXPR::SEXPR&) s )( "3.14" ) );
}
BOOST_AUTO_TEST_CASE( AsStringSymbol )
{
SEXPR::SEXPR_SYMBOL s{ "symbol" };
BOOST_CHECK_PREDICATE( KI_TEST::SexprConvertsToString, ( (SEXPR::SEXPR&) s )( "symbol" ) );
}
BOOST_AUTO_TEST_CASE( AsStringString )
{
SEXPR::SEXPR_STRING s{ "string" };
// strings get quotes
BOOST_CHECK_PREDICATE( KI_TEST::SexprConvertsToString, ( (SEXPR::SEXPR&) s )( "\"string\"" ) );
}
BOOST_AUTO_TEST_CASE( AsStringList )
{
SEXPR::SEXPR_LIST s_list;
s_list.AddChild( new SEXPR::SEXPR_SYMBOL{ "symbol" } );
{
auto* s_SubList = new SEXPR::SEXPR_LIST();
*s_SubList << 2 << 42.42 << "substring";
s_list.AddChild( s_SubList );
}
s_list << 1 << 3.14 << "string";
BOOST_CHECK_PREDICATE( KI_TEST::SexprIsListOfLength, ( (SEXPR::SEXPR&) s_list )( 5 ) );
// REVIEW: should there be a space at the end of the "symbol"?
BOOST_CHECK_PREDICATE( KI_TEST::SexprConvertsToString,
( (SEXPR::SEXPR&) s_list )( "(symbol \n"
" (2 42.42 \"substring\") 1 3.14 \"string\")" ) );
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,240 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file
* Test suite for SEXPR::PARSER
*/
#include <unit_test_utils/unit_test_utils.h>
// Code under test
#include <sexpr/sexpr_parser.h>
#include "sexpr_test_utils.h"
class TEST_SEXPR_PARSER_FIXTURE
{
public:
/**
* Wrap the parser function with a unique_ptr
*/
std::unique_ptr<SEXPR::SEXPR> Parse( const std::string& aIn )
{
return std::unique_ptr<SEXPR::SEXPR>( m_parser.Parse( aIn ) );
}
SEXPR::PARSER m_parser;
};
/**
* Collection of test cases for use when multiple cases can be handled in the
* same test case.
*/
struct TEST_SEXPR_CASE
{
std::string m_case_name;
std::string m_sexpr_data;
};
/**
* Declare the test suite
*/
BOOST_FIXTURE_TEST_SUITE( SexprParser, TEST_SEXPR_PARSER_FIXTURE )
/**
* Cases that result in no s-expr object
*/
BOOST_AUTO_TEST_CASE( Empty )
{
const std::vector<TEST_SEXPR_CASE> cases = {
{
"Empty string",
"",
},
{
"whitespace",
" ",
},
};
for( const auto& c : cases )
{
BOOST_TEST_CONTEXT( c.m_case_name )
{
const auto data = Parse( c.m_sexpr_data );
BOOST_CHECK_EQUAL( data.get(), nullptr );
}
}
}
/**
* This comes out as a single symbol
*/
BOOST_AUTO_TEST_CASE( Words )
{
const std::string content{ "this is just writing" };
const auto sexp = Parse( content );
BOOST_REQUIRE_NE( sexp.get(), nullptr );
BOOST_CHECK_PREDICATE( KI_TEST::SexprIsSymbolWithValue, ( *sexp )( "this" ) );
}
/**
* This comes out as a single symbol
*/
BOOST_AUTO_TEST_CASE( ParseExceptions )
{
const std::vector<TEST_SEXPR_CASE> cases = {
{
"Unclosed (symbol",
"(symbol",
},
{
"Comma",
",",
},
{
"Int only",
"1",
},
{
"Double only",
"3.14",
},
{
"Symbol only",
"symbol",
},
// { // this is OK for some reason
// "String only",
// "\"string\"",
// },
};
for( const auto& c : cases )
{
BOOST_TEST_CONTEXT( c.m_case_name )
{
BOOST_CHECK_THROW( Parse( c.m_sexpr_data ), SEXPR::PARSE_EXCEPTION );
}
}
}
/**
* This comes out as an empty list
*/
BOOST_AUTO_TEST_CASE( EmptyParens )
{
const std::string content{ "()" };
const auto sexp = Parse( content );
BOOST_REQUIRE_NE( sexp.get(), nullptr );
BOOST_CHECK_PREDICATE( KI_TEST::SexprIsListOfLength, ( *sexp )( 0 ) );
}
/**
* Single symbol in parens
*/
BOOST_AUTO_TEST_CASE( SimpleSymbol )
{
const std::string content{ "(symbol)" };
const auto sexp = Parse( content );
BOOST_REQUIRE_NE( sexp.get(), nullptr );
BOOST_REQUIRE_PREDICATE( KI_TEST::SexprIsListOfLength, ( *sexp )( 1 ) );
const SEXPR::SEXPR& child = *sexp->GetChild( 0 );
BOOST_CHECK_PREDICATE( KI_TEST::SexprIsSymbolWithValue, ( child )( "symbol" ) );
}
/**
* Test several atoms in a list, including nested lists
*/
BOOST_AUTO_TEST_CASE( SymbolString )
{
const std::string content{ "(symbol \"string\" 42 3.14 (nested 4 ()))" };
const auto sexp = Parse( content );
BOOST_REQUIRE_NE( sexp.get(), nullptr );
BOOST_REQUIRE_PREDICATE( KI_TEST::SexprIsListOfLength, ( *sexp )( 5 ) );
BOOST_CHECK_PREDICATE( KI_TEST::SexprIsSymbolWithValue, ( *sexp->GetChild( 0 ) )( "symbol" ) );
BOOST_CHECK_PREDICATE( KI_TEST::SexprIsStringWithValue, ( *sexp->GetChild( 1 ) )( "string" ) );
BOOST_CHECK_PREDICATE( KI_TEST::SexprIsIntegerWithValue, ( *sexp->GetChild( 2 ) )( 42 ) );
BOOST_CHECK_PREDICATE( KI_TEST::SexprIsDoubleWithValue, ( *sexp->GetChild( 3 ) )( 3.14 ) );
// and child list
const SEXPR::SEXPR& sublist = *sexp->GetChild( 4 );
BOOST_REQUIRE_PREDICATE( KI_TEST::SexprIsListOfLength, ( sublist )( 3 ) );
BOOST_CHECK_PREDICATE(
KI_TEST::SexprIsSymbolWithValue, ( *sublist.GetChild( 0 ) )( "nested" ) );
BOOST_CHECK_PREDICATE( KI_TEST::SexprIsIntegerWithValue, ( *sublist.GetChild( 1 ) )( 4 ) );
BOOST_CHECK_PREDICATE( KI_TEST::SexprIsListOfLength, ( *sublist.GetChild( 2 ) )( 0 ) );
}
/**
* Test for roundtripping (valid) s-expression back to strings
*
* Note: the whitespace has to be the same in this test.
*/
struct TEST_SEXPR_ROUNDTRIPPING
{
std::string m_case_name;
std::string m_input;
};
BOOST_AUTO_TEST_CASE( StringRoundtrip )
{
const std::vector<TEST_SEXPR_ROUNDTRIPPING> cases = {
{
"empty list",
"()",
},
{
"simple list",
"(42 3.14 \"string\")",
},
{
"nested list", // REVIEW space after 42?
"(42 \n (1 2))",
},
};
for( const auto& c : cases )
{
BOOST_TEST_CONTEXT( c.m_case_name )
{
const auto sexp = Parse( c.m_input );
const std::string as_str = sexp->AsString();
BOOST_CHECK_PREDICATE( KI_TEST::SexprConvertsToString, ( *sexp )( c.m_input ) );
}
}
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,44 @@
# This program source code file is part of KiCad, a free EDA CAD application.
#
# Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you may find one here:
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# or you may search the http://www.gnu.org website for the version 2 license,
# or you may write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# kicad2step s-expr handling routines
set( K2S_TEST_SRCS
test_module.cpp
pcb/test_base.cpp
)
add_executable( qa_kicad2step ${K2S_TEST_SRCS} )
target_link_libraries( qa_kicad2step
kicad2step_lib
unit_test_utils
${wxWidgets_LIBRARIES}
)
target_include_directories( qa_sexpr PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)
add_test( NAME kicad2step
COMMAND qa_kicad2step
)

View File

@ -0,0 +1,135 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file
* Test suite for PCB "base" sexpr parsing
*/
#include <unit_test_utils/unit_test_utils.h>
// Code under test
#include <pcb/base.h>
#include <sexpr/sexpr_parser.h>
#include <cmath>
BOOST_TEST_PRINT_NAMESPACE_OPEN
{
template <>
struct print_log_value<DOUBLET>
{
inline void operator()( std::ostream& os, DOUBLET const& o )
{
os << "DOUBLET[ " << o.x << ", " << o.y << " ]";
}
};
}
BOOST_TEST_PRINT_NAMESPACE_CLOSE
/**
* Radians from degrees
*/
constexpr double DegToRad( double aDeg )
{
return aDeg * M_PI / 180.0;
}
/**
* Declare the test suite
*/
BOOST_AUTO_TEST_SUITE( PcbBase )
struct TEST_2D_POS_ROT
{
std::string m_sexp;
bool m_valid;
DOUBLET m_exp_pos;
double m_exp_rot;
};
/**
* Test the Get2DPositionAndRotation function
*/
BOOST_AUTO_TEST_CASE( SexprTo2DPosAndRot )
{
const std::vector<TEST_2D_POS_ROT> cases = {
{
"(at 0 0 0)",
true,
{ 0.0, 0.0 },
0.0,
},
{
"(at 3.14 4.12 90.4)",
true,
{ 3.14, 4.12 },
DegToRad( 90.4 ),
},
{
"(at 3.14)", // no enough params
false,
{},
{},
},
{
"(att 3.14 4.12 90.4)",
false,
{},
{},
},
};
SEXPR::PARSER parser;
for( const auto& c : cases )
{
BOOST_TEST_CONTEXT( c.m_sexp )
{
DOUBLET gotPos;
double gotRot;
std::unique_ptr<SEXPR::SEXPR> sexpr( parser.Parse( c.m_sexp ) );
const bool ret = Get2DPositionAndRotation( sexpr.get(), gotPos, gotRot );
BOOST_CHECK_EQUAL( ret, c.m_valid );
if( !ret )
continue;
const double tolPercent = 0.00001; // seems small enough
BOOST_CHECK_CLOSE( gotPos.x, c.m_exp_pos.x, tolPercent );
BOOST_CHECK_CLOSE( gotPos.y, c.m_exp_pos.y, tolPercent );
BOOST_CHECK_CLOSE( gotRot, c.m_exp_rot, tolPercent );
}
}
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,48 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* Main file for the Eeschema tests to be compiled
*/
#include <boost/test/unit_test.hpp>
#include <wx/init.h>
bool init_unit_test()
{
boost::unit_test::framework::master_test_suite().p_name.value = "S-expression module tests";
return wxInitialize();
}
int main( int argc, char* argv[] )
{
int ret = boost::unit_test::unit_test_main( &init_unit_test, argc, argv );
// This causes some glib warnings on GTK3 (http://trac.wxwidgets.org/ticket/18274)
// but without it, Valgrind notices a lot of leaks from WX
wxUninitialize();
return ret;
}

View File

@ -1,6 +1,4 @@
include_directories( BEFORE include_directories( BEFORE
pcb
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include
) )
@ -9,8 +7,7 @@ include_directories( SYSTEM
${OCC_INCLUDE_DIR} ${OCC_INCLUDE_DIR}
) )
set( K2S_FILES set( KS2_LIB_FILES
kicad2step.cpp
pcb/3d_resolver.cpp pcb/3d_resolver.cpp
pcb/base.cpp pcb/base.cpp
pcb/kicadmodel.cpp pcb/kicadmodel.cpp
@ -19,8 +16,25 @@ set( K2S_FILES
pcb/kicadpcb.cpp pcb/kicadpcb.cpp
pcb/kicadcurve.cpp pcb/kicadcurve.cpp
pcb/oce_utils.cpp pcb/oce_utils.cpp
sexpr/sexpr.cpp )
sexpr/sexpr_parser.cpp
# Break the library out for re-use by both kicad2step and any qa that needs it
# In future, this could move for re-use by other programs needing s-expr support (?)
add_library( kicad2step_lib STATIC
${KS2_LIB_FILES}
)
target_include_directories( kicad2step_lib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries( kicad2step_lib
sexpr
Boost::boost
)
set( K2S_FILES
kicad2step.cpp
) )
if( MINGW ) if( MINGW )
@ -29,7 +43,11 @@ endif( MINGW )
add_executable( kicad2step ${K2S_FILES} ) add_executable( kicad2step ${K2S_FILES} )
target_link_libraries( kicad2step ${wxWidgets_LIBRARIES} ${OCC_LIBRARIES} Boost::boost ) target_link_libraries( kicad2step
kicad2step_lib
${wxWidgets_LIBRARIES}
${OCC_LIBRARIES}
)
if( APPLE ) if( APPLE )
# puts binaries into the *.app bundle while linking # puts binaries into the *.app bundle while linking

View File

@ -32,7 +32,7 @@
#include <sstream> #include <sstream>
#include <Standard_Failure.hxx> #include <Standard_Failure.hxx>
#include "kicadpcb.h" #include "pcb/kicadpcb.h"
class KICAD2MCAD : public wxAppConsole class KICAD2MCAD : public wxAppConsole
{ {

View File

@ -30,6 +30,8 @@
#ifndef KICADBASE_H #ifndef KICADBASE_H
#define KICADBASE_H #define KICADBASE_H
#include <ostream>
///> Minimum distance between points to treat them as separate ones (mm) ///> Minimum distance between points to treat them as separate ones (mm)
static constexpr double MIN_DISTANCE = 0.001; static constexpr double MIN_DISTANCE = 0.001;

View File

@ -21,15 +21,18 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <wx/log.h>
#include <iostream>
#include <sstream>
#include <math.h>
#include "sexpr/sexpr.h"
#include "kicadcurve.h" #include "kicadcurve.h"
#include <sexpr/sexpr.h>
#include <core/optional.h> #include <core/optional.h>
#include <wx/log.h>
#include <iostream>
#include <math.h>
#include <sstream>
/** /**
* Get the layer name from a layer element, if the layer is syntactically * Get the layer name from a layer element, if the layer is syntactically
* valid * valid

View File

@ -21,11 +21,13 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include "kicadmodel.h"
#include <sexpr/sexpr.h>
#include <wx/log.h> #include <wx/log.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include "sexpr/sexpr.h"
#include "kicadmodel.h"
KICADMODEL::KICADMODEL() : KICADMODEL::KICADMODEL() :

View File

@ -22,19 +22,22 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include "kicadmodule.h"
#include "3d_resolver.h"
#include "kicadcurve.h"
#include "kicadmodel.h"
#include "kicadpad.h"
#include "oce_utils.h"
#include <sexpr/sexpr.h>
#include <wx/log.h> #include <wx/log.h>
#include <iostream> #include <iostream>
#include <limits> #include <limits>
#include <sstream> #include <sstream>
#include "3d_resolver.h"
#include "sexpr/sexpr.h"
#include "kicadmodel.h"
#include "kicadmodule.h"
#include "kicadpad.h"
#include "kicadcurve.h"
#include "oce_utils.h"
KICADMODULE::KICADMODULE( KICADPCB* aParent ) KICADMODULE::KICADMODULE( KICADPCB* aParent )
{ {

View File

@ -29,9 +29,11 @@
#ifndef KICADMODULE_H #ifndef KICADMODULE_H
#define KICADMODULE_H #define KICADMODULE_H
#include "base.h"
#include "kicadpcb.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include "base.h"
namespace SEXPR namespace SEXPR
{ {

View File

@ -21,11 +21,14 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include "kicadpad.h"
#include <sexpr/sexpr.h>
#include <wx/log.h> #include <wx/log.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include "sexpr/sexpr.h"
#include "kicadpad.h"
static const char bad_pad[] = "* corrupt module in PCB file; bad pad"; static const char bad_pad[] = "* corrupt module in PCB file; bad pad";

View File

@ -21,21 +21,24 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <wx/utils.h> #include "kicadpcb.h"
#include "kicadcurve.h"
#include "kicadmodule.h"
#include "oce_utils.h"
#include <sexpr/sexpr.h>
#include <sexpr/sexpr_parser.h>
#include <wx/filename.h> #include <wx/filename.h>
#include <wx/log.h> #include <wx/log.h>
#include <wx/stdpaths.h> #include <wx/stdpaths.h>
#include <wx/utils.h>
#include <iostream> #include <iostream>
#include <memory>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <memory>
#include "kicadpcb.h"
#include "sexpr/sexpr.h"
#include "sexpr/sexpr_parser.h"
#include "kicadmodule.h"
#include "kicadcurve.h"
#include "oce_utils.h"
/* /*