1 module dli.string_stream.output_string_stream;
2 
3 public shared class OutputStringStream
4 {
5     private string _content = "";
6     immutable string lineTerminator;
7 
8     @property
9     public string content()
10     out(s)
11     {
12         assert(s !is null);
13     }
14     body
15     {
16         return _content;
17     }
18 
19     public this(string content = "", string lineTerminator = "\n")
20     in
21     {
22         assert(content !is null);
23         assert(lineTerminator !is null);
24     }
25     body
26     {
27         this.lineTerminator = lineTerminator;
28         write(content);
29     }
30 
31     public final void writeln(string s)
32     in
33     {
34         assert(s !is null);
35     }
36     body
37     {
38         write(s ~ lineTerminator);
39     }
40 
41     public final void write(string s)
42     in
43     {
44         assert(s !is null);
45     }
46     body
47     {
48         synchronized
49         {
50             _content ~= s;
51         }
52     }
53 }
54 
55 // TESTS
56 
57 @("OutputStringStream stores content appropriately")
58 unittest
59 {
60     import unit_threaded : shouldEqual;
61 
62     immutable string lineTerminator = "\n\r"; // Use something other than the default
63     immutable string initializerContent = "Content passed in the initializer" ~ lineTerminator;
64 
65     auto stream = new shared OutputStringStream(initializerContent, lineTerminator);
66 
67     stream.content.shouldEqual(initializerContent);
68 
69     immutable string startOfLine1 = "This is the start of line 1...";
70     stream.write(startOfLine1);
71 
72     stream.content.shouldEqual(initializerContent ~ startOfLine1);
73 
74     immutable string endOfLine1 = "... and this is the end of line 1";
75     stream.writeln(endOfLine1);
76 
77     stream.content.shouldEqual(initializerContent ~ startOfLine1 ~
78                                endOfLine1 ~ lineTerminator);
79 }
80 
81 @("OutputStringStream can be written to from multiple threads")
82 unittest
83 {
84     import unit_threaded : shouldEqual;
85 
86     import std..string : count;
87     import core.thread : ThreadGroup;
88 
89     immutable string toBeWritten = "This is what each thread should write, plus the default line terminator";
90 
91     auto stream = new shared OutputStringStream();
92 
93     auto threadGroup = new ThreadGroup();
94 
95     enum threadsToUse = 20;
96 
97     for(size_t i; i < threadsToUse; i++)
98         threadGroup.create(
99             {
100                 stream.writeln(toBeWritten);
101             });
102 
103     threadGroup.joinAll();
104 
105     stream.content.count(toBeWritten ~ stream.lineTerminator).shouldEqual(threadsToUse);
106 }