Commit e29dd21e authored by Jonathan Hanks's avatar Jonathan Hanks

Restructure the code to allow unit testing.

Bring in the catch2 test frame work.  Licensed under BOOST 1.0.

Make the main logic a library, so that it can be tested.  Add initial tests.
parent abb8d5b4
cmake_minimum_required(VERSION 3.0)
project(complete_chan)
# work even on old cmake.
# most of this goes away at cmake 3.1+
INCLUDE(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG(-std=c++0x HAS_CXX_0X)
CHECK_CXX_COMPILER_FLAG(-std=c++11 HAS_CXX_11)
if (${HAS_CXX_11})
set(CPP11_FLAG "-std=c++11")
else (${HAS_CXX_11})
if (${HAS_CXX_0X})
set(CPP11_FLAG "-std=c++0x")
else (${HAS_CXX_0X})
set(CPP11_FLAG "")
endif (${HAS_CXX_0X})
endif (${HAS_CXX_11})
macro(target_requires_cpp11 target mode)
if (${CMAKE_VERSION} VERSION_GREATER "3.0.99")
target_compile_features(${target} ${mode} cxx_auto_type)
else (${CMAKE_VERSION} VERSION_GREATER "3.0.99")
target_compile_options(${target} ${mode} ${CPP11_FLAG})
endif (${CMAKE_VERSION} VERSION_GREATER "3.0.99")
endmacro()
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
include(Cpp11)
enable_testing()
add_subdirectory(third_party)
add_subdirectory(bash)
add_executable(ligo_channel_completion channel_completion.cpp)
target_requires_cpp11(ligo_channel_completion PUBLIC)
install(TARGETS ligo_channel_completion DESTINATION lib)
\ No newline at end of file
add_subdirectory(lib)
add_subdirectory(src)
......@@ -14,3 +14,6 @@ You should have received a copy of the GNU General Public License
along with this program, (in the COPYING-GPL-2.txt file in this
directory). If not, see http://www.gnu.org/licenses/
This software makes use of the catch2 testing library, which is licensed under the Boost software. See the license file in thrid_party/catch2/LICENSE.txt.
if (nds_check_cpp11_included)
return()
endif(nds_check_cpp11_included)
set(nds_check_cpp11_included TRUE)
# works even on old cmake.
# most of this goes away at cmake 3.1+
INCLUDE(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG(-std=c++0x HAS_CXX_0X)
CHECK_CXX_COMPILER_FLAG(-std=c++11 HAS_CXX_11)
if (${HAS_CXX_11})
set(CPP11_FLAG "-std=c++11")
else (${HAS_CXX_11})
if (${HAS_CXX_0X})
set(CPP11_FLAG "-std=c++0x")
else (${HAS_CXX_0X})
set(CPP11_FLAG "")
endif (${HAS_CXX_0X})
endif (${HAS_CXX_11})
macro(target_requires_cpp11 target mode)
if (${CMAKE_VERSION} VERSION_GREATER "3.0.99")
target_compile_features(${target} ${mode} cxx_auto_type)
else (${CMAKE_VERSION} VERSION_GREATER "3.0.99")
target_compile_options(${target} ${mode} ${CPP11_FLAG})
endif (${CMAKE_VERSION} VERSION_GREATER "3.0.99")
endmacro()
\ No newline at end of file
add_library(completion INTERFACE)
target_include_directories(completion INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_requires_cpp11(completion INTERFACE)
add_executable(test_completion_lib
tests/test_main.cc
tests/test_completion_lib.cc)
target_link_libraries(test_completion_lib PUBLIC
completion
catch2)
add_test(NAME completion_lib
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_completion_lib)
\ No newline at end of file
#ifndef LIGO_CHANNEL_COMPLETION_HH
#define LIGO_CHANNEL_COMPLETION_HH
// Copyright 2019 California Institute of Technology.
// You should have received a copy of the licensing terms for this
// software included in the file “LICENSE” located in the top-level
// directory of this package. If you did not, you can view a copy at
// http://dcc.ligo.org/M1500244/LICENSE.txt
#include <algorithm>
#include <iterator>
#include <fstream>
#include <string>
#include <vector>
#include <cstring>
namespace completion
{
typedef std::vector< std::string > string_list;
struct Database
{
std::vector< std::string > channels;
};
inline bool
simple_comparison( const std::string& a, const std::string& b )
{
return std::strcmp( a.c_str( ), b.c_str( ) ) < 0;
}
inline bool
key_comparison( const std::string& key, const std::string& element )
{
int result =
std::strncmp( key.c_str( ), element.c_str( ), key.size( ) );
return result < 0;
}
inline Database
load_database( const std::string& path )
{
Database db;
std::ifstream input( path.c_str( ) );
std::string line;
while ( std::getline( input, line ) )
{
db.channels.emplace_back( line );
}
return db;
}
template < typename It >
string_list
search( It begin_it, It end_it, const std::string& key )
{
string_list results;
auto lower = std::lower_bound( begin_it, end_it, key, key_comparison );
auto upper = std::upper_bound( lower, end_it, key, key_comparison );
auto key_size = key.size( );
std::for_each(
lower, upper, [key_size, &results]( const std::string& entry ) {
static const std::string delimiters( "-_" );
auto pos = entry.find_first_of( delimiters, key_size );
if ( pos == key_size )
{
pos = entry.find_first_of( delimiters, key_size + 1 );
}
if ( pos != std::string::npos )
{
if ( results.empty( ) ||
std::strncmp( results.back( ).c_str( ),
entry.c_str( ),
pos ) != 0 )
{
results.emplace_back( entry.c_str( ), pos );
}
if ( results.size( ) <= 1 && pos != std::string::npos )
{
pos = entry.find_first_of( delimiters, pos + 1 );
pos =
( pos == std::string::npos ? entry.size( ) : pos );
}
}
else
{
results.emplace_back( entry );
}
} );
return results;
}
inline void
sort( Database& db )
{
std::sort(
db.channels.begin( ), db.channels.end( ), simple_comparison );
}
}
#endif // LIGO_CHANNEL_COMPLETION_HH
\ No newline at end of file
// Copyright 2019 California Institute of Technology.
// You should have received a copy of the licensing terms for this
// software included in the file “LICENSE” located in the top-level
// directory of this package. If you did not, you can view a copy at
// http://dcc.ligo.org/M1500244/LICENSE.txt
#include "completion.hh"
#include "catch.hpp"
TEST_CASE( "Basic completion behavior" )
{
completion::Database db;
db.channels = {
"H0:VAC-SYSTEM_1", "H0:VAC-SYSTEM_2", "H0:VAC-SYSTEM_3",
"H1:SYS-SUB_A", "H1:SYS-SUB_B", "H1:SYS-SUB_C",
};
{
completion::string_list results =
completion::search( db.channels.begin( ), db.channels.end( ), "" );
REQUIRE( results.size( ) == 2 );
REQUIRE( results[ 0 ] == "H0:VAC" );
REQUIRE( results[ 1 ] == "H1:SYS" );
}
}
TEST_CASE( "Basic DB sorting" )
{
completion::Database input;
input.channels = {
"H0:VAC-SYSTEM_3", "H0:VAC-SYSTEM_1", "H1:SYS-SUB_C",
"H0:VAC-SYSTEM_2", "H1:SYS-SUB_A", "H1:SYS-SUB_B",
};
completion::Database expected;
expected.channels = {
"H0:VAC-SYSTEM_1", "H0:VAC-SYSTEM_2", "H0:VAC-SYSTEM_3",
"H1:SYS-SUB_A", "H1:SYS-SUB_B", "H1:SYS-SUB_C",
};
completion::sort( input );
REQUIRE( input.channels.size( ) == expected.channels.size( ) );
for ( int i = 0; i < input.channels.size( ); ++i )
{
REQUIRE( input.channels[ i ] == expected.channels[ i ] );
}
}
\ No newline at end of file
// Copyright 2019 California Institute of Technology.
// You should have received a copy of the licensing terms for this
// software included in the file “LICENSE” located in the top-level
// directory of this package. If you did not, you can view a copy at
// http://dcc.ligo.org/M1500244/LICENSE.txt
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this
// in one cpp file
#include "catch.hpp"
\ No newline at end of file
#!/bin/bash
if which clang-format-3.8 > /dev/null; then
CFORMAT=`which clang-format-3.8`
elif which clang-format-mp-3.8 > /dev/null; then
CFORMAT=`which clang-format-mp-3.8`
else
echo "Could not find clang format"
exit 1
fi
SOURCE_DIRS="src lib"
for dir in ${SOURCE_DIRS}; do
echo "Reformatting in ${dir}"
find ${dir} -type f -iregex ".*\.\(c\|cc\|cxx\|cpp\|h\|hh\|hpp\|hxx\)" \! -iname catch.hpp \! -iname sqlite3.\* \! -iname bash_pattern.\* -exec "${CFORMAT}" -i -style=file -fallback-style=none {} \;
done
add_executable(ligo_channel_completion ligo_channel_completion.cpp)
target_link_libraries(ligo_channel_completion PUBLIC completion)
target_requires_cpp11(ligo_channel_completion PUBLIC)
install(TARGETS ligo_channel_completion DESTINATION lib)
\ No newline at end of file
......@@ -5,91 +5,13 @@
// directory of this package. If you did not, you can view a copy at
// http://dcc.ligo.org/M1500244/LICENSE.txt
#include <algorithm>
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <vector>
#include "completion.hh"
#include <iostream>
#include <cstdlib>
#include <cstring>
static const char CHAN_LIST_ENV[] = "CHAN_LIST";
typedef std::vector< std::string > string_list;
struct Database
{
std::vector< std::string > channels;
};
bool
simple_comparison( const std::string& a, const std::string& b )
{
return std::strcmp( a.c_str( ), b.c_str( ) ) < 0;
}
bool
key_comparison( const std::string& key, const std::string& element )
{
int result = std::strncmp( key.c_str( ), element.c_str( ), key.size( ) );
return result < 0;
}
Database
load_database( const std::string& path )
{
Database db;
std::ifstream input( path.c_str( ) );
std::string line;
while ( std::getline( input, line ) )
{
db.channels.emplace_back( line );
}
return db;
}
template < typename It >
string_list
search( It begin_it, It end_it, const std::string& key )
{
string_list results;
auto lower = std::lower_bound( begin_it, end_it, key, key_comparison );
auto upper = std::upper_bound( lower, end_it, key, key_comparison );
auto key_size = key.size( );
std::for_each(
lower, upper, [key_size, &results]( const std::string& entry ) {
static const std::string delimiters( "-_" );
auto pos = entry.find_first_of( delimiters, key_size );
volatile bool debug = false;
if ( pos == key_size )
{
pos = entry.find_first_of( delimiters, key_size + 1 );
}
if ( pos != std::string::npos )
{
if ( results.empty( ) ||
std::strncmp(
results.back( ).c_str( ), entry.c_str( ), pos ) != 0 )
{
results.emplace_back( entry.c_str( ), pos );
}
if ( results.size( ) <= 1 && pos != std::string::npos )
{
pos = entry.find_first_of( delimiters, pos + 1 );
pos = ( pos == std::string::npos ? entry.size( ) : pos );
}
}
else
{
results.emplace_back( entry );
}
} );
return results;
}
std::string
get_environment( const char* key )
{
......@@ -162,15 +84,16 @@ main( int argc, char* argv[] )
{
exit( 1 );
}
Database db = load_database( channel_db_path );
completion::Database db = completion::load_database( channel_db_path );
if ( opts.search )
{
string_list choices;
std::string key = opts.key;
std::string prev_key;
completion::string_list choices;
std::string key = opts.key;
std::string prev_key;
do
{
choices = search( db.channels.begin( ), db.channels.end( ), key );
choices = completion::search(
db.channels.begin( ), db.channels.end( ), key );
prev_key = key;
if ( !choices.empty( ) )
{
......@@ -183,8 +106,7 @@ main( int argc, char* argv[] )
}
else if ( opts.resort )
{
std::sort(
db.channels.begin( ), db.channels.end( ), simple_comparison );
completion::sort( db );
std::copy( db.channels.begin( ),
db.channels.end( ),
std::ostream_iterator< std::string >( std::cout, "\n" ) );
......
add_library(catch2 INTERFACE)
target_include_directories(catch2 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/catch2)
target_requires_cpp11(catch2 INTERFACE)
\ No newline at end of file
Boost Software License - Version 1.0 - August 17th, 2003
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.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment