// Generated by CoffeeScript 1.6.3
(function() {
  var assert, usb;

  assert = require('assert');

  usb = require("../usb.js");

  if (typeof gc === 'function') {
    afterEach(function() {
      return gc();
    });
  }

  describe('Module', function() {
    it('should describe basic constants', function() {
      assert.notEqual(usb, void 0, "usb must be undefined");
      assert.ok(usb.LIBUSB_CLASS_PER_INTERFACE !== void 0, "Constants must be described");
      return assert.ok(usb.LIBUSB_ENDPOINT_IN === 128);
    });
    it('should handle abuse without crashing', function() {
      assert.throws(function() {
        return new usb.Device();
      });
      assert.throws(function() {
        return usb.Device();
      });
      return assert.throws(function() {
        return usb.Device.prototype.open.call({});
      });
    });
    return describe('setDebugLevel', function() {
      it('should throw when passed invalid args', function() {
        assert.throws((function() {
          return usb.setDebugLevel();
        }), TypeError);
        assert.throws((function() {
          return usb.setDebugLevel(-1);
        }), TypeError);
        return assert.throws((function() {
          return usb.setDebugLevel(5);
        }), TypeError);
      });
      return it('should succeed with good args', function() {
        return assert.doesNotThrow(function() {
          return usb.setDebugLevel(0);
        });
      });
    });
  });

  describe('getDeviceList', function() {
    return it('should return at least one device', function() {
      var l;
      l = usb.getDeviceList();
      return assert.ok(l.length > 0);
    });
  });

  describe('findByIds', function() {
    return it('should return an array with length > 0', function() {
      var dev;
      dev = usb.findByIds(0x59e3, 0x0a23);
      return assert.ok(dev, "Demo device is not attached");
    });
  });

  describe('Device', function() {
    var device;
    device = null;
    before(function() {
      return device = usb.findByIds(0x59e3, 0x0a23);
    });
    it('should have sane properties', function() {
      assert.ok(device.busNumber > 0, "deviceAddress must be larger than 0");
      return assert.ok(device.deviceAddress > 0, "deviceAddress must be larger than 0");
    });
    it('should have a deviceDescriptor property', function() {
      var deviceDesc;
      return assert.ok((deviceDesc = device.deviceDescriptor) !== void 0);
    });
    it('should have a configDescriptor property', function() {
      return assert.ok(device.configDescriptor !== void 0);
    });
    it('should open', function() {
      return device.open();
    });
    it('gets string descriptors', function(done) {
      return device.getStringDescriptor(device.deviceDescriptor.iManufacturer, function(e, s) {
        assert.ok(e === void 0, e);
        assert.equal(s, 'Nonolith Labs');
        return done();
      });
    });
    describe('control transfer', function() {
      var b, _i, _results;
      b = Buffer((function() {
        _results = [];
        for (var _i = 0x30; 0x30 <= 0x40 ? _i < 0x40 : _i > 0x40; 0x30 <= 0x40 ? _i++ : _i--){ _results.push(_i); }
        return _results;
      }).apply(this));
      it('should OUT transfer when the IN bit is not set', function(done) {
        return device.controlTransfer(0x40, 0x81, 0, 0, b, function(e) {
          assert.ok(e === void 0, e);
          return done();
        });
      });
      it("should fail when bmRequestType doesn't match buffer / length", function() {
        return assert.throws(function() {
          return device.controlTransfer(0x40, 0x81, 0, 0, 64);
        });
      });
      return it('should IN transfer when the IN bit is set', function(done) {
        return device.controlTransfer(0xc0, 0x81, 0, 0, 128, function(e, d) {
          assert.ok(e === void 0, e);
          assert.equal(d.toString(), b.toString());
          return done();
        });
      });
    });
    describe('Interface', function() {
      var iface;
      iface = null;
      before(function() {
        return iface = device.interfaces[0];
      });
      it('should have one interface', function() {
        return assert.notEqual(iface, void 0);
      });
      it('should be the same as the interfaceNo 0', function() {
        return assert.strictEqual(iface, device["interface"](0));
      });
      if (process.platform === 'linux') {
        it("shouldn't have a kernel driver", function() {
          return assert.equal(iface.isKernelDriverActive(), false);
        });
        it("should fail to detach the kernel driver", function() {
          return assert.throws(function() {
            return iface.detachKernelDriver();
          });
        });
        it("should fail to attach the kernel driver", function() {
          return assert.throws(function() {
            return iface.attachKernelDriver();
          });
        });
      }
      it('should be able to claim an interface', function() {
        return iface.claim();
      });
      describe('IN endpoint', function() {
        var inEndpoint;
        inEndpoint = null;
        before(function() {
          return inEndpoint = iface.endpoints[0];
        });
        it('should be able to get the endpoint', function() {
          return assert.ok(inEndpoint != null);
        });
        it('should be able to get the endpoint by address', function() {
          return assert.equal(inEndpoint, iface.endpoint(0x81));
        });
        it('should have the IN direction flag', function() {
          return assert.equal(inEndpoint.direction, 'in');
        });
        it('should have a descriptor', function() {
          assert.equal(inEndpoint.descriptor.bEndpointAddress, 0x81);
          return assert.equal(inEndpoint.descriptor.wMaxPacketSize, 64);
        });
        it('should fail to write', function() {
          return assert.throws(function() {
            return inEndpoint.transfer(b);
          });
        });
        it('should support read', function(done) {
          return inEndpoint.transfer(64, function(e, d) {
            assert.ok(e === void 0, e);
            assert.ok(d.length === 64);
            return done();
          });
        });
        it('should signal errors', function(done) {
          return inEndpoint.transfer(1, function(e, d) {
            assert.equal(e.errno, usb.LIBUSB_TRANSFER_OVERFLOW);
            return done();
          });
        });
        return it('should be a readableStream', function(done) {
          var pkts;
          pkts = 0;
          inEndpoint.startStream(8, 64);
          inEndpoint.on('data', function(d) {
            assert.equal(d.length, 64);
            pkts++;
            if (pkts === 100) {
              return inEndpoint.stopStream();
            }
          });
          inEndpoint.on('error', function(e) {
            throw e;
          });
          return inEndpoint.on('end', function() {
            return done();
          });
        });
      });
      describe('OUT endpoint', function() {
        var outEndpoint;
        outEndpoint = null;
        before(function() {
          return outEndpoint = iface.endpoints[1];
        });
        it('should be able to get the endpoint', function() {
          return assert.ok(outEndpoint != null);
        });
        it('should be able to get the endpoint by address', function() {
          return assert.equal(outEndpoint, iface.endpoint(0x02));
        });
        it('should have the OUT direction flag', function() {
          return assert.equal(outEndpoint.direction, 'out');
        });
        it('should support write', function(done) {
          return outEndpoint.transfer([1, 2, 3, 4], function(e) {
            assert.ok(e === void 0, e);
            return done();
          });
        });
        return it('should be a writableStream', function(done) {
          var pkts;
          pkts = 0;
          outEndpoint.startStream(4, 64);
          outEndpoint.on('drain', function() {
            pkts++;
            outEndpoint.write(new Buffer(64));
            if (pkts === 100) {
              return outEndpoint.stopStream();
            }
          });
          outEndpoint.on('error', function(e) {});
          return outEndpoint.on('end', function() {
            return done();
          });
        });
      });
      return after(function(cb) {
        return iface.release(cb);
      });
    });
    return after(function() {
      return device.close();
    });
  });

}).call(this);
