1 module dshould.contain;
2 
3 import dshould.ShouldType;
4 import dshould.basic : not, should;
5 
6 /**
7  * The word `.contain` takes one value, expected to appear in the range on the left hand side.
8  */
9 public void contain(Should, T)(Should should, T expected, Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__)
10 if (isInstanceOf!(ShouldType, Should))
11 {
12     should.allowOnlyWords!("not", "only").before!"contain";
13 
14     should.addWord!"contain".checkContain(expected, file, line);
15 }
16 
17 ///
18 unittest
19 {
20     [2, 3, 4].should.contain(3);
21     [2, 3, 4].should.not.contain(5);
22 }
23 
24 public auto contain(Should)(Should should)
25 if (isInstanceOf!(ShouldType, Should))
26 {
27     should.allowOnlyWords!("not").before!"contain";
28 
29     return should.addWord!"contain";
30 }
31 
32 /**
33  * The phrase `.contain.only` or `.only.contain` takes a range, the elements of which are expected to be the only
34  * elements appearing in the range on the left hand side.
35  */
36 public void only(Should, T)(Should should, T expected, Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__)
37 if (isInstanceOf!(ShouldType, Should))
38 {
39     should.requireWord!"contain".before!"only";
40     should.allowOnlyWords!("not", "contain").before!"only";
41 
42     should.addWord!"only".checkContain(expected, file, line);
43 }
44 
45 ///
46 unittest
47 {
48     [3, 4].should.only.contain([4, 3]);
49     [3, 4].should.only.contain([1, 2, 3, 4]);
50     [3, 4].should.contain.only([4, 3]);
51     [2, 3, 4].should.not.only.contain([4, 3]);
52 }
53 
54 public auto only(Should)(Should should)
55 if (isInstanceOf!(ShouldType, Should))
56 {
57     should.allowOnlyWords!("not").before!"only";
58 
59     return should.addWord!"only";
60 }
61 
62 /**
63  * The phrase `.contain.all` takes a range, all elements of which are expected to appear
64  * in the range on the left hand side.
65  */
66 public void all(Should, T)(Should should, T expected, Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__)
67 if (isInstanceOf!(ShouldType, Should))
68 {
69     should.requireWord!"contain".before!"all";
70     should.allowOnlyWords!("not", "contain").before!"all";
71 
72     should.addWord!"all".checkContain(expected, file, line);
73 }
74 
75 ///
76 unittest
77 {
78     [2, 3, 4].should.contain.all([3]);
79     [2, 3, 4].should.contain.all([4, 3]);
80     [2, 3, 4].should.not.contain.all([3, 4, 5]);
81 }
82 
83 /**
84  * The phrase `.contain.any` takes a range, at least one element of which is expected to appear
85  * in the range on the left hand side.
86  */
87 public void any(Should, T)(Should should, T expected, Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__)
88 if (isInstanceOf!(ShouldType, Should))
89 {
90     should.requireWord!"contain".before!"any";
91     should.allowOnlyWords!("not", "contain").before!"any";
92 
93     should.addWord!"any".checkContain(expected, file, line);
94 }
95 
96 ///
97 unittest
98 {
99     [2, 3, 4].should.contain.any([4, 5]);
100     [2, 3, 4].should.not.contain.any([5, 6]);
101 }
102 
103 private void checkContain(Should, T)(Should should, T expected, string file, size_t line)
104 if (isInstanceOf!(ShouldType, Should))
105 {
106     import std.algorithm : any, all, canFind;
107     import std.format : format;
108     import std.range : ElementType, save;
109 
110     with (should)
111     {
112         auto got = should.got();
113 
114         enum rhsIsValue = is(T == ElementType!(typeof(got)));
115 
116         static if (rhsIsValue)
117         {
118             allowOnlyWords!("not", "only", "contain").before!"contain";
119 
120             static if (hasWord!"only")
121             {
122                 static if (hasWord!"not")
123                 {
124                     check(
125                         got.any!(a => a != expected),
126                         format("array containing values other than %s", expected),
127                         format("%s", got),
128                         file, line);
129                 }
130                 else
131                 {
132                     check(
133                         got.all!(a => a == expected),
134                         format("array containing only the value %s", expected),
135                         format("%s", got),
136                         file, line);
137                 }
138             }
139             else
140             {
141                 static if (hasWord!"not")
142                 {
143                     check(
144                         !got.save.canFind(expected),
145                         format("array not containing %s", expected),
146                         format("%s", got),
147                         file, line);
148                 }
149                 else
150                 {
151                     check(
152                         got.save.canFind(expected),
153                         format("array containing %s", expected),
154                         format("%s", got),
155                         file, line);
156                 }
157             }
158         }
159         else
160         {
161             static if (hasWord!"only")
162             {
163                 static if (hasWord!"not")
164                 {
165                     check(
166                         !got.all!(a => expected.save.canFind(a)),
167                         format("array containing values other than %s", expected),
168                         format("%s", got),
169                         file, line);
170                 }
171                 else
172                 {
173                     check(
174                         got.all!(a => expected.save.canFind(a)),
175                         format("array containing only the values %s", expected),
176                         format("%s", got),
177                         file, line);
178                 }
179             }
180             else static if (hasWord!"all")
181             {
182                 static if (hasWord!"not")
183                 {
184                     check(
185                         !expected.all!(a => got.save.canFind(a)),
186                         format("array not containing every value in %s", expected),
187                         format("%s", got),
188                         file, line);
189                 }
190                 else
191                 {
192                     check(
193                         expected.all!(a => got.save.canFind(a)),
194                         format("array containing every value in %s", expected),
195                         format("%s", got),
196                         file, line);
197                 }
198             }
199             else static if (hasWord!"any")
200             {
201                 static if (hasWord!"not")
202                 {
203                     check(
204                         !expected.any!(a => got.save.canFind(a)),
205                         format("array not containing any value in %s", expected),
206                         format("%s", got),
207                         file, line);
208                 }
209                 else
210                 {
211                     check(
212                         expected.any!(a => got.save.canFind(a)),
213                         format("array containing any value of %s", expected),
214                         format("%s", got),
215                         file, line);
216                 }
217             }
218             else
219             {
220                 static assert(false,
221                     `bad grammar: expected "contain all", "contain any", "contain only" (or "only contain")`);
222             }
223         }
224     }
225 }