1 module unittesting.articlegenerator;
2 
3 import std.datetime;
4 import std.random;
5 import std.range;
6 
7 import vibe.data.json;
8 
9 import devto.api;
10 
11 @safe:
12 
13 string articleTemplate = `{
14     "published_at":null,
15     "canonical_url":"https://dev.to/username/articleslug",
16     "comments_count":0,
17     "page_views_count":0,
18     "id":111111,
19     "published_timestamp":"2020-01-16T01:22:00Z",
20     "positive_reactions_count":0,
21     "published":false,
22     "body_markdown":"Text used in the article.",
23     "title":"Title of the Article",
24     "url":"https://dev.to/username/articleslug",
25     "user":{
26       "username":"username",
27       "profile_image":"https://res.cloudinary.com/practicaldev/SomeImage.png",
28       "github_username":"GitHubUserName",
29       "profile_image_90":"https://res.cloudinary.com/practicaldev/SomeImage.png",
30       "website_url":"https://www.example.com",
31       "twitter_username":null,
32       "name":"User Name"
33     },
34     "cover_image":null,
35     "slug":"articleslug",
36     "description":"",
37     "path":"/username/articleslug",
38     "tag_list":[
39       "testing"
40     ],
41     "type_of":"article"
42   }`;
43 
44 /**
45  * Provides an initial article template for testing.
46  *
47  * It is expected to be combined with std.range.generate and seqence.
48  *
49  * `generate!fakeArticleMe.seqence().take(3);`
50  */
51 auto fakeArticleMe() {
52     // Deep copy Json object
53     return articleTemplate.parseJsonString;
54 }
55 
56 /**
57  */
58 auto seqence(R)(R articles, SysTime newestDate = Clock.currTime)
59             if(is(ElementType!R == Json)) {
60     struct DateSequencing {
61         DateTime date;
62         uint id = 10_000;
63         R inner;
64 
65         auto empty () {
66             if(inner.empty) return true;
67             if(id < 2)      return true;
68             return false;
69         }
70 
71         auto front() {
72             auto ans = inner.front;
73             ans["id"] = Json(id);
74             // DateTime has no timezone, we pretend it is UTC after cast
75             ans["published_timestamp"] = Json(date.toISOExtString ~ "Z");
76             return ans;
77         }
78 
79         auto popFront() {
80             inner.popFront();
81             id--;
82             date -= dur!"days"(uniform(1,12));
83         }
84     }
85 
86     DateSequencing ds;
87     ds.date = cast(DateTime) newestDate;
88     ds.inner = articles;
89     return ds;
90 } unittest {
91     import std.algorithm : equal, map, isSorted;
92     auto seq = generate!fakeArticleMe.seqence(Clock.currTime).take(3);
93     assert(seq.map!(x => x["id"].get!uint).equal([10_000, 9_999, 9_998]));
94     assert(seq.map!(x => x["published_timestamp"].get!string).array.isSorted!"a > b");
95 }