// ========================================================================== // Project: SproutCore - JavaScript Application Framework // Copyright: ©2006-2011 Strobe Inc. and contributors. // Portions ©2008-2011 Apple Inc. All rights reserved. // License: Licensed under MIT license (see license.js) // ==========================================================================

// .….….….….….….….….….….…… // SC.Color.from parsing //

function matches(c, r, g, b, a, msg) {

var isEqual = c.get('r') === r &&
              c.get('g') === g &&
              c.get('b') === b &&
              c.get('a') === a;
ok(isEqual, msg + " [rgba(%@, %@, %@, %@) === rgba(%@, %@, %@, %@)]".fmt(r, g, b, a,
                                                                   c.get('r'), c.get('g'), c.get('b'), c.get('a')));

};

test(“SC.Color.from(rgb)”, function () {

matches(SC.Color.from("rgb(212, 15, 2)"),
                           212, 15, 2, 1,
                      "rgb() colors should be parseable");
matches(SC.Color.from("rgb(10000, 20, 256)"),
                           255, 20, 255, 1,
                      "Colors should be clamped to the device gamut");

matches(SC.Color.from("rgb(10%, 20%, 30%)"),
                           26, 51, 77, 1,
                      "rgb should allow percents as values");

matches(SC.Color.from("rgb(140%, 200%, 350%)"),
                           255, 255, 255, 1,
                      "rgb percents should be clamped to the device gamut");

ok(SC.Color.from("rgb(1,2,3)"), "Whitespace shouldn't matter");
ok(SC.Color.from("rgb(1   ,           2   ,   3  )"), "Whitespace shouldn't matter");

});

test(“SC.Color.from(rgba)”, function () {

matches(SC.Color.from("rgba(212, 15, 2, .2)"),
                            212, 15, 2, .2,
                      "rgba() colors should be parseable");
matches(SC.Color.from("rgba(260, 255, 20, 1.5)"),
                            255, 255, 20, 1,
                      "Alpha should be clamped to 1");

matches(SC.Color.from("rgba(10%, 20%, 30%, .5)"),
                           26, 51, 77, .5,
                      "rgba should allow percents as values");

matches(SC.Color.from("rgba(140%, 200%, 350%, .5)"),
                           255, 255, 255, .5,
                      "rgba percents should be clamped to the device gamut");

ok(!SC.ok(SC.Color.from("rgba(255, 255, 255, -.2)")),
   "Invalid alpha should create an SC.Color in error state");

ok(SC.Color.from("rgba(1,2,3,1)"), "Whitespace shouldn't matter");
ok(SC.Color.from("rgba(1   ,           2   ,   3 , 1 )"), "Whitespace shouldn't matter");

});

test(“SC.Color.from() with invalid rgb colors”, function () {

ok(!SC.ok(SC.Color.from("rgb(0, 0, 0, 0)")), "Too many arguments");

ok(!SC.ok(SC.Color.from("rgba(0, 0, 0)")), "Too few arguments");
ok(!SC.ok(SC.Color.from("rgb(0, 0)")), "Too few arguments");

ok(!SC.ok(SC.Color.from("rgb(0.0, 0.0, 0.0)")), "Floats are not allowed");

ok(!SC.ok(SC.Color.from("rgb(0, 0, 0")), "Missing parenthesis");

ok(!SC.ok(SC.Color.from("rgb(260, -10, 5)")), "Negative numbers");

});

test(“SC.Color.from(rgb)”, function () {

matches(SC.Color.from("#21a"),
        34, 17, 170, 1,
        "#rgb colors should be parseable");

ok(SC.Color.from("#ABC").isEqualTo(
   SC.Color.from("#abc")),
   "Character casing should not matter with hex colors");

});

test(“SC.Color.from(rrggbb)”, function () {

matches(SC.Color.from("#ABCDEF"),
        171, 205, 239, 1,
        "#rrggbb colors should be parseable");

ok(SC.Color.from("#ABCDEF").isEqualTo(
   SC.Color.from("#abcdef")),
   "Character casing should not matter with hex colors");

});

test(“SC.Color.from(aarrggbb)”, function () {

matches(SC.Color.from("#00ABCDEF"),
        171, 205, 239, 0,
        "#aarrggbb colors should be parseable");

ok(SC.Color.from("#BAABCDEF").isEqualTo(
   SC.Color.from("#baabcdef")),
   "Character casing should not matter with hex colors");

});

