chromium/chrome/browser/resources/chromeos/accessibility/common/rect_util_test.js

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

GEN_INCLUDE(['testing/common_e2e_test_base.js']);

/** Test fixture for rect_util.js. */
AccessibilityExtensionRectUtilTest = class extends CommonE2ETestBase {
  /** @override */
  async setUpDeferred() {
    await super.setUpDeferred();
    await importModule('RectUtil', '/common/rect_util.js');
  }
};

AX_TEST_F('AccessibilityExtensionRectUtilTest', 'Adjacent', function() {
  const baseRect = {left: 10, top: 10, width: 10, height: 10};
  const adjacentRects = [
    {left: 0, top: 0, width: 10, height: 10},
    {left: 7, top: 0, width: 10, height: 10},
    {left: 10, top: 0, width: 10, height: 10},
    {left: 17, top: 0, width: 10, height: 10},
    {left: 20, top: 0, width: 10, height: 10},
    {left: 0, top: 7, width: 10, height: 10},
    {left: 20, top: 7, width: 10, height: 10},
    {left: 0, top: 10, width: 10, height: 10},
    {left: 20, top: 10, width: 10, height: 10},
    {left: 0, top: 17, width: 10, height: 10},
    {left: 20, top: 17, width: 10, height: 10},
    {left: 0, top: 20, width: 10, height: 10},
    {left: 7, top: 20, width: 10, height: 10},
    {left: 10, top: 20, width: 10, height: 10},
    {left: 17, top: 20, width: 10, height: 10},
    {left: 20, top: 20, width: 10, height: 10},
  ];
  const nonAdjacentRects = [
    {left: 5, top: 0, width: 5, height: 5},
    {left: 20, top: 0, width: 5, height: 5},
    {left: 12, top: 4, width: 5, height: 5},
    {left: 0, top: 5, width: 5, height: 5},
    {left: 25, top: 5, width: 5, height: 5},
    {left: 12, top: 6, width: 5, height: 5},
    {left: 4, top: 12, width: 5, height: 5},
    {left: 6, top: 12, width: 5, height: 5},
    {left: 12, top: 12, width: 5, height: 5},
    {left: 19, top: 12, width: 5, height: 5},
    {left: 21, top: 12, width: 5, height: 5},
    {left: 12, top: 19, width: 5, height: 5},
    {left: 0, top: 20, width: 5, height: 5},
    {left: 21, top: 20, width: 5, height: 5},
    {left: 12, top: 21, width: 5, height: 5},
    {left: 5, top: 25, width: 5, height: 5},
    {left: 20, top: 25, width: 5, height: 5},
  ];

  for (const rect of adjacentRects) {
    assertTrue(
        RectUtil.adjacent(baseRect, rect),
        RectUtil.toString(baseRect) + ' should be adjacent to ' +
            RectUtil.toString(rect));
    assertTrue(
        RectUtil.adjacent(rect, baseRect),
        RectUtil.toString(rect) + ' should be adjacent to ' +
            RectUtil.toString(baseRect));
  }

  for (const rect of nonAdjacentRects) {
    assertFalse(
        RectUtil.adjacent(baseRect, rect),
        RectUtil.toString(baseRect) + ' should not be adjacent to ' +
            RectUtil.toString(rect));
    assertFalse(
        RectUtil.adjacent(rect, baseRect),
        RectUtil.toString(rect) + ' should not be adjacent to ' +
            RectUtil.toString(baseRect));
  }
});

AX_TEST_F('AccessibilityExtensionRectUtilTest', 'Close', function() {
  const centerRect = {left: 10, top: 10, width: 10, height: 10};
  assertTrue(RectUtil.close(centerRect, centerRect, 0));

  // Adjacent to the left of centerRect.
  const leftRect = {left: 5, top: 10, width: 5, height: 5};
  assertTrue(RectUtil.close(centerRect, leftRect, 5));
  assertTrue(RectUtil.close(centerRect, leftRect, 0));
  assertTrue(RectUtil.close(leftRect, centerRect, 0));

  // 2dp away to the right of centerRect.
  const rightRect = {left: 22, top: 17, width: 5, height: 5};
  assertTrue(RectUtil.close(centerRect, rightRect, 5));
  assertTrue(RectUtil.close(rightRect, centerRect, 5));
  assertFalse(RectUtil.close(centerRect, rightRect, 0));
  assertFalse(RectUtil.close(rightRect, centerRect, 0));

  // 5dp above centerRect.
  const topRect = {left: 12, top: 0, width: 5, height: 5};
  assertTrue(RectUtil.close(centerRect, topRect, 5));
  assertTrue(RectUtil.close(topRect, centerRect, 5));
  assertFalse(RectUtil.close(centerRect, topRect, 4));
  assertFalse(RectUtil.close(topRect, centerRect, 4));

  // Adjacent below centerRect.
  const bottomRect = {left: 15, top: 20, width: 5, height: 5};
  assertTrue(RectUtil.close(centerRect, bottomRect, 0));
  assertTrue(RectUtil.close(bottomRect, centerRect, 0));

  // Touching at the top left corner of centerRect.
  const topLeftRect = {left: 5, top: 5, width: 5, height: 5};
  assertTrue(RectUtil.close(centerRect, topLeftRect, 0));
  assertTrue(RectUtil.close(topLeftRect, centerRect, 0));

  // 1dp off in each dimension from the bottom right corner of centerRect.
  const bottomRightRect = {left: 21, top: 21, width: 5, height: 5};
  assertTrue(RectUtil.close(centerRect, bottomRightRect, 1));
  assertTrue(RectUtil.close(bottomRightRect, centerRect, 1));
  assertFalse(RectUtil.close(centerRect, bottomRightRect, 0));
  assertFalse(RectUtil.close(bottomRightRect, centerRect, 0));

  // Overlapping horizontally, but far vertically.
  const verticallyFarRect = {left: 15, top: 100, width: 5, height: 5};
  assertFalse(RectUtil.close(centerRect, verticallyFarRect, 5));
  assertFalse(RectUtil.close(verticallyFarRect, centerRect, 5));

  // Overlapping vertically, but far horizontally.
  const horizontallyFarRect = {left: 100, top: 15, width: 5, height: 5};
  assertFalse(RectUtil.close(centerRect, horizontallyFarRect, 5));
  assertFalse(RectUtil.close(horizontallyFarRect, centerRect, 5));

  // Far away in both dimensions from centerRect.
  const farRect = {left: 100, top: 100, width: 1, height: 1};
  assertFalse(RectUtil.close(centerRect, farRect, 20));
  assertFalse(RectUtil.close(farRect, centerRect, 20));
});

AX_TEST_F('AccessibilityExtensionRectUtilTest', 'Equals', function() {
  const rect1 = {left: 0, top: 0, width: 10, height: 10};
  const rect2 = {left: 0, top: 0, width: 10, height: 10};
  const rect3 = {left: 1, top: 0, width: 10, height: 10};
  const rect4 = {left: 0, top: 1, width: 10, height: 10};
  const rect5 = {left: 0, top: 0, width: 11, height: 10};
  const rect6 = {left: 0, top: 0, width: 10, height: 11};

  assertTrue(RectUtil.equal(rect1, rect1), 'equal should be reflexive');
  assertTrue(RectUtil.equal(rect1, rect2), 'Rect1 and Rect2 should be equal');
  assertTrue(RectUtil.equal(rect2, rect1), 'equal should be symmetric');
  assertFalse(
      RectUtil.equal(rect1, rect3), 'rect1 and rect3 should not be equal');
  assertFalse(RectUtil.equal(rect3, rect1), 'equal should be symmetric');
  assertFalse(
      RectUtil.equal(rect1, rect4), 'rect1 and rect4 should not be equal');
  assertFalse(RectUtil.equal(rect4, rect1), 'equal should be symmetric');
  assertFalse(
      RectUtil.equal(rect1, rect5), 'rect1 and rect5 should not be equal');
  assertFalse(RectUtil.equal(rect5, rect1), 'equal should be symmetric');
  assertFalse(
      RectUtil.equal(rect1, rect6), 'rect1 and rect6 should not be equal');
  assertFalse(RectUtil.equal(rect6, rect1), 'equal should be symmetric');
});

AX_TEST_F('AccessibilityExtensionRectUtilTest', 'Center', function() {
  const rect1 = {left: 0, top: 0, width: 10, height: 10};
  const rect2 = {left: 10, top: 20, width: 10, height: 40};

  const center1 = RectUtil.center(rect1);
  assertEquals(5, center1.x, 'Center1 x should be 5');
  assertEquals(5, center1.y, 'Center1 y should be 5');

  const center2 = RectUtil.center(rect2);
  assertEquals(15, center2.x, 'Center2 x should be 15');
  assertEquals(40, center2.y, 'Center2 y should be 40');
});

