Compare commits
	
		
			4 commits
		
	
	
		
			2022111466
			...
			master
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 35d68d884e | |||
| 3f6c19ed28 | |||
| 338d172893 | |||
| 828cec3f1e | 
					 7 changed files with 1294 additions and 639 deletions
				
			
		| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
  // Apply the application plugin to add support for building a CLI application in Java.
 | 
					  // Apply the application plugin to add support for building a CLI application in Java.
 | 
				
			||||||
  application
 | 
					  application
 | 
				
			||||||
 | 
					  checkstyle
 | 
				
			||||||
  id("com.gradleup.shadow") version "9.0.0-beta12"
 | 
					  id("com.gradleup.shadow") version "9.0.0-beta12"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +17,13 @@ repositories {
 | 
				
			||||||
  mavenCentral()
 | 
					  mavenCentral()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sourceSets { main { java { srcDirs("src/main/java") } } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					checkstyle {
 | 
				
			||||||
 | 
					  toolVersion = "10.12.4"
 | 
				
			||||||
 | 
					  configFile = file("./checkstyle.xml")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
  // Use JUnit Jupiter for testing.
 | 
					  // Use JUnit Jupiter for testing.
 | 
				
			||||||
  testImplementation(libs.junit.jupiter)
 | 
					  testImplementation(libs.junit.jupiter)
 | 
				
			||||||
| 
						 | 
					@ -26,6 +34,10 @@ dependencies {
 | 
				
			||||||
  implementation(libs.guava)
 | 
					  implementation(libs.guava)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  implementation("org.jline:jline:3.29.0")
 | 
					  implementation("org.jline:jline:3.29.0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  compileOnly("com.github.spotbugs:spotbugs-annotations:3.1.3")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  testImplementation("org.mockito:mockito-core:5.+")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Apply a specific Java toolchain to ease working on different environments.
 | 
					// Apply a specific Java toolchain to ease working on different environments.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										447
									
								
								app/checkstyle.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										447
									
								
								app/checkstyle.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,447 @@
 | 
				
			||||||
 | 
					<?xml version="1.0"?>
 | 
				
			||||||
 | 
					<!DOCTYPE module PUBLIC
 | 
				
			||||||
 | 
					          "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
 | 
				
			||||||
 | 
					          "https://checkstyle.org/dtds/configuration_1_3.dtd">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!--
 | 
				
			||||||
 | 
					    Checkstyle configuration that checks the Google coding conventions from Google Java Style
 | 
				
			||||||
 | 
					    that can be found at https://google.github.io/styleguide/javaguide.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Checkstyle is very configurable. Be sure to read the documentation at
 | 
				
			||||||
 | 
					    http://checkstyle.org (or in your downloaded distribution).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    To completely disable a check, just comment it out or delete it from the file.
 | 
				
			||||||
 | 
					    To suppress certain violations please review suppression filters.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Authors: Max Vetrenko, Mauryan Kansara, Ruslan Diachenko, Roman Ivanov.
 | 
				
			||||||
 | 
					 -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<module name="Checker">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <property name="charset" value="UTF-8"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <property name="severity" value="${org.checkstyle.google.severity}" default="warning"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <property name="fileExtensions" value="java, properties, xml"/>
 | 
				
			||||||
 | 
					  <!-- Excludes all 'module-info.java' files              -->
 | 
				
			||||||
 | 
					  <!-- See https://checkstyle.org/filefilters/index.html -->
 | 
				
			||||||
 | 
					  <!-- <module name="BeforeExecutionExclusionFileFilter"> -->
 | 
				
			||||||
 | 
					    <!-- <property name="fileNamePattern" value=""/> -->
 | 
				
			||||||
 | 
					  <!-- </module> -->
 | 
				
			||||||
 | 
					  <module name="SuppressWarningsFilter"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <!-- https://checkstyle.org/filters/suppressionfilter.html -->
 | 
				
			||||||
 | 
					  <module name="SuppressionFilter">
 | 
				
			||||||
 | 
					    <property name="file" value="${org.checkstyle.google.suppressionfilter.config}"
 | 
				
			||||||
 | 
					           default="checkstyle-suppressions.xml" />
 | 
				
			||||||
 | 
					    <property name="optional" value="true"/>
 | 
				
			||||||
 | 
					  </module>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <!-- https://checkstyle.org/filters/suppresswithnearbytextfilter.html -->
 | 
				
			||||||
 | 
					  <module name="SuppressWithNearbyTextFilter">
 | 
				
			||||||
 | 
					    <property name="nearbyTextPattern"
 | 
				
			||||||
 | 
					              value="CHECKSTYLE.SUPPRESS\: (\w+) for ([+-]\d+) lines"/>
 | 
				
			||||||
 | 
					    <property name="checkPattern" value="$1"/>
 | 
				
			||||||
 | 
					    <property name="lineRange" value="$2"/>
 | 
				
			||||||
 | 
					  </module>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <!-- Checks for whitespace                               -->
 | 
				
			||||||
 | 
					  <!-- See http://checkstyle.org/checks/whitespace/index.html -->
 | 
				
			||||||
 | 
					  <module name="FileTabCharacter">
 | 
				
			||||||
 | 
					    <property name="eachLine" value="true"/>
 | 
				
			||||||
 | 
					  </module>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <module name="LineLength">
 | 
				
			||||||
 | 
					    <property name="fileExtensions" value="java"/>
 | 
				
			||||||
 | 
					    <property name="max" value="100"/>
 | 
				
			||||||
 | 
					    <property name="ignorePattern"
 | 
				
			||||||
 | 
					             value="^package.*|^import.*|href\s*=\s*"[^"]*"|http://|https://|ftp://"/>
 | 
				
			||||||
 | 
					  </module>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <module name="TreeWalker">
 | 
				
			||||||
 | 
					    <module name="OuterTypeFilename"/>
 | 
				
			||||||
 | 
					    <module name="IllegalTokenText">
 | 
				
			||||||
 | 
					      <property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
 | 
				
			||||||
 | 
					      <property name="format"
 | 
				
			||||||
 | 
					               value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
 | 
				
			||||||
 | 
					      <property name="message"
 | 
				
			||||||
 | 
					               value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="AvoidEscapedUnicodeCharacters">
 | 
				
			||||||
 | 
					      <property name="allowEscapesForControlCharacters" value="true"/>
 | 
				
			||||||
 | 
					      <property name="allowByTailComment" value="true"/>
 | 
				
			||||||
 | 
					      <property name="allowNonPrintableEscapes" value="true"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="AvoidStarImport"/>
 | 
				
			||||||
 | 
					    <module name="OneTopLevelClass"/>
 | 
				
			||||||
 | 
					    <module name="NoLineWrap">
 | 
				
			||||||
 | 
					      <property name="tokens" value="PACKAGE_DEF, IMPORT, STATIC_IMPORT"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="NeedBraces">
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					               value="LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_IF, LITERAL_WHILE"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="LeftCurly">
 | 
				
			||||||
 | 
					      <property name="id" value="LeftCurlyEol"/>
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					                value="ANNOTATION_DEF, CLASS_DEF, CTOR_DEF, ENUM_CONSTANT_DEF, ENUM_DEF,
 | 
				
			||||||
 | 
					                    INTERFACE_DEF, LAMBDA, LITERAL_CATCH,
 | 
				
			||||||
 | 
					                    LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF,
 | 
				
			||||||
 | 
					                    LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, METHOD_DEF,
 | 
				
			||||||
 | 
					                    OBJBLOCK, STATIC_INIT, RECORD_DEF, COMPACT_CTOR_DEF"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="LeftCurly">
 | 
				
			||||||
 | 
					      <property name="id" value="LeftCurlyNl"/>
 | 
				
			||||||
 | 
					      <property name="option" value="nl"/>
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					                value="LITERAL_CASE, LITERAL_DEFAULT"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SuppressionXpathSingleFilter">
 | 
				
			||||||
 | 
					      <!-- LITERAL_CASE, LITERAL_DEFAULT are reused in SWITCH_RULE  -->
 | 
				
			||||||
 | 
					      <property name="id" value="LeftCurlyNl"/>
 | 
				
			||||||
 | 
					      <property name="query" value="//SWITCH_RULE/SLIST"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="RightCurly">
 | 
				
			||||||
 | 
					      <property name="id" value="RightCurlySame"/>
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					                value="LITERAL_TRY, LITERAL_CATCH, LITERAL_IF, LITERAL_ELSE,
 | 
				
			||||||
 | 
					                    LITERAL_DO"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SuppressionXpathSingleFilter">
 | 
				
			||||||
 | 
					      <property name="id" value="RightCurlySame"/>
 | 
				
			||||||
 | 
					      <property name="query" value="//RCURLY[parent::SLIST[parent::LITERAL_CATCH
 | 
				
			||||||
 | 
					                               and not(parent::LITERAL_CATCH/following-sibling::*)]]"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="RightCurly">
 | 
				
			||||||
 | 
					      <property name="id" value="RightCurlyAlone"/>
 | 
				
			||||||
 | 
					      <property name="option" value="alone"/>
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					               value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
 | 
				
			||||||
 | 
					                    INSTANCE_INIT, ANNOTATION_DEF, ENUM_DEF, INTERFACE_DEF, RECORD_DEF,
 | 
				
			||||||
 | 
					                    COMPACT_CTOR_DEF, LITERAL_SWITCH, LITERAL_CASE, LITERAL_FINALLY,
 | 
				
			||||||
 | 
					                    LITERAL_CATCH"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SuppressionXpathSingleFilter">
 | 
				
			||||||
 | 
					      <!-- suppression is required till https://github.com/checkstyle/checkstyle/issues/7541 -->
 | 
				
			||||||
 | 
					      <property name="id" value="RightCurlyAlone"/>
 | 
				
			||||||
 | 
					      <property name="query" value="//RCURLY[parent::SLIST[count(./*)=1
 | 
				
			||||||
 | 
					                               and not(parent::LITERAL_CATCH)]
 | 
				
			||||||
 | 
					                               or (preceding-sibling::*[last()][self::LCURLY]
 | 
				
			||||||
 | 
					                               and not(parent::SLIST/parent::LITERAL_CATCH))
 | 
				
			||||||
 | 
					                               or (parent::SLIST/parent::LITERAL_CATCH
 | 
				
			||||||
 | 
					                               and parent::SLIST/parent::LITERAL_CATCH/following-sibling::*)]"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="WhitespaceAfter">
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					               value="COMMA, SEMI, TYPECAST, LITERAL_IF, LITERAL_ELSE, LITERAL_RETURN,
 | 
				
			||||||
 | 
					                    LITERAL_WHILE, LITERAL_DO, LITERAL_FOR, LITERAL_FINALLY, DO_WHILE, ELLIPSIS,
 | 
				
			||||||
 | 
					                    LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_CATCH, LAMBDA,
 | 
				
			||||||
 | 
					                    LITERAL_YIELD, LITERAL_CASE, LITERAL_WHEN"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="WhitespaceAround">
 | 
				
			||||||
 | 
					      <property name="allowEmptyConstructors" value="true"/>
 | 
				
			||||||
 | 
					      <property name="allowEmptyLambdas" value="true"/>
 | 
				
			||||||
 | 
					      <property name="allowEmptyMethods" value="true"/>
 | 
				
			||||||
 | 
					      <property name="allowEmptyTypes" value="true"/>
 | 
				
			||||||
 | 
					      <property name="allowEmptyLoops" value="true"/>
 | 
				
			||||||
 | 
					      <property name="allowEmptySwitchBlockStatements" value="true"/>
 | 
				
			||||||
 | 
					      <property name="ignoreEnhancedForColon" value="false"/>
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					               value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR,
 | 
				
			||||||
 | 
					                    BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, DO_WHILE, EQUAL, GE, GT, LAMBDA, LAND,
 | 
				
			||||||
 | 
					                    LCURLY, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY,
 | 
				
			||||||
 | 
					                    LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, LITERAL_SWITCH, LITERAL_SYNCHRONIZED,
 | 
				
			||||||
 | 
					                    LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN,
 | 
				
			||||||
 | 
					                    NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, RCURLY, SL, SLIST, SL_ASSIGN, SR,
 | 
				
			||||||
 | 
					                    SR_ASSIGN, STAR, STAR_ASSIGN, LITERAL_ASSERT,
 | 
				
			||||||
 | 
					                    TYPE_EXTENSION_AND, LITERAL_WHEN"/>
 | 
				
			||||||
 | 
					      <message key="ws.notFollowed"
 | 
				
			||||||
 | 
					              value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks
 | 
				
			||||||
 | 
					               may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
 | 
				
			||||||
 | 
					      <message key="ws.notPreceded"
 | 
				
			||||||
 | 
					              value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SuppressionXpathSingleFilter">
 | 
				
			||||||
 | 
					      <property name="checks" value="WhitespaceAround"/>
 | 
				
			||||||
 | 
					      <property name="query" value="//*[self::LITERAL_IF or self::LITERAL_ELSE or
 | 
				
			||||||
 | 
					                                 self::STATIC_INIT]/SLIST[count(./*)=1]
 | 
				
			||||||
 | 
					                                 | //*[self::STATIC_INIT or self::LITERAL_TRY or self::LITERAL_IF]
 | 
				
			||||||
 | 
					                                 //*[self::RCURLY][parent::SLIST[count(./*)=1]]
 | 
				
			||||||
 | 
					                                 | //SLIST[count(./*)=1][parent::LITERAL_TRY and
 | 
				
			||||||
 | 
					                                 not(following-sibling::*)]
 | 
				
			||||||
 | 
					                                 | //SLIST[count(./*)=1][parent::LITERAL_CATCH and
 | 
				
			||||||
 | 
					                                 not(parent::LITERAL_CATCH/following-sibling::*)]"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="RegexpSinglelineJava">
 | 
				
			||||||
 | 
					      <property name="format" value="\{[ ]+\}"/>
 | 
				
			||||||
 | 
					      <property name="message" value="Empty blocks should have no spaces. Empty blocks
 | 
				
			||||||
 | 
					                                   may only be represented as '{}' when not part of a
 | 
				
			||||||
 | 
					                                   multi-block statement (4.1.3)"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="OneStatementPerLine"/>
 | 
				
			||||||
 | 
					    <module name="MultipleVariableDeclarations"/>
 | 
				
			||||||
 | 
					    <module name="ArrayTypeStyle"/>
 | 
				
			||||||
 | 
					    <module name="MissingSwitchDefault"/>
 | 
				
			||||||
 | 
					    <module name="FallThrough"/>
 | 
				
			||||||
 | 
					    <module name="UpperEll"/>
 | 
				
			||||||
 | 
					    <module name="ModifierOrder"/>
 | 
				
			||||||
 | 
					    <module name="EmptyLineSeparator">
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					               value="PACKAGE_DEF, IMPORT, STATIC_IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
 | 
				
			||||||
 | 
					                    STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF, VARIABLE_DEF, RECORD_DEF,
 | 
				
			||||||
 | 
					                    COMPACT_CTOR_DEF"/>
 | 
				
			||||||
 | 
					      <property name="allowNoEmptyLineBetweenFields" value="true"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SeparatorWrap">
 | 
				
			||||||
 | 
					      <property name="id" value="SeparatorWrapDot"/>
 | 
				
			||||||
 | 
					      <property name="tokens" value="DOT"/>
 | 
				
			||||||
 | 
					      <property name="option" value="nl"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SeparatorWrap">
 | 
				
			||||||
 | 
					      <property name="id" value="SeparatorWrapComma"/>
 | 
				
			||||||
 | 
					      <property name="tokens" value="COMMA"/>
 | 
				
			||||||
 | 
					      <property name="option" value="EOL"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SeparatorWrap">
 | 
				
			||||||
 | 
					      <!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/259 -->
 | 
				
			||||||
 | 
					      <property name="id" value="SeparatorWrapEllipsis"/>
 | 
				
			||||||
 | 
					      <property name="tokens" value="ELLIPSIS"/>
 | 
				
			||||||
 | 
					      <property name="option" value="EOL"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SeparatorWrap">
 | 
				
			||||||
 | 
					      <!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/258 -->
 | 
				
			||||||
 | 
					      <property name="id" value="SeparatorWrapArrayDeclarator"/>
 | 
				
			||||||
 | 
					      <property name="tokens" value="ARRAY_DECLARATOR"/>
 | 
				
			||||||
 | 
					      <property name="option" value="EOL"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SeparatorWrap">
 | 
				
			||||||
 | 
					      <property name="id" value="SeparatorWrapMethodRef"/>
 | 
				
			||||||
 | 
					      <property name="tokens" value="METHOD_REF"/>
 | 
				
			||||||
 | 
					      <property name="option" value="nl"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="PackageName">
 | 
				
			||||||
 | 
					      <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					             value="Package name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="TypeName">
 | 
				
			||||||
 | 
					      <property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
 | 
				
			||||||
 | 
					                    ANNOTATION_DEF, RECORD_DEF"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					             value="Type name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="MemberName">
 | 
				
			||||||
 | 
					      <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					             value="Member name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="ParameterName">
 | 
				
			||||||
 | 
					      <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					             value="Parameter name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="LambdaParameterName">
 | 
				
			||||||
 | 
					      <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					             value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="CatchParameterName">
 | 
				
			||||||
 | 
					      <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					             value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="LocalVariableName">
 | 
				
			||||||
 | 
					      <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					             value="Local variable name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="PatternVariableName">
 | 
				
			||||||
 | 
					      <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					             value="Pattern variable name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="ClassTypeParameterName">
 | 
				
			||||||
 | 
					      <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					             value="Class type name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="RecordComponentName">
 | 
				
			||||||
 | 
					      <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					               value="Record component name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="RecordTypeParameterName">
 | 
				
			||||||
 | 
					      <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					               value="Record type name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="MethodTypeParameterName">
 | 
				
			||||||
 | 
					      <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					             value="Method type name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="InterfaceTypeParameterName">
 | 
				
			||||||
 | 
					      <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					             value="Interface type name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="NoFinalizer"/>
 | 
				
			||||||
 | 
					    <module name="GenericWhitespace">
 | 
				
			||||||
 | 
					      <message key="ws.followed"
 | 
				
			||||||
 | 
					             value="GenericWhitespace ''{0}'' is followed by whitespace."/>
 | 
				
			||||||
 | 
					      <message key="ws.preceded"
 | 
				
			||||||
 | 
					             value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
 | 
				
			||||||
 | 
					      <message key="ws.illegalFollow"
 | 
				
			||||||
 | 
					             value="GenericWhitespace ''{0}'' should followed by whitespace."/>
 | 
				
			||||||
 | 
					      <message key="ws.notPreceded"
 | 
				
			||||||
 | 
					             value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="Indentation">
 | 
				
			||||||
 | 
					      <property name="basicOffset" value="2"/>
 | 
				
			||||||
 | 
					      <property name="braceAdjustment" value="2"/>
 | 
				
			||||||
 | 
					      <property name="caseIndent" value="2"/>
 | 
				
			||||||
 | 
					      <property name="throwsIndent" value="4"/>
 | 
				
			||||||
 | 
					      <property name="lineWrappingIndentation" value="4"/>
 | 
				
			||||||
 | 
					      <property name="arrayInitIndent" value="2"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <module name="AbbreviationAsWordInName">
 | 
				
			||||||
 | 
					      <property name="ignoreFinal" value="false"/>
 | 
				
			||||||
 | 
					      <property name="allowedAbbreviationLength" value="0"/>
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					               value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF,
 | 
				
			||||||
 | 
					                    PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF, PATTERN_VARIABLE_DEF, RECORD_DEF,
 | 
				
			||||||
 | 
					                    RECORD_COMPONENT_DEF"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="NoWhitespaceBeforeCaseDefaultColon"/>
 | 
				
			||||||
 | 
					    <module name="OverloadMethodsDeclarationOrder"/>
 | 
				
			||||||
 | 
					    <module name="ConstructorsDeclarationGrouping"/>
 | 
				
			||||||
 | 
					    <module name="VariableDeclarationUsageDistance"/>
 | 
				
			||||||
 | 
					    <module name="CustomImportOrder">
 | 
				
			||||||
 | 
					      <property name="sortImportsInGroupAlphabetically" value="true"/>
 | 
				
			||||||
 | 
					      <property name="separateLineBetweenGroups" value="true"/>
 | 
				
			||||||
 | 
					      <property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/>
 | 
				
			||||||
 | 
					      <property name="tokens" value="IMPORT, STATIC_IMPORT, PACKAGE_DEF"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="MethodParamPad">
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					               value="CTOR_DEF, LITERAL_NEW, METHOD_CALL, METHOD_DEF, CTOR_CALL,
 | 
				
			||||||
 | 
					                    SUPER_CTOR_CALL, ENUM_CONSTANT_DEF, RECORD_DEF, RECORD_PATTERN_DEF"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="NoWhitespaceBefore">
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					               value="COMMA, SEMI, POST_INC, POST_DEC, DOT,
 | 
				
			||||||
 | 
					                    LABELED_STAT, METHOD_REF"/>
 | 
				
			||||||
 | 
					      <property name="allowLineBreaks" value="true"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="ParenPad">
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					               value="ANNOTATION, ANNOTATION_FIELD_DEF, CTOR_CALL, CTOR_DEF, DOT, ENUM_CONSTANT_DEF,
 | 
				
			||||||
 | 
					                    EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW,
 | 
				
			||||||
 | 
					                    LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_CALL,
 | 
				
			||||||
 | 
					                    METHOD_DEF, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA,
 | 
				
			||||||
 | 
					                    RECORD_DEF, RECORD_PATTERN_DEF"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="OperatorWrap">
 | 
				
			||||||
 | 
					      <property name="option" value="NL"/>
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					               value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR,
 | 
				
			||||||
 | 
					                    LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF,
 | 
				
			||||||
 | 
					                    TYPE_EXTENSION_AND "/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="AnnotationLocation">
 | 
				
			||||||
 | 
					      <property name="id" value="AnnotationLocationMostCases"/>
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					               value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF,
 | 
				
			||||||
 | 
					                      RECORD_DEF, COMPACT_CTOR_DEF"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="AnnotationLocation">
 | 
				
			||||||
 | 
					      <property name="id" value="AnnotationLocationVariables"/>
 | 
				
			||||||
 | 
					      <property name="tokens" value="VARIABLE_DEF"/>
 | 
				
			||||||
 | 
					      <property name="allowSamelineMultipleAnnotations" value="true"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="NonEmptyAtclauseDescription"/>
 | 
				
			||||||
 | 
					    <module name="InvalidJavadocPosition"/>
 | 
				
			||||||
 | 
					    <module name="JavadocTagContinuationIndentation"/>
 | 
				
			||||||
 | 
					    <module name="SummaryJavadoc">
 | 
				
			||||||
 | 
					      <property name="forbiddenSummaryFragments"
 | 
				
			||||||
 | 
					               value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="JavadocParagraph">
 | 
				
			||||||
 | 
					      <property name="allowNewlineParagraph" value="false"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="RequireEmptyLineBeforeBlockTagGroup"/>
 | 
				
			||||||
 | 
					    <module name="AtclauseOrder">
 | 
				
			||||||
 | 
					      <property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
 | 
				
			||||||
 | 
					      <property name="target"
 | 
				
			||||||
 | 
					               value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="JavadocMethod">
 | 
				
			||||||
 | 
					      <property name="accessModifiers" value="public"/>
 | 
				
			||||||
 | 
					      <property name="allowMissingParamTags" value="true"/>
 | 
				
			||||||
 | 
					      <property name="allowMissingReturnTag" value="true"/>
 | 
				
			||||||
 | 
					      <property name="allowedAnnotations" value="Override, Test"/>
 | 
				
			||||||
 | 
					      <property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF, COMPACT_CTOR_DEF"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="MissingJavadocMethod">
 | 
				
			||||||
 | 
					      <property name="scope" value="protected"/>
 | 
				
			||||||
 | 
					      <property name="allowMissingPropertyJavadoc" value="true"/>
 | 
				
			||||||
 | 
					      <property name="allowedAnnotations" value="Override, Test"/>
 | 
				
			||||||
 | 
					      <property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF,
 | 
				
			||||||
 | 
					                                   COMPACT_CTOR_DEF"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SuppressionXpathSingleFilter">
 | 
				
			||||||
 | 
					      <property name="checks" value="MissingJavadocMethod"/>
 | 
				
			||||||
 | 
					      <property name="query" value="//*[self::METHOD_DEF or self::CTOR_DEF
 | 
				
			||||||
 | 
					                                 or self::ANNOTATION_FIELD_DEF or self::COMPACT_CTOR_DEF]
 | 
				
			||||||
 | 
					                                 [ancestor::*[self::INTERFACE_DEF or self::CLASS_DEF
 | 
				
			||||||
 | 
					                                 or self::RECORD_DEF or self::ENUM_DEF]
 | 
				
			||||||
 | 
					                                 [not(./MODIFIERS/LITERAL_PUBLIC)]]"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="MissingJavadocType">
 | 
				
			||||||
 | 
					      <property name="scope" value="protected"/>
 | 
				
			||||||
 | 
					      <property name="tokens"
 | 
				
			||||||
 | 
					                value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
 | 
				
			||||||
 | 
					                      RECORD_DEF, ANNOTATION_DEF"/>
 | 
				
			||||||
 | 
					      <property name="excludeScope" value="nothing"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="MethodName">
 | 
				
			||||||
 | 
					      <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
 | 
				
			||||||
 | 
					      <message key="name.invalidPattern"
 | 
				
			||||||
 | 
					             value="Method name ''{0}'' must match pattern ''{1}''."/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SuppressionXpathSingleFilter">
 | 
				
			||||||
 | 
					      <property name="checks" value="MethodName"/>
 | 
				
			||||||
 | 
					      <property name="query" value="//METHOD_DEF[
 | 
				
			||||||
 | 
					                                     ./MODIFIERS/ANNOTATION//IDENT[contains(@text, 'Test')]
 | 
				
			||||||
 | 
					                                   ]/IDENT"/>
 | 
				
			||||||
 | 
					      <property name="message" value="'[a-z][a-z0-9][a-zA-Z0-9]*(?:_[a-z][a-z0-9][a-zA-Z0-9]*)*'"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SingleLineJavadoc"/>
 | 
				
			||||||
 | 
					    <module name="EmptyCatchBlock">
 | 
				
			||||||
 | 
					      <property name="exceptionVariableName" value="expected"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="CommentsIndentation">
 | 
				
			||||||
 | 
					      <property name="tokens" value="SINGLE_LINE_COMMENT, BLOCK_COMMENT_BEGIN"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <!-- https://checkstyle.org/filters/suppressionxpathfilter.html -->
 | 
				
			||||||
 | 
					    <module name="SuppressionXpathFilter">
 | 
				
			||||||
 | 
					      <property name="file" value="${org.checkstyle.google.suppressionxpathfilter.config}"
 | 
				
			||||||
 | 
					             default="checkstyle-xpath-suppressions.xml" />
 | 
				
			||||||
 | 
					      <property name="optional" value="true"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SuppressWarningsHolder" />
 | 
				
			||||||
 | 
					    <module name="SuppressionCommentFilter">
 | 
				
			||||||
 | 
					      <property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)" />
 | 
				
			||||||
 | 
					      <property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)" />
 | 
				
			||||||
 | 
					      <property name="checkFormat" value="$1" />
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					    <module name="SuppressWithNearbyCommentFilter">
 | 
				
			||||||
 | 
					      <property name="commentFormat" value="CHECKSTYLE.SUPPRESS\: ([\w\|]+)"/>
 | 
				
			||||||
 | 
					      <!-- $1 refers to the first match group in the regex defined in commentFormat -->
 | 
				
			||||||
 | 
					      <property name="checkFormat" value="$1"/>
 | 
				
			||||||
 | 
					      <!-- The check is suppressed in the next line of code after the comment -->
 | 
				
			||||||
 | 
					      <property name="influenceFormat" value="1"/>
 | 
				
			||||||
 | 
					    </module>
 | 
				
			||||||
 | 
					  </module>
 | 
				
			||||||
 | 
					</module>
 | 
				
			||||||
| 
						 | 
					@ -12,64 +12,44 @@ import java.util.PriorityQueue;
 | 
				
			||||||
import java.util.Random;
 | 
					import java.util.Random;
 | 
				
			||||||
import java.util.function.Function;
 | 
					import java.util.function.Function;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Core class for impl graph.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
public class Graph {
 | 
					public class Graph {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public record EdgeRecord(String node1, String node2, int weight) {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private static class Node {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        String id;
 | 
					 | 
				
			||||||
        Map<Node, Integer> edges;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Node(final String id) {
 | 
					 | 
				
			||||||
            this.id = id;
 | 
					 | 
				
			||||||
            this.edges = new HashMap<>();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        void addEdge(final Node target) {
 | 
					 | 
				
			||||||
            edges.put(target, edges.getOrDefault(target, 0) + 1);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        List<String> getDOTEdges(final Function<EdgeRecord, String> callback) {
 | 
					 | 
				
			||||||
            final var dotEdges = new ArrayList<String>();
 | 
					 | 
				
			||||||
            for (final var entry : edges.entrySet()) {
 | 
					 | 
				
			||||||
                final Node target = entry.getKey();
 | 
					 | 
				
			||||||
                final int weight = entry.getValue();
 | 
					 | 
				
			||||||
                dotEdges.add(
 | 
					 | 
				
			||||||
                        callback.apply(new EdgeRecord(id, target.id, weight)) + ";\n");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return dotEdges;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        List<String> getDOTEdges() {
 | 
					 | 
				
			||||||
            final var dotEdges = new ArrayList<String>();
 | 
					 | 
				
			||||||
            for (final var entry : edges.entrySet()) {
 | 
					 | 
				
			||||||
                final Node target = entry.getKey();
 | 
					 | 
				
			||||||
                final int weight = entry.getValue();
 | 
					 | 
				
			||||||
                dotEdges.add(
 | 
					 | 
				
			||||||
                        String.format("%s -> %s [label=\"%d\"];\n", id, target.id, weight));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return dotEdges;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private final Map<String, Node> nodes;
 | 
					  private final Map<String, Node> nodes;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  private Map<Node, Double> pageRanks;
 | 
					  private Map<Node, Double> pageRanks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Initial func of Graph.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param input input text
 | 
				
			||||||
 | 
					   * @param d     d of page rank
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
  public Graph(final String input, final double d) {
 | 
					  public Graph(final String input, final double d) {
 | 
				
			||||||
    nodes = new HashMap<>();
 | 
					    nodes = new HashMap<>();
 | 
				
			||||||
    parse(input);
 | 
					    parse(input);
 | 
				
			||||||
    initRageRanks(d);
 | 
					    initRageRanks(d);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Initial func of Graph with default d.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param input input text
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
  public Graph(final String input) {
 | 
					  public Graph(final String input) {
 | 
				
			||||||
    nodes = new HashMap<>();
 | 
					    nodes = new HashMap<>();
 | 
				
			||||||
    parse(input);
 | 
					    parse(input);
 | 
				
			||||||
    initRageRanks(0.85);
 | 
					    initRageRanks(0.85);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Find bridge words.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param word1 first word
 | 
				
			||||||
 | 
					   * @param word2 second word
 | 
				
			||||||
 | 
					   * @return list of bridge words
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
  public Optional<List<String>> findBridgeWords(final String word1, final String word2) {
 | 
					  public Optional<List<String>> findBridgeWords(final String word1, final String word2) {
 | 
				
			||||||
    final Node node1 = nodes.get(word1.toLowerCase(Locale.ENGLISH));
 | 
					    final Node node1 = nodes.get(word1.toLowerCase(Locale.ENGLISH));
 | 
				
			||||||
    final Node node2 = nodes.get(word2.toLowerCase(Locale.ENGLISH));
 | 
					    final Node node2 = nodes.get(word2.toLowerCase(Locale.ENGLISH));
 | 
				
			||||||
| 
						 | 
					@ -87,6 +67,13 @@ public class Graph {
 | 
				
			||||||
    return Optional.of(bridgeWords);
 | 
					    return Optional.of(bridgeWords);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Find the shortest path between two words.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param word1 first word
 | 
				
			||||||
 | 
					   * @param word2 second word
 | 
				
			||||||
 | 
					   * @return list of the words in the path
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
  public Optional<List<String>> findShortestPath(final String word1, final String word2) {
 | 
					  public Optional<List<String>> findShortestPath(final String word1, final String word2) {
 | 
				
			||||||
    final var startWord = word1.toLowerCase(Locale.ENGLISH);
 | 
					    final var startWord = word1.toLowerCase(Locale.ENGLISH);
 | 
				
			||||||
    final var endWord = word2.toLowerCase(Locale.ENGLISH);
 | 
					    final var endWord = word2.toLowerCase(Locale.ENGLISH);
 | 
				
			||||||
| 
						 | 
					@ -144,6 +131,12 @@ public class Graph {
 | 
				
			||||||
    return Optional.of(reversePath);
 | 
					    return Optional.of(reversePath);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Calculate rage rank.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param nodeId id of node
 | 
				
			||||||
 | 
					   * @return page rank
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
  public double computePageRank(final String nodeId) {
 | 
					  public double computePageRank(final String nodeId) {
 | 
				
			||||||
    final Node node = nodes.get(nodeId);
 | 
					    final Node node = nodes.get(nodeId);
 | 
				
			||||||
    if (node == null) {
 | 
					    if (node == null) {
 | 
				
			||||||
| 
						 | 
					@ -153,6 +146,12 @@ public class Graph {
 | 
				
			||||||
    return pageRanks.getOrDefault(node, -1.0);
 | 
					    return pageRanks.getOrDefault(node, -1.0);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Random walk.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @return list of words in the walk path
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("PREDICTABLE_RANDOM")
 | 
				
			||||||
  public List<String> randomWalk() {
 | 
					  public List<String> randomWalk() {
 | 
				
			||||||
    final var path = new ArrayList<String>();
 | 
					    final var path = new ArrayList<String>();
 | 
				
			||||||
    if (nodes.isEmpty()) {
 | 
					    if (nodes.isEmpty()) {
 | 
				
			||||||
| 
						 | 
					@ -207,6 +206,13 @@ public class Graph {
 | 
				
			||||||
    return path;
 | 
					    return path;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Generate DOT lang to describe the graph.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param callback function to modify the option of the node
 | 
				
			||||||
 | 
					   * @return string of DOT lang
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  @SuppressWarnings("checkstyle:AbbreviationAsWordInName")
 | 
				
			||||||
  public String toDOT(final Function<EdgeRecord, String> callback) {
 | 
					  public String toDOT(final Function<EdgeRecord, String> callback) {
 | 
				
			||||||
    final var sb = new StringBuilder();
 | 
					    final var sb = new StringBuilder();
 | 
				
			||||||
    sb.append("digraph G {\n");
 | 
					    sb.append("digraph G {\n");
 | 
				
			||||||
| 
						 | 
					@ -219,6 +225,12 @@ public class Graph {
 | 
				
			||||||
    return sb.toString();
 | 
					    return sb.toString();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Generate DOT lang to describe the graph without callback lambda function.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @return string of DOT lang
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  @SuppressWarnings("checkstyle:AbbreviationAsWordInName")
 | 
				
			||||||
  public String toDOT() {
 | 
					  public String toDOT() {
 | 
				
			||||||
    final var sb = new StringBuilder();
 | 
					    final var sb = new StringBuilder();
 | 
				
			||||||
    sb.append("digraph G {\n");
 | 
					    sb.append("digraph G {\n");
 | 
				
			||||||
| 
						 | 
					@ -291,10 +303,62 @@ public class Graph {
 | 
				
			||||||
    pageRanks = myPageRanks;
 | 
					    pageRanks = myPageRanks;
 | 
				
			||||||
    for (final var node : nodes.values()) {
 | 
					    for (final var node : nodes.values()) {
 | 
				
			||||||
      if (node.edges.isEmpty()) {
 | 
					      if (node.edges.isEmpty()) {
 | 
				
			||||||
                nodes.values().stream().filter(n -> !n.equals(node))
 | 
					        nodes.values().stream()
 | 
				
			||||||
                        .forEach(n -> pageRanks.put(n, pageRanks.get(n) + pageRanks.get(node) / (totalNodes - 1)));
 | 
					                .filter(n -> !n.equals(node))
 | 
				
			||||||
 | 
					                .forEach(n -> pageRanks
 | 
				
			||||||
 | 
					                        .put(n, pageRanks.get(n) + pageRanks.get(node) / (totalNodes - 1)));
 | 
				
			||||||
        pageRanks.put(node, 0.0);
 | 
					        pageRanks.put(node, 0.0);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Record of edge.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param node1 fist node
 | 
				
			||||||
 | 
					   * @param node2 second node
 | 
				
			||||||
 | 
					   * @param weight weight of edge
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public record EdgeRecord(String node1, String node2, int weight) {
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private static class Node {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    String id;
 | 
				
			||||||
 | 
					    Map<Node, Integer> edges;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Node(final String id) {
 | 
				
			||||||
 | 
					      this.id = id;
 | 
				
			||||||
 | 
					      this.edges = new HashMap<>();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void addEdge(final Node target) {
 | 
				
			||||||
 | 
					      edges.put(target, edges.getOrDefault(target, 0) + 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @SuppressWarnings("checkstyle:AbbreviationAsWordInName")
 | 
				
			||||||
 | 
					    List<String> getDOTEdges(final Function<EdgeRecord, String> callback) {
 | 
				
			||||||
 | 
					      final var dotEdges = new ArrayList<String>();
 | 
				
			||||||
 | 
					      for (final var entry : edges.entrySet()) {
 | 
				
			||||||
 | 
					        final Node target = entry.getKey();
 | 
				
			||||||
 | 
					        final int weight = entry.getValue();
 | 
				
			||||||
 | 
					        dotEdges.add(
 | 
				
			||||||
 | 
					                callback.apply(new EdgeRecord(id, target.id, weight)) + ";\n");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return dotEdges;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @SuppressWarnings("checkstyle:AbbreviationAsWordInName")
 | 
				
			||||||
 | 
					    List<String> getDOTEdges() {
 | 
				
			||||||
 | 
					      final var dotEdges = new ArrayList<String>();
 | 
				
			||||||
 | 
					      for (final var entry : edges.entrySet()) {
 | 
				
			||||||
 | 
					        final Node target = entry.getKey();
 | 
				
			||||||
 | 
					        final int weight = entry.getValue();
 | 
				
			||||||
 | 
					        dotEdges.add(
 | 
				
			||||||
 | 
					                String.format("%s -> %s [label=\"%d\"];%n", id, target.id, weight));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return dotEdges;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,6 @@ package fun.youthlic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.BufferedReader;
 | 
					import java.io.BufferedReader;
 | 
				
			||||||
import java.io.BufferedWriter;
 | 
					import java.io.BufferedWriter;
 | 
				
			||||||
import java.io.File;
 | 
					 | 
				
			||||||
import java.io.FileReader;
 | 
					import java.io.FileReader;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.io.InputStreamReader;
 | 
					import java.io.InputStreamReader;
 | 
				
			||||||
| 
						 | 
					@ -15,17 +14,20 @@ import java.util.Arrays;
 | 
				
			||||||
import java.util.Random;
 | 
					import java.util.Random;
 | 
				
			||||||
import java.util.stream.Collectors;
 | 
					import java.util.stream.Collectors;
 | 
				
			||||||
import java.util.stream.IntStream;
 | 
					import java.util.stream.IntStream;
 | 
				
			||||||
 | 
					 | 
				
			||||||
import org.jline.reader.LineReader;
 | 
					import org.jline.reader.LineReader;
 | 
				
			||||||
import org.jline.reader.LineReaderBuilder;
 | 
					import org.jline.reader.LineReaderBuilder;
 | 
				
			||||||
import org.jline.reader.impl.DefaultParser;
 | 
					import org.jline.reader.impl.DefaultParser;
 | 
				
			||||||
import org.jline.terminal.Terminal;
 | 
					import org.jline.terminal.Terminal;
 | 
				
			||||||
import org.jline.terminal.TerminalBuilder;
 | 
					import org.jline.terminal.TerminalBuilder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class for running in Commandline.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@SuppressWarnings("ALL")
 | 
				
			||||||
public class GraphCLI {
 | 
					public class GraphCLI {
 | 
				
			||||||
  static String readFile(final String filename) {
 | 
					  static String readFile(final String filename) {
 | 
				
			||||||
    String text = null;
 | 
					    String text = null;
 | 
				
			||||||
        try (BufferedReader inputReader = new BufferedReader(new FileReader(new File(filename)))) {
 | 
					    try (BufferedReader inputReader = new BufferedReader(new FileReader(filename))) {
 | 
				
			||||||
      text = inputReader.lines().collect(Collectors.joining(System.lineSeparator()));
 | 
					      text = inputReader.lines().collect(Collectors.joining(System.lineSeparator()));
 | 
				
			||||||
    } catch (final IOException e) {
 | 
					    } catch (final IOException e) {
 | 
				
			||||||
      System.out.println("Error reading file: " + e.getMessage());
 | 
					      System.out.println("Error reading file: " + e.getMessage());
 | 
				
			||||||
| 
						 | 
					@ -33,6 +35,11 @@ public class GraphCLI {
 | 
				
			||||||
    return text;
 | 
					    return text;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * CommandLine entry point.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param args launch args
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
  public static void main(final String[] args) {
 | 
					  public static void main(final String[] args) {
 | 
				
			||||||
    GraphCLIHelper helper = null;
 | 
					    GraphCLIHelper helper = null;
 | 
				
			||||||
    Terminal terminal = null;
 | 
					    Terminal terminal = null;
 | 
				
			||||||
| 
						 | 
					@ -42,7 +49,8 @@ public class GraphCLI {
 | 
				
			||||||
      e.printStackTrace();
 | 
					      e.printStackTrace();
 | 
				
			||||||
      System.exit(-1);
 | 
					      System.exit(-1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        final LineReader reader = LineReaderBuilder.builder().terminal(terminal).parser(new DefaultParser())
 | 
					    final LineReader reader = LineReaderBuilder.builder().terminal(terminal)
 | 
				
			||||||
 | 
					        .parser(new DefaultParser())
 | 
				
			||||||
        .build();
 | 
					        .build();
 | 
				
			||||||
    while (true) {
 | 
					    while (true) {
 | 
				
			||||||
      final String line = reader.readLine("graph> ");
 | 
					      final String line = reader.readLine("graph> ");
 | 
				
			||||||
| 
						 | 
					@ -135,6 +143,7 @@ public class GraphCLI {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            System.out.println(helper.graph.toDOT());
 | 
					            System.out.println(helper.graph.toDOT());
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
        case "page-rank":
 | 
					        case "page-rank":
 | 
				
			||||||
          if (commands.length != 2) {
 | 
					          if (commands.length != 2) {
 | 
				
			||||||
            System.out.println("Usage: page-rank <word>");
 | 
					            System.out.println("Usage: page-rank <word>");
 | 
				
			||||||
| 
						 | 
					@ -166,6 +175,10 @@ public class GraphCLI {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Helper class for CommandLine.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@SuppressWarnings("ALL")
 | 
				
			||||||
class GraphCLIHelper {
 | 
					class GraphCLIHelper {
 | 
				
			||||||
  Graph graph;
 | 
					  Graph graph;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -173,19 +186,20 @@ class GraphCLIHelper {
 | 
				
			||||||
    graph = new Graph(text);
 | 
					    graph = new Graph(text);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static void showDirectedGraph(final Graph G) {
 | 
					  static void showDirectedGraph(final Graph graph) {
 | 
				
			||||||
    final ProcessBuilder processBuilder = new ProcessBuilder("graph-easy", "--as", "ascii");
 | 
					    final ProcessBuilder processBuilder = new ProcessBuilder("graph-easy", "--as", "ascii");
 | 
				
			||||||
    processBuilder.redirectErrorStream(true);
 | 
					    processBuilder.redirectErrorStream(true);
 | 
				
			||||||
        Process process = null;
 | 
					    Process process;
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      process = processBuilder.start();
 | 
					      process = processBuilder.start();
 | 
				
			||||||
    } catch (final IOException e) {
 | 
					    } catch (final IOException e) {
 | 
				
			||||||
      System.err.println("Failed to start process");
 | 
					      System.err.println("Failed to start process");
 | 
				
			||||||
      e.printStackTrace();
 | 
					      e.printStackTrace();
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    try (BufferedWriter writer = new BufferedWriter(
 | 
					    try (BufferedWriter writer = new BufferedWriter(
 | 
				
			||||||
        new OutputStreamWriter(process.getOutputStream(), StandardCharsets.UTF_8))) {
 | 
					        new OutputStreamWriter(process.getOutputStream(), StandardCharsets.UTF_8))) {
 | 
				
			||||||
            writer.write(G.toDOT());
 | 
					      writer.write(graph.toDOT());
 | 
				
			||||||
      writer.flush();
 | 
					      writer.flush();
 | 
				
			||||||
    } catch (final IOException e) {
 | 
					    } catch (final IOException e) {
 | 
				
			||||||
      System.err.println("Failed to write to process");
 | 
					      System.err.println("Failed to write to process");
 | 
				
			||||||
| 
						 | 
					@ -263,17 +277,11 @@ class GraphCLIHelper {
 | 
				
			||||||
    final ProcessBuilder processBuilder = new ProcessBuilder("graph-easy", "--as", "ascii");
 | 
					    final ProcessBuilder processBuilder = new ProcessBuilder("graph-easy", "--as", "ascii");
 | 
				
			||||||
    processBuilder.redirectErrorStream(true);
 | 
					    processBuilder.redirectErrorStream(true);
 | 
				
			||||||
    Process process = null;
 | 
					    Process process = null;
 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
    process = processBuilder.start();
 | 
					    process = processBuilder.start();
 | 
				
			||||||
        } catch (final IOException e) {
 | 
					 | 
				
			||||||
            throw e;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    try (BufferedWriter writer = new BufferedWriter(
 | 
					    try (BufferedWriter writer = new BufferedWriter(
 | 
				
			||||||
        new OutputStreamWriter(process.getOutputStream(), StandardCharsets.UTF_8))) {
 | 
					        new OutputStreamWriter(process.getOutputStream(), StandardCharsets.UTF_8))) {
 | 
				
			||||||
      writer.write(calcShortestPathToDOT(word1, word2));
 | 
					      writer.write(calcShortestPathToDOT(word1, word2));
 | 
				
			||||||
      writer.flush();
 | 
					      writer.flush();
 | 
				
			||||||
        } catch (final IOException e) {
 | 
					 | 
				
			||||||
            throw e;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    final StringBuilder output = new StringBuilder();
 | 
					    final StringBuilder output = new StringBuilder();
 | 
				
			||||||
    try (BufferedReader reader = new BufferedReader(
 | 
					    try (BufferedReader reader = new BufferedReader(
 | 
				
			||||||
| 
						 | 
					@ -282,8 +290,6 @@ class GraphCLIHelper {
 | 
				
			||||||
      while ((line = reader.readLine()) != null) {
 | 
					      while ((line = reader.readLine()) != null) {
 | 
				
			||||||
        output.append(line).append(System.lineSeparator());
 | 
					        output.append(line).append(System.lineSeparator());
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
        } catch (final IOException e) {
 | 
					 | 
				
			||||||
            throw e;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      final int exitCode = process.waitFor();
 | 
					      final int exitCode = process.waitFor();
 | 
				
			||||||
| 
						 | 
					@ -311,8 +317,8 @@ class GraphCLIHelper {
 | 
				
			||||||
        r.node1() + (path.contains(r.node1()) ? "~" : ""),
 | 
					        r.node1() + (path.contains(r.node1()) ? "~" : ""),
 | 
				
			||||||
        r.node2() + (path.contains(r.node2()) ? "~" : ""),
 | 
					        r.node2() + (path.contains(r.node2()) ? "~" : ""),
 | 
				
			||||||
        r.weight(),
 | 
					        r.weight(),
 | 
				
			||||||
                    (path.contains(r.node1()) && path.contains(r.node2()) &&
 | 
					        (path.contains(r.node1()) && path.contains(r.node2())
 | 
				
			||||||
                            IntStream.range(0, path.size() - 1).anyMatch(
 | 
					          && IntStream.range(0, path.size() - 1).anyMatch(
 | 
				
			||||||
            i -> path.get(i).equals(r.node1()) && path.get(i + 1).equals(r.node2())))
 | 
					            i -> path.get(i).equals(r.node1()) && path.get(i + 1).equals(r.node2())))
 | 
				
			||||||
          ? ",color=\"red\""
 | 
					          ? ",color=\"red\""
 | 
				
			||||||
          : ""));
 | 
					          : ""));
 | 
				
			||||||
| 
						 | 
					@ -320,13 +326,12 @@ class GraphCLIHelper {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Double calPageRank(final String word) {
 | 
					  Double calPageRank(final String word) {
 | 
				
			||||||
        final var pageRank = graph.computePageRank(word);
 | 
					    return graph.computePageRank(word);
 | 
				
			||||||
        return pageRank;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  String randomWalk() {
 | 
					  String randomWalk() {
 | 
				
			||||||
        final var text = graph.randomWalk().stream().collect(Collectors.joining(" "));
 | 
					    final var text = String.join(" ", graph.randomWalk());
 | 
				
			||||||
        final Path path = Paths.get("output.txt");
 | 
					    final Path path = Paths.get(System.getProperty("user.dir"), "output.txt");
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      Files.write(path, text.getBytes());
 | 
					      Files.write(path, text.getBytes());
 | 
				
			||||||
    } catch (final IOException e) {
 | 
					    } catch (final IOException e) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										126
									
								
								app/src/test/java/fun/youthlic/GraphCLIHelperTest.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								app/src/test/java/fun/youthlic/GraphCLIHelperTest.java
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,126 @@
 | 
				
			||||||
 | 
					package fun.youthlic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.Test;
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.io.TempDir;
 | 
				
			||||||
 | 
					import org.mockito.MockedStatic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.ByteArrayOutputStream;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.PrintStream;
 | 
				
			||||||
 | 
					import java.nio.file.AccessDeniedException;
 | 
				
			||||||
 | 
					import java.nio.file.Files;
 | 
				
			||||||
 | 
					import java.nio.file.Path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static org.junit.jupiter.api.Assertions.*;
 | 
				
			||||||
 | 
					import static org.mockito.ArgumentMatchers.any;
 | 
				
			||||||
 | 
					import static org.mockito.Mockito.mockStatic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class GraphCLIHelperTest {
 | 
				
			||||||
 | 
					  private final GraphCLIHelper graph = new GraphCLIHelper("B D E H A C D H A F D H A B G H A C G H A D G H");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testWord1NotInGraph() {
 | 
				
			||||||
 | 
					    var result = graph.queryBridgeWords("x", "a");
 | 
				
			||||||
 | 
					    assertEquals("No x or a in the graph!", result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testWord2NotInGraph() {
 | 
				
			||||||
 | 
					    String result = graph.queryBridgeWords("a", "x");
 | 
				
			||||||
 | 
					    assertEquals("No a or x in the graph!", result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testBothWordsNotInGraph() {
 | 
				
			||||||
 | 
					    String result = graph.queryBridgeWords("x", "y");
 | 
				
			||||||
 | 
					    assertEquals("No x or y in the graph!", result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testNoBridgeWords() {
 | 
				
			||||||
 | 
					    String result = graph.queryBridgeWords("a", "b");
 | 
				
			||||||
 | 
					    assertEquals("No bridge words from a to b!", result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testSingleBridgeWord() {
 | 
				
			||||||
 | 
					    String result = graph.queryBridgeWords("b", "e");
 | 
				
			||||||
 | 
					    assertEquals("The bridge words from b to e are: d.", result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testTwoBridgeWords() {
 | 
				
			||||||
 | 
					    String result = graph.queryBridgeWords("c", "h");
 | 
				
			||||||
 | 
					    assertEquals("The bridge words from c to h are: g, and d.", result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testThreeBridgeWords() {
 | 
				
			||||||
 | 
					    String result = graph.queryBridgeWords("a", "g");
 | 
				
			||||||
 | 
					    assertEquals("The bridge words from a to g are: d, c, and b.", result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testSameWordInput() {
 | 
				
			||||||
 | 
					    String result = graph.queryBridgeWords("a", "a");
 | 
				
			||||||
 | 
					    assertEquals("No bridge words from a to a!", result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testWord1Empty() {
 | 
				
			||||||
 | 
					    String result = graph.queryBridgeWords("", "a");
 | 
				
			||||||
 | 
					    assertEquals("No  or a in the graph!", result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testWord2Empty() {
 | 
				
			||||||
 | 
					    String result = graph.queryBridgeWords("a", "");
 | 
				
			||||||
 | 
					    assertEquals("No a or  in the graph!", result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testBothWordsEmpty() {
 | 
				
			||||||
 | 
					    String result = graph.queryBridgeWords("", "");
 | 
				
			||||||
 | 
					    assertEquals("No  or  in the graph!", result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testCaseMismatch() {
 | 
				
			||||||
 | 
					    String result = graph.queryBridgeWords("B", "E");
 | 
				
			||||||
 | 
					    assertEquals("The bridge words from B to E are: d.", result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testNormalExecution(@TempDir Path tempDir) throws IOException {
 | 
				
			||||||
 | 
					    System.setProperty("user.dir", tempDir.toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    String result = graph.randomWalk();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assertNotNull(result);
 | 
				
			||||||
 | 
					    assertFalse(result.isEmpty());
 | 
				
			||||||
 | 
					    Path outputPath = tempDir.resolve("output.txt");
 | 
				
			||||||
 | 
					    System.out.println(outputPath);
 | 
				
			||||||
 | 
					    assertTrue(Files.exists(outputPath));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    String fileContent = Files.readString(outputPath);
 | 
				
			||||||
 | 
					    assertEquals(fileContent, result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  void testWritePermissionDenied() {
 | 
				
			||||||
 | 
					    try (MockedStatic<Files> mockedFiles = mockStatic(Files.class)) {
 | 
				
			||||||
 | 
					      mockedFiles.when(() -> Files.write(any(Path.class), any(byte[].class)))
 | 
				
			||||||
 | 
					              .thenThrow(new AccessDeniedException("Permission denied"));
 | 
				
			||||||
 | 
					      ByteArrayOutputStream errContent = new ByteArrayOutputStream();
 | 
				
			||||||
 | 
					      System.setErr(new PrintStream(errContent));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      String result = graph.randomWalk();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      assertNotNull(result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      String errorOutput = errContent.toString();
 | 
				
			||||||
 | 
					      assertTrue(errorOutput.contains("Failed to write to file"));
 | 
				
			||||||
 | 
					      assertTrue(errorOutput.contains("AccessDeniedException"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@
 | 
				
			||||||
            kotlin-language-server
 | 
					            kotlin-language-server
 | 
				
			||||||
            ktfmt
 | 
					            ktfmt
 | 
				
			||||||
            jdt-language-server
 | 
					            jdt-language-server
 | 
				
			||||||
 | 
					            checkstyle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            graph-easy
 | 
					            graph-easy
 | 
				
			||||||
            graphviz
 | 
					            graphviz
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue