mateclaw/mateclaw-server/src/test/java/vip/mate/wiki/service/WikiEnrichmentBatchParseTest.java
matevip 0ffc224623 chore(test): backfill mateclaw-server/src/test/ that earlier PRIVATE_ITEMS pattern accidentally excluded
The PRIVATE_ITEMS list contained the bare 'test' entry, which rsync
interprets as 'any directory named test at any depth' — so it caught
the root-level /test/ scratch directory (intended) AND every src/test/
under each module (not intended).

Pattern is already anchored to /test (root-only). This commit rsyncs
the accumulated src/test/ tree forward so opensource has the unit tests
that have been written / updated against existing src/main/ code since
the pattern regression. Going forward each per-commit sync will carry
src/test/ files along with the main change.
2026-05-12 17:38:08 +08:00

95 lines
3.0 KiB
Java

package vip.mate.wiki.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import vip.mate.wiki.WikiProperties;
import vip.mate.wiki.dto.EnrichmentBatchPlan;
import vip.mate.wiki.job.WikiModelRoutingService;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock;
/**
* RFC-051 follow-up: pin parseBatchPlan's tolerance for the shapes weak
* models actually emit.
*/
class WikiEnrichmentBatchParseTest {
private WikiLinkEnrichmentService svc;
@BeforeEach
void setUp() {
svc = new WikiLinkEnrichmentService(
mock(WikiPageService.class),
mock(WikiModelRoutingService.class),
new WikiProperties(),
new ObjectMapper());
}
@Test
@DisplayName("happy path: parses well-formed multi-page plan")
void parsesGoodBatch() {
String json = """
{
"plans": {
"spring-ai": {
"replacements": [
{"original": "Spring AI", "replacement": "[[spring-ai|Spring AI]]", "occurrence": 1}
]
},
"linux": {
"replacements": []
}
}
}
""";
EnrichmentBatchPlan p = svc.parseBatchPlan(json);
assertNotNull(p);
assertEquals(2, p.plans().size());
assertEquals(1, p.plans().get("spring-ai").replacements().size());
assertTrue(p.plans().get("linux").replacements().isEmpty());
}
@Test
@DisplayName("tolerates fenced code block wrapper that some models love")
void parsesCodeFenced() {
String json = """
```json
{
"plans": {
"x": {"replacements": [{"original": "X", "replacement": "[[x|X]]", "occurrence": 1}]}
}
}
```""";
EnrichmentBatchPlan p = svc.parseBatchPlan(json);
assertNotNull(p);
assertEquals(1, p.plans().size());
}
@Test
@DisplayName("tolerates stray prose around the JSON object")
void parsesWithSurroundingProse() {
String json = "Sure! Here's the plan:\n{\"plans\":{\"x\":{\"replacements\":[]}}}\nLet me know if you need adjustments.";
EnrichmentBatchPlan p = svc.parseBatchPlan(json);
assertNotNull(p);
assertEquals(1, p.plans().size());
}
@Test
@DisplayName("returns empty (not null) when plans field is missing")
void missingPlansFieldYieldsEmpty() {
EnrichmentBatchPlan p = svc.parseBatchPlan("{}");
assertNotNull(p);
assertTrue(p.isEmpty());
}
@Test
@DisplayName("garbage input returns null so caller can skip cleanly")
void garbageReturnsNull() {
assertNull(svc.parseBatchPlan(""));
assertNull(svc.parseBatchPlan("not json at all"));
}
}