• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

leeonky / test-charm-java / 165

22 Mar 2025 11:09AM UTC coverage: 71.321% (-2.9%) from 74.248%
165

push

circleci

leeonky
update version

6809 of 9547 relevant lines covered (71.32%)

0.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.64
/DAL-java/src/main/java/com/github/leeonky/dal/ast/node/ListScopeNode.java
1
package com.github.leeonky.dal.ast.node;
2

3
import com.github.leeonky.dal.ast.opt.Factory;
4
import com.github.leeonky.dal.compiler.Notations;
5
import com.github.leeonky.dal.runtime.*;
6
import com.github.leeonky.dal.runtime.RuntimeContextBuilder.DALRuntimeContext;
7
import com.github.leeonky.interpreter.Clause;
8
import com.github.leeonky.interpreter.SyntaxException;
9
import com.github.leeonky.util.Zipped;
10

11
import java.util.ArrayList;
12
import java.util.Comparator;
13
import java.util.Iterator;
14
import java.util.List;
15

16
import static com.github.leeonky.dal.ast.node.DALExpression.expression;
17
import static com.github.leeonky.dal.ast.node.InputNode.INPUT_NODE;
18
import static com.github.leeonky.dal.ast.node.SortGroupNode.NOP_COMPARATOR;
19
import static com.github.leeonky.dal.ast.node.SymbolNode.Type.BRACKET;
20
import static com.github.leeonky.dal.runtime.DalException.locateError;
21
import static com.github.leeonky.dal.runtime.ExpressionException.exception;
22
import static com.github.leeonky.dal.runtime.ExpressionException.opt1;
23
import static com.github.leeonky.util.Zipped.zip;
24
import static java.lang.String.format;
25
import static java.util.Comparator.naturalOrder;
26
import static java.util.Comparator.reverseOrder;
27
import static java.util.stream.Collectors.joining;
28
import static java.util.stream.Collectors.toList;
29

