From 5769cf0f89fa4d076042e9f8dd24a32501280f8c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin <vadim@wxwidgets.org> Date: Sat, 12 Apr 2008 17:03:09 +0000 Subject: [PATCH] fix bugs introduced in wxCmdLineParser::ConvertStringToArgs() during Unicode transition; added a unit test for it git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@53142 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/cppunit.h | 16 +++++++ src/common/cmdline.cpp | 55 +++++++++-------------- tests/Makefile.in | 4 ++ tests/cmdline/cmdlinetest.cpp | 82 +++++++++++++++++++++++++++++++++++ tests/makefile.bcc | 4 ++ tests/makefile.gcc | 4 ++ tests/makefile.vc | 4 ++ tests/makefile.wat | 4 ++ tests/test.bkl | 1 + tests/test_test.dsp | 4 ++ tests/test_vc7_test.vcproj | 2 + tests/test_vc8_test.vcproj | 3 ++ 12 files changed, 148 insertions(+), 35 deletions(-) create mode 100644 tests/cmdline/cmdlinetest.cpp diff --git a/include/wx/cppunit.h b/include/wx/cppunit.h index e87892b5a2..a7affd50ae 100644 --- a/include/wx/cppunit.h +++ b/include/wx/cppunit.h @@ -87,6 +87,22 @@ // Use this macro to compare a size_t with a literal integer #define WX_ASSERT_SIZET_EQUAL(n, m) CPPUNIT_ASSERT_EQUAL(((size_t)n), m) +// Use this macro to compare a wxArrayString with the pipe-separated elements +// of the given string +// +// NB: it's a macro and not a function to have the correct line numbers in the +// test failure messages +#define WX_ASSERT_STRARRAY_EQUAL(s, a) \ + { \ + wxArrayString expected(wxSplit(s, '|', '\0')); \ + \ + CPPUNIT_ASSERT_EQUAL( expected.size(), a.size() ); \ + \ + for ( size_t n = 0; n < a.size(); n++ ) \ + { \ + CPPUNIT_ASSERT_EQUAL( expected[n], a[n] ); \ + } \ + } // Use this macro to assert with the given formatted message (it should contain // the format string and arguments in a separate pair of parentheses) diff --git a/src/common/cmdline.cpp b/src/common/cmdline.cpp index 63ee43c1a8..6f3b1860e5 100644 --- a/src/common/cmdline.cpp +++ b/src/common/cmdline.cpp @@ -1255,62 +1255,47 @@ wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxString& cmdline) bool isInsideQuotes = false; + const wxString::const_iterator end = cmdline.end(); wxString::const_iterator p = cmdline.begin(); for ( ;; ) { // skip white space - while ( p != cmdline.end() && (*p == _T(' ') || *p == _T('\t')) ) + while ( p != end && (*p == ' ' || *p == '\t') ) ++p; // anything left? - if ( p == cmdline.end() ) + if ( p == end ) break; // parse this parameter - bool endParam = false; bool lastBS = false; - for ( arg.clear(); !endParam; p++ ) + for ( arg.clear(); p != end; ++p ) { - switch ( (*p).GetValue() ) + const wxChar ch = *p; + if ( ch == '"' ) { - case _T('"'): - if ( !lastBS ) - { - isInsideQuotes = !isInsideQuotes; - - // don't put quote in arg - continue; - } - //else: quote has no special meaning but the backslash - // still remains -- makes no sense but this is what - // Windows does - break; - - case _T(' '): - case _T('\t'): - // backslash does *not* quote the space, only quotes do - if ( isInsideQuotes ) - { - // skip assignment below - break; - } - // fall through - - case _T('\0'): - endParam = true; + if ( !lastBS ) + { + isInsideQuotes = !isInsideQuotes; - break; + // don't put quote in arg + continue; + } + //else: quote has no special meaning but the backslash + // still remains -- makes no sense but this is what + // Windows does } - - if ( endParam ) + // note that backslash does *not* quote the space, only quotes do + else if ( !isInsideQuotes && (ch == ' ' || ch == '\t') ) { + ++p; // skip this space anyhow break; } - lastBS = *p == _T('\\'); + lastBS = ch == '\\'; - arg += *p; + arg += ch; } args.push_back(arg); diff --git a/tests/Makefile.in b/tests/Makefile.in index 950d9703af..562680c0f7 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -57,6 +57,7 @@ TEST_OBJECTS = \ test_tartest.o \ test_arrays.o \ test_base64.o \ + test_cmdlinetest.o \ test_fileconf.o \ test_datetimetest.o \ test_filekind.o \ @@ -344,6 +345,9 @@ test_arrays.o: $(srcdir)/arrays/arrays.cpp $(TEST_ODEP) test_base64.o: $(srcdir)/base64/base64.cpp $(TEST_ODEP) $(CXXC) -c -o $@ $(TEST_CXXFLAGS) $(srcdir)/base64/base64.cpp +test_cmdlinetest.o: $(srcdir)/cmdline/cmdlinetest.cpp $(TEST_ODEP) + $(CXXC) -c -o $@ $(TEST_CXXFLAGS) $(srcdir)/cmdline/cmdlinetest.cpp + test_fileconf.o: $(srcdir)/config/fileconf.cpp $(TEST_ODEP) $(CXXC) -c -o $@ $(TEST_CXXFLAGS) $(srcdir)/config/fileconf.cpp diff --git a/tests/cmdline/cmdlinetest.cpp b/tests/cmdline/cmdlinetest.cpp new file mode 100644 index 0000000000..8e879649ae --- /dev/null +++ b/tests/cmdline/cmdlinetest.cpp @@ -0,0 +1,82 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: tests/cmdline/cmdlinetest.cpp +// Purpose: wxCmdLineParser unit test +// Author: Vadim Zeitlin +// Created: 2008-04-12 +// RCS-ID: $Id$ +// Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org> +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "testprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif // WX_PRECOMP + +#include "wx/cmdline.h" + +// -------------------------------------------------------------------------- +// test class +// -------------------------------------------------------------------------- + +class CmdLineTestCase : public CppUnit::TestCase +{ +public: + CmdLineTestCase() {} + +private: + CPPUNIT_TEST_SUITE( CmdLineTestCase ); + CPPUNIT_TEST( ConvertStringTestCase ); + CPPUNIT_TEST_SUITE_END(); + + void ConvertStringTestCase(); + + DECLARE_NO_COPY_CLASS(CmdLineTestCase) +}; + +// register in the unnamed registry so that these tests are run by default +CPPUNIT_TEST_SUITE_REGISTRATION( CmdLineTestCase ); + +// also include in it's own registry so that these tests can be run alone +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CmdLineTestCase, "CmdLineTestCase" ); + +// ============================================================================ +// implementation +// ============================================================================ + +void CmdLineTestCase::ConvertStringTestCase() +{ + #define WX_ASSERT_ARGS_EQUAL(s, args) \ + { \ + const wxArrayString a(wxCmdLineParser::ConvertStringToArgs(args));\ + WX_ASSERT_STRARRAY_EQUAL(s, a); \ + } + + // normal cases + WX_ASSERT_ARGS_EQUAL( "foo", "foo" ) + WX_ASSERT_ARGS_EQUAL( "foo bar", "\"foo bar\"" ) + WX_ASSERT_ARGS_EQUAL( "foo|bar", "foo bar" ) + WX_ASSERT_ARGS_EQUAL( "foo|bar|baz", "foo bar baz" ) + WX_ASSERT_ARGS_EQUAL( "foo|bar baz", "foo \"bar baz\"" ) + + // special cases + WX_ASSERT_ARGS_EQUAL( "", "" ) + WX_ASSERT_ARGS_EQUAL( "foo", "foo " ) + WX_ASSERT_ARGS_EQUAL( "foo", "foo \t " ) + WX_ASSERT_ARGS_EQUAL( "foo|bar", "foo bar " ) + WX_ASSERT_ARGS_EQUAL( "foo|bar|", "foo bar \"" ) + WX_ASSERT_ARGS_EQUAL( "foo|bar|\\", "foo bar \\" ) + + // check for (broken) Windows semantics: backslash doesn't escape spaces + WX_ASSERT_ARGS_EQUAL( "foo|bar\\|baz", "foo bar\\ baz" ); + WX_ASSERT_ARGS_EQUAL( "foo|bar\\\"baz", "foo \"bar\\\"baz\"" ); + + #undef WX_ASSERT_ARGS_EQUAL +} diff --git a/tests/makefile.bcc b/tests/makefile.bcc index ecf68202c7..ee35fe01e1 100644 --- a/tests/makefile.bcc +++ b/tests/makefile.bcc @@ -43,6 +43,7 @@ TEST_OBJECTS = \ $(OBJS)\test_tartest.obj \ $(OBJS)\test_arrays.obj \ $(OBJS)\test_base64.obj \ + $(OBJS)\test_cmdlinetest.obj \ $(OBJS)\test_fileconf.obj \ $(OBJS)\test_datetimetest.obj \ $(OBJS)\test_filekind.obj \ @@ -376,6 +377,9 @@ $(OBJS)\test_arrays.obj: .\arrays\arrays.cpp $(OBJS)\test_base64.obj: .\base64\base64.cpp $(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\base64\base64.cpp +$(OBJS)\test_cmdlinetest.obj: .\cmdline\cmdlinetest.cpp + $(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\cmdline\cmdlinetest.cpp + $(OBJS)\test_fileconf.obj: .\config\fileconf.cpp $(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\config\fileconf.cpp diff --git a/tests/makefile.gcc b/tests/makefile.gcc index 1678a05f72..49dd117b90 100644 --- a/tests/makefile.gcc +++ b/tests/makefile.gcc @@ -35,6 +35,7 @@ TEST_OBJECTS = \ $(OBJS)\test_tartest.o \ $(OBJS)\test_arrays.o \ $(OBJS)\test_base64.o \ + $(OBJS)\test_cmdlinetest.o \ $(OBJS)\test_fileconf.o \ $(OBJS)\test_datetimetest.o \ $(OBJS)\test_filekind.o \ @@ -354,6 +355,9 @@ $(OBJS)\test_arrays.o: ./arrays/arrays.cpp $(OBJS)\test_base64.o: ./base64/base64.cpp $(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\test_cmdlinetest.o: ./cmdline/cmdlinetest.cpp + $(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\test_fileconf.o: ./config/fileconf.cpp $(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $< diff --git a/tests/makefile.vc b/tests/makefile.vc index 6477522b04..ada13d91f5 100644 --- a/tests/makefile.vc +++ b/tests/makefile.vc @@ -36,6 +36,7 @@ TEST_OBJECTS = \ $(OBJS)\test_tartest.obj \ $(OBJS)\test_arrays.obj \ $(OBJS)\test_base64.obj \ + $(OBJS)\test_cmdlinetest.obj \ $(OBJS)\test_fileconf.obj \ $(OBJS)\test_datetimetest.obj \ $(OBJS)\test_filekind.obj \ @@ -461,6 +462,9 @@ $(OBJS)\test_arrays.obj: .\arrays\arrays.cpp $(OBJS)\test_base64.obj: .\base64\base64.cpp $(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\base64\base64.cpp +$(OBJS)\test_cmdlinetest.obj: .\cmdline\cmdlinetest.cpp + $(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\cmdline\cmdlinetest.cpp + $(OBJS)\test_fileconf.obj: .\config\fileconf.cpp $(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\config\fileconf.cpp diff --git a/tests/makefile.wat b/tests/makefile.wat index 875a094a6c..f17975db60 100644 --- a/tests/makefile.wat +++ b/tests/makefile.wat @@ -248,6 +248,7 @@ TEST_OBJECTS = & $(OBJS)\test_tartest.obj & $(OBJS)\test_arrays.obj & $(OBJS)\test_base64.obj & + $(OBJS)\test_cmdlinetest.obj & $(OBJS)\test_fileconf.obj & $(OBJS)\test_datetimetest.obj & $(OBJS)\test_filekind.obj & @@ -407,6 +408,9 @@ $(OBJS)\test_arrays.obj : .AUTODEPEND .\arrays\arrays.cpp $(OBJS)\test_base64.obj : .AUTODEPEND .\base64\base64.cpp $(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $< +$(OBJS)\test_cmdlinetest.obj : .AUTODEPEND .\cmdline\cmdlinetest.cpp + $(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $< + $(OBJS)\test_fileconf.obj : .AUTODEPEND .\config\fileconf.cpp $(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $< diff --git a/tests/test.bkl b/tests/test.bkl index b9acc86aff..4d3d5caa3c 100644 --- a/tests/test.bkl +++ b/tests/test.bkl @@ -29,6 +29,7 @@ archive/tartest.cpp arrays/arrays.cpp base64/base64.cpp + cmdline/cmdlinetest.cpp config/fileconf.cpp datetime/datetimetest.cpp filekind/filekind.cpp diff --git a/tests/test_test.dsp b/tests/test_test.dsp index 8191d2c212..9726938675 100644 --- a/tests/test_test.dsp +++ b/tests/test_test.dsp @@ -255,6 +255,10 @@ SOURCE=.\streams\bstream.cpp # End Source File # Begin Source File +SOURCE=.\cmdline\cmdlinetest.cpp +# End Source File +# Begin Source File + SOURCE=.\mbconv\convautotest.cpp # End Source File # Begin Source File diff --git a/tests/test_vc7_test.vcproj b/tests/test_vc7_test.vcproj index f5be6007e4..0332add381 100644 --- a/tests/test_vc7_test.vcproj +++ b/tests/test_vc7_test.vcproj @@ -659,6 +659,8 @@ RelativePath=".\base64\base64.cpp"/> <File RelativePath=".\streams\bstream.cpp"/> + <File + RelativePath=".\cmdline\cmdlinetest.cpp"/> <File RelativePath=".\mbconv\convautotest.cpp"/> <File diff --git a/tests/test_vc8_test.vcproj b/tests/test_vc8_test.vcproj index c401ce3bda..0629254fdd 100644 --- a/tests/test_vc8_test.vcproj +++ b/tests/test_vc8_test.vcproj @@ -822,6 +822,9 @@ <File RelativePath=".\streams\bstream.cpp" /> + <File + RelativePath=".\cmdline\cmdlinetest.cpp" + /> <File RelativePath=".\mbconv\convautotest.cpp" /> -- 2.47.2