添加重量输入以及改变线体号

main
yangk 1 month ago
parent 04c36ca2b7
commit 4dc308f5e5

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">

@ -1,9 +0,0 @@
package com.example.pdaplccontrol;
public interface BagNumberSender {
/**
* PLC
*/
void sendBagNumber(short bagNumber) throws PlcCommunicationException;
}

@ -1,75 +1,114 @@
package com.example.pdaplccontrol; package com.example.pdaplccontrol;
import android.os.Bundle; import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View; import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity implements View.OnClickListener { public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button[] buttons = new Button[9]; private final Button[] lineButtons = new Button[9];
private EditText editWeightKg;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
// 初始化 9 个按钮 editWeightKg = findViewById(R.id.editWeightKg);
buttons[0] = findViewById(R.id.btnBag1); setupWeightInput();
buttons[1] = findViewById(R.id.btnBag2); setupLineButtons();
buttons[2] = findViewById(R.id.btnBag3); }
buttons[3] = findViewById(R.id.btnBag4);
buttons[4] = findViewById(R.id.btnBag5);
buttons[5] = findViewById(R.id.btnBag6);
buttons[6] = findViewById(R.id.btnBag7);
buttons[7] = findViewById(R.id.btnBag8);
buttons[8] = findViewById(R.id.btnBag9);
// 绑定点击事件,并设置 Tag 为袋子编号 (1-9) private void setupWeightInput() {
for (int i = 0; i < buttons.length; i++) { editWeightKg.setOnEditorActionListener(new TextView.OnEditorActionListener() {
buttons[i].setTag((short) (i + 1)); @Override
buttons[i].setOnClickListener(this); public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
boolean isDone = actionId == EditorInfo.IME_ACTION_DONE
|| (event != null
&& event.getAction() == KeyEvent.ACTION_UP
&& event.getKeyCode() == KeyEvent.KEYCODE_ENTER);
if (isDone) {
sendWeight();
return true;
}
return false;
}
});
}
private void setupLineButtons() {
lineButtons[0] = findViewById(R.id.btnLine10);
lineButtons[1] = findViewById(R.id.btnLine11);
lineButtons[2] = findViewById(R.id.btnLine12);
lineButtons[3] = findViewById(R.id.btnLine13);
lineButtons[4] = findViewById(R.id.btnLine14);
lineButtons[5] = findViewById(R.id.btnLine15);
lineButtons[6] = findViewById(R.id.btnLine16);
lineButtons[7] = findViewById(R.id.btnLine17);
lineButtons[8] = findViewById(R.id.btnLine18);
for (int i = 0; i < lineButtons.length; i++) {
lineButtons[i].setTag((short) (PlcConfig.MIN_LINE_NUMBER + i));
lineButtons[i].setOnClickListener(this);
} }
} }
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (v instanceof Button) { if (v instanceof Button) {
short bagNumber = (short) v.getTag(); short lineNumber = (short) v.getTag();
// 防抖设计:点击后立即禁用所有按钮,防止重复提交 setControlsEnabled(false);
setButtonsEnabled(false); Toast.makeText(this, "正在向 PLC 发送线体号 " + lineNumber + "...", Toast.LENGTH_SHORT).show();
Toast.makeText(this, "正在向 PLC 发送 " + bagNumber + " 号袋...", Toast.LENGTH_SHORT).show();
// 异步下发到 PLC PlcManager.getInstance().sendLineNumberAsync(lineNumber, createCallback());
PlcManager.getInstance().sendBagNumberAsync(bagNumber, new PlcManager.PlcCallback() {
@Override
public void onSuccess(String message) {
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
// 恢复按钮状态
setButtonsEnabled(true);
}
@Override
public void onError(String error) {
Toast.makeText(MainActivity.this, error, Toast.LENGTH_LONG).show();
// 恢复按钮状态
setButtonsEnabled(true);
}
});
} }
} }
/** private void sendWeight() {
* final short weightGrams;
*/ try {
private void setButtonsEnabled(boolean enabled) { weightGrams = WeightInputParser.kgToGrams(editWeightKg.getText().toString());
for (Button btn : buttons) { } catch (IllegalArgumentException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
return;
}
setControlsEnabled(false);
Toast.makeText(this, "正在向 PLC 发送重量 " + weightGrams + "g...", Toast.LENGTH_SHORT).show();
PlcManager.getInstance().sendWeightGramsAsync(weightGrams, createCallback());
}
private PlcManager.PlcCallback createCallback() {
return new PlcManager.PlcCallback() {
@Override
public void onSuccess(String message) {
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
setControlsEnabled(true);
}
@Override
public void onError(String error) {
Toast.makeText(MainActivity.this, error, Toast.LENGTH_LONG).show();
setControlsEnabled(true);
}
};
}
private void setControlsEnabled(boolean enabled) {
editWeightKg.setEnabled(enabled);
for (Button btn : lineButtons) {
if (btn != null) { if (btn != null) {
btn.setEnabled(enabled); btn.setEnabled(enabled);
} }
} }
} }
} }

