1 # builtin-eval-source.test.sh
2
3 #### Eval
4 eval "a=3"
5 echo $a
6 ## stdout: 3
7
8 #### eval accepts/ignores --
9 eval -- echo hi
10 ## STDOUT:
11 hi
12 ## END
13 ## BUG dash status: 127
14 ## BUG dash stdout-json: ""
15
16 #### eval usage
17 eval -
18 echo $?
19 eval -z
20 echo $?
21 ## STDOUT:
22 127
23 2
24 ## END
25 ## OK dash STDOUT:
26 127
27 127
28 ## END
29 ## OK mksh status: 1
30 ## OK mksh STDOUT:
31 127
32 ## END
33 ## OK zsh STDOUT:
34 0
35 127
36 ## END
37
38 #### Source
39 lib=$TMP/spec-test-lib.sh
40 echo 'LIBVAR=libvar' > $lib
41 . $lib # dash doesn't have source
42 echo $LIBVAR
43 ## stdout: libvar
44
45 #### source accepts/ignores --
46 echo 'echo foo' > $TMP/foo.sh
47 source -- $TMP/foo.sh
48 ## STDOUT:
49 foo
50 ## END
51 ## N-I dash stdout-json: ""
52 ## N-I dash status: 127
53
54 #### Source nonexistent
55 source /nonexistent/path
56 echo status=$?
57 ## stdout: status=1
58 ## OK dash/zsh stdout: status=127
59
60 #### Source with no arguments
61 source
62 echo status=$?
63 ## stdout: status=2
64 ## OK mksh/zsh stdout: status=1
65 ## N-I dash stdout: status=127
66
67 #### Source with arguments
68 . $REPO_ROOT/spec/testdata/show-argv.sh foo bar # dash doesn't have source
69 ## STDOUT:
70 show-argv: foo bar
71 ## END
72 ## N-I dash STDOUT:
73 show-argv:
74 ## END
75
76 #### Source from a function, mutating argv and defining a local var
77 f() {
78 . $REPO_ROOT/spec/testdata/source-argv.sh # no argv
79 . $REPO_ROOT/spec/testdata/source-argv.sh args to src # new argv
80 echo $@
81 echo foo=$foo # defined in source-argv.sh
82 }
83 f args to func
84 echo foo=$foo # not defined
85 ## STDOUT:
86 source-argv: args to func
87 source-argv: args to src
88 to func
89 foo=foo_val
90 foo=
91 ## END
92 ## N-I dash STDOUT:
93 source-argv: args to func
94 source-argv: to func
95 func
96 foo=foo_val
97 foo=
98 ## END
99
100 #### Source with syntax error
101 # TODO: We should probably use dash behavior of a fatal error.
102 # Although set-o errexit handles this. We don't want to break the invariant
103 # that a builtin like 'source' behaves like an external program. An external
104 # program can't halt the shell!
105 echo 'echo >' > $TMP/syntax-error.sh
106 . $TMP/syntax-error.sh
107 echo status=$?
108 ## stdout: status=2
109 ## OK bash/mksh stdout: status=1
110 ## OK zsh stdout: status=126
111 ## OK dash stdout-json: ""
112 ## OK dash status: 2
113
114 #### Eval with syntax error
115 eval 'echo >'
116 echo status=$?
117 ## stdout: status=2
118 ## OK bash/zsh stdout: status=1
119 ## OK dash stdout-json: ""
120 ## OK dash status: 2
121 ## OK mksh stdout-json: ""
122 ## OK mksh status: 1
123
124 #### Eval in does tilde expansion
125
126 x="~"
127 eval y="$x" # scalar
128 test "$x" = "$y" || echo FALSE
129 [[ $x == /* ]] || echo FALSE # doesn't start with /
130 [[ $y == /* ]] && echo TRUE
131
132 #argv "$x" "$y"
133
134 ## STDOUT:
135 FALSE
136 FALSE
137 TRUE
138 ## END
139 ## BUG dash status: 127
140 ## BUG dash stdout-json: "FALSE\n"
141 ## BUG mksh status: 1
142 ## BUG mksh stdout-json: "FALSE\n"
143
144 #### Eval in bash does tilde expansion in array
145
146 # the "make" plugin in bash-completion relies on this? wtf?
147 x="~"
148
149 # UPSTREAM CODE
150
151 #eval array=( "$x" )
152
153 # FIXED CODE -- proper quoting.
154
155 eval 'array=(' "$x" ')' # array
156
157 test "$x" = "${array[0]}" || echo FALSE
158 [[ $x == /* ]] || echo FALSE # doesn't start with /
159 [[ "${array[0]}" == /* ]] && echo TRUE
160 ## STDOUT:
161 FALSE
162 FALSE
163 TRUE
164 ## END
165 ## N-I dash status: 2
166 ## N-I dash stdout-json: ""
167 ## BUG mksh status: 1
168 ## BUG mksh STDOUT:
169 FALSE
170 ## END
171 ## BUG zsh status: 1
172 ## BUG zsh STDOUT:
173 FALSE
174 FALSE
175 ## END
176
177 #### source works for files in current directory (bash only)
178 cd $TMP
179 echo "echo current dir" > cmd
180 . cmd
181 echo status=$?
182 ## STDOUT:
183 current dir
184 status=0
185 ## END
186 ## N-I zsh STDOUT:
187 status=127
188 ## END
189
190 # This is a special builtin so failure is fatal.
191
192 ## N-I dash stdout-json: ""
193 ## N-I dash status: 2
194 ## N-I mksh stdout-json: ""
195 ## N-I mksh status: 1
196
197 #### source looks in PATH for files
198 mkdir -p dir
199 echo "echo hi" > dir/cmd
200 PATH="dir:$PATH"
201 . cmd
202 rm dir/cmd
203 ## STDOUT:
204 hi
205 ## END
206
207 #### source finds files in PATH before current dir
208 cd $TMP
209 mkdir -p dir
210 echo "echo path" > dir/cmd
211 echo "echo current dir" > cmd
212 PATH="dir:$PATH"
213 . cmd
214 echo status=$?
215 ## STDOUT:
216 path
217 status=0
218 ## END
219
220 #### source works for files in subdirectory
221 mkdir -p dir
222 echo "echo path" > dir/cmd
223 . dir/cmd
224 rm dir/cmd
225 ## STDOUT:
226 path
227 ## END
228
229 #### exit within eval (regression)
230 eval 'exit 42'
231 echo 'should not get here'
232 ## stdout-json: ""
233 ## status: 42
234
235 #### exit within source (regression)
236 cd $TMP
237 echo 'exit 42' > lib.sh
238 . ./lib.sh
239 echo 'should not get here'
240 ## stdout-json: ""
241 ## status: 42
242
243 #### source doesn't crash when targeting a directory
244 cd $TMP
245 mkdir -p dir
246 . ./dir/
247 echo status=$?
248 ## stdout: status=1
249 ## OK dash/zsh/mksh stdout: status=0