diff options
| author | Michael R. Mauger | 2019-02-20 22:13:51 -0500 |
|---|---|---|
| committer | Michael R. Mauger | 2019-02-20 22:13:51 -0500 |
| commit | c124d5323c05a4010db9b2d330575d029936ade1 (patch) | |
| tree | 9973520a2c520ed0f378690d0996c2b0b3a53e54 | |
| parent | 4d91e6469828d2b934c959de5932ad5a048ddfd5 (diff) | |
| download | emacs-c124d5323c05a4010db9b2d330575d029936ade1.tar.gz emacs-c124d5323c05a4010db9b2d330575d029936ade1.zip | |
Correct implementation of `sql-set-product-feature' (Bug#30494).
* lisp.progmodes/sql.el (sql-add-product): Correct argument spec.
(sql-set-product-feature): Handle all cases as intended.
(sql-get-product-feature): Fetch varaiable value by `eval'.
* test/lisp/progmodes/sql-tests.el (sql-test-feature-value-[a-d]):
New test variables.
(sql-test-product-feature-harness): New test macro.
(sql-test-add-product, sql-test-add-existing-product)
(sql-test-set-feature, sql-test-set-indirect-feature)
(sql-test-set-existing-feature)
(sql-test-set-existing-indirect-feature)
(sql-test-set-missing-product, sql-test-get-feature)
(sql-test-get-indirect-feature, sql-test-get-missing-product)
(sql-test-get-missing-feature)
(sql-test-get-missing-indirect-feature): New ERT tests
| -rw-r--r-- | lisp/progmodes/sql.el | 49 | ||||
| -rw-r--r-- | test/lisp/progmodes/sql-tests.el | 228 |
2 files changed, 206 insertions, 71 deletions
diff --git a/lisp/progmodes/sql.el b/lisp/progmodes/sql.el index 9bae3d86640..2a42e7f4515 100644 --- a/lisp/progmodes/sql.el +++ b/lisp/progmodes/sql.el | |||
| @@ -2725,7 +2725,7 @@ highlighting rules in SQL mode.") | |||
| 2725 | nil 'require-match | 2725 | nil 'require-match |
| 2726 | init 'sql-product-history init)))) | 2726 | init 'sql-product-history init)))) |
| 2727 | 2727 | ||
| 2728 | (defun sql-add-product (product display &rest plist) | 2728 | (defun sql-add-product (product display &optional plist) |
| 2729 | "Add support for a database product in `sql-mode'. | 2729 | "Add support for a database product in `sql-mode'. |
| 2730 | 2730 | ||
| 2731 | Add PRODUCT to `sql-product-alist' which enables `sql-mode' to | 2731 | Add PRODUCT to `sql-product-alist' which enables `sql-mode' to |
| @@ -2782,19 +2782,38 @@ list. See `sql-add-product' to add new products. The FEATURE | |||
| 2782 | argument must be a plist keyword accepted by | 2782 | argument must be a plist keyword accepted by |
| 2783 | `sql-product-alist'." | 2783 | `sql-product-alist'." |
| 2784 | 2784 | ||
| 2785 | (let* ((p (assoc product sql-product-alist)) | 2785 | (let* ((p (assoc product sql-product-alist)) ;; (PRODUCT :f v ...) |
| 2786 | (v (plist-get (cdr p) feature))) | 2786 | (v (plist-member (cdr p) feature))) ;; (:FEATURE value ...) or null |
| 2787 | (if (and p v) | 2787 | |
| 2788 | (if (and | 2788 | (if p |
| 2789 | (member feature sql-indirect-features) | 2789 | (if (member feature sql-indirect-features) ; is indirect |
| 2790 | (symbolp v)) | 2790 | (if v |
| 2791 | (set v newvalue) | 2791 | (if (car (cdr v)) |
| 2792 | (setcdr p (plist-put (cdr p) feature newvalue))) | 2792 | (if (symbolp (car (cdr v))) |
| 2793 | (progn | 2793 | ;; Indirect reference |
| 2794 | (when (null p) | 2794 | (set (car (cdr v)) newvalue) |
| 2795 | (error "`%s' is not a known product; use `sql-add-product' to add it first." product)) | 2795 | ;; indirect is not a symbol |
| 2796 | (when (null v) | 2796 | (error "The value of `%s' for `%s' is not a symbol" feature product)) |
| 2797 | (error "`%s' is not a known feature for `%s'; use `sql-add-product' to add it first." feature product)))))) | 2797 | ;; keyword present, set the indirect variable name |
| 2798 | (if (symbolp newvalue) | ||
| 2799 | (if (cdr v) | ||
| 2800 | (setf (car (cdr v)) newvalue) | ||
| 2801 | (setf (cdr v) (list newvalue))) | ||
| 2802 | (error "The indirect variable of `%s' for `%s' must be a symbol" feature product))) | ||
| 2803 | ;; not present; insert list | ||
| 2804 | (setq v (list feature newvalue)) | ||
| 2805 | (setf (cdr (cdr v)) (cdr p)) | ||
| 2806 | (setf (cdr p) v)) | ||
| 2807 | ;; Not an indirect feature | ||
| 2808 | (if v | ||
| 2809 | (if (cdr v) | ||
| 2810 | (setf (car (cdr v)) newvalue) | ||
| 2811 | (setf (cdr v) (list newvalue))) | ||
| 2812 | ;; no value; insert into the list | ||
| 2813 | (setq v (list feature newvalue)) | ||
| 2814 | (setf (cdr (cdr v)) (cdr p)) | ||
| 2815 | (setf (cdr p) v))) | ||
| 2816 | (error "`%s' is not a known product; use `sql-add-product' to add it first" product)))) | ||
| 2798 | 2817 | ||
| 2799 | (defun sql-get-product-feature (product feature &optional fallback not-indirect) | 2818 | (defun sql-get-product-feature (product feature &optional fallback not-indirect) |
| 2800 | "Lookup FEATURE associated with a SQL PRODUCT. | 2819 | "Lookup FEATURE associated with a SQL PRODUCT. |
| @@ -2822,7 +2841,7 @@ See `sql-product-alist' for a list of products and supported features." | |||
| 2822 | (member feature sql-indirect-features) | 2841 | (member feature sql-indirect-features) |
| 2823 | (not not-indirect) | 2842 | (not not-indirect) |
| 2824 | (symbolp v)) | 2843 | (symbolp v)) |
| 2825 | (symbol-value v) | 2844 | (eval v) |
| 2826 | v)) | 2845 | v)) |
| 2827 | (error "`%s' is not a known product; use `sql-add-product' to add it first." product) | 2846 | (error "`%s' is not a known product; use `sql-add-product' to add it first." product) |
| 2828 | nil))) | 2847 | nil))) |
diff --git a/test/lisp/progmodes/sql-tests.el b/test/lisp/progmodes/sql-tests.el index a68f9319c2f..7a11f762eb0 100644 --- a/test/lisp/progmodes/sql-tests.el +++ b/test/lisp/progmodes/sql-tests.el | |||
| @@ -53,6 +53,8 @@ | |||
| 53 | (error "some error")))) | 53 | (error "some error")))) |
| 54 | (should-not (sql-postgres-list-databases)))) | 54 | (should-not (sql-postgres-list-databases)))) |
| 55 | 55 | ||
| 56 | ;;; Check Connection Password Handling/Wallet | ||
| 57 | |||
| 56 | (defvar sql-test-login-params nil) | 58 | (defvar sql-test-login-params nil) |
| 57 | (defmacro with-sql-test-connect-harness (id login-params connection expected) | 59 | (defmacro with-sql-test-connect-harness (id login-params connection expected) |
| 58 | "Set-up and tear-down SQL connect related test. | 60 | "Set-up and tear-down SQL connect related test. |
| @@ -62,40 +64,40 @@ LOGIN-PARAMS. Provide the CONNECTION parameters and the EXPECTED | |||
| 62 | string of values passed to the comint function for validation." | 64 | string of values passed to the comint function for validation." |
| 63 | (declare (indent 2)) | 65 | (declare (indent 2)) |
| 64 | `(cl-letf | 66 | `(cl-letf |
| 65 | ((sql-test-login-params ' ,login-params) | 67 | ((sql-test-login-params ' ,login-params) |
| 66 | ((symbol-function 'sql-comint-test) | 68 | ((symbol-function 'sql-comint-test) |
| 67 | (lambda (product options &optional buf-name) | 69 | (lambda (product options &optional buf-name) |
| 68 | (with-current-buffer (get-buffer-create buf-name) | 70 | (with-current-buffer (get-buffer-create buf-name) |
| 69 | (insert (pp-to-string (list product options sql-user sql-password sql-server sql-database)))))) | 71 | (insert (pp-to-string (list product options sql-user sql-password sql-server sql-database)))))) |
| 70 | ((symbol-function 'sql-run-test) | 72 | ((symbol-function 'sql-run-test) |
| 71 | (lambda (&optional buffer) | 73 | (lambda (&optional buffer) |
| 72 | (interactive "P") | 74 | (interactive "P") |
| 73 | (sql-product-interactive 'sqltest buffer))) | 75 | (sql-product-interactive 'sqltest buffer))) |
| 74 | (sql-user nil) | 76 | (sql-user nil) |
| 75 | (sql-server nil) | 77 | (sql-server nil) |
| 76 | (sql-database nil) | 78 | (sql-database nil) |
| 77 | (sql-product-alist | 79 | (sql-product-alist |
| 78 | '((ansi) | 80 | '((ansi) |
| 79 | (sqltest | 81 | (sqltest |
| 80 | :name "SqlTest" | 82 | :name "SqlTest" |
| 81 | :sqli-login sql-test-login-params | 83 | :sqli-login sql-test-login-params |
| 82 | :sqli-comint-func sql-comint-test))) | 84 | :sqli-comint-func sql-comint-test))) |
| 83 | (sql-connection-alist | 85 | (sql-connection-alist |
| 84 | '((,(format "test-%s" id) | 86 | '((,(format "test-%s" id) |
| 85 | ,@connection))) | 87 | ,@connection))) |
| 86 | (sql-password-wallet | 88 | (sql-password-wallet |
| 87 | (list | 89 | (list |
| 88 | (make-temp-file | 90 | (make-temp-file |
| 89 | "sql-test-netrc" nil nil | 91 | "sql-test-netrc" nil nil |
| 90 | (mapconcat #'identity | 92 | (mapconcat #'identity |
| 91 | '("machine aMachine user aUserName password \"netrc-A aPassword\"" | 93 | '("machine aMachine user aUserName password \"netrc-A aPassword\"" |
| 92 | "machine aServer user aUserName password \"netrc-B aPassword\"" | 94 | "machine aServer user aUserName password \"netrc-B aPassword\"" |
| 93 | "machine aMachine server aServer user aUserName password \"netrc-C aPassword\"" | 95 | "machine aMachine server aServer user aUserName password \"netrc-C aPassword\"" |
| 94 | "machine aMachine database aDatabase user aUserName password \"netrc-D aPassword\"" | 96 | "machine aMachine database aDatabase user aUserName password \"netrc-D aPassword\"" |
| 95 | "machine aDatabase user aUserName password \"netrc-E aPassword\"" | 97 | "machine aDatabase user aUserName password \"netrc-E aPassword\"" |
| 96 | "machine aMachine server aServer database aDatabase user aUserName password \"netrc-F aPassword\"" | 98 | "machine aMachine server aServer database aDatabase user aUserName password \"netrc-F aPassword\"" |
| 97 | "machine \"aServer/aDatabase\" user aUserName password \"netrc-G aPassword\"" | 99 | "machine \"aServer/aDatabase\" user aUserName password \"netrc-G aPassword\"" |
| 98 | ) "\n"))))) | 100 | ) "\n"))))) |
| 99 | 101 | ||
| 100 | (let* ((connection ,(format "test-%s" id)) | 102 | (let* ((connection ,(format "test-%s" id)) |
| 101 | (buffername (format "*SQL: ERT TEST <%s>*" connection))) | 103 | (buffername (format "*SQL: ERT TEST <%s>*" connection))) |
| @@ -106,53 +108,167 @@ string of values passed to the comint function for validation." | |||
| 106 | (should (string-equal (with-current-buffer buffername (buffer-string)) ,expected)) | 108 | (should (string-equal (with-current-buffer buffername (buffer-string)) ,expected)) |
| 107 | (when (get-buffer buffername) | 109 | (when (get-buffer buffername) |
| 108 | (kill-buffer buffername)) | 110 | (kill-buffer buffername)) |
| 109 | (delete-file (car sql-password-wallet))))) | 111 | (delete-file (car sql-password-wallet))))) |
| 110 | 112 | ||
| 111 | (ert-deftest sql-test-connect () | 113 | (ert-deftest sql-test-connect () |
| 112 | "Test of basic `sql-connect'." | 114 | "Test of basic `sql-connect'." |
| 113 | (with-sql-test-connect-harness 1 (user password server database) | 115 | (with-sql-test-connect-harness 1 (user password server database) |
| 114 | ((sql-product 'sqltest) | 116 | ((sql-product 'sqltest) |
| 115 | (sql-user "aUserName") | 117 | (sql-user "aUserName") |
| 116 | (sql-password "test-1 aPassword") | 118 | (sql-password "test-1 aPassword") |
| 117 | (sql-server "aServer") | 119 | (sql-server "aServer") |
| 118 | (sql-database "aDatabase")) | 120 | (sql-database "aDatabase")) |
| 119 | "(sqltest nil \"aUserName\" \"test-1 aPassword\" \"aServer\" \"aDatabase\")\n")) | 121 | "(sqltest nil \"aUserName\" \"test-1 aPassword\" \"aServer\" \"aDatabase\")\n")) |
| 120 | 122 | ||
| 121 | (ert-deftest sql-test-connect-password-func () | 123 | (ert-deftest sql-test-connect-password-func () |
| 122 | "Test of password function." | 124 | "Test of password function." |
| 123 | (with-sql-test-connect-harness 2 (user password server database) | 125 | (with-sql-test-connect-harness 2 (user password server database) |
| 124 | ((sql-product 'sqltest) | 126 | ((sql-product 'sqltest) |
| 125 | (sql-user "aUserName") | 127 | (sql-user "aUserName") |
| 126 | (sql-password (lambda () (concat [?t ?e ?s ?t ?- ?2 ?\s | 128 | (sql-password (lambda () (concat [?t ?e ?s ?t ?- ?2 ?\s |
| 127 | ?a ?P ?a ?s ?s ?w ?o ?r ?d]))) | 129 | ?a ?P ?a ?s ?s ?w ?o ?r ?d]))) |
| 128 | (sql-server "aServer") | 130 | (sql-server "aServer") |
| 129 | (sql-database "aDatabase")) | 131 | (sql-database "aDatabase")) |
| 130 | "(sqltest nil \"aUserName\" \"test-2 aPassword\" \"aServer\" \"aDatabase\")\n")) | 132 | "(sqltest nil \"aUserName\" \"test-2 aPassword\" \"aServer\" \"aDatabase\")\n")) |
| 131 | 133 | ||
| 132 | (ert-deftest sql-test-connect-wallet-server-database () | 134 | (ert-deftest sql-test-connect-wallet-server-database () |
| 133 | "Test of password function." | 135 | "Test of password function." |
| 134 | (with-sql-test-connect-harness 3 (user password server database) | 136 | (with-sql-test-connect-harness 3 (user password server database) |
| 135 | ((sql-product 'sqltest) | 137 | ((sql-product 'sqltest) |
| 136 | (sql-user "aUserName") | 138 | (sql-user "aUserName") |
| 137 | (sql-server "aServer") | 139 | (sql-server "aServer") |
| 138 | (sql-database "aDatabase")) | 140 | (sql-database "aDatabase")) |
| 139 | "(sqltest nil \"aUserName\" \"netrc-G aPassword\" \"aServer\" \"aDatabase\")\n")) | 141 | "(sqltest nil \"aUserName\" \"netrc-G aPassword\" \"aServer\" \"aDatabase\")\n")) |
| 140 | 142 | ||
| 141 | (ert-deftest sql-test-connect-wallet-database () | 143 | (ert-deftest sql-test-connect-wallet-database () |
| 142 | "Test of password function." | 144 | "Test of password function." |
| 143 | (with-sql-test-connect-harness 4 (user password database) | 145 | (with-sql-test-connect-harness 4 (user password database) |
| 144 | ((sql-product 'sqltest) | 146 | ((sql-product 'sqltest) |
| 145 | (sql-user "aUserName") | 147 | (sql-user "aUserName") |
| 146 | (sql-database "aDatabase")) | 148 | (sql-database "aDatabase")) |
| 147 | "(sqltest nil \"aUserName\" \"netrc-E aPassword\" nil \"aDatabase\")\n")) | 149 | "(sqltest nil \"aUserName\" \"netrc-E aPassword\" nil \"aDatabase\")\n")) |
| 148 | 150 | ||
| 149 | (ert-deftest sql-test-connect-wallet-server () | 151 | (ert-deftest sql-test-connect-wallet-server () |
| 150 | "Test of password function." | 152 | "Test of password function." |
| 151 | (with-sql-test-connect-harness 5 (user password server) | 153 | (with-sql-test-connect-harness 5 (user password server) |
| 152 | ((sql-product 'sqltest) | 154 | ((sql-product 'sqltest) |
| 153 | (sql-user "aUserName") | 155 | (sql-user "aUserName") |
| 154 | (sql-server "aServer")) | 156 | (sql-server "aServer")) |
| 155 | "(sqltest nil \"aUserName\" \"netrc-B aPassword\" \"aServer\" nil)\n")) | 157 | "(sqltest nil \"aUserName\" \"netrc-B aPassword\" \"aServer\" nil)\n")) |
| 156 | 158 | ||
| 159 | ;;; Set/Get Product Features | ||
| 160 | |||
| 161 | (defvar sql-test-feature-value-a nil "Indirect value A.") | ||
| 162 | (defvar sql-test-feature-value-b nil "Indirect value B.") | ||
| 163 | (defvar sql-test-feature-value-c nil "Indirect value C.") | ||
| 164 | (defvar sql-test-feature-value-d nil "Indirect value D.") | ||
| 165 | (defmacro sql-test-product-feature-harness (&rest action) | ||
| 166 | "Set-up and tear-down of testing product/feature API. | ||
| 167 | |||
| 168 | Perform ACTION and validate results" | ||
| 169 | (declare (indent 2)) | ||
| 170 | `(cl-letf | ||
| 171 | ((sql-product-alist | ||
| 172 | (list (list 'a :X 1 :Y 2 :Z 'sql-test-feature-value-a) | ||
| 173 | (list 'b :X 3 :Z 'sql-test-feature-value-b) | ||
| 174 | (list 'c :Y 6 :Z 'sql-test-feature-value-c) | ||
| 175 | (list 'd :X 7 :Y 8 ))) | ||
| 176 | (sql-indirect-features '(:Z :W)) | ||
| 177 | (sql-test-feature-value-a "original A") | ||
| 178 | (sql-test-feature-value-b "original B") | ||
| 179 | (sql-test-feature-value-c "original C") | ||
| 180 | (sql-test-feature-value-d "original D")) | ||
| 181 | ,@action)) | ||
| 182 | |||
| 183 | (ert-deftest sql-test-add-product () | ||
| 184 | "Add a product" | ||
| 185 | |||
| 186 | (sql-test-product-feature-harness | ||
| 187 | (sql-add-product 'xyz "XyzDb") | ||
| 188 | |||
| 189 | (should (equal (pp-to-string (assoc 'xyz sql-product-alist)) | ||
| 190 | "(xyz :name \"XyzDb\")\n")))) | ||
| 191 | |||
| 192 | (ert-deftest sql-test-add-existing-product () | ||
| 193 | "Add a product that already exists." | ||
| 194 | |||
| 195 | (sql-test-product-feature-harness | ||
| 196 | (should-error (sql-add-feature 'a "Aaa")) | ||
| 197 | (should (equal (pp-to-string (assoc 'a sql-product-alist)) | ||
| 198 | "(a :X 1 :Y 2 :Z sql-test-feature-value-a)\n")))) | ||
| 199 | |||
| 200 | (ert-deftest sql-test-set-feature () | ||
| 201 | "Add a feature" | ||
| 202 | |||
| 203 | (sql-test-product-feature-harness | ||
| 204 | (sql-set-product-feature 'b :Y 4) | ||
| 205 | (should (equal (pp-to-string (assoc 'b sql-product-alist)) | ||
| 206 | "(b :Y 4 :X 3 :Z sql-test-feature-value-b)\n")))) | ||
| 207 | |||
| 208 | (ert-deftest sql-test-set-indirect-feature () | ||
| 209 | "Set a new indirect feature" | ||
| 210 | |||
| 211 | (sql-test-product-feature-harness | ||
| 212 | (sql-set-product-feature 'd :Z 'sql-test-feature-value-d) | ||
| 213 | (should (equal (pp-to-string (assoc 'd sql-product-alist)) | ||
| 214 | "(d :Z sql-test-feature-value-d :X 7 :Y 8)\n")))) | ||
| 215 | |||
| 216 | (ert-deftest sql-test-set-existing-feature () | ||
| 217 | "Set an existing feature." | ||
| 218 | |||
| 219 | (sql-test-product-feature-harness | ||
| 220 | (sql-set-product-feature 'b :X 33) | ||
| 221 | (should (equal (pp-to-string (assoc 'b sql-product-alist)) | ||
| 222 | "(b :X 33 :Z sql-test-feature-value-b)\n")))) | ||
| 223 | |||
| 224 | (ert-deftest sql-test-set-existing-indirect-feature () | ||
| 225 | "Set an existing indirect feature." | ||
| 226 | |||
| 227 | (sql-test-product-feature-harness | ||
| 228 | (should (equal sql-test-feature-value-b "original B")) | ||
| 229 | (sql-set-product-feature 'b :Z "Hurray!") | ||
| 230 | (should (equal (pp-to-string (assoc 'b sql-product-alist)) | ||
| 231 | "(b :X 3 :Z sql-test-feature-value-b)\n")) ;; unchanged | ||
| 232 | (should (equal sql-test-feature-value-b "Hurray!")))) | ||
| 233 | |||
| 234 | (ert-deftest sql-test-set-missing-product () | ||
| 235 | "Add a feature to a missing product." | ||
| 236 | |||
| 237 | (sql-test-product-feature-harness | ||
| 238 | (should-error (sql-set-product-feature 'x :Y 4)) | ||
| 239 | (should-not (assoc 'x sql-product-alist)))) | ||
| 240 | |||
| 241 | (ert-deftest sql-test-get-feature () | ||
| 242 | "Get a feature value." | ||
| 243 | |||
| 244 | (sql-test-product-feature-harness | ||
| 245 | (should (equal (sql-get-product-feature 'c :Y) 6)))) | ||
| 246 | |||
| 247 | (ert-deftest sql-test-get-indirect-feature () | ||
| 248 | "Get a feature indirect value." | ||
| 249 | |||
| 250 | (sql-test-product-feature-harness | ||
| 251 | (should (equal (sql-get-product-feature 'c :Z nil t) 'sql-test-feature-value-c)) | ||
| 252 | (should (equal sql-test-feature-value-c "original C")) | ||
| 253 | (should (equal (sql-get-product-feature 'c :Z) "original C")))) | ||
| 254 | |||
| 255 | (ert-deftest sql-test-get-missing-product () | ||
| 256 | "Get a feature value from a missing product." | ||
| 257 | |||
| 258 | (sql-test-product-feature-harness | ||
| 259 | (should-error (sql-get-product-feature 'x :Y)))) | ||
| 260 | |||
| 261 | (ert-deftest sql-test-get-missing-feature () | ||
| 262 | "Get a missing feature value." | ||
| 263 | |||
| 264 | (sql-test-product-feature-harness | ||
| 265 | (should-not (sql-get-product-feature 'c :X)))) | ||
| 266 | |||
| 267 | (ert-deftest sql-test-get-missing-indirect-feature () | ||
| 268 | "Get a missing indirect feature value." | ||
| 269 | |||
| 270 | (sql-test-product-feature-harness | ||
| 271 | (should-not (sql-get-product-feature 'd :Z)))) | ||
| 272 | |||
| 157 | (provide 'sql-tests) | 273 | (provide 'sql-tests) |
| 158 | ;;; sql-tests.el ends here | 274 | ;;; sql-tests.el ends here |