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

leeonky / test-charm-java / 290

08 Sep 2025 03:25PM UTC coverage: 74.312% (-0.003%) from 74.315%
290

push

circleci

leeonky
Introduce PropertyWriterDecorator

10 of 25 new or added lines in 6 files covered. (40.0%)

20 existing lines in 10 files now uncovered.

8155 of 10974 relevant lines covered (74.31%)

0.74 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.SortGroupNode.NOP_COMPARATOR;
18
import static com.github.leeonky.dal.ast.node.SymbolNode.Type.BRACKET;
19
import static com.github.leeonky.dal.runtime.DALException.locateError;
20
import static com.github.leeonky.dal.runtime.ExpressionException.exception;
21
import static com.github.leeonky.dal.runtime.ExpressionException.opt1;
22
import static com.github.leeonky.util.Zipped.zip;
23
import static java.lang.String.format;
24
import static java.util.Comparator.naturalOrder;
25
import static java.util.Comparator.reverseOrder;
26
import static java.util.stream.Collectors.joining;
27
import static java.util.stream.Collectors.toList;
28

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

227
    private boolean isListEllipsis(Clause<DALNode> clause) {
228
        return clause.expression(InputNode.Placeholder.INSTANCE) instanceof ListEllipsisNode;
1✔
229
    }
230

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

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

239

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

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

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

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

264
    static class DifferentCellSize extends AssertionFailure {
265
        public DifferentCellSize(String format, int position) {
266
            super(format, position);
1✔
267
        }
1✔
268
    }
269
}
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