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 * Given a range of `fakeArticleMe()` apply a decending id and publish date 58 * to replicate the behavior of the API. 59 * 60 * Note: This does not provide any unpublished articles which are provided 61 * first in the API. 62 */ 63 auto seqence(R)(R articles, const SysTime newestDate = Clock.currTime) 64 if(is(ElementType!R == Json)) { 65 struct DateSequencing { 66 DateTime date; 67 typeof(iota(3).randomCover) id; 68 R inner; 69 70 this(typeof(id) ids) { 71 id = ids; 72 } 73 74 auto empty () { 75 if(inner.empty) return true; 76 if(id.empty) return true; 77 return false; 78 } 79 80 auto front() { 81 auto ans = inner.front; 82 ans["id"] = Json(id.front); 83 // DateTime has no timezone, we pretend it is UTC after cast 84 ans["published_timestamp"] = Json(date.toISOExtString ~ "Z"); 85 ans["published"] = Json(true); 86 return ans; 87 } 88 89 auto popFront() { 90 inner.popFront(); 91 id.popFront; 92 date -= dur!"days"(uniform(1,12)); 93 } 94 } 95 96 DateSequencing ds = DateSequencing(iota(10_000).randomCover); 97 ds.date = cast(DateTime) newestDate; 98 ds.inner = articles; 99 return ds; 100 } unittest { 101 import std.algorithm : equal, map, isSorted; 102 auto seq = generate!fakeArticleMe.seqence(Clock.currTime).take(3); 103 assert(seq.map!(x => x["published_timestamp"].get!string).array.isSorted!"a > b"); 104 }