package com.baiyue.common.event; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.ValueSource; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; class ContainerNumbersTest { /** 规范化仍保持确定性,事件只能接受已冻结的规范值。 */ @Test void normalizesWhitespaceAndCaseButCanonicalFactsRequireExactValue() { assertThat(ContainerNumbers.normalizeRequired(" zcsu 7881970 ")).isEqualTo("ZCSU7881970"); assertThatThrownBy(() -> ContainerNumbers.requireCanonical("zcsu7881970")) .hasMessageContaining("normalized"); assertThatThrownBy(() -> ContainerNumbers.requireCanonical(" JZXH10231043 ")) .hasMessageContaining("normalized"); } /** 非 ISO 柜号可以作为事件事实,不在下游重新阻断。 */ @ParameterizedTest @ValueSource(strings = {"JZXH10231043", "ZCSU7881971", "MSCA6639870", "ABC", "ABCU123456789012", "LOCAL-2026-001"}) void acceptsNonIsoNumber(String containerNo) { assertThat(ContainerNumbers.normalizeRequired(" " + containerNo.toLowerCase(java.util.Locale.ROOT) + " ")) .isEqualTo(containerNo); assertThat(ContainerNumbers.requireCanonical(containerNo)).isEqualTo(containerNo); } /** 规范化前后均不得将空白柜号作为业务事实。 */ @ParameterizedTest @NullAndEmptySource @ValueSource(strings = {" ", "\u00a0\u3000"}) void rejectsMissingNumber(String containerNo) { assertThatThrownBy(() -> ContainerNumbers.normalizeRequired(containerNo)) .isInstanceOf(IllegalArgumentException.class).hasMessageContaining("required"); assertThatThrownBy(() -> ContainerNumbers.requireCanonical(containerNo)) .isInstanceOf(IllegalArgumentException.class).hasMessageContaining("required"); } }