AX_TEST_F('AccessibilityExtensionRectUtilTest', 'Union', function() {
  const rect1 = {left: 0, top: 0, width: 10, height: 10};
  const rect2 = {left: 4, top: 4, width: 2, height: 2};
  const rect3 = {left: 10, top: 20, width: 10, height: 40};
  const rect4 = {left: 0, top: 10, width: 10, height: 10};
  const rect5 = {left: 5, top: 5, width: 10, height: 10};

  // When one rect entirely contains the other, that rect is returned.
  const unionRect1Rect2 = RectUtil.union(rect1, rect2);
  assertTrue(
      RectUtil.equal(rect1, unionRect1Rect2),
      'Union of rect1 and rect2 should be rect1');

  const unionRect1Rect3 = RectUtil.union(rect1, rect3);
  let expected = {left: 0, top: 0, width: 20, height: 60};
  assertTrue(
      RectUtil.equal(expected, unionRect1Rect3),
      'Union of rect1 and rect3 does not match expected value');

  const unionRect1Rect4 = RectUtil.union(rect1, rect4);
  expected = {left: 0, top: 0, width: 10, height: 20};
  assertTrue(
      RectUtil.equal(expected, unionRect1Rect4),
      'Union of rect1 and rect4 does not match expected value');

  const unionRect1Rect5 = RectUtil.union(rect1, rect5);
  expected = {left: 0, top: 0, width: 15, height: 15};
  assertTrue(
      RectUtil.equal(expected, unionRect1Rect5),
      'Union of rect1 and rect5 does not match expected value');
});

AX_TEST_F('AccessibilityExtensionRectUtilTest', 'UnionAll', function() {
  const rect1 = {left: 0, top: 0, width: 10, height: 10};
  const rect2 = {left: 0, top: 10, width: 10, height: 10};
  const rect3 = {left: 10, top: 0, width: 10, height: 10};
  const rect4 = {left: 10, top: 10, width: 10, height: 10};
  const rect5 = {left: 0, top: 0, width: 100, height: 10};

  const union1 = RectUtil.unionAll([rect1, rect2, rect3, rect4]);
  let expected = {left: 0, top: 0, width: 20, height: 20};
  assertTrue(
      RectUtil.equal(expected, union1),
      'Union of rects 1-4 does not match expected value');

  const union2 = RectUtil.unionAll([rect1, rect2, rect3, rect4, rect5]);
  expected = {left: 0, top: 0, width: 100, height: 20};
  assertTrue(
      RectUtil.equal(expected, union2),
      'Union of rects 1-5 does not match expected value');
});

AX_TEST_F(
    'AccessibilityExtensionRectUtilTest', 'ExpandToFitWithPadding', function() {
      const padding = 5;
      let inner = {left: 100, top: 100, width: 100, height: 100};
      let outer = {left: 120, top: 120, width: 20, height: 20};
      let expected = {left: 95, top: 95, width: 110, height: 110};
      assertTrue(
          RectUtil.equal(
              expected, RectUtil.expandToFitWithPadding(padding, outer, inner)),
          'When outer is contained in inner, expandToFitWithPadding does not ' +
              'match expected value');

      inner = {left: 100, top: 100, width: 100, height: 100};
      outer = {left: 50, top: 50, width: 200, height: 200};
      assertTrue(
          RectUtil.equal(
              outer, RectUtil.expandToFitWithPadding(padding, outer, inner)),
          'When outer contains inner, expandToFitWithPadding should equal ' +
              'outer');

      inner = {left: 100, top: 100, width: 100, height: 100};
      outer = {left: 10, top: 10, width: 10, height: 10};
      expected = {left: 10, top: 10, width: 195, height: 195};
      assertTrue(
          RectUtil.equal(
              expected, RectUtil.expandToFitWithPadding(padding, outer, inner)),
          'When there is no overlap, expandToFitWithPadding does not match ' +
              'expected value');

      inner = {left: 100, top: 100, width: 100, height: 100};
      outer = {left: 120, top: 50, width: 200, height: 200};
      expected = {left: 95, top: 50, width: 225, height: 200};
      assertTrue(
          RectUtil.equal(
              expected, RectUtil.expandToFitWithPadding(padding, outer, inner)),
          'When there is some overlap, expandToFitWithPadding does not match ' +
              'expected value');

      inner = {left: 100, top: 100, width: 100, height: 100};
      outer = {left: 97, top: 95, width: 108, height: 110};
      expected = {left: 95, top: 95, width: 110, height: 110};
      assertTrue(
          RectUtil.equal(
              expected, RectUtil.expandToFitWithPadding(padding, outer, inner)),
          'When outer contains inner but without sufficient padding, ' +
              'expandToFitWithPadding does not match expected value');
    });

