[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [6096] Implement rectified test specification
From: |
Greg Chicares |
Subject: |
[lmi-commits] [6096] Implement rectified test specification |
Date: |
Fri, 23 Jan 2015 15:08:14 +0000 |
Revision: 6096
http://svn.sv.gnu.org/viewvc/?view=rev&root=lmi&revision=6096
Author: chicares
Date: 2015-01-23 15:08:13 +0000 (Fri, 23 Jan 2015)
Log Message:
-----------
Implement rectified test specification
Modified Paths:
--------------
lmi/trunk/ChangeLog
lmi/trunk/wx_test_paste_census.cpp
Modified: lmi/trunk/ChangeLog
===================================================================
--- lmi/trunk/ChangeLog 2015-01-23 03:02:40 UTC (rev 6095)
+++ lmi/trunk/ChangeLog 2015-01-23 15:08:13 UTC (rev 6096)
@@ -35581,3 +35581,9 @@
Clean up .fo.xml files created during PDF generation. See:
http://lists.nongnu.org/archive/html/lmi/2014-12/msg00089.html
+20150123T1508Z <address@hidden> [516]
+
+ wx_test_paste_census.cpp
+Implement rectified test specification. See:
+ http://lists.nongnu.org/archive/html/lmi/2014-12/msg00096.html
+
Modified: lmi/trunk/wx_test_paste_census.cpp
===================================================================
--- lmi/trunk/wx_test_paste_census.cpp 2015-01-23 03:02:40 UTC (rev 6095)
+++ lmi/trunk/wx_test_paste_census.cpp 2015-01-23 15:08:13 UTC (rev 6096)
@@ -36,49 +36,18 @@
#include <wx/app.h>
#include <wx/dataview.h>
#include <wx/dialog.h>
-#include <wx/ffile.h>
-#include <wx/filefn.h>
-#include <wx/html/htmlpars.h>
#include <wx/mdi.h>
#include <wx/radiobox.h>
#include <wx/testing.h>
#include <wx/uiaction.h>
+#include <algorithm>
+#include <set>
+#include <sstream>
+
namespace
{
-// Helper function to get the census data to be pasted.
-wxString get_census_data()
-{
- // Get the census example from help. This is an HTML file but we don't have
- // an HTML parser and HTML is not valid XML, so it can't be parsed as such.
- // Instead we just rely on the very particular format of this file: right
- // now it contains the census data between the only occurrences of <pre>
- // and </pre> tags in it, so locate them and take everything inside.
-
- wxFFile f(AddDataDir("pasting_to_a_census.html"));
- LMI_ASSERT(f.IsOpened());
-
- wxString html;
- LMI_ASSERT(f.ReadAll(&html));
-
- size_t const pos_pre = html.find("<pre>\n");
- LMI_ASSERT(pos_pre != wxString::npos);
-
- size_t const pos_pre_end = html.find("</pre>", pos_pre);
- LMI_ASSERT(pos_pre_end != wxString::npos);
-
- size_t const pos_pre_start = pos_pre + strlen("<pre>\n");
- wxString const text_pre = html.substr
- (pos_pre_start
- , pos_pre_end - pos_pre_start
- );
-
- // We're not done yet, we need to deal with the HTML entities. Do use HTML
- // parsing code in wxWidgets for this at least.
- return wxHtmlEntitiesParser().Parse(text_pre);
-}
-
// Helper function to find the wxDataViewCtrl used for the census display.
//
// Precondition: the currently active window must be a CensusView.
@@ -119,34 +88,91 @@
return list_model;
}
-// Check for the presence of the column with the given name.
-bool does_list_have_column(wxDataViewCtrl* dvc, wxString const& name)
+// Helper for building the diagnostic message in check_list_columns().
+std::string build_not_found_message(std::set<std::string> const& remaining)
{
+ std::ostringstream message;
+ bool const only_one = remaining.size() == 1;
+ message << (only_one ? "column" : "columns");
+
+ typedef std::set<std::string>::const_iterator ssci;
+ for(ssci i = remaining.begin(); i != remaining.end(); ++i)
+ {
+ if(i != remaining.begin())
+ {
+ message << ",";
+ }
+
+ message << " '" << *i << "'";
+ }
+
+ message << (only_one ? "was" : "were") << " not found";
+
+ return message.str();
+}
+
+// Check for the presence of all columns with the given name and, if specified,
+// for the absence of the given one.
+//
+// The 'when' parameter is used solely for the diagnostic messages in case of
+// the check failure.
+void check_list_columns
+ (wxDataViewCtrl* dvc
+ ,char const* when
+ ,std::set<std::string> const& expected
+ ,std::string const& unexpected = std::string()
+ )
+{
+ std::set<std::string> remaining(expected.begin(), expected.end());
+
unsigned int const num_columns = dvc->GetColumnCount();
for(unsigned int n = 0; n < num_columns; ++n)
{
- if (dvc->GetColumn(n)->GetTitle() == name)
+ std::string const title = dvc->GetColumn(n)->GetTitle().ToStdString();
+ LMI_ASSERT_WITH_MSG
+ (title != unexpected
+ ,"column '" << title << "' unexpectedly found " << when
+ );
+
+ // Notice that it is not an error if the column is not in the expected
+ // columns set, it is not exhaustive.
+ remaining.erase(title);
+ }
+
+ LMI_ASSERT_WITH_MSG
+ (remaining.empty()
+ ,build_not_found_message(remaining) << when
+ );
+}
+
+// Find the index of the column with the given title.
+//
+// Throws an exception if the column is not found.
+unsigned int find_model_column_by_title
+ (wxDataViewCtrl* dvc
+ ,std::string const& title
+ )
+{
+ unsigned int const num_columns = dvc->GetColumnCount();
+ for(unsigned int n = 0; n < num_columns; ++n)
+ {
+ wxDataViewColumn const* column = dvc->GetColumn(n);
+ if(column->GetTitle().ToStdString() == title)
{
- return true;
+ return column->GetModelColumn();
}
}
- return false;
+
+ throw std::runtime_error("column " + title + " not found");
}
} // Unnamed namespace.
-// ERASE THIS BLOCK COMMENT WHEN IMPLEMENTATION COMPLETE. The block
-// comment below changes the original specification, and does not
-// yet describe the present code. Desired changes:
-// - Save pastable data inline; don't extract from user manual.
-// - Validate all columns after each step (after initial pasting).
-// - Test change in class defaults (in addition to case defaults).
-
/// Test pasting spreadsheet data into a census.
///
/// Create a set of data that might reasonably be copied from a
/// spreadsheet. Initially at least, use the data in the user manual:
-/// file:///C:/lmi/src/web/lmi/pasting_to_a_census.html
+/// http://www.nongnu.org/lmi/pasting_to_a_census.html
/// Hardcode the data here; don't read them from the user manual.
/// (That didactic example was designed mainly to fit on a web page
/// and to make sense to end users. Some day we might want to make
@@ -181,8 +207,38 @@
LMI_WX_TEST_CASE(paste_census)
{
+ // The column titles are the user-visible strings corresponding to the
+ // internal column names actually used in the census data below.
+ std::set<std::string> column_titles;
+ column_titles.insert("Gender");
+ column_titles.insert("Underwriting Class");
+ column_titles.insert("Issue Age");
+ column_titles.insert("Payment");
+ column_titles.insert("Death Benefit Option");
+
+ char const* const census_data =
+ "Gender\tUnderwritingClass\tIssueAge\tPayment\tDeathBenefitOption\n"
+ "\n"
+ "Female\tPreferred\t30\tsevenpay,7;0\tb,7;a\n"
+ "Male\tPreferred\t35\tsevenpay,7;0\tb,7;a\n"
+ "Female\tStandard\t40\tsevenpay,7;0\tb,7;a\n"
+ "Male\tStandard\t45\tsevenpay,7;0\tb,7;a\n"
+ "Female\tPreferred\t50\tsevenpay,7;0\tb,7;a\n"
+ "Male\tPreferred\t55\tsevenpay,7;0\tb,7;a\n"
+ "Female\tStandard\t60\tsevenpay,7;0\tb,7;a\n"
+ ;
+
+ std::size_t const number_of_rows = std::count
+ (census_data
+ ,census_data + std::strlen(census_data)
+ ,'\n'
+ )
+ - 1 // Not counting the header.
+ - 1 // Nor the empty line after it.
+ ;
+
// Put the data to paste on clipboard.
- ClipboardEx::SetText(get_census_data().ToStdString());
+ ClipboardEx::SetText(census_data);
// Create a new census.
wx_test_new_census census;
@@ -196,11 +252,106 @@
// correctly.
wxDataViewCtrl* const list_window = find_census_list_window();
wxDataViewListModel* const list_model = get_census_list_model(list_window);
- LMI_ASSERT_EQUAL(list_model->GetCount(), 7);
+ LMI_ASSERT_EQUAL(list_model->GetCount(), number_of_rows);
- static char const* column_title = "Underwriting Class";
- LMI_ASSERT(does_list_have_column(list_window, column_title));
+ check_list_columns
+ (list_window
+ ,"after pasting initial census data"
+ ,column_titles
+ );
+ // Change class defaults: this requires a selection, so ensure we have one
+ // by clicking somewhere inside the control.
+ ui.MouseMove
+ (list_window->ClientToScreen
+ (wxPoint
+ (10*list_window->GetCharWidth()
+ ,3*list_window->GetCharHeight()
+ )
+ )
+ );
+ ui.MouseClick();
+ wxYield();
+
+ LMI_ASSERT_EQUAL(list_window->GetSelectedItemsCount(), 1);
+
+ ui.Char('e', wxMOD_CONTROL | wxMOD_ALT); // "Census|Edit class defaults"
+
+ struct change_gender_in_class_defaults_dialog
+ :public wxExpectModalBase<MvcController>
+ {
+ virtual int OnInvoked(MvcController* dialog) const
+ {
+ dialog->Show();
+ wxYield();
+
+ wxUIActionSimulator ui;
+
+ // Go to the third page: as the dialog remembers its last opened
+ // page, ensure that we start from the first one.
+ ui.Char(WXK_HOME);
+ ui.Char(WXK_RIGHT);
+ ui.Char(WXK_RIGHT);
+ wxYield();
+
+ // We can't find directly the radio button we're interested in,
+ // because it's not a real wxWindow, so we need to find the radio
+ // box containing it.
+ wxWindow* const gender_window = wxWindow::FindWindowByName
+ ("Gender"
+ ,dialog
+ );
+ LMI_ASSERT(gender_window);
+
+ wxRadioBox* const
+ gender_radiobox = dynamic_cast<wxRadioBox*>(gender_window);
+ LMI_ASSERT(gender_radiobox);
+
+ // It's difficult to select the radiobox using just
+ // wxUIActionSimulator as there is no keyboard shortcut to navigate
+ // to it and emulating a mouse click on it is tricky as we don't
+ // want to change its selection by clicking on the item, so do it
+ // programmatically, the effect should be absolutely the same.
+ gender_radiobox->SetFocus();
+ wxYield();
+
+ ui.Char(WXK_DOWN); // Select the last, "Unisex", radio button.
+ wxYield();
+
+ LMI_ASSERT_EQUAL(gender_radiobox->GetSelection(), 2);
+
+ return wxID_OK;
+ }
+ };
+
+ // The menu command above should have opened the "Class defaults" dialog
and
+ // our code dealing with it above is supposed to result in an appearance of
+ // "Apply all changes to every cell?" message box for which we provide an
+ // affirmative answer.
+ wxTEST_DIALOG
+ (wxYield()
+ ,change_gender_in_class_defaults_dialog()
+ ,wxExpectModal<wxMessageDialog>(wxYES)
+ );
+
+ // Check that all columns, including the "Gender" one, are still shown.
+ check_list_columns
+ (list_window
+ ,"after changing gender in class defaults"
+ ,column_titles
+ );
+
+ // Verify that the "Gender" column value is "Unisex" in every row now.
+ unsigned int const
+ gender_column = find_model_column_by_title(list_window, "Gender");
+ LMI_ASSERT_EQUAL(list_model->GetCount(), number_of_rows);
+ for(std::size_t row = 0; row < number_of_rows; ++row)
+ {
+ wxVariant value;
+ list_model->GetValueByRow(value, row, gender_column);
+ LMI_ASSERT_EQUAL(value.GetString(), "Unisex");
+ }
+
// Change the case defaults to get rid of the underwriting class.
ui.Char('e', wxMOD_CONTROL | wxMOD_SHIFT); // "Census|Edit case defaults"
@@ -263,9 +414,16 @@
// Check that we still have the same cells but that now the underwriting
// class column has disappeared as its value has been fixed.
- LMI_ASSERT_EQUAL(list_model->GetCount(), 7);
- LMI_ASSERT(!does_list_have_column(list_window, column_title));
+ LMI_ASSERT_EQUAL(list_model->GetCount(), number_of_rows);
+ column_titles.erase("Underwriting Class");
+ check_list_columns
+ (list_window
+ ,"after changing class in case defaults"
+ ,column_titles
+ ,"Underwriting Class"
+ );
+
// Finally save the census with the pasted data for later inspection.
wxString const census_file_name =
get_test_file_path_for("PasteCensus.cns");
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [lmi-commits] [6096] Implement rectified test specification,
Greg Chicares <=