Skip to content

Commit db91a72

Browse files
committed
test(api): harden printBlockToJSON tests against drift
Coverage added/consolidated around the hand-rolled printBlockToJSON from 0980488 so future regressions surface in tests, not at runtime. - Merge testPrintBlockToJSONVisibleFalse into testPrintBlockToJSONWithTransactions via a boolean[]{true,false} loop; flag-driven encoding difference remains covered by testPrintBlockToJSONVisibleFlagAffectsAddressEncoding. - testPrintBlockToJSONTransactionsKeyMatchesLegacyImpl: pin parity with the prior JsonFormat.printToString(block, ...) output for the transactions-key presence in both empty and non-empty cases. - testPrintBlockToJSONCoversAllProtoTopLevelFields: reflect over Block's descriptor to fail fast if a new top-level proto field is added without extending the hand-rolled assembler.
1 parent f4f7412 commit db91a72

1 file changed

Lines changed: 76 additions & 41 deletions

File tree

framework/src/test/java/org/tron/core/services/http/UtilMockTest.java

Lines changed: 76 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
import com.alibaba.fastjson.JSONArray;
44
import com.alibaba.fastjson.JSONObject;
55
import com.google.protobuf.ByteString;
6+
import com.google.protobuf.Descriptors;
67

78
import java.security.InvalidParameterException;
89
import java.util.ArrayList;
10+
import java.util.HashMap;
911
import java.util.List;
12+
import java.util.Map;
1013

