1 /**
2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved.
3 License: MPL-2
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 This Source Code Form is subject to the terms of the Mozilla Public License,
7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain
8 one at http://mozilla.org/MPL/2.0/.
9 */
10 module dextool.plugin.mutate.backend.interface_;
11 
12 import std.exception : collectException;
13 import std.stdio : File;
14 import logger = std.experimental.logger;
15 
16 import dextool.type : AbsolutePath;
17 
18 @safe:
19 
20 /** Validate source code locations for analyze and mutation.
21  */
22 interface ValidateLoc {
23     /// Returns: the root directory that files to be mutated must reside inside
24     AbsolutePath getOutputDir() nothrow;
25 
26     /// Returns: if a path should be analyzed for mutation points.
27     bool shouldAnalyze(AbsolutePath p);
28 
29     /// ditto
30     bool shouldAnalyze(string p);
31 
32     /// Returns: if a mutant are allowed to be written to this path.
33     bool shouldMutate(AbsolutePath p);
34 }
35 
36 /** Filesystem I/O from the backend.
37  *
38  * TODO: rename outputDir to workdir. It is the terminology used in git.
39  *
40  * The implementation of the interface shall:
41  *  ensure all SafeOutput objects are inside the _output directory_.
42  *
43  * The design is intended to create a clear distinction between output and
44  * input. It is to make it easier to do code review and reason about where
45  * filesystem output is created.
46  */
47 interface FilesysIO {
48     import std.stdio : File;
49 
50     // these are here so backend do not need to import std.stdio which makes it
51     // easier to review.
52     File getDevNull();
53     File getStdin();
54 
55     /// File output is restricted to this directory
56     AbsolutePath getOutputDir() nothrow;
57 
58     ///
59     SafeOutput makeOutput(AbsolutePath p);
60 
61     ///
62     SafeInput makeInput(AbsolutePath p);
63 
64 protected:
65     void putFile(AbsolutePath fname, const(ubyte)[] data);
66 }
67 
68 struct SafeOutput {
69     import std.array : Appender;
70 
71     private AbsolutePath fname;
72     private FilesysIO fsys;
73     private Appender!(ubyte[]) buf;
74     private bool is_open;
75 
76     @disable this(this);
77 
78     this(AbsolutePath fname, FilesysIO fsys) {
79         this.fname = fname;
80         this.fsys = fsys;
81         this.is_open = true;
82     }
83 
84     ~this() {
85         close();
86     }
87 
88     // trusted: the data is copied therefore it is safe to cast away const.
89     void write(T)(inout T data) @trusted if (!is(T == ubyte[])) {
90         buf.put(cast(ubyte[]) data);
91     }
92 
93     void write(T)(inout T data) if (is(T == ubyte[])) {
94         buf.put(data);
95     }
96 
97     void close() {
98         if (is_open) {
99             fsys.putFile(fname, buf.data);
100             buf.clear;
101         }
102         is_open = false;
103     }
104 }
105 
106 struct SafeInput {
107     private ubyte[] data;
108 
109     this(ubyte[] data) {
110         this.data = data;
111     }
112 
113     ubyte[] read() {
114         return data;
115     }
116 }