AX_TEST_F('AccessibilityExtensionRectUtilTest', 'Contains', function() {
  const outer = {left: 10, top: 10, width: 10, height: 10};
  assertTrue(RectUtil.contains(outer, outer), 'Rect should contain itself');

  let inner = {left: 10, top: 12, width: 10, height: 5};
  assertTrue(
      RectUtil.contains(outer, inner),
      'Rect should contain rect with same left/right bounds');
  inner = {left: 12, top: 10, width: 5, height: 10};
  assertTrue(
      RectUtil.contains(outer, inner),
      'Rect should contain rect with same top/bottom bounds');
  inner = {left: 12, top: 12, width: 5, height: 5};
  assertTrue(
      RectUtil.contains(outer, inner),
      'Rect should contain rect that is entirely within its bounds');

  inner = {left: 5, top: 12, width: 10, height: 5};
  assertFalse(
      RectUtil.contains(outer, inner),
      'Rect should not contain rect that extends past the left edge');
  inner = {left: 12, top: 8, width: 5, height: 10};
  assertFalse(
      RectUtil.contains(outer, inner),
      'Rect should not contain rect that extends past the top edge');
  inner = {left: 15, top: 5, width: 10, height: 20};
  assertFalse(
      RectUtil.contains(outer, inner),
      'Rect should not contain rect that extends past right edge and has ' +
          'larger height');
  inner = {left: 5, top: 15, width: 10, height: 10};
  assertFalse(
      RectUtil.contains(outer, inner),
      'Rect should not contain rect that extends below and left of it');
  inner = {left: 2, top: 12, width: 5, height: 5};
  assertFalse(
      RectUtil.contains(outer, inner),
      'Rect should not contain rect directly to its left');
  inner = {left: 12, top: 22, width: 5, height: 5};
  assertFalse(
      RectUtil.contains(outer, inner),
      'Rect should not contain rect directly below it');
  inner = {left: 22, top: 2, width: 5, height: 5};
  assertFalse(
      RectUtil.contains(outer, inner),
      'Rect should not contain rect above the the top-right corner');
  inner = {left: 12, top: 2, width: 5, height: 20};
  assertFalse(
      RectUtil.contains(outer, inner),
      'Rect should not contain rect that has a greater height');
  inner = {left: 2, top: 12, width: 20, height: 5};
  assertFalse(
      RectUtil.contains(outer, inner),
      'Rect should not contain rect that has a larger width');
});


AX_TEST_F('AccessibilityExtensionRectUtilTest', 'Difference', function() {
  const outer = {left: 10, top: 10, width: 10, height: 10};
  assertTrue(
      RectUtil.equal(RectUtil.ZERO_RECT, RectUtil.difference(outer, outer)),
      'Difference of rect with itself should the zero rect');

  let subtrahend = {left: 2, top: 2, width: 5, height: 5};
  assertTrue(
      RectUtil.equal(outer, RectUtil.difference(outer, subtrahend)),
      'Difference of non-overlapping rects should be the outer rect');

  subtrahend = {left: 5, top: 5, width: 20, height: 20};
  assertTrue(
      RectUtil.equal(
          RectUtil.ZERO_RECT, RectUtil.difference(outer, subtrahend)),
      'Difference where subtrahend contains outer should be the zero rect');

  subtrahend = {left: 12, top: 15, width: 6, height: 3};
  let expected = {left: 10, top: 10, width: 10, height: 5};
  assertTrue(
      RectUtil.equal(expected, RectUtil.difference(outer, subtrahend)),
      'Difference above should be largest');

  subtrahend = {left: 15, top: 8, width: 3, height: 10};
  expected = {left: 10, top: 10, width: 5, height: 10};
  assertTrue(
      RectUtil.equal(expected, RectUtil.difference(outer, subtrahend)),
      'Difference to the left should be the largest');

  subtrahend = {left: 5, top: 5, width: 13, height: 10};
  expected = {left: 10, top: 15, width: 10, height: 5};
  assertTrue(
      RectUtil.equal(expected, RectUtil.difference(outer, subtrahend)),
      'Difference below should be the largest');

  subtrahend = {left: 8, top: 8, width: 10, height: 15};
  expected = {left: 18, top: 10, width: 2, height: 10};
  assertTrue(
      RectUtil.equal(expected, RectUtil.difference(outer, subtrahend)),
      'Difference to the right should be the largest');
});

