lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [6154] Test all possible 'CurrentCoiMultiplier' validation


From: Greg Chicares
Subject: [lmi-commits] [6154] Test all possible 'CurrentCoiMultiplier' validation errors
Date: Fri, 27 Mar 2015 00:41:16 +0000

Revision: 6154
          http://svn.sv.gnu.org/viewvc/?view=rev&root=lmi&revision=6154
Author:   chicares
Date:     2015-03-27 00:41:16 +0000 (Fri, 27 Mar 2015)
Log Message:
-----------
Test all possible 'CurrentCoiMultiplier' validation errors

Modified Paths:
--------------
    lmi/trunk/ChangeLog
    lmi/trunk/main_wx_test.cpp
    lmi/trunk/wx_test_input_validation.cpp

Modified: lmi/trunk/ChangeLog
===================================================================
--- lmi/trunk/ChangeLog 2015-03-27 00:32:16 UTC (rev 6153)
+++ lmi/trunk/ChangeLog 2015-03-27 00:41:16 UTC (rev 6154)
@@ -35960,3 +35960,10 @@
 Add wx_test_existing_illustration helper class. See:
   http://lists.nongnu.org/archive/html/lmi/2015-03/msg00043.html
 
+20150327T0041Z <address@hidden> [516]
+
+  main_wx_test.cpp
+  wx_test_input_validation.cpp
+Test all possible 'CurrentCoiMultiplier' validation errors. See:
+  http://lists.nongnu.org/archive/html/lmi/2015-03/msg00043.html
+

Modified: lmi/trunk/main_wx_test.cpp
===================================================================
--- lmi/trunk/main_wx_test.cpp  2015-03-27 00:32:16 UTC (rev 6153)
+++ lmi/trunk/main_wx_test.cpp  2015-03-27 00:41:16 UTC (rev 6154)
@@ -662,6 +662,7 @@
     void RunTheTests();
 
     std::string runtime_error_;
+    std::string domain_error_;
     bool is_running_tests_;
 };
 
