[geary/mjog/636-add-account-name-validation: 1/2] Add manual Components.Validator::validator method



commit ca6cbecb837c004cb950d5a286df656dec3b001f
Author: Michael Gratton <mike vee net>
Date:   Wed Nov 20 14:45:04 2019 +1100

    Add manual Components.Validator::validator method
    
    Support manual validation where needed, add unit tests.
    
    This also slightly changes the behaviour of non-required field, since
    an empty non-required field should be valid.

 src/client/components/components-validator.vala    |  31 ++++--
 .../components/components-validator-test.vala      | 104 +++++++++++++++++++++
 test/meson.build                                   |   1 +
 test/test-client.vala                              |   1 +
 4 files changed, 127 insertions(+), 10 deletions(-)
---
diff --git a/src/client/components/components-validator.vala b/src/client/components/components-validator.vala
index 3e0a7eb8..e5bf0bfd 100644
--- a/src/client/components/components-validator.vala
+++ b/src/client/components/components-validator.vala
@@ -48,7 +48,9 @@ public class Components.Validator : GLib.Object {
 
     /** The cause of a validity check being required. */
     public enum Trigger {
-        /** The entry's contents changed */
+        /** A manual validation was requested via {@link validate}. */
+        MANUAL,
+        /** The entry's contents changed. */
         CHANGED,
         /** The entry lost the keyboard focus. */
         LOST_FOCUS,
@@ -162,6 +164,17 @@ public class Components.Validator : GLib.Object {
         this.pulse_timer.reset();
     }
 
+    /**
+     * Triggers a validation of the entry.
+     *
+     * In the case of an asynchronous validation implementations,
+     * result of the validation will be known sometime after this call
+     * has completed.
+     */
+    public void validate() {
+        validate_entry(MANUAL);
+    }
+
     /**
      * Called to validate the target entry's value.
      *
@@ -187,7 +200,7 @@ public class Components.Validator : GLib.Object {
      * By default, this always returns {@link Validity.VALID}, making
      * it useful for required, but otherwise free-form fields only.
      */
-    protected virtual Validity validate(string value, Trigger reason) {
+    protected virtual Validity do_validate(string value, Trigger reason) {
         return Validity.VALID;
     }
 
@@ -255,12 +268,10 @@ public class Components.Validator : GLib.Object {
         string value = this.target.get_text();
         Validity new_state = this.state;
         if (Geary.String.is_empty_or_whitespace(value)) {
-            new_state = this.is_required
-                ? Validity.EMPTY : Validity.INDETERMINATE;
+            new_state = this.is_required ? Validity.EMPTY : Validity.VALID;
         } else {
-            new_state = validate(value, reason);
+            new_state = do_validate(value, reason);
         }
-
         update_state(new_state, reason);
     }
 
@@ -384,8 +395,8 @@ public class Components.EmailValidator : Validator {
     }
 
 
-    protected override Validator.Validity validate(string value,
-                                                   Validator.Trigger reason) {
+    protected override Validator.Validity do_validate(string value,
+                                                      Validator.Trigger reason) {
         return Geary.RFC822.MailboxAddress.is_valid_address(value)
             ? Validator.Validity.VALID : Validator.Validity.INVALID;
     }
@@ -435,8 +446,8 @@ public class Components.NetworkAddressValidator : Validator {
     }
 
 
-    public override Validator.Validity validate(string value,
-                                                Validator.Trigger reason) {
+    public override Validator.Validity do_validate(string value,
+                                                   Validator.Trigger reason) {
         if (this.cancellable != null) {
             this.cancellable.cancel();
         }
diff --git a/test/client/components/components-validator-test.vala 
b/test/client/components/components-validator-test.vala
new file mode 100644
index 00000000..aebb6f1c
--- /dev/null
+++ b/test/client/components/components-validator-test.vala
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2019 Michael Gratton <mike vee net>
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+
+public class Components.ValidatorTest : TestCase {
+
+
+    private Gtk.Entry? entry = null;
+
+
+    public ValidatorTest() {
+        base("Components.ValidatorTest");
+        add_test("manual_empty", manual_empty);
+        add_test("manual_valid", manual_valid);
+        add_test("manual_not_required", manual_not_required);
+    }
+
+    public override void set_up() {
+        this.entry = new Gtk.Entry();
+    }
+
+    public override void tear_down() {
+        this.entry = null;
+    }
+
+    public void manual_empty() throws GLib.Error {
+        Validator test_article = new Validator(this.entry);
+
+        bool finished = false;
+        Validator.Trigger?  reason = null;
+        Validator.Validity? prev_state = null;
+        test_article.state_changed.connect((r, p) => {
+                finished = true;
+                reason = r;
+                prev_state = p;
+            });
+
+        test_article.validate();
+
+        while (!finished) {
+            this.main_loop.iteration(true);
+        }
+
+        assert_false(test_article.is_valid);
+        assert_true(test_article.state == EMPTY);
+        assert_true(reason == MANUAL);
+        assert_true(prev_state == INDETERMINATE);
+    }
+
+    public void manual_valid() throws GLib.Error {
+        this.entry.text = "OHHAI";
+        Validator test_article = new Validator(this.entry);
+
+        bool finished = false;
+        Validator.Trigger?  reason = null;
+        Validator.Validity? prev_state = null;
+        test_article.state_changed.connect((r, p) => {
+                finished = true;
+                reason = r;
+                prev_state = p;
+            });
+
+        test_article.validate();
+
+        while (!finished) {
+            this.main_loop.iteration(true);
+        }
+
+        assert_true(test_article.is_valid);
+        assert_true(test_article.state == VALID);
+        assert_true(reason == MANUAL);
+        assert_true(prev_state == INDETERMINATE);
+    }
+
+    public void manual_not_required() throws GLib.Error {
+        Validator test_article = new Validator(this.entry);
+        test_article.is_required = false;
+
+        bool finished = false;
+        Validator.Trigger?  reason = null;
+        Validator.Validity? prev_state = null;
+        test_article.state_changed.connect((r, p) => {
+                finished = true;
+                reason = r;
+                prev_state = p;
+            });
+
+        test_article.validate();
+
+        while (!finished) {
+            this.main_loop.iteration(true);
+        }
+
+        assert_true(test_article.is_valid);
+        assert_true(test_article.state == VALID);
+        assert_true(reason == MANUAL);
+        assert_true(prev_state == INDETERMINATE);
+    }
+
+}
diff --git a/test/meson.build b/test/meson.build
index 1cced2f7..38a3aae2 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -84,6 +84,7 @@ geary_test_client_sources = [
   'client/application/application-configuration-test.vala',
   'client/components/client-web-view-test.vala',
   'client/components/client-web-view-test-case.vala',
+  'client/components/components-validator-test.vala',
   'client/composer/composer-web-view-test.vala',
   'client/util/util-avatar-test.vala',
   'client/util/util-cache-test.vala',
diff --git a/test/test-client.vala b/test/test-client.vala
index 6b828b0c..1016d2a5 100644
--- a/test/test-client.vala
+++ b/test/test-client.vala
@@ -53,6 +53,7 @@ int main(string[] args) {
     client.add_suite(new Application.ConfigurationTest().get_suite());
     client.add_suite(new ClientWebViewTest().get_suite());
     client.add_suite(new Composer.WebViewTest().get_suite());
+    client.add_suite(new Components.ValidatorTest().get_suite());
     client.add_suite(new Util.Avatar.Test().get_suite());
     client.add_suite(new Util.Cache.Test().get_suite());
     client.add_suite(new Util.Email.Test().get_suite());


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