AX_TEST_F('AccessibilityExtensionRectUtilTest', 'Intersection', function() {
  const rect1 = {left: 10, top: 10, width: 10, height: 10};
  assertTrue(
      RectUtil.equal(rect1, RectUtil.intersection(rect1, rect1)),
      'Intersection of a rectangle with itself should be itself');

  let rect2 = {left: 12, top: 12, width: 5, height: 5};
  assertTrue(
      RectUtil.equal(rect2, RectUtil.intersection(rect1, rect2)),
      'When one rect contains another, intersection should be the inner rect');
  assertTrue(
      RectUtil.equal(rect2, RectUtil.intersection(rect2, rect1)),
      'Intersection should be symmetric');

  rect2 = {left: 5, top: 5, width: 20, height: 20};
  assertTrue(
      RectUtil.equal(rect1, RectUtil.intersection(rect1, rect2)),
      'When one rect contains another, intersection should be the inner rect');
  assertTrue(
      RectUtil.equal(rect1, RectUtil.intersection(rect2, rect1)),
      'Intersection should be symmetric');

  rect2 = {left: 30, top: 10, width: 10, height: 10};
  assertTrue(
      RectUtil.equal(RectUtil.ZERO_RECT, RectUtil.intersection(rect1, rect2)),
      'Intersection of non-overlapping rects should be zero rect');
  assertTrue(
      RectUtil.equal(RectUtil.ZERO_RECT, RectUtil.intersection(rect2, rect1)),
      'Intersection should be symmetric');

  rect2 = {left: 15, top: 10, width: 10, height: 10};
  let expected = {left: 15, top: 10, width: 5, height: 10};
  assertTrue(
      RectUtil.equal(expected, RectUtil.intersection(rect1, rect2)),
      'Side-by-side overlap is not computed correctly');
  assertTrue(
      RectUtil.equal(expected, RectUtil.intersection(rect2, rect1)),
      'Intersection should be symmetric');

  rect2 = {left: 15, top: 5, width: 10, height: 10};
  expected = {left: 15, top: 10, width: 5, height: 5};
  assertTrue(
      RectUtil.equal(expected, RectUtil.intersection(rect1, rect2)),
      'Top corner overlap is not computed correctly');
  assertTrue(
      RectUtil.equal(expected, RectUtil.intersection(rect2, rect1)),
      'Intersection should be symmetric');

  rect2 = {left: 5, top: 15, width: 20, height: 10};
  expected = {left: 10, top: 15, width: 10, height: 5};
  assertTrue(
      RectUtil.equal(expected, RectUtil.intersection(rect1, rect2)),
      'Bottom overlap is not computed correctly');
  assertTrue(
      RectUtil.equal(expected, RectUtil.intersection(rect2, rect1)),
      'Intersection should be symmetric');
});

AX_TEST_F('AccessibilityExtensionRectUtilTest', 'Overlaps', function() {
  var rect1 = {left: 0, top: 0, width: 100, height: 100};
  var rect2 = {left: 80, top: 0, width: 100, height: 20};
  var rect3 = {left: 0, top: 80, width: 20, height: 100};

  assertTrue(RectUtil.overlaps(rect1, rect1));
  assertTrue(RectUtil.overlaps(rect2, rect2));
  assertTrue(RectUtil.overlaps(rect3, rect3));
  assertTrue(RectUtil.overlaps(rect1, rect2));
  assertTrue(RectUtil.overlaps(rect1, rect3));
  assertFalse(RectUtil.overlaps(rect2, rect3));
});

AX_TEST_F('AccessibilityExtensionRectUtilTest', 'RectFromPoints', function() {
  var rect = {left: 10, top: 20, width: 50, height: 60};

  assertNotEquals(
      JSON.stringify(rect),
      JSON.stringify(RectUtil.rectFromPoints(0, 0, 10, 10)));
  assertEquals(
      JSON.stringify(rect),
      JSON.stringify(RectUtil.rectFromPoints(10, 20, 60, 80)));
  assertEquals(
      JSON.stringify(rect),
      JSON.stringify(RectUtil.rectFromPoints(60, 20, 10, 80)));
  assertEquals(
      JSON.stringify(rect),
      JSON.stringify(RectUtil.rectFromPoints(10, 80, 60, 20)));
  assertEquals(
      JSON.stringify(rect),
      JSON.stringify(RectUtil.rectFromPoints(60, 80, 10, 20)));
});