|
5 | 5 | import static org.hamcrest.Matchers.containsString; |
6 | 6 | import static org.hamcrest.core.Is.is; |
7 | 7 | import static org.hamcrest.number.IsCloseTo.closeTo; |
| 8 | +import static org.junit.Assert.assertTrue; |
8 | 9 |
|
9 | 10 | import java.math.BigDecimal; |
10 | 11 | import java.math.RoundingMode; |
| 12 | +import java.lang.reflect.Method; |
| 13 | +import java.util.ArrayList; |
| 14 | +import java.util.Comparator; |
11 | 15 | import java.util.List; |
12 | 16 | import java.util.concurrent.atomic.AtomicBoolean; |
13 | 17 |
|
| 18 | +import org.eclipse.swt.SWT; |
14 | 19 | import org.junit.Test; |
15 | 20 |
|
16 | 21 | import name.abuchen.portfolio.junit.AccountBuilder; |
|
28 | 33 | import name.abuchen.portfolio.snapshot.trades.Trade; |
29 | 34 | import name.abuchen.portfolio.snapshot.trades.TradeCategory; |
30 | 35 | import name.abuchen.portfolio.snapshot.trades.TradeCollector; |
| 36 | +import name.abuchen.portfolio.snapshot.trades.TradeCollectorException; |
31 | 37 | import name.abuchen.portfolio.snapshot.trades.TradesGroupedByTaxonomy; |
32 | 38 | import name.abuchen.portfolio.ui.util.viewers.Column; |
33 | 39 | import name.abuchen.portfolio.ui.util.viewers.ColumnEditingSupport.TouchClientListener; |
34 | 40 | import name.abuchen.portfolio.ui.util.viewers.MoneyColorLabelProvider; |
| 41 | +import name.abuchen.portfolio.ui.util.viewers.ColumnViewerSorter; |
35 | 42 | import name.abuchen.portfolio.ui.views.columns.NameColumn; |
36 | 43 | import name.abuchen.portfolio.ui.views.trades.TradeElement; |
| 44 | +import name.abuchen.portfolio.ui.views.trades.TradeDetailsView; |
37 | 45 |
|
38 | 46 | @SuppressWarnings("nls") |
39 | 47 | public class TradesTableViewerTest |
@@ -66,8 +74,7 @@ public void tradeReturnIsNotWeightedWhenGroupedByTaxonomy() throws Exception |
66 | 74 | double expected = trade.getReturn(); |
67 | 75 |
|
68 | 76 | assertThat(expected, closeTo(0.1, 0.0000001)); |
69 | | - assertThat(TradesTableViewer.getReturnValue(element), closeTo(expected, 0.0000001)); |
70 | | - assertThat(TradesTableViewer.getReturnValue(trade), closeTo(expected, 0.0000001)); |
| 77 | + assertThat(element.getTrade().getReturn(), closeTo(expected, 0.0000001)); |
71 | 78 | } |
72 | 79 |
|
73 | 80 | @Test |
@@ -201,7 +208,7 @@ public void renamingSecurityTouchesClient() throws Exception |
201 | 208 | Column column = new NameColumn(client); |
202 | 209 | column.getEditingSupport().addListener(new TouchClientListener(client)); |
203 | 210 |
|
204 | | - column.getEditingSupport().setValue(trade, "Renamed Security"); |
| 211 | + column.getEditingSupport().setValue(new TradeElement(trade, 0, 1.0), "Renamed Security"); |
205 | 212 |
|
206 | 213 | assertThat(security.getName(), is("Renamed Security")); |
207 | 214 | assertThat(client.getSecurities().get(0).getName(), is("Renamed Security")); |
@@ -249,4 +256,139 @@ public void renamingSecurityRefreshesAllTradeElements() throws Exception |
249 | 256 | assertThat(security.getName(), is("Renamed Security")); |
250 | 257 | assertThat(refreshCalled.get(), is(true)); |
251 | 258 | } |
| 259 | + |
| 260 | + @Test |
| 261 | + public void mapTradesToElementsAssignsNeutralSortOrder() throws TradeCollectorException |
| 262 | + { |
| 263 | + Client client = new Client(); |
| 264 | + |
| 265 | + Security security = new SecurityBuilder() // |
| 266 | + .addPrice("2020-01-01", Values.Quote.factorize(100)) // |
| 267 | + .addPrice("2020-02-01", Values.Quote.factorize(110)) // |
| 268 | + .addTo(client); |
| 269 | + |
| 270 | + Account account = new AccountBuilder() // |
| 271 | + .deposit_("2020-01-01", Values.Amount.factorize(20000)) // |
| 272 | + .addTo(client); |
| 273 | + |
| 274 | + new PortfolioBuilder(account) // |
| 275 | + .buy(security, "2020-01-01", Values.Share.factorize(50), Values.Amount.factorize(5000)) // |
| 276 | + .sell(security, "2020-02-01", Values.Share.factorize(50), Values.Amount.factorize(5500)) // |
| 277 | + .buy(security, "2020-03-01", Values.Share.factorize(25), Values.Amount.factorize(2500)) // |
| 278 | + .sell(security, "2020-04-01", Values.Share.factorize(25), Values.Amount.factorize(2600)) // |
| 279 | + .addTo(client); |
| 280 | + |
| 281 | + TradeCollector collector = new TradeCollector(client, new TestCurrencyConverter()); |
| 282 | + List<Trade> trades = collector.collect(security); |
| 283 | + |
| 284 | + List<TradeElement> elements = TradeDetailsView.mapTradesToElements(trades); |
| 285 | + |
| 286 | + assertThat(elements.size(), is(trades.size())); |
| 287 | + assertTrue(elements.stream().allMatch(TradeElement::isTrade)); |
| 288 | + assertTrue(elements.stream().mapToInt(TradeElement::getSortOrder).allMatch(order -> order == 0)); |
| 289 | + assertTrue(elements.stream().allMatch(element -> Double.compare(element.getWeight(), 1.0) == 0)); |
| 290 | + } |
| 291 | + |
| 292 | + @Test |
| 293 | + public void tradeElementComparatorUsesSortOrderBeforeDelegating() throws Exception |
| 294 | + { |
| 295 | + Client client = new Client(); |
| 296 | + |
| 297 | + Security security = new SecurityBuilder() // |
| 298 | + .addPrice("2020-01-01", Values.Quote.factorize(100)) // |
| 299 | + .addPrice("2020-02-01", Values.Quote.factorize(110)) // |
| 300 | + .addTo(client); |
| 301 | + |
| 302 | + Account account = new AccountBuilder() // |
| 303 | + .deposit_("2020-01-01", Values.Amount.factorize(20000)) // |
| 304 | + .addTo(client); |
| 305 | + |
| 306 | + new PortfolioBuilder(account) // |
| 307 | + .buy(security, "2020-01-01", Values.Share.factorize(100), Values.Amount.factorize(10000)) // |
| 308 | + .sell(security, "2020-02-01", Values.Share.factorize(100), Values.Amount.factorize(11000)) // |
| 309 | + .addTo(client); |
| 310 | + |
| 311 | + TradeCollector collector = new TradeCollector(client, new TestCurrencyConverter()); |
| 312 | + Trade trade = collector.collect(security).get(0); |
| 313 | + |
| 314 | + TradeElement first = new TradeElement(trade, 0, 1.0); |
| 315 | + TradeElement second = new TradeElement(trade, 1, 1.0); |
| 316 | + |
| 317 | + Comparator<Object> wrapped = (o1, o2) -> { |
| 318 | + throw new AssertionError("Comparator should not delegate when sort order differs"); |
| 319 | + }; |
| 320 | + |
| 321 | + setSortDirection(SWT.UP); |
| 322 | + try |
| 323 | + { |
| 324 | + TradesTableViewer.TradeElementComparator comparator = new TradesTableViewer.TradeElementComparator(wrapped); |
| 325 | + assertThat(comparator.compare(first, second), is(-1)); |
| 326 | + } |
| 327 | + finally |
| 328 | + { |
| 329 | + clearSortingContext(); |
| 330 | + } |
| 331 | + } |
| 332 | + |
| 333 | + @Test |
| 334 | + public void tradeElementComparatorDelegatesWhenSortOrderMatches() throws Exception |
| 335 | + { |
| 336 | + Client client = new Client(); |
| 337 | + |
| 338 | + Security security = new SecurityBuilder() // |
| 339 | + .addPrice("2020-01-01", Values.Quote.factorize(100)) // |
| 340 | + .addPrice("2020-02-01", Values.Quote.factorize(110)) // |
| 341 | + .addTo(client); |
| 342 | + |
| 343 | + Account account = new AccountBuilder() // |
| 344 | + .deposit_("2020-01-01", Values.Amount.factorize(20000)) // |
| 345 | + .addTo(client); |
| 346 | + |
| 347 | + new PortfolioBuilder(account) // |
| 348 | + .buy(security, "2020-01-01", Values.Share.factorize(100), Values.Amount.factorize(10000)) // |
| 349 | + .sell(security, "2020-02-01", Values.Share.factorize(100), Values.Amount.factorize(11000)) // |
| 350 | + .addTo(client); |
| 351 | + |
| 352 | + TradeCollector collector = new TradeCollector(client, new TestCurrencyConverter()); |
| 353 | + List<Trade> trades = collector.collect(security); |
| 354 | + |
| 355 | + TradeElement first = new TradeElement(trades.get(0), 0, 1.0); |
| 356 | + TradeElement second = new TradeElement(trades.get(0), 0, 1.0); |
| 357 | + |
| 358 | + List<TradeElement> compared = new ArrayList<>(); |
| 359 | + Comparator<Object> wrapped = (o1, o2) -> { |
| 360 | + compared.add((TradeElement) o1); |
| 361 | + compared.add((TradeElement) o2); |
| 362 | + return Double.compare(((TradeElement) o1).getTrade().getReturn(), |
| 363 | + ((TradeElement) o2).getTrade().getReturn()); |
| 364 | + }; |
| 365 | + |
| 366 | + setSortDirection(SWT.UP); |
| 367 | + try |
| 368 | + { |
| 369 | + TradesTableViewer.TradeElementComparator comparator = new TradesTableViewer.TradeElementComparator(wrapped); |
| 370 | + assertThat(comparator.compare(first, second), is(0)); |
| 371 | + } |
| 372 | + finally |
| 373 | + { |
| 374 | + clearSortingContext(); |
| 375 | + } |
| 376 | + |
| 377 | + assertThat(compared.size(), is(2)); |
| 378 | + assertTrue(compared.stream().allMatch(element -> element.getSortOrder() == 0)); |
| 379 | + } |
| 380 | + |
| 381 | + private static void setSortDirection(int direction) throws Exception |
| 382 | + { |
| 383 | + Method method = ColumnViewerSorter.SortingContext.class.getDeclaredMethod("setSortDirection", int.class); |
| 384 | + method.setAccessible(true); |
| 385 | + method.invoke(null, direction); |
| 386 | + } |
| 387 | + |
| 388 | + private static void clearSortingContext() throws Exception |
| 389 | + { |
| 390 | + Method method = ColumnViewerSorter.SortingContext.class.getDeclaredMethod("clear"); |
| 391 | + method.setAccessible(true); |
| 392 | + method.invoke(null); |
| 393 | + } |
252 | 394 | } |
0 commit comments