text: var Buffer = require("buffer/").Buffer;
  var should = require("should");
  var qzeonjs = require("../../index.js");
  
  describe("transaction.js", function () {
  
    var transaction = qzeonjs.transaction;
  
    it("should be object", function () {
      (transaction).should.be.type("object");
    });
  
    it("should have properties", function () {
      (transaction).should.have.property("createTransaction");
    })
  
    describe("#createTransaction", function () {
      var createTransaction = transaction.createTransaction;
      var trs = null;
  
      it("should be a function", function () {
        (createTransaction).should.be.type("function");
      });
  
      it("should create transaction without second signature", function () {
        trs = createTransaction("ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2", 1000, null, "secret");
        (trs).should.be.ok;
      });
  
      it("should create transaction without second signature from keys", function () {
        var secretKey = qzeonjs.ECPair.fromSeed("secret");
        secretKey.publicKey = secretKey.getPublicKeyBuffer().toString("hex");
  
        trs = createTransaction("ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2", 1000, null, secretKey);
        (trs).should.be.ok;
      });
  
      it("should create transaction with vendorField", function () {
        trs = createTransaction("ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2", 1000, "this is a test vendorfield", "secret");
        (trs).should.be.ok;
      });
  
      it("should create transaction with fee override", function () {
        const feeOverride = 1000000
        trs = createTransaction("ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2", 1000, null, "secret", undefined, undefined, feeOverride);
        (trs).should.be.ok;
        (trs.fee).should.equal(feeOverride)
      });
  
      it("should fail to create transaction with invalid fee override", function (done) {
        const feeOverride = '1000000'
        try {
          trs = createTransaction("ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2", 1000, null, "secret", undefined, undefined, feeOverride);
          should.fail()
        } catch (error) {
          done()
        }
      });
  
      it("should fail if transaction with vendorField length > 64", function () {
        var vf = "z";
        for (var i = 0; i < 6; i++) {
          vf = vf + vf;
        }
        vf = vf + "z";
        trs = createTransaction("ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2", 1000, vf, "secret");
        return (trs === null).should.equal(true);
  
      });
  
      it("should be ok if transaction with vendorField length = 64", function () {
        var vf = "z";
        for (var i = 0; i < 6; i++) {
          vf = vf + vf;
        }
        trs = createTransaction("ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2", 1000, vf, "secret");
        (trs).should.be.ok;
      });
  
      describe("returned transaction", function () {
        it("should be object", function () {
          (trs).should.be.type("object");
        });
  
        it("should have id as string", function () {
          (trs.id).should.be.type("string");
        });
  
        it("should have type as number and eqaul 0", function () {
          (trs.type).should.be.type("number").and.equal(0);
        });
  
        it("should have timestamp as number", function () {
          (trs.timestamp).should.be.type("number").and.not.NaN;
        });
  
        it("should have senderPublicKey as hex string", function () {
          (trs.senderPublicKey).should.be.type("string").and.match(function () {
            try {
              new Buffer(trs.senderPublicKey, "hex")
            } catch (e) {
              return false;
            }
  
            return true;
          })
        });
  
        it("should have recipientId as string and to be equal ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2", function () {
          (trs.recipientId).should.be.type("string").and.equal("ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2");
        });
  
        it("should have amount as number and eqaul to 1000", function () {
          (trs.amount).should.be.type("number").and.equal(1000);
        });
  
        it("should have empty asset object", function () {
          (trs.asset).should.be.type("object").and.empty;
        });
  
        it("should does not have second signature", function () {
          (trs).should.not.have.property("signSignature");
        });
  
        it("should have signature as hex string", function () {
          (trs.signature).should.be.type("string").and.match(function () {
            try {
              new Buffer(trs.signature, "hex")
            } catch (e) {
              return false;
            }
  
            return true;
          })
        });
  
        it("should be signed correctly", function () {
          var result = qzeonjs.crypto.verify(trs);
          result.should.equal(true);
        });
  
        it("should be deserialised correctly", function () {
          var deserialisedTx = qzeonjs.crypto.fromBytes(qzeonjs.crypto.getBytes(trs).toString("hex"));
          deserialisedTx.vendorField = new Buffer(deserialisedTx.vendorFieldHex, "hex").toString("utf8")
          delete deserialisedTx.vendorFieldHex;
          var keys = Object.keys(deserialisedTx)
          for (var key in keys) {
            if (keys[key] != "vendorFieldHex") {
              deserialisedTx[keys[key]].should.equal(trs[keys[key]]);
            }
          }
  
        });
  
        it("should not be signed correctly now", function () {
          trs.amount = 10000;
          var result = qzeonjs.crypto.verify(trs);
          result.should.equal(false);
        });
      });
    });
  
    describe("createTransaction and try to tamper signature", function () {
  
      it("should not validate overflown signatures", function () {
        var BigInteger = require('bigi')
        var bip66 = require('bip66')
  
        // custom bip66 encode for hacking away signature
        function BIP66_encode(r, s) {
          var lenR = r.length;
          var lenS = s.length;
          var signature = new Buffer(6 + lenR + lenS);
  
          // 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
          signature[0] = 0x30;
          signature[1] = signature.length - 2;
          signature[2] = 0x02;
          signature[3] = r.length;
          r.copy(signature, 4);
          signature[4 + lenR] = 0x02;
          signature[5 + lenR] = s.length;
          s.copy(signature, 6 + lenR);
  
          return signature;
        }
  
        // The transaction to replay
        var old_transaction = qzeonjs.transaction.createTransaction('ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2', 1, null, 'randomstring');
  
        // Decode signature
        var decode = bip66.decode(Buffer(old_transaction.signature, "hex"));
  
        var r = BigInteger.fromDERInteger(decode.r);
        var s = BigInteger.fromDERInteger(decode.s);
  
        // Transform the signature
        /*
        result = r|00
        result = result - r
        r = r + result
        */
  
        var result = BigInteger.fromBuffer(Buffer(r.toBuffer(r.toDERInteger().length).toString('hex') + '06', 'hex'));
        result = result.subtract(r);
        r = r.add(result);
  
        var new_signature = BIP66_encode(r.toBuffer(r.toDERInteger().length), s.toBuffer(s.toDERInteger().length)).toString('hex');
        //
        // console.log("OLD TRANSACTION : ");
        // console.log("TXID " + qzeonjs.crypto.getId(old_transaction));
        // console.log("VERIFY " + qzeonjs.crypto.verify(old_transaction));
        // console.log("SIG " + old_transaction.signature + "\n");
  
        qzeonjs.crypto.verify(old_transaction).should.equal(true);
  
        old_transaction.signature = new_signature;
        //
        // console.log("NEW TRANSACTION : ");
        // console.log("TXID " + qzeonjs.crypto.getId(old_transaction));
        // console.log("VERIFY " + qzeonjs.crypto.verify(old_transaction));
        // console.log("SIG " + old_transaction.signature);
  
        qzeonjs.crypto.verify(old_transaction).should.equal(false);
  
      });
  
    });
  
    describe("#createTransaction with second secret", function () {
      var createTransaction = transaction.createTransaction;
      var trs = null;
      var secondSecret = "second secret";
      var keys = qzeonjs.crypto.getKeys(secondSecret);
  
      it("should be a function", function () {
        (createTransaction).should.be.type("function");
      });
  
      it("should not accept bitcoin address", function () {
        try {
          trs = createTransaction("14owCmVDn8SaAFZcLbZfCVu5jvc4Lq7Tm1", 1000, null, "secret", secondSecret);
        } catch (error) {
          return (error).should.have.property("message").and.equal("Wrong recipientId")
        }
        true.should.equal(false);
      });
  
      it("should create transaction without second signature", function () {
        trs = createTransaction("ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2", 1000, null, "secret", secondSecret);
        (trs).should.be.ok;
      });
  
      describe("returned transaction", function () {
        it("should be object", function () {
          (trs).should.be.type("object");
        });
  
        it("should have id as string", function () {
          (trs.id).should.be.type("string");
        });
  
        it("should have type as number and eqaul 0", function () {
          (trs.type).should.be.type("number").and.equal(0);
        });
  
        it("should have timestamp as number", function () {
          (trs.timestamp).should.be.type("number").and.not.NaN;
        });
  
        it("should have senderPublicKey as hex string", function () {
          (trs.senderPublicKey).should.be.type("string").and.match(function () {
            try {
              new Buffer(trs.senderPublicKey, "hex")
            } catch (e) {
              return false;
            }
  
            return true;
          })
        });
  
        it("should have recipientId as string and to be equal ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2", function () {
          (trs.recipientId).should.be.type("string").and.equal("ZYMZuYJKKWsmWQzuLzAwCqJaVsu7aQ4ss2");
        });
  
        it("should have amount as number and eqaul to 1000", function () {
          (trs.amount).should.be.type("number").and.equal(1000);
        });
  
        it("should have empty asset object", function () {
          (trs.asset).should.be.type("object").and.empty;
        });
  
        it("should have second signature", function () {
          (trs).should.have.property("signSignature");
        });
  
        it("should have signature as hex string", function () {
          (trs.signature).should.be.type("string").and.match(function () {
            try {
              new Buffer(trs.signature, "hex")
            } catch (e) {
              return false;
            }
  
            return true;
          })
        });
  
        it("should have signSignature as hex string", function () {
          (trs.signSignature).should.be.type("string").and.match(function () {
            try {
              new Buffer(trs.signSignature, "hex");
            } catch (e) {
              return false;
            }
  
            return true;
          });
        });
  
        it("should be deserialised correctly", function () {
          var deserialisedTx = qzeonjs.crypto.fromBytes(qzeonjs.crypto.getBytes(trs).toString("hex"));
          delete deserialisedTx.vendorFieldHex;
          var keys = Object.keys(deserialisedTx)
          for (var key in keys) {
            deserialisedTx[keys[key]].should.equal(trs[keys[key]]);
          }
  
        });
  
        it("should be signed correctly", function () {
          var result = qzeonjs.crypto.verify(trs);
          (result).should.equal(true);
        });
  
        it("should be second signed correctly", function () {
          var result = qzeonjs.crypto.verifySecondSignature(trs, keys.publicKey);
          (result).should.equal(true);
        });
  
        it("should not be signed correctly now", function () {
          trs.amount = 10000;
          var result = qzeonjs.crypto.verify(trs);
          (result).should.equal(false);
        });
  
        it("should not be second signed correctly now", function () {
          trs.amount = 10000;
          var result = qzeonjs.crypto.verifySecondSignature(trs, keys.publicKey);
          (result).should.equal(false);
        });
      });
    });
  
  });
  