Fix gradle and add workflows
Build and Test j3270 / Build JAR & Run Tests (push) Failing after 2m24s

This commit is contained in:
2026-08-20 18:24:35 -04:00
parent 80166c477b
commit a1b1273022
68 changed files with 1102 additions and 153 deletions
@@ -0,0 +1,66 @@
package org.lib3270j.charset;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class EbcdicTranslatorTest {
private final EbcdicTranslator translator = new EbcdicTranslator();
@Test
public void testBasicAlphanumericTranslation() {
assertEquals('A', translator.ebcdicToUnicode(0xC1));
assertEquals('B', translator.ebcdicToUnicode(0xC2));
assertEquals('Z', translator.ebcdicToUnicode(0xE9));
assertEquals('a', translator.ebcdicToUnicode(0x81));
assertEquals('z', translator.ebcdicToUnicode(0xA9));
assertEquals('0', translator.ebcdicToUnicode(0xF0));
assertEquals('9', translator.ebcdicToUnicode(0xF9));
assertEquals(' ', translator.ebcdicToUnicode(0x40));
}
@Test
public void testReverseTranslation() {
assertEquals(0xC1, translator.unicodeToEbcdic('A'));
assertEquals(0x81, translator.unicodeToEbcdic('a'));
assertEquals(0xF0, translator.unicodeToEbcdic('0'));
assertEquals(0x40, translator.unicodeToEbcdic(' '));
assertEquals(0x4B, translator.unicodeToEbcdic('.'));
assertEquals(0x6B, translator.unicodeToEbcdic(','));
}
@Test
public void testSpecialCharactersCP037() {
// [ and ]
assertEquals(0xBA, translator.unicodeToEbcdic('['));
assertEquals(0xBB, translator.unicodeToEbcdic(']'));
assertEquals('[', translator.ebcdicToUnicode(0xBA));
assertEquals(']', translator.ebcdicToUnicode(0xBB));
// { and }
assertEquals(0xC0, translator.unicodeToEbcdic('{'));
assertEquals(0xD0, translator.unicodeToEbcdic('}'));
assertEquals('{', translator.ebcdicToUnicode(0xC0));
assertEquals('}', translator.ebcdicToUnicode(0xD0));
// Backslash \
assertEquals(0xE0, translator.unicodeToEbcdic('\\'));
assertEquals('\\', translator.ebcdicToUnicode(0xE0));
// Caret ^
assertEquals(0xB0, translator.unicodeToEbcdic('^'));
assertEquals('^', translator.ebcdicToUnicode(0xB0));
// Tilde ~
assertEquals(0xA1, translator.unicodeToEbcdic('~'));
assertEquals('~', translator.ebcdicToUnicode(0xA1));
}
@Test
public void testStringRoundTrip() {
String test = "Hello World! 123 [TEST] {VAR} \\";
byte[] ebcdic = translator.stringToEbcdic(test);
String restored = translator.ebcdicToString(ebcdic, 0, ebcdic.length);
assertEquals(test, restored);
}
}
@@ -0,0 +1,69 @@
package org.lib3270j.datastream;
import org.junit.jupiter.api.Test;
import org.lib3270j.TerminalModel;
import org.lib3270j.charset.EbcdicTranslator;
import org.lib3270j.screen.ScreenBuffer;
import org.lib3270j.screen.ExtendedAttribute;
import static org.junit.jupiter.api.Assertions.*;
import static org.lib3270j.protocol.DS3270Constants.*;
public class DataStreamProcessorTest {
private final EbcdicTranslator translator = new EbcdicTranslator();
private final ScreenBuffer screen = new ScreenBuffer(TerminalModel.IBM_3279_4, translator);
private final DataStreamProcessor processor = new DataStreamProcessor(screen, translator);
@Test
public void testEraseWriteAndSBAOrder() {
// Build an EW record:
// Byte 0: CMD_EW (0x05)
// Byte 1: WCC (0xC3) - restore keyboard, reset MDT
// Byte 2: ORDER_SBA (0x11)
// Byte 3, 4: Encoded address for 0 (0x40, 0x40)
// Byte 5: ORDER_SF (0x1D)
// Byte 6: FA (0xC0) - unprotected
// Byte 7..11: EBCDIC "HELLO" (0xC8, 0xC5, 0xD3, 0xD3, 0xD6)
byte[] record = new byte[] {
(byte) CMD_EW,
(byte) 0xC3,
(byte) ORDER_SBA,
(byte) 0x40, (byte) 0x40,
(byte) ORDER_SF,
(byte) FA_PRINTABLE,
(byte) 0xC8, (byte) 0xC5, (byte) 0xD3, (byte) 0xD3, (byte) 0xD6
};
processor.processRecord(record, 0, record.length, true);
assertTrue(screen.isFormatted());
assertTrue(screen.getCell(0).isFieldAttribute());
// Positions 1..5 should contain "HELLO"
assertEquals('H', screen.getCell(1).ucs4);
assertEquals('E', screen.getCell(2).ucs4);
assertEquals('L', screen.getCell(3).ucs4);
assertEquals('L', screen.getCell(4).ucs4);
assertEquals('O', screen.getCell(5).ucs4);
}
@Test
public void testRepeatToAddressOrder() {
// Write record with RA from 0 to 10 with character 'A' (0xC1)
byte[] record = new byte[] {
(byte) CMD_EW,
(byte) 0xC3,
(byte) ORDER_SBA,
(byte) 0x40, (byte) 0x40, // Address 0
(byte) ORDER_RA,
(byte) 0x40, (byte) 0x4A, // Address 10 (0x40, 0x4A)
(byte) 0xC1 // EBCDIC 'A'
};
processor.processRecord(record, 0, record.length, true);
for (int i = 0; i < 10; i++) {
assertEquals('A', screen.getCell(i).ucs4, "Cell " + i + " should be 'A'");
}
}
}
@@ -0,0 +1,55 @@
package org.lib3270j.datastream;
import org.junit.jupiter.api.Test;
import org.lib3270j.TerminalModel;
import org.lib3270j.charset.EbcdicTranslator;
import org.lib3270j.screen.ScreenBuffer;
import static org.junit.jupiter.api.Assertions.*;
import static org.lib3270j.protocol.DS3270Constants.*;
public class QueryReplyBuilderTest {
private final EbcdicTranslator translator = new EbcdicTranslator();
private final ScreenBuffer screen = new ScreenBuffer(TerminalModel.IBM_3279_4, translator);
private final QueryReplyBuilder qrBuilder = new QueryReplyBuilder(screen);
@Test
public void testBuildAllQueryReplies() {
byte[] replies = qrBuilder.buildAllQueryReplies(80, 43, 80 * 43);
assertNotNull(replies);
assertTrue(replies.length > 0);
assertEquals((byte) AID_SF, replies[0]);
}
@Test
public void testBuildFilteredQueryRepliesWithSupportedCodes() {
byte[] requested = new byte[] { (byte) QR_DDM, (byte) QR_USABLE_AREA };
byte[] replies = qrBuilder.buildQueryReplies(requested, 80, 43, 80 * 43);
assertNotNull(replies);
assertEquals((byte) AID_SF, replies[0]);
// First SF should be DDM: length (2 bytes), SFID_QREPLY (0x81), QR_DDM (0x95)
int len1 = ((replies[1] & 0xFF) << 8) | (replies[2] & 0xFF);
assertEquals(0x81, replies[3] & 0xFF);
assertEquals(QR_DDM, replies[4] & 0xFF);
// Second SF should be Usable Area
int pos2 = 1 + len1;
int len2 = ((replies[pos2] & 0xFF) << 8) | (replies[pos2 + 1] & 0xFF);
assertEquals(0x81, replies[pos2 + 2] & 0xFF);
assertEquals(QR_USABLE_AREA, replies[pos2 + 3] & 0xFF);
}
@Test
public void testBuildFilteredQueryRepliesWithUnsupportedCode() {
byte[] requested = new byte[] { (byte) 0x77 }; // Unsupported code
byte[] replies = qrBuilder.buildQueryReplies(requested, 80, 43, 80 * 43);
assertNotNull(replies);
assertEquals((byte) AID_SF, replies[0]);
// Should emit QR_NULL (0xFF)
assertEquals(0x81, replies[3] & 0xFF);
assertEquals(QR_NULL, replies[4] & 0xFF);
}
}
@@ -0,0 +1,83 @@
package org.lib3270j.ft;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class FTConfigTest {
@Test
public void testTsoReceiveAscii() {
FTConfig config = new FTConfig();
config.setHostType(FTConfig.HostType.TSO);
config.setDirection(FTConfig.Direction.RECEIVE);
config.setHostFilename("MY.DATASET");
config.setTransferMode(FTConfig.TransferMode.ASCII);
config.setCrAction(FTConfig.CrAction.REMOVE);
assertEquals("IND$FILE GET MY.DATASET ASCII CRLF", config.buildCommand());
}
@Test
public void testTsoReceiveBinary() {
FTConfig config = new FTConfig();
config.setHostType(FTConfig.HostType.TSO);
config.setDirection(FTConfig.Direction.RECEIVE);
config.setHostFilename("'USER.BIN.DATA'");
config.setTransferMode(FTConfig.TransferMode.BINARY);
assertEquals("IND$FILE GET 'USER.BIN.DATA'", config.buildCommand());
}
@Test
public void testTsoSendFixedRecfm() {
FTConfig config = new FTConfig();
config.setHostType(FTConfig.HostType.TSO);
config.setDirection(FTConfig.Direction.SEND);
config.setHostFilename("MY.DATASET");
config.setTransferMode(FTConfig.TransferMode.ASCII);
config.setCrAction(FTConfig.CrAction.REMOVE);
config.setRecfm("F");
config.setLrecl("80");
config.setBlksize("3120");
assertEquals("IND$FILE PUT MY.DATASET ASCII CRLF RECFM(F) LRECL(80) BLKSIZE(3120)", config.buildCommand());
}
@Test
public void testCmsReceiveBinaryNoNakedParen() {
FTConfig config = new FTConfig();
config.setHostType(FTConfig.HostType.CMS);
config.setDirection(FTConfig.Direction.RECEIVE);
config.setHostFilename("PROFILE EXEC A");
config.setTransferMode(FTConfig.TransferMode.BINARY);
// In CMS, binary receive has no options, so NO open parenthesis '(' should be generated!
assertEquals("IND$FILE GET PROFILE EXEC A", config.buildCommand());
}
@Test
public void testCmsReceiveAscii() {
FTConfig config = new FTConfig();
config.setHostType(FTConfig.HostType.CMS);
config.setDirection(FTConfig.Direction.RECEIVE);
config.setHostFilename("TEST DATA A");
config.setTransferMode(FTConfig.TransferMode.ASCII);
config.setCrAction(FTConfig.CrAction.REMOVE);
assertEquals("IND$FILE GET TEST DATA A (ASCII CRLF", config.buildCommand());
}
@Test
public void testCmsSendWithRecfmAndLrecl() {
FTConfig config = new FTConfig();
config.setHostType(FTConfig.HostType.CMS);
config.setDirection(FTConfig.Direction.SEND);
config.setHostFilename("TEST FILE A");
config.setTransferMode(FTConfig.TransferMode.ASCII);
config.setCrAction(FTConfig.CrAction.REMOVE);
config.setRecfm("V");
config.setLrecl("132");
assertEquals("IND$FILE PUT TEST FILE A (ASCII CRLF RECFM V LRECL 132", config.buildCommand());
}
}
@@ -0,0 +1,51 @@
package org.lib3270j.protocol;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.lib3270j.protocol.DS3270Constants.*;
public class DS3270ConstantsTest {
@Test
public void test12BitAddressRoundTrip() {
int rows = 24;
int cols = 80;
int maxAddr = rows * cols; // 1920
for (int addr = 0; addr < maxAddr; addr += 17) {
byte[] encoded = encodeAddress(addr, rows, cols);
assertEquals(2, encoded.length);
int decoded = decodeAddress(encoded[0] & 0xFF, encoded[1] & 0xFF);
assertEquals(addr, decoded, "Address " + addr + " failed round trip");
}
}
@Test
public void test14BitAddressRoundTrip() {
int rows = 60;
int cols = 80; // 4800 (> 4096, triggers 14-bit format)
int maxAddr = rows * cols;
for (int addr = 0; addr < maxAddr; addr += 123) {
byte[] encoded = encodeAddress(addr, rows, cols);
assertEquals(2, encoded.length);
int decoded = decodeAddress(encoded[0] & 0xFF, encoded[1] & 0xFF);
assertEquals(addr, decoded, "14-bit address " + addr + " failed round trip");
}
}
@Test
public void testFieldAttributePredicates() {
int protectedHighMod = FA_PRINTABLE | FA_PROTECT | FA_INT_HIGH_SEL | FA_MODIFY;
assertTrue(faIsProtected(protectedHighMod));
assertTrue(faIsHigh(protectedHighMod));
assertTrue(faIsModified(protectedHighMod));
assertFalse(faIsNumeric(protectedHighMod));
assertFalse(faIsSkip(protectedHighMod));
int skipField = FA_PRINTABLE | FA_PROTECT | FA_NUMERIC;
assertTrue(faIsSkip(skipField));
assertTrue(faIsProtected(skipField));
assertTrue(faIsNumeric(skipField));
}
}
@@ -0,0 +1,64 @@
package org.lib3270j.screen;
import org.junit.jupiter.api.Test;
import org.lib3270j.TerminalModel;
import org.lib3270j.charset.EbcdicTranslator;
import static org.junit.jupiter.api.Assertions.*;
import static org.lib3270j.protocol.DS3270Constants.*;
public class ScreenBufferTest {
private final EbcdicTranslator translator = new EbcdicTranslator();
private final ScreenBuffer screen = new ScreenBuffer(TerminalModel.IBM_3279_4, translator);
@Test
public void testScreenInitialization() {
assertEquals(24, screen.getRows());
assertEquals(80, screen.getCols());
assertEquals(43, screen.getMaxRows());
assertEquals(80, screen.getMaxCols());
assertFalse(screen.isFormatted());
}
@Test
public void testScreenEraseAlternate() {
screen.erase(true);
assertTrue(screen.isScreenAlt());
assertEquals(43, screen.getRows());
assertEquals(80, screen.getCols());
screen.erase(false);
assertFalse(screen.isScreenAlt());
assertEquals(24, screen.getRows());
assertEquals(80, screen.getCols());
}
@Test
public void testFieldNavigationAndFindAttribute() {
screen.erase(false);
// Place field attribute at position 0 (unprotected)
screen.setCellFA(0, (byte) FA_PRINTABLE);
// Place field attribute at position 20 (protected)
screen.setCellFA(20, (byte) (FA_PRINTABLE | FA_PROTECT));
assertTrue(screen.isFormatted());
assertEquals(0, screen.findFieldAttribute(5));
assertEquals(20, screen.findFieldAttribute(25));
// findNextUnprotected
int nextUnprot = screen.findNextUnprotected(0);
assertEquals(1, nextUnprot);
}
@Test
public void testGraphicEscapeTranslation() {
screen.erase(false);
// Set cell at position 10 to horizontal line (0xA2) with CS_GE (0x04)
ExtendedAttribute ea = screen.getCell(10);
ea.ec = (byte) 0xA2;
ea.cs = (byte) CS_GE;
screen.translateToUnicode();
assertEquals('\u2500', ea.ucs4); // '─'
}
}