сделал тест и он работает на то что бы изменить тект сообщения
This commit is contained in:
AidarKC 2026-01-07 23:50:16 +03:00
parent 06c77b1c1f
commit 1c94bb25a6
2 changed files with 63 additions and 25 deletions

View File

@ -21,11 +21,12 @@ import java.util.Objects;
* 1 = новое сообщение (начало ветки) * 1 = новое сообщение (начало ветки)
* 2 = ответ на сообщение (reply) * 2 = ответ на сообщение (reply)
* 3 = репост (repost) * 3 = репост (repost)
* 4 = редактирование (edit)
* *
* [2] textLenBytes (uint16) длина текста в байтах UTF-8 * [2] textLenBytes (uint16) длина текста в байтах UTF-8
* [N] text UTF-8 * [N] text UTF-8
* *
* Далее ТОЛЬКО если subType == 2 или subType == 3: * Далее ТОЛЬКО если subType == 2 или subType == 3 или subType == 4:
* [1] toBlockchainNameLen (uint8) * [1] toBlockchainNameLen (uint8)
* [N] toBlockchainName UTF-8 * [N] toBlockchainName UTF-8
* [4] toBlockGlobalNumber (int32) * [4] toBlockGlobalNumber (int32)
@ -45,14 +46,15 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
public static final short SUB_NEW = 1; public static final short SUB_NEW = 1;
public static final short SUB_REPLY = 2; public static final short SUB_REPLY = 2;
public static final short SUB_REPOST = 3; public static final short SUB_REPOST = 3;
public static final short SUB_EDIT = 4;
/** Подтип текстового сообщения (1/2/3). */ /** Подтип текстового сообщения (1/2/3/4). */
public final short subType; public final short subType;
/** Текст сообщения (строго валидный UTF-8, не пустой/не blank). */ /** Текст сообщения (строго валидный UTF-8, не пустой/не blank). */
public final String message; public final String message;
// Заполняются только если subType == SUB_REPLY или SUB_REPOST // Заполняются только если subType == SUB_REPLY || SUB_REPOST || SUB_EDIT
public final String toBlockchainName; public final String toBlockchainName;
public final int toBlockGlobalNumber; public final int toBlockGlobalNumber;
public final byte[] toBlockHash32; public final byte[] toBlockHash32;
@ -79,7 +81,10 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
} }
this.subType = bb.getShort(); this.subType = bb.getShort();
if (this.subType != SUB_NEW && this.subType != SUB_REPLY && this.subType != SUB_REPOST) { if (this.subType != SUB_NEW
&& this.subType != SUB_REPLY
&& this.subType != SUB_REPOST
&& this.subType != SUB_EDIT) {
throw new IllegalArgumentException("Bad subType: " + (this.subType & 0xFFFF)); throw new IllegalArgumentException("Bad subType: " + (this.subType & 0xFFFF));
} }
@ -109,8 +114,8 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
throw new IllegalArgumentException("Text message is blank"); throw new IllegalArgumentException("Text message is blank");
} }
// Поля ссылки только для reply/repost // Поля ссылки только для reply/repost/edit
if (this.subType == SUB_REPLY || this.subType == SUB_REPOST) { if (this.subType == SUB_REPLY || this.subType == SUB_REPOST || this.subType == SUB_EDIT) {
if (bb.remaining() < 1) { if (bb.remaining() < 1) {
throw new IllegalArgumentException("Missing toBlockchainNameLen"); throw new IllegalArgumentException("Missing toBlockchainNameLen");
@ -119,7 +124,7 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
int nameLen = Byte.toUnsignedInt(bb.get()); int nameLen = Byte.toUnsignedInt(bb.get());
if (nameLen <= 0) throw new IllegalArgumentException("toBlockchainNameLen is 0"); if (nameLen <= 0) throw new IllegalArgumentException("toBlockchainNameLen is 0");
if (bb.remaining() < nameLen + 4 + 32) { if (bb.remaining() < nameLen + 4 + 32) {
throw new IllegalArgumentException("Reply/Repost payload too short"); throw new IllegalArgumentException("Reply/Repost/Edit payload too short");
} }
byte[] nameBytes = new byte[nameLen]; byte[] nameBytes = new byte[nameLen];
@ -176,7 +181,7 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
this.toBlockHash32 = null; this.toBlockHash32 = null;
} }
/** Сообщение subType=REPLY (2) или subType=REPOST (3) со ссылкой на блок. */ /** Сообщение subType=REPLY (2) или subType=REPOST (3) или subType=EDIT (4) со ссылкой на блок. */
public TextBody(short subType, public TextBody(short subType,
String message, String message,
String toBlockchainName, String toBlockchainName,
@ -187,8 +192,8 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
Objects.requireNonNull(toBlockchainName, "toBlockchainName == null"); Objects.requireNonNull(toBlockchainName, "toBlockchainName == null");
Objects.requireNonNull(toBlockHash32, "toBlockHash32 == null"); Objects.requireNonNull(toBlockHash32, "toBlockHash32 == null");
if (subType != SUB_REPLY && subType != SUB_REPOST) { if (subType != SUB_REPLY && subType != SUB_REPOST && subType != SUB_EDIT) {
throw new IllegalArgumentException("subType must be SUB_REPLY or SUB_REPOST for this constructor"); throw new IllegalArgumentException("subType must be SUB_REPLY or SUB_REPOST or SUB_EDIT for this constructor");
} }
if (message.isBlank()) throw new IllegalArgumentException("message is blank"); if (message.isBlank()) throw new IllegalArgumentException("message is blank");
if (toBlockchainName.isBlank()) throw new IllegalArgumentException("toBlockchainName is blank"); if (toBlockchainName.isBlank()) throw new IllegalArgumentException("toBlockchainName is blank");
@ -217,7 +222,7 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
@Override @Override
public TextBody check() { public TextBody check() {
if (subType != SUB_NEW && subType != SUB_REPLY && subType != SUB_REPOST) { if (subType != SUB_NEW && subType != SUB_REPLY && subType != SUB_REPOST && subType != SUB_EDIT) {
throw new IllegalArgumentException("Bad subType: " + (subType & 0xFFFF)); throw new IllegalArgumentException("Bad subType: " + (subType & 0xFFFF));
} }
@ -225,7 +230,7 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
throw new IllegalArgumentException("Text message is blank"); throw new IllegalArgumentException("Text message is blank");
} }
if (subType == SUB_REPLY || subType == SUB_REPOST) { if (subType == SUB_REPLY || subType == SUB_REPOST || subType == SUB_EDIT) {
if (toBlockchainName == null || toBlockchainName.isBlank()) if (toBlockchainName == null || toBlockchainName.isBlank())
throw new IllegalArgumentException("toBlockchainName is blank"); throw new IllegalArgumentException("toBlockchainName is blank");
if (toBlockGlobalNumber < 0) if (toBlockGlobalNumber < 0)
@ -255,7 +260,7 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
byte[] nameBytes = null; byte[] nameBytes = null;
if (subType == SUB_REPLY || subType == SUB_REPOST) { if (subType == SUB_REPLY || subType == SUB_REPOST || subType == SUB_EDIT) {
nameBytes = toBlockchainName.getBytes(StandardCharsets.UTF_8); nameBytes = toBlockchainName.getBytes(StandardCharsets.UTF_8);
if (nameBytes.length == 0 || nameBytes.length > 255) { if (nameBytes.length == 0 || nameBytes.length > 255) {
throw new IllegalArgumentException("toBlockchainName utf8 len must be 1..255"); throw new IllegalArgumentException("toBlockchainName utf8 len must be 1..255");
@ -268,7 +273,7 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
} else { } else {
if (toBlockchainName != null || toBlockHash32 != null) { if (toBlockchainName != null || toBlockHash32 != null) {
throw new IllegalArgumentException("SUB_NEW must not contain reply/repost fields"); throw new IllegalArgumentException("SUB_NEW must not contain reply/repost/edit fields");
} }
} }
@ -282,7 +287,7 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
bb.putShort((short) msgUtf8.length); bb.putShort((short) msgUtf8.length);
bb.put(msgUtf8); bb.put(msgUtf8);
if (subType == SUB_REPLY || subType == SUB_REPOST) { if (subType == SUB_REPLY || subType == SUB_REPOST || subType == SUB_EDIT) {
bb.put((byte) nameBytes.length); bb.put((byte) nameBytes.length);
bb.put(nameBytes); bb.put(nameBytes);
bb.putInt(toBlockGlobalNumber); bb.putInt(toBlockGlobalNumber);
@ -298,10 +303,11 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
case SUB_NEW -> "NEW (1)"; case SUB_NEW -> "NEW (1)";
case SUB_REPLY -> "REPLY (2)"; case SUB_REPLY -> "REPLY (2)";
case SUB_REPOST -> "REPOST (3)"; case SUB_REPOST -> "REPOST (3)";
case SUB_EDIT -> "EDIT (4)";
default -> "UNKNOWN"; default -> "UNKNOWN";
}; };
if (subType == SUB_REPLY || subType == SUB_REPOST) { if (subType == SUB_REPLY || subType == SUB_REPOST || subType == SUB_EDIT) {
return """ return """
TextBody { TextBody {
тип записи : TEXT (type=1, ver=1) тип записи : TEXT (type=1, ver=1)
@ -358,16 +364,16 @@ public final class TextBody implements BodyRecord, BodyHasTarget {
@Override @Override
public String toBchName() { public String toBchName() {
return (subType == SUB_REPLY || subType == SUB_REPOST) ? toBlockchainName : null; return (subType == SUB_REPLY || subType == SUB_REPOST || subType == SUB_EDIT) ? toBlockchainName : null;
} }
@Override @Override
public Integer toBlockGlobalNumber() { public Integer toBlockGlobalNumber() {
return (subType == SUB_REPLY || subType == SUB_REPOST) ? toBlockGlobalNumber : null; return (subType == SUB_REPLY || subType == SUB_REPOST || subType == SUB_EDIT) ? toBlockGlobalNumber : null;
} }
@Override @Override
public byte[] toBlockHasheBytes() { public byte[] toBlockHasheBytes() {
return (subType == SUB_REPLY || subType == SUB_REPOST) ? toBlockHash32 : null; return (subType == SUB_REPLY || subType == SUB_REPOST || subType == SUB_EDIT) ? toBlockHash32 : null;
} }
} }

View File

@ -26,9 +26,13 @@ import static org.junit.jupiter.api.Assertions.*;
* 1) AddUser(USER1) 200 или 409 USER_ALREADY_EXISTS * 1) AddUser(USER1) 200 или 409 USER_ALREADY_EXISTS
* 2) AddUser(USER2) 200 или 409 USER_ALREADY_EXISTS * 2) AddUser(USER2) 200 или 409 USER_ALREADY_EXISTS
* *
* 3) USER1: HEADER + 3 NEW + 2 REPLY + 2 REACT (как было) * 3) USER1: HEADER + 3 NEW + 2 REPLY + 2 REACT + 3 EDIT (добавили)
* - редактируем два ранее написанных сообщения
* - одно сообщение редактируем два раза
*
* 4) USER2: HEADER + UserParams(name+address) + Connection(FRIEND -> USER1) * 4) USER2: HEADER + UserParams(name+address) + Connection(FRIEND -> USER1)
* 5) USER1: UserParams(name+surname) + Connection(FRIEND -> USER2) + Connection(FOLLOW -> USER2) * 5) USER1: UserParams(name+surname) + Connection(FRIEND -> USER2) + Connection(FOLLOW -> USER2)
* 6) USER2: Connection(UNFRIEND -> USER1)
* *
* Важно: * Важно:
* - у каждого пользователя СВОЙ ChainState * - у каждого пользователя СВОЙ ChainState
@ -97,7 +101,7 @@ public class IT_03_AddBlock_NoAuth {
); );
// ========================================================= // =========================================================
// 3) USER1 блоки (под message_stats) // 3) USER1 блоки (под message_stats + edits)
// ========================================================= // =========================================================
if (TestConfig.DEBUG()) { if (TestConfig.DEBUG()) {
TestLog.titleBlock(""" TestLog.titleBlock("""
@ -125,10 +129,10 @@ public class IT_03_AddBlock_NoAuth {
if (TestConfig.DEBUG()) TestLog.stepTitle("USER1: TEXT#1 (NEW) <- будет LIKE + REPLY"); if (TestConfig.DEBUG()) TestLog.stepTitle("USER1: TEXT#1 (NEW) <- будет LIKE + REPLY");
sender1.send(new TextBody(TextBody.SUB_NEW, "Hello #1 (NEW) from IT_03 test"), t); sender1.send(new TextBody(TextBody.SUB_NEW, "Hello #1 (NEW) from IT_03 test"), t);
if (TestConfig.DEBUG()) TestLog.stepTitle("USER1: TEXT#2 (NEW) <- будет ONLY LIKE"); if (TestConfig.DEBUG()) TestLog.stepTitle("USER1: TEXT#2 (NEW) <- будет ONLY LIKE + 2 EDIT");
sender1.send(new TextBody(TextBody.SUB_NEW, "Hello #2 (NEW) from IT_03 test"), t); sender1.send(new TextBody(TextBody.SUB_NEW, "Hello #2 (NEW) from IT_03 test"), t);
if (TestConfig.DEBUG()) TestLog.stepTitle("USER1: TEXT#3 (NEW) <- будет ONLY REPLY"); if (TestConfig.DEBUG()) TestLog.stepTitle("USER1: TEXT#3 (NEW) <- будет ONLY REPLY + 1 EDIT");
sender1.send(new TextBody(TextBody.SUB_NEW, "Hello #3 (NEW) from IT_03 test"), t); sender1.send(new TextBody(TextBody.SUB_NEW, "Hello #3 (NEW) from IT_03 test"), t);
byte[] text1Hash = st1.getGlobalHash32(1); byte[] text1Hash = st1.getGlobalHash32(1);
@ -174,8 +178,36 @@ public class IT_03_AddBlock_NoAuth {
text2Hash text2Hash
), t); ), t);
assertEquals(7, st1.globalLastNumber(), "USER1: должно быть 8 блоков: globalLastNumber=7"); // 3 EDIT (два сообщения исправляем, одно два раза)
assertEquals(5, st1.lineLastNumber((short) 1), "USER1: line=1 должно быть 5 TEXT блоков (3 new + 2 reply)"); if (TestConfig.DEBUG()) TestLog.stepTitle("USER1: TEXT#6 (EDIT -> TEXT#2) (исправление #1)");
sender1.send(new TextBody(
TextBody.SUB_EDIT,
"Hello #2 (EDIT#1) from IT_03 test",
TestConfig.BCH_NAME(),
2,
text2Hash
), t);
if (TestConfig.DEBUG()) TestLog.stepTitle("USER1: TEXT#7 (EDIT -> TEXT#2) (исправление #2)");
sender1.send(new TextBody(
TextBody.SUB_EDIT,
"Hello #2 (EDIT#2) from IT_03 test",
TestConfig.BCH_NAME(),
2,
text2Hash
), t);
if (TestConfig.DEBUG()) TestLog.stepTitle("USER1: TEXT#8 (EDIT -> TEXT#3) (исправление #1)");
sender1.send(new TextBody(
TextBody.SUB_EDIT,
"Hello #3 (EDIT#1) from IT_03 test",
TestConfig.BCH_NAME(),
3,
text3Hash
), t);
assertEquals(10, st1.globalLastNumber(), "USER1: после EDIT должно быть 11 блоков: globalLastNumber=10");
assertEquals(8, st1.lineLastNumber((short) 1), "USER1: line=1 должно быть 8 TEXT блоков (3 new + 2 reply + 3 edit)");
assertEquals(2, st1.lineLastNumber((short) 2), "USER1: line=2 должно быть 2 REACTION блока"); assertEquals(2, st1.lineLastNumber((short) 2), "USER1: line=2 должно быть 2 REACTION блока");
// ========================================================= // =========================================================