-
Notifications
You must be signed in to change notification settings - Fork 240
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Properly format and safely escape to CSV in DecodeEventLogger (#1092)
* Add failing test for toCSV() * Add missing " to timeslot value * Add failing test for quotes and commas in details * Separate comma and quote tests * Escape toCSV cells using utility * Use CSVFormatter instead of escape utils Allows us to control exactly how we want to format a CSV-valid row. * Never have a null cell Instead of using a stream map, opting for an explicit handling so the logger can explode when an unexpected null shows up. Prevents the situation where things are mysteriously blank, forcing developers to handle known null scenarios.
- Loading branch information
Showing
3 changed files
with
155 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 121 additions & 0 deletions
121
src/test/java/io/github/dsheirer/module/log/DecodeEventLoggerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package io.github.dsheirer.module.log; | ||
|
||
import io.github.dsheirer.alias.Alias; | ||
import io.github.dsheirer.alias.AliasModel; | ||
import io.github.dsheirer.channel.IChannelDescriptor; | ||
import io.github.dsheirer.identifier.IdentifierCollection; | ||
import io.github.dsheirer.identifier.Role; | ||
import io.github.dsheirer.identifier.configuration.AliasListConfigurationIdentifier; | ||
import io.github.dsheirer.identifier.configuration.DecoderTypeConfigurationIdentifier; | ||
import io.github.dsheirer.identifier.configuration.FrequencyConfigurationIdentifier; | ||
import io.github.dsheirer.module.decode.DecoderType; | ||
import io.github.dsheirer.module.decode.event.DecodeEvent; | ||
import io.github.dsheirer.module.decode.event.IDecodeEvent; | ||
import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; | ||
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup; | ||
import io.github.dsheirer.protocol.Protocol; | ||
import org.junit.jupiter.api.AfterEach; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.Arrays; | ||
|
||
import static org.junit.jupiter.api.Assertions.*; | ||
import static org.mockito.Mockito.*; | ||
|
||
class DecodeEventLoggerTest { | ||
IChannelDescriptor channelDescriptor = APCO25Channel.create(98765, 1); | ||
|
||
APCO25Talkgroup fromIdentifier = new APCO25Talkgroup(123, Role.FROM); | ||
APCO25Talkgroup toIdentifier = new APCO25Talkgroup(456, Role.TO); | ||
FrequencyConfigurationIdentifier freqIdentifier = new FrequencyConfigurationIdentifier(859562500L); | ||
DecoderTypeConfigurationIdentifier decoderIdentifier = new DecoderTypeConfigurationIdentifier(DecoderType.P25_PHASE1); | ||
AliasListConfigurationIdentifier aliasListIdentifier = new AliasListConfigurationIdentifier("My Alias List"); | ||
AliasModel aliasModel = new AliasModel(); | ||
|
||
Path logDirectory = Paths.get(System.getProperty("java.io.tmpdir"), "sdr_trunk_tests"); | ||
|
||
@BeforeEach | ||
void setUp() { | ||
aliasModel.addAliasList(aliasListIdentifier.getValue()); | ||
} | ||
|
||
@AfterEach | ||
void tearDown() { | ||
} | ||
|
||
IdentifierCollection buildIdentifierCollection() { | ||
return new IdentifierCollection(Arrays.asList( | ||
fromIdentifier, | ||
toIdentifier, | ||
decoderIdentifier, | ||
freqIdentifier, | ||
aliasListIdentifier | ||
)); | ||
} | ||
|
||
DecodeEvent.DecodeEventBuilder decodeEventBuilder() { | ||
return DecodeEvent.builder(1634428994000L) | ||
.channel(channelDescriptor) | ||
.identifiers(buildIdentifierCollection()) | ||
.duration(111) | ||
.protocol(Protocol.APCO25) | ||
.eventDescription("DATA_PACKET") | ||
.timeslot(2) | ||
.details("Some details"); | ||
} | ||
|
||
@Test | ||
void test_receive_writesToCsv() { | ||
IDecodeEvent decodeEvent = decodeEventBuilder().build(); | ||
|
||
DecodeEventLogger decodeEventLogger = new DecodeEventLogger(aliasModel, logDirectory, "_foo.txt", 859562500); | ||
DecodeEventLogger spy = spy(decodeEventLogger); | ||
|
||
doNothing().when(spy).write(anyString()); | ||
|
||
spy.receive(decodeEvent); | ||
|
||
String expectedToCsvString = | ||
"\"2021:10:16:20:03:14\",\"111\",\"APCO-25\",\"DATA_PACKET\",\"123\",\" (456)\",\"98765-1\",\"859.562500\",\"TS:2\",\"Some details\""; | ||
verify(spy).write(expectedToCsvString); | ||
} | ||
|
||
@Test | ||
void test_receive_withQuotesInDetails_writesToCsv() { | ||
IDecodeEvent decodeEvent = decodeEventBuilder() | ||
.details("Some details now with \"quotes\"!") | ||
.build(); | ||
|
||
DecodeEventLogger decodeEventLogger = new DecodeEventLogger(aliasModel, logDirectory, "_foo.txt", 859562500); | ||
DecodeEventLogger spy = spy(decodeEventLogger); | ||
|
||
doNothing().when(spy).write(anyString()); | ||
|
||
spy.receive(decodeEvent); | ||
|
||
String expectedToCsvString = | ||
"\"2021:10:16:20:03:14\",\"111\",\"APCO-25\",\"DATA_PACKET\",\"123\",\" (456)\",\"98765-1\",\"859.562500\",\"TS:2\",\"Some details now with \"\"quotes\"\"!\""; | ||
verify(spy).write(expectedToCsvString); | ||
} | ||
|
||
@Test | ||
void test_receive_withCommasInDetails_writesToCsv() { | ||
IDecodeEvent decodeEvent = decodeEventBuilder() | ||
.details("Some details now with, to an extent, commas!") | ||
.build(); | ||
|
||
DecodeEventLogger decodeEventLogger = new DecodeEventLogger(aliasModel, logDirectory, "_foo.txt", 859562500); | ||
DecodeEventLogger spy = spy(decodeEventLogger); | ||
|
||
doNothing().when(spy).write(anyString()); | ||
|
||
spy.receive(decodeEvent); | ||
|
||
String expectedToCsvString = | ||
"\"2021:10:16:20:03:14\",\"111\",\"APCO-25\",\"DATA_PACKET\",\"123\",\" (456)\",\"98765-1\",\"859.562500\",\"TS:2\",\"Some details now with, to an extent, commas!\""; | ||
verify(spy).write(expectedToCsvString); | ||
} | ||
} |