chromium/ui/file_manager/file_manager/foreground/js/banner_util_unittest.ts

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {assertFalse, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';

import type {VolumeInfo} from '../../background/js/volume_info.js';
import {RootType, VolumeType} from '../../common/js/volume_manager_types.js';

import {isAllowedVolume, isBelowThreshold} from './banner_controller.js';
import type {AllowedVolumeOrType, MinDiskThreshold} from './ui/banners/types.js';

let allowedVolumes: AllowedVolumeOrType[] = [];

/**
 * Returns a VolumeInfo with the type and id set.
 */
function createAndSetVolumeInfo(
    volumeType: VolumeType, volumeId: string|null = null) {
  class FakeVolumeInfo {
    volumeType: VolumeType;
    volumeId: string|null;
    constructor() {
      this.volumeType = volumeType;
      this.volumeId = volumeId;
    }
  }

  return new FakeVolumeInfo() as VolumeInfo;
}

/**
 * Creates a chrome.fileManagerPrivate.MountPointSizeStats type.
 */
function createRemainingSizeStats(remainingSize: number) {
  return {
    totalSize: 20 * 1024 * 1024 * 1024,  // 20 GB
    remainingSize,
  } as chrome.fileManagerPrivate.MountPointSizeStats;
}

export function tearDown() {
  allowedVolumes = [];
}

/**
 * Test when there are no allowed volume types.
 */
export function testNoAllowedVolumes() {
  const currentVolume = createAndSetVolumeInfo(VolumeType.DOWNLOADS);

  assertFalse(isAllowedVolume(
      currentVolume, /* currentRootType */ null, allowedVolumes));
}

/**
 * Test when there is a single allowed volume type matching the current volume.
 */
export function testAllowedVolume() {
  const currentVolume = createAndSetVolumeInfo(VolumeType.DOWNLOADS);
  allowedVolumes = [{type: VolumeType.DOWNLOADS}];

  assertTrue(isAllowedVolume(
      currentVolume, /* currentRootType */ null, allowedVolumes));
}

/**
 * Test when there are multiple volumes with one being the current volume.
 */
export function testMultipleAllowedVolumes() {
  const currentVolume = createAndSetVolumeInfo(VolumeType.DOWNLOADS);
  allowedVolumes = [
    {type: VolumeType.DOWNLOADS},
    {type: VolumeType.ANDROID_FILES},
  ];

  assertTrue(isAllowedVolume(
      currentVolume, /* currentRootType */ null, allowedVolumes));
}

/**
 * Test when there are multiple volumes but none match the current volume.
 */
export function testMultipleNoAllowedVolumes() {
  const currentVolume = createAndSetVolumeInfo(VolumeType.DOWNLOADS);
  allowedVolumes = [
    {type: VolumeType.ARCHIVE},
    {type: VolumeType.ANDROID_FILES},
  ];

  assertFalse(isAllowedVolume(
      currentVolume, /* currentRootType */ null, allowedVolumes));
}

/**
 * Test multiple identical volume types, with only one allowed volume id.
 */
export function testMultipleAllowedDocumentProviders() {
  const currentVolume =
      createAndSetVolumeInfo(VolumeType.DOCUMENTS_PROVIDER, 'provider_a');
  allowedVolumes = [
    {
      type: VolumeType.DOCUMENTS_PROVIDER,
      id: 'provider_a',
    },
    {type: VolumeType.DOCUMENTS_PROVIDER, id: 'provider_b'},
  ];

  assertTrue(isAllowedVolume(
      currentVolume, /* currentRootType */ null, allowedVolumes));
}

/**
 * Test multiple identical volume types, with none matching the current volume.
 */
export function testMultipleNoAllowedDocumentProviders() {
  const currentVolume =
      createAndSetVolumeInfo(VolumeType.DOCUMENTS_PROVIDER, 'provider_a');
  allowedVolumes = [
    {
      type: VolumeType.DOCUMENTS_PROVIDER,
      id: 'provider_b',
    },
    {type: VolumeType.DOCUMENTS_PROVIDER, id: 'provider_c'},
  ];

  assertFalse(isAllowedVolume(
      currentVolume, /* currentRootType */ null, allowedVolumes));
}

/**
 * Test that a single root type (with no volume info) returns true if the
 * allowed volumes only contains root information.
 */
export function testSingleRootTypeNoVolumeTypeOrId() {
  const currentRootType = RootType.DOWNLOADS;
  allowedVolumes = [{
    root: RootType.DOWNLOADS,
  }];
  assertTrue(isAllowedVolume(
      /* currentVolume */ null, currentRootType, allowedVolumes));
}

/**
 * Test that multiple root types defined in allowed volumes (with one matching
 * the current type) returns true.
 */
export function testMultipleRootTypesNoVolumeTypeOrId() {
  const currentRootType = RootType.DOWNLOADS;
  allowedVolumes = [
    {
      root: RootType.DOWNLOADS,
    },
    {
      root: RootType.DRIVE,
    },
  ];
  assertTrue(isAllowedVolume(
      /* currentVolume */ null, currentRootType, allowedVolumes));
}

/**
 * Test multiple defined root types with none matching the allowed volumes
 * returns false.
 */
export function testMultipleDisallowedRootTypesNoVolumeTypeOrId() {
  const currentRootType = RootType.SMB;
  allowedVolumes = [
    {
      root: RootType.DOWNLOADS,
    },
    {
      root: RootType.DRIVE,
    },
  ];
  assertFalse(isAllowedVolume(
      /* currentVolume */ null, currentRootType, allowedVolumes));
}

/**
 * Test both volume info and root type returns true (for stricter checking of
 * a volume type).)
 */
export function testVolumeTypeAndRootTypeNoId() {
  const currentRootType = RootType.SHARED_DRIVE;
  const currentVolume = createAndSetVolumeInfo(VolumeType.DRIVE);
  allowedVolumes = [{
    type: VolumeType.DRIVE,
    root: RootType.SHARED_DRIVE,
  }];
  assertTrue(isAllowedVolume(currentVolume, currentRootType, allowedVolumes));
}

/**
 * Test that if volume type matches with but not root type should return false.
 */
export function testVolumeTypeMatchesButNotRootType() {
  const currentRootType = RootType.SHARED_DRIVE;
  const currentVolume = createAndSetVolumeInfo(VolumeType.DRIVE);
  allowedVolumes = [{
    type: VolumeType.DRIVE,
    root: RootType.DRIVE_SHARED_WITH_ME,
  }];
  assertFalse(isAllowedVolume(currentVolume, currentRootType, allowedVolumes));
}

/**
 * Test that volume type is defined but the root type is null, allowed volumes
 * should allow for stricter checking of a volume type, this should return
 * false.
 */
export function testVolumeTypeDefinedButNotRootType() {
  const currentVolume = createAndSetVolumeInfo(VolumeType.DRIVE);
  allowedVolumes = [{
    type: VolumeType.DRIVE,
    root: RootType.DRIVE_SHARED_WITH_ME,
  }];
  assertFalse(isAllowedVolume(
      currentVolume, /* currentRootType */ null, allowedVolumes));
}

/**
 * Test that root type is defined but not volume type. If the allowed volumes
 * requires both defined, should return false.
 */
export function testRootTypeDefinedButNotVolumeType() {
  const currentRootType = RootType.TRASH;
  allowedVolumes = [{
    type: VolumeType.TRASH,
    root: RootType.TRASH,
  }];
  assertFalse(isAllowedVolume(
      /* currentVolume */ null, currentRootType, allowedVolumes));
}

/**
 * Test that volume type, root type and id are all defined.
 */
export function testVolumeTypeRootTypeAndIdDefined() {
  const currentVolume =
      createAndSetVolumeInfo(VolumeType.DOCUMENTS_PROVIDER, 'provider_a');
  const currentRootType = RootType.DOCUMENTS_PROVIDER;

  allowedVolumes = [{
    type: VolumeType.DOCUMENTS_PROVIDER,
    root: RootType.DOCUMENTS_PROVIDER,
    id: 'provider_a',
  }];
  assertTrue(isAllowedVolume(currentVolume, currentRootType, allowedVolumes));
}

/**
 * Test that volume type, root type are defined but id does not match.
 */
export function testVolumeTypeRootTypeAndIdDefinedNoMatch() {
  const currentVolume =
      createAndSetVolumeInfo(VolumeType.DOCUMENTS_PROVIDER, 'provider_a');
  const currentRootType = RootType.DOCUMENTS_PROVIDER;

  allowedVolumes = [{
    type: VolumeType.DOCUMENTS_PROVIDER,
    root: RootType.DOCUMENTS_PROVIDER,
    id: 'provider_b',
  }];
  assertFalse(isAllowedVolume(currentVolume, currentRootType, allowedVolumes));
}

/**
 * Test multiple volume types, root types and ids defined with one matching.
 */
export function testMultipleDifferentIdsSameVolumeTypeAndRootTypeOneMatches() {
  const currentVolume =
      createAndSetVolumeInfo(VolumeType.DOCUMENTS_PROVIDER, 'provider_a');
  const currentRootType = RootType.DOCUMENTS_PROVIDER;

  allowedVolumes = [
    {
      type: VolumeType.DOCUMENTS_PROVIDER,
      root: RootType.DOCUMENTS_PROVIDER,
      id: 'provider_b',
    },
    {
      type: VolumeType.DOCUMENTS_PROVIDER,
      root: RootType.DOCUMENTS_PROVIDER,
      id: 'provider_a',
    },
  ];
  assertTrue(isAllowedVolume(currentVolume, currentRootType, allowedVolumes));
}

/**
 * Test multiple volume types, root types and ids defined with none matching.
 */
export function testMultipleDifferentIdsSameVolumeTypeAndRootTypeNoneMatches() {
  const currentVolume =
      createAndSetVolumeInfo(VolumeType.DOCUMENTS_PROVIDER, 'provider_c');
  const currentRootType = RootType.DOCUMENTS_PROVIDER;

  allowedVolumes = [
    {
      type: VolumeType.DOCUMENTS_PROVIDER,
      root: RootType.DOCUMENTS_PROVIDER,
      id: 'provider_b',
    },
    {
      type: VolumeType.DOCUMENTS_PROVIDER,
      root: RootType.DOCUMENTS_PROVIDER,
      id: 'provider_a',
    },
  ];
  assertFalse(isAllowedVolume(currentVolume, currentRootType, allowedVolumes));
}

/**
 * Test undefined types return false.
 */
export function testUndefinedThresholdAndSizeStats() {
  const testMinSizeThreshold = {
    type: RootType.DOWNLOADS,
    minSize: 1 * 1024 * 1024 * 1024,  // 1 GB
  };
  const testMinRatioThreshold = {
    type: RootType.DOWNLOADS,
    minSize: 0.1,
  };
  const testSizeStats = {
    totalSize: 20 * 1024 * 1024 * 1024,     // 20 GB
    remainingSize: 1 * 1024 * 1024 * 1024,  // 1 GB
  };
  const testSizeStatsFull = {
    totalSize: 20 * 1024 * 1024 * 1024,  // 20 GB
    remainingSize: 0,                    // full
  };

  assertFalse(
      isBelowThreshold(undefined as unknown as MinDiskThreshold, undefined));
  assertFalse(isBelowThreshold(testMinSizeThreshold, undefined));
  assertFalse(isBelowThreshold(testMinRatioThreshold, undefined));
  assertFalse(isBelowThreshold(
      undefined as unknown as MinDiskThreshold, testSizeStats));
  assertTrue(isBelowThreshold(testMinRatioThreshold, testSizeStatsFull));
}

/**
 * Test that below, equal to and above the minSize threshold returns correct
 * results.
 */
export function testMinSizeReturnsCorrectly() {
  const createMinSizeThreshold = (minSize: number) => ({
    type: RootType.DOWNLOADS,
    minSize,
  });

  // Remaining Size: 512 KB, Min Size: 1 GB
  assertTrue(isBelowThreshold(
      createMinSizeThreshold(1 * 1024 * 1024 * 1024 /* 1 GB */),
      createRemainingSizeStats(512 * 1024 * 1024 /* 512 KB */)));

  // Remaining Size: 1 GB, Min Size: 1 GB
  assertTrue(isBelowThreshold(
      createMinSizeThreshold(1 * 1024 * 1024 * 1024 /* 1 GB */),
      createRemainingSizeStats(1 * 1024 * 1024 * 1024 /* 1 GB */)));

  // Remaining Size: 2 GB, Min Size: 1 GB
  assertFalse(isBelowThreshold(
      createMinSizeThreshold(1 * 1024 * 1024 * 1024 /* 1 GB */),
      createRemainingSizeStats(2 * 1024 * 1024 * 1024 /* 2 GB */)));
}

/**
 * Test that below, equal to and above the minRatio threshold returns correct
 * results.
 */
export function testMinRatioReturnsCorrectly() {
  const createMinRatioThreshold = (minRatio: number) => ({
    type: RootType.DOWNLOADS,
    minRatio,
  });

  // Remaining Size Ratio: 0.1, Threshold: 0.2
  assertTrue(isBelowThreshold(
      createMinRatioThreshold(0.2),
      createRemainingSizeStats(2 * 1024 * 1024 * 1024 /* 2 GB */)));

  // Remaining Size Ratio: 0.1, Threshold: 0.1
  assertTrue(isBelowThreshold(
      createMinRatioThreshold(0.1),
      createRemainingSizeStats(2 * 1024 * 1024 * 1024 /* 2 GB */)));

  // Remaining Size Ratio: 0.1, Threshold: 0.05
  assertFalse(isBelowThreshold(
      createMinRatioThreshold(0.05),
      createRemainingSizeStats(2 * 1024 * 1024 * 1024 /* 2 GB */)));
}