;;; python-tests.el --- Test suite for python.el
-;; Copyright (C) 2013-2015 Free Software Foundation, Inc.
+;; Copyright (C) 2013-2016 Free Software Foundation, Inc.
;; This file is part of GNU Emacs.
(require 'ert)
(require 'python)
+;; Dependencies for testing:
+(require 'electric)
+(require 'hideshow)
+(require 'tramp-sh)
+
+
(defmacro python-tests-with-temp-buffer (contents &rest body)
"Create a `python-mode' enabled temp buffer with CONTENTS.
BODY is code to be executed within the temp buffer. Point is
always located at the beginning of buffer."
(declare (indent 1) (debug t))
`(with-temp-buffer
- (python-mode)
- (insert ,contents)
- (goto-char (point-min))
- ,@body))
+ (let ((python-indent-guess-indent-offset nil))
+ (python-mode)
+ (insert ,contents)
+ (goto-char (point-min))
+ ,@body)))
(defmacro python-tests-with-temp-file (contents &rest body)
"Create a `python-mode' enabled file with CONTENTS.
(declare (indent 1) (debug t))
;; temp-file never actually used for anything?
`(let* ((temp-file (make-temp-file "python-tests" nil ".py"))
- (buffer (find-file-noselect temp-file)))
+ (buffer (find-file-noselect temp-file))
+ (python-indent-guess-indent-offset nil))
(unwind-protect
(with-current-buffer buffer
(python-mode)
(call-interactively 'self-insert-command)))
chars)))
+(defun python-tests-visible-string (&optional min max)
+ "Return the buffer string excluding invisible overlays.
+Argument MIN and MAX delimit the region to be returned and
+default to `point-min' and `point-max' respectively."
+ (let* ((min (or min (point-min)))
+ (max (or max (point-max)))
+ (buffer (current-buffer))
+ (buffer-contents (buffer-substring-no-properties min max))
+ (overlays
+ (sort (overlays-in min max)
+ (lambda (a b)
+ (let ((overlay-end-a (overlay-end a))
+ (overlay-end-b (overlay-end b)))
+ (> overlay-end-a overlay-end-b))))))
+ (with-temp-buffer
+ (insert buffer-contents)
+ (dolist (overlay overlays)
+ (if (overlay-get overlay 'invisible)
+ (delete-region (overlay-start overlay)
+ (overlay-end overlay))))
+ (buffer-substring-no-properties (point-min) (point-max)))))
+
\f
;;; Tests for your tests, so you can test while you test.
foo = long_function_name(var_one, var_two,
var_three, var_four)
"
- (should (eq (car (python-indent-context)) 'no-indent))
+ (should (eq (car (python-indent-context)) :no-indent))
(should (= (python-indent-calculate-indentation) 0))
(python-tests-look-at "foo = long_function_name(var_one, var_two,")
- (should (eq (car (python-indent-context)) 'after-line))
+ (should (eq (car (python-indent-context)) :after-comment))
(should (= (python-indent-calculate-indentation) 0))
(python-tests-look-at "var_three, var_four)")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren))
(should (= (python-indent-calculate-indentation) 25))))
(ert-deftest python-indent-pep8-2 ()
var_four):
print (var_one)
"
- (should (eq (car (python-indent-context)) 'no-indent))
+ (should (eq (car (python-indent-context)) :no-indent))
(should (= (python-indent-calculate-indentation) 0))
(python-tests-look-at "def long_function_name(")
- (should (eq (car (python-indent-context)) 'after-line))
+ (should (eq (car (python-indent-context)) :after-comment))
(should (= (python-indent-calculate-indentation) 0))
(python-tests-look-at "var_one, var_two, var_three,")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context))
+ :inside-paren-newline-start-from-block))
(should (= (python-indent-calculate-indentation) 8))
(python-tests-look-at "var_four):")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context))
+ :inside-paren-newline-start-from-block))
(should (= (python-indent-calculate-indentation) 8))
(python-tests-look-at "print (var_one)")
- (should (eq (car (python-indent-context)) 'after-beginning-of-block))
+ (should (eq (car (python-indent-context))
+ :after-block-start))
(should (= (python-indent-calculate-indentation) 4))))
(ert-deftest python-indent-pep8-3 ()
var_one, var_two,
var_three, var_four)
"
- (should (eq (car (python-indent-context)) 'no-indent))
+ (should (eq (car (python-indent-context)) :no-indent))
(should (= (python-indent-calculate-indentation) 0))
(python-tests-look-at "foo = long_function_name(")
- (should (eq (car (python-indent-context)) 'after-line))
+ (should (eq (car (python-indent-context)) :after-comment))
(should (= (python-indent-calculate-indentation) 0))
(python-tests-look-at "var_one, var_two,")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 4))
(python-tests-look-at "var_three, var_four)")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 4))))
+(ert-deftest python-indent-base-case ()
+ "Check base case does not trigger errors."
+ (python-tests-with-temp-buffer
+ "
+
+"
+ (goto-char (point-min))
+ (should (eq (car (python-indent-context)) :no-indent))
+ (should (= (python-indent-calculate-indentation) 0))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :no-indent))
+ (should (= (python-indent-calculate-indentation) 0))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :no-indent))
+ (should (= (python-indent-calculate-indentation) 0))))
+
(ert-deftest python-indent-after-comment-1 ()
"The most simple after-comment case that shouldn't fail."
(python-tests-with-temp-buffer
# with the exception with which the first child failed.
"
(python-tests-look-at "# We only complete")
- (should (eq (car (python-indent-context)) 'after-line))
+ (should (eq (car (python-indent-context)) :after-block-end))
(should (= (python-indent-calculate-indentation) 8))
(python-tests-look-at "# terminal state")
- (should (eq (car (python-indent-context)) 'after-comment))
+ (should (eq (car (python-indent-context)) :after-comment))
(should (= (python-indent-calculate-indentation) 8))
(python-tests-look-at "# with the exception")
- (should (eq (car (python-indent-context)) 'after-comment))
+ (should (eq (car (python-indent-context)) :after-comment))
;; This one indents relative to previous block, even given the fact
;; that it was under-indented.
(should (= (python-indent-calculate-indentation) 4))
(python-tests-look-at "# terminal state" -1)
;; It doesn't hurt to check again.
- (should (eq (car (python-indent-context)) 'after-comment))
+ (should (eq (car (python-indent-context)) :after-comment))
(python-indent-line)
(should (= (current-indentation) 8))
(python-tests-look-at "# with the exception")
- (should (eq (car (python-indent-context)) 'after-comment))
+ (should (eq (car (python-indent-context)) :after-comment))
;; Now everything should be lined up.
(should (= (python-indent-calculate-indentation) 8))))
def func(arg):
# I don't do much
return arg
- # This comment is badly indented just because.
- # But we won't mess with the user in this line.
+ # This comment is badly indented because the user forced so.
+ # At this line python.el wont dedent, user is always right.
-now_we_do_mess_cause_this_is_not_a_comment = 1
+comment_wins_over_ender = True
# yeah, that.
"
(python-tests-look-at "# I don't do much")
- (should (eq (car (python-indent-context)) 'after-beginning-of-block))
+ (should (eq (car (python-indent-context)) :after-block-start))
(should (= (python-indent-calculate-indentation) 4))
(python-tests-look-at "return arg")
;; Comment here just gets ignored, this line is not a comment so
;; the rules won't apply here.
- (should (eq (car (python-indent-context)) 'after-beginning-of-block))
+ (should (eq (car (python-indent-context)) :after-block-start))
(should (= (python-indent-calculate-indentation) 4))
- (python-tests-look-at "# This comment is badly")
- (should (eq (car (python-indent-context)) 'after-line))
- ;; The return keyword moves indentation backwards 4 spaces, but
- ;; let's assume this comment was placed there because the user
- ;; wanted to (manually adding spaces or whatever).
+ (python-tests-look-at "# This comment is badly indented")
+ (should (eq (car (python-indent-context)) :after-block-end))
+ ;; The return keyword do make indentation lose a level...
(should (= (python-indent-calculate-indentation) 0))
- (python-tests-look-at "# but we won't mess")
- (should (eq (car (python-indent-context)) 'after-comment))
+ ;; ...but the current indentation was forced by the user.
+ (python-tests-look-at "# At this line python.el wont dedent")
+ (should (eq (car (python-indent-context)) :after-comment))
(should (= (python-indent-calculate-indentation) 4))
- ;; Behave the same for blank lines: potentially a comment.
+ ;; Should behave the same for blank lines: potentially a comment.
(forward-line 1)
- (should (eq (car (python-indent-context)) 'after-comment))
+ (should (eq (car (python-indent-context)) :after-comment))
(should (= (python-indent-calculate-indentation) 4))
- (python-tests-look-at "now_we_do_mess")
- ;; Here is where comment indentation starts to get ignored and
- ;; where the user can't freely indent anymore.
- (should (eq (car (python-indent-context)) 'after-line))
- (should (= (python-indent-calculate-indentation) 0))
+ (python-tests-look-at "comment_wins_over_ender")
+ ;; The comment won over the ender because the user said so.
+ (should (eq (car (python-indent-context)) :after-comment))
+ (should (= (python-indent-calculate-indentation) 4))
+ ;; The indentation calculated fine for the assignment, but the user
+ ;; choose to force it back to the first column. Next line should
+ ;; be aware of that.
(python-tests-look-at "# yeah, that.")
- (should (eq (car (python-indent-context)) 'after-line))
+ (should (eq (car (python-indent-context)) :after-line))
(should (= (python-indent-calculate-indentation) 0))))
+(ert-deftest python-indent-after-comment-3 ()
+ "Test after-comment in buggy case."
+ (python-tests-with-temp-buffer
+ "
+class A(object):
+
+ def something(self, arg):
+ if True:
+ return arg
+
+ # A comment
+
+ @adecorator
+ def method(self, a, b):
+ pass
+"
+ (python-tests-look-at "@adecorator")
+ (should (eq (car (python-indent-context)) :after-comment))
+ (should (= (python-indent-calculate-indentation) 4))))
+
(ert-deftest python-indent-inside-paren-1 ()
"The most simple inside-paren case that shouldn't fail."
(python-tests-with-temp-buffer
}
"
(python-tests-look-at "data = {")
- (should (eq (car (python-indent-context)) 'after-line))
+ (should (eq (car (python-indent-context)) :no-indent))
(should (= (python-indent-calculate-indentation) 0))
(python-tests-look-at "'key':")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 4))
(python-tests-look-at "{")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 4))
(python-tests-look-at "'objlist': [")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 8))
(python-tests-look-at "{")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 12))
(python-tests-look-at "'pk': 1,")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 16))
(python-tests-look-at "'name': 'first',")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 16))
(python-tests-look-at "},")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context))
+ :inside-paren-at-closing-nested-paren))
(should (= (python-indent-calculate-indentation) 12))
(python-tests-look-at "{")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 12))
(python-tests-look-at "'pk': 2,")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 16))
(python-tests-look-at "'name': 'second',")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 16))
(python-tests-look-at "}")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context))
+ :inside-paren-at-closing-nested-paren))
(should (= (python-indent-calculate-indentation) 12))
(python-tests-look-at "]")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context))
+ :inside-paren-at-closing-nested-paren))
(should (= (python-indent-calculate-indentation) 8))
(python-tests-look-at "}")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context))
+ :inside-paren-at-closing-nested-paren))
(should (= (python-indent-calculate-indentation) 4))
(python-tests-look-at "}")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-at-closing-paren))
(should (= (python-indent-calculate-indentation) 0))))
(ert-deftest python-indent-inside-paren-2 ()
}}
"
(python-tests-look-at "data = {")
- (should (eq (car (python-indent-context)) 'after-line))
+ (should (eq (car (python-indent-context)) :no-indent))
(should (= (python-indent-calculate-indentation) 0))
(python-tests-look-at "'objlist': [")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 4))
(python-tests-look-at "{'pk': 1,")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 8))
(python-tests-look-at "'name': 'first'},")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren))
(should (= (python-indent-calculate-indentation) 9))
(python-tests-look-at "{'pk': 2,")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 8))
(python-tests-look-at "'name': 'second'}")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren))
(should (= (python-indent-calculate-indentation) 9))
(python-tests-look-at "]")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context))
+ :inside-paren-at-closing-nested-paren))
(should (= (python-indent-calculate-indentation) 4))
(python-tests-look-at "}}")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context))
+ :inside-paren-at-closing-nested-paren))
(should (= (python-indent-calculate-indentation) 0))
(python-tests-look-at "}")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-at-closing-paren))
(should (= (python-indent-calculate-indentation) 0))))
+(ert-deftest python-indent-inside-paren-3 ()
+ "The simplest case possible."
+ (python-tests-with-temp-buffer
+ "
+data = ('these',
+ 'are',
+ 'the',
+ 'tokens')
+"
+ (python-tests-look-at "data = ('these',")
+ (should (eq (car (python-indent-context)) :no-indent))
+ (should (= (python-indent-calculate-indentation) 0))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :inside-paren))
+ (should (= (python-indent-calculate-indentation) 8))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :inside-paren))
+ (should (= (python-indent-calculate-indentation) 8))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :inside-paren))
+ (should (= (python-indent-calculate-indentation) 8))))
+
+(ert-deftest python-indent-inside-paren-4 ()
+ "Respect indentation of first column."
+ (python-tests-with-temp-buffer
+ "
+data = [ [ 'these', 'are'],
+ ['the', 'tokens' ] ]
+"
+ (python-tests-look-at "data = [ [ 'these', 'are'],")
+ (should (eq (car (python-indent-context)) :no-indent))
+ (should (= (python-indent-calculate-indentation) 0))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :inside-paren))
+ (should (= (python-indent-calculate-indentation) 9))))
+
+(ert-deftest python-indent-inside-paren-5 ()
+ "Test when :inside-paren initial parens are skipped in context start."
+ (python-tests-with-temp-buffer
+ "
+while ((not some_condition) and
+ another_condition):
+ do_something_interesting(
+ with_some_arg)
+"
+ (python-tests-look-at "while ((not some_condition) and")
+ (should (eq (car (python-indent-context)) :no-indent))
+ (should (= (python-indent-calculate-indentation) 0))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :inside-paren))
+ (should (= (python-indent-calculate-indentation) 7))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :after-block-start))
+ (should (= (python-indent-calculate-indentation) 4))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
+ (should (= (python-indent-calculate-indentation) 8))))
+
+(ert-deftest python-indent-inside-paren-6 ()
+ "This should be aligned.."
+ (python-tests-with-temp-buffer
+ "
+CHOICES = (('some', 'choice'),
+ ('another', 'choice'),
+ ('more', 'choices'))
+"
+ (python-tests-look-at "CHOICES = (('some', 'choice'),")
+ (should (eq (car (python-indent-context)) :no-indent))
+ (should (= (python-indent-calculate-indentation) 0))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :inside-paren))
+ (should (= (python-indent-calculate-indentation) 11))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :inside-paren))
+ (should (= (python-indent-calculate-indentation) 11))))
+
+(ert-deftest python-indent-inside-paren-7 ()
+ "Test for Bug#21762."
+ (python-tests-with-temp-buffer
+ "import re as myre\nvar = [\n"
+ (goto-char (point-max))
+ ;; This signals an error if the test fails
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))))
+
(ert-deftest python-indent-after-block-1 ()
"The most simple after-block case that shouldn't fail."
(python-tests-with-temp-buffer
"
def foo(a, b, c=True):
"
- (should (eq (car (python-indent-context)) 'no-indent))
+ (should (eq (car (python-indent-context)) :no-indent))
(should (= (python-indent-calculate-indentation) 0))
(goto-char (point-max))
- (should (eq (car (python-indent-context)) 'after-beginning-of-block))
+ (should (eq (car (python-indent-context)) :after-block-start))
(should (= (python-indent-calculate-indentation) 4))))
(ert-deftest python-indent-after-block-2 ()
}):
"
(goto-char (point-max))
- (should (eq (car (python-indent-context)) 'after-beginning-of-block))
+ (should (eq (car (python-indent-context)) :after-block-start))
(should (= (python-indent-calculate-indentation) 4))))
+(ert-deftest python-indent-after-block-3 ()
+ "A weird (malformed) sample, usually found in python shells."
+ (python-tests-with-temp-buffer
+ "
+In [1]:
+def func():
+pass
+
+In [2]:
+something
+"
+ (python-tests-look-at "pass")
+ (should (eq (car (python-indent-context)) :after-block-start))
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at "something")
+ (end-of-line)
+ (should (eq (car (python-indent-context)) :after-line))
+ (should (= (python-indent-calculate-indentation) 0))))
+
(ert-deftest python-indent-after-backslash-1 ()
"The most common case."
(python-tests-with-temp-buffer
something_4, something_5
"
(python-tests-look-at "from foo.bar.baz import something, something_1")
- (should (eq (car (python-indent-context)) 'after-line))
+ (should (eq (car (python-indent-context)) :no-indent))
(should (= (python-indent-calculate-indentation) 0))
(python-tests-look-at "something_2 something_3,")
- (should (eq (car (python-indent-context)) 'after-backslash))
+ (should (eq (car (python-indent-context)) :after-backslash-first-line))
(should (= (python-indent-calculate-indentation) 4))
(python-tests-look-at "something_4, something_5")
- (should (eq (car (python-indent-context)) 'after-backslash))
+ (should (eq (car (python-indent-context)) :after-backslash))
(should (= (python-indent-calculate-indentation) 4))
(goto-char (point-max))
- (should (eq (car (python-indent-context)) 'after-line))
+ (should (eq (car (python-indent-context)) :after-line))
(should (= (python-indent-calculate-indentation) 0))))
(ert-deftest python-indent-after-backslash-2 ()
.values_list()
"
(python-tests-look-at "objects = Thing.objects.all()")
- (should (eq (car (python-indent-context)) 'after-line))
+ (should (eq (car (python-indent-context)) :no-indent))
(should (= (python-indent-calculate-indentation) 0))
(python-tests-look-at ".filter(")
- (should (eq (car (python-indent-context)) 'after-backslash))
+ (should (eq (car (python-indent-context))
+ :after-backslash-dotted-continuation))
(should (= (python-indent-calculate-indentation) 23))
(python-tests-look-at "type='toy',")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 27))
(python-tests-look-at "status='bought'")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 27))
(python-tests-look-at ") \\\\")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-at-closing-paren))
(should (= (python-indent-calculate-indentation) 23))
(python-tests-look-at ".aggregate(")
- (should (eq (car (python-indent-context)) 'after-backslash))
+ (should (eq (car (python-indent-context))
+ :after-backslash-dotted-continuation))
(should (= (python-indent-calculate-indentation) 23))
(python-tests-look-at "Sum('amount')")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-newline-start))
(should (= (python-indent-calculate-indentation) 27))
(python-tests-look-at ") \\\\")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren-at-closing-paren))
(should (= (python-indent-calculate-indentation) 23))
(python-tests-look-at ".values_list()")
- (should (eq (car (python-indent-context)) 'after-backslash))
+ (should (eq (car (python-indent-context))
+ :after-backslash-dotted-continuation))
(should (= (python-indent-calculate-indentation) 23))
(forward-line 1)
- (should (eq (car (python-indent-context)) 'after-line))
+ (should (eq (car (python-indent-context)) :after-line))
(should (= (python-indent-calculate-indentation) 0))))
+(ert-deftest python-indent-after-backslash-3 ()
+ "Backslash continuation from block start."
+ (python-tests-with-temp-buffer
+ "
+with open('/path/to/some/file/you/want/to/read') as file_1, \\\\
+ open('/path/to/some/file/being/written', 'w') as file_2:
+ file_2.write(file_1.read())
+"
+ (python-tests-look-at
+ "with open('/path/to/some/file/you/want/to/read') as file_1, \\\\")
+ (should (eq (car (python-indent-context)) :no-indent))
+ (should (= (python-indent-calculate-indentation) 0))
+ (python-tests-look-at
+ "open('/path/to/some/file/being/written', 'w') as file_2")
+ (should (eq (car (python-indent-context))
+ :after-backslash-block-continuation))
+ (should (= (python-indent-calculate-indentation) 5))
+ (python-tests-look-at "file_2.write(file_1.read())")
+ (should (eq (car (python-indent-context)) :after-block-start))
+ (should (= (python-indent-calculate-indentation) 4))))
+
+(ert-deftest python-indent-after-backslash-4 ()
+ "Backslash continuation from assignment."
+ (python-tests-with-temp-buffer
+ "
+super_awful_assignment = some_calculation() and \\\\
+ another_calculation() and \\\\
+ some_final_calculation()
+"
+ (python-tests-look-at
+ "super_awful_assignment = some_calculation() and \\\\")
+ (should (eq (car (python-indent-context)) :no-indent))
+ (should (= (python-indent-calculate-indentation) 0))
+ (python-tests-look-at "another_calculation() and \\\\")
+ (should (eq (car (python-indent-context))
+ :after-backslash-assignment-continuation))
+ (should (= (python-indent-calculate-indentation) 25))
+ (python-tests-look-at "some_final_calculation()")
+ (should (eq (car (python-indent-context)) :after-backslash))
+ (should (= (python-indent-calculate-indentation) 25))))
+
+(ert-deftest python-indent-after-backslash-5 ()
+ "Dotted continuation bizarre example."
+ (python-tests-with-temp-buffer
+ "
+def delete_all_things():
+ Thing \\\\
+ .objects.all() \\\\
+ .delete()
+"
+ (python-tests-look-at "Thing \\\\")
+ (should (eq (car (python-indent-context)) :after-block-start))
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at ".objects.all() \\\\")
+ (should (eq (car (python-indent-context)) :after-backslash-first-line))
+ (should (= (python-indent-calculate-indentation) 8))
+ (python-tests-look-at ".delete()")
+ (should (eq (car (python-indent-context))
+ :after-backslash-dotted-continuation))
+ (should (= (python-indent-calculate-indentation) 16))))
+
(ert-deftest python-indent-block-enders-1 ()
"Test de-indentation for pass keyword."
(python-tests-with-temp-buffer
- "
+ "
Class foo(object):
def bar(self):
else:
pass
"
- (python-tests-look-at "3)")
- (forward-line 1)
- (should (= (python-indent-calculate-indentation) 8))
- (python-tests-look-at "pass")
- (forward-line 1)
- (should (= (python-indent-calculate-indentation) 8))))
+ (python-tests-look-at "3)")
+ (forward-line 1)
+ (should (= (python-indent-calculate-indentation) 8))
+ (python-tests-look-at "pass")
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :after-block-end))
+ (should (= (python-indent-calculate-indentation) 8))))
(ert-deftest python-indent-block-enders-2 ()
"Test de-indentation for return keyword."
(python-tests-with-temp-buffer
- "
+ "
Class foo(object):
'''raise lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
2,
3)
"
- (python-tests-look-at "def")
- (should (= (python-indent-calculate-indentation) 4))
- (python-tests-look-at "if")
- (should (= (python-indent-calculate-indentation) 8))
- (python-tests-look-at "return")
- (should (= (python-indent-calculate-indentation) 12))
- (goto-char (point-max))
- (should (= (python-indent-calculate-indentation) 8))))
+ (python-tests-look-at "def")
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at "if")
+ (should (= (python-indent-calculate-indentation) 8))
+ (python-tests-look-at "return")
+ (should (= (python-indent-calculate-indentation) 12))
+ (goto-char (point-max))
+ (should (eq (car (python-indent-context)) :after-block-end))
+ (should (= (python-indent-calculate-indentation) 8))))
(ert-deftest python-indent-block-enders-3 ()
"Test de-indentation for continue keyword."
(python-tests-with-temp-buffer
- "
+ "
for element in lst:
if element is None:
continue
"
- (python-tests-look-at "if")
- (should (= (python-indent-calculate-indentation) 4))
- (python-tests-look-at "continue")
- (should (= (python-indent-calculate-indentation) 8))
- (forward-line 1)
- (should (= (python-indent-calculate-indentation) 4))))
+ (python-tests-look-at "if")
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at "continue")
+ (should (= (python-indent-calculate-indentation) 8))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :after-block-end))
+ (should (= (python-indent-calculate-indentation) 4))))
(ert-deftest python-indent-block-enders-4 ()
"Test de-indentation for break keyword."
(python-tests-with-temp-buffer
- "
+ "
for element in lst:
if element is None:
break
"
- (python-tests-look-at "if")
- (should (= (python-indent-calculate-indentation) 4))
- (python-tests-look-at "break")
- (should (= (python-indent-calculate-indentation) 8))
- (forward-line 1)
- (should (= (python-indent-calculate-indentation) 4))))
+ (python-tests-look-at "if")
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at "break")
+ (should (= (python-indent-calculate-indentation) 8))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :after-block-end))
+ (should (= (python-indent-calculate-indentation) 4))))
(ert-deftest python-indent-block-enders-5 ()
"Test de-indentation for raise keyword."
(python-tests-with-temp-buffer
- "
+ "
for element in lst:
if element is None:
raise ValueError('Element cannot be None')
"
- (python-tests-look-at "if")
- (should (= (python-indent-calculate-indentation) 4))
- (python-tests-look-at "raise")
- (should (= (python-indent-calculate-indentation) 8))
- (forward-line 1)
- (should (= (python-indent-calculate-indentation) 4))))
+ (python-tests-look-at "if")
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at "raise")
+ (should (= (python-indent-calculate-indentation) 8))
+ (forward-line 1)
+ (should (eq (car (python-indent-context)) :after-block-end))
+ (should (= (python-indent-calculate-indentation) 4))))
(ert-deftest python-indent-dedenters-1 ()
"Test de-indentation for the elif keyword."
(python-tests-with-temp-buffer
- "
+ "
if save:
try:
write_to_disk(data)
cleanup()
elif
"
- (python-tests-look-at "elif\n")
- (should (eq (car (python-indent-context)) 'dedenter-statement))
- (should (= (python-indent-calculate-indentation) 0))
- (should (equal (python-indent-calculate-levels) '(0)))))
+ (python-tests-look-at "elif\n")
+ (should (eq (car (python-indent-context)) :at-dedenter-block-start))
+ (should (= (python-indent-calculate-indentation) 0))
+ (should (= (python-indent-calculate-indentation t) 0))))
(ert-deftest python-indent-dedenters-2 ()
"Test de-indentation for the else keyword."
(python-tests-with-temp-buffer
- "
+ "
if save:
try:
write_to_disk(data)
finally:
data.free()
"
- (python-tests-look-at "else\n")
- (should (eq (car (python-indent-context)) 'dedenter-statement))
- (should (= (python-indent-calculate-indentation) 8))
- (should (equal (python-indent-calculate-levels) '(0 4 8)))))
+ (python-tests-look-at "else\n")
+ (should (eq (car (python-indent-context)) :at-dedenter-block-start))
+ (should (= (python-indent-calculate-indentation) 8))
+ (python-indent-line t)
+ (should (= (python-indent-calculate-indentation t) 4))
+ (python-indent-line t)
+ (should (= (python-indent-calculate-indentation t) 0))
+ (python-indent-line t)
+ (should (= (python-indent-calculate-indentation t) 8))))
(ert-deftest python-indent-dedenters-3 ()
"Test de-indentation for the except keyword."
(python-tests-with-temp-buffer
- "
+ "
if save:
try:
write_to_disk(data)
except
"
- (python-tests-look-at "except\n")
- (should (eq (car (python-indent-context)) 'dedenter-statement))
- (should (= (python-indent-calculate-indentation) 4))
- (should (equal (python-indent-calculate-levels) '(4)))))
+ (python-tests-look-at "except\n")
+ (should (eq (car (python-indent-context)) :at-dedenter-block-start))
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-indent-line t)
+ (should (= (python-indent-calculate-indentation t) 4))))
(ert-deftest python-indent-dedenters-4 ()
"Test de-indentation for the finally keyword."
(python-tests-with-temp-buffer
- "
+ "
if save:
try:
write_to_disk(data)
finally
"
- (python-tests-look-at "finally\n")
- (should (eq (car (python-indent-context)) 'dedenter-statement))
- (should (= (python-indent-calculate-indentation) 4))
- (should (equal (python-indent-calculate-levels) '(4)))))
+ (python-tests-look-at "finally\n")
+ (should (eq (car (python-indent-context)) :at-dedenter-block-start))
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-indent-line t)
+ (should (= (python-indent-calculate-indentation) 4))))
(ert-deftest python-indent-dedenters-5 ()
"Test invalid levels are skipped in a complex example."
(python-tests-with-temp-buffer
- "
+ "
if save:
try:
write_to_disk(data)
do_cleanup()
else
"
- (python-tests-look-at "else\n")
- (should (eq (car (python-indent-context)) 'dedenter-statement))
- (should (= (python-indent-calculate-indentation) 8))
- (should (equal (python-indent-calculate-levels) '(0 8)))))
+ (python-tests-look-at "else\n")
+ (should (eq (car (python-indent-context)) :at-dedenter-block-start))
+ (should (= (python-indent-calculate-indentation) 8))
+ (should (= (python-indent-calculate-indentation t) 0))
+ (python-indent-line t)
+ (should (= (python-indent-calculate-indentation t) 8))))
(ert-deftest python-indent-dedenters-6 ()
"Test indentation is zero when no opening block for dedenter."
(python-tests-with-temp-buffer
- "
+ "
try:
# if save:
write_to_disk(data)
else
"
- (python-tests-look-at "else\n")
- (should (eq (car (python-indent-context)) 'dedenter-statement))
- (should (= (python-indent-calculate-indentation) 0))
- (should (equal (python-indent-calculate-levels) '(0)))))
+ (python-tests-look-at "else\n")
+ (should (eq (car (python-indent-context)) :at-dedenter-block-start))
+ (should (= (python-indent-calculate-indentation) 0))
+ (should (= (python-indent-calculate-indentation t) 0))))
(ert-deftest python-indent-dedenters-7 ()
"Test indentation case from Bug#15163."
(python-tests-with-temp-buffer
- "
+ "
if a:
if b:
pass
pass
else:
"
- (python-tests-look-at "else:" 2)
- (should (eq (car (python-indent-context)) 'dedenter-statement))
- (should (= (python-indent-calculate-indentation) 0))
- (should (equal (python-indent-calculate-levels) '(0)))))
+ (python-tests-look-at "else:" 2)
+ (should (eq (car (python-indent-context)) :at-dedenter-block-start))
+ (should (= (python-indent-calculate-indentation) 0))
+ (should (= (python-indent-calculate-indentation t) 0))))
(ert-deftest python-indent-dedenters-8 ()
"Test indentation for Bug#18432."
elif (a == 3 or
a == 4):
"
+ (python-tests-look-at "elif (a == 3 or")
+ (should (eq (car (python-indent-context)) :at-dedenter-block-start))
+ (should (= (python-indent-calculate-indentation) 0))
+ (should (= (python-indent-calculate-indentation t) 0))
(python-tests-look-at "a == 4):\n")
- (should (eq (car (python-indent-context)) 'inside-paren))
+ (should (eq (car (python-indent-context)) :inside-paren))
(should (= (python-indent-calculate-indentation) 6))
- (should (equal (python-indent-calculate-levels) '(0 4 6)))))
+ (python-indent-line)
+ (should (= (python-indent-calculate-indentation t) 4))
+ (python-indent-line t)
+ (should (= (python-indent-calculate-indentation t) 0))
+ (python-indent-line t)
+ (should (= (python-indent-calculate-indentation t) 6))))
+
+(ert-deftest python-indent-inside-string-1 ()
+ "Test indentation for strings."
+ (python-tests-with-temp-buffer
+ "
+multiline = '''
+bunch
+of
+lines
+'''
+"
+ (python-tests-look-at "multiline = '''")
+ (should (eq (car (python-indent-context)) :no-indent))
+ (should (= (python-indent-calculate-indentation) 0))
+ (python-tests-look-at "bunch")
+ (should (eq (car (python-indent-context)) :inside-string))
+ (should (= (python-indent-calculate-indentation) 0))
+ (python-tests-look-at "of")
+ (should (eq (car (python-indent-context)) :inside-string))
+ (should (= (python-indent-calculate-indentation) 0))
+ (python-tests-look-at "lines")
+ (should (eq (car (python-indent-context)) :inside-string))
+ (should (= (python-indent-calculate-indentation) 0))
+ (python-tests-look-at "'''")
+ (should (eq (car (python-indent-context)) :inside-string))
+ (should (= (python-indent-calculate-indentation) 0))))
+
+(ert-deftest python-indent-inside-string-2 ()
+ "Test indentation for docstrings."
+ (python-tests-with-temp-buffer
+ "
+def fn(a, b, c=True):
+ '''docstring
+ bunch
+ of
+ lines
+ '''
+"
+ (python-tests-look-at "'''docstring")
+ (should (eq (car (python-indent-context)) :after-block-start))
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at "bunch")
+ (should (eq (car (python-indent-context)) :inside-docstring))
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at "of")
+ (should (eq (car (python-indent-context)) :inside-docstring))
+ ;; Any indentation deeper than the base-indent must remain unmodified.
+ (should (= (python-indent-calculate-indentation) 8))
+ (python-tests-look-at "lines")
+ (should (eq (car (python-indent-context)) :inside-docstring))
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at "'''")
+ (should (eq (car (python-indent-context)) :inside-docstring))
+ (should (= (python-indent-calculate-indentation) 4))))
+
+(ert-deftest python-indent-inside-string-3 ()
+ "Test indentation for nested strings."
+ (python-tests-with-temp-buffer
+ "
+def fn(a, b, c=True):
+ some_var = '''
+ bunch
+ of
+ lines
+ '''
+"
+ (python-tests-look-at "some_var = '''")
+ (should (eq (car (python-indent-context)) :after-block-start))
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at "bunch")
+ (should (eq (car (python-indent-context)) :inside-string))
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at "of")
+ (should (eq (car (python-indent-context)) :inside-string))
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at "lines")
+ (should (eq (car (python-indent-context)) :inside-string))
+ (should (= (python-indent-calculate-indentation) 4))
+ (python-tests-look-at "'''")
+ (should (eq (car (python-indent-context)) :inside-string))
+ (should (= (python-indent-calculate-indentation) 4))))
(ert-deftest python-indent-electric-colon-1 ()
"Test indentation case from Bug#18228."
expected)))))
(ert-deftest python-indent-region-5 ()
- "Test region indentation leaves strings untouched (start delimiter)."
+ "Test region indentation for docstrings."
(let ((contents "
def f():
'''
this is
-a multiline
+ a multiline
string
+'''
+ x = \\
+ '''
+this is an arbitrarily
+ indented multiline
+ string
'''
")
(expected "
def f():
'''
-this is
-a multiline
-string
+ this is
+ a multiline
+ string
+ '''
+ x = \\
+ '''
+this is an arbitrarily
+ indented multiline
+ string
'''
"))
(python-tests-with-temp-buffer
(should (string= (buffer-substring-no-properties (point-min) (point-max))
expected)))))
+\f
+;;; Mark
+
+(ert-deftest python-mark-defun-1 ()
+ """Test `python-mark-defun' with point at defun symbol start."""
+ (python-tests-with-temp-buffer
+ "
+def foo(x):
+ return x
+
+class A:
+ pass
+
+class B:
+
+ def __init__(self):
+ self.b = 'b'
+
+ def fun(self):
+ return self.b
+
+class C:
+ '''docstring'''
+"
+ (let ((expected-mark-beginning-position
+ (progn
+ (python-tests-look-at "class A:")
+ (1- (point))))
+ (expected-mark-end-position-1
+ (save-excursion
+ (python-tests-look-at "pass")
+ (forward-line)
+ (point)))
+ (expected-mark-end-position-2
+ (save-excursion
+ (python-tests-look-at "return self.b")
+ (forward-line)
+ (point)))
+ (expected-mark-end-position-3
+ (save-excursion
+ (python-tests-look-at "'''docstring'''")
+ (forward-line)
+ (point))))
+ ;; Select class A only, with point at bol.
+ (python-mark-defun 1)
+ (should (= (point) expected-mark-beginning-position))
+ (should (= (marker-position (mark-marker))
+ expected-mark-end-position-1))
+ ;; expand to class B, start position should remain the same.
+ (python-mark-defun 1)
+ (should (= (point) expected-mark-beginning-position))
+ (should (= (marker-position (mark-marker))
+ expected-mark-end-position-2))
+ ;; expand to class C, start position should remain the same.
+ (python-mark-defun 1)
+ (should (= (point) expected-mark-beginning-position))
+ (should (= (marker-position (mark-marker))
+ expected-mark-end-position-3)))))
+
+(ert-deftest python-mark-defun-2 ()
+ """Test `python-mark-defun' with point at nested defun symbol start."""
+ (python-tests-with-temp-buffer
+ "
+def foo(x):
+ return x
+
+class A:
+ pass
+
+class B:
+
+ def __init__(self):
+ self.b = 'b'
+
+ def fun(self):
+ return self.b
+
+class C:
+ '''docstring'''
+"
+ (let ((expected-mark-beginning-position
+ (progn
+ (python-tests-look-at "def __init__(self):")
+ (1- (line-beginning-position))))
+ (expected-mark-end-position-1
+ (save-excursion
+ (python-tests-look-at "self.b = 'b'")
+ (forward-line)
+ (point)))
+ (expected-mark-end-position-2
+ (save-excursion
+ (python-tests-look-at "return self.b")
+ (forward-line)
+ (point)))
+ (expected-mark-end-position-3
+ (save-excursion
+ (python-tests-look-at "'''docstring'''")
+ (forward-line)
+ (point))))
+ ;; Select B.__init only, with point at its start.
+ (python-mark-defun 1)
+ (should (= (point) expected-mark-beginning-position))
+ (should (= (marker-position (mark-marker))
+ expected-mark-end-position-1))
+ ;; expand to B.fun, start position should remain the same.
+ (python-mark-defun 1)
+ (should (= (point) expected-mark-beginning-position))
+ (should (= (marker-position (mark-marker))
+ expected-mark-end-position-2))
+ ;; expand to class C, start position should remain the same.
+ (python-mark-defun 1)
+ (should (= (point) expected-mark-beginning-position))
+ (should (= (marker-position (mark-marker))
+ expected-mark-end-position-3)))))
+
+(ert-deftest python-mark-defun-3 ()
+ """Test `python-mark-defun' with point inside defun symbol."""
+ (python-tests-with-temp-buffer
+ "
+def foo(x):
+ return x
+
+class A:
+ pass
+
+class B:
+
+ def __init__(self):
+ self.b = 'b'
+
+ def fun(self):
+ return self.b
+
+class C:
+ '''docstring'''
+"
+ (let ((expected-mark-beginning-position
+ (progn
+ (python-tests-look-at "def fun(self):")
+ (python-tests-look-at "(self):")
+ (1- (line-beginning-position))))
+ (expected-mark-end-position
+ (save-excursion
+ (python-tests-look-at "return self.b")
+ (forward-line)
+ (point))))
+ ;; Should select B.fun, despite point is inside the defun symbol.
+ (python-mark-defun 1)
+ (should (= (point) expected-mark-beginning-position))
+ (should (= (marker-position (mark-marker))
+ expected-mark-end-position)))))
+
\f
;;; Navigation
(should (save-excursion
(beginning-of-line)
(looking-at "c()")))
- ;; Movement next to a paren should do what lisp does and
- ;; unfortunately It can't change, because otherwise
- ;; `blink-matching-open' breaks.
+ ;; The default behavior when next to a paren should do what lisp
+ ;; does and, otherwise `blink-matching-open' breaks.
(python-nav-forward-sexp -1)
(should (looking-at "()"))
(should (save-excursion
(beginning-of-line)
(looking-at "c()")))
- (python-nav-forward-sexp -1)
+ (end-of-line)
+ ;; Skipping parens should jump to `bolp'
+ (python-nav-forward-sexp -1 nil t)
(should (looking-at "c()"))
+ (forward-line -1)
+ (end-of-line)
+ ;; b()
+ (python-nav-forward-sexp -1)
+ (should (looking-at "()"))
(python-nav-forward-sexp -1)
(should (looking-at "b()"))
+ (end-of-line)
+ (python-nav-forward-sexp -1 nil t)
+ (should (looking-at "b()"))
+ (forward-line -1)
+ (end-of-line)
+ ;; a()
+ (python-nav-forward-sexp -1)
+ (should (looking-at "()"))
(python-nav-forward-sexp -1)
+ (should (looking-at "a()"))
+ (end-of-line)
+ (python-nav-forward-sexp -1 nil t)
(should (looking-at "a()"))))
(ert-deftest python-nav-forward-sexp-2 ()
(python-nav-backward-up-list)
(should (looking-at "def f():"))))
+(ert-deftest python-indent-dedent-line-backspace-1 ()
+ "Check de-indentation on first call. Bug#18319."
+ (python-tests-with-temp-buffer
+ "
+if True:
+ x ()
+ if False:
+"
+ (python-tests-look-at "if False:")
+ (call-interactively #'python-indent-dedent-line-backspace)
+ (should (zerop (current-indentation)))
+ ;; XXX: This should be a call to `undo' but it's triggering errors.
+ (insert " ")
+ (should (= (current-indentation) 4))
+ (call-interactively #'python-indent-dedent-line-backspace)
+ (should (zerop (current-indentation)))))
+
+(ert-deftest python-indent-dedent-line-backspace-2 ()
+ "Check de-indentation with tabs. Bug#19730."
+ (let ((tab-width 8))
+ (python-tests-with-temp-buffer
+ "
+if x:
+\tabcdefg
+"
+ (python-tests-look-at "abcdefg")
+ (goto-char (line-end-position))
+ (call-interactively #'python-indent-dedent-line-backspace)
+ (should
+ (string= (buffer-substring-no-properties
+ (line-beginning-position) (line-end-position))
+ "\tabcdef")))))
+
+(ert-deftest python-indent-dedent-line-backspace-3 ()
+ "Paranoid check of de-indentation with tabs. Bug#19730."
+ (let ((tab-width 8))
+ (python-tests-with-temp-buffer
+ "
+if x:
+\tif y:
+\t abcdefg
+"
+ (python-tests-look-at "abcdefg")
+ (goto-char (line-end-position))
+ (call-interactively #'python-indent-dedent-line-backspace)
+ (should
+ (string= (buffer-substring-no-properties
+ (line-beginning-position) (line-end-position))
+ "\t abcdef"))
+ (back-to-indentation)
+ (call-interactively #'python-indent-dedent-line-backspace)
+ (should
+ (string= (buffer-substring-no-properties
+ (line-beginning-position) (line-end-position))
+ "\tabcdef"))
+ (call-interactively #'python-indent-dedent-line-backspace)
+ (should
+ (string= (buffer-substring-no-properties
+ (line-beginning-position) (line-end-position))
+ " abcdef"))
+ (call-interactively #'python-indent-dedent-line-backspace)
+ (should
+ (string= (buffer-substring-no-properties
+ (line-beginning-position) (line-end-position))
+ "abcdef")))))
+
\f
;;; Shell integration
(python-shell-interpreter-args "-B"))
(should (string=
(format "%s %s"
- python-shell-interpreter
+ (shell-quote-argument python-shell-interpreter)
python-shell-interpreter-args)
(python-shell-calculate-command)))))
+(ert-deftest python-shell-calculate-pythonpath-1 ()
+ "Test PYTHONPATH calculation."
+ (let ((process-environment '("PYTHONPATH=/path0"))
+ (python-shell-extra-pythonpaths '("/path1" "/path2")))
+ (should (string= (python-shell-calculate-pythonpath)
+ (concat "/path1" path-separator
+ "/path2" path-separator "/path0")))))
+
+(ert-deftest python-shell-calculate-pythonpath-2 ()
+ "Test existing paths are moved to front."
+ (let ((process-environment
+ (list (concat "PYTHONPATH=/path0" path-separator "/path1")))
+ (python-shell-extra-pythonpaths '("/path1" "/path2")))
+ (should (string= (python-shell-calculate-pythonpath)
+ (concat "/path1" path-separator
+ "/path2" path-separator "/path0")))))
+
(ert-deftest python-shell-calculate-process-environment-1 ()
"Test `python-shell-process-environment' modification."
(let* ((python-shell-process-environment
'("TESTVAR1=value1" "TESTVAR2=value2"))
- (process-environment
- (python-shell-calculate-process-environment)))
+ (process-environment (python-shell-calculate-process-environment)))
(should (equal (getenv "TESTVAR1") "value1"))
(should (equal (getenv "TESTVAR2") "value2"))))
(ert-deftest python-shell-calculate-process-environment-2 ()
"Test `python-shell-extra-pythonpaths' modification."
(let* ((process-environment process-environment)
- (original-pythonpath (setenv "PYTHONPATH" "path3"))
- (paths '("path1" "path2"))
- (python-shell-extra-pythonpaths paths)
- (process-environment
- (python-shell-calculate-process-environment)))
+ (original-pythonpath (setenv "PYTHONPATH" "/path0"))
+ (python-shell-extra-pythonpaths '("/path1" "/path2"))
+ (process-environment (python-shell-calculate-process-environment)))
(should (equal (getenv "PYTHONPATH")
- (concat
- (mapconcat 'identity paths path-separator)
- path-separator original-pythonpath)))))
+ (concat "/path1" path-separator
+ "/path2" path-separator "/path0")))))
(ert-deftest python-shell-calculate-process-environment-3 ()
"Test `python-shell-virtualenv-root' modification."
- (let* ((original-path (or (getenv "PATH") ""))
- (python-shell-virtualenv-root
- (directory-file-name user-emacs-directory))
+ (let* ((python-shell-virtualenv-root "/env")
(process-environment
- (python-shell-calculate-process-environment)))
+ (let (process-environment process-environment)
+ (setenv "PYTHONHOME" "/home")
+ (setenv "VIRTUAL_ENV")
+ (python-shell-calculate-process-environment))))
(should (not (getenv "PYTHONHOME")))
- (should (string= (getenv "VIRTUAL_ENV") python-shell-virtualenv-root))
- (should (equal (getenv "PATH")
- (format "%s/bin%s%s"
- python-shell-virtualenv-root
- path-separator original-path)))))
+ (should (string= (getenv "VIRTUAL_ENV") "/env"))))
(ert-deftest python-shell-calculate-process-environment-4 ()
- "Test `python-shell-unbuffered' modification."
- (setenv "PYTHONUNBUFFERED")
- (let* ((process-environment
- (python-shell-calculate-process-environment)))
- ;; Defaults to t
- (should python-shell-unbuffered)
+ "Test PYTHONUNBUFFERED when `python-shell-unbuffered' is non-nil."
+ (let* ((python-shell-unbuffered t)
+ (process-environment
+ (let ((process-environment process-environment))
+ (setenv "PYTHONUNBUFFERED")
+ (python-shell-calculate-process-environment))))
(should (string= (getenv "PYTHONUNBUFFERED") "1"))))
(ert-deftest python-shell-calculate-process-environment-5 ()
- (setenv "PYTHONUNBUFFERED")
- "Test `python-shell-unbuffered' modification."
+ "Test PYTHONUNBUFFERED when `python-shell-unbuffered' is nil."
(let* ((python-shell-unbuffered nil)
(process-environment
- (python-shell-calculate-process-environment)))
+ (let ((process-environment process-environment))
+ (setenv "PYTHONUNBUFFERED")
+ (python-shell-calculate-process-environment))))
(should (not (getenv "PYTHONUNBUFFERED")))))
+(ert-deftest python-shell-calculate-process-environment-6 ()
+ "Test PYTHONUNBUFFERED=1 when `python-shell-unbuffered' is nil."
+ (let* ((python-shell-unbuffered nil)
+ (process-environment
+ (let ((process-environment process-environment))
+ (setenv "PYTHONUNBUFFERED" "1")
+ (python-shell-calculate-process-environment))))
+ ;; User default settings must remain untouched:
+ (should (string= (getenv "PYTHONUNBUFFERED") "1"))))
+
+(ert-deftest python-shell-calculate-process-environment-7 ()
+ "Test no side-effects on `process-environment'."
+ (let* ((python-shell-process-environment
+ '("TESTVAR1=value1" "TESTVAR2=value2"))
+ (python-shell-virtualenv-root "/env")
+ (python-shell-unbuffered t)
+ (python-shell-extra-pythonpaths'("/path1" "/path2"))
+ (original-process-environment (copy-sequence process-environment)))
+ (python-shell-calculate-process-environment)
+ (should (equal process-environment original-process-environment))))
+
+(ert-deftest python-shell-calculate-process-environment-8 ()
+ "Test no side-effects on `tramp-remote-process-environment'."
+ (let* ((default-directory "/ssh::/example/dir/")
+ (python-shell-process-environment
+ '("TESTVAR1=value1" "TESTVAR2=value2"))
+ (python-shell-virtualenv-root "/env")
+ (python-shell-unbuffered t)
+ (python-shell-extra-pythonpaths'("/path1" "/path2"))
+ (original-process-environment
+ (copy-sequence tramp-remote-process-environment)))
+ (python-shell-calculate-process-environment)
+ (should (equal tramp-remote-process-environment original-process-environment))))
+
(ert-deftest python-shell-calculate-exec-path-1 ()
"Test `python-shell-exec-path' modification."
- (let* ((original-exec-path exec-path)
- (python-shell-exec-path '("path1" "path2"))
- (exec-path (python-shell-calculate-exec-path)))
- (should (equal
- exec-path
- (append python-shell-exec-path
- original-exec-path)))))
+ (let* ((exec-path '("/path0"))
+ (python-shell-exec-path '("/path1" "/path2"))
+ (new-exec-path (python-shell-calculate-exec-path)))
+ (should (equal new-exec-path '("/path1" "/path2" "/path0")))))
(ert-deftest python-shell-calculate-exec-path-2 ()
- "Test `python-shell-exec-path' modification."
- (let* ((original-exec-path exec-path)
- (python-shell-virtualenv-root
- (directory-file-name (expand-file-name user-emacs-directory)))
- (exec-path (python-shell-calculate-exec-path)))
- (should (equal
- exec-path
- (append (cons
- (format "%s/bin" python-shell-virtualenv-root)
- original-exec-path))))))
+ "Test `python-shell-virtualenv-root' modification."
+ (let* ((exec-path '("/path0"))
+ (python-shell-virtualenv-root "/env")
+ (new-exec-path (python-shell-calculate-exec-path)))
+ (should (equal new-exec-path
+ (list (expand-file-name "/env/bin") "/path0")))))
+
+(ert-deftest python-shell-calculate-exec-path-3 ()
+ "Test complete `python-shell-virtualenv-root' modification."
+ (let* ((exec-path '("/path0"))
+ (python-shell-exec-path '("/path1" "/path2"))
+ (python-shell-virtualenv-root "/env")
+ (new-exec-path (python-shell-calculate-exec-path)))
+ (should (equal new-exec-path
+ (list (expand-file-name "/env/bin")
+ "/path1" "/path2" "/path0")))))
+
+(ert-deftest python-shell-calculate-exec-path-4 ()
+ "Test complete `python-shell-virtualenv-root' with remote."
+ (let* ((default-directory "/ssh::/example/dir/")
+ (python-shell-remote-exec-path '("/path0"))
+ (python-shell-exec-path '("/path1" "/path2"))
+ (python-shell-virtualenv-root "/env")
+ (new-exec-path (python-shell-calculate-exec-path)))
+ (should (equal new-exec-path
+ (list (expand-file-name "/env/bin")
+ "/path1" "/path2" "/path0")))))
+
+(ert-deftest python-shell-calculate-exec-path-5 ()
+ "Test no side-effects on `exec-path'."
+ (let* ((exec-path '("/path0"))
+ (python-shell-exec-path '("/path1" "/path2"))
+ (python-shell-virtualenv-root "/env")
+ (original-exec-path (copy-sequence exec-path)))
+ (python-shell-calculate-exec-path)
+ (should (equal exec-path original-exec-path))))
+
+(ert-deftest python-shell-calculate-exec-path-6 ()
+ "Test no side-effects on `python-shell-remote-exec-path'."
+ (let* ((default-directory "/ssh::/example/dir/")
+ (python-shell-remote-exec-path '("/path0"))
+ (python-shell-exec-path '("/path1" "/path2"))
+ (python-shell-virtualenv-root "/env")
+ (original-exec-path (copy-sequence python-shell-remote-exec-path)))
+ (python-shell-calculate-exec-path)
+ (should (equal python-shell-remote-exec-path original-exec-path))))
+
+(ert-deftest python-shell-with-environment-1 ()
+ "Test environment with local `default-directory'."
+ (let* ((exec-path '("/path0"))
+ (python-shell-exec-path '("/path1" "/path2"))
+ (original-exec-path exec-path)
+ (python-shell-virtualenv-root "/env"))
+ (python-shell-with-environment
+ (should (equal exec-path
+ (list (expand-file-name "/env/bin")
+ "/path1" "/path2" "/path0")))
+ (should (not (getenv "PYTHONHOME")))
+ (should (string= (getenv "VIRTUAL_ENV") "/env")))
+ (should (equal exec-path original-exec-path))))
+
+(ert-deftest python-shell-with-environment-2 ()
+ "Test environment with remote `default-directory'."
+ (let* ((default-directory "/ssh::/example/dir/")
+ (python-shell-remote-exec-path '("/remote1" "/remote2"))
+ (python-shell-exec-path '("/path1" "/path2"))
+ (tramp-remote-process-environment '("EMACS=t"))
+ (original-process-environment (copy-sequence tramp-remote-process-environment))
+ (python-shell-virtualenv-root "/env"))
+ (python-shell-with-environment
+ (should (equal (python-shell-calculate-exec-path)
+ (list (expand-file-name "/env/bin")
+ "/path1" "/path2" "/remote1" "/remote2")))
+ (let ((process-environment (python-shell-calculate-process-environment)))
+ (should (not (getenv "PYTHONHOME")))
+ (should (string= (getenv "VIRTUAL_ENV") "/env"))
+ (should (equal tramp-remote-process-environment process-environment))))
+ (should (equal tramp-remote-process-environment original-process-environment))))
+
+(ert-deftest python-shell-with-environment-3 ()
+ "Test `python-shell-with-environment' is idempotent."
+ (let* ((python-shell-extra-pythonpaths '("/example/dir/"))
+ (python-shell-exec-path '("path1" "path2"))
+ (python-shell-virtualenv-root "/home/user/env")
+ (single-call
+ (python-shell-with-environment
+ (list exec-path process-environment)))
+ (nested-call
+ (python-shell-with-environment
+ (python-shell-with-environment
+ (list exec-path process-environment)))))
+ (should (equal single-call nested-call))))
(ert-deftest python-shell-make-comint-1 ()
"Check comint creation for global shell buffer."
:type 'user-error)))
(should
(string= (cadr error-data)
- "Invalid regexp \\( in `python-shell-prompt-input-regexps'"))))
+ (format-message
+ "Invalid regexp \\( in `python-shell-prompt-input-regexps'")))))
(ert-deftest python-shell-prompt-validate-regexps-2 ()
"Check `python-shell-prompt-output-regexps' are validated."
:type 'user-error)))
(should
(string= (cadr error-data)
- "Invalid regexp \\( in `python-shell-prompt-output-regexps'"))))
+ (format-message
+ "Invalid regexp \\( in `python-shell-prompt-output-regexps'")))))
(ert-deftest python-shell-prompt-validate-regexps-3 ()
"Check `python-shell-prompt-regexp' is validated."
:type 'user-error)))
(should
(string= (cadr error-data)
- "Invalid regexp \\( in `python-shell-prompt-regexp'"))))
+ (format-message
+ "Invalid regexp \\( in `python-shell-prompt-regexp'")))))
(ert-deftest python-shell-prompt-validate-regexps-4 ()
"Check `python-shell-prompt-block-regexp' is validated."
:type 'user-error)))
(should
(string= (cadr error-data)
- "Invalid regexp \\( in `python-shell-prompt-block-regexp'"))))
+ (format-message
+ "Invalid regexp \\( in `python-shell-prompt-block-regexp'")))))
(ert-deftest python-shell-prompt-validate-regexps-5 ()
"Check `python-shell-prompt-pdb-regexp' is validated."
:type 'user-error)))
(should
(string= (cadr error-data)
- "Invalid regexp \\( in `python-shell-prompt-pdb-regexp'"))))
+ (format-message
+ "Invalid regexp \\( in `python-shell-prompt-pdb-regexp'")))))
(ert-deftest python-shell-prompt-validate-regexps-6 ()
"Check `python-shell-prompt-output-regexp' is validated."
:type 'user-error)))
(should
(string= (cadr error-data)
- "Invalid regexp \\( in `python-shell-prompt-output-regexp'"))))
+ (format-message
+ "Invalid regexp \\( in `python-shell-prompt-output-regexp'")))))
(ert-deftest python-shell-prompt-validate-regexps-7 ()
"Check default regexps are valid."
:type 'user-error)))
(should
(string= (cadr error-data)
- "Invalid regexp \\( in `python-shell-prompt-output-regexp'"))))
+ (format-message
+ "Invalid regexp \\( in `python-shell-prompt-output-regexp'")))))
(ert-deftest python-shell-prompt-set-calculated-regexps-2 ()
"Check `python-shell-prompt-input-regexps' are set."
"))))
+(ert-deftest python-shell-buffer-substring-10 ()
+ "Check substring from partial block."
+ (python-tests-with-temp-buffer
+ "
+def foo():
+ print ('a')
+"
+ (should (string= (python-shell-buffer-substring
+ (python-tests-look-at "print ('a')")
+ (point-max))
+ "if True:
+
+ print ('a')
+"))))
+
+(ert-deftest python-shell-buffer-substring-11 ()
+ "Check substring from partial block and point within indentation."
+ (python-tests-with-temp-buffer
+ "
+def foo():
+ print ('a')
+"
+ (should (string= (python-shell-buffer-substring
+ (progn
+ (python-tests-look-at "print ('a')")
+ (backward-char 1)
+ (point))
+ (point-max))
+ "if True:
+
+ print ('a')
+"))))
+
+(ert-deftest python-shell-buffer-substring-12 ()
+ "Check substring from partial block and point in whitespace."
+ (python-tests-with-temp-buffer
+ "
+def foo():
+
+ # Whitespace
+
+ print ('a')
+"
+ (should (string= (python-shell-buffer-substring
+ (python-tests-look-at "# Whitespace")
+ (point-max))
+ "if True:
+
+
+ # Whitespace
+
+ print ('a')
+"))))
+
+
\f
;;; Shell completion
\f
;;; Eldoc
+(ert-deftest python-eldoc--get-symbol-at-point-1 ()
+ "Test paren handling."
+ (python-tests-with-temp-buffer
+ "
+map(xx
+map(codecs.open('somefile'
+"
+ (python-tests-look-at "ap(xx")
+ (should (string= (python-eldoc--get-symbol-at-point) "map"))
+ (goto-char (line-end-position))
+ (should (string= (python-eldoc--get-symbol-at-point) "map"))
+ (python-tests-look-at "('somefile'")
+ (should (string= (python-eldoc--get-symbol-at-point) "map"))
+ (goto-char (line-end-position))
+ (should (string= (python-eldoc--get-symbol-at-point) "codecs.open"))))
+
+(ert-deftest python-eldoc--get-symbol-at-point-2 ()
+ "Ensure self is replaced with the class name."
+ (python-tests-with-temp-buffer
+ "
+class TheClass:
+
+ def some_method(self, n):
+ return n
+
+ def other(self):
+ return self.some_method(1234)
+
+"
+ (python-tests-look-at "self.some_method")
+ (should (string= (python-eldoc--get-symbol-at-point)
+ "TheClass.some_method"))
+ (python-tests-look-at "1234)")
+ (should (string= (python-eldoc--get-symbol-at-point)
+ "TheClass.some_method"))))
+
+(ert-deftest python-eldoc--get-symbol-at-point-3 ()
+ "Ensure symbol is found when point is at end of buffer."
+ (python-tests-with-temp-buffer
+ "
+some_symbol
+
+"
+ (goto-char (point-max))
+ (should (string= (python-eldoc--get-symbol-at-point)
+ "some_symbol"))))
+
+(ert-deftest python-eldoc--get-symbol-at-point-4 ()
+ "Ensure symbol is found when point is at whitespace."
+ (python-tests-with-temp-buffer
+ "
+some_symbol some_other_symbol
+"
+ (python-tests-look-at " some_other_symbol")
+ (should (string= (python-eldoc--get-symbol-at-point)
+ "some_symbol"))))
+
\f
;;; Imenu
(python-tests-look-at "c):")
(should (not (python-info-block-continuation-line-p)))))
+(ert-deftest python-info-assignment-statement-p-1 ()
+ (python-tests-with-temp-buffer
+ "
+data = foo(), bar() \\\\
+ baz(), 4 \\\\
+ 5, 6
+"
+ (python-tests-look-at "data = foo(), bar()")
+ (should (python-info-assignment-statement-p))
+ (should (python-info-assignment-statement-p t))
+ (python-tests-look-at "baz(), 4")
+ (should (python-info-assignment-statement-p))
+ (should (not (python-info-assignment-statement-p t)))
+ (python-tests-look-at "5, 6")
+ (should (python-info-assignment-statement-p))
+ (should (not (python-info-assignment-statement-p t)))))
+
+(ert-deftest python-info-assignment-statement-p-2 ()
+ (python-tests-with-temp-buffer
+ "
+data = (foo(), bar()
+ baz(), 4
+ 5, 6)
+"
+ (python-tests-look-at "data = (foo(), bar()")
+ (should (python-info-assignment-statement-p))
+ (should (python-info-assignment-statement-p t))
+ (python-tests-look-at "baz(), 4")
+ (should (python-info-assignment-statement-p))
+ (should (not (python-info-assignment-statement-p t)))
+ (python-tests-look-at "5, 6)")
+ (should (python-info-assignment-statement-p))
+ (should (not (python-info-assignment-statement-p t)))))
+
+(ert-deftest python-info-assignment-statement-p-3 ()
+ (python-tests-with-temp-buffer
+ "
+data '=' 42
+"
+ (python-tests-look-at "data '=' 42")
+ (should (not (python-info-assignment-statement-p)))
+ (should (not (python-info-assignment-statement-p t)))))
+
(ert-deftest python-info-assignment-continuation-line-p-1 ()
(python-tests-with-temp-buffer
"
(forward-line 1)
(should (python-info-current-line-empty-p))))
+(ert-deftest python-info-docstring-p-1 ()
+ "Test module docstring detection."
+ (python-tests-with-temp-buffer
+ "# -*- coding: utf-8 -*-
+#!/usr/bin/python
+
+'''
+Module Docstring Django style.
+'''
+u'''Additional module docstring.'''
+'''Not a module docstring.'''
+"
+ (python-tests-look-at "Module Docstring Django style.")
+ (should (python-info-docstring-p))
+ (python-tests-look-at "u'''Additional module docstring.'''")
+ (should (python-info-docstring-p))
+ (python-tests-look-at "'''Not a module docstring.'''")
+ (should (not (python-info-docstring-p)))))
+
+(ert-deftest python-info-docstring-p-2 ()
+ "Test variable docstring detection."
+ (python-tests-with-temp-buffer
+ "
+variable = 42
+U'''Variable docstring.'''
+'''Additional variable docstring.'''
+'''Not a variable docstring.'''
+"
+ (python-tests-look-at "Variable docstring.")
+ (should (python-info-docstring-p))
+ (python-tests-look-at "u'''Additional variable docstring.'''")
+ (should (python-info-docstring-p))
+ (python-tests-look-at "'''Not a variable docstring.'''")
+ (should (not (python-info-docstring-p)))))
+
+(ert-deftest python-info-docstring-p-3 ()
+ "Test function docstring detection."
+ (python-tests-with-temp-buffer
+ "
+def func(a, b):
+ r'''
+ Function docstring.
+
+ onetwo style.
+ '''
+ R'''Additional function docstring.'''
+ '''Not a function docstring.'''
+ return a + b
+"
+ (python-tests-look-at "Function docstring.")
+ (should (python-info-docstring-p))
+ (python-tests-look-at "R'''Additional function docstring.'''")
+ (should (python-info-docstring-p))
+ (python-tests-look-at "'''Not a function docstring.'''")
+ (should (not (python-info-docstring-p)))))
+
+(ert-deftest python-info-docstring-p-4 ()
+ "Test class docstring detection."
+ (python-tests-with-temp-buffer
+ "
+class Class:
+ ur'''
+ Class docstring.
+
+ symmetric style.
+ '''
+ uR'''
+ Additional class docstring.
+ '''
+ '''Not a class docstring.'''
+ pass
+"
+ (python-tests-look-at "Class docstring.")
+ (should (python-info-docstring-p))
+ (python-tests-look-at "uR'''") ;; Additional class docstring
+ (should (python-info-docstring-p))
+ (python-tests-look-at "'''Not a class docstring.'''")
+ (should (not (python-info-docstring-p)))))
+
+(ert-deftest python-info-docstring-p-5 ()
+ "Test class attribute docstring detection."
+ (python-tests-with-temp-buffer
+ "
+class Class:
+ attribute = 42
+ Ur'''
+ Class attribute docstring.
+
+ pep-257 style.
+
+ '''
+ UR'''
+ Additional class attribute docstring.
+ '''
+ '''Not a class attribute docstring.'''
+ pass
+"
+ (python-tests-look-at "Class attribute docstring.")
+ (should (python-info-docstring-p))
+ (python-tests-look-at "UR'''") ;; Additional class attr docstring
+ (should (python-info-docstring-p))
+ (python-tests-look-at "'''Not a class attribute docstring.'''")
+ (should (not (python-info-docstring-p)))))
+
+(ert-deftest python-info-docstring-p-6 ()
+ "Test class method docstring detection."
+ (python-tests-with-temp-buffer
+ "
+class Class:
+
+ def __init__(self, a, b):
+ self.a = a
+ self.b = b
+
+ def __call__(self):
+ '''Method docstring.
+
+ pep-257-nn style.
+ '''
+ '''Additional method docstring.'''
+ '''Not a method docstring.'''
+ return self.a + self.b
+"
+ (python-tests-look-at "Method docstring.")
+ (should (python-info-docstring-p))
+ (python-tests-look-at "'''Additional method docstring.'''")
+ (should (python-info-docstring-p))
+ (python-tests-look-at "'''Not a method docstring.'''")
+ (should (not (python-info-docstring-p)))))
+
(ert-deftest python-info-encoding-from-cookie-1 ()
"Should detect it on first line."
(python-tests-with-temp-buffer
;;; Electricity
(ert-deftest python-parens-electric-indent-1 ()
- (require 'electric)
(let ((eim electric-indent-mode))
(unwind-protect
(progn
(python-tests-with-temp-buffer
- "
+ "
from django.conf.urls import patterns, include, url
from django.contrib import admin
url(r'^$', views.index
)
"
- (electric-indent-mode 1)
- (python-tests-look-at "views.index")
- (end-of-line)
-
- ;; Inserting commas within the same line should leave
- ;; indentation unchanged.
- (python-tests-self-insert ",")
- (should (= (current-indentation) 4))
-
- ;; As well as any other input happening within the same
- ;; set of parens.
- (python-tests-self-insert " name='index')")
- (should (= (current-indentation) 4))
-
- ;; But a comma outside it, should trigger indentation.
- (python-tests-self-insert ",")
- (should (= (current-indentation) 23))
-
- ;; Newline indents to the first argument column
- (python-tests-self-insert "\n")
- (should (= (current-indentation) 23))
-
- ;; All this input must not change indentation
- (indent-line-to 4)
- (python-tests-self-insert "url(r'^/login$', views.login)")
- (should (= (current-indentation) 4))
-
- ;; But this comma does
- (python-tests-self-insert ",")
- (should (= (current-indentation) 23))))
+ (electric-indent-mode 1)
+ (python-tests-look-at "views.index")
+ (end-of-line)
+
+ ;; Inserting commas within the same line should leave
+ ;; indentation unchanged.
+ (python-tests-self-insert ",")
+ (should (= (current-indentation) 4))
+
+ ;; As well as any other input happening within the same
+ ;; set of parens.
+ (python-tests-self-insert " name='index')")
+ (should (= (current-indentation) 4))
+
+ ;; But a comma outside it, should trigger indentation.
+ (python-tests-self-insert ",")
+ (should (= (current-indentation) 23))
+
+ ;; Newline indents to the first argument column
+ (python-tests-self-insert "\n")
+ (should (= (current-indentation) 23))
+
+ ;; All this input must not change indentation
+ (indent-line-to 4)
+ (python-tests-self-insert "url(r'^/login$', views.login)")
+ (should (= (current-indentation) 4))
+
+ ;; But this comma does
+ (python-tests-self-insert ",")
+ (should (= (current-indentation) 23))))
(or eim (electric-indent-mode -1)))))
(ert-deftest python-triple-quote-pairing ()
- (require 'electric)
(let ((epm electric-pair-mode))
(unwind-protect
(progn
(python-tests-with-temp-buffer
- "\"\"\n"
- (or epm (electric-pair-mode 1))
- (goto-char (1- (point-max)))
- (python-tests-self-insert ?\")
- (should (string= (buffer-string)
- "\"\"\"\"\"\"\n"))
- (should (= (point) 4)))
+ "\"\"\n"
+ (or epm (electric-pair-mode 1))
+ (goto-char (1- (point-max)))
+ (python-tests-self-insert ?\")
+ (should (string= (buffer-string)
+ "\"\"\"\"\"\"\n"))
+ (should (= (point) 4)))
(python-tests-with-temp-buffer
- "\n"
- (python-tests-self-insert (list ?\" ?\" ?\"))
- (should (string= (buffer-string)
- "\"\"\"\"\"\"\n"))
- (should (= (point) 4)))
+ "\n"
+ (python-tests-self-insert (list ?\" ?\" ?\"))
+ (should (string= (buffer-string)
+ "\"\"\"\"\"\"\n"))
+ (should (= (point) 4)))
(python-tests-with-temp-buffer
- "\"\n\"\"\n"
- (goto-char (1- (point-max)))
- (python-tests-self-insert ?\")
- (should (= (point) (1- (point-max))))
- (should (string= (buffer-string)
- "\"\n\"\"\"\n"))))
+ "\"\n\"\"\n"
+ (goto-char (1- (point-max)))
+ (python-tests-self-insert ?\")
+ (should (= (point) (1- (point-max))))
+ (should (string= (buffer-string)
+ "\"\n\"\"\"\n"))))
(or epm (electric-pair-mode -1)))))
+\f
+;;; Hideshow support
+
+(ert-deftest python-hideshow-hide-levels-1 ()
+ "Should hide all methods when called after class start."
+ (let ((enabled hs-minor-mode))
+ (unwind-protect
+ (progn
+ (python-tests-with-temp-buffer
+ "
+class SomeClass:
+
+ def __init__(self, arg, kwarg=1):
+ self.arg = arg
+ self.kwarg = kwarg
+
+ def filter(self, nums):
+ def fn(item):
+ return item in [self.arg, self.kwarg]
+ return filter(fn, nums)
+
+ def __str__(self):
+ return '%s-%s' % (self.arg, self.kwarg)
+"
+ (hs-minor-mode 1)
+ (python-tests-look-at "class SomeClass:")
+ (forward-line)
+ (hs-hide-level 1)
+ (should
+ (string=
+ (python-tests-visible-string)
+ "
+class SomeClass:
+
+ def __init__(self, arg, kwarg=1):
+ def filter(self, nums):
+ def __str__(self):"))))
+ (or enabled (hs-minor-mode -1)))))
+
+(ert-deftest python-hideshow-hide-levels-2 ()
+ "Should hide nested methods and parens at end of defun."
+ (let ((enabled hs-minor-mode))
+ (unwind-protect
+ (progn
+ (python-tests-with-temp-buffer
+ "
+class SomeClass:
+
+ def __init__(self, arg, kwarg=1):
+ self.arg = arg
+ self.kwarg = kwarg
+
+ def filter(self, nums):
+ def fn(item):
+ return item in [self.arg, self.kwarg]
+ return filter(fn, nums)
+
+ def __str__(self):
+ return '%s-%s' % (self.arg, self.kwarg)
+"
+ (hs-minor-mode 1)
+ (python-tests-look-at "def fn(item):")
+ (hs-hide-block)
+ (should
+ (string=
+ (python-tests-visible-string)
+ "
+class SomeClass:
+
+ def __init__(self, arg, kwarg=1):
+ self.arg = arg
+ self.kwarg = kwarg
+
+ def filter(self, nums):
+ def fn(item):
+ return filter(fn, nums)
+
+ def __str__(self):
+ return '%s-%s' % (self.arg, self.kwarg)
+"))))
+ (or enabled (hs-minor-mode -1)))))
+
+
(provide 'python-tests)
;; Local Variables:
-;; coding: utf-8
;; indent-tabs-mode: nil
;; End: