mirror of
https://github.com/mvvasilev/personal-finances.git
synced 2025-04-19 14:19:52 +03:00
Tests maybe
This commit is contained in:
parent
9f741918d7
commit
126d9abf6b
4 changed files with 257 additions and 10 deletions
|
@ -82,7 +82,7 @@ public class CategoryService {
|
||||||
|
|
||||||
processedTransactionCategoryRepository.deleteAllForTransactions(transactions.stream().map(AbstractEntity::getId).toList());
|
processedTransactionCategoryRepository.deleteAllForTransactions(transactions.stream().map(AbstractEntity::getId).toList());
|
||||||
|
|
||||||
// Run each category's rules for all transactions in parallel to eachother
|
// Run each category's rules for all transactions concurrently to each other
|
||||||
final var futures = categorizations.stream()
|
final var futures = categorizations.stream()
|
||||||
.filter(Categorization::isRoot)
|
.filter(Categorization::isRoot)
|
||||||
.collect(Collectors.groupingBy(Categorization::getCategoryId, HashMap::new, Collectors.toList()))
|
.collect(Collectors.groupingBy(Categorization::getCategoryId, HashMap::new, Collectors.toList()))
|
||||||
|
@ -118,7 +118,7 @@ public class CategoryService {
|
||||||
}))
|
}))
|
||||||
.toArray(length -> (CompletableFuture<List<ProcessedTransactionCategory>>[]) new CompletableFuture[length]);
|
.toArray(length -> (CompletableFuture<List<ProcessedTransactionCategory>>[]) new CompletableFuture[length]);
|
||||||
|
|
||||||
// Run them all in parallel
|
// Run them all concurrently/in parallel
|
||||||
final var ptcs = CompletableFuture.allOf(futures).thenApply((v) ->
|
final var ptcs = CompletableFuture.allOf(futures).thenApply((v) ->
|
||||||
Arrays.stream(futures)
|
Arrays.stream(futures)
|
||||||
.flatMap(future -> future.join().stream())
|
.flatMap(future -> future.join().stream())
|
||||||
|
@ -128,15 +128,9 @@ public class CategoryService {
|
||||||
processedTransactionCategoryRepository.saveAllAndFlush(ptcs);
|
processedTransactionCategoryRepository.saveAllAndFlush(ptcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<ProcessedTransactionCategory> categorizeTransaction(final Collection<Categorization> allCategorizations, Categorization categorization, ProcessedTransaction processedTransaction) {
|
|
||||||
if (matchesRule(allCategorizations, categorization, processedTransaction)) {
|
|
||||||
return Optional.of(new ProcessedTransactionCategory(processedTransaction.getId(), categorization.getCategoryId()));
|
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean matchesRule(final Collection<Categorization> allCategorizations, final Categorization categorization, final ProcessedTransaction processedTransaction) {
|
|
||||||
|
public boolean matchesRule(final Collection<Categorization> allCategorizations, final Categorization categorization, final ProcessedTransaction processedTransaction) {
|
||||||
return switch (categorization.getCategorizationRule()) {
|
return switch (categorization.getCategorizationRule()) {
|
||||||
// string operations
|
// string operations
|
||||||
case STRING_REGEX, STRING_EQ, STRING_CONTAINS, STRING_IS_EMPTY -> {
|
case STRING_REGEX, STRING_EQ, STRING_CONTAINS, STRING_IS_EMPTY -> {
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
package dev.mvvasilev.finances;
|
||||||
|
|
||||||
|
import dev.mvvasilev.finances.entity.Categorization;
|
||||||
|
import dev.mvvasilev.finances.enums.CategorizationRule;
|
||||||
|
import dev.mvvasilev.finances.enums.ProcessedTransactionField;
|
||||||
|
import org.apache.commons.lang3.RandomUtils;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class CategorizationBuilder {
|
||||||
|
|
||||||
|
private Categorization categorization;
|
||||||
|
|
||||||
|
public CategorizationBuilder() {}
|
||||||
|
|
||||||
|
private CategorizationBuilder(Categorization categorization) {
|
||||||
|
this.categorization = categorization;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CategorizationBuilder withUser(int userId) {
|
||||||
|
var categorization = new Categorization();
|
||||||
|
|
||||||
|
categorization.setUserId(userId);
|
||||||
|
|
||||||
|
return new CategorizationBuilder(categorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CategorizationBuilder withCategory(long categoryId) {
|
||||||
|
var categorization = new Categorization();
|
||||||
|
|
||||||
|
categorization.setCategoryId(categoryId);
|
||||||
|
|
||||||
|
return new CategorizationBuilder(categorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CategorizationBuilder onField(ProcessedTransactionField field, CategorizationRule rule, boolean booleanValue) {
|
||||||
|
var categorization = new Categorization();
|
||||||
|
|
||||||
|
categorization.setRuleBasedOn(field);
|
||||||
|
categorization.setCategorizationRule(rule);
|
||||||
|
categorization.setBooleanValue(booleanValue);
|
||||||
|
|
||||||
|
return new CategorizationBuilder(categorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CategorizationBuilder onField(ProcessedTransactionField field, CategorizationRule rule, double numericValue) {
|
||||||
|
var categorization = new Categorization();
|
||||||
|
|
||||||
|
categorization.setRuleBasedOn(field);
|
||||||
|
categorization.setCategorizationRule(rule);
|
||||||
|
categorization.setNumericValue(numericValue);
|
||||||
|
|
||||||
|
return new CategorizationBuilder(categorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CategorizationBuilder onField(ProcessedTransactionField field, CategorizationRule rule, String stringValue) {
|
||||||
|
var categorization = new Categorization();
|
||||||
|
|
||||||
|
categorization.setRuleBasedOn(field);
|
||||||
|
categorization.setCategorizationRule(rule);
|
||||||
|
categorization.setStringValue(stringValue);
|
||||||
|
|
||||||
|
return new CategorizationBuilder(categorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CategorizationBuilder onBetween(ProcessedTransactionField field, double greaterThan, double lessThan) {
|
||||||
|
var categorization = new Categorization();
|
||||||
|
|
||||||
|
categorization.setRuleBasedOn(field);
|
||||||
|
categorization.setCategorizationRule(CategorizationRule.NUMERIC_BETWEEN);
|
||||||
|
categorization.setNumericGreaterThan(greaterThan);
|
||||||
|
categorization.setNumericLessThan(lessThan);
|
||||||
|
|
||||||
|
return new CategorizationBuilder(categorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CategorizationBuilder onBetween(ProcessedTransactionField field, LocalDateTime greaterThan, LocalDateTime lessThan) {
|
||||||
|
var categorization = new Categorization();
|
||||||
|
|
||||||
|
categorization.setRuleBasedOn(field);
|
||||||
|
categorization.setCategorizationRule(CategorizationRule.TIMESTAMP_BETWEEN);
|
||||||
|
categorization.setTimestampGreaterThan(greaterThan);
|
||||||
|
categorization.setTimestampLessThan(lessThan);
|
||||||
|
|
||||||
|
return new CategorizationBuilder(categorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CategorizationBuilder and(Categorization left, Categorization right) {
|
||||||
|
var categorization = new Categorization();
|
||||||
|
|
||||||
|
categorization.setCategorizationRule(CategorizationRule.AND);
|
||||||
|
categorization.setLeftCategorizationId(left.getId());
|
||||||
|
categorization.setRightCategorizationId(right.getId());
|
||||||
|
|
||||||
|
return new CategorizationBuilder(categorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CategorizationBuilder or(Categorization left, Categorization right) {
|
||||||
|
var categorization = new Categorization();
|
||||||
|
|
||||||
|
categorization.setCategorizationRule(CategorizationRule.OR);
|
||||||
|
categorization.setLeftCategorizationId(left.getId());
|
||||||
|
categorization.setRightCategorizationId(right.getId());
|
||||||
|
|
||||||
|
return new CategorizationBuilder(categorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CategorizationBuilder not(Categorization right) {
|
||||||
|
var categorization = new Categorization();
|
||||||
|
|
||||||
|
categorization.setCategorizationRule(CategorizationRule.NOT);
|
||||||
|
categorization.setRightCategorizationId(right.getId());
|
||||||
|
|
||||||
|
return new CategorizationBuilder(categorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CategorizationBuilder user(int userId) {
|
||||||
|
categorization.setUserId(userId);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CategorizationBuilder category(long categoryId) {
|
||||||
|
categorization.setCategoryId(categoryId);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CategorizationBuilder on(ProcessedTransactionField field, CategorizationRule rule, boolean booleanValue) {
|
||||||
|
categorization.setRuleBasedOn(field);
|
||||||
|
categorization.setCategorizationRule(rule);
|
||||||
|
categorization.setBooleanValue(booleanValue);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CategorizationBuilder on(ProcessedTransactionField field, CategorizationRule rule, double numericValue) {
|
||||||
|
categorization.setRuleBasedOn(field);
|
||||||
|
categorization.setCategorizationRule(rule);
|
||||||
|
categorization.setNumericValue(numericValue);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CategorizationBuilder on(ProcessedTransactionField field, CategorizationRule rule, String stringValue) {
|
||||||
|
categorization.setRuleBasedOn(field);
|
||||||
|
categorization.setCategorizationRule(rule);
|
||||||
|
categorization.setStringValue(stringValue);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CategorizationBuilder between(ProcessedTransactionField field, double greaterThan, double lessThan) {
|
||||||
|
categorization.setRuleBasedOn(field);
|
||||||
|
categorization.setCategorizationRule(CategorizationRule.NUMERIC_BETWEEN);
|
||||||
|
categorization.setNumericGreaterThan(greaterThan);
|
||||||
|
categorization.setNumericLessThan(lessThan);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CategorizationBuilder between(ProcessedTransactionField field, LocalDateTime greaterThan, LocalDateTime lessThan) {
|
||||||
|
categorization.setRuleBasedOn(field);
|
||||||
|
categorization.setCategorizationRule(CategorizationRule.TIMESTAMP_BETWEEN);
|
||||||
|
categorization.setTimestampGreaterThan(greaterThan);
|
||||||
|
categorization.setTimestampLessThan(lessThan);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Categorization build(boolean isRoot) {
|
||||||
|
categorization.setId(RandomUtils.nextLong());
|
||||||
|
categorization.setRoot(isRoot);
|
||||||
|
|
||||||
|
return categorization;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Categorization build() {
|
||||||
|
categorization.setId(RandomUtils.nextLong());
|
||||||
|
categorization.setRoot(false);
|
||||||
|
|
||||||
|
return categorization;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package dev.mvvasilev.finances;
|
||||||
|
|
||||||
|
import dev.mvvasilev.finances.persistence.CategorizationRepository;
|
||||||
|
import dev.mvvasilev.finances.persistence.ProcessedTransactionCategoryRepository;
|
||||||
|
import dev.mvvasilev.finances.persistence.ProcessedTransactionRepository;
|
||||||
|
import dev.mvvasilev.finances.persistence.TransactionCategoryRepository;
|
||||||
|
import dev.mvvasilev.finances.services.CategoryService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
public class CategoryServiceTests {
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private TransactionCategoryRepository transactionCategoryRepository;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private CategorizationRepository categorizationRepository;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private ProcessedTransactionRepository processedTransactionRepository;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private ProcessedTransactionCategoryRepository processedTransactionCategoryRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CategoryService service;
|
||||||
|
|
||||||
|
public CategoryServiceTests() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package dev.mvvasilev.finances.services;
|
||||||
|
|
||||||
|
import dev.mvvasilev.finances.CategorizationBuilder;
|
||||||
|
import dev.mvvasilev.finances.persistence.CategorizationRepository;
|
||||||
|
import dev.mvvasilev.finances.persistence.ProcessedTransactionCategoryRepository;
|
||||||
|
import dev.mvvasilev.finances.persistence.ProcessedTransactionRepository;
|
||||||
|
import dev.mvvasilev.finances.persistence.TransactionCategoryRepository;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
@SpringBootTest
|
||||||
|
class CategoryServiceTest {
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private TransactionCategoryRepository transactionCategoryRepository;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private CategorizationRepository categorizationRepository;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private ProcessedTransactionRepository processedTransactionRepository;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private ProcessedTransactionCategoryRepository processedTransactionCategoryRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CategoryService service;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void matchesRule() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue