text: import * as utils from "../test-utils";
  import {CRYPTO_ENABLED} from "../../src/client";
  import {Filter, MemoryStore, Room} from "../../src/matrix";
  import {TestClient} from "../TestClient";
  
  describe("MatrixClient", function() {
      let client = null;
      let httpBackend = null;
      let store = null;
      const userId = "@alice:localhost";
      const accessToken = "aseukfgwef";
  
      beforeEach(function() {
          store = new MemoryStore();
  
          const testClient = new TestClient(userId, "aliceDevice", accessToken, undefined, {
              store: store,
          });
          httpBackend = testClient.httpBackend;
          client = testClient.client;
      });
  
      afterEach(function() {
          httpBackend.verifyNoOutstandingExpectation();
          return httpBackend.stop();
      });
  
      describe("uploadContent", function() {
          const buf = new Buffer('hello world');
          it("should upload the file", function() {
              httpBackend.when(
                  "POST", "/_matrix/media/r0/upload",
              ).check(function(req) {
                  expect(req.rawData).toEqual(buf);
                  expect(req.queryParams.filename).toEqual("hi.txt");
                  if (!(req.queryParams.access_token == accessToken ||
                          req.headers["Authorization"] == "Bearer " + accessToken)) {
                      expect(true).toBe(false);
                  }
                  expect(req.headers["Content-Type"]).toEqual("text/plain");
                  expect(req.opts.json).toBeFalsy();
                  expect(req.opts.timeout).toBe(undefined);
              }).respond(200, "content", true);
  
              const prom = client.uploadContent({
                  stream: buf,
                  name: "hi.txt",
                  type: "text/plain",
              });
  
              expect(prom).toBeTruthy();
  
              const uploads = client.getCurrentUploads();
              expect(uploads.length).toEqual(1);
              expect(uploads[0].promise).toBe(prom);
              expect(uploads[0].loaded).toEqual(0);
  
              const prom2 = prom.then(function(response) {
                  // for backwards compatibility, we return the raw JSON
                  expect(response).toEqual("content");
  
                  const uploads = client.getCurrentUploads();
                  expect(uploads.length).toEqual(0);
              });
  
              httpBackend.flush();
              return prom2;
          });
  
          it("should parse the response if rawResponse=false", function() {
              httpBackend.when(
                  "POST", "/_matrix/media/r0/upload",
              ).check(function(req) {
                  expect(req.opts.json).toBeFalsy();
              }).respond(200, { "content_uri": "uri" });
  
              const prom = client.uploadContent({
                  stream: buf,
                  name: "hi.txt",
                  type: "text/plain",
              }, {
                  rawResponse: false,
              }).then(function(response) {
                  expect(response.content_uri).toEqual("uri");
              });
  
              httpBackend.flush();
              return prom;
          });
  
          it("should parse errors into a MatrixError", function() {
              httpBackend.when(
                  "POST", "/_matrix/media/r0/upload",
              ).check(function(req) {
                  expect(req.rawData).toEqual(buf);
                  expect(req.opts.json).toBeFalsy();
              }).respond(400, {
                  "errcode": "M_SNAFU",
                  "error": "broken",
              });
  
              const prom = client.uploadContent({
                  stream: buf,
                  name: "hi.txt",
                  type: "text/plain",
              }).then(function(response) {
                  throw Error("request not failed");
              }, function(error) {
                  expect(error.httpStatus).toEqual(400);
                  expect(error.errcode).toEqual("M_SNAFU");
                  expect(error.message).toEqual("broken");
              });
  
              httpBackend.flush();
              return prom;
          });
  
          it("should return a promise which can be cancelled", function() {
              const prom = client.uploadContent({
                  stream: buf,
                  name: "hi.txt",
                  type: "text/plain",
              });
  
              const uploads = client.getCurrentUploads();
              expect(uploads.length).toEqual(1);
              expect(uploads[0].promise).toBe(prom);
              expect(uploads[0].loaded).toEqual(0);
  
              const prom2 = prom.then(function(response) {
                  throw Error("request not aborted");
              }, function(error) {
                  expect(error).toEqual("aborted");
  
                  const uploads = client.getCurrentUploads();
                  expect(uploads.length).toEqual(0);
              });
  
              const r = client.cancelUpload(prom);
              expect(r).toBe(true);
              return prom2;
          });
      });
  
      describe("joinRoom", function() {
          it("should no-op if you've already joined a room", function() {
              const roomId = "!foo:bar";
              const room = new Room(roomId, userId);
              room.addLiveEvents([
                  utils.mkMembership({
                      user: userId, room: roomId, mship: "join", event: true,
                  }),
              ]);
              store.storeRoom(room);
              client.joinRoom(roomId);
              httpBackend.verifyNoOutstandingRequests();
          });
      });
  
      describe("getFilter", function() {
          const filterId = "f1lt3r1d";
  
          it("should return a filter from the store if allowCached", function(done) {
              const filter = Filter.fromJson(userId, filterId, {
                  event_format: "client",
              });
              store.storeFilter(filter);
              client.getFilter(userId, filterId, true).then(function(gotFilter) {
                  expect(gotFilter).toEqual(filter);
                  done();
              });
              httpBackend.verifyNoOutstandingRequests();
          });
  
          it("should do an HTTP request if !allowCached even if one exists",
          function(done) {
              const httpFilterDefinition = {
                  event_format: "federation",
              };
  
              httpBackend.when(
                  "GET", "/user/" + encodeURIComponent(userId) + "/filter/" + filterId,
              ).respond(200, httpFilterDefinition);
  
              const storeFilter = Filter.fromJson(userId, filterId, {
                  event_format: "client",
              });
              store.storeFilter(storeFilter);
              client.getFilter(userId, filterId, false).then(function(gotFilter) {
                  expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition);
                  done();
              });
  
              httpBackend.flush();
          });
  
          it("should do an HTTP request if nothing is in the cache and then store it",
          function(done) {
              const httpFilterDefinition = {
                  event_format: "federation",
              };
              expect(store.getFilter(userId, filterId)).toBe(null);
  
              httpBackend.when(
                  "GET", "/user/" + encodeURIComponent(userId) + "/filter/" + filterId,
              ).respond(200, httpFilterDefinition);
              client.getFilter(userId, filterId, true).then(function(gotFilter) {
                  expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition);
                  expect(store.getFilter(userId, filterId)).toBeTruthy();
                  done();
              });
  
              httpBackend.flush();
          });
      });
  
      describe("createFilter", function() {
          const filterId = "f1llllllerid";
  
          it("should do an HTTP request and then store the filter", function(done) {
              expect(store.getFilter(userId, filterId)).toBe(null);
  
              const filterDefinition = {
                  event_format: "client",
              };
  
              httpBackend.when(
                  "POST", "/user/" + encodeURIComponent(userId) + "/filter",
              ).check(function(req) {
                  expect(req.data).toEqual(filterDefinition);
              }).respond(200, {
                  filter_id: filterId,
              });
  
              client.createFilter(filterDefinition).then(function(gotFilter) {
                  expect(gotFilter.getDefinition()).toEqual(filterDefinition);
                  expect(store.getFilter(userId, filterId)).toEqual(gotFilter);
                  done();
              });
  
              httpBackend.flush();
          });
      });
  
      describe("searching", function() {
          const response = {
              search_categories: {
                  room_events: {
                      count: 24,
                      results: {
                          "$flibble:localhost": {
                              rank: 0.1,
                              result: {
                                  type: "m.room.message",
                                  user_id: "@alice:localhost",
                                  room_id: "!feuiwhf:localhost",
                                  content: {
                                      body: "a result",
                                      msgtype: "m.text",
                                  },
                              },
                          },
                      },
                  },
              },
          };
  
          it("searchMessageText should perform a /search for room_events", function(done) {
              client.searchMessageText({
                  query: "monkeys",
              });
              httpBackend.when("POST", "/search").check(function(req) {
                  expect(req.data).toEqual({
                      search_categories: {
                          room_events: {
                              search_term: "monkeys",
                          },
                      },
                  });
              }).respond(200, response);
  
              httpBackend.flush().then(function() {
                  done();
              });
          });
      });
  
  
      describe("downloadKeys", function() {
          if (!CRYPTO_ENABLED) {
              return;
          }
  
          beforeEach(function() {
              return client.initCrypto();
          });
  
          it("should do an HTTP request and then store the keys", function() {
              const ed25519key = "7wG2lzAqbjcyEkOP7O4gU7ItYcn+chKzh5sT/5r2l78";
              // ed25519key = client.getDeviceEd25519Key();
              const borisKeys = {
                  dev1: {
                      algorithms: ["1"],
                      device_id: "dev1",
                      keys: { "ed25519:dev1": ed25519key },
                      signatures: {
                          boris: {
                              "ed25519:dev1":
                                  "RAhmbNDq1efK3hCpBzZDsKoGSsrHUxb25NW5/WbEV9R" +
                                  "JVwLdP032mg5QsKt/pBDUGtggBcnk43n3nBWlA88WAw",
                          },
                      },
                      unsigned: { "abc": "def" },
                      user_id: "boris",
                  },
              };
              const chazKeys = {
                  dev2: {
                      algorithms: ["2"],
                      device_id: "dev2",
                      keys: { "ed25519:dev2": ed25519key },
                      signatures: {
                          chaz: {
                             "ed25519:dev2":
                                  "FwslH/Q7EYSb7swDJbNB5PSzcbEO1xRRBF1riuijqvL" +
                                  "EkrK9/XVN8jl4h7thGuRITQ01siBQnNmMK9t45QfcCQ",
                          },
                      },
                      unsigned: { "ghi": "def" },
                      user_id: "chaz",
                  },
              };
  
              /*
              function sign(o) {
                  var anotherjson = require('another-json');
                  var b = JSON.parse(JSON.stringify(o));
                  delete(b.signatures);
                  delete(b.unsigned);
                  return client._crypto._olmDevice.sign(anotherjson.stringify(b));
              };
  
              logger.log("Ed25519: " + ed25519key);
              logger.log("boris:", sign(borisKeys.dev1));
              logger.log("chaz:", sign(chazKeys.dev2));
              */
  
              httpBackend.when("POST", "/keys/query").check(function(req) {
                  expect(req.data).toEqual({device_keys: {
                      'boris': {},
                      'chaz': {},
                  }});
              }).respond(200, {
                  device_keys: {
                      boris: borisKeys,
                      chaz: chazKeys,
                  },
              });
  
              const prom = client.downloadKeys(["boris", "chaz"]).then(function(res) {
                  assertObjectContains(res.boris.dev1, {
                      verified: 0, // DeviceVerification.UNVERIFIED
                      keys: { "ed25519:dev1": ed25519key },
                      algorithms: ["1"],
                      unsigned: { "abc": "def" },
                  });
  
                  assertObjectContains(res.chaz.dev2, {
                      verified: 0, // DeviceVerification.UNVERIFIED
                      keys: { "ed25519:dev2": ed25519key },
                      algorithms: ["2"],
                      unsigned: { "ghi": "def" },
                  });
              });
  
              httpBackend.flush();
              return prom;
          });
      });
  
      describe("deleteDevice", function() {
          const auth = {a: 1};
          it("should pass through an auth dict", function() {
              httpBackend.when(
                  "DELETE", "/_matrix/client/r0/devices/my_device",
              ).check(function(req) {
                  expect(req.data).toEqual({auth: auth});
              }).respond(200);
  
              const prom = client.deleteDevice("my_device", auth);
  
              httpBackend.flush();
              return prom;
          });
      });
  });
  
  function assertObjectContains(obj, expected) {
      for (const k in expected) {
          if (expected.hasOwnProperty(k)) {
              expect(obj[k]).toEqual(expected[k]);
          }
      }
  }
  