diff --git a/sources/Core/Color/ColorAPI.uc b/sources/Core/Color/ColorAPI.uc
new file mode 100644
index 0000000..6a72cb0
--- /dev/null
+++ b/sources/Core/Color/ColorAPI.uc
@@ -0,0 +1,812 @@
+/**
+ * API that provides functions for working with color.
+ * It has a wide range of pre-defined colors and some functions that
+ * allow to quickly assemble color from rgb(a) values, parse it from
+ * a `Text`/string or load it from an alias.
+ * Copyright 2020 Anton Tarasenko
+ *------------------------------------------------------------------------------
+ * This file is part of Acedia.
+ *
+ * Acedia is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Acedia is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Acedia. If not, see .
+ */
+class ColorAPI extends Singleton
+ dependson(Parser)
+ config(AcediaSystem);
+
+/**
+ * Enumeration for ways to represent `Color` as a `string`.
+ */
+enum ColorDisplayType
+{
+ // Hex format; for pink: #ffc0cb
+ CLRDISPLAY_HEX,
+ // RGB format; for pink: rgb(255,192,203)
+ CLRDISPLAY_RGB,
+ // RGBA format; for opaque pink: rgb(255,192,203,255)
+ CLRDISPLAY_RGBA,
+ // RGB format with tags; for pink: rgb(r=255,g=192,b=203)
+ CLRDISPLAY_RGB_TAG,
+ // RGBA format with tags; for pink: rgb(r=255,g=192,b=203,a=255)
+ CLRDISPLAY_RGBA_TAG
+};
+
+// Some useful predefined color values.
+// They are marked as `config` to allow server admins to mess about with
+// colors if they want to.
+// Pink colors
+var public config const Color Pink;
+var public config const Color LightPink;
+var public config const Color HotPink;
+var public config const Color DeepPink;
+var public config const Color PaleVioletRed;
+var public config const Color MediumVioletRed;
+// Red colors
+var public config const Color LightSalmon;
+var public config const Color Salmon;
+var public config const Color DarkSalmon;
+var public config const Color LightCoral;
+var public config const Color IndianRed;
+var public config const Color Crimson;
+var public config const Color Firebrick;
+var public config const Color DarkRed;
+var public config const Color Red;
+// Orange colors
+var public config const Color OrangeRed;
+var public config const Color Tomato;
+var public config const Color Coral;
+var public config const Color DarkOrange;
+var public config const Color Orange;
+// Yellow colors
+var public config const Color Yellow;
+var public config const Color LightYellow;
+var public config const Color LemonChiffon;
+var public config const Color LightGoldenrodYellow;
+var public config const Color PapayaWhip;
+var public config const Color Moccasin;
+var public config const Color PeachPuff;
+var public config const Color PaleGoldenrod;
+var public config const Color Khaki;
+var public config const Color DarkKhaki;
+var public config const Color Gold;
+// Brown colors
+var public config const Color Cornsilk;
+var public config const Color BlanchedAlmond;
+var public config const Color Bisque;
+var public config const Color NavajoWhite;
+var public config const Color Wheat;
+var public config const Color Burlywood;
+var public config const Color TanColor; // `Tan()` already taken by a function
+var public config const Color RosyBrown;
+var public config const Color SandyBrown;
+var public config const Color Goldenrod;
+var public config const Color DarkGoldenrod;
+var public config const Color Peru;
+var public config const Color Chocolate;
+var public config const Color SaddleBrown;
+var public config const Color Sienna;
+var public config const Color Brown;
+var public config const Color Maroon;
+// Green colors
+var public config const Color DarkOliveGreen;
+var public config const Color Olive;
+var public config const Color OliveDrab;
+var public config const Color YellowGreen;
+var public config const Color LimeGreen;
+var public config const Color Lime;
+var public config const Color LawnGreen;
+var public config const Color Chartreuse;
+var public config const Color GreenYellow;
+var public config const Color SpringGreen;
+var public config const Color MediumSpringGreen;
+var public config const Color LightGreen;
+var public config const Color PaleGreen;
+var public config const Color DarkSeaGreen;
+var public config const Color MediumAquamarine;
+var public config const Color MediumSeaGreen;
+var public config const Color SeaGreen;
+var public config const Color ForestGreen;
+var public config const Color Green;
+var public config const Color DarkGreen;
+// Cyan colors
+var public config const Color Aqua;
+var public config const Color Cyan;
+var public config const Color LightCyan;
+var public config const Color PaleTurquoise;
+var public config const Color Aquamarine;
+var public config const Color Turquoise;
+var public config const Color MediumTurquoise;
+var public config const Color DarkTurquoise;
+var public config const Color LightSeaGreen;
+var public config const Color CadetBlue;
+var public config const Color DarkCyan;
+var public config const Color Teal;
+// Blue colors
+var public config const Color LightSteelBlue;
+var public config const Color PowderBlue;
+var public config const Color LightBlue;
+var public config const Color SkyBlue;
+var public config const Color LightSkyBlue;
+var public config const Color DeepSkyBlue;
+var public config const Color DodgerBlue;
+var public config const Color CornflowerBlue;
+var public config const Color SteelBlue;
+var public config const Color RoyalBlue;
+var public config const Color Blue;
+var public config const Color MediumBlue;
+var public config const Color DarkBlue;
+var public config const Color Navy;
+var public config const Color MidnightBlue;
+// Purple, violet, and magenta colors
+var public config const Color Lavender;
+var public config const Color Thistle;
+var public config const Color Plum;
+var public config const Color Violet;
+var public config const Color Orchid;
+var public config const Color Fuchsia;
+var public config const Color Magenta;
+var public config const Color MediumOrchid;
+var public config const Color MediumPurple;
+var public config const Color BlueViolet;
+var public config const Color DarkViolet;
+var public config const Color DarkOrchid;
+var public config const Color DarkMagenta;
+var public config const Color Purple;
+var public config const Color Indigo;
+var public config const Color DarkSlateBlue;
+var public config const Color SlateBlue;
+var public config const Color MediumSlateBlue;
+// White colors
+var public config const Color White;
+var public config const Color Snow;
+var public config const Color Honeydew;
+var public config const Color MintCream;
+var public config const Color Azure;
+var public config const Color AliceBlue;
+var public config const Color GhostWhite;
+var public config const Color WhiteSmoke;
+var public config const Color Seashell;
+var public config const Color Beige;
+var public config const Color OldLace;
+var public config const Color FloralWhite;
+var public config const Color Ivory;
+var public config const Color AntiqueWhite;
+var public config const Color Linen;
+var public config const Color LavenderBlush;
+var public config const Color MistyRose;
+// Gray and black colors
+var public config const Color Gainsboro;
+var public config const Color LightGray;
+var public config const Color Silver;
+var public config const Color DarkGray;
+var public config const Color Gray;
+var public config const Color DimGray;
+var public config const Color LightSlateGray;
+var public config const Color SlateGray;
+var public config const Color DarkSlateGray;
+var public config const Color Eigengrau;
+var public config const Color Black;
+
+// Escape code point is used to change output's color and is used in
+// Unreal Engine's `string`s.
+var private const int CODEPOINT_ESCAPE;
+var private const int CODEPOINT_SMALL_A;
+
+/**
+ * Creates opaque color from (red, green, blue) triplet.
+ *
+ * @param red Red component, range from 0 to 255.
+ * @param green Green component, range from 0 to 255.
+ * @param blue Blue component, range from 0 to 255.
+ * @return `Color` with specified red, green and blue component and
+ * alpha component of `255`.
+ */
+public final function Color RGB(byte red, byte green, byte blue)
+{
+ local Color result;
+ result.r = red;
+ result.g = green;
+ result.b = blue;
+ result.a = 255;
+ return result;
+}
+
+/**
+ * Creates color from (red, green, blue, alpha) quadruplet.
+ *
+ * @param red Red component, range from 0 to 255.
+ * @param green Green component, range from 0 to 255.
+ * @param blue Blue component, range from 0 to 255.
+ * @param alpha Alpha component, range from 0 to 255.
+ * @return `Color` with specified red, green, blue and alpha component.
+ */
+public final function Color RGBA(byte red, byte green, byte blue, byte alpha)
+{
+ local Color result;
+ result.r = red;
+ result.g = green;
+ result.b = blue;
+ result.a = alpha;
+ return result;
+}
+
+/**
+ * Compares two colors for exact equality of red, green and blue components.
+ * Alpha component is ignored.
+ *
+ * @param color1 Color to compare
+ * @param color2 Color to compare
+ * @return `true` if colors' red, green and blue components are equal
+ * and `false` otherwise.
+ */
+public final function bool AreEqual(Color color1, Color color2, optional bool fixColors)
+{
+ if (fixColors) {
+ color1 = FixColor(color1);
+ color2 = FixColor(color2);
+ }
+ if (color1.r != color2.r) return false;
+ if (color1.g != color2.g) return false;
+ if (color1.b != color2.b) return false;
+ return true;
+}
+
+/**
+ * Compares two colors for exact equality of red, green, blue
+ * and alpha components.
+ *
+ * @param color1 Color to compare
+ * @param color2 Color to compare
+ * @return `true` if colors' red, green, blue and alpha components are equal
+ * and `false` otherwise.
+ */
+public final function bool AreEqualWithAlpha(Color color1, Color color2, optional bool fixColors)
+{
+ if (fixColors) {
+ color1 = FixColor(color1);
+ color2 = FixColor(color2);
+ }
+ if (color1.r != color2.r) return false;
+ if (color1.g != color2.g) return false;
+ if (color1.b != color2.b) return false;
+ if (color1.a != color2.a) return false;
+ return true;
+}
+
+/**
+ * Killing floor's standard methods of rendering colored `string`s
+ * make use of inserting 4-byte sequence into them: first bytes denotes
+ * the start of the sequence, 3 following bytes denote rgb color components.
+ * Unfortunately these methods also have issues with rendering `string`s
+ * if you specify certain values (`0` and `10`) of rgb color components.
+ *
+ * This function "fixes" components by replacing them with close and valid
+ * color component values (adds `1` to the component).
+ */
+public final function byte FixColorComponent(byte colorComponent)
+{
+ if (colorComponent == 0 || colorComponent == 10)
+ {
+ return colorComponent + 1;
+ }
+ return colorComponent;
+}
+
+/**
+ * Killing floor's standard methods of rendering colored `string`s
+ * make use of inserting 4-byte sequence into them: first bytes denotes
+ * the start of the sequence, 3 following bytes denote rgb color components.
+ * Unfortunately these methods also have issues with rendering `string`s
+ * if you specify certain values (`0` and `10`) as rgb color components.
+ *
+ * This function "fixes" given `Color`'s components by replacing them with
+ * close and valid color values (using `FixColorComponent()` method),
+ * resulting in a `Color` that looks almost the same, but is suitable to be
+ * included into 4-byte color change sequence.
+ *
+ * Since alpha component is never used in color-change sequences,
+ * it is never affected.
+ */
+public final function Color FixColor(Color colorToFix)
+{
+ colorToFix.r = FixColorComponent(colorToFix.r);
+ colorToFix.g = FixColorComponent(colorToFix.g);
+ colorToFix.b = FixColorComponent(colorToFix.b);
+ return colorToFix;
+}
+
+/**
+ * Returns 4-gyte sequence for color change to a given color.
+ *
+ * To make returned tag work in most sequences, the value of given color is
+ * auto "fixed" (see `FixColor()` for details).
+ * There is an option to skip color fixing, but method will still change
+ * `0` components to `1`, since they cannot otherwise be used in a tag at all.
+ *
+ * Also see `GetColorTagRGB()`.
+ *
+ * @param colorToUse Color to which tag must change the text.
+ * It's alpha value (`colorToUse.a`) is discarded.
+ * @param doNotFixComponents Minimizes changes to color components
+ * (only allows to change `0` components to `1` before creating a tag).
+ * @return `string` containing 4-byte sequence that will swap text's color to
+ * a given one in standard Unreal Engine's UI.
+ */
+public final function string GetColorTag(
+ Color colorToUse,
+ optional bool doNotFixComponents)
+{
+ if (!doNotFixComponents) {
+ colorToUse = FixColor(colorToUse);
+ }
+ colorToUse.r = Max(1, colorToUse.r);
+ colorToUse.g = Max(1, colorToUse.g);
+ colorToUse.b = Max(1, colorToUse.b);
+ return Chr(CODEPOINT_ESCAPE)
+ $ Chr(colorToUse.r)
+ $ Chr(colorToUse.g)
+ $ Chr(colorToUse.b);
+}
+
+/**
+ * Returns 4-gyte sequence for color change to a given color.
+ *
+ * To make returned tag work in most sequences, the value of given color is
+ * auto "fixed" (see `FixColor()` for details).
+ * There is an option to skip color fixing, but method will still change
+ * `0` components to `1`, since they cannot otherwise be used in a tag at all.
+ *
+ * Also see `GetColorTag()`.
+ *
+ * @param red Red component of color to which tag must
+ * change the text.
+ * @param green Green component of color to which tag must
+ * change the text.
+ * @param blue Blue component of color to which tag must
+ * change the text.
+ * @param doNotFixComponents Minimizes changes to color components
+ * (only allows to change `0` components to `1` before creating a tag).
+ * @return `string` containing 4-byte sequence that will swap text's color to
+ * a given one in standard Unreal Engine's UI.
+ */
+public final function string GetColorTagRGB(
+ int red,
+ int green,
+ int blue,
+ optional bool doNotFixComponents)
+{
+ if (!doNotFixComponents)
+ {
+ red = FixColorComponent(red);
+ green = FixColorComponent(green);
+ blue = FixColorComponent(blue);
+ }
+ red = Max(1, red);
+ green = Max(1, green);
+ blue = Max(1, blue);
+ return Chr(CODEPOINT_ESCAPE) $ Chr(red) $ Chr(green) $ Chr(blue);
+}
+
+// Helper function that converts `byte` with values between 0 and 15 into
+// a corresponding hex letter
+private final function string ByteToHexCharacter(byte component)
+{
+ component = Clamp(component, 0, 15);
+ if (component < 10) {
+ return string(component);
+ }
+ return Chr(component - 10 + CODEPOINT_SMALL_A);
+}
+
+// `byte` to `string` in hex
+private final function string ComponentToHex(byte component)
+{
+ local byte high4Bits, low4Bits;
+ low4Bits = component % 16;
+ if (component >= 16) {
+ high4Bits = (component - low4Bits) / 16;
+ }
+ else {
+ high4Bits = 0;
+ }
+ return ByteToHexCharacter(high4Bits) $ ByteToHexCharacter(low4Bits);
+}
+
+/**
+ * Displays given color as a string in a given style
+ * (hex color representation by default).
+ *
+ * @param colorToConvert Color to display as a `string`.
+ * @param displayType `enum` value, describing how should color
+ * be displayed.
+ * @return `string` representation of a given color in a given style.
+ */
+public final function string ToStringType(
+ Color colorToConvert,
+ optional ColorDisplayType displayType)
+{
+ if (displayType == CLRDISPLAY_HEX) {
+ return "#" $ ComponentToHex(colorToConvert.r)
+ $ ComponentToHex(colorToConvert.g)
+ $ ComponentToHex(colorToConvert.b);
+ }
+ else if (displayType == CLRDISPLAY_RGB)
+ {
+ return "rgb(" $ string(colorToConvert.r) $ ","
+ $ string(colorToConvert.g) $ ","
+ $ string(colorToConvert.b) $ ")";
+ }
+ else if (displayType == CLRDISPLAY_RGBA)
+ {
+ return "rgba(" $ string(colorToConvert.r) $ ","
+ $ string(colorToConvert.g) $ ","
+ $ string(colorToConvert.b) $ ","
+ $ string(colorToConvert.a) $ ")";
+ }
+ else if (displayType == CLRDISPLAY_RGB_TAG)
+ {
+ return "rgb(r=" $ string(colorToConvert.r) $ ","
+ $ "g=" $ string(colorToConvert.g) $ ","
+ $ "b=" $ string(colorToConvert.b) $ ")";
+ }
+ //else if (displayType == CLRDISPLAY_RGBA_TAG)
+ return "rgba(r=" $ string(colorToConvert.r) $ ","
+ $ "g=" $ string(colorToConvert.g) $ ","
+ $ "b=" $ string(colorToConvert.b) $ ","
+ $ "a=" $ string(colorToConvert.a) $ ")";
+}
+
+/**
+ * Displays given color as a string in RGB or RGBA format, depending on
+ * whether color is opaque.
+ *
+ * @param colorToConvert Color to display as a `string` in `CLRDISPLAY_RGB`
+ * style if `colorToConvert.a == 255` and `CLRDISPLAY_RGBA` otherwise.
+ * @return `string` representation of a given color in a given style.
+ */
+public final function string ToString(Color colorToConvert)
+{
+ if (colorToConvert.a < 255) {
+ return ToStringType(colorToConvert, CLRDISPLAY_RGBA);
+ }
+ return ToStringType(colorToConvert, CLRDISPLAY_RGB);
+}
+
+// Parses color in `CLRDISPLAY_RGB` and `CLRDISPLAY_RGB_TAG` representations.
+private final function Color ParseRGB(Parser parser)
+{
+ local int redComponent;
+ local int greenComponent;
+ local int blueComponent;
+ local Parser.ParserState initialParserState;
+ initialParserState = parser.GetCurrentState();
+ parser.Match("rgb(", true)
+ .MInteger(redComponent).Match(",")
+ .MInteger(greenComponent).Match(",")
+ .MInteger(blueComponent).Match(")");
+ if (!parser.Ok())
+ {
+ parser.RestoreState(initialParserState).Match("rgb(", true)
+ .Match("r=", true).MInteger(redComponent).Match(",")
+ .Match("g=", true).MInteger(greenComponent).Match(",")
+ .Match("b=", true).MInteger(blueComponent).Match(")");
+ }
+ return RGB(redComponent, greenComponent, blueComponent);
+}
+
+// Parses color in `CLRDISPLAY_RGBA` and `CLRDISPLAY_RGBA_TAG` representations.
+private final function Color ParseRGBA(Parser parser)
+{
+ local int redComponent;
+ local int greenComponent;
+ local int blueComponent;
+ local int alphaComponent;
+ local Parser.ParserState initialParserState;
+ initialParserState = parser.GetCurrentState();
+ parser.Match("rgba(", true)
+ .MInteger(redComponent).Match(",")
+ .MInteger(greenComponent).Match(",")
+ .MInteger(blueComponent).Match(",")
+ .MInteger(alphaComponent).Match(")");
+ if (!parser.Ok())
+ {
+ parser.RestoreState(initialParserState).Match("rgba(", true)
+ .Match("r=", true).MInteger(redComponent).Match(",")
+ .Match("g=", true).MInteger(greenComponent).Match(",")
+ .Match("b=", true).MInteger(blueComponent).Match(",")
+ .Match("a=", true).MInteger(alphaComponent).Match(")");
+ }
+ return RGBA(redComponent, greenComponent, blueComponent, alphaComponent);
+}
+
+// Parses color in `CLRDISPLAY_HEX` representation.
+private final function Color ParseHexColor(Parser parser)
+{
+ local int redComponent;
+ local int greenComponent;
+ local int blueComponent;
+ parser.Match("#")
+ .MUnsignedInteger(redComponent, 16, 2)
+ .MUnsignedInteger(greenComponent, 16, 2)
+ .MUnsignedInteger(blueComponent, 16, 2);
+ return RGB(redComponent, greenComponent, blueComponent);
+}
+
+/**
+ * Uses given parser to try and parse a color in any of the
+ * `ColorDisplayType` representations.
+ *
+ * @param parser Parser that method would use to parse color from
+ * wherever it left. It's confirmed state will not be changed.
+ * Do not treat `parser` bein in a non-failed state as a confirmation of
+ * successful parsing: color parsing might fail regardless.
+ * Check return value for that.
+ * @param resultingColor Parsed color will be written here if parsing is
+ * successful, otherwise value is undefined.
+ * If parsed color did not specify alpha component - 255 will be used.
+ * @return `true` if parsing was successful and false otherwise.
+ */
+public final function bool ParseWith(Parser parser, out Color resultingColor)
+{
+ local bool successfullyParsed;
+ local string colorAlias;
+ local Parser colorParser;
+ local Parser.ParserState initialParserState;
+ if (parser == none) return false;
+ resultingColor.a = 0xff;
+ colorParser = parser;
+ initialParserState = parser.GetCurrentState();
+ if (parser.Match("$").MUntil(colorAlias,, true).Ok())
+ {
+ colorParser = _.text.ParseString(_.alias.TryColor(colorAlias));
+ initialParserState = colorParser.GetCurrentState();
+ }
+ else {
+ parser.RestoreState(initialParserState);
+ }
+ resultingColor = ParseRGB(colorParser);
+ if (!colorParser.Ok())
+ {
+ colorParser.RestoreState(initialParserState);
+ resultingColor = ParseRGBA(colorParser);
+ }
+ if (!colorParser.Ok())
+ {
+ colorParser.RestoreState(initialParserState);
+ resultingColor = ParseHexColor(colorParser);
+ }
+ successfullyParsed = colorParser.Ok();
+ if (colorParser != parser) {
+ _.memory.Free(colorParser);
+ }
+ return successfullyParsed;
+}
+
+/**
+ * Parses a color in any of the `ColorDisplayType` representations from the
+ * beginning of a given `string`.
+ *
+ * @param stringWithColor String, that contains color definition at
+ * the beginning. Anything after color definition is not used.
+ * @param resultingColor Parsed color will be written here if parsing is
+ * successful, otherwise value is undefined.
+ * If parsed color did not specify alpha component - 255 will be used.
+ * @param stringType How to treat given `string`,
+ * see `StringType` for more details.
+ * @return `true` if parsing was successful and false otherwise.
+ */
+public final function bool ParseString(
+ string stringWithColor,
+ out Color resultingColor,
+ optional Text.StringType stringType)
+{
+ local bool successfullyParsed;
+ local Parser colorParser;
+ colorParser = _.text.ParseString(stringWithColor, stringType);
+ successfullyParsed = ParseWith(colorParser, resultingColor);
+ _.memory.Free(colorParser);
+ return successfullyParsed;
+}
+
+/**
+ * Parses a color in any of the `ColorDisplayType` representations from the
+ * beginning of a given `Text`.
+ *
+ * @param textWithColor `Text`, that contains color definition at
+ * the beginning. Anything after color definition is not used.
+ * @param resultingColor Parsed color will be written here if parsing is
+ * successful, otherwise value is undefined.
+ * If parsed color did not specify alpha component - 255 will be used.
+ * @return `true` if parsing was successful and false otherwise.
+ */
+public final function bool ParseText(
+ Text textWithColor,
+ out Color resultingColor)
+{
+ local bool successfullyParsed;
+ local Parser colorParser;
+ colorParser = _.text.Parse(textWithColor);
+ successfullyParsed = ParseWith(colorParser, resultingColor);
+ _.memory.Free(colorParser);
+ return successfullyParsed;
+}
+
+/**
+ * Parses a color in any of the `ColorDisplayType` representations from the
+ * beginning of a given raw data.
+ *
+ * @param rawDataWithColor Raw data, that contains color definition at
+ * the beginning. Anything after color definition is not used.
+ * @param resultingColor Parsed color will be written here if parsing is
+ * successful, otherwise value is undefined.
+ * If parsed color did not specify alpha component - 255 will be used.
+ * @return `true` if parsing was successful and false otherwise.
+ */
+public final function bool ParseRaw(
+ array rawDataWithColor,
+ out Color resultingColor)
+{
+ local bool successfullyParsed;
+ local Parser colorParser;
+ colorParser = _.text.ParseRaw(rawDataWithColor);
+ successfullyParsed = ParseWith(colorParser, resultingColor);
+ _.memory.Free(colorParser);
+ return successfullyParsed;
+}
+
+defaultproperties
+{
+ Pink=(R=255,G=192,B=203,A=255)
+ LightPink=(R=255,G=182,B=193,A=255)
+ HotPink=(R=255,G=105,B=180,A=255)
+ DeepPink=(R=255,G=20,B=147,A=255)
+ PaleVioletRed=(R=219,G=112,B=147,A=255)
+ MediumVioletRed=(R=199,G=21,B=133,A=255)
+ LightSalmon=(R=255,G=160,B=122,A=255)
+ Salmon=(R=250,G=128,B=114,A=255)
+ DarkSalmon=(R=233,G=150,B=122,A=255)
+ LightCoral=(R=240,G=128,B=128,A=255)
+ IndianRed=(R=205,G=92,B=92,A=255)
+ Crimson=(R=220,G=20,B=60,A=255)
+ Firebrick=(R=178,G=34,B=34,A=255)
+ DarkRed=(R=139,G=0,B=0,A=255)
+ Red=(R=255,G=0,B=0,A=255)
+ OrangeRed=(R=255,G=69,B=0,A=255)
+ Tomato=(R=255,G=99,B=71,A=255)
+ Coral=(R=255,G=127,B=80,A=255)
+ DarkOrange=(R=255,G=140,B=0,A=255)
+ Orange=(R=255,G=165,B=0,A=255)
+ Yellow=(R=255,G=255,B=0,A=255)
+ LightYellow=(R=255,G=255,B=224,A=255)
+ LemonChiffon=(R=255,G=250,B=205,A=255)
+ LightGoldenrodYellow=(R=250,G=250,B=210,A=255)
+ PapayaWhip=(R=255,G=239,B=213,A=255)
+ Moccasin=(R=255,G=228,B=181,A=255)
+ PeachPuff=(R=255,G=218,B=185,A=255)
+ PaleGoldenrod=(R=238,G=232,B=170,A=255)
+ Khaki=(R=240,G=230,B=140,A=255)
+ DarkKhaki=(R=189,G=183,B=107,A=255)
+ Gold=(R=255,G=215,B=0,A=255)
+ Cornsilk=(R=255,G=248,B=220,A=255)
+ BlanchedAlmond=(R=255,G=235,B=205,A=255)
+ Bisque=(R=255,G=228,B=196,A=255)
+ NavajoWhite=(R=255,G=222,B=173,A=255)
+ Wheat=(R=245,G=222,B=179,A=255)
+ Burlywood=(R=222,G=184,B=135,A=255)
+ TanColor=(R=210,G=180,B=140,A=255)
+ RosyBrown=(R=188,G=143,B=143,A=255)
+ SandyBrown=(R=244,G=164,B=96,A=255)
+ Goldenrod=(R=218,G=165,B=32,A=255)
+ DarkGoldenrod=(R=184,G=134,B=11,A=255)
+ Peru=(R=205,G=133,B=63,A=255)
+ Chocolate=(R=210,G=105,B=30,A=255)
+ SaddleBrown=(R=139,G=69,B=19,A=255)
+ Sienna=(R=160,G=82,B=45,A=255)
+ Brown=(R=165,G=42,B=42,A=255)
+ Maroon=(R=128,G=0,B=0,A=255)
+ DarkOliveGreen=(R=85,G=107,B=47,A=255)
+ Olive=(R=128,G=128,B=0,A=255)
+ OliveDrab=(R=107,G=142,B=35,A=255)
+ YellowGreen=(R=154,G=205,B=50,A=255)
+ LimeGreen=(R=50,G=205,B=50,A=255)
+ Lime=(R=0,G=255,B=0,A=255)
+ LawnGreen=(R=124,G=252,B=0,A=255)
+ Chartreuse=(R=127,G=255,B=0,A=255)
+ GreenYellow=(R=173,G=255,B=47,A=255)
+ SpringGreen=(R=0,G=255,B=127,A=255)
+ MediumSpringGreen=(R=0,G=250,B=154,A=255)
+ LightGreen=(R=144,G=238,B=144,A=255)
+ PaleGreen=(R=152,G=251,B=152,A=255)
+ DarkSeaGreen=(R=143,G=188,B=143,A=255)
+ MediumAquamarine=(R=102,G=205,B=170,A=255)
+ MediumSeaGreen=(R=60,G=179,B=113,A=255)
+ SeaGreen=(R=46,G=139,B=87,A=255)
+ ForestGreen=(R=34,G=139,B=34,A=255)
+ Green=(R=0,G=128,B=0,A=255)
+ DarkGreen=(R=0,G=100,B=0,A=255)
+ Aqua=(R=0,G=255,B=255,A=255)
+ Cyan=(R=0,G=255,B=255,A=255)
+ LightCyan=(R=224,G=255,B=255,A=255)
+ PaleTurquoise=(R=175,G=238,B=238,A=255)
+ Aquamarine=(R=127,G=255,B=212,A=255)
+ Turquoise=(R=64,G=224,B=208,A=255)
+ MediumTurquoise=(R=72,G=209,B=204,A=255)
+ DarkTurquoise=(R=0,G=206,B=209,A=255)
+ LightSeaGreen=(R=32,G=178,B=170,A=255)
+ CadetBlue=(R=95,G=158,B=160,A=255)
+ DarkCyan=(R=0,G=139,B=139,A=255)
+ Teal=(R=0,G=128,B=128,A=255)
+ LightSteelBlue=(R=176,G=196,B=222,A=255)
+ PowderBlue=(R=176,G=224,B=230,A=255)
+ LightBlue=(R=173,G=216,B=230,A=255)
+ SkyBlue=(R=135,G=206,B=235,A=255)
+ LightSkyBlue=(R=135,G=206,B=250,A=255)
+ DeepSkyBlue=(R=0,G=191,B=255,A=255)
+ DodgerBlue=(R=30,G=144,B=255,A=255)
+ CornflowerBlue=(R=100,G=149,B=237,A=255)
+ SteelBlue=(R=70,G=130,B=180,A=255)
+ RoyalBlue=(R=65,G=105,B=225,A=255)
+ Blue=(R=0,G=0,B=255,A=255)
+ MediumBlue=(R=0,G=0,B=205,A=255)
+ DarkBlue=(R=0,G=0,B=139,A=255)
+ Navy=(R=0,G=0,B=128,A=255)
+ MidnightBlue=(R=25,G=25,B=112,A=255)
+ Lavender=(R=230,G=230,B=250,A=255)
+ Thistle=(R=216,G=191,B=216,A=255)
+ Plum=(R=221,G=160,B=221,A=255)
+ Violet=(R=238,G=130,B=238,A=255)
+ Orchid=(R=218,G=112,B=214,A=255)
+ Fuchsia=(R=255,G=0,B=255,A=255)
+ Magenta=(R=255,G=0,B=255,A=255)
+ MediumOrchid=(R=186,G=85,B=211,A=255)
+ MediumPurple=(R=147,G=112,B=219,A=255)
+ BlueViolet=(R=138,G=43,B=226,A=255)
+ DarkViolet=(R=148,G=0,B=211,A=255)
+ DarkOrchid=(R=153,G=50,B=204,A=255)
+ DarkMagenta=(R=139,G=0,B=139,A=255)
+ Purple=(R=128,G=0,B=128,A=255)
+ Indigo=(R=75,G=0,B=130,A=255)
+ DarkSlateBlue=(R=72,G=61,B=139,A=255)
+ SlateBlue=(R=106,G=90,B=205,A=255)
+ MediumSlateBlue=(R=123,G=104,B=238,A=255)
+ White=(R=255,G=255,B=255,A=255)
+ Snow=(R=255,G=250,B=250,A=255)
+ Honeydew=(R=240,G=255,B=240,A=255)
+ MintCream=(R=245,G=255,B=250,A=255)
+ Azure=(R=240,G=255,B=255,A=255)
+ AliceBlue=(R=240,G=248,B=255,A=255)
+ GhostWhite=(R=248,G=248,B=255,A=255)
+ WhiteSmoke=(R=245,G=245,B=245,A=255)
+ Seashell=(R=255,G=245,B=238,A=255)
+ Beige=(R=245,G=245,B=220,A=255)
+ OldLace=(R=253,G=245,B=230,A=255)
+ FloralWhite=(R=255,G=250,B=240,A=255)
+ Ivory=(R=255,G=255,B=240,A=255)
+ AntiqueWhite=(R=250,G=235,B=215,A=255)
+ Linen=(R=250,G=240,B=230,A=255)
+ LavenderBlush=(R=255,G=240,B=245,A=255)
+ MistyRose=(R=255,G=228,B=225,A=255)
+ Gainsboro=(R=220,G=220,B=220,A=255)
+ LightGray=(R=211,G=211,B=211,A=255)
+ Silver=(R=192,G=192,B=192,A=255)
+ Gray=(R=169,G=169,B=169,A=255)
+ DimGray=(R=128,G=128,B=128,A=255)
+ DarkGray=(R=105,G=105,B=105,A=255)
+ LightSlateGray=(R=119,G=136,B=153,A=255)
+ SlateGray=(R=112,G=128,B=144,A=255)
+ DarkSlateGray=(R=47,G=79,B=79,A=255)
+ Eigengrau=(R=22,G=22,B=29,A=255)
+ Black=(R=0,G=0,B=0,A=255)
+ CODEPOINT_SMALL_A = 97
+ CODEPOINT_ESCAPE = 27
+}
\ No newline at end of file
diff --git a/sources/Core/Color/Tests/TEST_ColorAPI.uc b/sources/Core/Color/Tests/TEST_ColorAPI.uc
new file mode 100644
index 0000000..fc21a3d
--- /dev/null
+++ b/sources/Core/Color/Tests/TEST_ColorAPI.uc
@@ -0,0 +1,507 @@
+/**
+ * Set of tests for Color API.
+ * Copyright 2020 Anton Tarasenko
+ *------------------------------------------------------------------------------
+ * This file is part of Acedia.
+ *
+ * Acedia is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Acedia is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Acedia. If not, see .
+ */
+class TEST_ColorAPI extends TestCase
+ abstract;
+
+protected static function TESTS()
+{
+ Test_ColorCreation();
+ Test_EqualityCheck();
+ Test_ColorFixing();
+ Test_ToString();
+ Test_Parse();
+ Test_GetTag();
+}
+
+protected static function Test_ColorCreation()
+{
+ Context("Testing `ColorAPI`'s functions for creating color structures.");
+ SubTest_ColorCreationRGB();
+ SubTest_ColorCreationRGBA();
+}
+
+protected static function SubTest_ColorCreationRGB()
+{
+ local Color createdColor;
+ Issue("`RGB() function does not set red, green and blue components"
+ @ "correctly.");
+ createdColor = _().color.RGB(145, 67, 237);
+ TEST_ExpectTrue(createdColor.r == 145);
+ TEST_ExpectTrue(createdColor.g == 67);
+ TEST_ExpectTrue(createdColor.b == 237);
+
+ Issue("`RGB() function does not set alpha component to 255.");
+ TEST_ExpectTrue(createdColor.a == 255);
+
+ Issue("`RGB() function does not set special values (border values"
+ @ "`0`, `255` and value `10`, incorrect for coloring a `string`) for"
+ @"red, green and blue components correctly.");
+ createdColor = _().color.RGB(0, 10, 255);
+ TEST_ExpectTrue(createdColor.r == 0);
+ TEST_ExpectTrue(createdColor.g == 10);
+ TEST_ExpectTrue(createdColor.b == 255);
+
+ Issue("`RGB() function does not set alpha value to 255.");
+ TEST_ExpectTrue(createdColor.a == 255);
+}
+
+protected static function SubTest_ColorCreationRGBA()
+{
+ local Color createdColor;
+ Issue("`RGBA() function does not set red, green, blue, alpha"
+ @ "components correctly.");
+ createdColor = _().color.RGBA(93, 245, 1, 67);
+ TEST_ExpectTrue(createdColor.r == 93);
+ TEST_ExpectTrue(createdColor.g == 245);
+ TEST_ExpectTrue(createdColor.b == 1);
+ TEST_ExpectTrue(createdColor.a == 67);
+
+ Issue("`RGBA() function does not set special values (border values"
+ @ "`0`, `255` and value `10`, incorrect for coloring a `string`) for"
+ @"red, green, blue components correctly.");
+ createdColor = _().color.RGBA(0, 10, 10, 255);
+ TEST_ExpectTrue(createdColor.r == 0);
+ TEST_ExpectTrue(createdColor.g == 10);
+ TEST_ExpectTrue(createdColor.b == 10);
+ TEST_ExpectTrue(createdColor.a == 255);
+}
+
+protected static function Test_EqualityCheck()
+{
+ Context("Testing `ColorAPI`'s functions for color equality check.");
+ SubTest_EqualityCheckNotFixed();
+ SubTest_EqualityCheckFixed();
+}
+
+protected static function SubTest_EqualityCheckNotFixed()
+{
+ local Color color1, color2, color3;
+ color1 = _().color.RGB(45, 10, 19);
+ color2 = _().color.RGB(45, 11, 19);
+ color3 = _().color.RGBA(45, 10, 19, 178);
+ Issue("`AreEqual()` does not recognized equal colors as such.");
+ TEST_ExpectTrue(_().color.AreEqual(color1, color1));
+
+ Issue("`AreEqual()` does not recognized colors that differ only in alpha"
+ @ "channel as equal.");
+ TEST_ExpectTrue(_().color.AreEqual(color1, color3));
+
+ Issue("`AreEqual()` does not recognized different colors as such.");
+ TEST_ExpectFalse(_().color.AreEqual(color1, color2));
+
+ Issue("`AreEqualWithAlpha()` does not recognized equal colors as such.");
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(color1, color1));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(color3, color3));
+
+ Issue("`AreEqualWithAlpha()` does not recognized different colors"
+ @ "as such.");
+ TEST_ExpectFalse(_().color.AreEqualWithAlpha(color1, color2));
+ TEST_ExpectFalse(_().color.AreEqualWithAlpha(color1, color3));
+}
+
+protected static function SubTest_EqualityCheckFixed()
+{
+ local Color color1, color2, color3;
+ color1 = _().color.RGB(45, 10, 0);
+ color2 = _().color.RGB(45, 239, 19);
+ color3 = _().color.RGBA(45, 11, 1, 178);
+ Issue("`AreEqual()` does not recognized equal colors as such (with color"
+ @ "auto-fix).");
+ TEST_ExpectTrue(_().color.AreEqual(color1, color1, true));
+
+ Issue("`AreEqual()` does not recognized colors that differ only in alpha"
+ @ "channel as equal (with color auto-fix).");
+ TEST_ExpectTrue(_().color.AreEqual(color1, color3, true));
+
+ Issue("`AreEqual()` does not recognized different colors as such"
+ @ "(with color auto-fix).");
+ TEST_ExpectFalse(_().color.AreEqual(color1, color2, true));
+
+ Issue("`AreEqualWithAlpha()` does not recognized equal colors as such"
+ @ "(with color auto-fix).");
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(color1, color1, true));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(color3, color3, true));
+
+ Issue("`AreEqualWithAlpha()` does not recognized different colors as such"
+ @ "(with color auto-fix).");
+ TEST_ExpectFalse(_().color.AreEqualWithAlpha(color1, color2, true));
+ TEST_ExpectFalse(_().color.AreEqualWithAlpha(color1, color3, true));
+}
+
+protected static function Test_ColorFixing()
+{
+ local Color validColor, brokenColor;
+ validColor = _().color.RGB(23, 179, 244);
+ brokenColor = _().color.RGB(10, 35, 0);
+ Context("Testing `ColorAPI`'s functions for fixing color components for"
+ @ "game's native render functions.");
+ Issue("`FixColorComponent()` does not \"fix\" values it is expected to,"
+ @ "the way it is expected to.");
+ TEST_ExpectTrue(_().color.FixColorComponent(0) == 1);
+ TEST_ExpectTrue(_().color.FixColorComponent(10) == 11);
+
+ Issue("`FixColorComponent()` changes values it should not.");
+ TEST_ExpectTrue(_().color.FixColorComponent(9) == 9);
+ TEST_ExpectTrue(_().color.FixColorComponent(255) == 255);
+ TEST_ExpectTrue(_().color.FixColorComponent(87) == 87);
+
+ Issue("`FixColor()` changes colors it should not.");
+ TEST_ExpectTrue(
+ _().color.AreEqualWithAlpha(validColor,
+ _().color.FixColor(validColor)));
+
+ Issue("`FixColor()` doesn't fix color it should fix in an expected way.");
+ TEST_ExpectTrue(
+ _().color.AreEqualWithAlpha(_().color.RGB(11, 35, 1),
+ _().color.FixColor(brokenColor)));
+
+ Issue("`FixColor()` affects alpha channel.");
+ TEST_ExpectTrue(_().color.FixColor(validColor).a == 255);
+ validColor.a = 0;
+ TEST_ExpectTrue(_().color.FixColor(validColor).a == 0);
+ validColor.a = 10;
+ TEST_ExpectTrue(_().color.FixColor(validColor).a == 10);
+}
+
+protected static function Test_ToString()
+{
+ Context("Testing `ColorAPI`'s `ToString()` function.");
+ SubTest_ToStringType();
+ SubTest_ToString();
+}
+
+protected static function SubTest_ToStringType()
+{
+ local Color normalColor, borderValueColor;
+ normalColor = _().color.RGBA(24, 232, 187, 34);
+ borderValueColor = _().color.RGBA(0, 255, 255, 0);
+ Issue("`ToStringType()` improperly works with `CLRDISPLAY_HEX` option.");
+ TEST_ExpectTrue(_().color.ToStringType(normalColor) ~= "#18e8bb");
+ TEST_ExpectTrue(_().color.ToStringType(borderValueColor) ~= "#00ffff");
+
+ Issue("`ToStringType()` improperly works with `CLRDISPLAY_RGB` option.");
+ TEST_ExpectTrue(_().color.ToStringType(normalColor, CLRDISPLAY_RGB)
+ ~= "rgb(24,232,187)");
+ TEST_ExpectTrue(_().color.ToStringType(borderValueColor, CLRDISPLAY_RGB)
+ ~= "rgb(0,255,255)");
+
+ Issue("`ToStringType()` improperly works with `CLRDISPLAY_RGBA` option.");
+ TEST_ExpectTrue(_().color.ToStringType(normalColor, CLRDISPLAY_RGBA)
+ ~= "rgba(24,232,187,34)");
+ TEST_ExpectTrue(_().color.ToStringType(borderValueColor, CLRDISPLAY_RGBA)
+ ~= "rgba(0,255,255,0)");
+
+ Issue("`ToStringType()` improperly works with `CLRDISPLAY_RGB_TAG`"
+ @ "option.");
+ TEST_ExpectTrue(_().color.ToStringType(normalColor, CLRDISPLAY_RGB_TAG)
+ ~= "rgb(r=24,g=232,b=187)");
+ TEST_ExpectTrue(_().color.ToStringType(borderValueColor, CLRDISPLAY_RGB_TAG)
+ ~= "rgb(r=0,g=255,b=255)");
+
+ Issue("`ToStringType()` improperly works with `CLRDISPLAY_RGBA_TAG`"
+ @ "option.");
+ TEST_ExpectTrue(_().color.ToStringType(normalColor, CLRDISPLAY_RGBA_TAG)
+ ~= "rgba(r=24,g=232,b=187,a=34)");
+ TEST_ExpectTrue(
+ _().color.ToStringType(borderValueColor, CLRDISPLAY_RGBA_TAG)
+ ~= "rgba(r=0,g=255,b=255,a=0)");
+}
+
+protected static function SubTest_ToString()
+{
+ local Color opaqueColor, transparentColor;
+ opaqueColor = _().color.RGBA(143, 211, 43, 255);
+ transparentColor = _().color.RGBA(234, 32, 145, 13);
+ Issue("`ToString()` improperly converts color with opaque color.");
+ TEST_ExpectTrue(_().color.ToString(opaqueColor) ~= "rgb(143,211,43)");
+ Issue("`ToString()` improperly converts color with transparent color.");
+ TEST_ExpectTrue(_().color.ToString(transparentColor)
+ ~= "rgba(234,32,145,13)");
+}
+
+protected static function Test_GetTag()
+{
+ Context("Testing `ColorAPI`'s functionality of creating 4-byte color"
+ @ "change sequences.");
+ SubTest_GetTagColor();
+ SubTest_GetTagRGB();
+}
+
+protected static function SubTest_GetTagColor()
+{
+ local Color normalColor, borderColor;
+ normalColor = _().color.RGB(143, 211, 43);
+ borderColor = _().color.RGB(10, 0, 255);
+ Issue("`GetColorTag()` does not properly convert colors.");
+ TEST_ExpectTrue(_().color.GetColorTag(normalColor)
+ == (Chr(27) $ Chr(143) $ Chr(211) $ Chr(43)));
+ TEST_ExpectTrue(_().color.GetColorTag(borderColor)
+ == (Chr(27) $ Chr(11) $ Chr(1) $ Chr(255)));
+
+ Issue("`GetColorTag()` does not properly convert colors when asked not to"
+ @ "fix components.");
+ TEST_ExpectTrue(_().color.GetColorTag(normalColor, true)
+ == (Chr(27) $ Chr(143) $ Chr(211) $ Chr(43)));
+ TEST_ExpectTrue(_().color.GetColorTag(borderColor, true)
+ == (Chr(27) $ Chr(10) $ Chr(1) $ Chr(255)));
+}
+
+protected static function SubTest_GetTagRGB()
+{
+ Issue("`GetColorTagRGB()` does not properly convert colors.");
+ TEST_ExpectTrue(_().color.GetColorTagRGB(143, 211, 43)
+ == (Chr(27) $ Chr(143) $ Chr(211) $ Chr(43)));
+ TEST_ExpectTrue(_().color.GetColorTagRGB(10, 0, 255)
+ == (Chr(27) $ Chr(11) $ Chr(1) $ Chr(255)));
+
+ Issue("`GetColorTagRGB()` does not properly convert colors when asked"
+ @ "not to fix components.");
+ TEST_ExpectTrue(_().color.GetColorTagRGB(143, 211, 43, true)
+ == (Chr(27) $ Chr(143) $ Chr(211) $ Chr(43)));
+ TEST_ExpectTrue(_().color.GetColorTagRGB(10, 0, 255, true)
+ == (Chr(27) $ Chr(10) $ Chr(1) $ Chr(255)));
+}
+
+protected static function Test_Parse()
+{
+ Context("Testing `ColorAPI`'s parsing functionality.");
+ SubTest_ParseWithParser();
+ SubTest_ParseStringPlain();
+ SubTest_ParseStringColored();
+ SubTest_ParseStringFormatted();
+ SubTest_ParseText();
+ SubTest_ParseRaw();
+}
+
+protected static function SubTest_ParseWithParser()
+{
+ local Color expectedColor, resultColor;
+ expectedColor = _().color.RGBA(154, 255, 0, 187);
+ Issue("`ParseWith()` cannot parse hex colors.");
+ TEST_ExpectTrue(_().color.ParseWith(_().text.ParseString("#9aff00"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseWith()` cannot parse rgb colors.");
+ TEST_ExpectTrue(_().color.ParseWith(_().text.ParseString("rgb(154,255,0)"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseWith()` cannot parse rgba colors.");
+ TEST_ExpectTrue(_().color.ParseWith(
+ _().text.ParseString("rgba(154,255,0,187)"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(resultColor, expectedColor));
+
+ Issue("`ParseWith()` cannot parse rgb colors with tags.");
+ TEST_ExpectTrue(_().color.ParseWith(
+ _().text.ParseString("rgb(r=154,g=255,b=0)"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseWith()` cannot parse rgba colors with tags.");
+ TEST_ExpectTrue(_().color.ParseWith(
+ _().text.ParseString("rgba(r=154,g=255,b=0,a=187)"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(resultColor, expectedColor));
+
+ Issue("`ParseWith()` reports success when parsing invalid color string.");
+ TEST_ExpectFalse(_().color.ParseWith( _().text.ParseString("#9aff0g"),
+ resultColor));
+}
+
+protected static function SubTest_ParseStringPlain()
+{
+ local Color expectedColor, resultColor;
+ expectedColor = _().color.RGBA(154, 255, 0, 187);
+ Issue("`ParseString()` cannot parse hex colors.");
+ TEST_ExpectTrue(_().color.ParseString("#9aff00", resultColor));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseString()` cannot parse rgb colors.");
+ TEST_ExpectTrue(_().color.ParseString("rgb(154,255,0)", resultColor));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseString()` cannot parse rgba colors.");
+ TEST_ExpectTrue(_().color.ParseString("rgba(154,255,0,187)", resultColor));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(resultColor, expectedColor));
+
+ Issue("`ParseString()` cannot parse rgb colors with tags.");
+ TEST_ExpectTrue(_().color.ParseString("rgb(r=154,g=255,b=0)", resultColor));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseString()` cannot parse rgba colors with tags.");
+ TEST_ExpectTrue(_().color.ParseString( "rgba(r=154,g=255,b=0,a=187)",
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(resultColor, expectedColor));
+
+ Issue("`ParseString()` reports success when parsing invalid color string.");
+ TEST_ExpectFalse(_().color.ParseString("#9aff0g", resultColor));
+}
+
+protected static function SubTest_ParseStringColored()
+{
+ local Color expectedColor, resultColor;
+ expectedColor = _().color.RGBA(154, 255, 0, 187);
+ Issue("`ParseString(STRING_Colored)` cannot parse hex colors.");
+ TEST_ExpectTrue(_().color.ParseString(
+ "#9af" $ Chr(27) $ Chr(45) $ Chr(234) $ Chr(24) $ "f00",
+ resultColor, STRING_Colored));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseString(STRING_Colored)` cannot parse rgb colors.");
+ TEST_ExpectTrue(_().color.ParseString(
+ "rgb(154,2" $ Chr(27) $ Chr(23) $ Chr(32) $ Chr(53) $ "55,0)",
+ resultColor, STRING_Colored));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseString(STRING_Colored)` cannot parse rgba colors.");
+ TEST_ExpectTrue(_().color.ParseString(
+ "rgba(154,255,0,187" $ Chr(27) $ Chr(133) $ Chr(234) $ Chr(10) $ ")",
+ resultColor, STRING_Colored));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(resultColor, expectedColor));
+
+ Issue("`ParseString(STRING_Colored)` cannot parse rgb colors with tags.");
+ TEST_ExpectTrue(_().color.ParseString(
+ "rg" $ Chr(27) $ Chr(26) $ Chr(234) $ Chr(125) $ "b(r=154,g=255,b=0)",
+ resultColor, STRING_Colored));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseString(STRING_Colored)` cannot parse rgba colors with tags.");
+ TEST_ExpectTrue(_().color.ParseString(
+ "rgba(r=154,g=255,b" $ Chr(27) $ Chr(1) $ Chr(4) $ Chr(7) $ "=0,a=187)",
+ resultColor, STRING_Colored));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(resultColor, expectedColor));
+}
+
+protected static function SubTest_ParseStringFormatted()
+{
+ local Color expectedColor, resultColor;
+ expectedColor = _().color.RGBA(154, 255, 0, 187);
+ Issue("`ParseString(STRING_Formatted)` cannot parse hex colors.");
+ TEST_ExpectTrue(_().color.ParseString(
+ "#9a{#4753d5 ff0}0",
+ resultColor, STRING_Formatted));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseString(STRING_Formatted)` cannot parse rgb colors.");
+ TEST_ExpectTrue(_().color.ParseString(
+ "rg{rgb(45,67,123) b(154,25}5,0)",
+ resultColor, STRING_Formatted));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseString(STRING_Formatted)` cannot parse rgba colors.");
+ TEST_ExpectTrue(_().color.ParseString(
+ "rgba(154,2{#34d1a7 }55,0,187)",
+ resultColor, STRING_Formatted));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(resultColor, expectedColor));
+
+ Issue("`ParseString(STRING_Formatted)` cannot parse rgb colors with tags.");
+ TEST_ExpectTrue(_().color.ParseString(
+ "rgb(r{#34d1a7 }=154,g=255,b=0)",
+ resultColor, STRING_Formatted));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseString(STRING_Formatted)` cannot parse rgba colors with"
+ @ "tags.");
+ TEST_ExpectTrue(_().color.ParseString(
+ "r{rgb(12,12,253) gba(r=154,g=255,b=0,a=187)}",
+ resultColor, STRING_Formatted));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(resultColor, expectedColor));
+}
+
+protected static function SubTest_ParseText()
+{
+ local Color expectedColor, resultColor;
+ expectedColor = _().color.RGBA(154, 255, 0, 187);
+ Issue("`ParseText()` cannot parse hex colors.");
+ TEST_ExpectTrue(_().color.ParseText(_().text.FromString("#9aff00"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseText()` cannot parse rgb colors.");
+ TEST_ExpectTrue(_().color.ParseText(_().text.FromString("rgb(154,255,0)"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseText()` cannot parse rgba colors.");
+ TEST_ExpectTrue(_().color.ParseText(
+ _().text.FromString("rgba(154,255,0,187)"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(resultColor, expectedColor));
+
+ Issue("`ParseText()` cannot parse rgb colors with tags.");
+ TEST_ExpectTrue(_().color.ParseText(
+ _().text.FromString("rgb(r=154,g=255,b=0)"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseText()` cannot parse rgba colors with tags.");
+ TEST_ExpectTrue(_().color.ParseText(
+ _().text.FromString("rgba(r=154,g=255,b=0,a=187)"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(resultColor, expectedColor));
+
+ Issue("`ParseText()` reports success when parsing invalid color string.");
+ TEST_ExpectFalse(_().color.ParseText( _().text.FromString("#9aff0g"),
+ resultColor));
+}
+
+protected static function SubTest_ParseRaw()
+{
+ local Color expectedColor, resultColor;
+ expectedColor = _().color.RGBA(154, 255, 0, 187);
+ Issue("`ParseRaw()` cannot parse hex colors.");
+ TEST_ExpectTrue(_().color.ParseRaw( _().text.StringToRaw("#9aff00"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseRaw()` cannot parse rgb colors.");
+ TEST_ExpectTrue(_().color.ParseRaw( _().text.StringToRaw("rgb(154,255,0)"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseRaw()` cannot parse rgba colors.");
+ TEST_ExpectTrue(_().color.ParseRaw(
+ _().text.StringToRaw("rgba(154,255,0,187)"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(resultColor, expectedColor));
+
+ Issue("`ParseRaw()` cannot parse rgb colors with tags.");
+ TEST_ExpectTrue(_().color.ParseRaw(
+ _().text.StringToRaw("rgb(r=154,g=255,b=0)"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqual(resultColor, expectedColor));
+
+ Issue("`ParseRaw()` cannot parse rgba colors with tags.");
+ TEST_ExpectTrue(_().color.ParseRaw(
+ _().text.StringToRaw("rgba(r=154,g=255,b=0,a=187)"),
+ resultColor));
+ TEST_ExpectTrue(_().color.AreEqualWithAlpha(resultColor, expectedColor));
+
+ Issue("`ParseRaw()` reports success when parsing invalid color string.");
+ TEST_ExpectFalse(_().color.ParseRaw(_().text.StringToRaw("#9aff0g"),
+ resultColor));
+}
+
+defaultproperties
+{
+ caseName = "Colors"
+}
\ No newline at end of file