test(“SC.Color.from() with invalid hex colors”, function () {

ok(!SC.ok(SC.Color.from("#GAB")), "Invalid character");

ok(!SC.ok(SC.Color.from("#0000")), "Invalid length");
ok(!SC.ok(SC.Color.from("#00000")), "Invalid length");
ok(!SC.ok(SC.Color.from("#0000000")), "Invalid length");

});

test(“SC.Color error state”, function() {

var color = SC.Color.create(); // black
color.set('r', 255); // red
matches(color, 255, 0, 0, 1, "PRELIM: Color is as expected");
color.set('cssText', 'nonsense'); //error (transparent)
ok(color.get('isError'), "Setting cssText to nonsense puts the color in an error state.");
equals(color.get('errorValue'), 'nonsense', "Errored color's errorValue property should be");
equals(color.get('cssText'), 'nonsense', "Errored color's cssText should be");
equals(color.get('validCssText'), 'transparent', "Errored color's validCssText should be");
color.set('g', 255); // shouldn't work
equals(color.get('g'), 0, "Color values become read-only while in error state");
color.reset(); // back to red
ok(!color.get('isError'), "Resetting an errored color should remove the error flag.");
matches(color, 255, 0, 0, 1, "Resetting an errored color should reset its values to last-good values");

})

test(“SC.Color.from(hsl)”, function () {

matches(SC.Color.from("hsl(330, 60%, 54%)"),
        208, 67, 138, 1,
        "hsl() colors should be parseable");

matches(SC.Color.from("hsl(-90, 50%, 44%)"),
        112, 56, 168, 1,
        "negative hues should be allowed");

matches(SC.Color.from("hsl(-810, 50%, 44%)"),
        112, 56, 168, 1,
        "negative hues should be allowed");

matches(SC.Color.from("hsl(690, 60%, 54%)"),
        208, 67, 138, 1,
        "hues above 360 degrees should be valid");

matches(SC.Color.from("hsl(1050, 60%, 54%)"),
        208, 67, 138, 1,
        "hues above 360 degrees should be valid");

matches(SC.Color.from("hsl(1050, 150%, 190%)"),
        255, 255, 255, 1,
        "luminosity and saturation should be clamped between 0 and 100");

ok(SC.Color.from("hsl(1,2%,3%)"), "Whitespace shouldn't matter");
ok(SC.Color.from("hsl(1   ,           2%   ,   3% )"), "Whitespace shouldn't matter");

});

test(“SC.Color.from(hsla)”, function () {

matches(SC.Color.from("hsla(210, 87%, 55%, 0.4)"),
        40, 140, 240, .4,
        "hsla() colors should be parseable");

matches(SC.Color.from("hsla(-150, 87%, 55%, 0.4)"),
        40, 140, 240, .4,
        "negative hues should be allowed");

matches(SC.Color.from("hsla(-510, 87%, 55%, 0.4)"),
        40, 140, 240, .4,
        "negative hues should be allowed");

matches(SC.Color.from("hsla(570, 87%, 55%, 0.4)"),
        40, 140, 240, .4,
        "hues above 360 degrees should be valid");

matches(SC.Color.from("hsla(930, 87%, 55%, 0.4)"),
        40, 140, 240, .4,
        "hues above 360 degrees should be valid");

matches(SC.Color.from("hsla(930, 0427%, 200%, 0.4)"),
        255, 255, 255, .4,
        "luminosity and saturation should be clamped between 0 and 100");

ok(SC.Color.from("hsla(1,2%,3%,1)"), "Whitespace shouldn't matter");
ok(SC.Color.from("hsla(1   ,           2%   ,   3% , 1 )"), "Whitespace shouldn't matter");

});

test(“SC.Color.from(transparent)”, function () {

matches(SC.Color.from("transparent"),
        0, 0, 0, 0,
        "transparent should be black with an alpha of 0");

});

test(“SC.Color.from(white, black)”, function () {

matches(SC.Color.from("white"),
        255, 255, 255, 1,
        "white should convert to rgb(255, 255, 255)");

matches(SC.Color.from("black"),
        0, 0, 0, 1,
        "black should convert to rgb(0, 0, 0)");

});