@@ -723,10 +724,19 @@
 
 bool SkeletonTest::StoreCurrentException()
 {
+    // We store all the exceptions that are expected to be caught by the tests
+    // here, in order to be able to rethrow them later. Almost all tests need
+    // just std::runtime_error, but the input validation one also can get a
+    // domain_error in some cases, so we need to handle that one as well.
     try
         {
         throw;
         }
+    catch(std::domain_error& e)
+        {
+        domain_error_ = e.what();
+        return true;
+        }
     catch (std::runtime_error const& e)
         {
         runtime_error_ = e.what();
@@ -738,8 +748,15 @@
 
 void SkeletonTest::RethrowStoredException()
 {
-    if (!runtime_error_.empty())
+    if(!domain_error_.empty())
         {
+        std::domain_error const e(domain_error_);
+        domain_error_.clear();
+        throw e;
+        }
+
+    if(!runtime_error_.empty())
+        {
         std::runtime_error const e(runtime_error_);
         runtime_error_.clear();
         throw e;

Modified: lmi/trunk/wx_test_input_validation.cpp
===================================================================
--- lmi/trunk/wx_test_input_validation.cpp      2015-03-27 00:32:16 UTC (rev 
6153)
+++ lmi/trunk/wx_test_input_validation.cpp      2015-03-27 00:41:16 UTC (rev 
6154)
@@ -28,74 +28,241 @@
 
 #include "assert_lmi.hpp"
 #include "configurable_settings.hpp"
+#include "global_settings.hpp"
+#include "mvc_controller.hpp"
 #include "wx_test_case.hpp"
+#include "wx_test_document.hpp"
 
 #include <wx/testing.h>
 #include <wx/uiaction.h>
 
+#include <cstring>
 #include <stdexcept>
 
-/*
-    Test for the expected validation errors.
+/// Test validation of the COI multiplier input field.
+///
+/// Open the file CoiMultiplier.ill provided with the distribution and test
+/// various values of the "CurrentCoiMultiplier" field in the dialog invoked by
+///     Illustration | Edit cell
+///
+/// The following inputs must result in an error:
+///     (a) Empty string value.
+///     (b) Negative value.
+///     (c) Zero value.
+///
+/// The following input must result in an error in the normal execution case
+/// but not when one of the special back door command line arguments is
+/// specified:
+///     (d) Positive value less than the minimum (which is 0.9).
+///
+/// Finally, these inputs must not trigger any errors:
+///     (e) Exactly the minimum value.
+///     (f) Value of 1.
+///     (g) Value greater than 1.
+///
+/// Errors are tested by catching the exceptions and examining their associated
+/// messages and not by checking for the message boxes displayed by the program
+/// because these message boxes are shown from OnExceptionInMainLoop() method
+/// of the application object which behaves differently in the test suite.
 
-    This commit implements the following item of the testing specification:
+namespace
+{
 
-        15. Validate input ranges and anticipate error for
-            'CurrentCoiMultiplier' input.
+// The field value with the expected error message (or at least its variable
+// part, see below for how the full error message is constructed) or NULL if no
+// error should be given.
+struct coi_multiplier_test_data
+{
+    char const* value;
+    char const* error;
+};
 
-          A. File | Open | 'CoiMultiplier.cns'
-             Census | run case
-             Expected result:
-              Error message for last life with a zero multiplier:
+coi_multiplier_test_data const test_cases[] =
+{
+    { ""    ,"COI multiplier entered is '', but it must contain at least one 
number other than zero." },
+    { "-1"  ,"Lowest COI multiplier entered is -1, but 0.9 is the lowest 
multiplier allowed." },
+    { "0"   ,"COI multiplier entered is '0', but it must contain at least one 
number other than zero." },
+    { "0.8" ,"Lowest COI multiplier entered is 0.8, but 0.9 is the lowest 
multiplier allowed." },
+    { "0.9" ,NULL },
+    { "1"   ,NULL },
+    { "1.1" ,NULL },
+};
 
-              Input validation problems for '':
-              COI multiplier entered is '0', but it must
-               contain at least one number other than zero.
+} // anonymous namespace
 
-    However it doesn't check for the message box being displayed, because of
-    significant difficulty of doing it due to the fact that this message box is
-    shown from the global OnExceptionInMainLoop() function, but just checks for
-    the expected exception being thrown.
- */
 LMI_WX_TEST_CASE(input_validation)
 {
-    wxUIActionSimulator ui;
-    ui.Char('o', wxMOD_CONTROL);    // "File|Open"
+    skip_if_not_distribution();
 
-    wxTEST_DIALOG
-        (wxYield()
-         
,wxExpectModal<wxFileDialog>(get_test_file_path_for("CoiMultiplier.cns"))
-        );
+    wx_test_existing_illustration 
ill(get_test_file_path_for("CoiMultiplier.ill"));
 
-    ui.Char('r', wxMOD_CONTROL | wxMOD_SHIFT);  // "Census|Run case"
+    struct test_coi_multiplier_dialog : public wxExpectModalBase<MvcController>
+    {
+        explicit test_coi_multiplier_dialog(char const* value)
+            :value_(value)
+        {}
 
-    // Test that the expected exception is generated.
-    bool error_detected = false;
-    try
+        virtual int OnInvoked(MvcController* dialog) const
+            {
+            dialog->Show();
+            wxYield();
+
+            wx_test_focus_controller_child(*dialog, "CurrentCoiMultiplier");
+
+            wxUIActionSimulator ui;
+            if(*value_ == '\0')
+                {
+                // Special case of the empty value: we must clear the entry
+                // contents in this case, but emulating the input of "nothing"
+                // wouldn't be enough to do it, so do it manually instead.
+                ui.Char(WXK_SPACE);
+                ui.Char(WXK_BACK);
+                }
+            else
+                {
+                ui.Text(value_);
+                }
+            wxYield();
+
+            return wxID_OK;
+            }
+
+        virtual wxString GetDefaultDescription() const
+            {
+            return wxString::Format
+                ("edit cell dialog for testing COI multiplier \"%s\""
+                ,value_
+                );
+            }
+
+        char const* const value_;
+    };
+
+    for(std::size_t n = 0; n < sizeof test_cases / sizeof(test_cases[0]); n++)
         {
-        wxYield();
-        }
-    catch(std::runtime_error& e)
-        {
-        error_detected = true;
+        coi_multiplier_test_data const& td = test_cases[n];
 
-        // The error message contains a line of the form "[file %s, line %d]"
-        // at the end which we want to ignore, as the line number and possibly
-        // the file name can change and are irrelevant to this check anyhow, so
-        // find this line presence and ignore it in comparison.
-        std::string const error_message = e.what();
-        std::string::size_type loc_pos = error_message.find("\n[file");
-        LMI_ASSERT(loc_pos != std::string::npos);
+        // This flag is used to assert that all expected exceptions were
+        // generated at the end of the loop. The reason for using it instead of
+        // just asserting directly inside the "try" statement is that failing
+        // assert also throws an exception which would have been caught by our
+        // own "catch" clause and while we could test for it and rethrow the
+        // exception if we recognize it as ours, it is finally simpler to just
+        // avoid catching it in the first place.
+        bool check_for_expected_exception = false;
+        try
+            {
+            wxUIActionSimulator ui;
+            ui.Char('e', wxMOD_CONTROL); // "Illustration|Edit Cell"
+            wxTEST_DIALOG
+                (wxYield()
+                ,test_coi_multiplier_dialog(td.value)
+                );
 
-        LMI_ASSERT_EQUAL
-            (error_message.substr(0, loc_pos),
-             "Input validation problems for '':\n"
-             "COI multiplier entered is '0', but it must contain at least one 
number other than zero.\n"
-            );
+            // A special case: when using one of the special command line back
+            // door options, the test for the minimal COI multiplier value is
+            // skipped and doesn't result in the expected error -- which is
+            // itself expected, so don't fail the test in this case.
+            if
+                (
+                    !global_settings::instance().mellon()
+                ||  std::strcmp(td.value, "0.8") != 0
+                )
+                {
+                // Outside of this special case, do verify that we didn't miss
+                // an expected exception below.
+                check_for_expected_exception = true;
+                }
+            }
+        catch(std::domain_error& e)
+            {
+            // This is another special case: normally a negative value would
+            // fail the check comparing it with the lowest multiplier allowed,
+            // however this check is disabled when one of the special command
+            // line back door options is used. In this case the negative value
+            // still doesn't pass a subsequent check in coi_rate_from_q(),
+            // which is expected and doesn't constitute a test failure.
+            // Anything else does however.
+            LMI_ASSERT_WITH_MSG
+                (
+                    global_settings::instance().mellon()
+                &&  td.value
+                &&  td.value[0] == '-'
+                &&  std::strcmp(e.what(), "q is negative.") == 0
+                ,"COI multiplier value \""
+                    << td.value
+                    << "\" resulted in an unexpected domain error ("
+                    << e.what()
+                    << ")"
+                );
+            }
+        catch(std::runtime_error& e)
+            {
+            std::string const error_message = e.what();
+
+            LMI_ASSERT_WITH_MSG
+                (td.error
+                ,"COI multiplier value \""
+                    << td.value
+                    << "\" unexpectedly resulted in an error ("
+                    << error_message
+                    << ")"
+                );
+
+            // The error message always starts with the same prefix, discard it
+            // to make the failure messages below in case of a difference
+            // between the expected and actual errors more concise.
+            char const* const
+                error_prefix = "Input validation problems for '':\n";
+            std::size_t error_prefix_len = std::strlen(error_prefix);
+
+            LMI_ASSERT_WITH_MSG
+                (error_message.substr(0, error_prefix_len) == error_prefix
+                ,"Error message for COI multiplier value \""
+                    << td.value
+                    << "\" doesn't contain the expected prefix ("
+                    << e.what()
+                    << ")"
+                );
+
+            // The error message contains a line of the form "[file %s, line
+            // %d]" at the end which we want to ignore, as the line number and
+            // possibly the file name can change and are irrelevant to this
+            // check anyhow, so find this line presence and ignore it in
+            // comparison.
+            std::string::size_type const
+                loc_pos = error_message.find("\n\n[file", error_prefix_len);
+            LMI_ASSERT_WITH_MSG
+                (loc_pos != std::string::npos
+                ,"Error message for COI multiplier value \""
+                    << td.value
+                    << "\" unexpectedly doesn't contain location information ("
+                    << e.what()
+                    << ")"
+                );
+
+            // Finally check that what remains, i.e. the real error message,
+            // conforms to the expected one.
+            std::string const validation_error = error_message.substr
+                (error_prefix_len
+                ,loc_pos - error_prefix_len
+                );
+
+            LMI_ASSERT_EQUAL(validation_error, td.error);
+            }
+
+        if(check_for_expected_exception)
+            {
+            LMI_ASSERT_WITH_MSG
+                (!td.error
+                ,"COI multiplier value \""
+                    << td.value
+                    << "\" didn't generate the expected error ("
+                    << td.error
+                    << ")"
+                );
+            }
         }
 
-    ui.Char('l', wxMOD_CONTROL);    // "File|Close"
-    wxYield();
-
-    LMI_ASSERT(error_detected);
+    ill.close_discard_changes();
 }




reply via email to

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