lmi-commits
[Top][All Lists]
Advanced

[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");
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]