// .….….….….….….….….….….…… // SC.Color helper functions //

test(“SC.Color.clamp”, function () {

equals(SC.Color.clamp(0, 0, 1), 0);
equals(SC.Color.clamp(.5, 0, 1), .5);
equals(SC.Color.clamp(1, 0, 1), 1);

equals(SC.Color.clamp(-1, 0, 1), 0);
equals(SC.Color.clamp(2, 0, 1), 1);

});

test(“SC.Color.clampInt”, function () {

equals(SC.Color.clampInt(0, 0, 1), 0);
equals(SC.Color.clampInt(.5, 0, 1), 1);
equals(SC.Color.clampInt(1, 0, 1), 1);

equals(SC.Color.clampInt(-1, 0, 1), 0);
equals(SC.Color.clampInt(2, 0, 1), 1);

});

test(“SC.Color.clampToDeviceGamut”, function () {

equals(SC.Color.clampToDeviceGamut(250.25), 250);
equals(SC.Color.clampToDeviceGamut(260), 255);
equals(SC.Color.clampToDeviceGamut(-20), 0);

});

test(“SC.Color.supportsArgb”, function () {

ok(SC.Color.hasOwnProperty('supportsArgb'),
   "supportsARGB should exist on SC.Color");

});

test(“SC.Color.supportsRgba”, function () {

ok(SC.Color.hasOwnProperty('supportsRgba'),
   "supportsRGBA should exist on SC.Color");

});

// .….….….….….….….….….….…… // SC.Color color space conversion functions //

test(“SC.Color.hsvToRgb”, function () {

var rgb = SC.Color.hsvToRgb(252, .94, .7843),
    isValid;

isValid = rgb[0] === 50 &&
          rgb[1] === 12 &&
          rgb[2] === 200;
ok(isValid, "[rgb(50, 12, 200) === rgb(" + rgb.join(', ') + ")");

});

test(“SC.Color.rgbToHsv”, function () {

var hsv = SC.Color.rgbToHsv(50, 12, 200),
    isValid;

hsv[0] = Math.round(hsv[0]);
hsv[1] = Math.round(hsv[1] * 100);
hsv[2] = Math.round(hsv[2] * 100);

isValid = hsv[0] === 252 &&
          hsv[1] === 94 &&
          hsv[2] === 78;
ok(isValid, "[rgb(50, 12, 200) === hsv(212, 75%, 49%) === hsv(" + hsv.join(', ') + ")]");

});

test(“Converting between color spaces doesn't reduce accuracy”, function () {

var rgb = [20, 145, 42],
    cRgb = SC.Color.hsvToRgb.apply(null, SC.Color.rgbToHsv.apply(null, rgb));

ok(rgb[0] === cRgb[0] &&
   rgb[1] === cRgb[1] &&
   rgb[2] === cRgb[2]);

cRgb = SC.Color.hslToRgb.apply(null, SC.Color.rgbToHsl.apply(null, rgb));

ok(rgb[0] === cRgb[0] &&
   rgb[1] === cRgb[1] &&
   rgb[2] === cRgb[2]);

});

// .….….….….….….….….….….…… // SC.Copyable //

test(“SC.Color.isCopyable”, function () {

ok(SC.Color.create().isCopyable);

});

test(“SC.Color copy() creates a clone of the current color”, function () {

var teal = SC.Color.from("teal"),
    cTeal = teal.copy();

ok(teal.isEqualTo(cTeal), "the colors should be equivalent");
teal.incrementProperty('hue', 30);
ok(!teal.isEqualTo(cTeal), "mutating one color should not affect the other");

});

// .….….….….….….….….….….…… // SC.Color properties //

test(“SC.Color#cssText”, function () {

var color = SC.Color.create({
  r: 255, g: 255, b: 255
});
equals(color.get('cssText'), '#ffffff');

color.set('r', 0);
equals(color.get('cssText'), '#00ffff');

color.set('g', 128);
equals(color.get('cssText'), '#0080ff');

color.set('b', 128);
equals(color.get('cssText'), '#008080');

color.set('a', 0.5);
ok(color.get('cssText') !== '#008080');

});

test(“SC.Color#hue”, function () {

var color = SC.Color.from("hsl(330, 60%, 54%)"),
    round = Math.round;

equals(round(color.get('hue')), 330);

color.set('hue', 300);

equals(color.get('r'), 208);
equals(color.get('g'), 67);
equals(color.get('b'), 208);

equals(round(color.get('hue')), 300);

});

