-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEasyCucumber.java
151 lines (137 loc) · 7.44 KB
/
EasyCucumber.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package scs.comp5903.cucumber;
import org.slf4j.Logger;
import scs.comp5903.cucumber.builder.BaseObjectProvider;
import scs.comp5903.cucumber.builder.EasyCachingObjectProvider;
import scs.comp5903.cucumber.builder.JFeatureBuilder;
import scs.comp5903.cucumber.builder.params.CucumberExpressionJStepParameterExtractor;
import scs.comp5903.cucumber.execution.JFeature;
import scs.comp5903.cucumber.model.exception.EasyCucumberException;
import scs.comp5903.cucumber.model.exception.ErrorCode;
import scs.comp5903.cucumber.parser.jfeature.GherkinBasedJFeatureFileParser;
import scs.comp5903.cucumber.parser.jstep.JStepDefinitionHookParser;
import scs.comp5903.cucumber.parser.jstep.JStepDefinitionMethodParser;
import scs.comp5903.cucumber.parser.jstep.JStepDefinitionParser;
import scs.comp5903.cucumber.util.ReflectionUtil;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import static org.slf4j.LoggerFactory.getLogger;
/**
* The facade class of building the runnable {@link JFeature}. <br/>
* It contains: <br/>
* 1. {@code build(Path featureFile, Object... stepDefinitionInstances)} <br/>
* 2. {@code build(Path featureFile, Class<?>... stepDefinitionClasses)} <br/>
* 3. {@code build(Path featureFile, List<Object> stepDefinitionInstances)} <br/>
* 4. {@code build(Path featureFile, String packages)} <br/>
* 5. {@code build(Path featureFile, String packages, BaseObjectProvider objectProvider)} <br/>
* 6. {@code build(Path featureFile, List<Class<?>> stepDefinitionClasses, BaseObjectProvider objectProvider)} <br/>
* <p>
* Where all methods except last one delegate to the last method
*
* @author Charles Chen 101035684
* @date 2022-06-18
*/
public class EasyCucumber {
private static final Logger log = getLogger(EasyCucumber.class);
private EasyCucumber() {
}
/**
* Build the runnable {@link JFeature} from the given feature file and one or more instances of step definition classes.
*
* @param featureFile the feature file to be parsed and ran
* @param stepDefinitionInstances the instances of step definition classes
* @return the runnable {@link JFeature}
*/
public static JFeature build(Path featureFile, Object... stepDefinitionInstances) {
var objectProvider = new EasyCachingObjectProvider(stepDefinitionInstances);
Class<?>[] stepDefinitionClasses = new Class<?>[stepDefinitionInstances.length];
for (int i = 0; i < stepDefinitionInstances.length; i++) {
stepDefinitionClasses[i] = stepDefinitionInstances[i].getClass();
}
return build(featureFile, List.of(stepDefinitionClasses), objectProvider);
}
/**
* Build the runnable {@link JFeature} from the given feature file and one or more step definition classes.
* @param featureFile the feature file to be parsed and ran
* @param stepDefinitionClasses the step definition classes
* @return the runnable {@link JFeature}
*/
public static JFeature build(Path featureFile, Class<?>... stepDefinitionClasses) {
return build(featureFile, List.of(stepDefinitionClasses), new EasyCachingObjectProvider());
}
/**
* Build the runnable {@link JFeature} from the given feature file and step definitions. <br/>
* The step definitions can be either a list of instances of step definition classes or a list of step definition classes.
*
* @param featureFile the feature file to be parsed and ran
* @param stepDefinitions the step definitions, the list can contain either the instances of step definition classes or the step definition classes.
* The list can mix contain both.
* @return the runnable {@link JFeature}
*/
public static JFeature build(Path featureFile, List<Object> stepDefinitions) {
if (stepDefinitions.isEmpty()) {
// 033 is the one of the error code where it can appear twice
throw new EasyCucumberException(ErrorCode.EZCU033, "Need at least one step definition class");
}
var classes = new ArrayList<Class<?>>(stepDefinitions.size());
var instances = new ArrayList<>(stepDefinitions.size());
for (Object o : stepDefinitions) {
if (o instanceof Class<?>) {
classes.add((Class<?>) o);
} else {
classes.add(o.getClass());
instances.add(o);
}
}
return build(featureFile, classes, new EasyCachingObjectProvider(instances.toArray()));
}
/**
* Build the runnable {@link JFeature} from the given feature file and step definition classes from a given package. <br/>
* @param featureFile the feature file to be parsed and ran
* @param packageName the name of the package (in forms of {@code "package.name"}) where it stores all step definition classes
* @return the runnable {@link JFeature}
*/
public static JFeature build(Path featureFile, String packageName) {
return build(featureFile, packageName, new EasyCachingObjectProvider());
}
/**
* Build the runnable {@link JFeature} from the given feature file and step definition classes from a given package,
* and use a custom {@link BaseObjectProvider} to provide the step definition instances. <br/>
* @param featureFile the feature file to be parsed and ran
* @param packageName the name of the package (in forms of {@code "package.name"}) where it stores all step definition classes
* @param objectProvider the custom {@link BaseObjectProvider} to provide the step definition instances
* @return the runnable {@link JFeature}
*/
public static JFeature build(Path featureFile, String packageName, BaseObjectProvider objectProvider) {
return build(featureFile, new ArrayList<>(ReflectionUtil.findAllClassesUsingClassLoader(packageName)), objectProvider);
}
/**
* The most abstract way of creating a runnable {@link JFeature}. <br/>
* Build the runnable {@link JFeature} from the given feature file and a list of step definition classes,
* and use a custom {@link BaseObjectProvider} to provide the step definition instances. <br/>
*
* @param featureFile the feature file to be parsed and ran
* @param stepDefinitionClasses the list of step definition classes
* @param objectProvider the custom {@link BaseObjectProvider} to provide the step definition instances
* @return the runnable feature
*/
public static JFeature build(Path featureFile, List<Class<?>> stepDefinitionClasses, BaseObjectProvider objectProvider) {
if (stepDefinitionClasses.isEmpty()) {
throw new EasyCucumberException(ErrorCode.EZCU033, "Need at least one step definition class");
}
log.info("Start building the runnable JFeature from feature file: {} with step definition classes: {}", featureFile, stepDefinitionClasses);
var jFeatureFileParser = new GherkinBasedJFeatureFileParser();
var jStepDefinitionMethodParser = new JStepDefinitionMethodParser();
var jStepDefinitionHookParser = new JStepDefinitionHookParser();
var jStepDefinitionParser = new JStepDefinitionParser(jStepDefinitionMethodParser, jStepDefinitionHookParser);
var jStepParameterExtractor = new CucumberExpressionJStepParameterExtractor();
// parse jfeature file to detail object
var featureDetail = jFeatureFileParser.parse(featureFile);
// parse step definition class to detail object
var jStepDefDetail = jStepDefinitionParser.parse(stepDefinitionClasses);
// build runnable feature
var jFeature = new JFeatureBuilder(jStepParameterExtractor).build(featureDetail, jStepDefDetail, objectProvider);
log.info("Successfully built the runnable JFeature: {}", jFeature.getTitle());
return jFeature;
}
}