Testcase generation tool for combinatorial interaction testing
リビジョン | 9a57fefe6b476ca5bdcda3dac3b8f02b3fc272f5 (tree) |
---|---|
日時 | 2018-07-27 13:39:53 |
作者 | Tatsuhiro Tsuchiya <t-tutiya@ist....> |
コミッター | Tatsuhiro Tsuchiya |
find forbidden pairs
@@ -0,0 +1,7 @@ | ||
1 | +P1 (A1 A2 A3) | |
2 | +P2 (B1 B2 B3) | |
3 | +P3 (C1 C2 C3) | |
4 | + | |
5 | +(if (== [P1] A1) (== [P2] B1)) | |
6 | + | |
7 | +(if (== [P2] B1) (== [P3] C1)) |
@@ -0,0 +1,224 @@ | ||
1 | +package fbt; | |
2 | +import v1.*; | |
3 | +import v1.Error; | |
4 | + | |
5 | +import java.util.List; | |
6 | +import java.util.TreeSet; | |
7 | + | |
8 | +public class Main { | |
9 | + static int randomSeed = -1; | |
10 | + static String modelFile; | |
11 | + static int numOfIterations = 1; | |
12 | + static String seedFile; | |
13 | + static String outputFile; | |
14 | + static int strength = 2; // default strength | |
15 | + | |
16 | + static final int MAX_LEVEL = 63; | |
17 | + | |
18 | + static final int MAX_ITERATIONS = 100000; | |
19 | + static final int MAX_STRENGTH = 5; | |
20 | + static final int Max_RandomSeed = 65535; | |
21 | + // static final int Max_RandomSeed = 10; | |
22 | + | |
23 | + static boolean debugMode = false; | |
24 | + | |
25 | + enum Language { | |
26 | + JP, EN | |
27 | + }; | |
28 | + | |
29 | + static Language language = Language.JP; | |
30 | + | |
31 | + // Start the whole process | |
32 | + public static void main(String[] args) { | |
33 | + | |
34 | + long start = System.currentTimeMillis(); | |
35 | + | |
36 | + try { | |
37 | + // コマンド引数処理 | |
38 | + String errorMessage = processCommandArgument(args); | |
39 | + | |
40 | + // エラー出力先設定 | |
41 | + Error.setOutputFile(outputFile); | |
42 | + | |
43 | + // コマンド引数でのエラー出力 | |
44 | + if (errorMessage != null) | |
45 | + Error.printError(errorMessage); | |
46 | + | |
47 | + // モデル読み込み | |
48 | + // System.err.println("starting reading model"); | |
49 | + InputFileData inputfiledata = Inputer.readModel(modelFile); | |
50 | + | |
51 | + // 制約処理 BDD作成 | |
52 | + ConstraintHandler conhndl = new ConstraintHandler( | |
53 | + inputfiledata.parameterList, inputfiledata.constraintList, inputfiledata.constrainedParameters); | |
54 | + | |
55 | + // | |
56 | + ParameterModel parametermodel = new ParameterModel(inputfiledata.parameterList); | |
57 | + | |
58 | + checkAllTuples(parametermodel, conhndl, inputfiledata); | |
59 | + | |
60 | + } catch (OutOfMemoryError e) { | |
61 | + Error.printError(Main.language == Main.Language.JP ? "メモリ不足です." | |
62 | + : "Out of memory"); | |
63 | + } catch (Exception e) { | |
64 | + Error.printError(Main.language == Main.Language.JP ? "プログラムが異常終了しました." | |
65 | + : "Abnormal termination"); | |
66 | + } | |
67 | + | |
68 | + // long end = System.currentTimeMillis(); | |
69 | + // System.err.println("time: " + (end - start) + "ms"); | |
70 | + } | |
71 | + | |
72 | + // コマンド引数処理 | |
73 | + private static String processCommandArgument(String[] args) { | |
74 | + if (args.length == 0) { | |
75 | + Error.printError("usage: java -jar Program.jar [-i input] [-o output] [-policy] ..."); | |
76 | + } | |
77 | + | |
78 | + // policyの表示 | |
79 | + if (args.length == 1 && args[0].equals("-policy")) { | |
80 | + System.out | |
81 | + .println("This software (CIT-BACH 1.1) is distributed under the zlib license.\n" | |
82 | + + "The software contains Java classes from JDD, a Java BDD library " | |
83 | + + "developed by Arash Vahidi.\n" | |
84 | + + "JDD is free software distributed under the zlib license.\n" | |
85 | + + "\n" | |
86 | + + "Copyright (c) 2015, Tatsuhiro Tsuchiya\n" | |
87 | + + "This software is provided 'as-is', without any express or implied \n" | |
88 | + + "warranty. In no event will the authors be held liable for any damages \n" | |
89 | + + "arising from the use of this software. \n" | |
90 | + + "\n" | |
91 | + + "Permission is granted to anyone to use this software for any purpose, \n" | |
92 | + + "including commercial applications, and to alter it and redistribute it \n" | |
93 | + + "freely, subject to the following restrictions: \n" | |
94 | + + " \n" | |
95 | + + " 1. The origin of this software must not be misrepresented; you must not \n" | |
96 | + + " claim that you wrote the original software. If you use this software \n" | |
97 | + + " in a product, an acknowledgment in the product documentation would be \n" | |
98 | + + " appreciated but is not required. \n" | |
99 | + + " \n" | |
100 | + + " 2. Altered source versions must be plainly marked as such, and must not be \n" | |
101 | + + " misrepresented as being the original software. \n" | |
102 | + + " \n" | |
103 | + + " 3. This notice may not be removed or altered from any source \n" | |
104 | + + " distribution. \n"); | |
105 | + System.exit(0); | |
106 | + } | |
107 | + | |
108 | + // エラー表示を出力ファイルが指定されるまで遅らせる | |
109 | + String errorMessage = null; | |
110 | + | |
111 | + for (int i = 0; i + 1 < args.length; i += 2) { | |
112 | + String option = args[i]; | |
113 | + String str = args[i + 1]; | |
114 | + if (option.equals("-i")) { | |
115 | + modelFile = str; | |
116 | + } else if (option.equals("-o")) { | |
117 | + outputFile = str; | |
118 | + } else if (option.equals("-random")) { | |
119 | + try { | |
120 | + randomSeed = Integer.parseInt(str); | |
121 | + } catch (NumberFormatException e) { | |
122 | + // Error.printError("invalid number"); | |
123 | + errorMessage = Main.language == Main.Language.JP ? "ランダムシードに無効な値が指定されています." | |
124 | + : "Invalid random seed"; | |
125 | + continue; | |
126 | + } | |
127 | + randomSeed = Math.abs(randomSeed) % (Max_RandomSeed + 1); | |
128 | + } else if (option.equals("-c")) { | |
129 | + if (str.equals("all")) { | |
130 | + // 全網羅 | |
131 | + strength = -1; | |
132 | + } else { | |
133 | + try { | |
134 | + strength = Integer.parseInt(str); | |
135 | + } catch (NumberFormatException e) { | |
136 | + // Error.printError("invalid number"); | |
137 | + errorMessage = Main.language == Main.Language.JP ? "網羅度に無効な値が指定されています." | |
138 | + : "Invalid strength"; | |
139 | + continue; | |
140 | + } | |
141 | + if (strength < 2 || MAX_STRENGTH < strength) { | |
142 | + // Error.printError("invalid strength"); | |
143 | + errorMessage = Main.language == Main.Language.JP ? "網羅度に無効な値が指定されています." | |
144 | + : "Invalid strength"; | |
145 | + continue; | |
146 | + } | |
147 | + } | |
148 | + } | |
149 | + // 繰り返し数 | |
150 | + else if (option.equals("-repeat")) { | |
151 | + try { | |
152 | + numOfIterations = Integer.parseInt(str); | |
153 | + } catch (NumberFormatException e) { | |
154 | + // Error.printError("invalid repeating number"); | |
155 | + errorMessage = Main.language == Main.Language.JP ? "くり返し数に無効な値が指定されています." | |
156 | + : "Invalid number of repetition times"; | |
157 | + continue; | |
158 | + } | |
159 | + if (numOfIterations <= 0 || numOfIterations > MAX_ITERATIONS) { | |
160 | + // Error.printError("invalid repeating number"); | |
161 | + errorMessage = Main.language == Main.Language.JP ? "くり返し数に無効な値が指定されています." | |
162 | + : "Invalid number of repetition times"; | |
163 | + continue; | |
164 | + } | |
165 | + } else if (option.equals("-s")) { | |
166 | + seedFile = str; | |
167 | + } else if (option.equals("-debug")) { | |
168 | + debugMode = true; | |
169 | + // 次の引数はダミー | |
170 | + } else if (option.equals("-lang")) { | |
171 | + if (str.matches("JP|jp")) { | |
172 | + Main.language = Main.Language.JP; | |
173 | + } else if (str.matches("EN|en")) { | |
174 | + Main.language = Main.Language.EN; | |
175 | + } else { | |
176 | + errorMessage = "無効な言語が指定されています (Invalid Language)"; | |
177 | + continue; | |
178 | + } | |
179 | + } else { | |
180 | + // Error.printError("Invalid option"); | |
181 | + errorMessage = Main.language == Main.Language.JP ? "無効なオプションが指定されています." | |
182 | + : "Invalid option"; | |
183 | + continue; | |
184 | + } | |
185 | + } | |
186 | + | |
187 | + if (randomSeed == -1) { | |
188 | + randomSeed = (int) Math.floor(Math.random() * (Max_RandomSeed + 1)); | |
189 | + } | |
190 | + | |
191 | + return errorMessage; | |
192 | + } | |
193 | + | |
194 | + private static void checkAllTuples(ParameterModel parametermodel, ConstraintHandler conhndl, | |
195 | + InputFileData inputfiledata) { | |
196 | + // strength = 2 | |
197 | + int numOfParameters = parametermodel.size; | |
198 | + for (int i = 0; i < numOfParameters - 1; i++) { | |
199 | + for (int j = i + 1; j < numOfParameters; j++) { | |
200 | + for (byte v1 = 0; v1 < parametermodel.range[i]; v1++) { | |
201 | + for (byte v2 = 0; v2 < parametermodel.range[j]; v2++) { | |
202 | + // pairの生成 | |
203 | + Testcase pair = new Testcase(numOfParameters); | |
204 | + pair.quantify(); | |
205 | + pair.set(i, v1); | |
206 | + pair.set(j, v2); | |
207 | + // pairのチェック | |
208 | + // 禁則違反ならset | |
209 | + if (conhndl.isPossible(pair) == false) { | |
210 | +// System.out.println("[" + i + ", " + v1 + "]" + ", " + | |
211 | + // "[" + j + ", " + v2 + "]]"); | |
212 | + String para1 = inputfiledata.parameterList.get(i).name; | |
213 | + String str1 = inputfiledata.parameterList.get(i).value_name.get(v1); | |
214 | + String para2 = inputfiledata.parameterList.get(i).name; | |
215 | + String str2 = inputfiledata.parameterList.get(j).value_name.get(v2); | |
216 | + System.out.println("[" + para1 + ", " + str1 + "]" + ", " + | |
217 | + "[" + para2 + ", " + str2 + "]"); | |
218 | + } | |
219 | + } | |
220 | + } | |
221 | + } | |
222 | + } | |
223 | + } | |
224 | +} |
@@ -0,0 +1,19 @@ | ||
1 | +package v1; | |
2 | + | |
3 | +import java.util.List; | |
4 | +import java.util.TreeSet; | |
5 | + | |
6 | +public class InputFileData { | |
7 | + public PList parameterList; | |
8 | + public GList groupList; | |
9 | + public List<Node> constraintList; | |
10 | + public TreeSet<Integer> constrainedParameters; | |
11 | + | |
12 | + InputFileData(PList parameterList, GList groupList, | |
13 | + List<Node> constraintList, TreeSet<Integer> constrainedParameters) { | |
14 | + this.parameterList = parameterList; | |
15 | + this.groupList = groupList; | |
16 | + this.constraintList = constraintList; | |
17 | + this.constrainedParameters = constrainedParameters; | |
18 | + } | |
19 | +} |
@@ -0,0 +1,45 @@ | ||
1 | +package v1; | |
2 | + | |
3 | +import java.util.LinkedList; | |
4 | +import java.util.TreeSet; | |
5 | + | |
6 | +public class PList extends LinkedList<Parameter> { | |
7 | + | |
8 | + private static final long serialVersionUID = 1L; | |
9 | + | |
10 | + boolean checkNameDuplication() { | |
11 | + for (int i = 0; i < this.size() - 1; i++) | |
12 | + for (int j = i + 1; j < this.size(); j++) { | |
13 | + if (this.get(i).name.equals(this.get(j).name)) { | |
14 | + return true; | |
15 | + } | |
16 | + } | |
17 | + return false; | |
18 | + } | |
19 | + | |
20 | + int getID(String str) throws NoParameterNameException { | |
21 | + for (int i = 0; i < this.size(); i++) { | |
22 | + if (this.get(i).name.equals(str)) | |
23 | + return i; | |
24 | + } | |
25 | + throw new NoParameterNameException(); | |
26 | + } | |
27 | + | |
28 | + // useless? | |
29 | + int getRestrictedID(String str, TreeSet<Integer> RestrictedParameters) | |
30 | + throws NoParameterNameException { | |
31 | + try { | |
32 | + int parameter = this.getID(str); | |
33 | + int num = 0; | |
34 | + for (Integer i: RestrictedParameters) { | |
35 | + if (i == parameter) | |
36 | + return num; | |
37 | + num++; | |
38 | + } | |
39 | + } catch (NoParameterNameException e) { | |
40 | + throw e; | |
41 | + } | |
42 | + // if the parameter is not a relevant one | |
43 | + throw new NoParameterNameException(); | |
44 | + } | |
45 | +} |
@@ -0,0 +1,91 @@ | ||
1 | +package v1; | |
2 | + | |
3 | +import java.io.BufferedWriter; | |
4 | +import java.io.IOException; | |
5 | + | |
6 | +public class Testcase { | |
7 | + byte[] value; // 0..level-1, or <0 (wildcard) | |
8 | + | |
9 | + // これを他から読んでるとまずいかも? | |
10 | + public Testcase(int n) { | |
11 | + this.value = new byte[n]; | |
12 | + } | |
13 | + | |
14 | + public void set(int parameter, byte value) { | |
15 | + this.value[parameter] = value; | |
16 | + } | |
17 | + | |
18 | + void setWildCard(int parameter) { | |
19 | + this.value[parameter] = -1; | |
20 | + } | |
21 | + | |
22 | + byte get(int parameter) { | |
23 | + return value[parameter]; | |
24 | + } | |
25 | + | |
26 | + int getint(int parameter) { | |
27 | + return (int) value[parameter]; | |
28 | + } | |
29 | + | |
30 | + public void quantify() { | |
31 | + for (int i = 0; i < this.value.length; i++) | |
32 | + this.value[i] = -1; | |
33 | + } | |
34 | + | |
35 | + Testcase makeClone() { | |
36 | + Testcase newtest = new Testcase(this.value.length); | |
37 | + for (int i = 0; i < newtest.value.length; i++) { | |
38 | + newtest.value[i] = this.value[i]; | |
39 | + } | |
40 | + return newtest; | |
41 | + } | |
42 | + | |
43 | + void print() { | |
44 | + for (int i = 0; i < value.length; i++) | |
45 | + System.err.print(value[i] + ","); | |
46 | + System.err.println(); | |
47 | + } | |
48 | + | |
49 | + // TODO Outputer.java に移動 | |
50 | + void print(BufferedWriter writer, InputFileData inputfiledata) | |
51 | + throws IOException { | |
52 | + for (int i = 0; i < value.length; i++) | |
53 | + writer.write((i == 0 ? "" : ",") | |
54 | + + inputfiledata.parameterList.get(i).value_name | |
55 | + .get(value[i])); | |
56 | + writer.write("\n"); | |
57 | + } | |
58 | + | |
59 | + // tupleを重ねる | |
60 | + // return true if a tuple is superimposed | |
61 | + // 重ねた時に禁則に違反することあり->チェックする | |
62 | + boolean superimpose(Testcase tuple, ConstraintHandler h) { | |
63 | + Testcase tmp = this.makeClone(); | |
64 | + if (tmp.superimpose(tuple) == false) | |
65 | + return false; | |
66 | + if (h.isPossible(tmp) == false) | |
67 | + return false; | |
68 | + return this.superimpose(tuple); | |
69 | + // must be true; | |
70 | + } | |
71 | + | |
72 | + // tupleを重ねる | |
73 | + // return true if a tuple is superimposed | |
74 | + // 重ねた時に禁則に違反することあり->チェックしない | |
75 | + private boolean superimpose(Testcase tuple) { | |
76 | + // TODO Auto-generated method stu | |
77 | + for (int i = 0; i < value.length; i++) { | |
78 | + if (value[i] < 0 || tuple.value[i] < 0) | |
79 | + continue; | |
80 | + if (value[i] == tuple.value[i]) | |
81 | + continue; | |
82 | + return false; | |
83 | + } | |
84 | + | |
85 | + for (int i = 0; i < value.length; i++) { | |
86 | + if (value[i] < 0) | |
87 | + this.set(i, tuple.get(i)); | |
88 | + } | |
89 | + return true; | |
90 | + } | |
91 | +} |