Repository: redpen-cc/redpen (java)

Issue:
Validator to check list level
This validator detects the too deeply nested list blocks as follows.

```
* level 1
  * level 2
     * level 3
       * level 4
          * level 5
...
```

Pull request description:
Add ListLevelValidator which closes #765
I'm not sure if this is the right way to implement validators for list.

Patch:
diff --git a/redpen-cli/sample/conf/redpen-conf-en.xml b/redpen-cli/sample/conf/redpen-conf-en.xml
index 575eb5ed..85425cef 100644
--- a/redpen-cli/sample/conf/redpen-conf-en.xml
+++ b/redpen-cli/sample/conf/redpen-conf-en.xml
@@ -26,6 +26,7 @@
         <validator name="EmptySection" />
         <validator name="GappedSection" />
         <validator name="SectionLevel" />
+        <validator name="ListLevel" />
 
         <!--Rules on symbols and terminologies-->
         <validator name="InvalidSymbol"/>
diff --git a/redpen-cli/sample/conf/redpen-conf-ja.xml b/redpen-cli/sample/conf/redpen-conf-ja.xml
index cb1ea4e7..06f997bf 100644
--- a/redpen-cli/sample/conf/redpen-conf-ja.xml
+++ b/redpen-cli/sample/conf/redpen-conf-ja.xml
@@ -39,6 +39,7 @@
         <validator name="GappedSection" />
         <validator name="SectionLevel" />
         <validator name="ParagraphNumber"/>
+        <validator name="ListLevel" />
 
         <!--Load JavaScript validators-->
         <validator name="JavaScript" />
diff --git a/redpen-core/src/main/java/cc/redpen/validator/section/ListLevelValidator.java b/redpen-core/src/main/java/cc/redpen/validator/section/ListLevelValidator.java
new file mode 100644
index 00000000..f9786872
--- /dev/null
+++ b/redpen-core/src/main/java/cc/redpen/validator/section/ListLevelValidator.java
@@ -0,0 +1,46 @@
+/**
+ * redpen: a text inspection tool
+ * Copyright (c) 2014-2015 Recruit Technologies Co., Ltd. and contributors
+ * (see CONTRIBUTORS.md)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cc.redpen.validator.section;
+
+import cc.redpen.model.ListBlock;
+import cc.redpen.model.ListElement;
+import cc.redpen.model.Section;
+import cc.redpen.validator.Validator;
+
+/**
+ * Validate that list elements are not deeper than the given level.
+ */
+public class ListLevelValidator extends Validator {
+
+    public ListLevelValidator() {
+        super("max_level", 5); // Default maximum level of list elements
+    }
+
+    @Override
+    public void validate(Section section) {
+        for (ListBlock listBlock : section.getListBlocks()) {
+            for (ListElement listElement : listBlock.getListElements()) {
+                final int maxLevel = getInt("max_level");
+                if (listElement.getLevel() > maxLevel) {
+                    addLocalizedError(listElement.getSentence(0), maxLevel);
+                }
+            }
+        }
+    }
+
+}
diff --git a/redpen-core/src/main/resources/cc/redpen/validator/section/error-messages.properties b/redpen-core/src/main/resources/cc/redpen/validator/section/error-messages.properties
index a24b7eaa..503566a3 100644
--- a/redpen-core/src/main/resources/cc/redpen/validator/section/error-messages.properties
+++ b/redpen-core/src/main/resources/cc/redpen/validator/section/error-messages.properties
@@ -5,4 +5,5 @@ DuplicatedSectionValidator=Found duplicated section (starts from line {0}).
 SectionLevelValidator=The section "{0}" is too deep.
 VoidSectionValidator=The section is void.
 EmptySectionValidator=The section "{0}" is empty.