30
public class ListScopeNode extends DALNode {
31
    private List<DALNode> verificationExpressions;
32
    private List<DALNode> inputExpressions;
33
    private List<Clause<DALNode>> inputClauses;
34
    private final Type type;
35
    private final Style style;
36
    private final Comparator<Data> comparator;
37

38
    public ListScopeNode(List<Clause<DALNode>> clauses, Comparator<Data> comparator, Style style) {
1✔
39
        type = guessType(clauses);
1✔
40
        inputClauses = clauses;
1✔
41
        this.comparator = comparator;
1✔
42
        this.style = style;
1✔
43
    }
1✔
44

45
    public ListScopeNode(List<DALNode> verificationExpressions, Type type, Comparator<Data> comparator, Style style) {
1✔
46
        this.verificationExpressions = inputExpressions = new ArrayList<>(verificationExpressions);
1✔
47
        this.type = type;
1✔
48
        this.comparator = comparator;
1✔
49
        this.style = style;
1✔
50
    }
1✔
51

52
    public ListScopeNode(List<Clause<DALNode>> clauses) {
53
        this(clauses, NOP_COMPARATOR, Style.LIST);
1✔
54
    }
1✔
55

56
    private List<DALNode> getVerificationExpressions(Data.DataList list, Data actual) {
57
        return verificationExpressions != null ? verificationExpressions : buildVerificationExpressions(list, actual)
1✔
58
                .stream().filter(node -> !(node instanceof ListEllipsisNode)).collect(toList());
1✔
59
    }
60

61
    private List<DALNode> buildVerificationExpressions(Data.DataList list, Data actual) {
62
        if (inputExpressions != null)
1✔
63
            return inputExpressions;
×
64
        return new ArrayList<DALNode>() {
1✔
65
            {
66
                List<Clause<DALNode>> usefulInputClauses = new ArrayList<>(inputClauses);
1✔
67
                if (type == Type.FIRST_N_ITEMS)
1✔
68
                    for (int i = 0; i < usefulInputClauses.size() - 1; i++)
1✔
69
                        add(buildIndexExpression(usefulInputClauses.get(i), i + list.firstIndex()));
1✔
70
                else if (type == Type.LAST_N_ITEMS)
1✔
71
                    for (int i = usefulInputClauses.size() - 1; i >= 0; i--)
1✔
72
                        add(0, buildIndexExpression(usefulInputClauses.get(i), i - usefulInputClauses.size()));
1✔
73
                else if (type == Type.ALL_ITEMS) {
1✔
74
                    Zipped<Clause<DALNode>, Integer> zipped = zip(usefulInputClauses, list.indexes());
1✔
75
                    zipped.forEachElement((clause, index) -> add(buildIndexExpression(clause, index)));
1✔
76
                    if (zipped.hasLeft())
1✔
77
                        throw differentSizeException(usefulInputClauses, actual, zipped.index());
1✔
78
                    if (zipped.hasRight() && !list.infinite())
1✔
79
                        throw differentSizeException(usefulInputClauses, actual, list.size());
1✔
80
                }
81
            }
1✔
82

83
            private DALNode buildIndexExpression(Clause<DALNode> clause, Integer index) {
84
                DALNode symbolNode = new SymbolNode(index, BRACKET);
1✔
85
                DALNode expression = clause.expression(expression(INPUT_NODE, Factory.executable(Notations.EMPTY), symbolNode));
1✔
86
                symbolNode.setPositionBegin(expression.getOperandPosition());
1✔
87
                return expression;
1✔
88
            }
89
        };
90
    }
91

92
    private AssertionFailure differentSizeException(List<Clause<DALNode>> usefulInputClauses, Data actual, int index) {
93
        String message = format("Unexpected list size\nExpected: <%d>\nActual: <%d>\nActual list: %s",
1✔
94
                usefulInputClauses.size(), index, actual.dump());
1✔
95
        return style == Style.ROW ? new DifferentCellSize(message, getPositionBegin())
1✔
96
                : new AssertionFailure(message, getPositionBegin());
1✔
97
    }
98

99
    @Override
100
    protected ExpectationFactory toVerify(DALRuntimeContext context) {
101
        return (operator, actual) -> new ExpectationFactory.Expectation() {
1✔
102
            @Override
103
            public Data matches() {
104
                return equalTo();
1✔
105
            }
106

107
            @Override
108
            public Data equalTo() {
109
                try {
110
                    Data sorted = actual.map(r -> opt1(r::list).sort(getComparator(context))).resolve();
1✔
111
                    return sorted.execute(() -> type == Type.CONTAINS ?
1✔
112
                            verifyContainElement(context, sorted.resolved().list(), actual)
1✔
113
                            : verifyCorrespondingElement(context, getVerificationExpressions(sorted.resolved().list(), actual)));
1✔
114
                } catch (ListMappingElementAccessException e) {
1✔
115
                    throw exception(expression -> locateError(e, expression.left().getOperandPosition()));
1✔
116
                }
117
            }
118

119
            @Override
120
            public ExpectationFactory.Type type() {
121
                return ExpectationFactory.Type.LIST;
×
122
            }
123
        };
124
    }
125

126
    protected Comparator<Data> getComparator(DALRuntimeContext context) {
127
        return comparator;
1✔
128
    }
129

130
    //    TODO tobe refactored
131
    private List<DALNode> buildVerificationExpressions() {
132
        if (inputExpressions != null)
1✔
133
            return inputExpressions;
×
134
        return new ArrayList<DALNode>() {{
1✔
135
            if (type == Type.LAST_N_ITEMS) {
1✔
136
                int negativeIndex = -1;
1✔
137
                for (int i = inputClauses.size() - 1; i >= 0; i--) {
1✔
138
                    add(0, inputClauses.get(i).expression(expression(INPUT_NODE, Factory.executable(Notations.EMPTY),
1✔
139
                            new SymbolNode(negativeIndex--, BRACKET))));
1✔
140
                }
141
            } else {
1✔
142
                for (int i = 0; i < inputClauses.size(); i++)
1✔
143
                    add(inputClauses.get(i).expression(expression(INPUT_NODE, Factory.executable(Notations.EMPTY),
1✔
144
                            new SymbolNode(i, BRACKET))));
1✔
145
            }
146
        }};
1✔
147
    }
148

149
    private Type guessType(List<Clause<DALNode>> clauses) {
150
        List<Boolean> isListEllipsis = clauses.stream().map(this::isListEllipsis).collect(toList());
1✔
151
        long ellipsesCount = isListEllipsis.stream().filter(Boolean::booleanValue).count();
1✔
152
        if (ellipsesCount > 0) {
1✔
153
            if (ellipsesCount == 1) {
1✔
154
                if (isListEllipsis.get(0))
1✔
155
                    return Type.LAST_N_ITEMS;
1✔
156
                if (isListEllipsis.get(isListEllipsis.size() - 1))
1✔
157
                    return Type.FIRST_N_ITEMS;
1✔
158
            } else if (ellipsesCount == 2 && isListEllipsis.get(0) && isListEllipsis.get(isListEllipsis.size() - 1))
1✔
159
                return Type.CONTAINS;
1✔
160
            throw new SyntaxException("Invalid ellipsis", clauses.get(isListEllipsis.lastIndexOf(true))
1✔
161
                    .expression(null).getOperandPosition());
1✔
162
        }
163
        return Type.ALL_ITEMS;
1✔
164
    }
165

166
    @Override
167
    public String inspect() {
168
        if (type == Type.CONTAINS)
1✔
169
            return inputClauses.stream().map(clause -> clause.expression(INPUT_NODE).inspect())
1✔
170
                    .collect(joining(", ", "[", "]"));
1✔
171
        return buildVerificationExpressions().stream().map(DALNode::inspect).collect(joining(", ", "[", "]"));
1✔
172
    }
173

174
    private Data verifyContainElement(DALRuntimeContext context, Data.DataList list, Data actual) {
175
        Iterator<Integer> iterator = list.indexes().iterator();
1✔
176
        List<Clause<DALNode>> expected = trimFirstEllipsis();
1✔
177
        for (int clauseIndex = 0; clauseIndex < expected.size(); clauseIndex++) {
1✔
178
            Clause<DALNode> clause = expected.get(clauseIndex);
1✔
179
            try {
180
                while (true) {
181
                    int elementIndex = getElementIndex(clause, iterator, actual);
1✔
182
                    try {
183
                        clause.expression(expression(INPUT_NODE, Factory.executable(Notations.EMPTY),
1✔
184
                                new SymbolNode(elementIndex, BRACKET))).evaluate(context);
1✔
185
                        break;
1✔
186
//                        TODO test should which exception ignore which exception not ignore
187
                    } catch (DalException ignore) {
1✔
188
                    }
189
                }
1✔
190
            } catch (AssertionFailure exception) {
1✔
191
                throw style == Style.LIST ? exception : new RowAssertionFailure(clauseIndex, exception);
1✔
192
            }
1✔
193
        }
194
        return actual;
1✔
195
    }
196

197
    private int getElementIndex(Clause<DALNode> clause, Iterator<Integer> iterator, Data actual) {
198
        if (iterator.hasNext())
1✔
199
            return iterator.next();
1✔
200
        throw new AssertionFailure("No such element in list: " + actual.dump(),
1✔
201
                clause.expression(INPUT_NODE).getOperandPosition());
1✔
202
    }
203

204
    private List<Clause<DALNode>> trimFirstEllipsis() {
205
        return inputClauses.subList(1, inputClauses.size() - 1);
1✔
206
    }
207

208
    private Data verifyCorrespondingElement(DALRuntimeContext context, List<DALNode> expressions) {
209
        Data result = context.data(null);
1✔
210
        if (style != Style.LIST)
1✔
211
            for (int index = 0; index < expressions.size(); index++)
1✔
212
                try {
213
                    result = expressions.get(index).evaluateData(context).resolve();
1✔
214
                } catch (DifferentCellSize differentCellSize) {
1✔
215
                    throw new RowAssertionFailure(index, differentCellSize);
1✔
216
                } catch (DalException dalException) {
1✔
217
                    if (style == Style.TABLE)
1✔
218
                        throw new ElementAssertionFailure(index, dalException);
1✔
219
                    throw dalException;
1✔
220
                }
1✔
221
        else {
222
            for (DALNode expression : expressions)
1✔
223
                result = expression.evaluateData(context).resolve();
1✔
224
        }
225
        return result;
1✔
226
    }
227

228
    private boolean isListEllipsis(Clause<DALNode> clause) {
229
        return clause.expression(INPUT_NODE) instanceof ListEllipsisNode;
1✔
230
    }
231

232
    public enum Type {
1✔
233
        ALL_ITEMS, FIRST_N_ITEMS, LAST_N_ITEMS, CONTAINS
1✔
234
    }
235

236
    public enum Style {
1✔
237
        LIST, TABLE, ROW
1✔
238
    }
239

240

241
    private static ListScopeNode sorted(List<Clause<DALNode>> clauses, Comparator<?> comparator, String sortOpt) {
242
        return new ListScopeNode(clauses, null, Style.LIST) {
1✔
243
            @SuppressWarnings("unchecked")
244
            @Override
245
            protected Comparator<Data> getComparator(DALRuntimeContext context) {
246
                return Comparator.comparing((Data data) -> context.transformComparable(data.instance()),
1✔
247
                        (Comparator<Object>) comparator);
248
            }
249

250
            @Override
251
            public String inspect() {
252
                return sortOpt + super.inspect();
1✔
253
            }
254
        };
255
    }
256

257
    public static ListScopeNode sortedNaturalOrder(List<Clause<DALNode>> clauses) {
258
        return sorted(clauses, naturalOrder(), "+");
1✔
259
    }
260

261
    public static ListScopeNode sortedReverseOrder(List<Clause<DALNode>> clauses) {
262
        return sorted(clauses, reverseOrder(), "-");
1✔
263
    }
264

265
    static class DifferentCellSize extends AssertionFailure {
266
        public DifferentCellSize(String format, int position) {
267
            super(format, position);
1✔
268
        }
1✔
269
    }
270
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc