11package fi .helsinki .cs .tmc .langs .r ;
22
3-
43import fi .helsinki .cs .tmc .langs .AbstractLanguagePlugin ;
4+ import fi .helsinki .cs .tmc .langs .abstraction .Strategy ;
5+ import fi .helsinki .cs .tmc .langs .abstraction .ValidationError ;
56import fi .helsinki .cs .tmc .langs .abstraction .ValidationResult ;
67import fi .helsinki .cs .tmc .langs .domain .ExerciseBuilder ;
78import fi .helsinki .cs .tmc .langs .domain .ExerciseDesc ;
89import fi .helsinki .cs .tmc .langs .domain .RunResult ;
10+ import fi .helsinki .cs .tmc .langs .domain .SpecialLogs ;
911import fi .helsinki .cs .tmc .langs .domain .TestDesc ;
12+ import fi .helsinki .cs .tmc .langs .domain .TestResult ;
1013import fi .helsinki .cs .tmc .langs .io .StudentFilePolicy ;
1114import fi .helsinki .cs .tmc .langs .io .sandbox .StudentFileAwareSubmissionProcessor ;
1215import fi .helsinki .cs .tmc .langs .io .zip .StudentFileAwareUnzipper ;
1316import fi .helsinki .cs .tmc .langs .io .zip .StudentFileAwareZipper ;
14-
1517import fi .helsinki .cs .tmc .langs .utils .ProcessRunner ;
1618
17-
1819import com .google .common .base .Optional ;
1920import com .google .common .collect .ImmutableList ;
20-
21+ import com .google .common .collect .ImmutableMap ;
22+ import com .google .common .collect .Maps ;
2123
2224import org .apache .commons .lang3 .ArrayUtils ;
2325import org .apache .commons .lang3 .SystemUtils ;
26+ import org .apache .commons .lang3 .exception .ExceptionUtils ;
2427
2528import org .slf4j .Logger ;
2629import org .slf4j .LoggerFactory ;
2730
31+ import java .io .File ;
2832import java .io .IOException ;
33+ import java .nio .file .Files ;
2934import java .nio .file .Path ;
35+ import java .nio .file .Paths ;
36+ import java .util .ArrayList ;
37+ import java .util .HashMap ;
38+ import java .util .List ;
3039import java .util .Locale ;
40+ import java .util .Map ;
3141
42+ public final class RPlugin extends AbstractLanguagePlugin {
3243
33-
34- public class RPlugin extends AbstractLanguagePlugin {
35-
36- // Various static final Path-variables for filepaths
37- // to various folders and files in a R exercise project here
44+ /**
45+ * R folder contains the actual R files used in the
46+ * project/package. It is automatically included when creating a
47+ * R package but now when making a regular project in RStudio.
48+ */
3849 private static final Path R_FOLDER_PATH = Paths .get ("R" );
50+
51+ /**
52+ * test/testthat folder contains the unit testing
53+ * files which use the testThat library for the R project.
54+ */
3955 private static final Path TEST_FOLDER_PATH = Paths .get ("tests" );
4056 private static final Path TESTTHAT_FOLDER_PATH = Paths .get ("testthat" );
41- private static final Path TESTTHAT_FILE_PATH = Paths .get ("testthat.R" );
42- private static final Path DESCRIPTION_PATH = Paths .get ("DESCRIPTION" );
43- private static final Path RESULT_R_PATH = Paths .get ("result.R" );
44-
4557
46-
47- // Various static final String-variables for
48- // error messages related to parsing and running R tests here
4958 private static final String CANNOT_RUN_TESTS_MESSAGE = "Failed to run tests." ;
5059 private static final String CANNOT_PARSE_TEST_RESULTS_MESSAGE = "Failed to read test results." ;
5160 private static final String CANNOT_SCAN_EXERCISE_MESSAGE = "Failed to scan exercise." ;
@@ -62,33 +71,14 @@ public RPlugin() {
6271 new StudentFileAwareUnzipper ());
6372 }
6473
74+ /**
75+ * NOTE: Files.exists does not seem to be able to verify the R and
76+ * testthat folder's existence if they are empty.
77+ */
6578 @ Override
6679 public boolean isExerciseTypeCorrect (Path path ) {
6780 return Files .exists (path .resolve (R_FOLDER_PATH ))
68- || Files .exists (path .resolve (TEST_FOLDER_PATH ).resolve (TESTTHAT_FOLDER_PATH ))
69- || Files .exists (path .resolve (TEST_FOLDER_PATH ).resolve (TESTTHAT_FILE_PATH ))
70- || Files .exists (path .resolve (DESCRIPTION_PATH ));
71- /*
72- R folder contains the actual R files used in the
73- project/package. It is automatically included when creating a
74- R package but now when making a regular project in RStudio.
75-
76- test/testthat folder contains the unit testing
77- files which use the testThat library for the R project.
78-
79- DESCRIPTION file contains package information.
80- Included automatically when making a new package, but not
81- included when making a regular project in RStudio.
82-
83- .RHistory file contains the history of executed code on
84- the R terminal. Generated after running code on the R
85- terminal for the first time.
86-
87- tmc/result.R contains the call to tmcRtestrunner's runTests function.
88-
89- NOTE: Files.exists does not seem to be able to verify the R and
90- testthat folder's existence if they are empty.
91- */
81+ || Files .exists (path .resolve (TEST_FOLDER_PATH ).resolve (TESTTHAT_FOLDER_PATH ));
9282 }
9383
9484 @ Override
@@ -104,43 +94,67 @@ public String getPluginName() {
10494 @ Override
10595 public Optional <ExerciseDesc > scanExercise (Path path , String exerciseName ) {
10696 ProcessRunner runner = new ProcessRunner (this .getAvailablePointsCommand (), path );
97+
10798 try {
10899 runner .call ();
109100 } catch (Exception e ) {
110- System .out .println (e );
111101 log .error (CANNOT_SCAN_EXERCISE_MESSAGE , e );
102+ return Optional .absent ();
112103 }
104+
113105 try {
114106 ImmutableList <TestDesc > testDescs = new RExerciseDescParser (path ).parse ();
115107 return Optional .of (new ExerciseDesc (exerciseName , testDescs ));
116108 } catch (IOException e ) {
117109 log .error (CANNOT_PARSE_EXERCISE_DESCRIPTION_MESSAGE , e );
118110 }
111+
119112 return Optional .absent ();
120113 }
121114
122115 @ Override
123116 public RunResult runTests (Path path ) {
124-
125117 ProcessRunner runner = new ProcessRunner (getTestCommand (), path );
118+
126119 try {
127120 runner .call ();
128121 } catch (Exception e ) {
129122 log .error (CANNOT_RUN_TESTS_MESSAGE , e );
123+ return getGenericErrorRunResult (e );
130124 }
131125
132126 try {
133127 return new RTestResultParser (path ).parse ();
134128 } catch (IOException e ) {
135129 log .error (CANNOT_PARSE_TEST_RESULTS_MESSAGE , e );
130+ return getGenericErrorRunResult (e );
136131 }
137- return null ;
132+ }
133+
134+ private RunResult getGenericErrorRunResult (Throwable exception ) {
135+ Map <String , byte []> logMap = new HashMap <>();
136+ byte [] stackTraceAsByteArray = ExceptionUtils .getStackTrace (exception ).getBytes ();
137+ logMap .put (SpecialLogs .GENERIC_ERROR_MESSAGE , stackTraceAsByteArray );
138+
139+ ImmutableMap <String , byte []> logs = ImmutableMap .copyOf (logMap );
140+
141+ return new RunResult (RunResult .Status .GENERIC_ERROR ,
142+ ImmutableList .copyOf (new ArrayList <TestResult >()), logs );
138143 }
139144
140145 @ Override
141- public ValidationResult checkCodeStyle (Path path , Locale messageLocale ) throws UnsupportedOperationException {
142- // TO DO
143- return null ;
146+ public ValidationResult checkCodeStyle (Path path , Locale messageLocale ) {
147+ return new ValidationResult () {
148+ @ Override
149+ public Strategy getStrategy () {
150+ return Strategy .DISABLED ;
151+ }
152+
153+ @ Override
154+ public Map <File , List <ValidationError >> getValidationErrors () {
155+ return Maps .newHashMap ();
156+ }
157+ };
144158 }
145159
146160 public String [] getTestCommand () {
@@ -165,9 +179,10 @@ public String[] getAvailablePointsCommand() {
165179 return ArrayUtils .addAll (command , args );
166180 }
167181
168-
182+ /**
183+ * No operation for now. To be possibly implemented later: remove .Rdata, .Rhistory etc
184+ */
169185 @ Override
170186 public void clean (Path path ) {
171- // TO DO
172187 }
173188}
0 commit comments