diff --git a/src/main/java/com/zachary_moore/filters/BaseFilter.java b/src/main/java/com/zachary_moore/filters/BaseFilter.java index bc39eda..36598b3 100644 --- a/src/main/java/com/zachary_moore/filters/BaseFilter.java +++ b/src/main/java/com/zachary_moore/filters/BaseFilter.java @@ -23,7 +23,7 @@ class BaseFilter { * @return {@link ArrayList} of given class type from JSONFile */ List getAllOfType(JSONFile file, Class clazz) { - Object baseObject = file.getObject(); + Object baseObject = file.getChild(); if (baseObject instanceof JSONObject) { return accumulateType((JSONObject) baseObject, clazz); } else if (baseObject instanceof JSONArray){ @@ -42,7 +42,7 @@ List getAllOfType(JSONFile file, Class clazz) { */ List> getAllOfWrappedType(JSONFile file, Class clazz) { ArrayList> wrappedTypeList = new ArrayList<>(); - Object baseObject = file.getObject(); + Object baseObject = file.getChild(); if (baseObject instanceof JSONObject) { wrappedTypeList.addAll(accumulateWrappedTypeFromEntrySet(((JSONObject) baseObject).toMap().entrySet(), clazz)); } else if (baseObject instanceof JSONArray) { diff --git a/src/main/java/com/zachary_moore/filters/FilterMapper.java b/src/main/java/com/zachary_moore/filters/FilterMapper.java index 1f12c44..eafdd75 100644 --- a/src/main/java/com/zachary_moore/filters/FilterMapper.java +++ b/src/main/java/com/zachary_moore/filters/FilterMapper.java @@ -7,6 +7,7 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.util.Collections; import java.util.List; public class FilterMapper { @@ -50,6 +51,8 @@ public static List filter(JSONFile jsonFile, LintImplementation lintImplement return filters.filterToObjects(jsonFile); } else if (lintImplementation.getClazz() == JSONArray.class) { return filters.filterToArrays(jsonFile); + } else if (lintImplementation.getClazz() == JSONFile.class) { + return Collections.singletonList(jsonFile); } else { return null; } diff --git a/src/main/java/com/zachary_moore/lint/BaseJSONAnalyzer.java b/src/main/java/com/zachary_moore/lint/BaseJSONAnalyzer.java index ae1d1c9..52606fb 100644 --- a/src/main/java/com/zachary_moore/lint/BaseJSONAnalyzer.java +++ b/src/main/java/com/zachary_moore/lint/BaseJSONAnalyzer.java @@ -1,9 +1,6 @@ package com.zachary_moore.lint; -import com.zachary_moore.objects.JSONArray; -import com.zachary_moore.objects.JSONObject; -import com.zachary_moore.objects.WrappedObject; -import com.zachary_moore.objects.WrappedPrimitive; +import com.zachary_moore.objects.*; import java.util.Arrays; import java.util.List; @@ -213,4 +210,15 @@ protected boolean isParentOfType(WrappedObject object, Class clazz) { protected boolean reduceBooleans(Boolean... booleans) { return Arrays.stream(booleans).filter(b -> !b).count() == 0; } + + protected int getLineNumber(String offendingText, WrappedObject originatingObject) { + if (originatingObject == null) { + return -1; + } + if (originatingObject instanceof JSONFile) { + return ((JSONFile) originatingObject).getLineNumber(offendingText); + } else { + return getLineNumber(offendingText, originatingObject.getParentObject()); + } + } } diff --git a/src/main/java/com/zachary_moore/objects/JSONFile.java b/src/main/java/com/zachary_moore/objects/JSONFile.java index 9ca21aa..faba179 100644 --- a/src/main/java/com/zachary_moore/objects/JSONFile.java +++ b/src/main/java/com/zachary_moore/objects/JSONFile.java @@ -1,5 +1,6 @@ package com.zachary_moore.objects; +import org.apache.commons.io.FilenameUtils; import org.json.JSONException; import org.json.JSONTokener; @@ -7,22 +8,36 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; -public class JSONFile { +public class JSONFile implements WrappedObject { - private org.json.JSONObject jsonObject; - private org.json.JSONArray jsonArray; + private JSONObject wrappedJsonObject; + private JSONArray wrappedJsonArray; private String filePath; + private String fileExtension; + private List linesInFile; public JSONFile(File file) throws IOException { filePath = file.getCanonicalPath(); + fileExtension = FilenameUtils.getExtension(filePath); + initializeLineNumberData(file); + initializeWrappedObjects(file); + } + + private void initializeWrappedObjects(File file) throws IOException { BufferedReader bufferedReader = new BufferedReader(new FileReader(file)); JSONTokener jsonTokener = new JSONTokener(bufferedReader); try { - jsonObject = new org.json.JSONObject(jsonTokener); + this.wrappedJsonObject = new JSONObject(null, + this, + new org.json.JSONObject(jsonTokener)); } catch (JSONException e) { jsonTokener.back(); - jsonArray = new org.json.JSONArray(jsonTokener); + this.wrappedJsonArray = new JSONArray(null, + this, + new org.json.JSONArray(jsonTokener)); } bufferedReader.close(); } @@ -30,20 +45,54 @@ public JSONFile(File file) throws IOException { /** * @return either {@link JSONObject} or {@link JSONArray} based on input file to constructor */ - public Object getObject() { - if (jsonObject != null) { - return new JSONObject(null, null, jsonObject); - } else if (jsonArray != null) { - return new JSONArray(null, null, jsonArray); - } else { - throw new RuntimeException("Could not parse either a JSONArray or JSONObject from file"); - } + public WrappedObject getChild() { + return wrappedJsonObject != null ? wrappedJsonObject : wrappedJsonArray; + } + + @Override + public String getOriginatingKey() { + return null; + } + + @Override + public WrappedObject getParentObject() { + return null; + } + + @Override + public void parseAndReplaceWithWrappers() { } + + @Override + public boolean isPrimitive() { + return false; } public String getFilePath() { return filePath; } + public String getFileExtension() { + return fileExtension; + } + + private void initializeLineNumberData(File file) throws IOException{ + linesInFile = new ArrayList<>(); + BufferedReader bufferedReader = new BufferedReader(new FileReader(file)); + String line; + while ((line = bufferedReader.readLine()) != null) { + linesInFile.add(line); + } + } + + public int getLineNumber(String offendingText) { + for (int i = 0; i < linesInFile.size(); i++) { + if (linesInFile.get(i).contains(offendingText)) { + return i + 1; + } + } + return -1; + } + @Override public int hashCode() { return this.filePath.hashCode(); diff --git a/src/test/java/com/zachary_moore/objects/JSONFileShould.java b/src/test/java/com/zachary_moore/objects/JSONFileShould.java index 791b80f..2fadce6 100644 --- a/src/test/java/com/zachary_moore/objects/JSONFileShould.java +++ b/src/test/java/com/zachary_moore/objects/JSONFileShould.java @@ -3,29 +3,56 @@ import java.io.File; import java.io.IOException; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNotNull; + public class JSONFileShould { + private File jsonObjectFile; + private File jsonArrayFile; + + public JSONFileShould() { + jsonObjectFile = new File(getClass() + .getClassLoader() + .getResource("test-2.json") + .getFile()); + jsonArrayFile = new File(getClass() + .getClassLoader() + .getResource("array-file.json") + .getFile()); + } + @Test public void JSONFileGivesJSONArray() throws IOException { - JSONFile jsonFile = new JSONFile( - new File(getClass() - .getClassLoader() - .getResource("array-file.json") - .getFile())); - assert(jsonFile.getObject() instanceof JSONArray); - assert(((JSONArray)jsonFile.getObject()).length() == 3); + JSONFile jsonFile = new JSONFile(jsonArrayFile); + assert(jsonFile.getChild() instanceof JSONArray); + assert(((JSONArray)jsonFile.getChild()).length() == 3); } @Test public void JSONFileGivesJSONObject() throws IOException { - JSONFile jsonFile = new JSONFile( - new File(getClass() - .getClassLoader() - .getResource("test-2.json") - .getFile())); - assert(jsonFile.getObject() instanceof JSONObject); + JSONFile jsonFile = new JSONFile(jsonObjectFile); + assert(jsonFile.getChild() instanceof JSONObject); + } + + @Test + public void JSONFileGivesFilePath() throws IOException { + JSONFile jsonFile = new JSONFile(jsonObjectFile); + assert(jsonFile.getFilePath().equals(jsonObjectFile.getAbsolutePath())); + } + + @Test + public void JSONFileGivesFileExtension() throws IOException { + JSONFile jsonFile = new JSONFile(jsonObjectFile); + assert(jsonFile.getFileExtension().equals("json")); + } + + @Test + public void JSONFileChildShouldHaveParent() throws IOException { + JSONFile jsonFile = new JSONFile(jsonObjectFile); + assertNotNull(jsonFile.getChild().getParentObject()); } } diff --git a/src/test/java/com/zachary_moore/overall/JSONFileLineNumberShould.java b/src/test/java/com/zachary_moore/overall/JSONFileLineNumberShould.java new file mode 100644 index 0000000..990e09b --- /dev/null +++ b/src/test/java/com/zachary_moore/overall/JSONFileLineNumberShould.java @@ -0,0 +1,66 @@ +package com.zachary_moore.overall; + +import com.zachary_moore.lint.LintImplementation; +import com.zachary_moore.lint.LintLevel; +import com.zachary_moore.lint.LintRegister; +import com.zachary_moore.lint.LintRule; +import com.zachary_moore.objects.JSONFile; +import com.zachary_moore.objects.JSONObject; +import com.zachary_moore.objects.WrappedPrimitive; +import com.zachary_moore.runner.LintRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class JSONFileLineNumberShould { + + private LintRule.Builder builder; + private LintRegister lintRegister; + + @BeforeEach + public void setUp() { + this.builder = new LintRule.Builder().setIssueId(""); + this.lintRegister = new LintRegister(); + } + + @Test + public void basicLineNumberShouldReturnCorrect() throws Exception { + LintRule lintRule = this.builder.setImplementation(new LintImplementation>() { + @Override + public Class getClazz() { + return String.class; + } + + @Override + public boolean shouldReport(WrappedPrimitive wrappedPrimitive) { + if (wrappedPrimitive.equals("test")) { + setReportMessage("Error occurs on line " + getLineNumber(wrappedPrimitive.getValue(), wrappedPrimitive)); + return true; + } + return false; + } + }).setLevel(LintLevel.ERROR) + .build(); + this.lintRegister.register(lintRule); + LintRunner lintRunner = + new LintRunner(this.lintRegister, + "./src/test/resources/test-2.json"); + + Map>> lintOutput = lintRunner.lint(); + assert(lintRunner.analyzeLintAndGiveExitCode() == 1); + assert(lintOutput.get(lintRule).size() == 1); + + + for (Map.Entry> entry : lintOutput.get(lintRule).entrySet()) { + for (int i = 0; i < entry.getValue().size(); i++) { + if (i == 0) { + assert(entry.getValue().get(i).equals("Error occurs on line 2")); + } + } + } + } +} diff --git a/src/test/java/com/zachary_moore/overall/LintSituationsShould.java b/src/test/java/com/zachary_moore/overall/LintSituationsShould.java new file mode 100644 index 0000000..16c37d9 --- /dev/null +++ b/src/test/java/com/zachary_moore/overall/LintSituationsShould.java @@ -0,0 +1,121 @@ +package com.zachary_moore.overall; + +import com.zachary_moore.lint.LintImplementation; +import com.zachary_moore.lint.LintLevel; +import com.zachary_moore.lint.LintRegister; +import com.zachary_moore.lint.LintRule; +import com.zachary_moore.objects.JSONFile; +import com.zachary_moore.objects.JSONObject; +import com.zachary_moore.objects.WrappedObject; +import com.zachary_moore.runner.LintRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.List; +import java.util.Map; + + +public class LintSituationsShould { + + private LintRule.Builder builder; + private LintRegister lintRegister; + + @BeforeEach + public void setUp() { + this.builder = new LintRule.Builder().setIssueId(""); + this.lintRegister = new LintRegister(); + } + + @Test + public void shouldReportFilePathViolation() throws Exception { + LintRule lintRule = this.builder.setImplementation(new LintImplementation() { + @Override + public Class getClazz() { + return JSONFile.class; + } + + @Override + public boolean shouldReport(JSONFile jsonFile) { + File file = new File(jsonFile.getFilePath()); + return file.getParentFile().getName().contains("resources"); + } + + @Override + public String report(JSONFile jsonFile) { + return "File can not have parent directory resources"; + } + }).setLevel(LintLevel.ERROR) + .build(); + this.lintRegister.register(lintRule); + LintRunner lintRunner = + new LintRunner(this.lintRegister, + "./src/test/resources/test-2.json", + "./src/test/resources/test-file.pdsc"); + + Map>> lintOutput = lintRunner.lint(); + assert(lintRunner.analyzeLintAndGiveExitCode() == 1); + assert(lintOutput.get(lintRule).size() == 2); + } + + @Test + public void jsonFileShouldHaveChildObject() throws Exception { + LintRule lintRule = this.builder.setImplementation(new LintImplementation() { + @Override + public Class getClazz() { + return JSONFile.class; + } + + @Override + public boolean shouldReport(JSONFile jsonFile) { + WrappedObject child = jsonFile.getChild(); + return child instanceof JSONObject; + } + + @Override + public String report(JSONFile jsonFile) { + return "Expect a JSONArray as child"; + } + }).setLevel(LintLevel.ERROR) + .build(); + this.lintRegister.register(lintRule); + LintRunner lintRunner = + new LintRunner(this.lintRegister, + "./src/test/resources/test-2.json", + "./src/test/resources/test-file.pdsc"); + + Map>> lintOutput = lintRunner.lint(); + assert(lintRunner.analyzeLintAndGiveExitCode() == 1); + assert(lintOutput.get(lintRule).size() == 2); + } + + @Test + public void jsonFileShouldDetectFileExtension() throws Exception { + LintRule lintRule = this.builder.setImplementation(new LintImplementation() { + @Override + public Class getClazz() { + return JSONFile.class; + } + + @Override + public boolean shouldReport(JSONFile jsonFile) { + return jsonFile.getFileExtension().equals("pdsc"); + } + + @Override + public String report(JSONFile jsonFile) { + return "Expect a JSONArray as child"; + } + }).setLevel(LintLevel.ERROR) + .build(); + this.lintRegister.register(lintRule); + LintRunner lintRunner = + new LintRunner(this.lintRegister, + "./src/test/resources/test-2.json", + "./src/test/resources/test-file.pdsc"); + + Map>> lintOutput = lintRunner.lint(); + assert(lintRunner.analyzeLintAndGiveExitCode() == 1); + assert(lintOutput.get(lintRule).size() == 1); + } +}