diff --git a/build.gradle b/build.gradle index 4f189b0..93018a4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,9 @@ plugins { id 'java' id "org.jetbrains.intellij" version "0.2.13" + id 'info.solidsoft.pitest' version '1.3.0' + id 'jacoco' } - group 'io.github.vcuswimlab' version '0.2.2' @@ -47,4 +48,8 @@ dependencies { compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.8.2' compile group: 'org.jasypt', name: 'jasypt', version: '1.9.2' testCompile group: 'org.mockito', name: 'mockito-core', version: '2.8.8' + +} +pitest{ + threads = 4 } \ No newline at end of file diff --git a/src/main/java/io/github/vcuswimlab/stackintheflow/controller/info/TfIdf.java b/src/main/java/io/github/vcuswimlab/stackintheflow/controller/info/TfIdf.java index 7865d4b..cfce9b5 100644 --- a/src/main/java/io/github/vcuswimlab/stackintheflow/controller/info/TfIdf.java +++ b/src/main/java/io/github/vcuswimlab/stackintheflow/controller/info/TfIdf.java @@ -16,7 +16,7 @@ public static Map getTermFrequencies(String document, Pattern p Matcher matcher = pattern.matcher(document); while(matcher.find()) { - String term = matcher.group(1); + String term = matcher.group(0); termFrequencies.put(term, termFrequencies.getOrDefault(term, 0) + 1); } diff --git a/src/main/java/io/github/vcuswimlab/stackintheflow/model/personalsearch/PersonalSearchModel.java b/src/main/java/io/github/vcuswimlab/stackintheflow/model/personalsearch/PersonalSearchModel.java index a4f86a5..368a83f 100644 --- a/src/main/java/io/github/vcuswimlab/stackintheflow/model/personalsearch/PersonalSearchModel.java +++ b/src/main/java/io/github/vcuswimlab/stackintheflow/model/personalsearch/PersonalSearchModel.java @@ -46,11 +46,11 @@ public List rankQuestionList(List initialList) { } private void generateWeightedRank(List initialList) { - Collections.sort(initialList, (a, b) -> Double.compare(calculateRawScore(b.question), calculateRawScore(a.question))); + initialList.sort((a, b) -> Double.compare(calculateRawScore(b.question), calculateRawScore(a.question))); } private void generateFinalRank(List weightedList) { - Collections.sort(weightedList, Comparator.comparingDouble(QuestionRank::getAverageRank)); + weightedList.sort(Comparator.comparingDouble(QuestionRank::getAverageRank)); } private double calculateRawScore(Question question) { @@ -64,12 +64,10 @@ private double calculateRawScore(Question question) { // If this is a tag the user has clicked on if (userStatMap.containsKey(tag)) { - Optional statOptional = tagStatComponent.getTagStat(tag); // This tag is in the dump if (statOptional.isPresent()) { - double clickFrequency = userStatMap.containsKey(tag) ? 1 + Math.log10(userStatMap.get(tag)) : 0; score += statOptional.get().getIdf() * clickFrequency; } @@ -80,6 +78,10 @@ private double calculateRawScore(Question question) { } } + public Map getUserStatMap() { + return userStatMap; + } + private class QuestionRank { final int INITIAL_RANK; @@ -94,5 +96,6 @@ public QuestionRank(Question question, int INITIAL_RANK) { public double getAverageRank() { return (INITIAL_RANK + weightedRank) / 2; } + } } diff --git a/src/test/java/io/github/vcuswimlab/stackintheflow/controller/info/TfIdfTest.java b/src/test/java/io/github/vcuswimlab/stackintheflow/controller/info/TfIdfTest.java new file mode 100644 index 0000000..bc926e4 --- /dev/null +++ b/src/test/java/io/github/vcuswimlab/stackintheflow/controller/info/TfIdfTest.java @@ -0,0 +1,30 @@ +package io.github.vcuswimlab.stackintheflow.controller.info; + +import org.junit.Test; + +import java.util.Map; +import java.util.regex.Pattern; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class TfIdfTest { + + @Test + public void getTermFrequencies() { + String document = "asdf test asdf test\n rare"; + Pattern pattern = Pattern.compile("rare"); + Map termFrequencies = TfIdf.getTermFrequencies(document, pattern); + termFrequencies.forEach((term, count) -> System.out.println(term + ":\t" + count)); + assertEquals(java.util.Optional.of(1).get(), termFrequencies.get("rare")); + } + + @Test + public void getInverseDocumentFrequency() { + String term = "rare"; + String[] documents = {"asdf asdf asdf fdsa test", "rare", "another test document", "test2", "asdf test"}; + double idf = TfIdf.getInverseDocumentFrequency(term, documents); + System.out.println(idf); + assertTrue(idf > 0); + } +} \ No newline at end of file diff --git a/src/test/java/io/github/vcuswimlab/stackintheflow/controller/info/match/StringMatchUtilsTest.java b/src/test/java/io/github/vcuswimlab/stackintheflow/controller/info/match/StringMatchUtilsTest.java new file mode 100644 index 0000000..0700a1f --- /dev/null +++ b/src/test/java/io/github/vcuswimlab/stackintheflow/controller/info/match/StringMatchUtilsTest.java @@ -0,0 +1,37 @@ +package io.github.vcuswimlab.stackintheflow.controller.info.match; + +import org.junit.Test; + +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class StringMatchUtilsTest { + + @Test + public void removeComments() { + String singleLineCommentString = "test outside of commment // this is a single line comment\n"; + String multilineComment1 = "test outside of commment /* Multiline comment */"; + String multilineComment2 = "test outside of commment /** JavaDoc comment */"; + assertEquals(StringMatchUtils.removeComments(singleLineCommentString), "test outside of commment "); + assertEquals(StringMatchUtils.removeComments(multilineComment1), "test outside of commment "); + assertEquals(StringMatchUtils.removeComments(multilineComment2), "test outside of commment "); + } + + @Test + public void extractImports() { + String testString = "\n" + + "import java.util.regex.Matcher;\n" + + "import java.util.regex.Pattern;\n" + + "import java.util.Set;\n" + + "public class StringMatchUtils {\n" + + " public static final Pattern IMPORT_STATEMENT_PATTERN = Pattern.compile(\"import\\\\s+([\\\\w\\\\.]*?(\\\\w+));\");\n" + + " public static final Pattern TERM_PATTERN = Pattern.compile(\"\\\\b([A-Z]\\\\w+)\\\\b\");\n"; + Set imports = StringMatchUtils.extractImports(testString); + assertEquals(3, imports.size()); + assertTrue(imports.contains("java.util.regex.Matcher")); + assertTrue(imports.contains("java.util.regex.Pattern")); + assertTrue(imports.contains("java.util.Set")); + } +} \ No newline at end of file diff --git a/src/test/java/io/github/vcuswimlab/stackintheflow/model/personalsearch/PersonalSearchModelTest.java b/src/test/java/io/github/vcuswimlab/stackintheflow/model/personalsearch/PersonalSearchModelTest.java new file mode 100644 index 0000000..188a421 --- /dev/null +++ b/src/test/java/io/github/vcuswimlab/stackintheflow/model/personalsearch/PersonalSearchModelTest.java @@ -0,0 +1,79 @@ +package io.github.vcuswimlab.stackintheflow.model.personalsearch; + +import io.github.vcuswimlab.stackintheflow.controller.component.stat.Stat; +import io.github.vcuswimlab.stackintheflow.controller.component.stat.tags.TagStatComponent; +import io.github.vcuswimlab.stackintheflow.model.Question; +import org.junit.Before; +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class PersonalSearchModelTest { + private TagStatComponent tagStatComponent; + + Map userStateMap = new HashMap<>(); + private PersonalSearchModel searchModel; + + @Before + public void setup() { + tagStatComponent = mock(TagStatComponent.class); + when(tagStatComponent.getTagStat("test")).thenReturn(Optional.of(new Stat(42, 42, 42.42, 42.42))); + this.searchModel = new PersonalSearchModel(tagStatComponent, userStateMap); + } + + @Test + public void increaseTags() { + this.searchModel.increaseTags(Collections.singletonList("test")); + assertTrue(this.searchModel.getUserStatMap().containsKey("test")); + assertEquals(this.searchModel.getUserStatMap().size(), 1); + } + + @Test + public void increaseTagsUsermapNewKey() { + this.searchModel.increaseTags(Collections.singletonList("test"), 42); + assertTrue(this.searchModel.getUserStatMap().containsKey("test")); + assertEquals(this.searchModel.getUserStatMap().get("test"), Optional.of(42).get()); + } + + @Test + public void increaseTagsUsermapHasKey() { + this.searchModel.increaseTags(Collections.singletonList("test")); + this.searchModel.increaseTags(Collections.singletonList("test"), 42); + assertTrue(this.searchModel.getUserStatMap().containsKey("test")); + assertEquals(this.searchModel.getUserStatMap().get("test"), Optional.of(43).get()); + } + + @Test + public void rankQuestionList() { + List questions = new ArrayList<>(); +// questions.add(new Question(null, null, null, null, null)); + questions.add(new Question(Arrays.asList("test", "test1", "test3"), "test", "test", "test", "test")); + questions.add(new Question(Collections.emptyList(), "test2", "test2", "test2", "test2")); + questions.add(new Question(Arrays.asList("", "test"), "test1", "test2", "test3", "test3")); + + + List ranked = this.searchModel.rankQuestionList(questions); + assertEquals("test", ranked.get(0).getTitle()); + assertEquals("test2", ranked.get(1).getTitle()); + assertEquals("test3", ranked.get(2).getTitle()); + } + + @Test + public void rankQuestionListUserStatMapPreexisting() { + List questions = new ArrayList<>(); +// questions.add(new Question()); + questions.add(new Question(Arrays.asList("test", "test1", "test3"), "test", "test", "test", "test")); + questions.add(new Question(Collections.emptyList(), "test2", "test2", "test2", "test2")); + questions.add(new Question(Arrays.asList("", "test"), "test1", "test2", "test3", "test3")); + this.searchModel.increaseTags(Collections.singletonList("test")); + + List ranked = this.searchModel.rankQuestionList(questions); + assertEquals("test", ranked.get(0).getTitle()); + assertEquals("test3", ranked.get(1).getTitle()); + assertEquals("test2", ranked.get(2).getTitle()); + } +} \ No newline at end of file