var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import chaiAsPromised from 'chai-as-promised';
import sinon from 'sinon';
import chai, { expect } from 'chai';
import { DwnErrorCode } from '../../../../src/core/dwn-error.js';
import { MessageStoreLevel } from '../../../../src/store/message-store-level.js';
import { RecordsWrite } from '../../../../src/interfaces/records/messages/records-write.js';
import { TestDataGenerator } from '../../../utils/test-data-generator.js';
import { getCurrentTimeInHighPrecision, sleep } from '../../../../src/utils/time.js';
import { Jws, KeyDerivationScheme } from '../../../../src/index.js';
chai.use(chaiAsPromised);
describe('RecordsWrite', () => {
    if (process.env.TESTSOFF === 'true') {
        return;
    }
    describe('create()', () => {
        it('should be able to create and authorize a valid RecordsWrite message', () => __awaiter(void 0, void 0, void 0, function* () {
            // testing `create()` first
            const alice = yield TestDataGenerator.generatePersona();
            const options = {
                data: TestDataGenerator.randomBytes(10),
                dataFormat: 'application/json',
                dateCreated: '2022-10-14T10:20:30.405060Z',
                recordId: yield TestDataGenerator.randomCborSha256Cid(),
                authorizationSignatureInput: Jws.createSignatureInput(alice)
            };
            const recordsWrite = yield RecordsWrite.create(options);
            const message = recordsWrite.message;
            expect(message.authorization).to.exist;
            expect(message.descriptor.dataFormat).to.equal(options.dataFormat);
            expect(message.descriptor.dateCreated).to.equal(options.dateCreated);
            expect(message.recordId).to.equal(options.recordId);
            const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
            yield recordsWrite.authorize(alice.did, messageStoreStub);
        }));
        it('should be able to auto-fill `datePublished` when `published` set to `true` but `datePublished` not given', () => __awaiter(void 0, void 0, void 0, function* () {
            const alice = yield TestDataGenerator.generatePersona();
            const options = {
                data: TestDataGenerator.randomBytes(10),
                dataFormat: 'application/json',
                recordId: yield TestDataGenerator.randomCborSha256Cid(),
                published: true,
                authorizationSignatureInput: Jws.createSignatureInput(alice)
            };
            const recordsWrite = yield RecordsWrite.create(options);
            const message = recordsWrite.message;
            expect(message.descriptor.datePublished).to.exist;
        }));
        it('should not allow `data` and `dataCid` to be both defined or undefined', () => __awaiter(void 0, void 0, void 0, function* () {
            const alice = yield TestDataGenerator.generatePersona();
            // testing `data` and `dataCid` both defined
            const options1 = {
                recipient: alice.did,
                data: TestDataGenerator.randomBytes(10),
                dataCid: yield TestDataGenerator.randomCborSha256Cid(),
                dataFormat: 'application/json',
                recordId: yield TestDataGenerator.randomCborSha256Cid(),
                published: true,
                authorizationSignatureInput: Jws.createSignatureInput(alice)
            };
            const createPromise1 = RecordsWrite.create(options1);
            yield expect(createPromise1).to.be.rejectedWith('one and only one parameter between `data` and `dataCid` is allowed');
            // testing `data` and `dataCid` both undefined
            const options2 = {
                recipient: alice.did,
                // intentionally showing both `data` and `dataCid` are undefined
                // data                        : TestDataGenerator.randomBytes(10),
                // dataCid                     : await TestDataGenerator.randomCborSha256Cid(),
                dataFormat: 'application/json',
                recordId: yield TestDataGenerator.randomCborSha256Cid(),
                published: true,
                authorizationSignatureInput: Jws.createSignatureInput(alice)
            };
            const createPromise2 = RecordsWrite.create(options2);
            yield expect(createPromise2).to.be.rejectedWith('one and only one parameter between `data` and `dataCid` is allowed');
        }));
        it('should required `dataCid` and `dataSize` to be both defined or undefined at the same time', () => __awaiter(void 0, void 0, void 0, function* () {
            const alice = yield TestDataGenerator.generatePersona();
            const options1 = {
                recipient: alice.did,
                dataCid: yield TestDataGenerator.randomCborSha256Cid(),
                // dataSize                  : 123, // intentionally missing
                dataFormat: 'application/json',
                recordId: yield TestDataGenerator.randomCborSha256Cid(),
                published: true,
                authorizationSignatureInput: Jws.createSignatureInput(alice)
            };
            const createPromise1 = RecordsWrite.create(options1);
            yield expect(createPromise1).to.be.rejectedWith('`dataCid` and `dataSize` must both be defined or undefined at the same time');
            const options2 = {
                recipient: alice.did,
                data: TestDataGenerator.randomBytes(10),
                // dataCid                   : await TestDataGenerator.randomCborSha256Cid(), // intentionally missing
                dataSize: 123,
                dataFormat: 'application/json',
                recordId: yield TestDataGenerator.randomCborSha256Cid(),
                published: true,
                authorizationSignatureInput: Jws.createSignatureInput(alice)
            };
            const createPromise2 = RecordsWrite.create(options2);
            yield expect(createPromise2).to.be.rejectedWith('`dataCid` and `dataSize` must both be defined or undefined at the same time');
        }));
        it('should auto-normalize protocol URL', () => __awaiter(void 0, void 0, void 0, function* () {
            const alice = yield TestDataGenerator.generatePersona();
            const options = {
                recipient: alice.did,
                data: TestDataGenerator.randomBytes(10),
                dataFormat: 'application/json',
                authorizationSignatureInput: Jws.createSignatureInput(alice),
                protocol: 'example.com/',
                protocolPath: 'example',
                schema: 'http://foo.bar/schema'
            };
            const recordsWrite = yield RecordsWrite.create(options);
            const message = recordsWrite.message;
            expect(message.descriptor.protocol).to.eq('http://example.com');
        }));
        it('should required `protocol` and `protocolPath` to be both defined or undefined at the same time', () => __awaiter(void 0, void 0, void 0, function* () {
            const alice = yield TestDataGenerator.generatePersona();
            const options1 = {
                recipient: alice.did,
                protocol: 'http://example.com',
                // protocolPath                : 'foo/bar', // intentionally missing
                dataCid: yield TestDataGenerator.randomCborSha256Cid(),
                dataSize: 123,
                dataFormat: 'application/json',
                recordId: yield TestDataGenerator.randomCborSha256Cid(),
                authorizationSignatureInput: Jws.createSignatureInput(alice)
            };
            const createPromise1 = RecordsWrite.create(options1);
            yield expect(createPromise1).to.be.rejectedWith('`protocol` and `protocolPath` must both be defined or undefined at the same time');
            const options2 = {
                recipient: alice.did,
                // protocol                    : 'http://example.com', // intentionally missing
                protocolPath: 'foo/bar',
                data: TestDataGenerator.randomBytes(10),
                dataCid: yield TestDataGenerator.randomCborSha256Cid(),
                dataSize: 123,
                dataFormat: 'application/json',
                recordId: yield TestDataGenerator.randomCborSha256Cid(),
                authorizationSignatureInput: Jws.createSignatureInput(alice)
            };
            const createPromise2 = RecordsWrite.create(options2);
            yield expect(createPromise2).to.be.rejectedWith('`protocol` and `protocolPath` must both be defined or undefined at the same time');
        }));
        it('should throw if attempting to use `protocols` key derivation encryption scheme on non-protocol-based record', () => __awaiter(void 0, void 0, void 0, function* () {
            const alice = yield TestDataGenerator.generatePersona();
            const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(16);
            const dataEncryptionKey = TestDataGenerator.randomBytes(32);
            const encryptionInput = {
                initializationVector: dataEncryptionInitializationVector,
                key: dataEncryptionKey,
                keyEncryptionInputs: [{
                        publicKeyId: alice.keyId,
                        publicKey: alice.keyPair.publicJwk,
                        derivationScheme: KeyDerivationScheme.Protocols
                    }]
            };
            // intentionally generating a record that is not protocol-based
            const createPromise = RecordsWrite.create({
                authorizationSignatureInput: Jws.createSignatureInput(alice),
                dataFormat: 'application/json',
                data: TestDataGenerator.randomBytes(10),
                encryptionInput
            });
            yield expect(createPromise).to.be.rejectedWith(DwnErrorCode.RecordsProtocolsDerivationSchemeMissingProtocol);
        }));
        it('should throw if attempting to use `schemas` key derivation encryption scheme on a record without `schema`', () => __awaiter(void 0, void 0, void 0, function* () {
            const alice = yield TestDataGenerator.generatePersona();
            const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(16);
            const dataEncryptionKey = TestDataGenerator.randomBytes(32);
            const encryptionInput = {
                initializationVector: dataEncryptionInitializationVector,
                key: dataEncryptionKey,
                keyEncryptionInputs: [{
                        publicKeyId: alice.keyId,
                        publicKey: alice.keyPair.publicJwk,
                        derivationScheme: KeyDerivationScheme.Schemas
                    }]
            };
            // intentionally generating a record that is without `schema`
            const createPromise = RecordsWrite.create({
                authorizationSignatureInput: Jws.createSignatureInput(alice),
                dataFormat: 'application/octet-stream',
                data: TestDataGenerator.randomBytes(10),
                encryptionInput
            });
            yield expect(createPromise).to.be.rejectedWith(DwnErrorCode.RecordsSchemasDerivationSchemeMissingSchema);
        }));
    });
    describe('createFrom()', () => {
        it('should create a RecordsWrite with `published` set to `true` with just `publishedDate` given', () => __awaiter(void 0, void 0, void 0, function* () {
            const { author, recordsWrite } = yield TestDataGenerator.generateRecordsWrite({
                published: false
            });
            const write = yield RecordsWrite.createFrom({
                unsignedRecordsWriteMessage: recordsWrite.message,
                datePublished: getCurrentTimeInHighPrecision(),
                authorizationSignatureInput: Jws.createSignatureInput(author)
            });
            expect(write.message.descriptor.published).to.be.true;
        }));
    });
    describe('compareModifiedTime', () => {
        it('should return 0 if age is same', () => __awaiter(void 0, void 0, void 0, function* () {
            const dateModified = getCurrentTimeInHighPrecision();
            const a = (yield TestDataGenerator.generateRecordsWrite({ dateModified })).message;
            const b = JSON.parse(JSON.stringify(a)); // create a deep copy of `a`
            const compareResult = yield RecordsWrite.compareModifiedTime(a, b);
            expect(compareResult).to.equal(0);
        }));
    });
    describe('getNewestMessage', () => {
        it('should return the newest message', () => __awaiter(void 0, void 0, void 0, function* () {
            const a = (yield TestDataGenerator.generateRecordsWrite()).message;
            yield sleep(1); // need to sleep for at least one millisecond else some messages get generated with the same time
            const b = (yield TestDataGenerator.generateRecordsWrite()).message;
            yield sleep(1);
            const c = (yield TestDataGenerator.generateRecordsWrite()).message; // c is the newest since its created last
            const newestMessage = yield RecordsWrite.getNewestMessage([b, c, a]);
            expect(newestMessage.recordId).to.equal(c.recordId);
        }));
    });
    describe('isInitialWrite', () => {
        it('should return false if given message is not a RecordsWrite', () => __awaiter(void 0, void 0, void 0, function* () {
            const { message } = yield TestDataGenerator.generateRecordsQuery();
            const isInitialWrite = yield RecordsWrite.isInitialWrite(message);
            expect(isInitialWrite).to.be.false;
        }));
    });
    describe('getEntryId', () => {
        it('should throw if the given author is undefined', () => __awaiter(void 0, void 0, void 0, function* () {
            const { message } = yield TestDataGenerator.generateRecordsWrite();
            const author = undefined;
            expect(RecordsWrite.getEntryId(author, message.descriptor)).to.be.rejectedWith(DwnErrorCode.RecordsWriteGetEntryIdUndefinedAuthor);
        }));
    });
});
//# sourceMappingURL=records-write.spec.js.map