blob: 5e9636be9ebc16afa09fc3b7fd07ca9dbb70ac08 [file] [log] [blame]
@safe unittest
{
import std.conv;
import std.exception : assertThrown;
assertThrown!ConvException(to!int("abc"));
}
@safe unittest
{
import std.conv;
import std.exception : assertThrown;
assertThrown!ConvOverflowException(to!ubyte(1_000_000));
}
@safe pure unittest
{
import std.conv;
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
}
@safe pure unittest
{
import std.conv;
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
}
@safe pure unittest
{
import std.conv;
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
}
@safe pure unittest
{
import std.conv;
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
}
@safe pure unittest
{
import std.conv;
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
}
@safe pure unittest
{
import std.conv;
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
}
@safe unittest
{
import std.conv;
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
}
@safe pure unittest
{
import std.conv;
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
}
@system pure unittest
{
import std.conv;
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
}
@safe pure unittest
{
import std.conv;
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
}
@safe unittest
{
import std.conv;
assert(roundTo!int(3.14) == 3);
assert(roundTo!int(3.49) == 3);
assert(roundTo!int(3.5) == 4);
assert(roundTo!int(3.999) == 4);
assert(roundTo!int(-3.14) == -3);
assert(roundTo!int(-3.49) == -3);
assert(roundTo!int(-3.5) == -4);
assert(roundTo!int(-3.999) == -4);
assert(roundTo!(const int)(to!(const double)(-3.999)) == -4);
}
@safe unittest
{
import std.conv;
import std.typecons : Flag, Yes, No;
auto s = "true";
bool b = parse!bool(s);
assert(b);
auto s2 = "true";
bool b2 = parse!(bool, string, No.doCount)(s2);
assert(b2);
auto s3 = "true";
auto b3 = parse!(bool, string, Yes.doCount)(s3);
assert(b3.data && b3.count == 4);
auto s4 = "falSE";
auto b4 = parse!(bool, string, Yes.doCount)(s4);
assert(!b4.data && b4.count == 5);
}
@safe pure unittest
{
import std.conv;
import std.typecons : Flag, Yes, No;
string s = "123";
auto a = parse!int(s);
assert(a == 123);
string s1 = "123";
auto a1 = parse!(int, string, Yes.doCount)(s1);
assert(a1.data == 123 && a1.count == 3);
}
@safe pure unittest
{
import std.conv;
import std.string : tr;
import std.typecons : Flag, Yes, No;
string test = "123 \t 76.14";
auto a = parse!uint(test);
assert(a == 123);
assert(test == " \t 76.14"); // parse bumps string
test = tr(test, " \t\n\r", "", "d"); // skip ws
assert(test == "76.14");
auto b = parse!double(test);
assert(b == 76.14);
assert(test == "");
string test2 = "123 \t 76.14";
auto a2 = parse!(uint, string, Yes.doCount)(test2);
assert(a2.data == 123 && a2.count == 3);
assert(test2 == " \t 76.14");// parse bumps string
test2 = tr(test2, " \t\n\r", "", "d"); // skip ws
assert(test2 == "76.14");
auto b2 = parse!(double, string, Yes.doCount)(test2);
assert(b2.data == 76.14 && b2.count == 5);
assert(test2 == "");
}
@safe unittest
{
import std.conv;
import std.typecons : Flag, Yes, No, tuple;
enum EnumType : bool { a = true, b = false, c = a }
auto str = "a";
assert(parse!EnumType(str) == EnumType.a);
auto str2 = "a";
assert(parse!(EnumType, string, No.doCount)(str2) == EnumType.a);
auto str3 = "a";
assert(parse!(EnumType, string, Yes.doCount)(str3) == tuple(EnumType.a, 1));
}
@safe unittest
{
import std.conv;
import std.math.operations : isClose;
import std.math.traits : isNaN, isInfinity;
import std.typecons : Flag, Yes, No;
auto str = "123.456";
assert(parse!double(str).isClose(123.456));
auto str2 = "123.456";
assert(parse!(double, string, No.doCount)(str2).isClose(123.456));
auto str3 = "123.456";
auto r = parse!(double, string, Yes.doCount)(str3);
assert(r.data.isClose(123.456));
assert(r.count == 7);
auto str4 = "-123.456";
r = parse!(double, string, Yes.doCount)(str4);
assert(r.data.isClose(-123.456));
assert(r.count == 8);
auto str5 = "+123.456";
r = parse!(double, string, Yes.doCount)(str5);
assert(r.data.isClose(123.456));
assert(r.count == 8);
auto str6 = "inf0";
r = parse!(double, string, Yes.doCount)(str6);
assert(isInfinity(r.data) && r.count == 3 && str6 == "0");
auto str7 = "-0";
auto r2 = parse!(float, string, Yes.doCount)(str7);
assert(r2.data.isClose(0.0) && r2.count == 2);
auto str8 = "nan";
auto r3 = parse!(real, string, Yes.doCount)(str8);
assert(isNaN(r3.data) && r3.count == 3);
}
@safe pure unittest
{
import std.conv;
import std.typecons : Flag, Yes, No;
auto s = "Hello, World!";
char first = parse!char(s);
assert(first == 'H');
assert(s == "ello, World!");
char second = parse!(char, string, No.doCount)(s);
assert(second == 'e');
assert(s == "llo, World!");
auto third = parse!(char, string, Yes.doCount)(s);
assert(third.data == 'l' && third.count == 1);
assert(s == "lo, World!");
}
@safe pure unittest
{
import std.conv;
import std.exception : assertThrown;
import std.typecons : Flag, Yes, No;
alias NullType = typeof(null);
auto s1 = "null";
assert(parse!NullType(s1) is null);
assert(s1 == "");
auto s2 = "NUll"d;
assert(parse!NullType(s2) is null);
assert(s2 == "");
auto s3 = "nuLlNULl";
assert(parse!(NullType, string, No.doCount)(s3) is null);
auto r = parse!(NullType, string, Yes.doCount)(s3);
assert(r.data is null && r.count == 4);
auto m = "maybe";
assertThrown!ConvException(parse!NullType(m));
assertThrown!ConvException(parse!(NullType, string, Yes.doCount)(m));
assert(m == "maybe"); // m shouldn't change on failure
auto s = "NULL";
assert(parse!(const NullType)(s) is null);
}
@safe pure unittest
{
import std.conv;
import std.typecons : Flag, Yes, No;
auto s1 = `[['h', 'e', 'l', 'l', 'o'], "world"]`;
auto a1 = parse!(string[])(s1);
assert(a1 == ["hello", "world"]);
auto s2 = `["aaa", "bbb", "ccc"]`;
auto a2 = parse!(string[])(s2);
assert(a2 == ["aaa", "bbb", "ccc"]);
auto s3 = `[['h', 'e', 'l', 'l', 'o'], "world"]`;
auto len3 = s3.length;
auto a3 = parse!(string[], string, Yes.doCount)(s3);
assert(a3.data == ["hello", "world"]);
assert(a3.count == len3);
}
@safe pure unittest
{
import std.conv;
import std.typecons : Flag, Yes, No, tuple;
import std.range.primitives : save;
import std.array : assocArray;
auto s1 = "[1:10, 2:20, 3:30]";
auto copyS1 = s1.save;
auto aa1 = parse!(int[int])(s1);
assert(aa1 == [1:10, 2:20, 3:30]);
assert(tuple([1:10, 2:20, 3:30], copyS1.length) == parse!(int[int], string, Yes.doCount)(copyS1));
auto s2 = `["aaa":10, "bbb":20, "ccc":30]`;
auto copyS2 = s2.save;
auto aa2 = parse!(int[string])(s2);
assert(aa2 == ["aaa":10, "bbb":20, "ccc":30]);
assert(tuple(["aaa":10, "bbb":20, "ccc":30], copyS2.length) ==
parse!(int[string], string, Yes.doCount)(copyS2));
auto s3 = `["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]`;
auto copyS3 = s3.save;
auto aa3 = parse!(int[][string])(s3);
assert(aa3 == ["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]);
assert(tuple(["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]], copyS3.length) ==
parse!(int[][string], string, Yes.doCount)(copyS3));
auto s4 = `[]`;
int[int] emptyAA;
assert(tuple(emptyAA, s4.length) == parse!(int[int], string, Yes.doCount)(s4));
}
@safe unittest
{
import std.conv;
assert( text(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"c);
assert(wtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"w);
assert(dtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"d);
}
@safe unittest
{
import std.conv;
// Same as 0177
auto a = octal!177;
// octal is a compile-time device
enum b = octal!160;
// Create an unsigned octal
auto c = octal!"1_000_000u";
// Leading zeros are allowed when converting from a string
auto d = octal!"0001_200_000";
}
@safe unittest
{
import std.conv;
import std.traits : Unsigned;
immutable int s = 42;
auto u1 = unsigned(s); //not qualified
static assert(is(typeof(u1) == uint));
Unsigned!(typeof(s)) u2 = unsigned(s); //same qualification
static assert(is(typeof(u2) == immutable uint));
immutable u3 = unsigned(s); //explicitly qualified
}
@safe unittest
{
import std.conv;
import std.traits : Signed;
immutable uint u = 42;
auto s1 = signed(u); //not qualified
static assert(is(typeof(s1) == int));
Signed!(typeof(u)) s2 = signed(u); //same qualification
static assert(is(typeof(s2) == immutable int));
immutable s3 = signed(u); //explicitly qualified
}
@safe unittest
{
import std.conv;
enum A { a = 42 }
static assert(is(typeof(A.a.asOriginalType) == int));
assert(A.a.asOriginalType == 42);
enum B : double { a = 43 }
static assert(is(typeof(B.a.asOriginalType) == double));
assert(B.a.asOriginalType == 43);
}
@system unittest
{
import std.conv;
// Regular cast, which has been verified to be legal by the programmer:
{
long x;
auto y = cast(int) x;
}
// However this will still compile if 'x' is changed to be a pointer:
{
long* x;
auto y = cast(int) x;
}
// castFrom provides a more reliable alternative to casting:
{
long x;
auto y = castFrom!long.to!int(x);
}
// Changing the type of 'x' will now issue a compiler error,
// allowing bad casts to be caught before it's too late:
{
long* x;
static assert(
!__traits(compiles, castFrom!long.to!int(x))
);
// if cast is still needed, must be changed to:
auto y = castFrom!(long*).to!int(x);
}
}
@safe unittest
{
import std.conv;
// conversion at compile time
auto string1 = hexString!"304A314B";
assert(string1 == "0J1K");
auto string2 = hexString!"304A314B"w;
assert(string2 == "0J1K"w);
auto string3 = hexString!"304A314B"d;
assert(string3 == "0J1K"d);
}
@safe unittest
{
import std.conv;
import std.algorithm.comparison : equal;
assert(toChars(1).equal("1"));
assert(toChars(1_000_000).equal("1000000"));
assert(toChars!(2)(2U).equal("10"));
assert(toChars!(16)(255U).equal("ff"));
assert(toChars!(16, char, LetterCase.upper)(255U).equal("FF"));
}
@safe unittest
{
import std.conv;
uint n = 0xDEADBEEF;
version (LittleEndian)
assert(n.bitCast!(ubyte[4]) == [0xEF, 0xBE, 0xAD, 0xDE]);
version (BigEndian)
assert(n.bitCast!(ubyte[4]) == [0xDE, 0xAD, 0xBE, 0xEF]);
}