1114
import org.apache.commons.lang3.StringUtils;
1215
import org.junit.After;
@@ -87,47 +90,30 @@ public void testPrintBlockToJSONEmptyTransactions() {
8790

8891
@Test
8992
public void testPrintBlockToJSONWithTransactions() {
90-
BlockCapsule blockCapsule = new BlockCapsule(1, Sha256Hash.ZERO_HASH,
91-
System.currentTimeMillis(), Sha256Hash.ZERO_HASH.getByteString());
92-
TransactionCapsule txCap = getTransactionCapsuleExample();
93-
blockCapsule.addTransaction(txCap);
94-
95-
JSONObject json = Util.printBlockToJSON(blockCapsule.getInstance(), true);
96-
Assert.assertTrue(json.containsKey("blockID"));
97-
Assert.assertTrue(json.containsKey("block_header"));
98-
Assert.assertTrue(json.containsKey("transactions"));
99-
Assert.assertFalse(json.getString("blockID").isEmpty());
100-
JSONObject blockHeader = json.getJSONObject("block_header");
101-
Assert.assertNotNull(blockHeader);
102-
Assert.assertTrue(blockHeader.containsKey("raw_data"));
103-
104-
JSONArray txArray = json.getJSONArray("transactions");
105-
Assert.assertEquals(1, txArray.size());
106-
JSONObject txJson = txArray.getJSONObject(0);
107-
Assert.assertTrue(txJson.containsKey("txID"));
108-
Assert.assertTrue(txJson.containsKey("raw_data"));
109-
}
110-
111-
@Test
112-
public void testPrintBlockToJSONVisibleFalse() {
113-
BlockCapsule blockCapsule = new BlockCapsule(1, Sha256Hash.ZERO_HASH,
114-
System.currentTimeMillis(), Sha256Hash.ZERO_HASH.getByteString());
115-
TransactionCapsule txCap = getTransactionCapsuleExample();
116-
blockCapsule.addTransaction(txCap);
117-
118-
JSONObject json = Util.printBlockToJSON(blockCapsule.getInstance(), false);
119-
Assert.assertTrue(json.containsKey("blockID"));
120-
Assert.assertTrue(json.containsKey("block_header"));
121-
Assert.assertTrue(json.containsKey("transactions"));
122-
JSONObject blockHeader = json.getJSONObject("block_header");
123-
Assert.assertNotNull(blockHeader);
124-
Assert.assertTrue(blockHeader.containsKey("raw_data"));
125-
126-
JSONArray txArray = json.getJSONArray("transactions");
127-
Assert.assertEquals(1, txArray.size());
128-
JSONObject txJson = txArray.getJSONObject(0);
129-
Assert.assertTrue(txJson.containsKey("txID"));
130-
Assert.assertTrue(txJson.containsKey("raw_data"));
93+
// Structural invariants must hold under either visible flag; the flag-driven
94+
// encoding difference is covered by testPrintBlockToJSONVisibleFlagAffectsAddressEncoding.
95+
for (boolean visible : new boolean[]{true, false}) {
96+
BlockCapsule blockCapsule = new BlockCapsule(1, Sha256Hash.ZERO_HASH,
97+
System.currentTimeMillis(), Sha256Hash.ZERO_HASH.getByteString());
98+
blockCapsule.addTransaction(getTransactionCapsuleExample());
99+
100+
JSONObject json = Util.printBlockToJSON(blockCapsule.getInstance(), visible);
101+
102+
String msg = "visible=" + visible;
103+
Assert.assertTrue(msg, json.containsKey("blockID"));
104+
Assert.assertTrue(msg, json.containsKey("block_header"));
105+
Assert.assertTrue(msg, json.containsKey("transactions"));
106+
Assert.assertFalse(msg, json.getString("blockID").isEmpty());
107+
JSONObject blockHeader = json.getJSONObject("block_header");
108+
Assert.assertNotNull(msg, blockHeader);
109+
Assert.assertTrue(msg, blockHeader.containsKey("raw_data"));
110+
111+
JSONArray txArray = json.getJSONArray("transactions");
112+
Assert.assertEquals(msg, 1, txArray.size());
113+
JSONObject txJson = txArray.getJSONObject(0);
114+
Assert.assertTrue(msg, txJson.containsKey("txID"));
115+
Assert.assertTrue(msg, txJson.containsKey("raw_data"));
116+
}
131117
}
132118

133119
@Test
@@ -165,6 +151,55 @@ public void testPrintBlockToJSONVisibleFlagAffectsAddressEncoding() {
165151
Assert.assertNotEquals(witnessVisible, witnessHidden);
166152
}
167153

154+
@Test
155+
public void testPrintBlockToJSONTransactionsKeyMatchesLegacyImpl() {
156+
// Legacy impl produced JSON via JsonFormat.printToString(block, selfType),
157+
// which omits repeated fields when empty. New impl mirrors that with an
158+
// explicit isEmpty() guard. Pin parity using JsonFormat output as ground
159+
// truth so a future refactor can't quietly start emitting "transactions": []
160+
// (or stop emitting the key when non-empty).
161+
BlockCapsule empty = new BlockCapsule(1, Sha256Hash.ZERO_HASH,
162+
System.currentTimeMillis(), Sha256Hash.ZERO_HASH.getByteString());
163+
assertTransactionsKeyMatchesLegacy(empty.getInstance(), false);
164+
165+
BlockCapsule nonEmpty = new BlockCapsule(1, Sha256Hash.ZERO_HASH,
166+
System.currentTimeMillis(), Sha256Hash.ZERO_HASH.getByteString());
167+
nonEmpty.addTransaction(getTransactionCapsuleExample());
168+
assertTransactionsKeyMatchesLegacy(nonEmpty.getInstance(), true);
169+
}
170+
171+
private static void assertTransactionsKeyMatchesLegacy(Protocol.Block block,
172+
boolean expectTransactionsKey) {
173+
JSONObject legacy = JSONObject.parseObject(JsonFormat.printToString(block, true));
174+
Assert.assertEquals("legacy JsonFormat parity broken — proto behavior changed?",
175+
expectTransactionsKey, legacy.containsKey("transactions"));
176+
177+
JSONObject actual = Util.printBlockToJSON(block, true);
178+
Assert.assertEquals("new impl diverged from legacy on 'transactions' key presence",
179+
expectTransactionsKey, actual.containsKey("transactions"));
180+
}
181+
182+
@Test
183+
public void testPrintBlockToJSONCoversAllProtoTopLevelFields() {
184+
// Guards against proto field drift: the old impl delegated to JsonFormat on
185+
// the whole Block message, so any new top-level Block field appeared
186+
// automatically. The new impl hand-assembles the JSON, so a future proto
187+
// field would be silently dropped. Reflect over Block's descriptor and
188+
// assert every declared top-level field is handled.
189+
Map<String, String> protoFieldToJsonKey = new HashMap<>();
190+
protoFieldToJsonKey.put("block_header", "block_header");
191+
// "transactions" is present only when non-empty; parity verified in
192+
// testPrintBlockToJSONTransactionsKeyMatchesLegacyImpl.
193+
protoFieldToJsonKey.put("transactions", "transactions");
194+
195+
for (Descriptors.FieldDescriptor f : Protocol.Block.getDescriptor().getFields()) {
196+
Assert.assertTrue(
197+
"Block proto field '" + f.getName() + "' is not handled by printBlockToJSON. "
198+
+ "If you added a new top-level field, extend printBlockToJSON and this test.",
199+
protoFieldToJsonKey.containsKey(f.getName()));
200+
}
201+
}
202+
168203
@Test
169204
public void testPrintTransactionList() {
170205
TransactionCapsule transactionCapsule = getTransactionCapsuleExample();

0 commit comments

Comments
 (0)