/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright The 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 3 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, see . */ #include #include #include /** * Define a stream function for logging this type. */ template std::ostream& boost_test_print_type( std::ostream& os, const std::vector>& aTable ) { os << "TABLE[ " << std::endl; for( size_t i = 0; i < aTable.size(); ++i ) { const auto& row = aTable[i]; os << " Row " << i << " [ "; for( size_t j = 0; j < row.size(); ++j ) { os << row[j]; if( j < row.size() - 1 ) os << ", "; } os << "] " << std::endl; } os << " ]" << std::endl; return os; } static bool TableDataEqual( const std::vector>& aExpected, const std::vector>& aActual ) { if( aExpected.size() != aActual.size() ) { BOOST_TEST_MESSAGE( "Row count mismatch: " << aExpected.size() << " != " << aActual.size() ); return false; } for( size_t i = 0; i < aExpected.size(); ++i ) { BOOST_TEST_INFO_SCOPE( "Row " << i ); if( aExpected[i].size() != aActual[i].size() ) return false; for( size_t j = 0; j < aExpected[i].size(); ++j ) { if( aExpected[i][j] != aActual[i][j] ) return false; } } return true; } BOOST_AUTO_TEST_SUITE( CsvTests ) struct CsvRoundTripCase { wxString m_name; std::vector> m_rows; wxString m_expected; }; BOOST_AUTO_TEST_CASE( BasicRoundTrips ) { // clang-format off static const std::vector testCases = { { "Basic CSV, Double Quoted, Backslash escaped", { { "Head 1", "Head 2", "Head, \"3\"" }, { "Row 1 Col 1", "Row 1 Col 2", "Row 1 Col 3" } }, "\"Head 1\",\"Head 2\",\"Head, \"\"3\"\"\"\n" "\"Row 1 Col 1\",\"Row 1 Col 2\",\"Row 1 Col 3\"\n", }, }; // clang-format on for( const auto& testCase : testCases ) { BOOST_TEST_INFO_SCOPE( testCase.m_name ); wxStringOutputStream os; CSV_WRITER writer( os ); writer.WriteLines( testCase.m_rows ); BOOST_CHECK_EQUAL( os.GetString(), testCase.m_expected ); std::vector> readRows; bool result = AutoDecodeCSV( os.GetString(), readRows ); BOOST_CHECK( result ); BOOST_CHECK_PREDICATE( TableDataEqual, ( testCase.m_rows )( readRows ) ); } } struct CsvDecodeCase { wxString m_name; wxString m_input; std::vector> m_expectedRows; }; BOOST_AUTO_TEST_CASE( BasicDecode ) { // clang-format off static const std::vector testCases = { { "Basic TSV, Double Quoted", "\"Head 1\"\t\"Head 2\"\t\"Head, 3\"\n" "\"Row 1 Col 1\"\t\"Row 1 Col 2\"\t\"Row 1 Col 3\"\n", { { "Head 1", "Head 2", "Head, 3" }, { "Row 1 Col 1", "Row 1 Col 2", "Row 1 Col 3" } }, } }; // clang-format on for( const auto& testCase : testCases ) { BOOST_TEST_INFO_SCOPE( testCase.m_name ); std::vector> readRows; bool result = AutoDecodeCSV( testCase.m_input, readRows ); BOOST_CHECK( result ); BOOST_CHECK_PREDICATE( TableDataEqual, ( testCase.m_expectedRows )( readRows ) ); } } BOOST_AUTO_TEST_SUITE_END()