-HeaderLengthValidator=The length of header ({0}) exceeds the maximum of {1}.
\ No newline at end of file
+HeaderLengthValidator=The length of header ({0}) exceeds the maximum of {1}.
+ListLevelValidator=The list item is nested too deeply.
diff --git a/redpen-core/src/main/resources/cc/redpen/validator/section/error-messages_ja.properties b/redpen-core/src/main/resources/cc/redpen/validator/section/error-messages_ja.properties
index 8c4f09e0..14006bfd 100644
--- a/redpen-core/src/main/resources/cc/redpen/validator/section/error-messages_ja.properties
+++ b/redpen-core/src/main/resources/cc/redpen/validator/section/error-messages_ja.properties
@@ -6,3 +6,4 @@ SectionLevelValidator=\u7BC0"{0}"\u306E\u30EC\u30D9\u30EB\u304C\u6DF1\u3059\u304
 VoidSectionValidator=\u7BC0\u306E\u5185\u5BB9\u304C\u7A7A\u3067\u3059\u3002
 EmptySectionValidator=\u7BC0 "{0}" \u306B\u4E2D\u8EAB\u304C\u3042\u308A\u307E\u305B\u3093\u3002
 HeaderLengthValidator=\u898B\u51FA\u3057\u9577\uFF08"{0}"\uFF09\u304C\u6700\u5927\u5024 "{1}" \u3092\u8D85\u3048\u3066\u3044\u307E\u3059\u3002
+ListLevelValidator=\u30ea\u30b9\u30c8\u306e\u30ec\u30d9\u30eb\u304c\u6df1\u3059\u304e\u307e\u3059\u3002


Test patch:
diff --git a/redpen-core/src/test/java/cc/redpen/validator/section/ListLevelValidatorTest.java b/redpen-core/src/test/java/cc/redpen/validator/section/ListLevelValidatorTest.java
new file mode 100644
index 00000000..e7f18239
--- /dev/null
+++ b/redpen-core/src/test/java/cc/redpen/validator/section/ListLevelValidatorTest.java
@@ -0,0 +1,72 @@
+/**
+ * redpen: a text inspection tool
+ * Copyright (c) 2014-2015 Recruit Technologies Co., Ltd. and contributors
+ * (see CONTRIBUTORS.md)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cc.redpen.validator.section;
+
+import cc.redpen.RedPenException;
+import cc.redpen.config.Configuration;
+import cc.redpen.config.ValidatorConfiguration;
+import cc.redpen.model.Section;
+import cc.redpen.model.Sentence;
+import cc.redpen.validator.ValidationError;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+public class ListLevelValidatorTest {
+
+    private ListLevelValidator validator;
+
+    @Before
+    public void setUp() throws RedPenException {
+        validator = new ListLevelValidator();
+        validator.preInit(new ValidatorConfiguration("ListLevel").addProperty("max_level", 3), Configuration.builder().build());
+    }
+
+    @Test
+    public void testValid() throws Exception {
+        Section section = new Section(0, "header");
+        section.appendListBlock();
+        section.appendListElement(1, Arrays.asList(new Sentence("item1", 1)));
+        section.appendListElement(2, Arrays.asList(new Sentence("item2", 1)));
+        section.appendListElement(3, Arrays.asList(new Sentence("item3", 1)));
+        List<ValidationError> errors = new ArrayList<>();
+        validator.setErrorList(errors);
+        validator.validate(section);
+        assertEquals(0, errors.size());
+    }
+
+    @Test
+    public void testInvalid() throws Exception {
+        Section section = new Section(0, "header");
+        section.appendListBlock();
+        section.appendListElement(1, Arrays.asList(new Sentence("item1", 1)));
+        section.appendListElement(2, Arrays.asList(new Sentence("item2", 1)));
+        section.appendListElement(3, Arrays.asList(new Sentence("item3", 1)));
+        section.appendListElement(4, Arrays.asList(new Sentence("item4", 1)));
+        List<ValidationError> errors = new ArrayList<>();
+        validator.setErrorList(errors);
+        validator.validate(section);
+        assertEquals(1, errors.size());
+    }
+
+}