summaryrefslogtreecommitdiffstats
path: root/tests/test_shells
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:40:16 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:40:16 +0000
commit3f25952c13d5847d510c0cae22a8ba876638d570 (patch)
tree02f505f016ed5a1029277dcae520d5e2a75906fb /tests/test_shells
parentInitial commit. (diff)
downloadpowerline-3f25952c13d5847d510c0cae22a8ba876638d570.tar.xz
powerline-3f25952c13d5847d510c0cae22a8ba876638d570.zip
Adding upstream version 2.8.3.upstream/2.8.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/test_shells')
-rwxr-xr-xtests/test_shells/bgscript.sh5
-rw-r--r--tests/test_shells/inputs/bash73
-rw-r--r--tests/test_shells/inputs/busybox37
-rw-r--r--tests/test_shells/inputs/dash37
-rw-r--r--tests/test_shells/inputs/fish69
-rw-r--r--tests/test_shells/inputs/ipython7
-rw-r--r--tests/test_shells/inputs/mksh38
-rw-r--r--tests/test_shells/inputs/pdb89
-rw-r--r--tests/test_shells/inputs/rc33
-rw-r--r--tests/test_shells/inputs/tcsh24
-rw-r--r--tests/test_shells/inputs/zsh90
-rw-r--r--tests/test_shells/ipython_home/profile_default/ipython_config.py22
-rw-r--r--tests/test_shells/outputs/bash.daemon.ok45
-rw-r--r--tests/test_shells/outputs/bash.nodaemon.ok45
-rw-r--r--tests/test_shells/outputs/busybox.daemon.ok29
-rw-r--r--tests/test_shells/outputs/busybox.nodaemon.ok29
-rw-r--r--tests/test_shells/outputs/dash.daemon.ok28
-rw-r--r--tests/test_shells/outputs/dash.nodaemon.ok28
-rw-r--r--tests/test_shells/outputs/fish.ok52
-rw-r--r--tests/test_shells/outputs/ipython.ok14
-rw-r--r--tests/test_shells/outputs/mksh.daemon.ok32
-rw-r--r--tests/test_shells/outputs/mksh.nodaemon.ok32
-rw-r--r--tests/test_shells/outputs/pdb.module.ok222
-rw-r--r--tests/test_shells/outputs/pdb.subclass.ok217
-rw-r--r--tests/test_shells/outputs/rc.daemon.ok24
-rw-r--r--tests/test_shells/outputs/rc.nodaemon.ok24
-rw-r--r--tests/test_shells/outputs/tcsh.ok17
-rw-r--r--tests/test_shells/outputs/zsh.daemon.ok52
-rw-r--r--tests/test_shells/outputs/zsh.nodaemon.ok52
-rw-r--r--tests/test_shells/outputs/zsh.zpython.ok52
-rw-r--r--tests/test_shells/pdb-main.py24
-rw-r--r--tests/test_shells/pdb-script.py38
-rwxr-xr-xtests/test_shells/postproc.py130
-rwxr-xr-xtests/test_shells/run_script.py125
-rwxr-xr-xtests/test_shells/test.sh491
-rwxr-xr-xtests/test_shells/waitpid.sh4
-rw-r--r--tests/test_shells/zsh_test_script.zsh11
37 files changed, 2341 insertions, 0 deletions
diff --git a/tests/test_shells/bgscript.sh b/tests/test_shells/bgscript.sh
new file mode 100755
index 0000000..71886e6
--- /dev/null
+++ b/tests/test_shells/bgscript.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+echo $$ > pid
+while true ; do
+ sleep 0.1s
+done
diff --git a/tests/test_shells/inputs/bash b/tests/test_shells/inputs/bash
new file mode 100644
index 0000000..b0d1478
--- /dev/null
+++ b/tests/test_shells/inputs/bash
@@ -0,0 +1,73 @@
+set_theme_option() {
+ export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2"
+}
+set_theme() {
+ export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1"
+}
+set_theme_option default.segment_data.hostname.args.only_if_ssh false
+set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
+ABOVE_LEFT='[{
+ "left": [
+ {
+ "function": "powerline.segments.common.env.environment",
+ "args": {"variable": "DISPLAYED_ENV_VAR"}
+ }
+ ]
+}]'
+ABOVE_FULL='[{
+ "left": [
+ {
+ "type": "string",
+ "name": "background",
+ "draw_hard_divider": false,
+ "width": "auto"
+ }
+ ],
+ "right": [
+ {
+ "function": "powerline.segments.common.env.environment",
+ "args": {"variable": "DISPLAYED_ENV_VAR"}
+ }
+ ]
+}]'
+set_theme default_leftonly
+export VIRTUAL_ENV=
+source powerline/bindings/bash/powerline.sh
+cd "$TEST_ROOT"/3rd
+cd .git
+cd ..
+VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"
+VIRTUAL_ENV=
+bgscript.sh & waitpid.sh
+false
+kill `cat pid` ; sleep 1s
+set_theme_option default.segment_data.hostname.display false
+set_theme_option default_leftonly.segment_data.hostname.display false
+set_theme_option default.segment_data.user.display false
+set_theme_option default_leftonly.segment_data.user.display false
+echo '
+abc
+def
+'
+cd "$DIR1"
+cd ../"$DIR2"
+cd ../'\[\]'
+cd ../'%%'
+cd ../'#[bold]'
+cd ../'(echo)'
+cd ../'$(echo)'
+cd ../'`echo`'
+cd ../'«Unicode!»'
+(exit 42)|(exit 43)
+set_theme default
+set_theme_option default.segments.above "$ABOVE_LEFT"
+export DISPLAYED_ENV_VAR=foo
+unset DISPLAYED_ENV_VAR
+set_theme_option default.segments.above "$ABOVE_FULL"
+export DISPLAYED_ENV_VAR=foo
+unset DISPLAYED_ENV_VAR
+set_theme_option default.segments.above
+set_theme_option default.dividers.left.hard \$ABC
+false
+true is the last line
+exit
diff --git a/tests/test_shells/inputs/busybox b/tests/test_shells/inputs/busybox
new file mode 100644
index 0000000..5d1495a
--- /dev/null
+++ b/tests/test_shells/inputs/busybox
@@ -0,0 +1,37 @@
+set_theme_option() {
+ export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2"
+}
+set_theme() {
+ export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1"
+}
+set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
+set_theme default_leftonly
+. powerline/bindings/shell/powerline.sh
+export VIRTUAL_ENV=
+cd "$TEST_ROOT"/3rd
+cd .git
+cd ..
+VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"
+VIRTUAL_ENV=
+bgscript.sh & waitpid.sh
+false
+kill `cat pid` ; sleep 1s
+set_theme_option default_leftonly.segment_data.hostname.display false
+set_theme_option default_leftonly.segment_data.user.display false
+echo '
+abc
+def
+'
+cd "$DIR1"
+cd ../"$DIR2"
+cd ../'\[\]'
+cd ../'%%'
+cd ../'#[bold]'
+cd ../'(echo)'
+cd ../'$(echo)'
+cd ../'`echo`'
+cd ../'«Unicode!»'
+set_theme_option default_leftonly.dividers.left.hard \$ABC
+false
+true is the last line
+exit
diff --git a/tests/test_shells/inputs/dash b/tests/test_shells/inputs/dash
new file mode 100644
index 0000000..5d1495a
--- /dev/null
+++ b/tests/test_shells/inputs/dash
@@ -0,0 +1,37 @@
+set_theme_option() {
+ export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2"
+}
+set_theme() {
+ export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1"
+}
+set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
+set_theme default_leftonly
+. powerline/bindings/shell/powerline.sh
+export VIRTUAL_ENV=
+cd "$TEST_ROOT"/3rd
+cd .git
+cd ..
+VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"
+VIRTUAL_ENV=
+bgscript.sh & waitpid.sh
+false
+kill `cat pid` ; sleep 1s
+set_theme_option default_leftonly.segment_data.hostname.display false
+set_theme_option default_leftonly.segment_data.user.display false
+echo '
+abc
+def
+'
+cd "$DIR1"
+cd ../"$DIR2"
+cd ../'\[\]'
+cd ../'%%'
+cd ../'#[bold]'
+cd ../'(echo)'
+cd ../'$(echo)'
+cd ../'`echo`'
+cd ../'«Unicode!»'
+set_theme_option default_leftonly.dividers.left.hard \$ABC
+false
+true is the last line
+exit
diff --git a/tests/test_shells/inputs/fish b/tests/test_shells/inputs/fish
new file mode 100644
index 0000000..9a20613
--- /dev/null
+++ b/tests/test_shells/inputs/fish
@@ -0,0 +1,69 @@
+function set_theme_option
+ set -g -x POWERLINE_THEME_OVERRIDES "$POWERLINE_THEME_OVERRIDES;$argv[1]=$argv[2]"
+end
+function set_theme
+ set -g -x POWERLINE_CONFIG_OVERRIDES "ext.shell.theme=$argv"
+end
+set -g -x POWERLINE_
+set -g ABOVE_LEFT '[{
+ "left": [
+ {
+ "function": "powerline.segments.common.env.environment",
+ "args": {"variable": "DISPLAYED_ENV_VAR"}
+ }
+ ]
+}]'
+set -g ABOVE_FULL '[{
+ "left": [
+ {
+ "type": "string",
+ "name": "background",
+ "draw_hard_divider": false,
+ "width": "auto"
+ }
+ ],
+ "right": [
+ {
+ "function": "powerline.segments.common.env.environment",
+ "args": {"variable": "DISPLAYED_ENV_VAR"}
+ }
+ ]
+}]'
+set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
+set_theme default_leftonly
+set fish_function_path "$PWD/powerline/bindings/fish" $fish_function_path
+while jobs | grep fish_update_completions
+ sleep 1
+end
+powerline-setup
+setenv VIRTUAL_ENV
+cd "$TEST_ROOT"/3rd
+cd .git
+cd ..
+setenv VIRTUAL_ENV "$HOME/.virtenvs/some-virtual-environment"
+setenv VIRTUAL_ENV
+bgscript.sh & waitpid.sh
+false
+kill (cat pid) ; sleep 1s
+cd "$DIR1"
+cd ../"$DIR2"
+cd ../'\[\]'
+cd ../'%%'
+cd ../'#[bold]'
+cd ../'(echo)'
+cd ../'$(echo)'
+cd ../'`echo`'
+cd ../'«Unicode!»'
+set_theme default
+set_theme_option default.segments.above "$ABOVE_LEFT"
+set -g -x DISPLAYED_ENV_VAR foo
+set -g -x -e DISPLAYED_ENV_VAR
+set_theme_option default.segments.above "$ABOVE_FULL"
+set -g -x DISPLAYED_ENV_VAR foo
+set -g -x -e DISPLAYED_ENV_VAR
+set_theme_option default.segments.above ''
+set -g fish_key_bindings fish_vi_key_bindings
+ii
+false
+true is the last line
+exit
diff --git a/tests/test_shells/inputs/ipython b/tests/test_shells/inputs/ipython
new file mode 100644
index 0000000..257cba6
--- /dev/null
+++ b/tests/test_shells/inputs/ipython
@@ -0,0 +1,7 @@
+print ('cd ' + '"$TEST_ROOT"/3rd') # Start of the test marker
+bool 42
+bool 44
+class Test(object):
+pass
+
+exit
diff --git a/tests/test_shells/inputs/mksh b/tests/test_shells/inputs/mksh
new file mode 100644
index 0000000..ca45783
--- /dev/null
+++ b/tests/test_shells/inputs/mksh
@@ -0,0 +1,38 @@
+set_theme_option() {
+ export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2"
+}
+set_theme() {
+ export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1"
+}
+set_theme default_leftonly
+set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
+. powerline/bindings/shell/powerline.sh
+export VIRTUAL_ENV=
+cd "$TEST_ROOT"/3rd
+cd .git
+cd ..
+VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"
+VIRTUAL_ENV=
+bgscript.sh & waitpid.sh
+false
+kill `cat pid` ; sleep 1
+set_theme_option default_leftonly.segment_data.hostname.display false
+set_theme_option default_leftonly.segment_data.user.display false
+echo -n
+echo '
+abc
+def
+'
+cd "$DIR1"
+cd ../"$DIR2"
+cd ../'\[\]'
+cd ../'%%'
+cd ../'#[bold]'
+cd ../'(echo)'
+cd ../'$(echo)'
+cd ../'`echo`'
+cd ../'«Unicode!»'
+set_theme_option default_leftonly.dividers.left.hard \$ABC
+false
+true is the last line
+exit
diff --git a/tests/test_shells/inputs/pdb b/tests/test_shells/inputs/pdb
new file mode 100644
index 0000000..e9ac498
--- /dev/null
+++ b/tests/test_shells/inputs/pdb
@@ -0,0 +1,89 @@
+s
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/test_shells/inputs/rc b/tests/test_shells/inputs/rc
new file mode 100644
index 0000000..c88bcf9
--- /dev/null
+++ b/tests/test_shells/inputs/rc
@@ -0,0 +1,33 @@
+fn set_theme_option {
+ POWERLINE_THEME_OVERRIDES = $POWERLINE_THEME_OVERRIDES';'$1'='$2
+}
+set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
+POWERLINE_CONFIG_OVERRIDES = 'ext.shell.theme=default_leftonly'
+. powerline/bindings/rc/powerline.rc
+VIRTUAL_ENV = ()
+cd $TEST_ROOT/3rd
+true cd "$TEST_ROOT"/3rd # Test start marker
+cd .git
+cd ..
+VIRTUAL_ENV = '/home/foo/.virtenvs/some-virtual-environment'
+VIRTUAL_ENV = ()
+bgscript.sh & waitpid.sh
+false
+kill `{cat pid} ; sleep 1s
+cd $DIR1
+cd ../$DIR2
+cd ../'\[\]'
+cd ../'%%'
+cd ../'#[bold]'
+cd ../'(echo)'
+cd ../'$(echo)'
+cd ../'`echo`'
+cd ../'«Unicode!»'
+false
+set_theme_option default_leftonly.segment_data.hostname.display false
+set_theme_option default_leftonly.segment_data.user.display false
+echo `{
+ echo Continuation!
+}
+true is the last line
+exit
diff --git a/tests/test_shells/inputs/tcsh b/tests/test_shells/inputs/tcsh
new file mode 100644
index 0000000..c7d722a
--- /dev/null
+++ b/tests/test_shells/inputs/tcsh
@@ -0,0 +1,24 @@
+setenv POWERLINE_THEME_OVERRIDES "default_leftonly.segment_data.hostname.args.only_if_ssh=false"
+setenv POWERLINE_CONFIG_OVERRIDES "ext.shell.theme=default_leftonly"
+source powerline/bindings/tcsh/powerline.tcsh
+unsetenv VIRTUAL_ENV
+cd "$TEST_ROOT"/3rd
+cd .git
+cd ..
+setenv VIRTUAL_ENV "/home/foo/.virtenvs/some-virtual-environment"
+unsetenv VIRTUAL_ENV
+bgscript.sh & waitpid.sh
+false # Warning: currently tcsh bindings do not support job count
+kill `cat pid` ; sleep 1s
+cd $DIR1:q
+cd ../$DIR2:q
+cd ../'\[\]'
+cd ../'%%'
+cd ../'#[bold]'
+cd ../'(echo)'
+cd ../'$(echo)'
+cd ../'`echo`'
+cd ../'«Unicode\!»'
+false
+true is the last line
+exit
diff --git a/tests/test_shells/inputs/zsh b/tests/test_shells/inputs/zsh
new file mode 100644
index 0000000..811684e
--- /dev/null
+++ b/tests/test_shells/inputs/zsh
@@ -0,0 +1,90 @@
+unset HOME
+unsetopt promptsp notransientrprompt
+setopt interactivecomments
+setopt autonamedirs
+setopt warncreateglobal
+function set_theme_option() {
+ export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2"
+ powerline-reload-config
+}
+function set_theme() {
+ export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1"
+ powerline-reload-config
+}
+if test -n "$POWERLINE_NO_ZSH_ZPYTHON" ; then
+ powerline-reload-config():
+fi
+source powerline/bindings/zsh/powerline.zsh
+set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
+set_theme_option default.segment_data.hostname.args.only_if_ssh false
+ABOVE_LEFT='[{
+ "left": [
+ {
+ "function": "powerline.segments.common.env.environment",
+ "args": {"variable": "DISPLAYED_ENV_VAR"}
+ }
+ ]
+}]'
+ABOVE_FULL='[{
+ "left": [
+ {
+ "type": "string",
+ "name": "background",
+ "draw_hard_divider": false,
+ "width": "auto"
+ }
+ ],
+ "right": [
+ {
+ "function": "powerline.segments.common.env.environment",
+ "args": {"variable": "DISPLAYED_ENV_VAR"}
+ }
+ ]
+}]'
+set_theme default_leftonly
+export VIRTUAL_ENV=
+cd "$TEST_ROOT"/3rd
+cd .git
+cd ..
+VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment"
+VIRTUAL_ENV=
+bgscript.sh & waitpid.sh
+false
+kill `cat pid` ; sleep 1s
+cd "$DIR1"
+cd ../"$DIR2"
+cd ../'\[\]'
+cd ../'%%'
+cd ../'#[bold]'
+cd ../'(echo)'
+cd ../'$(echo)'
+cd ../'`echo`'
+cd ../'«Unicode!»'
+cd ..
+bindkey -v ; set_theme default
+
+
+echo abc
+false
+set_theme_option default.segment_data.hostname.display false
+set_theme_option default.segment_data.user.display false
+select abc in def ghi jkl
+do
+ echo $abc
+ break
+done
+1
+cd .
+cd .
+set_theme_option default.segments.above "$ABOVE_LEFT"
+export DISPLAYED_ENV_VAR=foo
+unset DISPLAYED_ENV_VAR
+set_theme_option default.segments.above "$ABOVE_FULL"
+export DISPLAYED_ENV_VAR=foo
+unset DISPLAYED_ENV_VAR
+set_theme_option default.segments.above
+hash -d foo=$PWD:h ; cd .
+set_theme_option default.dividers.left.hard \$ABC
+true
+true is the last line
+exit
diff --git a/tests/test_shells/ipython_home/profile_default/ipython_config.py b/tests/test_shells/ipython_home/profile_default/ipython_config.py
new file mode 100644
index 0000000..ffb5865
--- /dev/null
+++ b/tests/test_shells/ipython_home/profile_default/ipython_config.py
@@ -0,0 +1,22 @@
+from powerline.bindings.ipython.since_7 import PowerlinePrompts
+import os
+c = get_config()
+c.TerminalInteractiveShell.simple_prompt = False
+c.TerminalIPythonApp.display_banner = False
+c.TerminalInteractiveShell.prompts_class = PowerlinePrompts
+c.TerminalInteractiveShell.autocall = 1
+c.Powerline.config_paths = [os.path.abspath('powerline/config_files')]
+c.Powerline.theme_overrides = {
+ 'in': {
+ 'segment_data': {
+ 'virtualenv': {
+ 'display': False
+ }
+ }
+ }
+}
+c.Powerline.config_overrides = {
+ 'common': {
+ 'default_top_theme': 'ascii'
+ }
+}
diff --git a/tests/test_shells/outputs/bash.daemon.ok b/tests/test_shells/outputs/bash.daemon.ok
new file mode 100644
index 0000000..7b8cd6c
--- /dev/null
+++ b/tests/test_shells/outputs/bash.daemon.ok
@@ -0,0 +1,45 @@
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+[1] PID
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s
+[1]+ Terminated bgscript.sh
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default.segment_data.hostname.display false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.hostname.display false
+ USER   BRANCH  …  tmp  shell  3rd  set_theme_option default.segment_data.user.display false
+ USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false
+  BRANCH  …  tmp  shell  3rd  echo '
+                                   abc
+                                   def
+                                   '
+
+abc
+def
+
+  BRANCH  …  tmp  shell  3rd  cd "$DIR1"
+  BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"
+  BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  BRANCH  …  shell  3rd  «Unicode!»  (exit 42)|(exit 43)
+  BRANCH  …  shell  3rd  «Unicode!»  42  43  set_theme default
+ …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above "$ABOVE_LEFT"
+ …  shell  3rd  «Unicode!»     BRANCH export DISPLAYED_ENV_VAR=foo
+ foo  
+ …  shell  3rd  «Unicode!»     BRANCH unset DISPLAYED_ENV_VAR
+ …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above "$ABOVE_FULL"
+                                                                                                                                                                                                                                                                                                            
+ …  shell  3rd  «Unicode!»     BRANCH export DISPLAYED_ENV_VAR=foo
+                                                                                                                                                                                                                                                                                                       foo 
+ …  shell  3rd  «Unicode!»     BRANCH unset DISPLAYED_ENV_VAR
+                                                                                                                                                                                                                                                                                                            
+ …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above
+ …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.dividers.left.hard \$ABC
+ …  shell  3rd  «Unicode!» $ABC   BRANCH false
diff --git a/tests/test_shells/outputs/bash.nodaemon.ok b/tests/test_shells/outputs/bash.nodaemon.ok
new file mode 100644
index 0000000..458c1a1
--- /dev/null
+++ b/tests/test_shells/outputs/bash.nodaemon.ok
@@ -0,0 +1,45 @@
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+[1] PID
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s
+[1]+ Terminated bgscript.sh
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default.segment_data.hostname.display false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.hostname.display false
+ USER   BRANCH  …  tmp  shell  3rd  set_theme_option default.segment_data.user.display false
+ USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false
+  BRANCH  …  tmp  shell  3rd  echo '
+   abc
+   def
+   '
+
+abc
+def
+
+  BRANCH  …  tmp  shell  3rd  cd "$DIR1"
+  BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"
+  BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  BRANCH  …  shell  3rd  «Unicode!»  (exit 42)|(exit 43)
+  BRANCH  …  shell  3rd  «Unicode!»  42  43  set_theme default
+ …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above "$ABOVE_LEFT"
+ …  shell  3rd  «Unicode!»     BRANCH export DISPLAYED_ENV_VAR=foo
+ foo  
+ …  shell  3rd  «Unicode!»     BRANCH unset DISPLAYED_ENV_VAR
+ …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above "$ABOVE_FULL"
+                                                                                                                                                                                                                                                                                                            
+ …  shell  3rd  «Unicode!»     BRANCH export DISPLAYED_ENV_VAR=foo
+                                                                                                                                                                                                                                                                                                       foo 
+ …  shell  3rd  «Unicode!»     BRANCH unset DISPLAYED_ENV_VAR
+                                                                                                                                                                                                                                                                                                            
+ …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above
+ …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.dividers.left.hard \$ABC
+ …  shell  3rd  «Unicode!» $ABC   BRANCH false
diff --git a/tests/test_shells/outputs/busybox.daemon.ok b/tests/test_shells/outputs/busybox.daemon.ok
new file mode 100644
index 0000000..446d88e
--- /dev/null
+++ b/tests/test_shells/outputs/busybox.daemon.ok
@@ -0,0 +1,29 @@
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s
+[1]+ Terminated bgscript.sh
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  set_theme_option default_leftonly.segment_data.hostname.display false
+ USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false
+  BRANCH  …  tmp  shell  3rd  echo '
+                                   abc
+                                   def
+                                   '
+
+abc
+def
+
+  BRANCH  …  tmp  shell  3rd  cd "$DIR1"
+  BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"
+  BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC
+  BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse
diff --git a/tests/test_shells/outputs/busybox.nodaemon.ok b/tests/test_shells/outputs/busybox.nodaemon.ok
new file mode 100644
index 0000000..afda9a5
--- /dev/null
+++ b/tests/test_shells/outputs/busybox.nodaemon.ok
@@ -0,0 +1,29 @@
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s
+[1]+ Terminated bgscript.sh
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  set_theme_option default_leftonly.segment_data.hostname.display false
+ USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false
+  BRANCH  …  tmp  shell  3rd  echo '
+   abc
+   def
+   '
+
+abc
+def
+
+  BRANCH  …  tmp  shell  3rd  cd "$DIR1"
+  BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"
+  BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC
+  BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse
diff --git a/tests/test_shells/outputs/dash.daemon.ok b/tests/test_shells/outputs/dash.daemon.ok
new file mode 100644
index 0000000..71ca500
--- /dev/null
+++ b/tests/test_shells/outputs/dash.daemon.ok
@@ -0,0 +1,28 @@
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s
+set_theme_option default_leftonly.segment_data.hostname.display false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1   USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false
+  BRANCH  …  tmp  shell  3rd  echo '
+                                   abc
+                                   def
+                                   '
+
+abc
+def
+
+  BRANCH  …  tmp  shell  3rd  cd "$DIR1"
+  BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"
+  BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC
+  BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse
diff --git a/tests/test_shells/outputs/dash.nodaemon.ok b/tests/test_shells/outputs/dash.nodaemon.ok
new file mode 100644
index 0000000..c289cd2
--- /dev/null
+++ b/tests/test_shells/outputs/dash.nodaemon.ok
@@ -0,0 +1,28 @@
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s
+set_theme_option default_leftonly.segment_data.hostname.display false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1   USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false
+  BRANCH  …  tmp  shell  3rd  echo '
+   abc
+   def
+   '
+
+abc
+def
+
+  BRANCH  …  tmp  shell  3rd  cd "$DIR1"
+  BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"
+  BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC
+  BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse
diff --git a/tests/test_shells/outputs/fish.ok b/tests/test_shells/outputs/fish.ok
new file mode 100644
index 0000000..4d208bb
--- /dev/null
+++ b/tests/test_shells/outputs/fish.ok
@@ -0,0 +1,52 @@
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^H  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  %%  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  
+ USER  …  shell  3rd  «Unicode!»  
+   BRANCH 
+   BRANCH 
+   BRANCH 
+ USER  …  shell  3rd  «Unicode!»  
+   BRANCH 
+   BRANCH 
+   BRANCH 
+ foo  
+ USER  …  shell  3rd  «Unicode!»  
+   BRANCH 
+   BRANCH 
+   BRANCH 
+                                                                                                                                                                                                                                                                                                           
+                                                                                                                                                                                                                                                                                                      foo 
+                                                                                                                                                                                                                                                                                                           
+ USER  …  shell  3rd  «Unicode!»  
+   BRANCH 
+   BRANCH 
+   BRANCH 
+ INSERT  USER  …  shell  3rd  «Unicode!»  
+   BRANCH 
+ DEFAULT  USER  …  shell  3rd  «Unicode!»  
+   BRANCH 
+ INSERT  USER  …  shell  3rd  «Unicode!»  
+   BRANCH 
+ DEFAULT  USER  …  shell  3rd  «Unicode!»  
+   BRANCH 
+ INSERT  USER  …  shell  3rd  «Unicode!»  
+   BRANCH 
+   BRANCH 
+ INSERT  USER  …  shell  3rd  «Unicode!»  
+   BRANCH 
+   BRANCH 
+   BRANCH 
diff --git a/tests/test_shells/outputs/ipython.ok b/tests/test_shells/outputs/ipython.ok
new file mode 100644
index 0000000..166604d
--- /dev/null
+++ b/tests/test_shells/outputs/ipython.ok
@@ -0,0 +1,14 @@
+
+ In [2]  bool 42
+ 2>  bool(42)
+ Out[2]  True
+
+ In [3]  bool 44
+ 3>  bool(44)
+ Out[3]  True
+
+ In [4]  class Test(object):
+   pass
+  
+
+ In [5]  exit
diff --git a/tests/test_shells/outputs/mksh.daemon.ok b/tests/test_shells/outputs/mksh.daemon.ok
new file mode 100644
index 0000000..264dff8
--- /dev/null
+++ b/tests/test_shells/outputs/mksh.daemon.ok
@@ -0,0 +1,32 @@
+
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+[1] PID
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1
+[1] + Terminated bash -c ...
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.hostname.display false
+ USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false
+  BRANCH  …  tmp  shell  3rd  echo -n
+  BRANCH  …  tmp  shell  3rd  echo '
+                                   abc
+                                   def
+                                   '
+
+abc
+def
+
+  BRANCH  …  tmp  shell  3rd  cd "$DIR1"
+  BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"
+  BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC
+  BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse
diff --git a/tests/test_shells/outputs/mksh.nodaemon.ok b/tests/test_shells/outputs/mksh.nodaemon.ok
new file mode 100644
index 0000000..d8d9d70
--- /dev/null
+++ b/tests/test_shells/outputs/mksh.nodaemon.ok
@@ -0,0 +1,32 @@
+
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+[1] PID
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1
+[1] + Terminated bash -c ...
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.hostname.display false
+ USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false
+  BRANCH  …  tmp  shell  3rd  echo -n
+  BRANCH  …  tmp  shell  3rd  echo '
+   abc
+   def
+   '
+
+abc
+def
+
+  BRANCH  …  tmp  shell  3rd  cd "$DIR1"
+  BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"
+  BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC
+  BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse
diff --git a/tests/test_shells/outputs/pdb.module.ok b/tests/test_shells/outputs/pdb.module.ok
new file mode 100644
index 0000000..7554dd6
--- /dev/null
+++ b/tests/test_shells/outputs/pdb.module.ok
@@ -0,0 +1,222 @@
+ 1  pdb-script.py:6 <module>  
+--Call--
+-> class Foo(object):
+ 2  pdb-script.py:6 <module>  pdb-script.py:6 Foo  
+-> class Foo(object):
+ 2  pdb-script.py:6 <module>  pdb-script.py:6 Foo  
+-> def __init__(self):
+ 2  pdb-script.py:6 <module>  pdb-script.py:7 Foo  
+-> @classmethod
+ 2  pdb-script.py:6 <module>  pdb-script.py:13 Foo  
+-> @staticmethod
+ 2  pdb-script.py:6 <module>  pdb-script.py:17 Foo  
+-> def bra(self):
+ 2  pdb-script.py:6 <module>  pdb-script.py:21 Foo  
+--Return--
+-> def bra(self):
+ 2  pdb-script.py:6 <module>  pdb-script.py:21 Foo  
+-> def brah():
+ 1  pdb-script.py:25 <module>  
+-> f = Foo()
+ 1  pdb-script.py:29 <module>  
+--Call--
+-> def __init__(self):
+ 2  pdb-script.py:29 <module>  pdb-script.py:7 __init__  
+-> nop('__init__')
+ 2  pdb-script.py:29 <module>  pdb-script.py:8 __init__  
+--Call--
+-> def nop(_):
+ 3  pdb-script.py:29 <module>  pdb-script.py:8 __init__  pdb-script.py:2 nop  
+-> pass
+ 3  pdb-script.py:29 <module>  pdb-script.py:8 __init__  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 3  pdb-script.py:29 <module>  pdb-script.py:8 __init__  pdb-script.py:3 nop  
+-> self.bar()
+ 2  pdb-script.py:29 <module>  pdb-script.py:9 __init__  
+--Call--
+-> @classmethod
+ 3  pdb-script.py:29 <module>  pdb-script.py:9 __init__  pdb-script.py:13 bar  
+-> nop(cls.__name__)
+ 3  pdb-script.py:29 <module>  pdb-script.py:9 __init__  pdb-script.py:15 bar  
+--Call--
+-> def nop(_):
+ 4  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:2 nop  
+-> pass
+ 4  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 4  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:3 nop  
+--Return--
+-> nop(cls.__name__)
+ 3  pdb-script.py:29 <module>  pdb-script.py:9 __init__  pdb-script.py:15 bar  
+-> self.baz()
+ 2  pdb-script.py:29 <module>  pdb-script.py:10 __init__  
+--Call--
+-> @staticmethod
+ 3  pdb-script.py:29 <module>  pdb-script.py:10 __init__  pdb-script.py:17 baz  
+-> nop(1)
+ 3  pdb-script.py:29 <module>  pdb-script.py:10 __init__  pdb-script.py:19 baz  
+--Call--
+-> def nop(_):
+ 4  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:2 nop  
+-> pass
+ 4  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 4  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:3 nop  
+--Return--
+-> nop(1)
+ 3  pdb-script.py:29 <module>  pdb-script.py:10 __init__  pdb-script.py:19 baz  
+-> self.bra()
+ 2  pdb-script.py:29 <module>  pdb-script.py:11 __init__  
+--Call--
+-> def bra(self):
+ 3  pdb-script.py:29 <module>  pdb-script.py:11 __init__  pdb-script.py:21 bra  
+-> nop(self.__class__.__name__)
+ 3  pdb-script.py:29 <module>  pdb-script.py:11 __init__  pdb-script.py:22 bra  
+--Call--
+-> def nop(_):
+ 4  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:2 nop  
+-> pass
+ 4  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 4  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:3 nop  
+--Return--
+-> nop(self.__class__.__name__)
+ 3  pdb-script.py:29 <module>  pdb-script.py:11 __init__  pdb-script.py:22 bra  
+--Return--
+-> self.bra()
+ 2  pdb-script.py:29 <module>  pdb-script.py:11 __init__  
+-> Foo.bar()
+ 1  pdb-script.py:30 <module>  
+--Call--
+-> @classmethod
+ 2  pdb-script.py:30 <module>  pdb-script.py:13 bar  
+-> nop(cls.__name__)
+ 2  pdb-script.py:30 <module>  pdb-script.py:15 bar  
+--Call--
+-> def nop(_):
+ 3  pdb-script.py:30 <module>  pdb-script.py:15 bar  pdb-script.py:2 nop  
+-> pass
+ 3  pdb-script.py:30 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 3  pdb-script.py:30 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
+--Return--
+-> nop(cls.__name__)
+ 2  pdb-script.py:30 <module>  pdb-script.py:15 bar  
+-> Foo.baz()
+ 1  pdb-script.py:31 <module>  
+--Call--
+-> @staticmethod
+ 2  pdb-script.py:31 <module>  pdb-script.py:17 baz  
+-> nop(1)
+ 2  pdb-script.py:31 <module>  pdb-script.py:19 baz  
+--Call--
+-> def nop(_):
+ 3  pdb-script.py:31 <module>  pdb-script.py:19 baz  pdb-script.py:2 nop  
+-> pass
+ 3  pdb-script.py:31 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 3  pdb-script.py:31 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
+--Return--
+-> nop(1)
+ 2  pdb-script.py:31 <module>  pdb-script.py:19 baz  
+-> Foo.bra(f)
+ 1  pdb-script.py:32 <module>  
+--Call--
+-> def bra(self):
+ 2  pdb-script.py:32 <module>  pdb-script.py:21 bra  
+-> nop(self.__class__.__name__)
+ 2  pdb-script.py:32 <module>  pdb-script.py:22 bra  
+--Call--
+-> def nop(_):
+ 3  pdb-script.py:32 <module>  pdb-script.py:22 bra  pdb-script.py:2 nop  
+-> pass
+ 3  pdb-script.py:32 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 3  pdb-script.py:32 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
+--Return--
+-> nop(self.__class__.__name__)
+ 2  pdb-script.py:32 <module>  pdb-script.py:22 bra  
+-> f.bar()
+ 1  pdb-script.py:34 <module>  
+--Call--
+-> @classmethod
+ 2  pdb-script.py:34 <module>  pdb-script.py:13 bar  
+-> nop(cls.__name__)
+ 2  pdb-script.py:34 <module>  pdb-script.py:15 bar  
+--Call--
+-> def nop(_):
+ 3  pdb-script.py:34 <module>  pdb-script.py:15 bar  pdb-script.py:2 nop  
+-> pass
+ 3  pdb-script.py:34 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 3  pdb-script.py:34 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
+--Return--
+-> nop(cls.__name__)
+ 2  pdb-script.py:34 <module>  pdb-script.py:15 bar  
+-> f.baz()
+ 1  pdb-script.py:35 <module>  
+--Call--
+-> @staticmethod
+ 2  pdb-script.py:35 <module>  pdb-script.py:17 baz  
+-> nop(1)
+ 2  pdb-script.py:35 <module>  pdb-script.py:19 baz  
+--Call--
+-> def nop(_):
+ 3  pdb-script.py:35 <module>  pdb-script.py:19 baz  pdb-script.py:2 nop  
+-> pass
+ 3  pdb-script.py:35 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 3  pdb-script.py:35 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
+--Return--
+-> nop(1)
+ 2  pdb-script.py:35 <module>  pdb-script.py:19 baz  
+-> f.bra()
+ 1  pdb-script.py:36 <module>  
+--Call--
+-> def bra(self):
+ 2  pdb-script.py:36 <module>  pdb-script.py:21 bra  
+-> nop(self.__class__.__name__)
+ 2  pdb-script.py:36 <module>  pdb-script.py:22 bra  
+--Call--
+-> def nop(_):
+ 3  pdb-script.py:36 <module>  pdb-script.py:22 bra  pdb-script.py:2 nop  
+-> pass
+ 3  pdb-script.py:36 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 3  pdb-script.py:36 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
+--Return--
+-> nop(self.__class__.__name__)
+ 2  pdb-script.py:36 <module>  pdb-script.py:22 bra  
+-> brah()
+ 1  pdb-script.py:38 <module>  
+--Call--
+-> def brah():
+ 2  pdb-script.py:38 <module>  pdb-script.py:25 brah  
+-> nop('brah')
+ 2  pdb-script.py:38 <module>  pdb-script.py:26 brah  
+--Call--
+-> def nop(_):
+ 3  pdb-script.py:38 <module>  pdb-script.py:26 brah  pdb-script.py:2 nop  
+-> pass
+ 3  pdb-script.py:38 <module>  pdb-script.py:26 brah  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 3  pdb-script.py:38 <module>  pdb-script.py:26 brah  pdb-script.py:3 nop  
+--Return--
+-> nop('brah')
+ 2  pdb-script.py:38 <module>  pdb-script.py:26 brah  
+--Return--
+-> brah()
+ 1  pdb-script.py:38 <module>  
+--Return--
+ 0  
diff --git a/tests/test_shells/outputs/pdb.subclass.ok b/tests/test_shells/outputs/pdb.subclass.ok
new file mode 100644
index 0000000..d8eba5e
--- /dev/null
+++ b/tests/test_shells/outputs/pdb.subclass.ok
@@ -0,0 +1,217 @@
+ 2  <string>:1 <module>  pdb-script.py:6 <module>  
+--Call--
+-> class Foo(object):
+ 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:6 Foo  
+-> class Foo(object):
+ 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:6 Foo  
+-> def __init__(self):
+ 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:7 Foo  
+-> @classmethod
+ 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:13 Foo  
+-> @staticmethod
+ 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:17 Foo  
+-> def bra(self):
+ 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:21 Foo  
+--Return--
+-> def bra(self):
+ 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:21 Foo  
+-> def brah():
+ 2  <string>:1 <module>  pdb-script.py:25 <module>  
+-> f = Foo()
+ 2  <string>:1 <module>  pdb-script.py:29 <module>  
+--Call--
+-> def __init__(self):
+ 3  <string>:1 <module>  pdb-script.py:29 <module>  pdb-script.py:7 __init__  
+-> nop('__init__')
+ 3  <string>:1 <module>  pdb-script.py:29 <module>  pdb-script.py:8 __init__  
+--Call--
+-> def nop(_):
+ 4  pdb-script.py:29 <module>  pdb-script.py:8 __init__  pdb-script.py:2 nop  
+-> pass
+ 4  pdb-script.py:29 <module>  pdb-script.py:8 __init__  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 4  pdb-script.py:29 <module>  pdb-script.py:8 __init__  pdb-script.py:3 nop  
+-> self.bar()
+ 3  <string>:1 <module>  pdb-script.py:29 <module>  pdb-script.py:9 __init__  
+--Call--
+-> @classmethod
+ 4  pdb-script.py:29 <module>  pdb-script.py:9 __init__  pdb-script.py:13 bar  
+-> nop(cls.__name__)
+ 4  pdb-script.py:29 <module>  pdb-script.py:9 __init__  pdb-script.py:15 bar  
+--Call--
+-> def nop(_):
+ 5  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:2 nop  
+-> pass
+ 5  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 5  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:3 nop  
+--Return--
+-> nop(cls.__name__)
+ 4  pdb-script.py:29 <module>  pdb-script.py:9 __init__  pdb-script.py:15 bar  
+-> self.baz()
+ 3  <string>:1 <module>  pdb-script.py:29 <module>  pdb-script.py:10 __init__  
+--Call--
+-> @staticmethod
+ 4  pdb-script.py:29 <module>  pdb-script.py:10 __init__  pdb-script.py:17 baz  
+-> nop(1)
+ 4  pdb-script.py:29 <module>  pdb-script.py:10 __init__  pdb-script.py:19 baz  
+--Call--
+-> def nop(_):
+ 5  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:2 nop  
+-> pass
+ 5  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 5  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:3 nop  
+--Return--
+-> nop(1)
+ 4  pdb-script.py:29 <module>  pdb-script.py:10 __init__  pdb-script.py:19 baz  
+-> self.bra()
+ 3  <string>:1 <module>  pdb-script.py:29 <module>  pdb-script.py:11 __init__  
+--Call--
+-> def bra(self):
+ 4  pdb-script.py:29 <module>  pdb-script.py:11 __init__  pdb-script.py:21 bra  
+-> nop(self.__class__.__name__)
+ 4  pdb-script.py:29 <module>  pdb-script.py:11 __init__  pdb-script.py:22 bra  
+--Call--
+-> def nop(_):
+ 5  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:2 nop  
+-> pass
+ 5  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 5  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:3 nop  
+--Return--
+-> nop(self.__class__.__name__)
+ 4  pdb-script.py:29 <module>  pdb-script.py:11 __init__  pdb-script.py:22 bra  
+--Return--
+-> self.bra()
+ 3  <string>:1 <module>  pdb-script.py:29 <module>  pdb-script.py:11 __init__  
+-> Foo.bar()
+ 2  <string>:1 <module>  pdb-script.py:30 <module>  
+--Call--
+-> @classmethod
+ 3  <string>:1 <module>  pdb-script.py:30 <module>  pdb-script.py:13 bar  
+-> nop(cls.__name__)
+ 3  <string>:1 <module>  pdb-script.py:30 <module>  pdb-script.py:15 bar  
+--Call--
+-> def nop(_):
+ 4  pdb-script.py:30 <module>  pdb-script.py:15 bar  pdb-script.py:2 nop  
+-> pass
+ 4  pdb-script.py:30 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 4  pdb-script.py:30 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
+--Return--
+-> nop(cls.__name__)
+ 3  <string>:1 <module>  pdb-script.py:30 <module>  pdb-script.py:15 bar  
+-> Foo.baz()
+ 2  <string>:1 <module>  pdb-script.py:31 <module>  
+--Call--
+-> @staticmethod
+ 3  <string>:1 <module>  pdb-script.py:31 <module>  pdb-script.py:17 baz  
+-> nop(1)
+ 3  <string>:1 <module>  pdb-script.py:31 <module>  pdb-script.py:19 baz  
+--Call--
+-> def nop(_):
+ 4  pdb-script.py:31 <module>  pdb-script.py:19 baz  pdb-script.py:2 nop  
+-> pass
+ 4  pdb-script.py:31 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 4  pdb-script.py:31 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
+--Return--
+-> nop(1)
+ 3  <string>:1 <module>  pdb-script.py:31 <module>  pdb-script.py:19 baz  
+-> Foo.bra(f)
+ 2  <string>:1 <module>  pdb-script.py:32 <module>  
+--Call--
+-> def bra(self):
+ 3  <string>:1 <module>  pdb-script.py:32 <module>  pdb-script.py:21 bra  
+-> nop(self.__class__.__name__)
+ 3  <string>:1 <module>  pdb-script.py:32 <module>  pdb-script.py:22 bra  
+--Call--
+-> def nop(_):
+ 4  pdb-script.py:32 <module>  pdb-script.py:22 bra  pdb-script.py:2 nop  
+-> pass
+ 4  pdb-script.py:32 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 4  pdb-script.py:32 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
+--Return--
+-> nop(self.__class__.__name__)
+ 3  <string>:1 <module>  pdb-script.py:32 <module>  pdb-script.py:22 bra  
+-> f.bar()
+ 2  <string>:1 <module>  pdb-script.py:34 <module>  
+--Call--
+-> @classmethod
+ 3  <string>:1 <module>  pdb-script.py:34 <module>  pdb-script.py:13 bar  
+-> nop(cls.__name__)
+ 3  <string>:1 <module>  pdb-script.py:34 <module>  pdb-script.py:15 bar  
+--Call--
+-> def nop(_):
+ 4  pdb-script.py:34 <module>  pdb-script.py:15 bar  pdb-script.py:2 nop  
+-> pass
+ 4  pdb-script.py:34 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 4  pdb-script.py:34 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
+--Return--
+-> nop(cls.__name__)
+ 3  <string>:1 <module>  pdb-script.py:34 <module>  pdb-script.py:15 bar  
+-> f.baz()
+ 2  <string>:1 <module>  pdb-script.py:35 <module>  
+--Call--
+-> @staticmethod
+ 3  <string>:1 <module>  pdb-script.py:35 <module>  pdb-script.py:17 baz  
+-> nop(1)
+ 3  <string>:1 <module>  pdb-script.py:35 <module>  pdb-script.py:19 baz  
+--Call--
+-> def nop(_):
+ 4  pdb-script.py:35 <module>  pdb-script.py:19 baz  pdb-script.py:2 nop  
+-> pass
+ 4  pdb-script.py:35 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 4  pdb-script.py:35 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
+--Return--
+-> nop(1)
+ 3  <string>:1 <module>  pdb-script.py:35 <module>  pdb-script.py:19 baz  
+-> f.bra()
+ 2  <string>:1 <module>  pdb-script.py:36 <module>  
+--Call--
+-> def bra(self):
+ 3  <string>:1 <module>  pdb-script.py:36 <module>  pdb-script.py:21 bra  
+-> nop(self.__class__.__name__)
+ 3  <string>:1 <module>  pdb-script.py:36 <module>  pdb-script.py:22 bra  
+--Call--
+-> def nop(_):
+ 4  pdb-script.py:36 <module>  pdb-script.py:22 bra  pdb-script.py:2 nop  
+-> pass
+ 4  pdb-script.py:36 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 4  pdb-script.py:36 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
+--Return--
+-> nop(self.__class__.__name__)
+ 3  <string>:1 <module>  pdb-script.py:36 <module>  pdb-script.py:22 bra  
+-> brah()
+ 2  <string>:1 <module>  pdb-script.py:38 <module>  
+--Call--
+-> def brah():
+ 3  <string>:1 <module>  pdb-script.py:38 <module>  pdb-script.py:25 brah  
+-> nop('brah')
+ 3  <string>:1 <module>  pdb-script.py:38 <module>  pdb-script.py:26 brah  
+--Call--
+-> def nop(_):
+ 4  pdb-script.py:38 <module>  pdb-script.py:26 brah  pdb-script.py:2 nop  
+-> pass
+ 4  pdb-script.py:38 <module>  pdb-script.py:26 brah  pdb-script.py:3 nop  
+--Return--
+-> pass
+ 4  pdb-script.py:38 <module>  pdb-script.py:26 brah  pdb-script.py:3 nop  
+--Return--
+-> nop('brah')
+ 3  <string>:1 <module>  pdb-script.py:38 <module>  pdb-script.py:26 brah  
diff --git a/tests/test_shells/outputs/rc.daemon.ok b/tests/test_shells/outputs/rc.daemon.ok
new file mode 100644
index 0000000..c49b9a3
--- /dev/null
+++ b/tests/test_shells/outputs/rc.daemon.ok
@@ -0,0 +1,24 @@
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV = '/home/foo/.virtenvs/some-virtual-environment'
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV = ()
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+PID
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `{cat pid} ; sleep 1s
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd $DIR1
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m  cd ../$DIR2
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  false
+  HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  1  set_theme_option default_leftonly.segment_data.hostname.display false
+ USER   BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.segment_data.user.display false
+  BRANCH  …  shell  3rd  «Unicode!»  echo `{
+                                           echo Continuation!
+                                          }
+Continuation!
diff --git a/tests/test_shells/outputs/rc.nodaemon.ok b/tests/test_shells/outputs/rc.nodaemon.ok
new file mode 100644
index 0000000..28376cb
--- /dev/null
+++ b/tests/test_shells/outputs/rc.nodaemon.ok
@@ -0,0 +1,24 @@
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV = '/home/foo/.virtenvs/some-virtual-environment'
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV = ()
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+PID
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `{cat pid} ; sleep 1s
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd $DIR1
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m  cd ../$DIR2
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  false
+  HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  1  set_theme_option default_leftonly.segment_data.hostname.display false
+ USER   BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.segment_data.user.display false
+  BRANCH  …  shell  3rd  «Unicode!»  echo `{
+    echo Continuation!
+   }
+Continuation!
diff --git a/tests/test_shells/outputs/tcsh.ok b/tests/test_shells/outputs/tcsh.ok
new file mode 100644
index 0000000..07089bf
--- /dev/null
+++ b/tests/test_shells/outputs/tcsh.ok
@@ -0,0 +1,17 @@
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^H  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  %%  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`  
+  HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  
diff --git a/tests/test_shells/outputs/zsh.daemon.ok b/tests/test_shells/outputs/zsh.daemon.ok
new file mode 100644
index 0000000..32e80d8
--- /dev/null
+++ b/tests/test_shells/outputs/zsh.daemon.ok
@@ -0,0 +1,52 @@
+
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment"
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+[1] PID
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s
+[1] + terminated bgscript.sh
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd "$DIR1"
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bindkey -v ; set_theme default
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd   COMMND   HOSTNAME  USER  …  tmp  shell  3rd  
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd  
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd  echo abc
+abc
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd  false
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd  set_theme_option default.segment_data.hostname.display false
+ INSERT  USER  …  tmp  shell  3rd  set_theme_option default.segment_data.user.display false
+ INSERT  …  tmp  shell  3rd  select abc in def ghi jkl
+ select                          do
+ select                           echo $abc
+ select                           break
+ select                          done
+1) def 2) ghi 3) jkl
+                 Select variant  1
+def
+ INSERT  …  tmp  shell  3rd  cd .
+ INSERT  …  tmp  shell  3rd  cd .
+ INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above "$ABOVE_LEFT"
+ INSERT  …  tmp  shell  3rd  export DISPLAYED_ENV_VAR=foo
+ foo  
+ INSERT  …  tmp  shell  3rd  unset DISPLAYED_ENV_VAR
+ INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above "$ABOVE_FULL"
+                                                                                                                                                                                                                                                                                                           
+ INSERT  …  tmp  shell  3rd  export DISPLAYED_ENV_VAR=foo
+                                                                                                                                                                                                                                                                                                      foo 
+ INSERT  …  tmp  shell  3rd  unset DISPLAYED_ENV_VAR
+                                                                                                                                                                                                                                                                                                           
+ INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above
+ INSERT  …  tmp  shell  3rd  hash -d foo=$PWD:h ; cd .
+ INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC
+ INSERT $ABC~foo  3rd $ABCtrue
diff --git a/tests/test_shells/outputs/zsh.nodaemon.ok b/tests/test_shells/outputs/zsh.nodaemon.ok
new file mode 100644
index 0000000..3aa285f
--- /dev/null
+++ b/tests/test_shells/outputs/zsh.nodaemon.ok
@@ -0,0 +1,52 @@
+
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment"
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+[1] PID
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s
+[1] + terminated bgscript.sh
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd "$DIR1"
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bindkey -v ; set_theme default
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd   COMMND   HOSTNAME  USER  …  tmp  shell  3rd  
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd  
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd  echo abc
+abc
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd  false
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd  set_theme_option default.segment_data.hostname.display false
+ INSERT  USER  …  tmp  shell  3rd  set_theme_option default.segment_data.user.display false
+ INSERT  …  tmp  shell  3rd  select abc in def ghi jkl
+ select  do
+ select   echo $abc
+ select   break
+ select  done
+1) def 2) ghi 3) jkl
+ Select variant  1
+def
+ INSERT  …  tmp  shell  3rd  cd .
+ INSERT  …  tmp  shell  3rd  cd .
+ INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above "$ABOVE_LEFT"
+ INSERT  …  tmp  shell  3rd  export DISPLAYED_ENV_VAR=foo
+ foo  
+ INSERT  …  tmp  shell  3rd  unset DISPLAYED_ENV_VAR
+ INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above "$ABOVE_FULL"
+                                                                                                                                                                                                                                                                                                           
+ INSERT  …  tmp  shell  3rd  export DISPLAYED_ENV_VAR=foo
+                                                                                                                                                                                                                                                                                                      foo 
+ INSERT  …  tmp  shell  3rd  unset DISPLAYED_ENV_VAR
+                                                                                                                                                                                                                                                                                                           
+ INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above
+ INSERT  …  tmp  shell  3rd  hash -d foo=$PWD:h ; cd .
+ INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC
+ INSERT $ABC~foo  3rd $ABCtrue
diff --git a/tests/test_shells/outputs/zsh.zpython.ok b/tests/test_shells/outputs/zsh.zpython.ok
new file mode 100644
index 0000000..32e80d8
--- /dev/null
+++ b/tests/test_shells/outputs/zsh.zpython.ok
@@ -0,0 +1,52 @@
+
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git
+  HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment"
+  HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh
+[1] PID
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s
+[1] + terminated bgscript.sh
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd "$DIR1"
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"
+  HOSTNAME  USER   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]  cd ../'%%'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
+  HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  cd ..
+  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bindkey -v ; set_theme default
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd   COMMND   HOSTNAME  USER  …  tmp  shell  3rd  
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd  
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd  echo abc
+abc
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd  false
+ INSERT   HOSTNAME  USER  …  tmp  shell  3rd  set_theme_option default.segment_data.hostname.display false
+ INSERT  USER  …  tmp  shell  3rd  set_theme_option default.segment_data.user.display false
+ INSERT  …  tmp  shell  3rd  select abc in def ghi jkl
+ select                          do
+ select                           echo $abc
+ select                           break
+ select                          done
+1) def 2) ghi 3) jkl
+                 Select variant  1
+def
+ INSERT  …  tmp  shell  3rd  cd .
+ INSERT  …  tmp  shell  3rd  cd .
+ INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above "$ABOVE_LEFT"
+ INSERT  …  tmp  shell  3rd  export DISPLAYED_ENV_VAR=foo
+ foo  
+ INSERT  …  tmp  shell  3rd  unset DISPLAYED_ENV_VAR
+ INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above "$ABOVE_FULL"
+                                                                                                                                                                                                                                                                                                           
+ INSERT  …  tmp  shell  3rd  export DISPLAYED_ENV_VAR=foo
+                                                                                                                                                                                                                                                                                                      foo 
+ INSERT  …  tmp  shell  3rd  unset DISPLAYED_ENV_VAR
+                                                                                                                                                                                                                                                                                                           
+ INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above
+ INSERT  …  tmp  shell  3rd  hash -d foo=$PWD:h ; cd .
+ INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC
+ INSERT $ABC~foo  3rd $ABCtrue
diff --git a/tests/test_shells/pdb-main.py b/tests/test_shells/pdb-main.py
new file mode 100644
index 0000000..37af785
--- /dev/null
+++ b/tests/test_shells/pdb-main.py
@@ -0,0 +1,24 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+import pdb
+import os
+import sys
+
+from powerline.bindings.pdb import use_powerline_prompt
+
+
+@use_powerline_prompt
+class Pdb(pdb.Pdb):
+ pass
+
+
+p = Pdb()
+
+
+script = os.path.join(os.path.dirname(__file__), 'pdb-script.py')
+with open(script, 'r') as fd:
+ code = compile(fd.read(), script, 'exec')
+
+
+p.run('exec(code)', globals={'code': code})
diff --git a/tests/test_shells/pdb-script.py b/tests/test_shells/pdb-script.py
new file mode 100644
index 0000000..40db5e8
--- /dev/null
+++ b/tests/test_shells/pdb-script.py
@@ -0,0 +1,38 @@
+# vim:fileencoding=utf-8:noet
+def nop(_):
+ pass
+
+
+class Foo(object):
+ def __init__(self):
+ nop('__init__')
+ self.bar()
+ self.baz()
+ self.bra()
+
+ @classmethod
+ def bar(cls):
+ nop(cls.__name__)
+
+ @staticmethod
+ def baz():
+ nop(1)
+
+ def bra(self):
+ nop(self.__class__.__name__)
+
+
+def brah():
+ nop('brah')
+
+
+f = Foo()
+Foo.bar()
+Foo.baz()
+Foo.bra(f)
+
+f.bar()
+f.baz()
+f.bra()
+
+brah()
diff --git a/tests/test_shells/postproc.py b/tests/test_shells/postproc.py
new file mode 100755
index 0000000..7926155
--- /dev/null
+++ b/tests/test_shells/postproc.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+import os
+import socket
+import sys
+import codecs
+import platform
+import re
+
+
+test_root = os.environ['TEST_ROOT']
+test_type = sys.argv[1]
+test_client = sys.argv[2]
+shell = sys.argv[3]
+fname = os.path.join(test_root, '.'.join((shell, test_type, test_client, 'full.log')))
+new_fname = os.path.join(test_root, '.'.join((shell, test_type, test_client, 'log')))
+pid_fname = os.path.join(test_root, '3rd', 'pid')
+
+is_pypy = platform.python_implementation() == 'PyPy'
+
+
+try:
+ with open(pid_fname, 'r') as P:
+ pid = P.read().strip()
+except IOError:
+ pid = None
+hostname = socket.gethostname()
+user = os.environ['USER']
+
+REFS_RE = re.compile(r'^\[\d+ refs\]\n')
+IPYPY_DEANSI_RE = re.compile(r'\033(?:\[(?:\?\d+[lh]|[^a-zA-Z]+[a-ln-zA-Z])|[=>])')
+ZSH_HL_RE = re.compile(r'\033\[\?\d+[hl]')
+
+start_str = 'cd "$TEST_ROOT"/3rd'
+if shell == 'pdb':
+ start_str = 'class Foo(object):'
+
+with codecs.open(fname, 'r', encoding='utf-8') as R:
+ with codecs.open(new_fname, 'w', encoding='utf-8') as W:
+ found_cd = False
+ i = -1
+ for line in (R if shell != 'fish' else R.read().split('\n')):
+ i += 1
+ if not found_cd:
+ found_cd = (start_str in line)
+ continue
+ if 'true is the last line' in line:
+ break
+ line = line.translate({
+ ord('\r'): None
+ })
+ if REFS_RE.match(line):
+ continue
+ line = line.replace(hostname, 'HOSTNAME')
+ line = line.replace(user, 'USER')
+ if pid is not None:
+ line = line.replace(pid, 'PID')
+ if shell == 'zsh':
+ line = line.replace('\033[0m\033[23m\033[24m\033[J', '')
+ line = ZSH_HL_RE.subn('', line)[0]
+ elif shell == 'fish':
+ res = ''
+ try:
+ while line.index('\033[0;'):
+ start = line.index('\033[0;')
+ end = line.index('\033[0m', start)
+ res += line[start:end + 4] + '\n'
+ line = line[end + 4:]
+ except ValueError:
+ pass
+ line = res
+ elif shell == 'tcsh':
+ try:
+ start = line.index('\033[0;')
+ end = line.index(' ', start)
+ line = line[start:end] + '\n'
+ except ValueError:
+ line = ''
+ elif shell == 'mksh':
+ # Output is different in travis: on my machine I see full
+ # command, in travis it is truncated just after `true`.
+ if line.startswith('[1] + Terminated'):
+ line = '[1] + Terminated bash -c ...\n'
+ elif shell == 'dash':
+ # Position of this line is not stable: it may go both before and
+ # after the next line
+ if line.startswith('[1] + Terminated'):
+ continue
+ elif shell == 'ipython' and is_pypy:
+ try:
+ end_idx = line.rindex('\033[0m')
+ try:
+ idx = line[:end_idx].rindex('\033[1;1H')
+ except ValueError:
+ idx = line[:end_idx].rindex('\033[?25h')
+ line = line[idx + len('\033[1;1H'):]
+ except ValueError:
+ pass
+ try:
+ data_end_idx = line.rindex('\033[1;1H')
+ line = line[:data_end_idx] + '\n'
+ except ValueError:
+ pass
+ if line == '\033[1;1H\n':
+ continue
+ was_empty = line == '\n'
+ line = IPYPY_DEANSI_RE.subn('', line)[0]
+ if line == '\n' and not was_empty:
+ line = ''
+ elif shell == 'rc':
+ if line == 'read() failed: Connection reset by peer\n':
+ line = ''
+ elif shell == 'pdb':
+ if is_pypy:
+ if line == '\033[?1h\033=\033[?25l\033[1A\n':
+ line = ''
+ line = IPYPY_DEANSI_RE.subn('', line)[0]
+ if line == '\n':
+ line = ''
+ if line.startswith(('>',)):
+ line = ''
+ elif line == '-> self.quitting = 1\n':
+ line = '-> self.quitting = True\n'
+ elif line == '\n':
+ line = ''
+ if line == '-> self.quitting = True\n':
+ break
+ W.write(line)
diff --git a/tests/test_shells/run_script.py b/tests/test_shells/run_script.py
new file mode 100755
index 0000000..2eebca1
--- /dev/null
+++ b/tests/test_shells/run_script.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+import argparse
+import os
+import re
+
+from time import sleep
+from subprocess import check_call
+from io import BytesIO
+
+import pexpect
+
+
+def get_argparser(ArgumentParser=argparse.ArgumentParser):
+ parser = ArgumentParser(description='Run powerline shell test using pexpect')
+ parser.add_argument('--wait-for-echo', action='store_true', help='Wait until the input is echoed back.')
+ parser.add_argument('--type', metavar='TYPE', help='Test type (daemon, nodaemon, …).')
+ parser.add_argument('--client', metavar='CLIENT', help='Type of the client used (C, shell, zpython, …).')
+ parser.add_argument('--shell', metavar='SHELL', help='Shell name.')
+ parser.add_argument('command', nargs=argparse.REMAINDER, metavar='COMMAND',
+ help='Command to run and its argument.')
+ return parser
+
+
+def main():
+ test_root = os.environ['TEST_ROOT']
+ parser = get_argparser()
+ args = parser.parse_args()
+
+ shell = args.shell or args.command[0]
+ test_type = args.type or shell
+ test_client = args.client or test_type
+
+ log_file_base = '{0}.{1}.{2}'.format(shell, test_type, test_client)
+ full_log_file_name = os.path.join(test_root, '{0}.full.log'.format(log_file_base))
+
+ local_paths = [
+ os.path.abspath(os.path.join(test_root, 'path')),
+ os.path.abspath('scripts'),
+ ]
+
+ if test_type == 'fish':
+ local_paths += ['/usr/bin', '/bin']
+
+ python_paths = os.environ.get('PYTHONPATH', '')
+ if python_paths:
+ python_paths = ':' + python_paths
+ python_paths = os.path.abspath('.') + python_paths
+
+ environ = {
+ 'LANG': 'en_US.UTF-8',
+ 'PATH': os.pathsep.join(local_paths),
+ 'TERM': 'screen-256color',
+ 'DIR1': os.environ['DIR1'],
+ 'DIR2': os.environ['DIR2'],
+ 'XDG_CONFIG_HOME': os.path.abspath(os.path.join(test_root, 'fish_home')),
+ 'IPYTHONDIR': os.path.abspath(os.path.join(test_root, 'ipython_home')),
+ 'PYTHONPATH': python_paths,
+ 'POWERLINE_CONFIG_OVERRIDES': os.environ.get('POWERLINE_CONFIG_OVERRIDES', ''),
+ 'POWERLINE_THEME_OVERRIDES': os.environ.get('POWERLINE_THEME_OVERRIDES', ''),
+ 'POWERLINE_CONFIG_PATHS': os.path.abspath(os.path.join('powerline', 'config_files')),
+ 'POWERLINE_COMMAND_ARGS': os.environ.get('POWERLINE_COMMAND_ARGS', ''),
+ 'POWERLINE_COMMAND': os.environ.get('POWERLINE_COMMAND', ''),
+ 'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH', ''),
+ 'TEST_ROOT': test_root,
+ }
+
+ os.environ['PATH'] = environ['PATH']
+
+ if test_type == 'daemon':
+ environ['POWERLINE_SHELL_CONTINUATION'] = '1'
+ environ['POWERLINE_SHELL_SELECT'] = '1'
+
+ if test_type != 'zpython' and shell == 'zsh':
+ environ['POWERLINE_NO_ZSH_ZPYTHON'] = '1'
+
+ sio = BytesIO()
+
+ child = pexpect.spawn(
+ args.command[0],
+ args.command[1:],
+ env=environ,
+ logfile=sio,
+ timeout=30,
+ )
+ child.expect(re.compile(b'.*'))
+ sleep(0.5)
+ child.setwinsize(1, 300)
+
+ with open(os.path.join('tests', 'test_shells', 'inputs', shell), 'rb') as F:
+ if not args.wait_for_echo:
+ child.send(F.read())
+ else:
+ for line in F:
+ child.send(line)
+ sleep(1)
+ # TODO Implement something more smart
+
+ with open(full_log_file_name, 'wb') as LF:
+ while True:
+ try:
+ s = child.read_nonblocking(1000)
+ except pexpect.TIMEOUT:
+ break
+ except pexpect.EOF:
+ break
+ else:
+ LF.write(s)
+
+ child.close(force=True)
+
+ check_call([
+ os.path.join(test_root, 'path', 'python'),
+ os.path.join('tests', 'test_shells', 'postproc.py'),
+ test_type, test_client, shell
+ ])
+ pidfile = os.path.join(test_root, '3rd', 'pid')
+ if os.path.exists(pidfile):
+ os.unlink(pidfile)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/test_shells/test.sh b/tests/test_shells/test.sh
new file mode 100755
index 0000000..4494302
--- /dev/null
+++ b/tests/test_shells/test.sh
@@ -0,0 +1,491 @@
+#!/bin/sh
+. tests/shlib/common.sh
+
+enter_suite shell final
+
+if test $# -eq 0 ; then
+ FAST=1
+fi
+ONLY_SHELL="$1"
+ONLY_TEST_TYPE="$2"
+ONLY_TEST_CLIENT="$3"
+
+export PYTHON
+
+if test "$ONLY_SHELL" = "--help" ; then
+cat << EOF
+Usage:
+ $0 [[[ONLY_SHELL | ""] (ONLY_TEST_TYPE | "")] (ONLY_TEST_CLIENT | "")]
+
+ONLY_SHELL: execute only tests for given shell
+ONLY_TEST_TYPE: execute only "daemon" or "nodaemon" tests
+ONLY_TEST_CLIENT: use only given test client (one of C, python, render, shell)
+EOF
+exit 0
+fi
+
+check_screen_log() {
+ TEST_TYPE="$1"
+ TEST_CLIENT="$2"
+ SH="$3"
+ if test -e "$ROOT/tests/test_shells/outputs/${SH}.${TEST_TYPE}.ok" ; then
+ diff -a -u "$ROOT/tests/test_shells/outputs/${SH}.${TEST_TYPE}.ok" \
+ "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log"
+ return $?
+ elif test -e "$ROOT/tests/test_shells/outputs/${SH}.ok" ; then
+ diff -a -u "$ROOT/tests/test_shells/outputs/${SH}.ok" \
+ "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log"
+ return $?
+ else
+ cat "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log"
+ return 1
+ fi
+}
+
+# HACK: get newline for use in strings given that "\n" and $'' do not work.
+NL="$(printf '\nE')"
+NL="${NL%E}"
+
+print_full_output() {
+ TEST_TYPE="$1"
+ TEST_CLIENT="$2"
+ SH="$3"
+ echo "Full output:"
+ echo '============================================================'
+ cat "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log"
+ echo
+ echo '____________________________________________________________'
+ if test "$POWERLINE_TEST_NO_CAT_V" != "1" ; then
+ echo "Full output (cat -v):"
+ echo '============================================================'
+ cat -v "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log"
+ echo
+ echo '____________________________________________________________'
+ fi
+}
+
+do_run_test() {
+ TEST_TYPE="$1"
+ shift
+ TEST_CLIENT="$1"
+ shift
+ SH="$1"
+
+ local wait_for_echo_arg=
+ if ( \
+ test "${SH}" = "dash" \
+ || ( \
+ test "${SH}" = "pdb" \
+ && ( \
+ ( \
+ test "$PYTHON_VERSION_MAJOR" -eq 3 \
+ && test "$PYTHON_VERSION_MINOR" -eq 2 \
+ && test "$PYTHON_IMPLEMENTATION" = "CPython" \
+ ) \
+ || test "$PYTHON_IMPLEMENTATION" = "PyPy" \
+ ) \
+ ) \
+ || ( \
+ test "${SH}" = "ipython" \
+ && test "$("${PYTHON}" -mIPython --version | head -n1 | cut -d. -f1)" -ge 5 \
+ ) \
+ ) ; then
+ wait_for_echo_arg="--wait-for-echo"
+ fi
+ "${PYTHON}" tests/test_shells/run_script.py \
+ $wait_for_echo_arg --type=${TEST_TYPE} --client=${TEST_CLIENT} --shell=${SH} \
+ "$@"
+ if ! check_screen_log ${TEST_TYPE} ${TEST_CLIENT} ${SH} ; then
+ echo '____________________________________________________________'
+ if test "$POWERLINE_TEST_NO_CAT_V" != "1" ; then
+ # Repeat the diff to make it better viewable in travis output
+ echo "Diff (cat -v):"
+ echo '============================================================'
+ check_screen_log ${TEST_TYPE} ${TEST_CLIENT} ${SH} | cat -v
+ echo '____________________________________________________________'
+ fi
+ echo -n "Failed ${SH}. "
+ print_full_output ${TEST_TYPE} ${TEST_CLIENT} ${SH}
+ case "${SH}" in
+ *ksh)
+ "$TEST_ROOT/path/${SH}" -c 'echo ${KSH_VERSION}'
+ ;;
+ dash)
+ # ?
+ ;;
+ busybox)
+ busybox --help
+ ;;
+ *)
+ "$TEST_ROOT/path/${SH}" --version
+ ;;
+ esac
+ if which dpkg >/dev/null ; then
+ dpkg -s ${SH}
+ fi
+ return 1
+ fi
+ return 0
+}
+
+run_test() {
+ TEST_TYPE="$1"
+ TEST_CLIENT="$2"
+ SH="$3"
+ local attempts=3
+ if test -n "$ONLY_SHELL$ONLY_TEST_TYPE$ONLY_TEST_CLIENT" ; then
+ attempts=1
+ fi
+ while test $attempts -gt 0 ; do
+ rm -f "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log"
+ rm -f "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log"
+ do_run_test "$@" && return 0
+ attempts=$(( attempts - 1 ))
+ done
+ return 1
+}
+
+make_test_root
+
+git init "$TEST_ROOT/3rd"
+git --git-dir="$TEST_ROOT/3rd/.git" checkout -b BRANCH
+export DIR1=""
+export DIR2=""
+mkdir "$TEST_ROOT/3rd/$DIR1"
+mkdir "$TEST_ROOT/3rd/$DIR2"
+mkdir "$TEST_ROOT"/3rd/'\[\]'
+mkdir "$TEST_ROOT"/3rd/'%%'
+mkdir "$TEST_ROOT"/3rd/'#[bold]'
+mkdir "$TEST_ROOT"/3rd/'(echo)'
+mkdir "$TEST_ROOT"/3rd/'$(echo)'
+mkdir "$TEST_ROOT"/3rd/'`echo`'
+mkdir "$TEST_ROOT"/3rd/'«Unicode!»'
+
+mkdir "$TEST_ROOT/fish_home"
+mkdir "$TEST_ROOT/fish_home/fish"
+mkdir "$TEST_ROOT/fish_home/fish/generated_completions"
+cp -r "$ROOT/tests/test_shells/ipython_home" "$TEST_ROOT"
+
+mkdir "$TEST_ROOT/path"
+ln -s "$(which "${PYTHON}")" "$TEST_ROOT/path/python"
+ln -s "$(which env)" "$TEST_ROOT/path"
+ln -s "$(which git)" "$TEST_ROOT/path"
+ln -s "$(which sleep)" "$TEST_ROOT/path"
+ln -s "$(which cat)" "$TEST_ROOT/path"
+ln -s "$(which false)" "$TEST_ROOT/path"
+ln -s "$(which true)" "$TEST_ROOT/path"
+ln -s "$(which kill)" "$TEST_ROOT/path"
+ln -s "$(which echo)" "$TEST_ROOT/path"
+ln -s "$(which which)" "$TEST_ROOT/path"
+ln -s "$(which dirname)" "$TEST_ROOT/path"
+ln -s "$(which wc)" "$TEST_ROOT/path"
+ln -s "$(which stty)" "$TEST_ROOT/path"
+ln -s "$(which cut)" "$TEST_ROOT/path"
+ln -s "$(which bc)" "$TEST_ROOT/path"
+ln -s "$(which expr)" "$TEST_ROOT/path"
+ln -s "$(which mktemp)" "$TEST_ROOT/path"
+ln -s "$(which grep)" "$TEST_ROOT/path"
+ln -s "$(which sed)" "$TEST_ROOT/path"
+ln -s "$(which rm)" "$TEST_ROOT/path"
+ln -s "$(which tr)" "$TEST_ROOT/path"
+ln -s "$(which uname)" "$TEST_ROOT/path"
+ln -s "$(which test)" "$TEST_ROOT/path"
+ln -s "$(which pwd)" "$TEST_ROOT/path"
+ln -s "$(which hostname)" "$TEST_ROOT/path"
+ln -s "$ROOT/tests/test_shells/bgscript.sh" "$TEST_ROOT/path"
+ln -s "$ROOT/tests/test_shells/waitpid.sh" "$TEST_ROOT/path"
+if which socat ; then
+ ln -s "$(which socat)" "$TEST_ROOT/path"
+fi
+for pexe in powerline powerline-config powerline-render powerline.sh powerline.py ; do
+ if test -e "$ROOT/scripts/$pexe" ; then
+ ln -s "$ROOT/scripts/$pexe" "$TEST_ROOT/path"
+ elif test -e client/$pexe ; then
+ ln -s "$ROOT/client/$pexe" "$TEST_ROOT/path"
+ elif which $pexe ; then
+ ln -s "$(which $pexe)" "$TEST_ROOT/path"
+ else
+ echo "Executable $pexe was not found"
+ exit 1
+ fi
+done
+
+ln -s python "$TEST_ROOT/path/pdb"
+PDB_PYTHON=pdb
+ln -s python "$TEST_ROOT/path/ipython"
+IPYTHON_PYTHON=ipython
+
+if test -z "$POWERLINE_RC_EXE" ; then
+ if which rc-status >/dev/null ; then
+ # On Gentoo `rc` executable is from OpenRC. Thus app-shells/rc instals
+ # `rcsh` executable.
+ POWERLINE_RC_EXE=rcsh
+ else
+ POWERLINE_RC_EXE=rc
+ fi
+fi
+
+if which "$POWERLINE_RC_EXE" >/dev/null ; then
+ ln -s "$(which $POWERLINE_RC_EXE)" "$TEST_ROOT/path/rc"
+fi
+
+exes="bash zsh busybox tcsh mksh"
+
+if test "$TRAVIS" != "true" ; then
+ # For some reason fish does not work on travis
+ exes="$exes fish"
+fi
+
+# dash has some problems with job control
+#exes="$exes dash"
+
+for exe in $exes ; do
+ if which $exe >/dev/null ; then
+ if test "$exe" = "fish" ; then
+ fish_version="$(fish --version 2>&1)"
+ fish_version="${fish_version##* }"
+ fish_version_major="${fish_version%%.*}"
+ if test "$fish_version_major" != "$fish_version" ; then
+ # No dot is in development version compiled by bot-ci
+ fish_version_minor="${fish_version#*.}"
+ fish_version_patch="${fish_version_minor#*.}"
+ fish_version_dev="${fish_version_patch#*-}"
+ if test "$fish_version_dev" = "$fish_version_patch" ; then
+ fish_version_dev=""
+ fi
+ fish_version_minor="${fish_version_minor%%.*}"
+ fish_version_patch="${fish_version_patch%%-*}"
+ if test $fish_version_major -lt 2 || ( \
+ test $fish_version_major -eq 2 && (\
+ test $fish_version_minor -lt 1 || (\
+ test $fish_version_minor -eq 1 &&
+ test $fish_version_patch -lt 2 && \
+ test -z "$fish_version_dev"
+ ) \
+ ) \
+ ) ; then
+ continue
+ fi
+ fi
+ fi
+ ln -s "$(which $exe)" "$TEST_ROOT/path"
+ fi
+done
+
+mkdir "$TEST_ROOT/home"
+export HOME="$TEST_ROOT/home"
+
+unset ENV
+
+export ADDRESS="powerline-ipc-test-$$"
+export PYTHON
+echo "Powerline address: $ADDRESS"
+
+check_test_client() {
+ local executable="$1"
+ local client_type="$2"
+ local actual_mime_type="$(
+ file --mime-type --brief --dereference "$TEST_ROOT/path/$executable" \
+ | cut -d/ -f1
+ )"
+ local expected_mime_type
+ case "$client_type" in
+ C) expected_mime_type="application/x-executable" ;;
+ python) expected_mime_type="text/x-python" ;;
+ render) expected_mime_type="text/x-python" ;;
+ shell) expected_mime_type="text/x-shellscript" ;;
+ esac
+ expected_mime_type="${expected_mime_type%/*}"
+ if test "$expected_mime_type" != "$actual_mime_type" ; then
+ fail "MIME-$executable" "M" "Expected $executable to have MIME type $expected_mime_type, but got $actual_mime_type"
+ fi
+}
+
+if ( \
+ test -z "${ONLY_SHELL}" \
+ || test "${ONLY_SHELL%sh}" != "${ONLY_SHELL}" \
+ || test "${ONLY_SHELL}" = "busybox" \
+ || test "${ONLY_SHELL}" = "rc" \
+) ; then
+ scripts/powerline-config shell command
+
+ for TEST_TYPE in "daemon" "nodaemon" ; do
+ if test -n "$ONLY_TEST_TYPE" && test "$ONLY_TEST_TYPE" != "$TEST_TYPE"
+ then
+ continue
+ fi
+ if test "$FAST" = 1 ; then
+ if test $TEST_TYPE = daemon ; then
+ VARIANTS=3
+ else
+ VARIANTS=4
+ fi
+ EXETEST="$(( ${RANDOM:-`date +%N | sed s/^0*//`} % $VARIANTS ))"
+ echo "Execute tests: $EXETEST"
+ fi
+
+ if test $TEST_TYPE = daemon ; then
+ sh -c '
+ echo $$ > "$TEST_ROOT/daemon_pid"
+ exec "$PYTHON" ./scripts/powerline-daemon -s"$ADDRESS" -f >"$TEST_ROOT/daemon_log" 2>&1
+ ' &
+ fi
+ echo "> Testing $TEST_TYPE"
+ I=-1
+ for POWERLINE_COMMAND in \
+ powerline \
+ powerline-render \
+ powerline.py \
+ powerline.sh
+ do
+ case "$POWERLINE_COMMAND" in
+ powerline) TEST_CLIENT=C ;;
+ powerline-render) TEST_CLIENT=render ;;
+ powerline.py) TEST_CLIENT=python ;;
+ powerline.sh) TEST_CLIENT=shell ;;
+ esac
+ check_test_client "$POWERLINE_COMMAND" $TEST_CLIENT
+ if test "$TEST_CLIENT" = render && test "$TEST_TYPE" = daemon ; then
+ continue
+ fi
+ I="$(( I + 1 ))"
+ if test "$TEST_CLIENT" = "C" && ! test -x "$ROOT/scripts/powerline"
+ then
+ if which powerline >/dev/null ; then
+ POWERLINE_COMMAND=powerline
+ else
+ continue
+ fi
+ fi
+ if ( \
+ test "$TEST_CLIENT" = "shell" \
+ && ! test -x "$TEST_ROOT/path/socat" \
+ ) ; then
+ continue
+ fi
+ if ( \
+ test -n "$ONLY_TEST_CLIENT" \
+ && test "$TEST_CLIENT" != "$ONLY_TEST_CLIENT" \
+ ) ; then
+ continue
+ fi
+ export POWERLINE_COMMAND_ARGS="--socket $ADDRESS"
+ export POWERLINE_COMMAND="$POWERLINE_COMMAND"
+ echo ">> powerline command is ${POWERLINE_COMMAND:-empty}"
+ J=-1
+ for TEST_COMMAND in \
+ "bash --norc --noprofile -i" \
+ "zsh -f -i" \
+ "fish -i" \
+ "tcsh -f -i" \
+ "busybox ash -i" \
+ "mksh -i" \
+ "dash -i" \
+ "rc -i -p"
+ do
+ J="$(( J + 1 ))"
+ if test "$FAST" = 1 ; then
+ if test $(( (I + J) % $VARIANTS )) -ne $EXETEST ; then
+ continue
+ fi
+ fi
+ SH="${TEST_COMMAND%% *}"
+ if test -n "$ONLY_SHELL" && test "$ONLY_SHELL" != "$SH" ; then
+ continue
+ fi
+ if ! test -x "$TEST_ROOT/path/$SH" ; then
+ continue
+ fi
+ echo ">>> $(readlink "$TEST_ROOT/path/$SH")"
+ if ! run_test $TEST_TYPE $TEST_CLIENT $TEST_COMMAND ; then
+ fail "$SH-$TEST_TYPE-$TEST_CLIENT:test" F \
+ "Failed checking $TEST_COMMAND"
+ fi
+ done
+ done
+ if test $TEST_TYPE = daemon ; then
+ "$PYTHON" ./scripts/powerline-daemon -s"$ADDRESS" -k
+ wait $(cat "$TEST_ROOT/daemon_pid")
+ if ! test -z "$(cat "$TEST_ROOT/daemon_log")" ; then
+ echo '____________________________________________________________'
+ echo "Daemon log:"
+ echo '============================================================'
+ cat "$TEST_ROOT/daemon_log"
+ fail "$SH-$TEST_TYPE-$TEST_CLIENT:log" E \
+ "Non-empty daemon log for ${TEST_COMMAND}"
+ fi
+ fi
+ done
+fi
+
+if "$PYTHON" scripts/powerline-daemon -s"$ADDRESS" \
+ > "$TEST_ROOT/daemon_log_2" 2>&1
+then
+ sleep 1
+ "$PYTHON" scripts/powerline-daemon -s"$ADDRESS" -k
+else
+ fail "daemon:run" F "Daemon exited with status $?"
+fi
+
+if ! test -z "$(cat "$TEST_ROOT/daemon_log_2")" ; then
+ echo '____________________________________________________________'
+ echo "Daemon log (2nd):"
+ echo '============================================================'
+ cat "$TEST_ROOT/daemon_log_2"
+ fail "daemon:log" E "Daemon run with non-empty log"
+fi
+
+if ( test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "zsh" ) \
+ && ( test -z "${ONLY_TEST_TYPE}" || test "${ONLY_TEST_TYPE}" = "zpython" ) \
+ && "$TEST_ROOT/path/zsh" "$ROOT/tests/test_shells/zsh_test_script.zsh"
+then
+ echo "> zpython"
+ if ! run_test zpython zpython zsh -f -i ; then
+ fail "zsh-zpython:test" F "Failed checking zsh -f -i"
+ fi
+fi
+
+if test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "pdb" ; then
+ if test "$PYTHON_IMPLEMENTATION" != "PyPy" ; then
+ if test -z "${ONLY_TEST_TYPE}" || test "${ONLY_TEST_TYPE}" = "subclass"
+ then
+ echo "> pdb subclass"
+ if ! run_test subclass python $PDB_PYTHON \
+ "$ROOT/tests/test_shells/pdb-main.py"
+ then
+ fail --allow-failure "pdb-subclass:test" F \
+ "Failed checking $PDB_PYTHON $ROOT/tests/test_shells/pdb-main.py"
+ fi
+ fi
+ if test -z "${ONLY_TEST_TYPE}" || test "${ONLY_TEST_TYPE}" = "module" ; then
+ echo "> pdb module"
+ MODULE="powerline.bindings.pdb"
+ if test "$PYTHON_MM" = "2.6" ; then
+ MODULE="powerline.bindings.pdb.__main__"
+ fi
+ if ! run_test module python "$PDB_PYTHON" -m"$MODULE" \
+ "$ROOT/tests/test_shells/pdb-script.py"
+ then
+ fail --allow-failure "pdb-module:test" F \
+ "Failed checking $PDB_PYTHON -m$MODULE $ROOT/tests/test_shells/pdb-script"
+ fi
+ fi
+ fi
+fi
+
+if test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "ipython" ; then
+ if "${PYTHON}" -c "try: import IPython${NL}except ImportError: raise SystemExit(1)" ; then
+ # Define some overrides which should be ignored by IPython.
+ export POWERLINE_CONFIG_OVERRIDES='common.term_escape_style=fbterm'
+ export POWERLINE_THEME_OVERRIDES='in.segments.left=[]'
+ echo "> ipython"
+ if ! run_test ipython ipython ${IPYTHON_PYTHON} -mIPython ; then
+ # Do not allow ipython tests to spoil the build
+ fail --allow-failure "ipython:test" F "Failed checking ${IPYTHON_PYTHON} -mIPython"
+ fi
+ unset POWERLINE_THEME_OVERRIDES
+ unset POWERLINE_CONFIG_OVERRIDES
+ fi
+fi
+
+exit_suite
diff --git a/tests/test_shells/waitpid.sh b/tests/test_shells/waitpid.sh
new file mode 100755
index 0000000..8d98e21
--- /dev/null
+++ b/tests/test_shells/waitpid.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+while ! test -e pid ; do
+ sleep 0.1s
+done
diff --git a/tests/test_shells/zsh_test_script.zsh b/tests/test_shells/zsh_test_script.zsh
new file mode 100644
index 0000000..3957f56
--- /dev/null
+++ b/tests/test_shells/zsh_test_script.zsh
@@ -0,0 +1,11 @@
+set -e
+set -x
+. tests/bot-ci/scripts/common/main.sh
+zmodload zpython || zmodload libzpython
+zpython 'import zsh'
+zpython 'import platform'
+zpython 'zsh.setvalue("ZSH_PYTHON_VERSION", platform.python_version())'
+zpython 'zsh.setvalue("ZSH_PYTHON_IMPLEMENTATION", platform.python_implementation())'
+
+[[ $ZSH_PYTHON_IMPLEMENTATION = $PYTHON_IMPLEMENTATION ]]
+[[ $ZSH_PYTHON_VERSION = $PYTHON_VERSION ]]