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.slice.char")
80 unittest {
81     auto chars = ['a', 'b', 'c'];
82     backAndForth(chars);
83 }
84 
85 
86 @("aa.int.string")
87 unittest {
88     backAndForth([1: "foo", 2: "bar"]);
89 }
90 
91 
92 @("aa.string.int")
93 unittest {
94     backAndForth(["foo": 1, "bar": 2]);
95 }
96 
97 
98 @("tuple.int.int.int")
99 unittest {
100     backAndForth(tuple(3, 5, 7));
101 }
102 
103 
104 @("tuple.int.string")
105 unittest {
106     backAndForth(tuple(42, "foo"));
107 }
108 
109 
110 @("udt.intstring.val")
111 unittest {
112     backAndForth(IntString(42, "quux"));
113 }
114 
115 @("udt.intstring.ptr")
116 unittest {
117     const value = new IntString(42, "quux");
118     const back = value.toPython.to!(typeof(value));
119     (*back).should == *value;
120 }
121 
122 
123 @("udt.class")
124 unittest {
125 
126     static class Class {
127         int i;
128         this(int i) { this.i = i; }
129         int twice() @safe @nogc pure nothrow const { return i * 2; }
130         override string toString() @safe pure const {
131             import std.conv: text;
132             return text("Class(", i, ")");
133         }
134     }
135 
136     backAndForth(new Class(42));
137 }
138 
139 
140 @("udt.class.baseref")
141 unittest {
142     import std.conv: text;
143     import std.string: fromStringz;
144 
145     static class Base {
146         int i;
147         this() {}
148         this(int i) { this.i = i; }
149         int twice() @safe @nogc pure nothrow const { return i * 2; }
150         override string toString() @safe pure const {
151             import std.conv: text;
152             return text("Base(", i, ")");
153         }
154     }
155 
156     static class Child: Base {
157         this() {}
158         this(int i) { super(i); }
159         override string toString() @safe pure const {
160             import std.conv: text;
161             return text("Child(", i, ")");
162         }
163     }
164 
165 
166     auto child = new Child(42);
167     child.toString.should == "Child(42)";
168     auto python = child.toPython;
169     auto back = python.to!Base;
170     assert(typeid(back) == typeid(Child), text("Expected Child but got ", typeid(back)));
171     back.toString.should == "Child(42)";
172 }
173 
174 
175 @("udt.struct.ptr.uncopiable")
176 unittest {
177     static struct Uncopiable {
178         @disable this(this);
179         int i;
180     }
181     const value = new Uncopiable(42);
182     const back = value.toPython.to!(typeof(value));
183 }