276 lines
12 KiB
Java
276 lines
12 KiB
Java
package auctiora;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.api.DisplayName;
|
|
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.time.LocalDateTime;
|
|
import java.time.Instant;
|
|
import java.time.ZoneId;
|
|
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
import static org.mockito.Mockito.*;
|
|
|
|
/**
|
|
* Test cases for ScraperDataAdapter.
|
|
* Tests conversion from external scraper schema to monitor schema.
|
|
*/
|
|
class ScraperDataAdapterTest {
|
|
|
|
@Test
|
|
@DisplayName("Should extract numeric ID from text format auction ID")
|
|
void testExtractNumericIdFromAuctionId() {
|
|
assertEquals(39813, ScraperDataAdapter.extractNumericId("A7-39813"));
|
|
assertEquals(12345, ScraperDataAdapter.extractNumericId("A1-12345"));
|
|
assertEquals(0, ScraperDataAdapter.extractNumericId(null));
|
|
assertEquals(0, ScraperDataAdapter.extractNumericId(""));
|
|
assertEquals(0, ScraperDataAdapter.extractNumericId("ABC"));
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should extract numeric ID from text format lot ID")
|
|
void testExtractNumericIdFromLotId() {
|
|
// "A1-28505-5" → 285055 (concatenates all digits)
|
|
assertEquals(285055, ScraperDataAdapter.extractNumericId("A1-28505-5"));
|
|
assertEquals(123456, ScraperDataAdapter.extractNumericId("A7-1234-56"));
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should return 0 for IDs that exceed Long.MAX_VALUE")
|
|
void testExtractNumericIdTooLarge() {
|
|
// These IDs are too large for a long (> 19 digits or > Long.MAX_VALUE)
|
|
assertEquals(0, ScraperDataAdapter.extractNumericId("856462986966260305674"));
|
|
assertEquals(0, ScraperDataAdapter.extractNumericId("28492384530402679688"));
|
|
assertEquals(0, ScraperDataAdapter.extractNumericId("A7-856462986966260305674"));
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should convert scraper auction format to AuctionInfo")
|
|
void testFromScraperAuction() throws SQLException {
|
|
// Mock ResultSet with scraper format data
|
|
ResultSet rs = mock(ResultSet.class);
|
|
when(rs.getString("auction_id")).thenReturn("A7-39813");
|
|
when(rs.getString("title")).thenReturn("Industrial Equipment Auction");
|
|
when(rs.getString("location")).thenReturn("Cluj-Napoca, RO");
|
|
when(rs.getString("url")).thenReturn("https://example.com/auction/A7-39813");
|
|
when(rs.getInt("lots_count")).thenReturn(150);
|
|
when(rs.getString("first_lot_closing_time")).thenReturn("2025-12-15T14:30:00");
|
|
|
|
AuctionInfo result = ScraperDataAdapter.fromScraperAuction(rs);
|
|
|
|
assertNotNull(result);
|
|
assertEquals(39813, result.auctionId());
|
|
assertEquals("Industrial Equipment Auction", result.title());
|
|
assertEquals("Cluj-Napoca, RO", result.location());
|
|
assertEquals("Cluj-Napoca", result.city());
|
|
assertEquals("RO", result.country());
|
|
assertEquals("https://example.com/auction/A7-39813", result.url());
|
|
assertEquals("A7", result.typePrefix());
|
|
assertEquals(150, result.lotCount());
|
|
assertNotNull(result.firstLotClosingTime());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should handle auction with simple location without country")
|
|
void testFromScraperAuctionSimpleLocation() throws SQLException {
|
|
ResultSet rs = mock(ResultSet.class);
|
|
when(rs.getString("auction_id")).thenReturn("A1-12345");
|
|
when(rs.getString("title")).thenReturn("Test Auction");
|
|
when(rs.getString("location")).thenReturn("Amsterdam");
|
|
when(rs.getString("url")).thenReturn("https://example.com/auction/A1-12345");
|
|
when(rs.getInt("lots_count")).thenReturn(50);
|
|
when(rs.getString("first_lot_closing_time")).thenReturn(null);
|
|
|
|
AuctionInfo result = ScraperDataAdapter.fromScraperAuction(rs);
|
|
|
|
assertEquals("Amsterdam", result.city());
|
|
assertEquals("", result.country());
|
|
assertNull(result.firstLotClosingTime());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should convert scraper lot format to Lot")
|
|
void testFromScraperLot() throws SQLException {
|
|
ResultSet rs = mock(ResultSet.class);
|
|
when(rs.getString("lot_id")).thenReturn("A1-28505-5");
|
|
when(rs.getString("auction_id")).thenReturn("A7-39813");
|
|
when(rs.getString("title")).thenReturn("Forklift Toyota");
|
|
when(rs.getString("description")).thenReturn("Electric forklift in good condition");
|
|
when(rs.getString("category")).thenReturn("Machinery");
|
|
when(rs.getString("current_bid")).thenReturn("€1250.50");
|
|
when(rs.getString("closing_time")).thenReturn("2025-12-15T14:30:00");
|
|
when(rs.getString("url")).thenReturn("https://example.com/lot/A1-28505-5");
|
|
|
|
Lot result = ScraperDataAdapter.fromScraperLot(rs);
|
|
|
|
assertNotNull(result);
|
|
assertEquals(285055, result.lotId());
|
|
assertEquals(39813, result.saleId());
|
|
assertEquals("Forklift Toyota", result.title());
|
|
assertEquals("Electric forklift in good condition", result.description());
|
|
assertEquals("Machinery", result.category());
|
|
assertEquals(1250.50, result.currentBid(), 0.01);
|
|
assertEquals("EUR", result.currency());
|
|
assertEquals("https://example.com/lot/A1-28505-5", result.url());
|
|
assertNotNull(result.closingTime());
|
|
assertFalse(result.closingNotified());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should parse bid amount from various formats")
|
|
void testParseBidAmount() throws SQLException {
|
|
// Test €123.45 format
|
|
ResultSet rs1 = createLotResultSet("€123.45");
|
|
Lot lot1 = ScraperDataAdapter.fromScraperLot(rs1);
|
|
assertEquals(123.45, lot1.currentBid(), 0.01);
|
|
assertEquals("EUR", lot1.currency());
|
|
|
|
// Test $50.00 format
|
|
ResultSet rs2 = createLotResultSet("$50.00");
|
|
Lot lot2 = ScraperDataAdapter.fromScraperLot(rs2);
|
|
assertEquals(50.00, lot2.currentBid(), 0.01);
|
|
assertEquals("USD", lot2.currency());
|
|
|
|
// Test "No bids" format
|
|
ResultSet rs3 = createLotResultSet("No bids");
|
|
Lot lot3 = ScraperDataAdapter.fromScraperLot(rs3);
|
|
assertEquals(0.0, lot3.currentBid(), 0.01);
|
|
|
|
// Test plain number
|
|
ResultSet rs4 = createLotResultSet("999.99");
|
|
Lot lot4 = ScraperDataAdapter.fromScraperLot(rs4);
|
|
assertEquals(999.99, lot4.currentBid(), 0.01);
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should handle missing or null fields gracefully")
|
|
void testHandleNullFields() throws SQLException {
|
|
ResultSet rs = mock(ResultSet.class);
|
|
when(rs.getString("lot_id")).thenReturn("A1-12345-1");
|
|
when(rs.getString("auction_id")).thenReturn("A7-99999");
|
|
when(rs.getString("title")).thenReturn("Test Lot");
|
|
when(rs.getString("description")).thenReturn(null);
|
|
when(rs.getString("category")).thenReturn(null);
|
|
when(rs.getString("current_bid")).thenReturn(null);
|
|
when(rs.getString("closing_time")).thenReturn(null);
|
|
when(rs.getString("url")).thenReturn("https://example.com/lot");
|
|
|
|
Lot result = ScraperDataAdapter.fromScraperLot(rs);
|
|
|
|
assertNotNull(result);
|
|
assertEquals("", result.description());
|
|
assertEquals("", result.category());
|
|
assertEquals(0.0, result.currentBid());
|
|
assertNull(result.closingTime());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should parse various timestamp formats")
|
|
void testTimestampParsing() throws SQLException {
|
|
// ISO local date time
|
|
ResultSet rs1 = mock(ResultSet.class);
|
|
setupBasicLotMock(rs1);
|
|
when(rs1.getString("closing_time")).thenReturn("2025-12-15T14:30:00");
|
|
Lot lot1 = ScraperDataAdapter.fromScraperLot(rs1);
|
|
assertNotNull(lot1.closingTime());
|
|
assertEquals(LocalDateTime.of(2025, 12, 15, 14, 30, 0), lot1.closingTime());
|
|
|
|
// SQL timestamp format
|
|
ResultSet rs2 = mock(ResultSet.class);
|
|
setupBasicLotMock(rs2);
|
|
when(rs2.getString("closing_time")).thenReturn("2025-12-15 14:30:00");
|
|
Lot lot2 = ScraperDataAdapter.fromScraperLot(rs2);
|
|
assertNotNull(lot2.closingTime());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should handle invalid timestamp gracefully")
|
|
void testInvalidTimestamp() throws SQLException {
|
|
ResultSet rs = mock(ResultSet.class);
|
|
setupBasicLotMock(rs);
|
|
when(rs.getString("closing_time")).thenReturn("invalid-date");
|
|
|
|
Lot result = ScraperDataAdapter.fromScraperLot(rs);
|
|
assertNull(result.closingTime());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should extract type prefix from auction ID")
|
|
void testTypeExtraction() throws SQLException {
|
|
ResultSet rs1 = mock(ResultSet.class);
|
|
when(rs1.getString("auction_id")).thenReturn("A7-39813");
|
|
when(rs1.getString("title")).thenReturn("Test");
|
|
when(rs1.getString("location")).thenReturn("Test, NL");
|
|
when(rs1.getString("url")).thenReturn("http://test.com");
|
|
when(rs1.getInt("lots_count")).thenReturn(10);
|
|
when(rs1.getString("first_lot_closing_time")).thenReturn(null);
|
|
|
|
AuctionInfo auction1 = ScraperDataAdapter.fromScraperAuction(rs1);
|
|
assertEquals("A7", auction1.typePrefix());
|
|
|
|
ResultSet rs2 = mock(ResultSet.class);
|
|
when(rs2.getString("auction_id")).thenReturn("B1-12345");
|
|
when(rs2.getString("title")).thenReturn("Test");
|
|
when(rs2.getString("location")).thenReturn("Test, NL");
|
|
when(rs2.getString("url")).thenReturn("http://test.com");
|
|
when(rs2.getInt("lots_count")).thenReturn(10);
|
|
when(rs2.getString("first_lot_closing_time")).thenReturn(null);
|
|
|
|
AuctionInfo auction2 = ScraperDataAdapter.fromScraperAuction(rs2);
|
|
assertEquals("B1", auction2.typePrefix());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should handle GBP currency symbol")
|
|
void testGBPCurrency() throws SQLException {
|
|
ResultSet rs = createLotResultSet("£75.00");
|
|
Lot lot = ScraperDataAdapter.fromScraperLot(rs);
|
|
assertEquals(75.00, lot.currentBid(), 0.01);
|
|
assertEquals("GBP", lot.currency());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should parse epoch seconds timestamp")
|
|
void testParseEpochSeconds() {
|
|
long seconds = 1765994400L;
|
|
LocalDateTime expected = LocalDateTime.ofInstant(Instant.ofEpochSecond(seconds), ZoneId.systemDefault());
|
|
LocalDateTime parsed = ScraperDataAdapter.parseTimestamp(String.valueOf(seconds));
|
|
assertEquals(expected, parsed);
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("Should parse epoch milliseconds timestamp")
|
|
void testParseEpochMillis() {
|
|
long millis = 1765994400000L;
|
|
LocalDateTime expected = LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.systemDefault());
|
|
LocalDateTime parsed = ScraperDataAdapter.parseTimestamp(String.valueOf(millis));
|
|
assertEquals(expected, parsed);
|
|
}
|
|
|
|
// Helper methods
|
|
|
|
private ResultSet createLotResultSet(String bidAmount) throws SQLException {
|
|
ResultSet rs = mock(ResultSet.class);
|
|
when(rs.getString("lot_id")).thenReturn("A1-12345-1");
|
|
when(rs.getString("auction_id")).thenReturn("A7-99999");
|
|
when(rs.getString("title")).thenReturn("Test Lot");
|
|
when(rs.getString("description")).thenReturn("Test description");
|
|
when(rs.getString("category")).thenReturn("Test");
|
|
when(rs.getString("current_bid")).thenReturn(bidAmount);
|
|
when(rs.getString("closing_time")).thenReturn("2025-12-15T14:30:00");
|
|
when(rs.getString("url")).thenReturn("https://example.com/lot");
|
|
return rs;
|
|
}
|
|
|
|
private void setupBasicLotMock(ResultSet rs) throws SQLException {
|
|
when(rs.getString("lot_id")).thenReturn("A1-12345-1");
|
|
when(rs.getString("auction_id")).thenReturn("A7-99999");
|
|
when(rs.getString("title")).thenReturn("Test Lot");
|
|
when(rs.getString("description")).thenReturn("Test");
|
|
when(rs.getString("category")).thenReturn("Test");
|
|
when(rs.getString("current_bid")).thenReturn("€100.00");
|
|
when(rs.getString("url")).thenReturn("https://example.com/lot");
|
|
}
|
|
}
|