@ -3,10 +3,19 @@ package com.example.pdaplccontrol;
import Moka7.S7; import Moka7.S7;
import Moka7.S7Client; import Moka7.S7Client;
class Moka7BagNumberSender implements BagNumberSender { class Moka7PlcValueSender implements PlcValueSender {
@Override @Override
public void sendBagNumber(short bagNumber) throws PlcCommunicationException { public void sendLineNumber(short lineNumber) throws PlcCommunicationException {
writeWord(PlcConfig.LINE_NUMBER_OFFSET, lineNumber);
}
@Override
public void sendWeightGrams(short weightGrams) throws PlcCommunicationException {
writeWord(PlcConfig.WEIGHT_GRAMS_OFFSET, weightGrams);
}
private void writeWord(int offset, short value) throws PlcCommunicationException {
S7Client client = new S7Client(); S7Client client = new S7Client();
try { try {
client.SetConnectionType(S7.OP); client.SetConnectionType(S7.OP);
@ -15,14 +24,12 @@ class Moka7BagNumberSender implements BagNumberSender {
throw new PlcCommunicationException("PLC连接失败错误码" + connectRes); throw new PlcCommunicationException("PLC连接失败错误码" + connectRes);
} }
byte[] data = encodeBagNumber(bagNumber);
int writeRes = client.WriteArea( int writeRes = client.WriteArea(
S7.S7AreaDB, S7.S7AreaDB,
PlcConfig.DB_NUMBER, PlcConfig.DB_NUMBER,
PlcConfig.OFFSET, offset,
PlcConfig.BAG_NUMBER_BYTE_LENGTH, PlcConfig.WORD_BYTE_LENGTH,
data encodeWord(value)
); );
if (writeRes != 0) { if (writeRes != 0) {
throw new PlcCommunicationException("写入数据失败,错误码:" + S7Client.ErrorText(writeRes)); throw new PlcCommunicationException("写入数据失败,错误码:" + S7Client.ErrorText(writeRes));
@ -36,10 +43,10 @@ class Moka7BagNumberSender implements BagNumberSender {
} }
} }
static byte[] encodeBagNumber(short bagNumber) { static byte[] encodeWord(short value) {
byte[] data = new byte[PlcConfig.BAG_NUMBER_BYTE_LENGTH]; byte[] data = new byte[PlcConfig.WORD_BYTE_LENGTH];
// PLC 的 INT 为 2 字节,按 S7 大端格式写入,保证与 DB 中的整型变量匹配 // S7 的 Word/Int 都是 2 字节大端格式;当前值范围都在正数区间内
S7.SetShortAt(data, 0, bagNumber); S7.SetShortAt(data, 0, value);
return data; return data;
} }
} }

@ -2,13 +2,18 @@ package com.example.pdaplccontrol;
final class PlcConfig { final class PlcConfig {
// TODO: 参数修改,避免 PLC 地址散落在业务代码里。 // 参数集中放置,现场地址变化时只改这里。
static final String PLC_IP = "192.168.0.1"; static final String PLC_IP = "192.168.11.1";
static final int RACK = 0; static final int RACK = 0;
static final int SLOT = 1; static final int SLOT = 1;
static final int DB_NUMBER = 1; static final int DB_NUMBER = 49;
static final int OFFSET = 0; static final int LINE_NUMBER_OFFSET = 32;
static final int BAG_NUMBER_BYTE_LENGTH = 2; static final int WEIGHT_GRAMS_OFFSET = 34;
static final int WORD_BYTE_LENGTH = 2;
static final int MIN_LINE_NUMBER = 10;
static final int MAX_LINE_NUMBER = 18;
static final int MIN_WEIGHT_GRAMS = 0;
static final int MAX_WEIGHT_GRAMS = 30000;
private PlcConfig() { private PlcConfig() {
} }

@ -9,18 +9,16 @@ import java.util.concurrent.Executors;
public class PlcManager { public class PlcManager {
private static PlcManager instance; private static PlcManager instance;
private static final int MIN_BAG_NUMBER = 1; private final PlcValueSender plcValueSender;
private static final int MAX_BAG_NUMBER = 9;
private final BagNumberSender bagNumberSender;
private final Executor commandExecutor; private final Executor commandExecutor;
private final Executor callbackExecutor; private final Executor callbackExecutor;
private PlcManager() { private PlcManager() {
this(new Moka7BagNumberSender(), Executors.newSingleThreadExecutor(), new MainThreadExecutor()); this(new Moka7PlcValueSender(), Executors.newSingleThreadExecutor(), new MainThreadExecutor());
} }
PlcManager(BagNumberSender bagNumberSender, Executor commandExecutor, Executor callbackExecutor) { PlcManager(PlcValueSender plcValueSender, Executor commandExecutor, Executor callbackExecutor) {
this.bagNumberSender = bagNumberSender; this.plcValueSender = plcValueSender;
this.commandExecutor = commandExecutor; this.commandExecutor = commandExecutor;
this.callbackExecutor = callbackExecutor; this.callbackExecutor = callbackExecutor;
} }
@ -37,14 +35,9 @@ public class PlcManager {
void onError(String error); void onError(String error);
} }
/** public void sendLineNumberAsync(final short lineNumber, final PlcCallback callback) {
* PLC if (!isValidLineNumber(lineNumber)) {
* @param bagNumber (1-9) notifyError(callback, "线体号无效,只允许 10-18");
* @param callback
*/
public void sendBagNumberAsync(final short bagNumber, final PlcCallback callback) {
if (!isValidBagNumber(bagNumber)) {
notifyError(callback, "袋子编号无效,只允许 1-9");
return; return;
} }
@ -52,8 +45,8 @@ public class PlcManager {
@Override @Override
public void run() { public void run() {
try { try {
bagNumberSender.sendBagNumber(bagNumber); plcValueSender.sendLineNumber(lineNumber);
notifySuccess(callback, "成功下发袋子编号: " + bagNumber); notifySuccess(callback, "成功下发线体号: " + lineNumber);
} catch (PlcCommunicationException e) { } catch (PlcCommunicationException e) {
notifyError(callback, e.getMessage()); notifyError(callback, e.getMessage());
} }
@ -61,8 +54,31 @@ public class PlcManager {
}); });
} }
static boolean isValidBagNumber(short bagNumber) { public void sendWeightGramsAsync(final short weightGrams, final PlcCallback callback) {
return bagNumber >= MIN_BAG_NUMBER && bagNumber <= MAX_BAG_NUMBER; if (!isValidWeightGrams(weightGrams)) {
notifyError(callback, "重量范围为 0-30kg");
return;
}
commandExecutor.execute(new Runnable() {
@Override
public void run() {
try {
plcValueSender.sendWeightGrams(weightGrams);
notifySuccess(callback, "成功下发重量: " + weightGrams + "g");
} catch (PlcCommunicationException e) {
notifyError(callback, e.getMessage());
}
}
});
}
static boolean isValidLineNumber(short lineNumber) {
return lineNumber >= PlcConfig.MIN_LINE_NUMBER && lineNumber <= PlcConfig.MAX_LINE_NUMBER;
}
static boolean isValidWeightGrams(short weightGrams) {
return weightGrams >= PlcConfig.MIN_WEIGHT_GRAMS && weightGrams <= PlcConfig.MAX_WEIGHT_GRAMS;
} }
private void notifySuccess(final PlcCallback callback, final String message) { private void notifySuccess(final PlcCallback callback, final String message) {

@ -0,0 +1,14 @@
package com.example.pdaplccontrol;
public interface PlcValueSender {
/**
* 线
*/
void sendLineNumber(short lineNumber) throws PlcCommunicationException;
/**
* PLC
*/
void sendWeightGrams(short weightGrams) throws PlcCommunicationException;
}

@ -0,0 +1,36 @@
package com.example.pdaplccontrol;
import java.math.BigDecimal;
final class WeightInputParser {
private static final BigDecimal GRAMS_PER_KG = new BigDecimal("1000");
private WeightInputParser() {
}
static short kgToGrams(String input) {
if (input == null || input.trim().isEmpty()) {
throw new IllegalArgumentException("请输入重量");
}
BigDecimal kg;
try {
kg = new BigDecimal(input.trim());
} catch (NumberFormatException e) {
throw new IllegalArgumentException("重量格式不正确");
}
BigDecimal grams = kg.movePointRight(3).stripTrailingZeros();
if (kg.compareTo(BigDecimal.ZERO) < 0
|| grams.compareTo(BigDecimal.valueOf(PlcConfig.MAX_WEIGHT_GRAMS)) > 0) {
throw new IllegalArgumentException("重量范围为 0-30kg");
}
try {
return grams.shortValueExact();
} catch (ArithmeticException e) {
throw new IllegalArgumentException("重量最多精确到 0.001kg");
}
}
}

@ -2,17 +2,36 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center" android:gravity="center"
android:orientation="vertical"
android:padding="16dp"> android:padding="16dp">
<TextView
android:layout_width="220dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="重量(kg)"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginBottom="8dp" />
<EditText
android:id="@+id/editWeightKg"
android:layout_width="220dp"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:hint="0.000"
android:imeOptions="actionDone"
android:inputType="numberDecimal"
android:singleLine="true"
android:textSize="20sp" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="请选择要使用的袋子" android:layout_marginBottom="8dp"
android:textSize="24sp" android:text="请选择线体号"
android:textStyle="bold" android:textSize="18sp" />
android:layout_marginBottom="32dp"/>
<GridLayout <GridLayout
android:id="@+id/gridLayout" android:id="@+id/gridLayout"
@ -21,16 +40,78 @@
android:columnCount="3" android:columnCount="3"
android:rowCount="3"> android:rowCount="3">
<Button android:id="@+id/btnBag1" android:layout_width="80dp" android:layout_height="80dp" android:layout_margin="8dp" android:text="1号" android:textSize="20sp"/> <Button
<Button android:id="@+id/btnBag2" android:layout_width="80dp" android:layout_height="80dp" android:layout_margin="8dp" android:text="2号" android:textSize="20sp"/> android:id="@+id/btnLine10"
<Button android:id="@+id/btnBag3" android:layout_width="80dp" android:layout_height="80dp" android:layout_margin="8dp" android:text="3号" android:textSize="20sp"/> android:layout_width="80dp"
<Button android:id="@+id/btnBag4" android:layout_width="80dp" android:layout_height="80dp" android:layout_margin="8dp" android:text="4号" android:textSize="20sp"/> android:layout_height="80dp"
<Button android:id="@+id/btnBag5" android:layout_width="80dp" android:layout_height="80dp" android:layout_margin="8dp" android:text="5号" android:textSize="20sp"/> android:layout_margin="8dp"
<Button android:id="@+id/btnBag6" android:layout_width="80dp" android:layout_height="80dp" android:layout_margin="8dp" android:text="6号" android:textSize="20sp"/> android:text="10号"
<Button android:id="@+id/btnBag7" android:layout_width="80dp" android:layout_height="80dp" android:layout_margin="8dp" android:text="7号" android:textSize="20sp"/> android:textSize="20sp" />
<Button android:id="@+id/btnBag8" android:layout_width="80dp" android:layout_height="80dp" android:layout_margin="8dp" android:text="8号" android:textSize="20sp"/>
<Button android:id="@+id/btnBag9" android:layout_width="80dp" android:layout_height="80dp" android:layout_margin="8dp" android:text="9号" android:textSize="20sp"/> <Button
android:id="@+id/btnLine11"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="8dp"
android:text="11号"
android:textSize="20sp" />
<Button
android:id="@+id/btnLine12"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="8dp"
android:text="12号"
android:textSize="20sp" />
<Button
android:id="@+id/btnLine13"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="8dp"
android:text="13号"
android:textSize="20sp" />
<Button
android:id="@+id/btnLine14"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="8dp"
android:text="14号"
android:textSize="20sp" />
<Button
android:id="@+id/btnLine15"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="8dp"
android:text="15号"
android:textSize="20sp" />
<Button
android:id="@+id/btnLine16"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="8dp"
android:text="16号"
android:textSize="20sp" />
<Button
android:id="@+id/btnLine17"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="8dp"
android:text="17号"
android:textSize="20sp" />
<Button
android:id="@+id/btnLine18"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="8dp"
android:text="18号"
android:textSize="20sp" />
</GridLayout> </GridLayout>
</LinearLayout> </LinearLayout>

@ -4,28 +4,44 @@ import org.junit.Test;
import static org.junit.Assert.*; import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest { public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
@Test @Test
public void isValidBagNumber_acceptsOneToNine() { public void isValidLineNumber_acceptsTenToEighteen() {
for (short bagNumber = 1; bagNumber <= 9; bagNumber++) { for (short lineNumber = 10; lineNumber <= 18; lineNumber++) {
assertTrue(PlcManager.isValidBagNumber(bagNumber)); assertTrue(PlcManager.isValidLineNumber(lineNumber));
} }
} }
@Test @Test
public void isValidBagNumber_rejectsOutOfRange() { public void isValidLineNumber_rejectsOutOfRange() {
assertFalse(PlcManager.isValidBagNumber((short) 0)); assertFalse(PlcManager.isValidLineNumber((short) 9));
assertFalse(PlcManager.isValidBagNumber((short) 10)); assertFalse(PlcManager.isValidLineNumber((short) 19));
assertFalse(PlcManager.isValidBagNumber((short) -1)); }
@Test
public void kgToGrams_acceptsZeroToThirtyKgWithGramPrecision() {
assertEquals(0, WeightInputParser.kgToGrams("0"));
assertEquals(1000, WeightInputParser.kgToGrams("1"));
assertEquals(12345, WeightInputParser.kgToGrams("12.345"));
assertEquals(30000, WeightInputParser.kgToGrams("30"));
}
@Test
public void kgToGrams_rejectsInvalidInput() {
assertInvalidWeight("");
assertInvalidWeight("abc");
assertInvalidWeight("-0.001");
assertInvalidWeight("30.001");
assertInvalidWeight("1.2345");
}
private void assertInvalidWeight(String input) {
try {
WeightInputParser.kgToGrams(input);
fail("Expected invalid weight for input: " + input);
} catch (IllegalArgumentException expected) {
// 测试只关心非法输入会被拦截,具体提示由业务层统一维护。
}
} }
} }

@ -1,19 +0,0 @@
package com.example.pdaplccontrol;
import org.junit.Test;
import static org.junit.Assert.*;
public class Moka7BagNumberSenderTest {
@Test
public void encodeBagNumber_oneToNine_usesS7IntBigEndianBytes() {
for (short bagNumber = 1; bagNumber <= 9; bagNumber++) {
byte[] data = Moka7BagNumberSender.encodeBagNumber(bagNumber);
assertEquals(PlcConfig.BAG_NUMBER_BYTE_LENGTH, data.length);
assertEquals(0, data[0]);
assertEquals(bagNumber, data[1]);
}
}
}

@ -0,0 +1,22 @@
package com.example.pdaplccontrol;
import Moka7.S7;
import org.junit.Test;
import static org.junit.Assert.*;
public class Moka7PlcValueSenderTest {
@Test
public void encodeWord_validPositiveValues_usesS7BigEndianBytes() {
short[] values = new short[] {10, 18, 0, 12345, 30000};
for (short value : values) {
byte[] data = Moka7PlcValueSender.encodeWord(value);
assertEquals(PlcConfig.WORD_BYTE_LENGTH, data.length);
assertEquals(value, (short) S7.GetShortAt(data, 0));
}
}
}

@ -9,32 +9,62 @@ import static org.junit.Assert.*;
public class PlcManagerTest { public class PlcManagerTest {
@Test @Test
public void sendBagNumberAsync_oneToNine_delegatesExactBagNumber() { public void sendLineNumberAsync_tenToEighteen_delegatesExactLineNumber() {
for (short bagNumber = 1; bagNumber <= 9; bagNumber++) { for (short lineNumber = 10; lineNumber <= 18; lineNumber++) {
RecordingBagNumberSender sender = new RecordingBagNumberSender(); RecordingPlcValueSender sender = new RecordingPlcValueSender();
RecordingCallback callback = new RecordingCallback(); RecordingCallback callback = new RecordingCallback();
PlcManager manager = new PlcManager(sender, new DirectExecutor(), new DirectExecutor()); PlcManager manager = new PlcManager(sender, new DirectExecutor(), new DirectExecutor());
manager.sendBagNumberAsync(bagNumber, callback); manager.sendLineNumberAsync(lineNumber, callback);
assertTrue(sender.called); assertNotNull(sender.lineNumber);
assertEquals(bagNumber, sender.bagNumber); assertEquals((int) lineNumber, (int) sender.lineNumber);
assertEquals("成功下发袋子编号: " + bagNumber, callback.successMessage); assertNull(sender.weightGrams);
assertEquals("成功下发线体号: " + lineNumber, callback.successMessage);
assertNull(callback.errorMessage); assertNull(callback.errorMessage);
} }
} }
@Test @Test
public void sendBagNumberAsync_invalidNumber_doesNotCallSender() { public void sendLineNumberAsync_invalidNumber_doesNotCallSender() {
RecordingBagNumberSender sender = new RecordingBagNumberSender(); RecordingPlcValueSender sender = new RecordingPlcValueSender();
RecordingCallback callback = new RecordingCallback(); RecordingCallback callback = new RecordingCallback();
PlcManager manager = new PlcManager(sender, new DirectExecutor(), new DirectExecutor()); PlcManager manager = new PlcManager(sender, new DirectExecutor(), new DirectExecutor());
manager.sendBagNumberAsync((short) 10, callback); manager.sendLineNumberAsync((short) 9, callback);
assertFalse(sender.called); assertNull(sender.lineNumber);
assertNull(sender.weightGrams);
assertNull(callback.successMessage); assertNull(callback.successMessage);
assertEquals("袋子编号无效,只允许 1-9", callback.errorMessage); assertEquals("线体号无效,只允许 10-18", callback.errorMessage);
}
@Test
public void sendWeightGramsAsync_validWeight_delegatesExactGrams() {
RecordingPlcValueSender sender = new RecordingPlcValueSender();
RecordingCallback callback = new RecordingCallback();
PlcManager manager = new PlcManager(sender, new DirectExecutor(), new DirectExecutor());
manager.sendWeightGramsAsync((short) 12345, callback);
assertNull(sender.lineNumber);
assertEquals(12345, (int) sender.weightGrams);
assertEquals("成功下发重量: 12345g", callback.successMessage);
assertNull(callback.errorMessage);
}
@Test
public void sendWeightGramsAsync_invalidWeight_doesNotCallSender() {
RecordingPlcValueSender sender = new RecordingPlcValueSender();
RecordingCallback callback = new RecordingCallback();
PlcManager manager = new PlcManager(sender, new DirectExecutor(), new DirectExecutor());
manager.sendWeightGramsAsync((short) -1, callback);
assertNull(sender.lineNumber);
assertNull(sender.weightGrams);
assertNull(callback.successMessage);
assertEquals("重量范围为 0-30kg", callback.errorMessage);
} }
private static class DirectExecutor implements Executor { private static class DirectExecutor implements Executor {
@ -44,14 +74,18 @@ public class PlcManagerTest {
} }
} }
private static class RecordingBagNumberSender implements BagNumberSender { private static class RecordingPlcValueSender implements PlcValueSender {
private boolean called; private Short lineNumber;
private short bagNumber; private Short weightGrams;
@Override @Override
public void sendBagNumber(short bagNumber) { public void sendLineNumber(short lineNumber) {
this.called = true; this.lineNumber = lineNumber;
this.bagNumber = bagNumber; }
@Override
public void sendWeightGrams(short weightGrams) {
this.weightGrams = weightGrams;
} }
} }

Loading…
Cancel
Save