1 module pynih.python.conv; 2 3 4 import unit_threaded; 5 import python.conv; 6 import std.datetime: Date, DateTime; 7 import std.typecons: tuple; 8 9 10 struct IntString { 11 int i; 12 string s; 13 } 14 15 16 // helper function to test that converting to python and back yields the same value 17 private void backAndForth(T) 18 (T value, in string file = __FILE__, in size_t line = __LINE__) 19 { 20 value.toPython.to!(typeof(value)).shouldEqual(value, file, line); 21 } 22 23 24 @Types!( 25 bool, 26 byte, ubyte, short, ushort, int, uint, long, ulong, // integral 27 float, double, 28 int[], double[], 29 ) 30 void testBackAndForth(T)() 31 { 32 check!((T d) => d.toPython.to!T == d); 33 } 34 35 36 @("DateTime") 37 unittest { 38 backAndForth(DateTime(2018, 1, 2, 3, 4, 5)); 39 } 40 41 42 @("Date") 43 unittest { 44 backAndForth(Date(2018, 1, 2)); 45 } 46 47 48 @Values("foobar", "quux") 49 @("string.ascii") 50 unittest { 51 const value = getValue!string; 52 backAndForth(value); 53 } 54 55 56 @ShouldFail 57 @Values("café", "açaí") 58 @("string.unicode") 59 unittest { 60 const value = getValue!string; 61 backAndForth(value); 62 } 63 64 65 @("array.static.int") 66 unittest { 67 int[2] value = [1, 2]; 68 backAndForth(value); 69 } 70 71 72 @("array.static.double") 73 unittest { 74 double[3] value = [11.1, 22.2, 33.3]; 75 backAndForth(value); 76 } 77 78 79 @("array.static.immutable(int)") 80 unittest { 81 immutable(int)[3] ints = [1, 2, 3]; 82 backAndForth(ints); 83 } 84 85 86 @("array.slice.char") 87 unittest { 88 auto chars = ['a', 'b', 'c']; 89 backAndForth(chars); 90 } 91 92 93 @("array.slice.immutable(int)") 94 unittest { 95 immutable(int)[] ints = [1, 2, 3]; 96 backAndForth(ints); 97 } 98 99 @("aa.int.string") 100 unittest { 101 backAndForth([1: "foo", 2: "bar"]); 102 } 103 104 105 @("aa.string.int") 106 unittest { 107 backAndForth(["foo": 1, "bar": 2]); 108 } 109 110 111 @("tuple.int.int.int") 112 unittest { 113 backAndForth(tuple(3, 5, 7)); 114 } 115 116 117 @("tuple.int.string") 118 unittest { 119 backAndForth(tuple(42, "foo")); 120 } 121 122 123 @("udt.intstring.val") 124 unittest { 125 backAndForth(IntString(42, "quux")); 126 } 127 128 @("udt.intstring.ptr") 129 unittest { 130 const value = new IntString(42, "quux"); 131 const back = value.toPython.to!(typeof(value)); 132 (*back).should == *value; 133 } 134 135 136 @("udt.class") 137 unittest { 138 139 static class Class { 140 int i; 141 this(int i) { this.i = i; } 142 int twice() @safe @nogc pure nothrow const { return i * 2; } 143 override string toString() @safe pure const { 144 import std.conv: text; 145 return text("Class(", i, ")"); 146 } 147 } 148 149 backAndForth(new Class(42)); 150 } 151 152 153 @("udt.class.baseref") 154 unittest { 155 import std.conv: text; 156 import std.string: fromStringz; 157 158 static class Base { 159 int i; 160 this() {} 161 this(int i) { this.i = i; } 162 int twice() @safe @nogc pure nothrow const { return i * 2; } 163 override string toString() @safe pure const { 164 import std.conv: text; 165 return text("Base(", i, ")"); 166 } 167 } 168 169 static class Child: Base { 170 this() {} 171 this(int i) { super(i); } 172 override string toString() @safe pure const { 173 import std.conv: text; 174 return text("Child(", i, ")"); 175 } 176 } 177 178 179 auto child = new Child(42); 180 child.toString.should == "Child(42)"; 181 auto python = child.toPython; 182 auto back = python.to!Base; 183 assert(typeid(back) == typeid(Child), text("Expected Child but got ", typeid(back))); 184 back.toString.should == "Child(42)"; 185 } 186 187 188 @("udt.struct.ptr.uncopiable") 189 unittest { 190 static struct Uncopiable { 191 @disable this(this); 192 int i; 193 } 194 const value = new Uncopiable(42); 195 const back = value.toPython.to!(typeof(value)); 196 } 197 198 199 @("udt.struct.char") 200 unittest { 201 static struct Char { 202 char c; 203 } 204 backAndForth(Char('a')); 205 } 206 207 208 @("udt.struct.charptr") 209 unittest { 210 static struct CharPtr { 211 char* ptr; 212 bool opEquals(in CharPtr other) @safe @nogc pure nothrow const { 213 if(ptr is null && other.ptr is null) return true; 214 if(ptr is null && other.ptr !is null) return false; 215 if(ptr !is null && other.ptr is null) return false; 216 return *ptr == *other.ptr; 217 } 218 } 219 backAndForth(CharPtr(new char('a'))); 220 } 221 222 223 // Similar to issue with std.bitmanip.BitArray. 224 // The presence of `opCast` makes the conversion to `const(T)` fail 225 // since there's no available cast to `const(T)`. 226 @("udt.struct.opCast") 227 unittest { 228 static struct Struct { 229 230 void[] opCast(T: void[])() @safe @nogc pure nothrow { 231 return null; 232 } 233 234 size_t[] opCast(T: size_t[])() @safe @nogc pure nothrow { 235 return null; 236 } 237 } 238 239 const s = Struct(); 240 backAndForth(s); 241 } 242 243 244 @ShouldFail("D function pointers not yet supported") 245 @("function") 246 unittest { 247 static string fun(int i, double d) { 248 import std.conv: text; 249 return text("i: ", i, " d: ", d); 250 } 251 const back = (&fun).toPython.to!(typeof(&fun)); 252 } 253 254 255 @("Duration") 256 unittest { 257 import core.time: seconds; 258 backAndForth(1.seconds); 259 } 260 261 262 @("enum.int") 263 unittest { 264 static enum Enum { 265 foo, 266 bar, 267 baz, 268 } 269 270 backAndForth(Enum.bar); 271 } 272 273 274 @("enum.char") 275 unittest { 276 static enum Char: char { 277 a = 'a', 278 b = 'b', 279 } 280 281 backAndForth(Char.b); 282 } 283 284 285 @("dchar") 286 unittest { 287 const str = "foobar"d; 288 backAndForth(str[0]); 289 }