basic.js
  1  var t = require('tap')
  2  var fs = require('fs')
  3  var path = require('path')
  4  var fixture = path.resolve(__dirname, 'fixtures')
  5  var meow = fixture + '/meow.cat'
  6  var mine = fixture + '/mine.cat'
  7  var ours = fixture + '/ours.cat'
  8  var fail = fixture + '/fail.false'
  9  var noent = fixture + '/enoent.exe'
 10  var mkdirp = require('mkdirp')
 11  var rimraf = require('rimraf')
 12  
 13  var isWindows = process.platform === 'win32'
 14  var hasAccess = typeof fs.access === 'function'
 15  var winSkip = isWindows && 'windows'
 16  var accessSkip = !hasAccess && 'no fs.access function'
 17  var hasPromise = typeof Promise === 'function'
 18  var promiseSkip = !hasPromise && 'no global Promise'
 19  
 20  function reset () {
 21    delete require.cache[require.resolve('../')]
 22    return require('../')
 23  }
 24  
 25  t.test('setup fixtures', function (t) {
 26    rimraf.sync(fixture)
 27    mkdirp.sync(fixture)
 28    fs.writeFileSync(meow, '#!/usr/bin/env cat\nmeow\n')
 29    fs.chmodSync(meow, parseInt('0755', 8))
 30    fs.writeFileSync(fail, '#!/usr/bin/env false\n')
 31    fs.chmodSync(fail, parseInt('0644', 8))
 32    fs.writeFileSync(mine, '#!/usr/bin/env cat\nmine\n')
 33    fs.chmodSync(mine, parseInt('0744', 8))
 34    fs.writeFileSync(ours, '#!/usr/bin/env cat\nours\n')
 35    fs.chmodSync(ours, parseInt('0754', 8))
 36    t.end()
 37  })
 38  
 39  t.test('promise', { skip: promiseSkip }, function (t) {
 40    var isexe = reset()
 41    t.test('meow async', function (t) {
 42      isexe(meow).then(function (is) {
 43        t.ok(is)
 44        t.end()
 45      })
 46    })
 47    t.test('fail async', function (t) {
 48      isexe(fail).then(function (is) {
 49        t.notOk(is)
 50        t.end()
 51      })
 52    })
 53    t.test('noent async', function (t) {
 54      isexe(noent).catch(function (er) {
 55        t.ok(er)
 56        t.end()
 57      })
 58    })
 59    t.test('noent ignore async', function (t) {
 60      isexe(noent, { ignoreErrors: true }).then(function (is) {
 61        t.notOk(is)
 62        t.end()
 63      })
 64    })
 65    t.end()
 66  })
 67  
 68  t.test('no promise', function (t) {
 69    global.Promise = null
 70    var isexe = reset()
 71    t.throws('try to meow a promise', function () {
 72      isexe(meow)
 73    })
 74    t.end()
 75  })
 76  
 77  t.test('access', { skip: accessSkip || winSkip }, function (t) {
 78    runTest(t)
 79  })
 80  
 81  t.test('mode', { skip: winSkip }, function (t) {
 82    delete fs.access
 83    delete fs.accessSync
 84    var isexe = reset()
 85    t.ok(isexe.sync(ours, { uid: 0, gid: 0 }))
 86    t.ok(isexe.sync(mine, { uid: 0, gid: 0 }))
 87    runTest(t)
 88  })
 89  
 90  t.test('windows', function (t) {
 91    global.TESTING_WINDOWS = true
 92    var pathExt = '.EXE;.CAT;.CMD;.COM'
 93    t.test('pathExt option', function (t) {
 94      runTest(t, { pathExt: '.EXE;.CAT;.CMD;.COM' })
 95    })
 96    t.test('pathExt env', function (t) {
 97      process.env.PATHEXT = pathExt
 98      runTest(t)
 99    })
100    t.test('no pathExt', function (t) {
101      // with a pathExt of '', any filename is fine.
102      // so the "fail" one would still pass.
103      runTest(t, { pathExt: '', skipFail: true })
104    })
105    t.test('pathext with empty entry', function (t) {
106      // with a pathExt of '', any filename is fine.
107      // so the "fail" one would still pass.
108      runTest(t, { pathExt: ';' + pathExt, skipFail: true })
109    })
110    t.end()
111  })
112  
113  t.test('cleanup', function (t) {
114    rimraf.sync(fixture)
115    t.end()
116  })
117  
118  function runTest (t, options) {
119    var isexe = reset()
120  
121    var optionsIgnore = Object.create(options || {})
122    optionsIgnore.ignoreErrors = true
123  
124    if (!options || !options.skipFail) {
125      t.notOk(isexe.sync(fail, options))
126    }
127    t.notOk(isexe.sync(noent, optionsIgnore))
128    if (!options) {
129      t.ok(isexe.sync(meow))
130    } else {
131      t.ok(isexe.sync(meow, options))
132    }
133  
134    t.ok(isexe.sync(mine, options))
135    t.ok(isexe.sync(ours, options))
136    t.throws(function () {
137      isexe.sync(noent, options)
138    })
139  
140    t.test('meow async', function (t) {
141      if (!options) {
142        isexe(meow, function (er, is) {
143          if (er) {
144            throw er
145          }
146          t.ok(is)
147          t.end()
148        })
149      } else {
150        isexe(meow, options, function (er, is) {
151          if (er) {
152            throw er
153          }
154          t.ok(is)
155          t.end()
156        })
157      }
158    })
159  
160    t.test('mine async', function (t) {
161      isexe(mine, options, function (er, is) {
162        if (er) {
163          throw er
164        }
165        t.ok(is)
166        t.end()
167      })
168    })
169  
170    t.test('ours async', function (t) {
171      isexe(ours, options, function (er, is) {
172        if (er) {
173          throw er
174        }
175        t.ok(is)
176        t.end()
177      })
178    })
179  
180    if (!options || !options.skipFail) {
181      t.test('fail async', function (t) {
182        isexe(fail, options, function (er, is) {
183          if (er) {
184            throw er
185          }
186          t.notOk(is)
187          t.end()
188        })
189      })
190    }
191  
192    t.test('noent async', function (t) {
193      isexe(noent, options, function (er, is) {
194        t.ok(er)
195        t.notOk(is)
196        t.end()
197      })
198    })
199  
200    t.test('noent ignore async', function (t) {
201      isexe(noent, optionsIgnore, function (er, is) {
202        if (er) {
203          throw er
204        }
205        t.notOk(is)
206        t.end()
207      })
208    })
209  
210    t.test('directory is not executable', function (t) {
211      isexe(__dirname, options, function (er, is) {
212        if (er) {
213          throw er
214        }
215        t.notOk(is)
216        t.end()
217      })
218    })
219  
220    t.end()
221  }