Coverage Summary for Class: SimpleRepairStrategy (io.github.haibiiin.json.repair.strategy)

Class Method, % Branch, % Line, %
SimpleRepairStrategy 100% (2/2) 50% (1/2) 85.7% (6/7)
SimpleRepairStrategy$1
SimpleRepairStrategy$BaseFixStrategy
SimpleRepairStrategy$FixStrategy 96.3% (26/27) 83.9% (47/56) 90.5% (76/84)
SimpleRepairStrategy$SimpleNodeWrapper 100% (12/12) 67.6% (23/34) 100% (27/27)
Total 97.6% (40/41) 77.2% (71/92) 92.4% (109/118)


 /*
  * Copyright 2024 HAibiiin
  *
  * 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 io.github.haibiiin.json.repair.strategy;
 
 import io.github.haibiiin.json.repair.Expecting;
 import io.github.haibiiin.json.repair.RepairStrategy;
 import io.github.haibiiin.json.repair.UnableHandleException;
 import io.github.haibiiin.json.repair.antlr.KeySymbol;
 import java.util.List;
 import java.util.function.BiPredicate;
 import org.antlr.v4.runtime.tree.ErrorNode;
 import org.antlr.v4.runtime.tree.ErrorNodeImpl;
 import org.antlr.v4.runtime.tree.ParseTree;
 
 public class SimpleRepairStrategy implements RepairStrategy {
     
     @Override
     public String repair(String json, List<ParseTree> beRepairParseList, Expecting expecting) {
         Expecting.Node node = expecting.first();
         SimpleNodeWrapper nodeWrapper = new SimpleNodeWrapper(node);
         
         FixStrategy strategy = FixStrategy.get(nodeWrapper, beRepairParseList);
         if (strategy == null) {
             throw new UnableHandleException();
         }
         
         return strategy.fixStrategy.fix(json, nodeWrapper, beRepairParseList);
     }
     
     static class SimpleNodeWrapper {
         
         private final Expecting.Node node;
         
         private SimpleNodeWrapper(Expecting.Node node) {
             this.node = node;
         }
         
         public String key() {
             return node.key();
         }
         
         public boolean isEOF() {
             return KeySymbol.EOF.val().equalsIgnoreCase(node.key());
         }
         
         public boolean endObjOrPair() {
             return node.expectingList().size() == 2
                     && node.expectingList().contains(KeySymbol.COMMA.val())
                     && node.expectingList().contains(KeySymbol.R_BRACE.val());
         }
         
         public boolean endArrOrValue() {
             return node.expectingList().size() == 2
                     && node.expectingList().contains(KeySymbol.COMMA.val())
                     && node.expectingList().contains(KeySymbol.R_BRACKET.val());
         }
         
         public boolean startPair() {
             return node.expectingList().size() == 1
                     && node.expectingList().contains(KeySymbol.STRING.val());
         }
         
         public boolean expectingValue() {
             return node.expectingList().size() == 7
                     && node.expectingList().contains(KeySymbol.L_BRACE.val())
                     && node.expectingList().contains(KeySymbol.L_BRACKET.val())
                     && node.expectingList().contains(KeySymbol.TRUE.val())
                     && node.expectingList().contains(KeySymbol.FALSE.val())
                     && node.expectingList().contains(KeySymbol.NULL.val())
                     && node.expectingList().contains(KeySymbol.STRING.val())
                     && node.expectingList().contains(KeySymbol.NUMBER.val());
         }
         
         public boolean expectingObj() {
             return node.expectingList().size() == 11;
         }
         
         public boolean expectingArr() {
             return node.expectingList().size() == 7;
         }
         
         public boolean expectingEOF() {
             return KeySymbol.COLON.val().equalsIgnoreCase(node.key())
                     && node.expectingList().size() == 1
                     && node.expectingList().contains(KeySymbol.EOF.val());
         }
         
         public boolean expectingToken() {
             return node.expectingList().size() == 1 && node.expectingList().contains(KeySymbol.TOKEN.val());
         }
     }
     
     enum FixStrategy {
         
         END_OBJ_OR_PAIR(
                 (node, beRepairParseList) -> node.isEOF() && node.endObjOrPair(),
                 (json, node, beRepairParseList) -> json + KeySymbol.R_BRACE.val()),
         END_ARR_OR_VALUE(
                 (node, beRepairParseList) -> node.isEOF() && node.endArrOrValue(),
                 (json, node, beRepairParseList) -> json + KeySymbol.R_BRACKET.val()),
         START_PAIR(
                 (node, beRepairParseList) -> node.isEOF() && node.startPair(),
                 (json, node, beRepairParseList) -> {
                     int index = -1;
                     for (int i = beRepairParseList.size() - 1; i > 0; i--) {
                         ParseTree parseNode = beRepairParseList.get(i);
                         if (parseNode instanceof ErrorNode) {
                             index = ((ErrorNodeImpl) (beRepairParseList.get(i))).getSymbol().getCharPositionInLine();
                         }
                     }
                     return json.substring(0, index) + KeySymbol.R_BRACE.val();
                 }),
         VALUE(
                 (node, beRepairParseList) -> node.isEOF() && node.expectingValue(),
                 (json, node, beRepairParseList) -> {
                     int index = -1;
                     for (int i = beRepairParseList.size() - 1; i > 0; i--) {
                         ParseTree parseNode = beRepairParseList.get(i);
                         if (parseNode instanceof ErrorNode) {
                             index = ((ErrorNodeImpl) (beRepairParseList.get(i))).getSymbol().getCharPositionInLine();
                         }
                     }
                     if (json.substring(index).contains(KeySymbol.COMMA.val())) {
                         return json.substring(0, index) + KeySymbol.R_BRACKET.val();
                     }
                     if (json.substring(index).contains(KeySymbol.COLON.val())) {
                         return json + KeySymbol.NULL.val() + KeySymbol.R_BRACE.val();
                     }
                     throw new UnableHandleException();
                 }),
         EOF(
                 (node, beRepairParseList) -> node.expectingEOF(),
                 (json, node, beRepairParseList) -> KeySymbol.L_BRACE.val() + json),
         CLOSE_QUOTATION_MARK(
                 (node, beRepairParseList) -> node.expectingToken() && node.key().startsWith("\""),
                 (json, node, beRepairParseList) -> {
                     if (json.lastIndexOf(KeySymbol.COMMA.val()) != -1) {
                         ParseTree errorNode = beRepairParseList.stream().filter((parse) -> parse instanceof ErrorNode).findFirst().orElse(null);
                         if (errorNode != null && KeySymbol.COLON.val().equalsIgnoreCase(errorNode.getText())) {
                             return json.replaceFirst(node.key(), node.key().substring(0, node.key().length() - 1) + "\",");
                         }
                         throw new UnableHandleException();
                     } else {
                         return json.replaceFirst(node.key(), node.key() + "\"");
                     }
                 }),
         OPEN_QUOTATION_MARK(
                 (node, beRepairParseList) -> node.expectingToken() && node.key().endsWith("\""),
                 (json, node, beRepairParseList) -> json.replaceFirst(node.key(), "\"" + node.key())),
         STRING_QUOTATION_MARK(
                 (node, beRepairParseList) -> node.expectingToken() && node.key().endsWith(KeySymbol.COLON.val()),
                 (json, node, beRepairParseList) -> json.replaceFirst(node.key(), "\"" + node.key().substring(0, node.key().length() - 1) + "\":")),
         VALUE_QUOTATION_MARK(
                 (node, beRepairParseList) -> node.expectingToken(),
                 (json, node, beRepairParseList) -> json.replaceFirst(node.key(), "\"" + node.key() + "\"")),
         CLOSE_BRACE(
                 (node, beRepairParseList) -> beRepairParseList.stream().anyMatch(
                         (parse) -> parse instanceof ErrorNode
                                 && node.key().equalsIgnoreCase(parse.getText()) && node.expectingObj()),
                 (json, node, beRepairParseList) -> {
                     final int[] index = {-1};
                     beRepairParseList.stream().filter(
                             (parse) -> parse instanceof ErrorNode && node.key().equalsIgnoreCase(parse.getText())).findFirst()
                             .ifPresent(parseTree -> index[0] = ((ErrorNodeImpl) parseTree).getSymbol().getCharPositionInLine());
                     if (index[0] == -1) {
                         throw new UnableHandleException();
                     }
                     if (index[0] == json.length() - 1) {
                         return json + KeySymbol.R_BRACE.val();
                     }
                     String prefix = json.substring(0, index[0] + 1);
                     String suffix = json.substring(index[0] + 1);
                     return prefix + KeySymbol.R_BRACE.val() + suffix;
                 }),
         CLOSE_BRACKET(
                 (node, beRepairParseList) -> beRepairParseList.stream().anyMatch(
                         (parse) -> parse instanceof ErrorNode
                                 && node.key().equalsIgnoreCase(parse.getText()) && node.expectingArr()),
                 (json, node, beRepairParseList) -> {
                     final int[] index = {-1};
                     beRepairParseList.stream().filter(
                             (parse) -> parse instanceof ErrorNode && node.key().equalsIgnoreCase(parse.getText())).findFirst()
                             .ifPresent(parseTree -> index[0] = ((ErrorNodeImpl) parseTree).getSymbol().getCharPositionInLine());
                     if (index[0] == -1) {
                         throw new UnableHandleException();
                     }
                     if (index[0] == json.length() - 1) {
                         return json + KeySymbol.R_BRACKET.val();
                     }
                     String prefix = json.substring(0, index[0] + 1);
                     String suffix = json.substring(index[0] + 1);
                     return prefix + KeySymbol.R_BRACKET.val() + suffix;
                 }),
                 ;
         
         final BiPredicate<SimpleNodeWrapper, List<ParseTree>> expectingFixStrategy;
         final BaseFixStrategy fixStrategy;
         
         FixStrategy(BiPredicate<SimpleNodeWrapper, List<ParseTree>> expectingFixStrategy, BaseFixStrategy fixStrategy) {
             this.expectingFixStrategy = expectingFixStrategy;
             this.fixStrategy = fixStrategy;
         }
         
         public static FixStrategy get(SimpleNodeWrapper node, List<ParseTree> parseTrees) {
             for (FixStrategy strategy : values()) {
                 if (strategy.expectingFixStrategy.test(node, parseTrees)) {
                     return strategy;
                 }
             }
             return null;
         }
         
     }
     
     interface BaseFixStrategy {
         
         String fix(String json, SimpleNodeWrapper node, List<ParseTree> beRepairParseList);
     }
 }