2424
2525import java .util .List ;
2626import java .util .Random ;
27- import java .util .concurrent .ExecutorService ;
28- import java .util .concurrent .Executors ;
29- import java .util .concurrent .TimeUnit ;
27+ import java .util .concurrent .*;
3028import java .util .concurrent .atomic .AtomicInteger ;
3129
3230import static org .junit .Assert .assertEquals ;
@@ -39,9 +37,9 @@ public class EncodeDecodeTest {
3937 new GsonBuilder ().serializeSpecialFloatingPointValues ().create ();
4038
4139 private static final int NUMBER_OF_POINTS = 5000 ;
40+ private static final int NUMBER_OF_TASKS = NUMBER_OF_POINTS * Territory .values ().length ;
4241 private static final int LOG_LINE_EVERY = 500 ;
4342
44-
4543 @ Test
4644 public void encodeDecodeTestFixedSeed () throws Exception {
4745 final long seed = 1431977987367L ;
@@ -56,19 +54,22 @@ public void encodeDecodeTestRandomSeed() throws Exception {
5654 doEncodeDecode (seed );
5755 }
5856
57+ @ SuppressWarnings ("BusyWait" )
5958 private static void doEncodeDecode (final long seed ) throws InterruptedException {
6059
6160 // Keep error count and create thread pool.
6261 final AtomicInteger errors = new AtomicInteger (0 );
62+ final AtomicInteger tasks = new AtomicInteger (0 );
63+
6364 final int threads = Runtime .getRuntime ().availableProcessors ();
6465 LOG .info ("encodeDecodeTest: Starting {} threads..." , threads );
65- final ExecutorService executor = Executors .newFixedThreadPool (threads );
66+ final ExecutorService executor = new ThreadPoolExecutor (
67+ threads , threads , // Fixed number of threads.
68+ 0L , TimeUnit .MILLISECONDS , // No keep-alive.
69+ new LinkedBlockingQueue <Runnable >(25000 )); // Reasonable-size blocking queue.
6670
6771 final Random randomGenerator = new Random (seed );
6872 for (int i = 0 ; i < NUMBER_OF_POINTS ; i ++) {
69- if ((i % LOG_LINE_EVERY ) == 0 ) {
70- LOG .info ("encodeDecodeTest: #{}/{}" , i , NUMBER_OF_POINTS );
71- }
7273
7374 // Encode location.
7475 final Point encode = Point .fromUniformlyDistributedRandomPoints (randomGenerator );
@@ -86,62 +87,82 @@ private static void doEncodeDecode(final long seed) throws InterruptedException
8687
8788 // Walk through the list in reverse order to get International first.
8889 for (final Territory territory : Territory .values ()) {
89- executor .execute (new Runnable () {
90- @ Override
91- public void run () {
92- try {
93- final List <Mapcode > resultsLimited = MapcodeCodec .encode (latDeg , lonDeg , territory );
94- for (final Mapcode mapcode : resultsLimited ) {
95-
96- // Check if the territory matches.
97- assertEquals (territory , mapcode .getTerritory ());
98-
99- // Check max distance.
100- final String codePrecision0 = mapcode .getCode (0 );
101- final String codePrecision1 = mapcode .getCode (1 );
102- final String codePrecision2 = mapcode .getCode (2 );
103-
104- final Point decodeLocationPrecision0 = MapcodeCodec .decode (codePrecision0 , territory );
105- final Point decodeLocationPrecision1 = MapcodeCodec .decode (codePrecision1 , territory );
106- final Point decodeLocationPrecision2 = MapcodeCodec .decode (codePrecision2 , territory );
107-
108- final double distancePrecision0Meters = Point .distanceInMeters (encode , decodeLocationPrecision0 );
109- final double distancePrecision1Meters = Point .distanceInMeters (encode , decodeLocationPrecision1 );
110- final double distancePrecision2Meters = Point .distanceInMeters (encode , decodeLocationPrecision2 );
111-
112- if (distancePrecision0Meters >= Mapcode .getSafeMaxOffsetInMeters (0 )) {
113- LOG .error ("encodeDecodeTest: " + mapcode + " distancePrecision0Meters = " + distancePrecision0Meters + " >= " + Mapcode .getSafeMaxOffsetInMeters (0 ));
114- errors .getAndIncrement ();
115- }
116- if (distancePrecision1Meters >= Mapcode .getSafeMaxOffsetInMeters (1 )) {
117- LOG .error ("encodeDecodeTest: " + mapcode + " distancePrecision1Meters = " + distancePrecision1Meters + " >= " + Mapcode .getSafeMaxOffsetInMeters (1 ));
118- errors .getAndIncrement ();
119- }
120- if (distancePrecision2Meters >= Mapcode .getSafeMaxOffsetInMeters (2 )) {
121- LOG .error ("encodeDecodeTest: " + mapcode + " distancePrecision2Meters = " + distancePrecision2Meters + " >= " + Mapcode .getSafeMaxOffsetInMeters (2 ));
122- errors .getAndIncrement ();
123- }
90+ while (true ) {
91+ try {
92+ executor .execute (new Runnable () {
93+
94+ @ Override
95+ public void run () {
96+ try {
97+ final int count = tasks .incrementAndGet ();
98+ if ((count % LOG_LINE_EVERY ) == 0 ) {
99+ LOG .info ("encodeDecodeTest: #{}/{}" , count , NUMBER_OF_TASKS );
100+ }
124101
125- // Check conversion from/to alphabets.
126- for (final Alphabet alphabet : Alphabet .values ()) {
127- final String mapcodeAlphabet = mapcode .getCode (alphabet );
128- final String mapcodeAscii = Mapcode .convertStringToPlainAscii (mapcodeAlphabet );
129- if (!codePrecision0 .equals (mapcodeAscii )) {
130- LOG .error ("encodeDecodeTest: " + mapcode + " alphabet=" + alphabet + ", original=" + codePrecision0 +
131- ", mapcodeAlphabet=" + mapcodeAlphabet + ", mapcodeAscii=" + mapcodeAscii );
102+ final List <Mapcode > resultsLimited = MapcodeCodec .encode (latDeg , lonDeg , territory );
103+ for (final Mapcode mapcode : resultsLimited ) {
104+
105+ // Check if the territory matches.
106+ assertEquals (territory , mapcode .getTerritory ());
107+
108+ // Check max distance.
109+ final String codePrecision0 = mapcode .getCode (0 );
110+ final String codePrecision1 = mapcode .getCode (1 );
111+ final String codePrecision2 = mapcode .getCode (2 );
112+
113+ final Point decodeLocationPrecision0 = MapcodeCodec .decode (codePrecision0 , territory );
114+ final Point decodeLocationPrecision1 = MapcodeCodec .decode (codePrecision1 , territory );
115+ final Point decodeLocationPrecision2 = MapcodeCodec .decode (codePrecision2 , territory );
116+
117+ final double distancePrecision0Meters = Point .distanceInMeters (encode , decodeLocationPrecision0 );
118+ final double distancePrecision1Meters = Point .distanceInMeters (encode , decodeLocationPrecision1 );
119+ final double distancePrecision2Meters = Point .distanceInMeters (encode , decodeLocationPrecision2 );
120+
121+ if (distancePrecision0Meters >= Mapcode .getSafeMaxOffsetInMeters (0 )) {
122+ LOG .error ("encodeDecodeTest: " + mapcode + " distancePrecision0Meters = " + distancePrecision0Meters + " >= " + Mapcode .getSafeMaxOffsetInMeters (0 ));
123+ errors .getAndIncrement ();
124+ }
125+ if (distancePrecision1Meters >= Mapcode .getSafeMaxOffsetInMeters (1 )) {
126+ LOG .error ("encodeDecodeTest: " + mapcode + " distancePrecision1Meters = " + distancePrecision1Meters + " >= " + Mapcode .getSafeMaxOffsetInMeters (1 ));
127+ errors .getAndIncrement ();
128+ }
129+ if (distancePrecision2Meters >= Mapcode .getSafeMaxOffsetInMeters (2 )) {
130+ LOG .error ("encodeDecodeTest: " + mapcode + " distancePrecision2Meters = " + distancePrecision2Meters + " >= " + Mapcode .getSafeMaxOffsetInMeters (2 ));
131+ errors .getAndIncrement ();
132+ }
133+
134+ // Check conversion from/to alphabets.
135+ for (final Alphabet alphabet : Alphabet .values ()) {
136+ final String mapcodeAlphabet = mapcode .getCode (alphabet );
137+ final String mapcodeAscii = Mapcode .convertStringToPlainAscii (mapcodeAlphabet );
138+ if (!codePrecision0 .equals (mapcodeAscii )) {
139+ LOG .error ("encodeDecodeTest: " + mapcode + " alphabet=" + alphabet + ", original=" + codePrecision0 +
140+ ", mapcodeAlphabet=" + mapcodeAlphabet + ", mapcodeAscii=" + mapcodeAscii );
141+ }
142+ }
132143 }
144+ } catch (final Exception e ) {
145+ LOG .error ("encodeDecodeTest: Unexpected exception: " , e );
146+ errors .getAndIncrement ();
133147 }
134148 }
135- } catch (final Exception e ) {
136- LOG .error ("encodeDecodeTest: Unexpected exception: " , e );
137- errors .getAndIncrement ();
138- }
149+ });
150+
151+ // Break out of loop and process next value.
152+ break ;
153+
154+ } catch (final RejectedExecutionException ignored ) {
155+
156+ // Perfectly fine; buffer is full. Just wait a bit and re-enter while loop.
157+ LOG .info ("encodeDecodeTest: buffer full, waiting, executed {} tasks so far" , tasks );
158+ Thread .sleep (1000 );
139159 }
140- });
160+ }
141161 }
142162 }
143163 executor .shutdown ();
144164 executor .awaitTermination (60 , TimeUnit .SECONDS );
145165 assertEquals ("Found errors" , 0 , errors .get ());
166+ LOG .info ("encodeDecodeTest: executed {} tasks" , tasks );
146167 }
147168}
0 commit comments