>From f12c6acc88811bd7ba241b463c67f2712819fe37 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 6 Dec 2014 21:44:24 +0100 Subject: [PATCH] Output the version string shown in the dialog title. Check that the year in the dialog text is the same as the year in the version string and also the current year. Verify that the dialog showing the full license text can be opened and scrolled. Link GUI test with boost.regex now that it's used by it and hence also use --allow-multiple-definition linker option for it as required by the current build system. --- objects.make | 1 + workhorse.make | 2 +- wx_test_about_version.cpp | 184 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 181 insertions(+), 6 deletions(-) diff --git a/objects.make b/objects.make index ca1ad1b..84dbaba 100644 --- a/objects.make +++ b/objects.make @@ -355,6 +355,7 @@ lmi_wx_objects := \ main_wx.o \ wx_test_objects := \ + $(boost_regex_objects) \ main_wx_test.o \ wx_test_about_version.o \ wx_test_benchmark_census.o \ diff --git a/workhorse.make b/workhorse.make index 2b7f5ec..dd372d4 100644 --- a/workhorse.make +++ b/workhorse.make @@ -857,7 +857,7 @@ antediluvian_cli_monolithic$(EXEEXT): $(cli_objects) $(antediluvian_common_objec wx_new$(SHREXT): wx_new.o wx_test$(EXEEXT): lmi_so_attributes := -DLMI_USE_SO -wx_test$(EXEEXT): EXTRA_LDFLAGS := $(wx_ldflags) +wx_test$(EXEEXT): EXTRA_LDFLAGS := $(wx_ldflags) -Wl,--allow-multiple-definition wx_test$(EXEEXT): $(wx_test_objects) skeleton$(SHREXT) liblmi$(SHREXT) # TODO ?? This needs a corresponding test target. diff --git a/wx_test_about_version.cpp b/wx_test_about_version.cpp index c8dad96..69bcfea 100644 --- a/wx_test_about_version.cpp +++ b/wx_test_about_version.cpp @@ -27,13 +27,20 @@ #endif #include "assert_lmi.hpp" +#include "calendar_date.hpp" #include "wx_test_case.hpp" #include "version.hpp" #include +#include +#include #include #include +#include + +#include // INT_MAX + /// Validate version string (timestamp) from "About" dialog title. /// /// Test that the version string matches the timestamp specified in @@ -57,6 +64,111 @@ /// license's dialog box is scrollable--to guard against this problem: /// http://lists.nongnu.org/archive/html/lmi/2010-01/msg00001.html +namespace +{ + +// Convert a string known to consist of just 4 digits to a number. +// +// This function contains LMI_ASSERT() checks but they should be never +// triggered if the preconditions are filled as any string of 4 digits can be +// converted to an int value. +int year_from_string(wxString const& s) +{ + unsigned long year; + + LMI_ASSERT(s.ToCULong(&year)); + LMI_ASSERT(year < INT_MAX); + + return static_cast(year); +} + +// Find the last copyright year in the given HTML license notices text. +// +// May throw if the input doesn't conform to the expectations. +int extract_last_copyright_year(wxString const& html) +{ + // Find the line starting with "Copyright". + wxArrayString const lines = wxSplit(html ,'\n' ,'\0'); + + wxString line; + for(wxArrayString::const_iterator i = lines.begin(); i != lines.end(); ++i) + { + if(i->StartsWith("Copyright")) + { + LMI_ASSERT_WITH_MSG + (line.empty() + ,"Unexpectedly found more than one copyright line in the " + "license notices text" + ); + + line = *i; + } + } + + LMI_ASSERT_WITH_MSG + (!line.empty() + ,"Copyright line not found in the license notices text" + ); + + // We suppose that we have a sequence of comma-separated (4 digit, let + // someone else worry about Y10K problem) years and so the year we are + // interested in is just the last one of them. + // + // Notice also the use of utf8_str() to ensure that conversion from + // wxString never fails (it could if the string contained non-ASCII + // characters such as the copyright sign), while avoiding the use of wide + // char boost::regex functions that are not available under all platforms + // and notably not with MinGW 3.4. As we are only interested in matching + // ASCII characters such as digits, using UTF-8 is safe even though + // boost::regex has no real support for it. + std::string const line_utf8(line.utf8_str()); + boost::smatch m; + LMI_ASSERT_WITH_MSG + (boost::regex_search + (line_utf8 + ,m + ,boost::regex("(?:\\d{4}, )+(\\d{4})") + ) + ,"Copyright line \"" + line + "\" doesn't contain copyright years" + ); + + return year_from_string(wxString(m[1])); +} + +// Find the only wxHtmlWindow inside the given dialog. +// +// Throws if there are none, or more than one, windows of wxHtmlWindow type in +// the dialog. The dialog name is only used for diagnostic purposes. +wxHtmlWindow* find_html_window(wxWindow* parent, std::string const& dialog_name) +{ + wxHtmlWindow* html_win = 0; + wxWindowList const& wl = parent->GetChildren(); + for(wxWindowList::const_iterator i = wl.begin(); i != wl.end(); ++i) + { + wxHtmlWindow* const maybe_html_win = dynamic_cast(*i); + if(maybe_html_win) + { + LMI_ASSERT_WITH_MSG + (!html_win + ,"Unexpectedly found more than one wxHtmlWindow in " + "the " + dialog_name + " dialog" + ); + + html_win = maybe_html_win; + } + } + + LMI_ASSERT_WITH_MSG + (html_win + ,"wxHtmlWindow showing the license notices not found in " + "the " + dialog_name + " dialog" + ); + + return html_win; +} + +} // anonymous namespace + LMI_WX_TEST_CASE(about_dialog_version) { struct expect_about_dialog : public wxExpectModalBase @@ -64,16 +176,78 @@ virtual int OnInvoked(wxDialog* d) const { LMI_ASSERT(0 != d); - LMI_ASSERT(d->GetTitle().EndsWith(LMI_VERSION)); + + // Extract the last word of the dialog title. + wxString const last_word = d->GetTitle().AfterLast(' '); + wxLogMessage("About dialog version string is \"%s\".", last_word); + LMI_ASSERT_EQUAL(last_word, LMI_VERSION); + + // Find the wxHtmlWindow showing the license notices. + wxHtmlWindow* const + license_notices_win = find_html_window(d, "about"); + + // Check that the years in the copyright, license notices and + // version string are all the same. + int const copyright_year = + extract_last_copyright_year(license_notices_win->ToText()); + + LMI_ASSERT_EQUAL(copyright_year, today().year()); + + int const version_year = year_from_string(wxString(LMI_VERSION, 4)); + LMI_ASSERT_EQUAL(version_year, copyright_year); + + // Finally bring up the dialog showing the license itself: for this + // we first need to show this dialog itself. + d->Show(); + wxYield(); + + // And then press the default button in it which opens the license. + struct expect_license_dialog : public wxExpectModalBase + { + virtual int OnInvoked(wxDialog* d) const + { + wxHtmlWindow* const + license_win = find_html_window(d, "license"); + + // This is a rather indirect -- because testing this + // directly is not easily possible -- test of the scrollbar + // presence in the license window: we try to scroll it and + // expect it to have a result, as the license text is known + // to be long enough to not fit on a single page, even in + // high vertical resolutions. + // + // The first test just checks that the return value of + // LineXXX() methods makes sense: it should return false if + // no scrolling is possible. The second test checks that + // scrolling down does actually work. + LMI_ASSERT_WITH_MSG + (!license_win->LineUp() + ,"License window unexpectedly scrolled up" + ); + + LMI_ASSERT_WITH_MSG + (license_win->LineDown() + ,"License window didn't scroll down" + ); + + return wxID_OK; + } + }; + + wxUIActionSimulator z; + z.Char(WXK_RETURN); + wxTEST_DIALOG + (wxYield() + ,expect_license_dialog() + ); + return wxID_OK; } }; wxUIActionSimulator z; - z.KeyDown('h', wxMOD_ALT); - z.KeyUp ('h', wxMOD_ALT); - z.KeyDown('a' ); - z.KeyUp ('a' ); + z.Char('h', wxMOD_ALT); + z.Char('a' ); wxTEST_DIALOG (wxYield() ,expect_about_dialog() -- 1.7.9