test(“SC.Color#saturation”, function () {

var color = SC.Color.from("hsl(330, 60%, 54%)"),
    round = Math.round;

equals(round(color.get('saturation') * 100), 60);

color.set('saturation', .5);

equals(color.get('r'), 196);
equals(color.get('g'), 79);
equals(color.get('b'), 138);

equals(round(color.get('saturation') * 100), 50);

});

test(“SC.Color#luminosity”, function () {

var color = SC.Color.from("hsl(330, 60%, 54%)"),
    round = Math.round;

equals(round(color.get('luminosity') * 100), 54);

color.set('luminosity', .74);

equals(color.get('r'), 228);
equals(color.get('g'), 149);
equals(color.get('b'), 189);

equals(round(color.get('luminosity') * 100), 74);

});

test(“SC.Color#isEqualTo”, function () {

var white = SC.Color.from("white"),
    cWhite = SC.Color.create({ r: 255, g: 255, b: 255 });

ok(white.isEqualTo(cWhite));

});

test(“SC.Color#toRgb”, function () {

equals(SC.Color.create({ r: 50, g: 240, b: 250, a: .4 }).toRgb(),
       "rgb(50,240,250)");

equals(SC.Color.create({ r: -50, g: 270, b: 250 }).toRgb(),
       "rgb(0,255,250)",
       "Color clamping should occur");

});

test(“SC.Color#toRgba”, function () {

equals(SC.Color.create({ r: 50, g: 240, b: 250, a: .4 }).toRgba(),
       "rgba(50,240,250,0.4)");

equals(SC.Color.create({ r: -50, g: 270, b: 250 }).toRgba(),
       "rgba(0,255,250,1)",
       "Color clamping should occur");

});

test(“SC.Color#toHex”, function () {

equals(SC.Color.create({ r: 50, g: 240, b: 250, a: .4 }).toHex(),
       "#32f0fa");

equals(SC.Color.create({ r: -50, g: 270, b: 250 }).toHex(),
       "#00fffa",
       "Color clamping should occur");

});

test(“SC.Color#toArgb”, function () {

equals(SC.Color.create({ r: 50, g: 240, b: 250, a: .4 }).toArgb(),
       "#6632f0fa");

equals(SC.Color.create({ r: -50, g: 270, b: 250 }).toArgb(),
       "#ff00fffa",
       "Color clamping should occur");

});

test(“SC.Color#toHsl”, function () {

equals(SC.Color.create({ r: 50, g: 240, b: 250, a: .4 }).toHsl(),
       "hsl(183,95%,59%)");

equals(SC.Color.create({ r: -50, g: 270, b: 250 }).toHsl(),
       "hsl(179,100%,50%)",
       "Color clamping should occur");

});

test(“SC.Color#toHsla”, function () {

equals(SC.Color.create({ r: 50, g: 240, b: 250, a: .4 }).toHsla(),
       "hsla(183,95%,59%,0.4)");

equals(SC.Color.create({ r: -50, g: 270, b: 250 }).toHsla(),
       "hsla(179,100%,50%,1)",
       "Color clamping should occur");

});

test(“SC.Color#add”, function () {

var white = SC.Color.create({ r: 255, g: 255, b: 255 }),
    red = SC.Color.create({ r: 255, g: 0, b: 25, a: .4 }),
    c;

c = white.add(red);
equals(c.get('r'), 510);
equals(c.get('g'), 255);
equals(c.get('b'), 280);
equals(c.get('a'), 1.4);

});

test(“SC.Color#sub”, function () {

var white = SC.Color.create({ r: 255, g: 255, b: 255 }),
    red = SC.Color.create({ r: 255, g: 0, b: 25, a: .4 }),
    c;

c = white.sub(red);
equals(c.get('r'), 0);
equals(c.get('g'), 255);
equals(c.get('b'), 230);
equals(c.get('a'), .6);

});

test(“SC.Color#mult”, function () {

var c = SC.Color.create({ r: 10, g: 20, b: 30 });

c = c.mult(.5);
equals(c.get('r'), 5);
equals(c.get('g'), 10);
equals(c.get('b'), 15);
equals(c.get('a'), .5);

});