content: // Copyright 2018 Google Inc. Use of this source code is governed by an
  // MIT-style license that can be found in the LICENSE file or at
  // https://opensource.org/licenses/MIT.
  
  @TestOn('vm')
  library;
  
  import 'package:test/test.dart';
  
  import 'package:sass/sass.dart';
  
  import 'utils.dart';
  
  void main() {
    group("an RGB color", () {
      late SassColor value;
      setUp(() => value = parseValue("#123456") as SassColor);
  
      test("has RGB channels", () {
        expect(value.red, equals(0x12));
        expect(value.green, equals(0x34));
        expect(value.blue, equals(0x56));
      });
  
      test("has HSL channels", () {
        expect(value.hue, equals(210));
        expect(value.saturation, equals(65.3846153846154));
        expect(value.lightness, equals(20.392156862745097));
      });
  
      test("has HWB channels", () {
        expect(value.hue, equals(210));
        expect(value.whiteness, equals(7.0588235294117645));
        expect(value.blackness, equals(66.27450980392157));
      });
  
      test("has an alpha channel", () {
        expect(value.alpha, equals(1));
      });
  
      test("has a named alpha channel", () {
        expect(value.channel("alpha"), equals(1));
      });
  
      group("channel()", () {
        test("returns RGB channels", () {
          expect(value.channel("red"), equals(0x12));
          expect(value.channel("green"), equals(0x34));
          expect(value.channel("blue"), equals(0x56));
        });
  
        test("returns alpha", () {
          expect(value.channel("alpha"), equals(1));
        });
  
        test("throws for a channel not in this space", () {
          expect(() => value.channel("hue"), throwsSassScriptException);
        });
      });
  
      test("isChannelMissing() throws for a channel not in this space", () {
        expect(() => value.channel("hue"), throwsSassScriptException);
      });
  
      test("isChannelPowerless() throws for a channel not in this space", () {
        expect(() => value.channel("hue"), throwsSassScriptException);
      });
  
      test("has a space", () {
        expect(value.space, equals(ColorSpace.rgb));
      });
  
      test("is a legacy color", () {
        expect(value.isLegacy, isTrue);
      });
  
      test("equals the same color", () {
        expect(value, equalsWithHash(SassColor.rgb(0x12, 0x34, 0x56)));
      });
  
      test("equals an equivalent legacy color", () {
        expect(
          value,
          equalsWithHash(
            SassColor.hsl(210, 65.3846153846154, 20.392156862745097),
          ),
        );
      });
  
      test("does not equal an equivalent non-legacy color", () {
        expect(value, isNot(equals(SassColor.srgb(0x12, 0x34, 0x56))));
      });
  
      group("isInGamut", () {
        test("returns true if the color is in the RGB gamut", () {
          expect(value.isInGamut, isTrue);
        });
  
        test("returns false if the color is outside the RGB gamut", () {
          expect(value.changeChannels({"red": 0x100}).isInGamut, isFalse);
        });
      });
  
      group("toSpace", () {
        test("converts the color to a given space", () {
          expect(
            value.toSpace(ColorSpace.lab),
            equals(
              SassColor.lab(
                20.675469453386192,
                -2.276792630515417,
                -24.59314874484676,
              ),
            ),
          );
        });
  
        test("with legacyMissing: true, makes a powerless channel missing", () {
          expect(
            SassColor.rgb(
              0,
              0,
              0,
            ).toSpace(ColorSpace.hsl).isChannelMissing("hue"),
            isTrue,
          );
        });
  
        test("with legacyMissing: false, makes a powerless channel zero", () {
          var result = SassColor.rgb(
            0,
            0,
            0,
          ).toSpace(ColorSpace.hsl, legacyMissing: false);
          expect(result.isChannelMissing("hue"), isFalse);
          expect(result.channel("hue"), equals(0));
        });
  
        test(
          "even with legacyMissing: false, preserves missing channels for same "
          "space",
          () {
            expect(
              SassColor.rgb(0, null, 0)
                  .toSpace(ColorSpace.rgb, legacyMissing: false)
                  .isChannelMissing("green"),
              isTrue,
            );
          },
        );
      });
  
      group("toGamut() brings the color into its gamut", () {
        setUp(() => value = parseValue("rgb(300 200 100)") as SassColor);
  
        test("with clip", () {
          expect(
            value.toGamut(GamutMapMethod.clip),
            equals(SassColor.rgb(255, 200, 100)),
          );
        });
  
        test("with localMinde", () {
          // TODO: update
          expect(
            value.toGamut(GamutMapMethod.localMinde),
            equals(SassColor.rgb(255, 200, 100)),
          );
        });
      });
  
      group("changeRgb()", () {
        test("changes RGB values", () {
          expect(
            value.changeRgb(red: 0xAA),
            equals(SassColor.rgb(0xAA, 0x34, 0x56)),
          );
          expect(
            value.changeRgb(green: 0xAA),
            equals(SassColor.rgb(0x12, 0xAA, 0x56)),
          );
          expect(
            value.changeRgb(blue: 0xAA),
            equals(SassColor.rgb(0x12, 0x34, 0xAA)),
          );
          expect(
            value.changeRgb(alpha: 0.5),
            equals(SassColor.rgb(0x12, 0x34, 0x56, 0.5)),
          );
          expect(
            value.changeRgb(red: 0xAA, green: 0xAA, blue: 0xAA, alpha: 0.5),
            equals(SassColor.rgb(0xAA, 0xAA, 0xAA, 0.5)),
          );
        });
  
        test("allows in-gamut alpha", () {
          expect(value.changeRgb(alpha: 1).alpha, equals(1));
          expect(value.changeRgb(alpha: 0).alpha, equals(0));
        });
  
        test("allows out-of-gamut values", () {
          expect(value.changeRgb(red: -1).red, equals(-1));
          expect(value.changeRgb(red: 0x100).red, equals(0x100));
        });
  
        test("disallows out-of-gamut alpha", () {
          expect(() => value.changeRgb(alpha: -0.1), throwsRangeError);
          expect(() => value.changeRgb(alpha: 1.1), throwsRangeError);
        });
      });
  
      test("changeHsl() changes HSL values", () {
        expect(
          value.changeHsl(hue: 120),
          equals(SassColor.hsl(120, 65.3846153846154, 20.392156862745097)),
        );
        expect(
          value.changeHsl(saturation: 42),
          equals(SassColor.hsl(210, 42, 20.392156862745097)),
        );
        expect(
          value.changeHsl(lightness: 42),
          equals(SassColor.hsl(210, 65.3846153846154, 42)),
        );
        expect(
          value.changeHsl(alpha: 0.5),
          equals(SassColor.hsl(210, 65.3846153846154, 20.392156862745097, 0.5)),
        );
        expect(
          value.changeHsl(hue: 120, saturation: 42, lightness: 42, alpha: 0.5),
          equals(SassColor.hsl(120, 42, 42, 0.5)),
        );
      });
  
      test("changeHwb() changes HWB values", () {
        expect(
          value.changeHwb(hue: 120),
          equals(SassColor.hwb(120, 7.0588235294117645, 66.27450980392157)),
        );
        expect(
          value.changeHwb(whiteness: 20),
          equals(SassColor.hwb(210, 20, 66.27450980392157)),
        );
        expect(
          value.changeHwb(blackness: 42),
          equals(SassColor.hwb(210, 7.0588235294117645, 42)),
        );
        expect(
          value.changeHwb(alpha: 0.5),
          equals(SassColor.hwb(210, 7.0588235294117645, 66.27450980392157, 0.5)),
        );
        expect(
          value.changeHwb(hue: 120, whiteness: 42, blackness: 42, alpha: 0.5),
          equals(SassColor.hwb(120, 42, 42, 0.5)),
        );
        expect(
          value.changeHwb(whiteness: 50),
          equals(SassColor.hwb(210, 43.0016863406408, 56.9983136593592)),
        );
      });
  
      group("changeChannels()", () {
        test("changes RGB values", () {
          expect(
            value.changeChannels({"red": 0xAA}),
            equals(SassColor.rgb(0xAA, 0x34, 0x56)),
          );
          expect(
            value.changeChannels({"green": 0xAA}),
            equals(SassColor.rgb(0x12, 0xAA, 0x56)),
          );
          expect(
            value.changeChannels({"blue": 0xAA}),
            equals(SassColor.rgb(0x12, 0x34, 0xAA)),
          );
          expect(
            value.changeChannels({"alpha": 0.5}),
            equals(SassColor.rgb(0x12, 0x34, 0x56, 0.5)),
          );
          expect(
            value.changeChannels({
              "red": 0xAA,
              "green": 0xAA,
              "blue": 0xAA,
              "alpha": 0.5,
            }),
            equals(SassColor.rgb(0xAA, 0xAA, 0xAA, 0.5)),
          );
        });
  
        test("allows in-gamut alpha", () {
          expect(value.changeChannels({"alpha": 1}).alpha, equals(1));
          expect(value.changeChannels({"alpha": 0}).alpha, equals(0));
        });
  
        test("allows out-of-gamut values", () {
          expect(value.changeChannels({"red": -1}).red, equals(-1));
          expect(value.changeChannels({"red": 0x100}).red, equals(0x100));
        });
  
        test("disallows out-of-gamut alpha", () {
          expect(() => value.changeChannels({"alpha": -0.1}), throwsRangeError);
          expect(() => value.changeChannels({"alpha": 1.1}), throwsRangeError);
        });
      });
  
      group("changeAlpha()", () {
        test("changes the alpha value", () {
          expect(
            value.changeAlpha(0.5),
            equals(SassColor.rgb(0x12, 0x34, 0x56, 0.5)),
          );
        });
  
        test("allows valid alphas", () {
          expect(value.changeAlpha(0).alpha, equals(0));
          expect(value.changeAlpha(1).alpha, equals(1));
        });
  
        test("rejects invalid alphas", () {
          expect(() => value.changeAlpha(-0.1), throwsRangeError);
          expect(() => value.changeAlpha(1.1), throwsRangeError);
        });
      });
  
      test("is a color", () {
        expect(value.assertColor(), equals(value));
      });
  
      test("isn't any other type", () {
        expect(value.assertBoolean, throwsSassScriptException);
        expect(value.assertCalculation, throwsSassScriptException);
        expect(value.assertFunction, throwsSassScriptException);
        expect(value.assertMap, throwsSassScriptException);
        expect(value.tryMap(), isNull);
        expect(value.assertNumber, throwsSassScriptException);
        expect(value.assertString, throwsSassScriptException);
      });
    });
  
    group("a color with a missing channel", () {
      late SassColor value;
      setUp(
        () => value = parseValue("color(display-p3 0.3 0.4 none)") as SassColor,
      );
  
      test("reports present channels as present", () {
        expect(value.isChannelMissing("red"), isFalse);
        expect(value.isChannelMissing("green"), isFalse);
        expect(value.isChannelMissing("alpha"), isFalse);
      });
  
      test("reports the missing channel as missing", () {
        expect(value.isChannelMissing("blue"), isTrue);
      });
  
      test("reports the missing channel's value as 0", () {
        expect(value.channel("blue"), equals(0));
      });
  
      test("does not report the missing channel as powerless", () {
        expect(value.isChannelPowerless("blue"), isFalse);
      });
    });
  
    group("a color with a powerless channel", () {
      late SassColor value;
      setUp(() => value = parseValue("hsl(120 0% 50%)") as SassColor);
  
      test("reports powerful channels as powerful", () {
        expect(value.isChannelPowerless("saturation"), isFalse);
        expect(value.isChannelPowerless("lightness"), isFalse);
        expect(value.isChannelPowerless("alpha"), isFalse);
      });
  
      test("reports the powerless channel as powerless", () {
        expect(value.isChannelPowerless("hue"), isTrue);
      });
  
      test("reports the powerless channel's value", () {
        expect(value.channel("hue"), 120);
      });
  
      test("does not report the powerless channel as missing", () {
        expect(value.isChannelMissing("hue"), isFalse);
      });
    });
  
    group("an LCH color", () {
      late SassColor value;
      setUp(() => value = parseValue("lch(42% 42% 120)") as SassColor);
  
      test("throws for legacy channels", () {
        expect(() => value.red, throwsSassScriptException);
        expect(() => value.green, throwsSassScriptException);
        expect(() => value.blue, throwsSassScriptException);
        expect(() => value.hue, throwsSassScriptException);
        expect(() => value.saturation, throwsSassScriptException);
        expect(() => value.lightness, throwsSassScriptException);
        expect(() => value.whiteness, throwsSassScriptException);
        expect(() => value.blackness, throwsSassScriptException);
      });
  
      test("has an alpha channel", () {
        expect(value.alpha, equals(1));
      });
  
      group("channel()", () {
        test("returns LCH channels", () {
          expect(value.channel("lightness"), equals(42));
          expect(value.channel("chroma"), equals(63));
          expect(value.channel("hue"), equals(120));
        });
  
        test("returns alpha", () {
          expect(value.channel("alpha"), equals(1));
        });
  
        test("throws for a channel not in this space", () {
          expect(() => value.channel("red"), throwsSassScriptException);
        });
      });
  
      test("is not a legacy color", () {
        expect(value.isLegacy, isFalse);
      });
  
      test("equals the same color", () {
        expect(value, equalsWithHash(SassColor.lch(42, 63, 120)));
      });
  
      test("doesn't equal an equivalent color", () {
        expect(
          value,
          isNot(
            equals(
              SassColor.xyzD65(
                0.07461544022446227,
                0.12417002656711021,
                0.011301590030256693,
              ),
            ),
          ),
        );
      });
  
      test("changeChannels() changes LCH values", () {
        expect(
          value.changeChannels({"lightness": 30}),
          equals(SassColor.lch(30, 63, 120)),
        );
        expect(
          value.changeChannels({"chroma": 30}),
          equals(SassColor.lch(42, 30, 120)),
        );
        expect(
          value.changeChannels({"hue": 80}),
          equals(SassColor.lch(42, 63, 80)),
        );
        expect(
          value.changeChannels({"alpha": 0.5}),
          equals(SassColor.lch(42, 63, 120, 0.5)),
        );
        expect(
          value.changeChannels({
            "lightness": 30,
            "chroma": 30,
            "hue": 30,
            "alpha": 0.5,
          }),
          equals(SassColor.lch(30, 30, 30, 0.5)),
        );
      });
    });
  
    test("an RGBA color has an alpha channel", () {
      var color = parseValue("rgba(10, 20, 30, 0.7)") as SassColor;
      expect(color.alpha, closeTo(0.7, 1e-11));
    });
  
    group("new SassColor.rgb()", () {
      test("allows out-of-gamut values", () {
        expect(SassColor.rgb(-1, 0, 0, 0).channel("red"), equals(-1));
        expect(SassColor.rgb(0, 100, 0, 0).channel("green"), equals(100));
      });
  
      test("disallows out-of-gamut alpha values", () {
        expect(() => SassColor.rgb(0, 0, 0, -0.1), throwsRangeError);
        expect(() => SassColor.rgb(0, 0, 0, 1.1), throwsRangeError);
      });
    });
  }
  