Merge branch release/0.4.0 into master
Upgrade kemitix-parent to 2.0.0 Add ImmutableTree implementation Switch to static factory constructors
This commit is contained in:
commit
f4d1d6e689
26 changed files with 1157 additions and 1301 deletions
36
.gitignore
vendored
36
.gitignore
vendored
|
@ -1,10 +1,3 @@
|
|||
/target
|
||||
/nbproject
|
||||
*.class
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
|
@ -13,5 +6,30 @@
|
|||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
/.idea/libraries/
|
||||
/.idea/workspace.xml
|
||||
# maven build outputs
|
||||
target/
|
||||
|
||||
# netbeans legacy
|
||||
nbproject/
|
||||
nbactions.xml
|
||||
|
||||
# eclipse legacy
|
||||
.project
|
||||
|
||||
# intellij
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
# Spring
|
||||
spring.log
|
||||
logs/
|
||||
/application.properties
|
||||
/bootstrap.properties
|
||||
|
||||
# Composer-style
|
||||
vendor
|
||||
|
||||
# Git and temp files
|
||||
*.orig
|
||||
*.patch
|
||||
*~
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CheckStyle-IDEA">
|
||||
<option name="configuration">
|
||||
<map>
|
||||
<entry key="scan-before-checkin" value="false" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
|
@ -1,104 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectCodeStyleSettingsManager">
|
||||
<option name="PER_PROJECT_SETTINGS">
|
||||
<value>
|
||||
<option name="GENERATE_FINAL_LOCALS" value="true" />
|
||||
<option name="GENERATE_FINAL_PARAMETERS" value="true" />
|
||||
<option name="VISIBILITY" value="packageLocal" />
|
||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="9999" />
|
||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="9999" />
|
||||
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
|
||||
<value />
|
||||
</option>
|
||||
<option name="IMPORT_LAYOUT_TABLE">
|
||||
<value>
|
||||
<package name="" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="" withSubpackages="true" static="true" />
|
||||
<emptyLine />
|
||||
<package name="java" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="javax" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="org.springframework" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="uk.ac.fife" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="net.kemitix" withSubpackages="true" static="false" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="JD_ADD_BLANK_AFTER_PARM_COMMENTS" value="true" />
|
||||
<option name="JD_ADD_BLANK_AFTER_RETURN" value="true" />
|
||||
<option name="WRAP_COMMENTS" value="true" />
|
||||
<JavaCodeStyleSettings>
|
||||
<option name="ANNOTATION_PARAMETER_WRAP" value="1" />
|
||||
</JavaCodeStyleSettings>
|
||||
<XML>
|
||||
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
||||
</XML>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<option name="RIGHT_MARGIN" value="80" />
|
||||
<option name="KEEP_LINE_BREAKS" value="false" />
|
||||
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
|
||||
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
|
||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
|
||||
<option name="BLANK_LINES_AROUND_FIELD" value="1" />
|
||||
<option name="BLANK_LINES_AROUND_FIELD_IN_INTERFACE" value="1" />
|
||||
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
|
||||
<option name="INDENT_CASE_FROM_SWITCH" value="false" />
|
||||
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
|
||||
<option name="ALIGN_MULTILINE_THROWS_LIST" value="true" />
|
||||
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
|
||||
<option name="SPACE_BEFORE_ANNOTATION_ARRAY_INITIALIZER_LBRACE" value="true" />
|
||||
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="RESOURCE_LIST_WRAP" value="1" />
|
||||
<option name="EXTENDS_LIST_WRAP" value="1" />
|
||||
<option name="THROWS_LIST_WRAP" value="1" />
|
||||
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
|
||||
<option name="THROWS_KEYWORD_WRAP" value="1" />
|
||||
<option name="METHOD_CALL_CHAIN_WRAP" value="5" />
|
||||
<option name="BINARY_OPERATION_WRAP" value="1" />
|
||||
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
|
||||
<option name="TERNARY_OPERATION_WRAP" value="5" />
|
||||
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
|
||||
<option name="FOR_STATEMENT_WRAP" value="1" />
|
||||
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
|
||||
<option name="ASSIGNMENT_WRAP" value="1" />
|
||||
<option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
|
||||
<option name="ASSERT_STATEMENT_WRAP" value="1" />
|
||||
<option name="ASSERT_STATEMENT_COLON_ON_NEXT_LINE" value="true" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||
<option name="FOR_BRACE_FORCE" value="3" />
|
||||
<option name="WRAP_LONG_LINES" value="true" />
|
||||
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
|
||||
<option name="VARIABLE_ANNOTATION_WRAP" value="1" />
|
||||
<option name="ENUM_CONSTANTS_WRAP" value="1" />
|
||||
<arrangement>
|
||||
<groups>
|
||||
<group>
|
||||
<type>GETTERS_AND_SETTERS</type>
|
||||
<order>KEEP</order>
|
||||
</group>
|
||||
<group>
|
||||
<type>OVERRIDDEN_METHODS</type>
|
||||
<order>KEEP</order>
|
||||
</group>
|
||||
<group>
|
||||
<type>DEPENDENT_METHODS</type>
|
||||
<order>BREADTH_FIRST</order>
|
||||
</group>
|
||||
</groups>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</value>
|
||||
</option>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,33 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<option name="DEFAULT_COMPILER" value="Javac" />
|
||||
<resourceExtensions />
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="!?*.java" />
|
||||
<entry name="!?*.form" />
|
||||
<entry name="!?*.class" />
|
||||
<entry name="!?*.groovy" />
|
||||
<entry name="!?*.scala" />
|
||||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
<entry name="!?*.aj" />
|
||||
</wildcardResourcePatterns>
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
<processorPath useClasspath="true" />
|
||||
</profile>
|
||||
<profile default="false" name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<processorPath useClasspath="true" />
|
||||
<module name="node" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
<bytecodeTargetLevel>
|
||||
<module name="node" target="1.8" />
|
||||
</bytecodeTargetLevel>
|
||||
</component>
|
||||
</project>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$" charset="UTF-8" />
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,213 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="org.twodividedbyzero.idea.findbugs">
|
||||
<option name="annotationTypeSettings">
|
||||
<map>
|
||||
<entry key="ExpPriority" value="-4473925;-12828863;-8355712;WAVE_UNDERSCORE;0;" />
|
||||
<entry key="HighPriority" value="-39836;-12828863;-39836;WAVE_UNDERSCORE;1;" />
|
||||
<entry key="IgnorePriority" value="-4473925;-12828863;-11978414;WAVE_UNDERSCORE;0;" />
|
||||
<entry key="LowPriority" value="-4473925;-12828863;-10316203;BOXED;0;" />
|
||||
<entry key="NormalPriority" value="-4473925;-12828863;-10461184;WAVE_UNDERSCORE;2;" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="_basePreferences">
|
||||
<map>
|
||||
<entry key="property.analysisEffortLevel" value="default" />
|
||||
<entry key="property.analyzeAfterCompile" value="false" />
|
||||
<entry key="property.annotationGutterIconEnabled" value="true" />
|
||||
<entry key="property.annotationSuppressWarningsClass" value="edu.umd.cs.findbugs.annotations.SuppressWarnings" />
|
||||
<entry key="property.annotationTextRangeMarkupEnabled" value="true" />
|
||||
<entry key="property.exportAsHtml" value="true" />
|
||||
<entry key="property.exportAsXml" value="true" />
|
||||
<entry key="property.exportBaseDir" value="" />
|
||||
<entry key="property.exportCreateArchiveDir" value="false" />
|
||||
<entry key="property.exportOpenBrowser" value="true" />
|
||||
<entry key="property.minPriorityToReport" value="Medium" />
|
||||
<entry key="property.runAnalysisInBackground" value="false" />
|
||||
<entry key="property.showHiddenDetectors" value="false" />
|
||||
<entry key="property.toolWindowToFront" value="true" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="_detectors">
|
||||
<map>
|
||||
<entry key="AppendingToAnObjectOutputStream" value="true" />
|
||||
<entry key="AtomicityProblem" value="true" />
|
||||
<entry key="BadAppletConstructor" value="false" />
|
||||
<entry key="BadResultSetAccess" value="true" />
|
||||
<entry key="BadSyntaxForRegularExpression" value="true" />
|
||||
<entry key="BadUseOfReturnValue" value="true" />
|
||||
<entry key="BadlyOverriddenAdapter" value="true" />
|
||||
<entry key="BooleanReturnNull" value="true" />
|
||||
<entry key="BuildInterproceduralCallGraph" value="false" />
|
||||
<entry key="BuildObligationPolicyDatabase" value="true" />
|
||||
<entry key="CallToUnsupportedMethod" value="false" />
|
||||
<entry key="CalledMethods" value="true" />
|
||||
<entry key="CheckCalls" value="false" />
|
||||
<entry key="CheckExpectedWarnings" value="false" />
|
||||
<entry key="CheckImmutableAnnotation" value="true" />
|
||||
<entry key="CheckTypeQualifiers" value="true" />
|
||||
<entry key="CloneIdiom" value="true" />
|
||||
<entry key="ComparatorIdiom" value="true" />
|
||||
<entry key="ConfusedInheritance" value="true" />
|
||||
<entry key="ConfusionBetweenInheritedAndOuterMethod" value="true" />
|
||||
<entry key="CrossSiteScripting" value="true" />
|
||||
<entry key="DefaultEncodingDetector" value="true" />
|
||||
<entry key="DoInsideDoPrivileged" value="true" />
|
||||
<entry key="DontCatchIllegalMonitorStateException" value="true" />
|
||||
<entry key="DontIgnoreResultOfPutIfAbsent" value="true" />
|
||||
<entry key="DontUseEnum" value="true" />
|
||||
<entry key="DroppedException" value="true" />
|
||||
<entry key="DumbMethodInvocations" value="true" />
|
||||
<entry key="DumbMethods" value="true" />
|
||||
<entry key="DuplicateBranches" value="true" />
|
||||
<entry key="EmptyZipFileEntry" value="true" />
|
||||
<entry key="EqualsOperandShouldHaveClassCompatibleWithThis" value="true" />
|
||||
<entry key="ExplicitSerialization" value="true" />
|
||||
<entry key="FieldItemSummary" value="true" />
|
||||
<entry key="FinalizerNullsFields" value="true" />
|
||||
<entry key="FindBadCast2" value="true" />
|
||||
<entry key="FindBadForLoop" value="true" />
|
||||
<entry key="FindBugsSummaryStats" value="true" />
|
||||
<entry key="FindCircularDependencies" value="false" />
|
||||
<entry key="FindDeadLocalStores" value="true" />
|
||||
<entry key="FindDoubleCheck" value="true" />
|
||||
<entry key="FindEmptySynchronizedBlock" value="true" />
|
||||
<entry key="FindFieldSelfAssignment" value="true" />
|
||||
<entry key="FindFinalizeInvocations" value="true" />
|
||||
<entry key="FindFloatEquality" value="true" />
|
||||
<entry key="FindFloatMath" value="false" />
|
||||
<entry key="FindHEmismatch" value="true" />
|
||||
<entry key="FindInconsistentSync2" value="true" />
|
||||
<entry key="FindJSR166LockMonitorenter" value="true" />
|
||||
<entry key="FindLocalSelfAssignment2" value="true" />
|
||||
<entry key="FindMaskedFields" value="true" />
|
||||
<entry key="FindMismatchedWaitOrNotify" value="true" />
|
||||
<entry key="FindNakedNotify" value="true" />
|
||||
<entry key="FindNonSerializableStoreIntoSession" value="false" />
|
||||
<entry key="FindNonSerializableValuePassedToWriteObject" value="false" />
|
||||
<entry key="FindNonShortCircuit" value="true" />
|
||||
<entry key="FindNullDeref" value="true" />
|
||||
<entry key="FindNullDerefsInvolvingNonShortCircuitEvaluation" value="true" />
|
||||
<entry key="FindOpenStream" value="true" />
|
||||
<entry key="FindPuzzlers" value="true" />
|
||||
<entry key="FindRefComparison" value="true" />
|
||||
<entry key="FindReturnRef" value="true" />
|
||||
<entry key="FindRunInvocations" value="true" />
|
||||
<entry key="FindSelfComparison" value="true" />
|
||||
<entry key="FindSelfComparison2" value="true" />
|
||||
<entry key="FindSleepWithLockHeld" value="true" />
|
||||
<entry key="FindSpinLoop" value="true" />
|
||||
<entry key="FindSqlInjection" value="true" />
|
||||
<entry key="FindTwoLockWait" value="true" />
|
||||
<entry key="FindUncalledPrivateMethods" value="true" />
|
||||
<entry key="FindUnconditionalWait" value="true" />
|
||||
<entry key="FindUninitializedGet" value="true" />
|
||||
<entry key="FindUnrelatedTypesInGenericContainer" value="true" />
|
||||
<entry key="FindUnreleasedLock" value="true" />
|
||||
<entry key="FindUnsatisfiedObligation" value="true" />
|
||||
<entry key="FindUnsyncGet" value="true" />
|
||||
<entry key="FindUseOfNonSerializableValue" value="true" />
|
||||
<entry key="FindUselessControlFlow" value="true" />
|
||||
<entry key="FormatStringChecker" value="true" />
|
||||
<entry key="FunctionsThatMightBeMistakenForProcedures" value="true" />
|
||||
<entry key="HugeSharedStringConstants" value="true" />
|
||||
<entry key="IDivResultCastToDouble" value="true" />
|
||||
<entry key="IncompatMask" value="true" />
|
||||
<entry key="InconsistentAnnotations" value="true" />
|
||||
<entry key="InefficientMemberAccess" value="false" />
|
||||
<entry key="InefficientToArray" value="true" />
|
||||
<entry key="InfiniteLoop" value="true" />
|
||||
<entry key="InfiniteRecursiveLoop" value="true" />
|
||||
<entry key="InheritanceUnsafeGetResource" value="true" />
|
||||
<entry key="InitializationChain" value="true" />
|
||||
<entry key="InitializeNonnullFieldsInConstructor" value="true" />
|
||||
<entry key="InstantiateStaticClass" value="true" />
|
||||
<entry key="IntCast2LongAsInstant" value="true" />
|
||||
<entry key="InvalidJUnitTest" value="true" />
|
||||
<entry key="IteratorIdioms" value="true" />
|
||||
<entry key="LazyInit" value="true" />
|
||||
<entry key="LoadOfKnownNullValue" value="true" />
|
||||
<entry key="LostLoggerDueToWeakReference" value="true" />
|
||||
<entry key="MethodReturnCheck" value="true" />
|
||||
<entry key="Methods" value="true" />
|
||||
<entry key="MultithreadedInstanceAccess" value="true" />
|
||||
<entry key="MutableLock" value="true" />
|
||||
<entry key="MutableStaticFields" value="true" />
|
||||
<entry key="Naming" value="true" />
|
||||
<entry key="Noise" value="false" />
|
||||
<entry key="NoiseNullDeref" value="false" />
|
||||
<entry key="NoteAnnotationRetention" value="true" />
|
||||
<entry key="NoteCheckReturnValueAnnotations" value="true" />
|
||||
<entry key="NoteDirectlyRelevantTypeQualifiers" value="true" />
|
||||
<entry key="NoteJCIPAnnotation" value="true" />
|
||||
<entry key="NoteNonNullAnnotations" value="true" />
|
||||
<entry key="NoteNonnullReturnValues" value="true" />
|
||||
<entry key="NoteSuppressedWarnings" value="true" />
|
||||
<entry key="NoteUnconditionalParamDerefs" value="true" />
|
||||
<entry key="NumberConstructor" value="true" />
|
||||
<entry key="OverridingEqualsNotSymmetrical" value="true" />
|
||||
<entry key="PreferZeroLengthArrays" value="true" />
|
||||
<entry key="PublicSemaphores" value="false" />
|
||||
<entry key="QuestionableBooleanAssignment" value="true" />
|
||||
<entry key="ReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass" value="true" />
|
||||
<entry key="ReadReturnShouldBeChecked" value="true" />
|
||||
<entry key="RedundantInterfaces" value="true" />
|
||||
<entry key="ReflectiveClasses" value="true" />
|
||||
<entry key="RepeatedConditionals" value="true" />
|
||||
<entry key="ResolveAllReferences" value="false" />
|
||||
<entry key="RuntimeExceptionCapture" value="true" />
|
||||
<entry key="SerializableIdiom" value="true" />
|
||||
<entry key="StartInConstructor" value="true" />
|
||||
<entry key="StaticCalendarDetector" value="true" />
|
||||
<entry key="StringConcatenation" value="true" />
|
||||
<entry key="SuperfluousInstanceOf" value="true" />
|
||||
<entry key="SuspiciousThreadInterrupted" value="true" />
|
||||
<entry key="SwitchFallthrough" value="true" />
|
||||
<entry key="SynchronizationOnSharedBuiltinConstant" value="true" />
|
||||
<entry key="SynchronizeAndNullCheckField" value="true" />
|
||||
<entry key="SynchronizeOnClassLiteralNotGetClass" value="true" />
|
||||
<entry key="SynchronizingOnContentsOfFieldToProtectField" value="true" />
|
||||
<entry key="TestASM" value="false" />
|
||||
<entry key="TestDataflowAnalysis" value="false" />
|
||||
<entry key="TestingGround" value="false" />
|
||||
<entry key="TestingGround2" value="false" />
|
||||
<entry key="TrainFieldStoreTypes" value="true" />
|
||||
<entry key="TrainLongInstantfParams" value="true" />
|
||||
<entry key="TrainNonNullAnnotations" value="true" />
|
||||
<entry key="TrainUnconditionalDerefParams" value="true" />
|
||||
<entry key="URLProblems" value="true" />
|
||||
<entry key="UncallableMethodOfAnonymousClass" value="true" />
|
||||
<entry key="UnnecessaryMath" value="true" />
|
||||
<entry key="UnreadFields" value="true" />
|
||||
<entry key="UselessSubclassMethod" value="false" />
|
||||
<entry key="VarArgsProblems" value="true" />
|
||||
<entry key="VolatileUsage" value="true" />
|
||||
<entry key="WaitInLoop" value="true" />
|
||||
<entry key="WrongMapIterator" value="true" />
|
||||
<entry key="XMLFactoryBypass" value="true" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="_reportCategories">
|
||||
<map>
|
||||
<entry key="BAD_PRACTICE" value="true" />
|
||||
<entry key="CORRECTNESS" value="true" />
|
||||
<entry key="EXPERIMENTAL" value="true" />
|
||||
<entry key="I18N" value="true" />
|
||||
<entry key="MALICIOUS_CODE" value="true" />
|
||||
<entry key="MT_CORRECTNESS" value="true" />
|
||||
<entry key="PERFORMANCE" value="true" />
|
||||
<entry key="SECURITY" value="true" />
|
||||
<entry key="STYLE" value="true" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="_annotationTypeSettings">
|
||||
<map>
|
||||
<entry key="ExpPriority" value="-4473925;-12828863;-8355712;WAVE_UNDERSCORE;0;" />
|
||||
<entry key="HighPriority" value="-39836;-12828863;-39836;WAVE_UNDERSCORE;1;" />
|
||||
<entry key="IgnorePriority" value="-4473925;-12828863;-11978414;WAVE_UNDERSCORE;0;" />
|
||||
<entry key="LowPriority" value="-4473925;-12828863;-10316203;BOXED;0;" />
|
||||
<entry key="NormalPriority" value="-4473925;-12828863;-10461184;WAVE_UNDERSCORE;2;" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
|
@ -1,60 +0,0 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<option name="myLocal" value="true" />
|
||||
<inspection_tool class="AssertEqualsCalledOnArray" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AssertEqualsMayBeAssertSame" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AssertsWithoutMessages" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="BeforeClassOrAfterClassIsPublicStaticVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="BeforeOrAfterIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConstantJUnitAssertArgument" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ExpectedExceptionNeverThrown" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="FindBugsIDEA" enabled="true" level="SERVER PROBLEM" enabled_by_default="true" />
|
||||
<inspection_tool class="IgnoredJUnitTest" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="JUnit3MethodNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="JUnit3StyleTestMethodInJUnit4Class" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="JUnit4MethodNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="JUnitAbstractTestClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_regex" value="[A-Z][A-Za-z\d]*TestCase" />
|
||||
<option name="m_minLength" value="12" />
|
||||
<option name="m_maxLength" value="64" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="JUnitDatapoint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="JUnitRule" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="JUnitTestClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_regex" value="[A-Z][A-Za-z\d]*(Test|IT)" />
|
||||
<option name="m_minLength" value="8" />
|
||||
<option name="m_maxLength" value="64" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
|
||||
<option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="MigrateAssertToMatcherAssert" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="MisorderedAssertEqualsParameters" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="MisspelledSetUp" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="MisspelledTearDown" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="MultipleExceptionsDeclaredOnTestMethod" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ParameterizedParametersStaticCollection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SetupCallsSuperSetup" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SetupIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SimplifiableJUnitAssertion" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="StaticSuite" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SuperTearDownInFinally" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TeardownCallsSuperTeardown" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TeardownIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TestCaseInProductCode" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TestCaseWithConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TestCaseWithNoTestMethods" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreSupers" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="TestMethodInProductCode" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TestMethodIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TestMethodWithoutAssertion" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="assertionMethods" value="org.junit.Assert,assert.*|fail.*,junit.framework.Assert,assert.*|fail.*,org.mockito.Mockito,verify.*,org.mockito.InOrder,verify,org.junit.rules.ExpectedException,expect.*,org.hamcrest.MatcherAssert,assertThat,org.assertj.core.api.Assertions,assertThat,org.assertj.core.api.SoftAssertions,assertAll" />
|
||||
<option name="assertKeywordIsAssertion" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnconstructableTestCase" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UseOfObsoleteAssert" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
|
@ -1,7 +0,0 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="PROJECT_PROFILE" value="Project Default" />
|
||||
<option name="USE_PROJECT_PROFILE" value="true" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
|
@ -1,42 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
</component>
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||
<OptionsSetting value="true" id="Add" />
|
||||
<OptionsSetting value="true" id="Remove" />
|
||||
<OptionsSetting value="true" id="Checkout" />
|
||||
<OptionsSetting value="true" id="Update" />
|
||||
<OptionsSetting value="true" id="Status" />
|
||||
<OptionsSetting value="true" id="Edit" />
|
||||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/classes" />
|
||||
</component>
|
||||
<component name="masterDetails">
|
||||
<states>
|
||||
<state key="ProjectJDKs.UI">
|
||||
<settings>
|
||||
<last-edited>1.8</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
</states>
|
||||
</component>
|
||||
</project>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/node.iml" filepath="$PROJECT_DIR$/node.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,3 +1,5 @@
|
|||
language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
after_success:
|
||||
- mvn clean test jacoco:report coveralls:report
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.4.0
|
||||
------
|
||||
|
||||
* Upgrade kemitix-parent to 2.0.0
|
||||
* Add ImmutableTree implementation
|
||||
* Switch to static factory constructors
|
||||
|
||||
0.3.0
|
||||
------
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
[![Build Status](https://travis-ci.org/kemitix/node.svg?branch=develop)](https://travis-ci.org/kemitix/node)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/kemitix/node/badge.svg?branch=develop)](https://coveralls.io/github/kemitix/node?branch=develop)
|
||||
|
||||
# node
|
||||
|
||||
[![Join the chat at https://gitter.im/kemitix/node](https://badges.gitter.im/kemitix/node.svg)](https://gitter.im/kemitix/node?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
|
192
checkstyle.xml
192
checkstyle.xml
|
@ -1,192 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
|
||||
<!--
|
||||
|
||||
Checkstyle configuration that checks the sun coding conventions from:
|
||||
|
||||
- the Java Language Specification at
|
||||
http://java.sun.com/docs/books/jls/second_edition/html/index.html
|
||||
|
||||
- the Sun Code Conventions at http://java.sun.com/docs/codeconv/
|
||||
|
||||
- the Javadoc guidelines at
|
||||
http://java.sun.com/j2se/javadoc/writingdoccomments/index.html
|
||||
|
||||
- the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html
|
||||
|
||||
- some best practices
|
||||
|
||||
Checkstyle is very configurable. Be sure to read the documentation at
|
||||
http://checkstyle.sf.net (or in your downloaded distribution).
|
||||
|
||||
Most Checks are configurable, be sure to consult the documentation.
|
||||
|
||||
To completely disable a check, just comment it out or delete it from the file.
|
||||
|
||||
Finally, it is worth reading the documentation.
|
||||
|
||||
-->
|
||||
|
||||
<module name="Checker">
|
||||
<!--
|
||||
If you set the basedir property below, then all reported file
|
||||
names will be relative to the specified directory. See
|
||||
http://checkstyle.sourceforge.net/5.x/config.html#Checker
|
||||
|
||||
<property name="basedir" value="${basedir}"/>
|
||||
-->
|
||||
|
||||
<!-- Checks that a package-info.java file exists for each package. -->
|
||||
<!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage -->
|
||||
<module name="JavadocPackage"/>
|
||||
|
||||
<!-- Checks whether files end with a new line. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
|
||||
<module name="NewlineAtEndOfFile"/>
|
||||
|
||||
<!-- Checks that property files contain the same keys. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html#Translation -->
|
||||
<module name="Translation"/>
|
||||
|
||||
<!-- Checks for Size Violations. -->
|
||||
<!-- See http://checkstyle.sf.net/config_sizes.html -->
|
||||
<module name="FileLength"/>
|
||||
|
||||
<!-- Checks for whitespace -->
|
||||
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
|
||||
<module name="FileTabCharacter"/>
|
||||
|
||||
<!-- Miscellaneous other checks. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html -->
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="\s+$"/>
|
||||
<property name="minimum" value="0"/>
|
||||
<property name="maximum" value="0"/>
|
||||
<property name="message" value="Line has trailing spaces."/>
|
||||
</module>
|
||||
|
||||
|
||||
<!-- Checks for Headers -->
|
||||
<!-- See http://checkstyle.sf.net/config_header.html -->
|
||||
<!-- <module name="Header"> -->
|
||||
<!-- <property name="headerFile" value="${checkstyle.header.file}"/> -->
|
||||
<!-- <property name="fileExtensions" value="java"/> -->
|
||||
<!-- </module> -->
|
||||
|
||||
<module name="TreeWalker">
|
||||
|
||||
<!-- Support @SuppressWarnings annotation -->
|
||||
<!-- See http://checkstyle.sourceforge.net/config.html -->
|
||||
<module name="SuppressWarningsHolder"/>
|
||||
|
||||
<module name="FileContentsHolder"/>
|
||||
|
||||
<!-- Checks for Javadoc comments. -->
|
||||
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
|
||||
<module name="JavadocMethod">
|
||||
<property name="scope" value="public"/>
|
||||
</module>
|
||||
<module name="JavadocType"/>
|
||||
<!--<module name="JavadocVariable"/>-->
|
||||
<module name="JavadocStyle"/>
|
||||
|
||||
|
||||
<!-- Checks for Naming Conventions. -->
|
||||
<!-- See http://checkstyle.sf.net/config_naming.html -->
|
||||
<module name="ConstantName"/>
|
||||
<module name="LocalFinalVariableName"/>
|
||||
<module name="LocalVariableName"/>
|
||||
<module name="MemberName"/>
|
||||
<module name="MethodName"/>
|
||||
<module name="PackageName"/>
|
||||
<module name="ParameterName"/>
|
||||
<module name="StaticVariableName"/>
|
||||
<module name="TypeName"/>
|
||||
|
||||
|
||||
<!-- Checks for imports -->
|
||||
<!-- See http://checkstyle.sf.net/config_import.html -->
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
|
||||
<module name="RedundantImport"/>
|
||||
<module name="UnusedImports"/>
|
||||
|
||||
|
||||
<!-- Checks for Size Violations. -->
|
||||
<!-- See http://checkstyle.sf.net/config_sizes.html -->
|
||||
<module name="LineLength"/>
|
||||
<module name="MethodLength"/>
|
||||
<module name="ParameterNumber"/>
|
||||
|
||||
|
||||
<!-- Checks for whitespace -->
|
||||
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
|
||||
<module name="EmptyForIteratorPad"/>
|
||||
<module name="GenericWhitespace"/>
|
||||
<module name="MethodParamPad"/>
|
||||
<module name="NoWhitespaceAfter"/>
|
||||
<module name="NoWhitespaceBefore"/>
|
||||
<module name="OperatorWrap"/>
|
||||
<module name="ParenPad"/>
|
||||
<module name="TypecastParenPad"/>
|
||||
<module name="WhitespaceAfter"/>
|
||||
<module name="WhitespaceAround"/>
|
||||
|
||||
|
||||
<!-- Modifier Checks -->
|
||||
<!-- See http://checkstyle.sf.net/config_modifiers.html -->
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="RedundantModifier"/>
|
||||
|
||||
|
||||
<!-- Checks for blocks. You know, those {}'s -->
|
||||
<!-- See http://checkstyle.sf.net/config_blocks.html -->
|
||||
<module name="AvoidNestedBlocks"/>
|
||||
<module name="EmptyBlock"/>
|
||||
<module name="LeftCurly"/>
|
||||
<module name="NeedBraces"/>
|
||||
<module name="RightCurly"/>
|
||||
|
||||
|
||||
<!-- Checks for common coding problems -->
|
||||
<!-- See http://checkstyle.sf.net/config_coding.html -->
|
||||
<module name="AvoidInlineConditionals"/>
|
||||
<module name="EmptyStatement"/>
|
||||
<module name="EqualsHashCode"/>
|
||||
<module name="HiddenField">
|
||||
<property name="ignoreConstructorParameter" value="true"/>
|
||||
<property name="ignoreSetter" value="true"/>
|
||||
<property name="setterCanReturnItsClass" value="true"/>
|
||||
</module>
|
||||
<module name="IllegalInstantiation"/>
|
||||
<module name="InnerAssignment"/>
|
||||
<module name="MagicNumber"/>
|
||||
<module name="MissingSwitchDefault"/>
|
||||
<module name="SimplifyBooleanExpression"/>
|
||||
<module name="SimplifyBooleanReturn"/>
|
||||
|
||||
<!-- Checks for class design -->
|
||||
<!-- See http://checkstyle.sf.net/config_design.html -->
|
||||
<!--<module name="DesignForExtension"/>-->
|
||||
<module name="FinalClass"/>
|
||||
<module name="HideUtilityClassConstructor"/>
|
||||
<module name="InterfaceIsType"/>
|
||||
<module name="VisibilityModifier"/>
|
||||
|
||||
|
||||
<!-- Miscellaneous other checks. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html -->
|
||||
<module name="ArrayTypeStyle"/>
|
||||
<module name="FinalParameters"/>
|
||||
<module name="TodoComment"/>
|
||||
<module name="UpperEll"/>
|
||||
|
||||
</module>
|
||||
|
||||
<module name="SuppressWarningsFilter"/>
|
||||
<module name="SuppressionCommentFilter"/>
|
||||
|
||||
</module>
|
180
node.iml
180
node.iml
|
@ -1,180 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.projectlombok:lombok:1.16.8" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.4.1" level="project" />
|
||||
</component>
|
||||
<component name="org.twodividedbyzero.idea.findbugs">
|
||||
<option name="_detectors">
|
||||
<map>
|
||||
<entry key="AppendingToAnObjectOutputStream" value="true" />
|
||||
<entry key="AtomicityProblem" value="true" />
|
||||
<entry key="BadAppletConstructor" value="false" />
|
||||
<entry key="BadResultSetAccess" value="true" />
|
||||
<entry key="BadSyntaxForRegularExpression" value="true" />
|
||||
<entry key="BadUseOfReturnValue" value="true" />
|
||||
<entry key="BadlyOverriddenAdapter" value="true" />
|
||||
<entry key="BooleanReturnNull" value="true" />
|
||||
<entry key="BuildInterproceduralCallGraph" value="false" />
|
||||
<entry key="BuildObligationPolicyDatabase" value="true" />
|
||||
<entry key="CallToUnsupportedMethod" value="false" />
|
||||
<entry key="CalledMethods" value="true" />
|
||||
<entry key="CheckCalls" value="false" />
|
||||
<entry key="CheckExpectedWarnings" value="false" />
|
||||
<entry key="CheckImmutableAnnotation" value="true" />
|
||||
<entry key="CheckTypeQualifiers" value="true" />
|
||||
<entry key="CloneIdiom" value="true" />
|
||||
<entry key="ComparatorIdiom" value="true" />
|
||||
<entry key="ConfusedInheritance" value="true" />
|
||||
<entry key="ConfusionBetweenInheritedAndOuterMethod" value="true" />
|
||||
<entry key="CrossSiteScripting" value="true" />
|
||||
<entry key="DefaultEncodingDetector" value="true" />
|
||||
<entry key="DoInsideDoPrivileged" value="true" />
|
||||
<entry key="DontCatchIllegalMonitorStateException" value="true" />
|
||||
<entry key="DontIgnoreResultOfPutIfAbsent" value="true" />
|
||||
<entry key="DontUseEnum" value="true" />
|
||||
<entry key="DroppedException" value="true" />
|
||||
<entry key="DumbMethodInvocations" value="true" />
|
||||
<entry key="DumbMethods" value="true" />
|
||||
<entry key="DuplicateBranches" value="true" />
|
||||
<entry key="EmptyZipFileEntry" value="true" />
|
||||
<entry key="EqualsOperandShouldHaveClassCompatibleWithThis" value="true" />
|
||||
<entry key="ExplicitSerialization" value="true" />
|
||||
<entry key="FieldItemSummary" value="true" />
|
||||
<entry key="FinalizerNullsFields" value="true" />
|
||||
<entry key="FindBadCast2" value="true" />
|
||||
<entry key="FindBadForLoop" value="true" />
|
||||
<entry key="FindBugsSummaryStats" value="true" />
|
||||
<entry key="FindCircularDependencies" value="false" />
|
||||
<entry key="FindDeadLocalStores" value="true" />
|
||||
<entry key="FindDoubleCheck" value="true" />
|
||||
<entry key="FindEmptySynchronizedBlock" value="true" />
|
||||
<entry key="FindFieldSelfAssignment" value="true" />
|
||||
<entry key="FindFinalizeInvocations" value="true" />
|
||||
<entry key="FindFloatEquality" value="true" />
|
||||
<entry key="FindFloatMath" value="false" />
|
||||
<entry key="FindHEmismatch" value="true" />
|
||||
<entry key="FindInconsistentSync2" value="true" />
|
||||
<entry key="FindJSR166LockMonitorenter" value="true" />
|
||||
<entry key="FindLocalSelfAssignment2" value="true" />
|
||||
<entry key="FindMaskedFields" value="true" />
|
||||
<entry key="FindMismatchedWaitOrNotify" value="true" />
|
||||
<entry key="FindNakedNotify" value="true" />
|
||||
<entry key="FindNonSerializableStoreIntoSession" value="false" />
|
||||
<entry key="FindNonSerializableValuePassedToWriteObject" value="false" />
|
||||
<entry key="FindNonShortCircuit" value="true" />
|
||||
<entry key="FindNullDeref" value="true" />
|
||||
<entry key="FindNullDerefsInvolvingNonShortCircuitEvaluation" value="true" />
|
||||
<entry key="FindOpenStream" value="true" />
|
||||
<entry key="FindPuzzlers" value="true" />
|
||||
<entry key="FindRefComparison" value="true" />
|
||||
<entry key="FindReturnRef" value="true" />
|
||||
<entry key="FindRunInvocations" value="true" />
|
||||
<entry key="FindSelfComparison" value="true" />
|
||||
<entry key="FindSelfComparison2" value="true" />
|
||||
<entry key="FindSleepWithLockHeld" value="true" />
|
||||
<entry key="FindSpinLoop" value="true" />
|
||||
<entry key="FindSqlInjection" value="true" />
|
||||
<entry key="FindTwoLockWait" value="true" />
|
||||
<entry key="FindUncalledPrivateMethods" value="true" />
|
||||
<entry key="FindUnconditionalWait" value="true" />
|
||||
<entry key="FindUninitializedGet" value="true" />
|
||||
<entry key="FindUnrelatedTypesInGenericContainer" value="true" />
|
||||
<entry key="FindUnreleasedLock" value="true" />
|
||||
<entry key="FindUnsatisfiedObligation" value="true" />
|
||||
<entry key="FindUnsyncGet" value="true" />
|
||||
<entry key="FindUseOfNonSerializableValue" value="true" />
|
||||
<entry key="FindUselessControlFlow" value="true" />
|
||||
<entry key="FormatStringChecker" value="true" />
|
||||
<entry key="FunctionsThatMightBeMistakenForProcedures" value="true" />
|
||||
<entry key="HugeSharedStringConstants" value="true" />
|
||||
<entry key="IDivResultCastToDouble" value="true" />
|
||||
<entry key="IncompatMask" value="true" />
|
||||
<entry key="InconsistentAnnotations" value="true" />
|
||||
<entry key="InefficientMemberAccess" value="false" />
|
||||
<entry key="InefficientToArray" value="true" />
|
||||
<entry key="InfiniteLoop" value="true" />
|
||||
<entry key="InfiniteRecursiveLoop" value="true" />
|
||||
<entry key="InheritanceUnsafeGetResource" value="true" />
|
||||
<entry key="InitializationChain" value="true" />
|
||||
<entry key="InitializeNonnullFieldsInConstructor" value="true" />
|
||||
<entry key="InstantiateStaticClass" value="true" />
|
||||
<entry key="IntCast2LongAsInstant" value="true" />
|
||||
<entry key="InvalidJUnitTest" value="true" />
|
||||
<entry key="IteratorIdioms" value="true" />
|
||||
<entry key="LazyInit" value="true" />
|
||||
<entry key="LoadOfKnownNullValue" value="true" />
|
||||
<entry key="LostLoggerDueToWeakReference" value="true" />
|
||||
<entry key="MethodReturnCheck" value="true" />
|
||||
<entry key="Methods" value="true" />
|
||||
<entry key="MultithreadedInstanceAccess" value="true" />
|
||||
<entry key="MutableLock" value="true" />
|
||||
<entry key="MutableStaticFields" value="true" />
|
||||
<entry key="Naming" value="true" />
|
||||
<entry key="Noise" value="false" />
|
||||
<entry key="NoiseNullDeref" value="false" />
|
||||
<entry key="NoteAnnotationRetention" value="true" />
|
||||
<entry key="NoteCheckReturnValueAnnotations" value="true" />
|
||||
<entry key="NoteDirectlyRelevantTypeQualifiers" value="true" />
|
||||
<entry key="NoteJCIPAnnotation" value="true" />
|
||||
<entry key="NoteNonNullAnnotations" value="true" />
|
||||
<entry key="NoteNonnullReturnValues" value="true" />
|
||||
<entry key="NoteSuppressedWarnings" value="true" />
|
||||
<entry key="NoteUnconditionalParamDerefs" value="true" />
|
||||
<entry key="NumberConstructor" value="true" />
|
||||
<entry key="OverridingEqualsNotSymmetrical" value="true" />
|
||||
<entry key="PreferZeroLengthArrays" value="true" />
|
||||
<entry key="PublicSemaphores" value="false" />
|
||||
<entry key="QuestionableBooleanAssignment" value="true" />
|
||||
<entry key="ReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass" value="true" />
|
||||
<entry key="ReadReturnShouldBeChecked" value="true" />
|
||||
<entry key="RedundantInterfaces" value="true" />
|
||||
<entry key="ReflectiveClasses" value="true" />
|
||||
<entry key="RepeatedConditionals" value="true" />
|
||||
<entry key="ResolveAllReferences" value="false" />
|
||||
<entry key="RuntimeExceptionCapture" value="true" />
|
||||
<entry key="SerializableIdiom" value="true" />
|
||||
<entry key="StartInConstructor" value="true" />
|
||||
<entry key="StaticCalendarDetector" value="true" />
|
||||
<entry key="StringConcatenation" value="true" />
|
||||
<entry key="SuperfluousInstanceOf" value="true" />
|
||||
<entry key="SuspiciousThreadInterrupted" value="true" />
|
||||
<entry key="SwitchFallthrough" value="true" />
|
||||
<entry key="SynchronizationOnSharedBuiltinConstant" value="true" />
|
||||
<entry key="SynchronizeAndNullCheckField" value="true" />
|
||||
<entry key="SynchronizeOnClassLiteralNotGetClass" value="true" />
|
||||
<entry key="SynchronizingOnContentsOfFieldToProtectField" value="true" />
|
||||
<entry key="TestASM" value="false" />
|
||||
<entry key="TestDataflowAnalysis" value="false" />
|
||||
<entry key="TestingGround" value="false" />
|
||||
<entry key="TestingGround2" value="false" />
|
||||
<entry key="TrainFieldStoreTypes" value="true" />
|
||||
<entry key="TrainLongInstantfParams" value="true" />
|
||||
<entry key="TrainNonNullAnnotations" value="true" />
|
||||
<entry key="TrainUnconditionalDerefParams" value="true" />
|
||||
<entry key="URLProblems" value="true" />
|
||||
<entry key="UncallableMethodOfAnonymousClass" value="true" />
|
||||
<entry key="UnnecessaryMath" value="true" />
|
||||
<entry key="UnreadFields" value="true" />
|
||||
<entry key="UselessSubclassMethod" value="false" />
|
||||
<entry key="VarArgsProblems" value="true" />
|
||||
<entry key="VolatileUsage" value="true" />
|
||||
<entry key="WaitInLoop" value="true" />
|
||||
<entry key="WrongMapIterator" value="true" />
|
||||
<entry key="XMLFactoryBypass" value="true" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</module>
|
23
pom.xml
23
pom.xml
|
@ -2,7 +2,7 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>node</artifactId>
|
||||
<version>0.3.0</version>
|
||||
<version>0.4.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Node</name>
|
||||
|
@ -11,11 +11,13 @@
|
|||
<parent>
|
||||
<groupId>net.kemitix</groupId>
|
||||
<artifactId>kemitix-parent</artifactId>
|
||||
<version>0.6.0</version>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<assertj.version>3.4.1</assertj.version>
|
||||
<coveralls-maven-plugin.version>4.2.0</coveralls-maven-plugin.version>
|
||||
<trajano-commons-testing.version>2.1.0</trajano-commons-testing.version>
|
||||
</properties>
|
||||
|
||||
<issueManagement>
|
||||
|
@ -33,12 +35,21 @@
|
|||
|
||||
<inceptionYear>2016</inceptionYear>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eluder.coveralls</groupId>
|
||||
<artifactId>coveralls-maven-plugin</artifactId>
|
||||
<version>${coveralls-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.16.8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
@ -58,5 +69,11 @@
|
|||
<version>${assertj.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.trajano.commons</groupId>
|
||||
<artifactId>commons-testing</artifactId>
|
||||
<version>${trajano-commons-testing.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
155
src/main/java/net/kemitix/node/AbstractNodeItem.java
Normal file
155
src/main/java/net/kemitix/node/AbstractNodeItem.java
Normal file
|
@ -0,0 +1,155 @@
|
|||
package net.kemitix.node;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* An abstract node item, providing default implementations for most read-only
|
||||
* operations.
|
||||
*
|
||||
* @author Paul Campbell
|
||||
*
|
||||
* @param <T> the type of data stored in each node
|
||||
*/
|
||||
abstract class AbstractNodeItem<T> implements Node<T> {
|
||||
|
||||
private T data;
|
||||
|
||||
private String name;
|
||||
|
||||
private Node<T> parent;
|
||||
|
||||
private final Set<Node<T>> children;
|
||||
|
||||
protected AbstractNodeItem(
|
||||
final T data, final String name, final Node<T> parent,
|
||||
final Set<Node<T>> children) {
|
||||
this.data = data;
|
||||
this.name = name;
|
||||
this.parent = parent;
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> getData() {
|
||||
return Optional.ofNullable(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return data == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Node<T>> getParent() {
|
||||
return Optional.ofNullable(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Node<T>> getChildren() {
|
||||
return new HashSet<>(children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the node for the child if present.
|
||||
*
|
||||
* @param child the child's data to search for
|
||||
*
|
||||
* @return an {@link Optional} containing the child node if found
|
||||
*/
|
||||
@Override
|
||||
public Optional<Node<T>> findChild(@NonNull final T child) {
|
||||
return children.stream().filter(node -> {
|
||||
final Optional<T> d = node.getData();
|
||||
return d.isPresent() && d.get().equals(child);
|
||||
}).findAny();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node<T> getChild(final T child) {
|
||||
return findChild(child).orElseThrow(
|
||||
() -> new NodeException("Child not found"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the node is an ancestor.
|
||||
*
|
||||
* @param node the potential ancestor
|
||||
*
|
||||
* @return true if the node is an ancestor
|
||||
*/
|
||||
@Override
|
||||
public boolean isDescendantOf(final Node<T> node) {
|
||||
return parent != null && (node.equals(parent) || parent.isDescendantOf(
|
||||
node));
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks the node tree using the path to select each child.
|
||||
*
|
||||
* @param path the path to the desired child
|
||||
*
|
||||
* @return the child or null
|
||||
*/
|
||||
@Override
|
||||
public Optional<Node<T>> findInPath(@NonNull final List<T> path) {
|
||||
if (path.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Node<T> current = this;
|
||||
for (T item : path) {
|
||||
final Optional<Node<T>> child = current.findChild(item);
|
||||
if (child.isPresent()) {
|
||||
current = child.get();
|
||||
} else {
|
||||
current = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Optional.ofNullable(current);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Node<T>> findChildByName(@NonNull final String named) {
|
||||
return children.stream()
|
||||
.filter(n -> n.getName().equals(named))
|
||||
.findAny();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node<T> getChildByName(final String named) {
|
||||
return findChildByName(named).orElseThrow(
|
||||
() -> new NodeException("Named child not found"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String drawTree(final int depth) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final String unnamed = "(unnamed)";
|
||||
if (isNamed()) {
|
||||
sb.append(formatByDepth(name, depth));
|
||||
} else if (!children.isEmpty()) {
|
||||
sb.append(formatByDepth(unnamed, depth));
|
||||
}
|
||||
getChildren().forEach(c -> sb.append(c.drawTree(depth + 1)));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String formatByDepth(final String value, final int depth) {
|
||||
return String.format("[%1$" + (depth + value.length()) + "s]\n", value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNamed() {
|
||||
return name != null && name.length() > 0;
|
||||
}
|
||||
}
|
95
src/main/java/net/kemitix/node/ImmutableNodeItem.java
Normal file
95
src/main/java/net/kemitix/node/ImmutableNodeItem.java
Normal file
|
@ -0,0 +1,95 @@
|
|||
package net.kemitix.node;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents an immutable tree of nodes.
|
||||
*
|
||||
* <p>Due to the use of generics the data within a node may not be immutable.
|
||||
* (We can't create a defensive copy.) So if a user were to use {@code
|
||||
* getData()} they could then modify the original data within the node. This
|
||||
* wouldn't affect the integrity of the node tree structure, however.</p>
|
||||
*
|
||||
* @author Paul Campbell
|
||||
*
|
||||
* @param <T> the type of data stored in each node
|
||||
*/
|
||||
final class ImmutableNodeItem<T> extends AbstractNodeItem<T> {
|
||||
|
||||
private static final String IMMUTABLE_OBJECT = "Immutable object";
|
||||
|
||||
private ImmutableNodeItem(
|
||||
final T data, final String name, final Node<T> parent,
|
||||
final Set<Node<T>> children) {
|
||||
super(data, name, parent, children);
|
||||
}
|
||||
|
||||
static <T> ImmutableNodeItem<T> newRoot(
|
||||
final T data, final String name, final Set<Node<T>> children) {
|
||||
return new ImmutableNodeItem<>(data, name, null, children);
|
||||
}
|
||||
|
||||
static <T> ImmutableNodeItem<T> newChild(
|
||||
final T data, final String name, final Node<T> parent,
|
||||
final Set<Node<T>> children) {
|
||||
return new ImmutableNodeItem<>(data, name, parent, children);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(final String name) {
|
||||
throw new UnsupportedOperationException(IMMUTABLE_OBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(final T data) {
|
||||
throw new UnsupportedOperationException(IMMUTABLE_OBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(final Node<T> parent) {
|
||||
throw new UnsupportedOperationException(IMMUTABLE_OBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChild(final Node<T> child) {
|
||||
throw new UnsupportedOperationException(IMMUTABLE_OBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node<T> createChild(final T child) {
|
||||
throw new UnsupportedOperationException(IMMUTABLE_OBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node<T> createChild(final T child, final String name) {
|
||||
throw new UnsupportedOperationException(IMMUTABLE_OBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDescendantLine(final List<T> descendants) {
|
||||
throw new UnsupportedOperationException(IMMUTABLE_OBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node<T> findOrCreateChild(final T child) {
|
||||
return findChild(child).orElseThrow(
|
||||
() -> new UnsupportedOperationException(IMMUTABLE_OBJECT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertInPath(final Node<T> node, final String... path) {
|
||||
throw new UnsupportedOperationException(IMMUTABLE_OBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeChild(final Node<T> node) {
|
||||
throw new UnsupportedOperationException(IMMUTABLE_OBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeParent() {
|
||||
throw new UnsupportedOperationException(IMMUTABLE_OBJECT);
|
||||
}
|
||||
|
||||
}
|
|
@ -7,9 +7,9 @@ import java.util.Set;
|
|||
/**
|
||||
* An interface for tree node items.
|
||||
*
|
||||
* @param <T> the type of data held in each node
|
||||
* @author Paul Campbell
|
||||
*
|
||||
* @author pcampbell
|
||||
* @param <T> the type of data held in each node
|
||||
*/
|
||||
public interface Node<T> {
|
||||
|
||||
|
@ -113,6 +113,9 @@ public interface Node<T> {
|
|||
* @param child the child's data to search or create with
|
||||
*
|
||||
* @return the found or created child node
|
||||
*
|
||||
* @deprecated use node.findChild(child).orElseGet(() ->
|
||||
* node.createChild(child));
|
||||
*/
|
||||
@Deprecated
|
||||
Node<T> findOrCreateChild(T child);
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
package net.kemitix.node;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Represents a tree of nodes.
|
||||
*
|
||||
* @param <T> the type of data stored in each node
|
||||
* @author Paul Campbell
|
||||
*
|
||||
* @author pcampbell
|
||||
* @param <T> the type of data stored in each node
|
||||
*/
|
||||
public class NodeItem<T> implements Node<T> {
|
||||
class NodeItem<T> implements Node<T> {
|
||||
|
||||
private T data;
|
||||
|
||||
private final Set<Node<T>> children = new HashSet<>();
|
||||
|
||||
private Function<Node<T>, String> nameSupplier;
|
||||
|
||||
private Node<T> parent;
|
||||
|
||||
private String name;
|
||||
|
@ -32,7 +32,7 @@ public class NodeItem<T> implements Node<T> {
|
|||
* @param data the data or null
|
||||
* @param name the name
|
||||
*/
|
||||
public NodeItem(final T data, final String name) {
|
||||
NodeItem(final T data, final String name) {
|
||||
this(data);
|
||||
this.name = name;
|
||||
}
|
||||
|
@ -42,21 +42,8 @@ public class NodeItem<T> implements Node<T> {
|
|||
*
|
||||
* @param data the data or null
|
||||
*/
|
||||
public NodeItem(final T data) {
|
||||
NodeItem(final T data) {
|
||||
this.data = data;
|
||||
this.nameSupplier = (n) -> null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates root node with a name supplier.
|
||||
*
|
||||
* @param data the data or null
|
||||
* @param nameSupplier the name supplier function
|
||||
*/
|
||||
public NodeItem(
|
||||
final T data, final Function<Node<T>, String> nameSupplier) {
|
||||
this(data);
|
||||
this.nameSupplier = nameSupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,7 +52,7 @@ public class NodeItem<T> implements Node<T> {
|
|||
* @param data the data or null
|
||||
* @param parent the parent node
|
||||
*/
|
||||
public NodeItem(final T data, final Node<T> parent) {
|
||||
NodeItem(final T data, final Node<T> parent) {
|
||||
this.data = data;
|
||||
setParent(parent);
|
||||
}
|
||||
|
@ -77,44 +64,14 @@ public class NodeItem<T> implements Node<T> {
|
|||
* @param name the name
|
||||
* @param parent the parent node
|
||||
*/
|
||||
public NodeItem(final T data, final String name, final Node<T> parent) {
|
||||
NodeItem(final T data, final String name, final Node<T> parent) {
|
||||
this.data = data;
|
||||
this.name = name;
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a node with a name supplier and a parent.
|
||||
*
|
||||
* @param data the data or null
|
||||
* @param nameSupplier the name supplier function
|
||||
* @param parent the parent node
|
||||
*/
|
||||
public NodeItem(
|
||||
final T data, final Function<Node<T>, String> nameSupplier,
|
||||
final Node<T> parent) {
|
||||
this(data, nameSupplier);
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
private String generateName() {
|
||||
return getNameSupplier().apply(this);
|
||||
}
|
||||
|
||||
private Function<Node<T>, String> getNameSupplier() {
|
||||
if (nameSupplier != null) {
|
||||
return nameSupplier;
|
||||
}
|
||||
// no test for parent as root nodes will always have a default name
|
||||
// supplier
|
||||
return ((NodeItem<T>) parent).getNameSupplier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (name == null) {
|
||||
return generateName();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
@ -154,32 +111,35 @@ public class NodeItem<T> implements Node<T> {
|
|||
* @param child the node to add
|
||||
*/
|
||||
@Override
|
||||
public void addChild(final Node<T> child) {
|
||||
if (child == null) {
|
||||
throw new NullPointerException("child");
|
||||
}
|
||||
if (this.equals(child) || isDescendantOf(child)) {
|
||||
throw new NodeException("Child is an ancestor");
|
||||
}
|
||||
if (child.isNamed()) {
|
||||
final Optional<Node<T>> existingChild = findChildByName(
|
||||
child.getName());
|
||||
if (existingChild.isPresent() && existingChild.get() != child) {
|
||||
throw new NodeException(
|
||||
"Node with that name already exists here");
|
||||
}
|
||||
}
|
||||
public void addChild(@NonNull final Node<T> child) {
|
||||
verifyChildIsNotAnAncestor(child);
|
||||
verifyChildWithSameNameDoesNotAlreadyExist(child);
|
||||
children.add(child);
|
||||
// update the child's parent if they don't have one or it is not this
|
||||
Optional<Node<T>> childParent = child.getParent();
|
||||
boolean isOrphan = !childParent.isPresent();
|
||||
boolean hasDifferentParent = !isOrphan && !childParent.get()
|
||||
.equals(this);
|
||||
if (isOrphan || hasDifferentParent) {
|
||||
val childParent = child.getParent();
|
||||
if (!childParent.isPresent() || !childParent.get().equals(this)) {
|
||||
child.setParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyChildWithSameNameDoesNotAlreadyExist(
|
||||
final @NonNull Node<T> child) {
|
||||
if (child.isNamed()) {
|
||||
findChildByName(child.getName())
|
||||
.filter(existingChild -> existingChild != child)
|
||||
.ifPresent(existingChild -> {
|
||||
throw new NodeException(
|
||||
"Node with that name already exists here");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyChildIsNotAnAncestor(final @NonNull Node<T> child) {
|
||||
if (this.equals(child) || isDescendantOf(child)) {
|
||||
throw new NodeException("Child is an ancestor");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new node and adds it as a child of the current node.
|
||||
*
|
||||
|
@ -188,10 +148,7 @@ public class NodeItem<T> implements Node<T> {
|
|||
* @return the new child node
|
||||
*/
|
||||
@Override
|
||||
public Node<T> createChild(final T child) {
|
||||
if (child == null) {
|
||||
throw new NullPointerException("child");
|
||||
}
|
||||
public Node<T> createChild(@NonNull final T child) {
|
||||
return new NodeItem<>(child, this);
|
||||
}
|
||||
|
||||
|
@ -210,10 +167,7 @@ public class NodeItem<T> implements Node<T> {
|
|||
* @param descendants the line of descendants from the current node
|
||||
*/
|
||||
@Override
|
||||
public void createDescendantLine(final List<T> descendants) {
|
||||
if (descendants == null) {
|
||||
throw new NullPointerException("descendants");
|
||||
}
|
||||
public void createDescendantLine(@NonNull final List<T> descendants) {
|
||||
if (!descendants.isEmpty()) {
|
||||
findOrCreateChild(descendants.get(0)).createDescendantLine(
|
||||
descendants.subList(1, descendants.size()));
|
||||
|
@ -227,12 +181,13 @@ public class NodeItem<T> implements Node<T> {
|
|||
* @param child the child's data to search or create with
|
||||
*
|
||||
* @return the found or created child node
|
||||
*
|
||||
* @deprecated use node.findChild(child).orElseGet(() -> node.createChild
|
||||
* (child));
|
||||
*/
|
||||
@Override
|
||||
public Node<T> findOrCreateChild(final T child) {
|
||||
if (child == null) {
|
||||
throw new NullPointerException("child");
|
||||
}
|
||||
@Deprecated
|
||||
public Node<T> findOrCreateChild(@NonNull final T child) {
|
||||
return findChild(child).orElseGet(() -> createChild(child));
|
||||
}
|
||||
|
||||
|
@ -244,14 +199,11 @@ public class NodeItem<T> implements Node<T> {
|
|||
* @return an {@link Optional} containing the child node if found
|
||||
*/
|
||||
@Override
|
||||
public Optional<Node<T>> findChild(final T child) {
|
||||
if (child == null) {
|
||||
throw new NullPointerException("child");
|
||||
}
|
||||
return children.stream()
|
||||
.filter(n -> !n.isEmpty())
|
||||
.filter(n -> n.getData().get().equals(child))
|
||||
.findAny();
|
||||
public Optional<Node<T>> findChild(@NonNull final T child) {
|
||||
return children.stream().filter(node -> {
|
||||
final Optional<T> d = node.getData();
|
||||
return d.isPresent() && d.get().equals(child);
|
||||
}).findAny();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -282,10 +234,7 @@ public class NodeItem<T> implements Node<T> {
|
|||
* @param parent the new parent node
|
||||
*/
|
||||
@Override
|
||||
public final void setParent(final Node<T> parent) {
|
||||
if (parent == null) {
|
||||
throw new NullPointerException("parent");
|
||||
}
|
||||
public final void setParent(@NonNull final Node<T> parent) {
|
||||
if (this.equals(parent) || parent.isDescendantOf(this)) {
|
||||
throw new NodeException("Parent is a descendant");
|
||||
}
|
||||
|
@ -304,61 +253,65 @@ public class NodeItem<T> implements Node<T> {
|
|||
* @return the child or null
|
||||
*/
|
||||
@Override
|
||||
public Optional<Node<T>> findInPath(final List<T> path) {
|
||||
if (path == null) {
|
||||
throw new NullPointerException("path");
|
||||
}
|
||||
if (path.size() > 0) {
|
||||
Optional<Node<T>> found = findChild(path.get(0));
|
||||
if (found.isPresent()) {
|
||||
if (path.size() > 1) {
|
||||
return found.get().findInPath(path.subList(1, path.size()));
|
||||
}
|
||||
return found;
|
||||
}
|
||||
}
|
||||
public Optional<Node<T>> findInPath(@NonNull final List<T> path) {
|
||||
if (path.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Node<T> current = this;
|
||||
for (T item : path) {
|
||||
final Optional<Node<T>> child = current.findChild(item);
|
||||
if (child.isPresent()) {
|
||||
current = child.get();
|
||||
} else {
|
||||
current = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Optional.ofNullable(current);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertInPath(final Node<T> nodeItem, final String... path) {
|
||||
if (path.length == 0) {
|
||||
if (!nodeItem.isNamed()) { // nothing to conflict with
|
||||
addChild(nodeItem);
|
||||
return;
|
||||
insertChild(nodeItem);
|
||||
} else {
|
||||
val item = path[0];
|
||||
findChildByName(item)
|
||||
.orElseGet(() -> new NodeItem<>(null, item, this))
|
||||
.insertInPath(nodeItem,
|
||||
Arrays.copyOfRange(path, 1, path.length));
|
||||
}
|
||||
String nodeName = nodeItem.getName();
|
||||
final Optional<Node<T>> childNamed = findChildByName(nodeName);
|
||||
if (!childNamed.isPresent()) { // nothing with the same name exists
|
||||
addChild(nodeItem);
|
||||
return;
|
||||
}
|
||||
|
||||
private void insertChild(final Node<T> nodeItem) {
|
||||
if (nodeItem.isNamed()) {
|
||||
insertNamedChild(nodeItem);
|
||||
} else {
|
||||
// nothing to conflict with
|
||||
addChild(nodeItem);
|
||||
}
|
||||
}
|
||||
|
||||
private void insertNamedChild(final Node<T> nodeItem) {
|
||||
val childByName = findChildByName(nodeItem.getName());
|
||||
if (childByName.isPresent()) {
|
||||
// we have an existing node with the same name
|
||||
final Node<T> existing = childNamed.get();
|
||||
if (!existing.isEmpty()) {
|
||||
throw new NodeException("A non-empty node named '" + nodeName
|
||||
+ "' already exists here");
|
||||
} else {
|
||||
val existing = childByName.get();
|
||||
if (existing.isEmpty()) {
|
||||
// place any data in the new node into the existing empty node
|
||||
nodeItem.getData().ifPresent(existing::setData);
|
||||
}
|
||||
return;
|
||||
}
|
||||
String item = path[0];
|
||||
final Optional<Node<T>> childNamed = findChildByName(item);
|
||||
Node<T> child;
|
||||
if (!childNamed.isPresent()) {
|
||||
child = new NodeItem<>(null, item, this);
|
||||
} else {
|
||||
child = childNamed.get();
|
||||
throw new NodeException("A non-empty node named '"
|
||||
+ nodeItem.getName() + "' already exists here");
|
||||
}
|
||||
} else {
|
||||
// nothing with the same name exists
|
||||
addChild(nodeItem);
|
||||
}
|
||||
child.insertInPath(nodeItem, Arrays.copyOfRange(path, 1, path.length));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Node<T>> findChildByName(final String named) {
|
||||
if (named == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
public Optional<Node<T>> findChildByName(@NonNull final String named) {
|
||||
return children.stream()
|
||||
.filter((Node<T> t) -> t.getName().equals(named))
|
||||
.findAny();
|
||||
|
@ -378,17 +331,18 @@ public class NodeItem<T> implements Node<T> {
|
|||
final StringBuilder sb = new StringBuilder();
|
||||
final String unnamed = "(unnamed)";
|
||||
if (isNamed()) {
|
||||
sb.append(String.format("[%1$" + (depth + name.length()) + "s]\n",
|
||||
name));
|
||||
sb.append(formatByDepth(name, depth));
|
||||
} else if (!children.isEmpty()) {
|
||||
sb.append(
|
||||
String.format("[%1$" + (depth + unnamed.length()) + "s]\n",
|
||||
unnamed));
|
||||
sb.append(formatByDepth(unnamed, depth));
|
||||
}
|
||||
getChildren().stream().forEach(c -> sb.append(c.drawTree(depth + 1)));
|
||||
getChildren().forEach(c -> sb.append(c.drawTree(depth + 1)));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String formatByDepth(final String value, final int depth) {
|
||||
return String.format("[%1$" + (depth + value.length()) + "s]\n", value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNamed() {
|
||||
String currentName = getName();
|
||||
|
@ -406,14 +360,8 @@ public class NodeItem<T> implements Node<T> {
|
|||
public void removeParent() {
|
||||
if (parent != null) {
|
||||
Node<T> oldParent = parent;
|
||||
Function<Node<T>, String> supplier = getNameSupplier();
|
||||
parent = null;
|
||||
oldParent.removeChild(this);
|
||||
if (this.nameSupplier == null) {
|
||||
// this is now a root node, so must provide a default name
|
||||
// supplier
|
||||
this.nameSupplier = supplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
107
src/main/java/net/kemitix/node/Nodes.java
Normal file
107
src/main/java/net/kemitix/node/Nodes.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
package net.kemitix.node;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Utility class for {@link Node} items.
|
||||
*
|
||||
* @author pcampbell
|
||||
*/
|
||||
public final class Nodes {
|
||||
|
||||
private Nodes() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new unnamed root node.
|
||||
*
|
||||
* @param data the data the node will contain
|
||||
* @param <T> the type of the data
|
||||
*
|
||||
* @return the new node
|
||||
*/
|
||||
public static <T> Node<T> unnamedRoot(final T data) {
|
||||
return new NodeItem<>(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new named root node.
|
||||
*
|
||||
* @param data the data the node will contain
|
||||
* @param name the name of the node
|
||||
* @param <T> the type of the data
|
||||
*
|
||||
* @return the new node
|
||||
*/
|
||||
public static <T> Node<T> namedRoot(final T data, final String name) {
|
||||
return new NodeItem<>(data, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new unnamed child node.
|
||||
*
|
||||
* @param data the data the node will contain
|
||||
* @param parent the parent of the node
|
||||
* @param <T> the type of the data
|
||||
*
|
||||
* @return the new node
|
||||
*/
|
||||
public static <T> Node<T> unnamedChild(final T data, final Node<T> parent) {
|
||||
return new NodeItem<>(data, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new named child node.
|
||||
*
|
||||
* @param data the data the node will contain
|
||||
* @param name the name of the node
|
||||
* @param parent the parent of the node
|
||||
* @param <T> the type of the data
|
||||
*
|
||||
* @return the new node
|
||||
*/
|
||||
public static <T> Node<T> namedChild(
|
||||
final T data, final String name, final Node<T> parent) {
|
||||
return new NodeItem<>(data, name, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an immutable copy of an existing node tree.
|
||||
*
|
||||
* @param root the root node of the source tree
|
||||
* @param <T> the type of the data
|
||||
*
|
||||
* @return the immutable copy of the tree
|
||||
*/
|
||||
public static <T> Node<T> asImmutable(final Node<T> root) {
|
||||
if (root.getParent().isPresent()) {
|
||||
throw new IllegalArgumentException("source must be the root node");
|
||||
}
|
||||
final Set<Node<T>> children = getImmutableChildren(root);
|
||||
return ImmutableNodeItem.newRoot(root.getData().orElse(null),
|
||||
root.getName(), children);
|
||||
}
|
||||
|
||||
private static <T> Set<Node<T>> getImmutableChildren(final Node<T> source) {
|
||||
return source.getChildren()
|
||||
.stream()
|
||||
.map(Nodes::asImmutableChild)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private static <T> Node<T> asImmutableChild(
|
||||
final Node<T> source) {
|
||||
final Optional<Node<T>> sourceParent = source.getParent();
|
||||
if (sourceParent.isPresent()) {
|
||||
return ImmutableNodeItem.newChild(source.getData().orElse(null),
|
||||
source.getName(), sourceParent.get(),
|
||||
getImmutableChildren(source));
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"source must not be the root node");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
454
src/test/java/net/kemitix/node/ImmutableNodeItemTest.java
Normal file
454
src/test/java/net/kemitix/node/ImmutableNodeItemTest.java
Normal file
|
@ -0,0 +1,454 @@
|
|||
package net.kemitix.node;
|
||||
|
||||
import lombok.val;
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link ImmutableNodeItem}.
|
||||
*
|
||||
* @author pcampbell
|
||||
*/
|
||||
public class ImmutableNodeItemTest {
|
||||
|
||||
private static final String IMMUTABLE_OBJECT = "Immutable object";
|
||||
|
||||
@Rule
|
||||
public ExpectedException exception = ExpectedException.none();
|
||||
|
||||
private Node<String> immutableNode;
|
||||
|
||||
private void expectImmutableException() {
|
||||
exception.expect(UnsupportedOperationException.class);
|
||||
exception.expectMessage(IMMUTABLE_OBJECT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDataReturnsData() {
|
||||
//given
|
||||
val data = "this immutableNode data";
|
||||
//when
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(data));
|
||||
//then
|
||||
assertThat(immutableNode.getData()).as(
|
||||
"can get the data from a immutableNode").
|
||||
contains(data);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canCreateAnEmptyAndUnnamedNode() {
|
||||
//when
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(null));
|
||||
//then
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
softly.assertThat(immutableNode.isEmpty())
|
||||
.as("immutableNode is empty")
|
||||
.isTrue();
|
||||
softly.assertThat(immutableNode.isNamed())
|
||||
.as("immutableNode is unnamed")
|
||||
.isFalse();
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowExceptionOnSetName() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(null));
|
||||
expectImmutableException();
|
||||
//when
|
||||
immutableNode.setName("named");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rootNodeShouldHaveNoParent() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot("data"));
|
||||
//then
|
||||
assertThat(immutableNode.getParent()).as(
|
||||
"immutableNode created without a parent has no parent")
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldContainImmutableCopyOfChild() {
|
||||
//given
|
||||
val parent = Nodes.unnamedRoot("root");
|
||||
val child = Nodes.namedChild("child", "child", parent);
|
||||
//when
|
||||
immutableNode = Nodes.asImmutable(parent);
|
||||
//then
|
||||
val immutableChild = immutableNode.getChildByName("child");
|
||||
assertThat(immutableChild).isNotSameAs(child);
|
||||
assertThat(immutableChild.getName()).isEqualTo("child");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void childShouldHaveImmutableParent() {
|
||||
//given
|
||||
val parent = Nodes.namedRoot("parent", "root");
|
||||
Nodes.namedChild("subject", "child", parent);
|
||||
//when
|
||||
immutableNode = Nodes.asImmutable(parent);
|
||||
//then
|
||||
// get the immutable node's child's parent
|
||||
val immutableChild = immutableNode.getChildByName("child");
|
||||
final Optional<Node<String>> optionalParent
|
||||
= immutableChild.getParent();
|
||||
if (optionalParent.isPresent()) {
|
||||
val p = optionalParent.get();
|
||||
assertThat(p).hasFieldOrPropertyWithValue("name", "root")
|
||||
.hasFieldOrPropertyWithValue("data",
|
||||
Optional.of("parent"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotBeAbleToAddChildToImmutableTree() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot("root"));
|
||||
expectImmutableException();
|
||||
//when
|
||||
Nodes.unnamedChild("child", immutableNode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowExceptionWhenSetParent() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot("subject"));
|
||||
expectImmutableException();
|
||||
//when
|
||||
immutableNode.setParent(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowExceptionWhenAddingChild() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot("subject"));
|
||||
expectImmutableException();
|
||||
//when
|
||||
immutableNode.addChild(Nodes.unnamedRoot("child"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can walk a tree to the target node.
|
||||
*/
|
||||
@Test
|
||||
@Category(NodeFindInPathTestsCategory.class)
|
||||
public void shouldWalkTreeToNode() {
|
||||
//given
|
||||
val root = Nodes.unnamedRoot("root");
|
||||
Nodes.namedChild("child", "child", Nodes.unnamedChild("parent", root));
|
||||
immutableNode = Nodes.asImmutable(root);
|
||||
//when
|
||||
val result = immutableNode.findInPath(Arrays.asList("parent", "child"));
|
||||
//then
|
||||
assertThat(result.isPresent()).isTrue();
|
||||
if (result.isPresent()) {
|
||||
assertThat(result.get().getName()).isEqualTo("child");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we get an empty {@link Optional} when walking a path that
|
||||
* doesn't exist.
|
||||
*/
|
||||
@Test
|
||||
@Category(NodeFindInPathTestsCategory.class)
|
||||
public void shouldNotFindNonExistentChildNode() {
|
||||
//given
|
||||
val root = Nodes.unnamedRoot("root");
|
||||
Nodes.unnamedChild("child", Nodes.unnamedChild("parent", root));
|
||||
immutableNode = Nodes.asImmutable(root);
|
||||
//when
|
||||
val result = immutableNode.findInPath(
|
||||
Arrays.asList("parent", "no child"));
|
||||
//then
|
||||
assertThat(result.isPresent()).isFalse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that when we pass null we get an exception.
|
||||
*/
|
||||
@Test
|
||||
@Category(NodeFindInPathTestsCategory.class)
|
||||
public void shouldThrowNEWhenWalkTreeNull() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot("subject"));
|
||||
exception.expect(NullPointerException.class);
|
||||
exception.expectMessage("path");
|
||||
//when
|
||||
immutableNode.findInPath(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that when we pass an empty path we get and empty {@link Optional} as
|
||||
* a result.
|
||||
*/
|
||||
@Test
|
||||
@Category(NodeFindInPathTestsCategory.class)
|
||||
public void shouldReturnEmptyForEmptyWalkTreePath() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot("subject"));
|
||||
//when
|
||||
val result = immutableNode.findInPath(Collections.emptyList());
|
||||
//then
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can find a child of a immutableNode.
|
||||
*/
|
||||
@Test
|
||||
public void shouldFindExistingChildNode() {
|
||||
//given
|
||||
val root = Nodes.unnamedRoot("root");
|
||||
Nodes.unnamedChild("child", root);
|
||||
immutableNode = Nodes.asImmutable(root);
|
||||
//when
|
||||
val result = immutableNode.findChild("child");
|
||||
//then
|
||||
assertThat(result.isPresent()).isTrue();
|
||||
if (result.isPresent()) {
|
||||
assertThat(result.get().getData()).contains("child");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that if we pass null we get an exception.
|
||||
*/
|
||||
@Test
|
||||
public void findOrCreateChildShouldThrowNPEFWhenChildIsNull() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot("subject"));
|
||||
exception.expect(NullPointerException.class);
|
||||
exception.expectMessage("child");
|
||||
//when
|
||||
immutableNode.findOrCreateChild(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we throw an exception when passed null.
|
||||
*/
|
||||
@Test
|
||||
public void getChildShouldThrowNPEWhenThereIsNoChild() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot("data"));
|
||||
exception.expect(NullPointerException.class);
|
||||
exception.expectMessage("child");
|
||||
//when
|
||||
immutableNode.findChild(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getChildNamedFindsChild() {
|
||||
//given
|
||||
val root = Nodes.namedRoot("root data", "root");
|
||||
val alpha = Nodes.namedRoot("alpha data", "alpha");
|
||||
val beta = Nodes.namedRoot("beta data", "beta");
|
||||
root.addChild(alpha);
|
||||
root.addChild(beta);
|
||||
immutableNode = Nodes.asImmutable(root);
|
||||
//when
|
||||
val result = immutableNode.getChildByName("alpha");
|
||||
//then
|
||||
assertThat(result.getName()).isEqualTo(alpha.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getChildNamedFindsNothing() {
|
||||
//given
|
||||
val root = Nodes.namedRoot("root data", "root");
|
||||
val alpha = Nodes.namedRoot("alpha data", "alpha");
|
||||
val beta = Nodes.namedRoot("beta data", "beta");
|
||||
root.addChild(alpha);
|
||||
root.addChild(beta);
|
||||
exception.expect(NodeException.class);
|
||||
exception.expectMessage("Named child not found");
|
||||
immutableNode = Nodes.asImmutable(root);
|
||||
//when
|
||||
immutableNode.getChildByName("gamma");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removingParentThrowsException() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(null));
|
||||
expectImmutableException();
|
||||
//when
|
||||
immutableNode.removeParent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findChildNamedShouldThrowNPEWhenNameIsNull() {
|
||||
//given
|
||||
exception.expect(NullPointerException.class);
|
||||
exception.expectMessage("name");
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(null));
|
||||
//when
|
||||
immutableNode.findChildByName(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNamedNull() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(null));
|
||||
//then
|
||||
assertThat(immutableNode.isNamed()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNamedEmpty() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.namedRoot(null, ""));
|
||||
//then
|
||||
assertThat(immutableNode.isNamed()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNamedNamed() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.namedRoot(null, "named"));
|
||||
//then
|
||||
assertThat(immutableNode.isNamed()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeChildThrowsExceptions() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(null));
|
||||
expectImmutableException();
|
||||
//then
|
||||
immutableNode.removeChild(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void drawTreeIsCorrect() {
|
||||
//given
|
||||
val root = Nodes.namedRoot("root data", "root");
|
||||
val bob = Nodes.namedChild("bob data", "bob", root);
|
||||
val alice = Nodes.namedChild("alice data", "alice", root);
|
||||
Nodes.namedChild("dave data", "dave", alice);
|
||||
Nodes.unnamedChild("bob's child's data",
|
||||
bob); // has no name and no children so no included
|
||||
val kim = Nodes.unnamedChild("kim data", root); // nameless mother
|
||||
Nodes.namedChild("lucy data", "lucy", kim);
|
||||
immutableNode = Nodes.asImmutable(root);
|
||||
//when
|
||||
val tree = immutableNode.drawTree(0);
|
||||
//then
|
||||
String[] lines = tree.split("\n");
|
||||
assertThat(lines).contains("[root]", "[ alice]", "[ dave]",
|
||||
"[ (unnamed)]", "[ lucy]", "[ bob]");
|
||||
assertThat(lines).containsSubsequence("[root]", "[ alice]", "[ dave]");
|
||||
assertThat(lines).containsSubsequence("[root]", "[ (unnamed)]",
|
||||
"[ lucy]");
|
||||
assertThat(lines).containsSubsequence("[root]", "[ bob]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setDataShouldThrowException() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot("initial"));
|
||||
expectImmutableException();
|
||||
//when
|
||||
immutableNode.setData("updated");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createChildThrowsException() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(null));
|
||||
expectImmutableException();
|
||||
//when
|
||||
immutableNode.createChild("child data", "child name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canGetChildWhenFound() {
|
||||
//given
|
||||
val root = Nodes.unnamedRoot("data");
|
||||
val child = Nodes.namedChild("child data", "child name", root);
|
||||
immutableNode = Nodes.asImmutable(root);
|
||||
//when
|
||||
val found = immutableNode.getChild("child data");
|
||||
//then
|
||||
assertThat(found.getName()).isEqualTo(child.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canGetChildWhenNotFound() {
|
||||
//given
|
||||
exception.expect(NodeException.class);
|
||||
exception.expectMessage("Child not found");
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot("data"));
|
||||
//when
|
||||
immutableNode.getChild("child data");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canSafelyHandleFindChildWhenAChildHasNoData() {
|
||||
//given
|
||||
val root = Nodes.unnamedRoot("");
|
||||
Nodes.unnamedChild(null, root);
|
||||
immutableNode = Nodes.asImmutable(root);
|
||||
//when
|
||||
immutableNode.findChild("data");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createChildShouldThrowException() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(""));
|
||||
expectImmutableException();
|
||||
//when
|
||||
immutableNode.createChild("child");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createDescendantLineShouldThrowException() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(""));
|
||||
expectImmutableException();
|
||||
//when
|
||||
immutableNode.createDescendantLine(
|
||||
Arrays.asList("child", "grandchild"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertInPathShouldThrowException() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(""));
|
||||
expectImmutableException();
|
||||
//when
|
||||
immutableNode.insertInPath(null, "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOrCreateChildShouldReturnChildWhenChildIsFound() {
|
||||
//given
|
||||
val root = Nodes.unnamedRoot("");
|
||||
Nodes.namedChild("child", "child", root);
|
||||
immutableNode = Nodes.asImmutable(root);
|
||||
//when
|
||||
val found = immutableNode.findOrCreateChild("child");
|
||||
assertThat(found).extracting(Node::getName).contains("child");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOrCreateChildShouldThrowExceptionWhenChildNotFound() {
|
||||
//given
|
||||
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(""));
|
||||
expectImmutableException();
|
||||
//when
|
||||
immutableNode.findOrCreateChild("child");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package net.kemitix.node;
|
||||
|
||||
/**
|
||||
* Category marker for tests relating to implementations of Node.findInPath(...).
|
||||
*
|
||||
* @author Paul Campbell
|
||||
*/
|
||||
public interface NodeFindInPathTestsCategory {
|
||||
}
|
|
@ -4,17 +4,14 @@ import lombok.val;
|
|||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link NodeItem}.
|
||||
|
@ -33,7 +30,7 @@ public class NodeItemTest {
|
|||
//given
|
||||
val data = "this node data";
|
||||
//when
|
||||
node = new NodeItem<>(data);
|
||||
node = Nodes.unnamedRoot(data);
|
||||
//then
|
||||
assertThat(node.getData()).as("can get the data from a node").
|
||||
contains(data);
|
||||
|
@ -42,7 +39,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void canCreateAnEmptyAndUnnamedNode() {
|
||||
//when
|
||||
node = new NodeItem<>(null);
|
||||
node = Nodes.unnamedRoot(null);
|
||||
//then
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
softly.assertThat(node.isEmpty()).as("node is empty").isTrue();
|
||||
|
@ -50,21 +47,10 @@ public class NodeItemTest {
|
|||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canCreateNodeWithParentAndCustomNameSupplier() {
|
||||
//given
|
||||
node = new NodeItem<>(null, n -> "root name supplier");
|
||||
//when
|
||||
val child = new NodeItem<String>(null, n -> "overridden", node);
|
||||
//then
|
||||
assertThat(child.getName()).isEqualTo("overridden");
|
||||
assertThat(child.getParent()).contains(node);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canSetName() {
|
||||
//given
|
||||
node = new NodeItem<>(null);
|
||||
node = Nodes.unnamedRoot(null);
|
||||
//when
|
||||
node.setName("named");
|
||||
//then
|
||||
|
@ -77,7 +63,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldHaveNullForDefaultParent() {
|
||||
//given
|
||||
node = new NodeItem<>("data");
|
||||
node = Nodes.unnamedRoot("data");
|
||||
//then
|
||||
assertThat(node.getParent()).as(
|
||||
"node created without a parent has no parent").isEmpty();
|
||||
|
@ -89,9 +75,9 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldReturnNodeParent() {
|
||||
//given
|
||||
val parent = new NodeItem<String>("parent");
|
||||
val parent = Nodes.unnamedRoot("parent");
|
||||
//when
|
||||
node = new NodeItem<>("subject", parent);
|
||||
node = Nodes.unnamedChild("subject", parent);
|
||||
//then
|
||||
assertThat(node.getParent()).as(
|
||||
"node created with a parent can return the parent")
|
||||
|
@ -105,8 +91,8 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void setParentShouldThrowNodeExceptionWhenParentIsAChild() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
val child = new NodeItem<String>("child", node);
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
val child = Nodes.unnamedChild("child", node);
|
||||
exception.expect(NodeException.class);
|
||||
exception.expectMessage("Parent is a descendant");
|
||||
//when
|
||||
|
@ -121,9 +107,9 @@ public class NodeItemTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
public void shouldAddNewNodeAsChildToParent() {
|
||||
//given
|
||||
val parent = new NodeItem<String>("parent");
|
||||
val parent = Nodes.unnamedRoot("parent");
|
||||
//when
|
||||
node = new NodeItem<>("subject", parent);
|
||||
node = Nodes.unnamedChild("subject", parent);
|
||||
//then
|
||||
assertThat(parent.getChildren()).as(
|
||||
"when a node is created with a parent, the parent has the new"
|
||||
|
@ -136,8 +122,8 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldReturnSetParent() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
val parent = new NodeItem<String>("parent");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
val parent = Nodes.unnamedRoot("parent");
|
||||
//when
|
||||
node.setParent(parent);
|
||||
//then
|
||||
|
@ -152,7 +138,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldThrowNPEWhenSetParentNull() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
exception.expect(NullPointerException.class);
|
||||
exception.expectMessage("parent");
|
||||
//when
|
||||
|
@ -166,7 +152,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void setParentShouldThrowNodeExceptionWhenParentIsSelf() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
exception.expect(NodeException.class);
|
||||
exception.expectMessage("Parent is a descendant");
|
||||
//when
|
||||
|
@ -180,9 +166,9 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldUpdateOldParentWhenNodeSetToNewParent() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
val child = node.createChild("child");
|
||||
val newParent = new NodeItem<String>("newParent");
|
||||
val newParent = Nodes.unnamedRoot("newParent");
|
||||
//when
|
||||
child.setParent(newParent);
|
||||
//then
|
||||
|
@ -201,9 +187,9 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldRemoveNodeFromOldParentWhenAddedAsChildToNewParent() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
val child = node.createChild("child");
|
||||
val newParent = new NodeItem<String>("newParent");
|
||||
val newParent = Nodes.unnamedRoot("newParent");
|
||||
//when
|
||||
newParent.addChild(child);
|
||||
//then
|
||||
|
@ -223,7 +209,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldThrowNPEWhenAddingNullAsChild() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
exception.expect(NullPointerException.class);
|
||||
exception.expectMessage("child");
|
||||
//when
|
||||
|
@ -237,8 +223,8 @@ public class NodeItemTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
public void shouldReturnAddedChild() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
val child = new NodeItem<String>("child");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
val child = Nodes.unnamedRoot("child");
|
||||
//when
|
||||
node.addChild(child);
|
||||
//then
|
||||
|
@ -253,7 +239,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void addChildShouldThrowNodeExceptionWhenAddingANodeAsOwnChild() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
exception.expect(NodeException.class);
|
||||
exception.expectMessage("Child is an ancestor");
|
||||
//then
|
||||
|
@ -266,7 +252,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void addChildShouldThrowNodeExceptionWhenAddingSelfAsChild() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
exception.expect(NodeException.class);
|
||||
exception.expectMessage("Child is an ancestor");
|
||||
//when
|
||||
|
@ -280,8 +266,8 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void addChildShouldThrowNodeExceptionWhenChildIsParent() {
|
||||
//given
|
||||
val parent = new NodeItem<String>("parent");
|
||||
node = new NodeItem<>("subject", parent);
|
||||
val parent = Nodes.unnamedRoot("parent");
|
||||
node = Nodes.unnamedChild("subject", parent);
|
||||
exception.expect(NodeException.class);
|
||||
exception.expectMessage("Child is an ancestor");
|
||||
//when
|
||||
|
@ -295,9 +281,9 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void addChildShouldThrowNodeExceptionWhenAddingGrandParentAsChild() {
|
||||
//given
|
||||
val grandParent = new NodeItem<String>("grandparent");
|
||||
val parent = new NodeItem<String>("parent", grandParent);
|
||||
node = new NodeItem<>("subject", parent);
|
||||
val grandParent = Nodes.unnamedRoot("grandparent");
|
||||
val parent = Nodes.unnamedChild("parent", grandParent);
|
||||
node = Nodes.unnamedChild("subject", parent);
|
||||
exception.expect(NodeException.class);
|
||||
exception.expectMessage("Child is an ancestor");
|
||||
//when
|
||||
|
@ -310,8 +296,8 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldSetParentOnChildWhenAddedAsChild() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
val child = new NodeItem<String>("child");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
val child = Nodes.unnamedRoot("child");
|
||||
//when
|
||||
node.addChild(child);
|
||||
//then
|
||||
|
@ -324,14 +310,15 @@ public class NodeItemTest {
|
|||
* Test that we can walk a tree to the target node.
|
||||
*/
|
||||
@Test
|
||||
@Category(NodeFindInPathTestsCategory.class)
|
||||
public void shouldWalkTreeToNode() {
|
||||
//given
|
||||
val grandparent = "grandparent";
|
||||
val grandParentNode = new NodeItem<String>(grandparent);
|
||||
val grandParentNode = Nodes.unnamedRoot(grandparent);
|
||||
val parent = "parent";
|
||||
val parentNode = new NodeItem<String>(parent, grandParentNode);
|
||||
val parentNode = Nodes.unnamedChild(parent, grandParentNode);
|
||||
val subject = "subject";
|
||||
node = new NodeItem<>(subject, parentNode);
|
||||
node = Nodes.unnamedChild(subject, parentNode);
|
||||
//when
|
||||
val result = grandParentNode.findInPath(Arrays.asList(parent, subject));
|
||||
//then
|
||||
|
@ -349,12 +336,13 @@ public class NodeItemTest {
|
|||
* doesn't exist.
|
||||
*/
|
||||
@Test
|
||||
@Category(NodeFindInPathTestsCategory.class)
|
||||
public void shouldNotFindNonExistentChildNode() {
|
||||
//given
|
||||
val parent = "parent";
|
||||
val parentNode = new NodeItem<String>(parent);
|
||||
val parentNode = Nodes.unnamedRoot(parent);
|
||||
val subject = "subject";
|
||||
node = new NodeItem<>(subject, parentNode);
|
||||
node = Nodes.unnamedChild(subject, parentNode);
|
||||
//when
|
||||
val result = parentNode.findInPath(Arrays.asList(subject, "no child"));
|
||||
//then
|
||||
|
@ -367,9 +355,10 @@ public class NodeItemTest {
|
|||
* Test that when we pass null we get an exception.
|
||||
*/
|
||||
@Test
|
||||
@Category(NodeFindInPathTestsCategory.class)
|
||||
public void shouldThrowNEWhenWalkTreeNull() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
exception.expect(NullPointerException.class);
|
||||
exception.expectMessage("path");
|
||||
//when
|
||||
|
@ -381,9 +370,10 @@ public class NodeItemTest {
|
|||
* a result.
|
||||
*/
|
||||
@Test
|
||||
@Category(NodeFindInPathTestsCategory.class)
|
||||
public void shouldReturnEmptyForEmptyWalkTreePath() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
//when
|
||||
val result = node.findInPath(Collections.emptyList());
|
||||
//then
|
||||
|
@ -396,7 +386,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldCreateDescendantNodes() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
val alphaData = "alpha";
|
||||
val betaData = "beta";
|
||||
val gammaData = "gamma";
|
||||
|
@ -445,7 +435,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void createDescendantLineShouldThrowNPEWhenDescendantsAreNull() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
exception.expect(NullPointerException.class);
|
||||
exception.expectMessage("descendants");
|
||||
//when
|
||||
|
@ -458,7 +448,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldChangeNothingWhenCreateDescendantEmpty() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
//when
|
||||
node.createDescendantLine(Collections.emptyList());
|
||||
//then
|
||||
|
@ -473,9 +463,9 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldFindExistingChildNode() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
val childData = "child";
|
||||
val child = new NodeItem<String>(childData, node);
|
||||
val child = Nodes.unnamedChild(childData, node);
|
||||
//when
|
||||
val found = node.findOrCreateChild(childData);
|
||||
//then
|
||||
|
@ -490,7 +480,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldFindCreateNewChildNode() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
val childData = "child";
|
||||
//when
|
||||
val found = node.findOrCreateChild(childData);
|
||||
|
@ -506,7 +496,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void findOrCreateChildShouldThrowNPEFWhenChildIsNull() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
exception.expect(NullPointerException.class);
|
||||
exception.expectMessage("child");
|
||||
//when
|
||||
|
@ -519,9 +509,9 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldGetChild() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
val childData = "child";
|
||||
val child = new NodeItem<String>(childData);
|
||||
val child = Nodes.unnamedRoot(childData);
|
||||
node.addChild(child);
|
||||
//when
|
||||
val found = node.findChild(childData);
|
||||
|
@ -541,7 +531,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void getChildShouldThrowNPEWhenThereIsNoChild() {
|
||||
//given
|
||||
node = new NodeItem<>("data");
|
||||
node = Nodes.unnamedRoot("data");
|
||||
exception.expect(NullPointerException.class);
|
||||
exception.expectMessage("child");
|
||||
//when
|
||||
|
@ -555,7 +545,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void shouldCreateChild() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
val childData = "child";
|
||||
//when
|
||||
val child = node.createChild(childData);
|
||||
|
@ -580,82 +570,25 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void createChildShouldThrowNPEWhenChildIsNull() {
|
||||
//given
|
||||
node = new NodeItem<>("subject");
|
||||
node = Nodes.unnamedRoot("subject");
|
||||
exception.expect(NullPointerException.class);
|
||||
exception.expectMessage("child");
|
||||
//when
|
||||
node.createChild(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNameShouldBeCorrect() {
|
||||
//given
|
||||
node = new NodeItem<>("subject", n -> n.getData().get());
|
||||
//then
|
||||
assertThat(node.getName()).isEqualTo("subject");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNameShouldUseParentNameSupplier() {
|
||||
//given
|
||||
val root = new NodeItem<String>("root", n -> n.getData().get());
|
||||
node = new NodeItem<>("child", root);
|
||||
//then
|
||||
assertThat(node.getName()).isEqualTo("child");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNameShouldReturnNameForNonStringData() {
|
||||
val root = new NodeItem<LocalDate>(LocalDate.parse("2016-05-23"), n -> {
|
||||
if (n.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return n.getData().get().format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
|
||||
});
|
||||
//then
|
||||
assertThat(root.getName()).isEqualTo("20160523");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNameShouldUseClosestNameSupplier() {
|
||||
node = new NodeItem<>("root", n -> n.getData().get());
|
||||
val child = new NodeItem<String>("child", Object::toString);
|
||||
node.addChild(child);
|
||||
val grandChild = new NodeItem<>("grandchild", child);
|
||||
//then
|
||||
assertThat(node.getName()).isEqualTo("root");
|
||||
assertThat(child.getName()).isNotEqualTo("child");
|
||||
assertThat(grandChild.getName()).isNotEqualTo("grandchild");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNameShouldWorkWithoutNameSupplier() {
|
||||
node = new NodeItem<>(null, "root");
|
||||
val namedchild = new NodeItem<>("named", "Alice", node);
|
||||
//then
|
||||
assertThat(node.getName()).isEqualTo("root");
|
||||
assertThat(namedchild.getName()).isEqualTo("Alice");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canCreateRootNodeWithoutData() {
|
||||
node = new NodeItem<>(null, "empty");
|
||||
assertThat(node.getData()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canCreateRootNodeWithoutDataButWithNameSupplier() {
|
||||
node = new NodeItem<>(null);
|
||||
node = Nodes.namedRoot(null, "empty");
|
||||
assertThat(node.getData()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getChildNamedFindsChild() {
|
||||
//given
|
||||
node = new NodeItem<>(null, "root");
|
||||
val alpha = new NodeItem<String>(null, "alpha");
|
||||
val beta = new NodeItem<String>(null, "beta");
|
||||
node = Nodes.namedRoot("root data", "root");
|
||||
val alpha = Nodes.namedRoot("alpha data", "alpha");
|
||||
val beta = Nodes.namedRoot("beta data", "beta");
|
||||
node.addChild(alpha);
|
||||
node.addChild(beta);
|
||||
//when
|
||||
|
@ -667,9 +600,9 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void getChildNamedFindsNothing() {
|
||||
//given
|
||||
node = new NodeItem<>(null, "root");
|
||||
val alpha = new NodeItem<String>(null, "alpha");
|
||||
val beta = new NodeItem<String>(null, "beta");
|
||||
node = Nodes.namedRoot("root data", "root");
|
||||
val alpha = Nodes.namedRoot("alpha data", "alpha");
|
||||
val beta = Nodes.namedRoot("beta data", "beta");
|
||||
node.addChild(alpha);
|
||||
node.addChild(beta);
|
||||
exception.expect(NodeException.class);
|
||||
|
@ -681,10 +614,10 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void nodeNamesAreUniqueWithinAParent() {
|
||||
//given
|
||||
node = new NodeItem<>(null, "root");
|
||||
val alpha = new NodeItem<String>(null, "alpha");
|
||||
node = Nodes.namedRoot("root data", "root");
|
||||
val alpha = Nodes.namedRoot("alpha data", "alpha");
|
||||
node.addChild(alpha);
|
||||
val beta = new NodeItem<String>(null, "alpha");
|
||||
val beta = Nodes.namedRoot("beta data", "alpha");
|
||||
exception.expect(NodeException.class);
|
||||
exception.expectMessage("Node with that name already exists here");
|
||||
//when
|
||||
|
@ -694,8 +627,8 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void canPlaceNodeInTreeByPathNames() {
|
||||
//given
|
||||
node = new NodeItem<>(null, "root"); // create a root
|
||||
val four = new NodeItem<String>("data", "four");
|
||||
node = Nodes.namedRoot("root data", "root"); // create a root
|
||||
val four = Nodes.namedRoot("data", "four");
|
||||
//when
|
||||
node.insertInPath(four, "one", "two", "three");
|
||||
//then
|
||||
|
@ -717,9 +650,9 @@ public class NodeItemTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
public void canPlaceInTreeUnderExistingNode() {
|
||||
//given
|
||||
node = new NodeItem<>(null, "root");
|
||||
val child = new NodeItem<String>("child data", "child");
|
||||
val grandchild = new NodeItem<String>("grandchild data", "grandchild");
|
||||
node = Nodes.namedRoot(null, "root");
|
||||
val child = Nodes.namedRoot("child data", "child");
|
||||
val grandchild = Nodes.namedRoot("grandchild data", "grandchild");
|
||||
//when
|
||||
node.insertInPath(child); // as root/child
|
||||
node.insertInPath(grandchild, "child"); // as root/child/grandchild
|
||||
|
@ -734,9 +667,9 @@ public class NodeItemTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
public void canPlaceInTreeAboveExistingNode() {
|
||||
//given
|
||||
node = new NodeItem<>(null, "root");
|
||||
val child = new NodeItem<String>("child data", "child");
|
||||
val grandchild = new NodeItem<String>("grandchild data", "grandchild");
|
||||
node = Nodes.namedRoot(null, "root");
|
||||
val child = Nodes.namedRoot("child data", "child");
|
||||
val grandchild = Nodes.namedRoot("grandchild data", "grandchild");
|
||||
//when
|
||||
node.insertInPath(grandchild, "child");
|
||||
node.insertInPath(child);
|
||||
|
@ -752,7 +685,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void removingParentFromNodeWithNoParentIsNoop() {
|
||||
//given
|
||||
node = new NodeItem<>(null);
|
||||
node = Nodes.unnamedRoot(null);
|
||||
//when
|
||||
node.removeParent();
|
||||
}
|
||||
|
@ -760,8 +693,8 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void removingParentFromNodeWithParentRemovesParent() {
|
||||
//given
|
||||
node = new NodeItem<>(null);
|
||||
val child = new NodeItem<String>(null, node);
|
||||
node = Nodes.unnamedRoot(null);
|
||||
val child = Nodes.unnamedChild("child data", node);
|
||||
//when
|
||||
child.removeParent();
|
||||
//then
|
||||
|
@ -775,22 +708,22 @@ public class NodeItemTest {
|
|||
exception.expect(NodeException.class);
|
||||
exception.expectMessage(
|
||||
"A non-empty node named 'grandchild' already exists here");
|
||||
node = new NodeItem<>(null);
|
||||
val child = new NodeItem<String>(null, "child", node);
|
||||
new NodeItem<>("data", "grandchild", child);
|
||||
node = Nodes.unnamedRoot(null);
|
||||
val child = Nodes.namedChild("child data", "child", node);
|
||||
Nodes.namedChild("data", "grandchild", child);
|
||||
// root -> child -> grandchild
|
||||
// only grandchild has data
|
||||
//when
|
||||
// attempt to add another node called 'grandchild' to 'child'
|
||||
node.insertInPath(new NodeItem<>("cuckoo", "grandchild"), "child");
|
||||
node.insertInPath(Nodes.namedRoot("cuckoo", "grandchild"), "child");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void placeNodeInTreeWhenAddedNodeIsUnnamed() {
|
||||
//given
|
||||
node = new NodeItem<>(null);
|
||||
final Node<String> newNode = new NodeItem<>(null);
|
||||
node = Nodes.unnamedRoot(null);
|
||||
final Node<String> newNode = Nodes.unnamedRoot(null);
|
||||
//when
|
||||
node.insertInPath(newNode);
|
||||
//then
|
||||
|
@ -801,12 +734,12 @@ public class NodeItemTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
public void placeNodeInTreeWhenEmptyChildWithTargetNameExists() {
|
||||
//given
|
||||
node = new NodeItem<>(null);
|
||||
final NodeItem<String> child = new NodeItem<>(null, "child");
|
||||
final NodeItem<String> target = new NodeItem<>(null, "target");
|
||||
node = Nodes.unnamedRoot(null);
|
||||
final Node<String> child = Nodes.namedRoot(null, "child");
|
||||
final Node<String> target = Nodes.namedRoot(null, "target");
|
||||
node.addChild(child);
|
||||
child.addChild(target);
|
||||
final NodeItem<String> addMe = new NodeItem<>("I'm new", "target");
|
||||
val addMe = Nodes.namedRoot("I'm new", "target");
|
||||
assertThat(addMe.getParent()).isEmpty();
|
||||
assertThat(child.getChildByName("target").isEmpty()).as(
|
||||
"target starts empty").isTrue();
|
||||
|
@ -823,7 +756,7 @@ public class NodeItemTest {
|
|||
//given
|
||||
exception.expect(NullPointerException.class);
|
||||
exception.expectMessage("name");
|
||||
node = new NodeItem<>(null);
|
||||
node = Nodes.unnamedRoot(null);
|
||||
//when
|
||||
node.findChildByName(null);
|
||||
}
|
||||
|
@ -831,7 +764,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void isNamedNull() {
|
||||
//given
|
||||
node = new NodeItem<>(null);
|
||||
node = Nodes.unnamedRoot(null);
|
||||
//then
|
||||
assertThat(node.isNamed()).isFalse();
|
||||
}
|
||||
|
@ -839,7 +772,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void isNamedEmpty() {
|
||||
//given
|
||||
node = new NodeItem<>(null, "");
|
||||
node = Nodes.namedRoot(null, "");
|
||||
//then
|
||||
assertThat(node.isNamed()).isFalse();
|
||||
}
|
||||
|
@ -847,32 +780,16 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void isNamedNamed() {
|
||||
//given
|
||||
node = new NodeItem<>(null, "named");
|
||||
node = Nodes.namedRoot(null, "named");
|
||||
//then
|
||||
assertThat(node.isNamed()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeParentNodeProvidesSameNameSupplier() {
|
||||
// once a node has it's parent removed it should provide a default name
|
||||
// provider
|
||||
//given
|
||||
node = new NodeItem<>("data", n -> n.getData().get());
|
||||
final NodeItem<String> child = new NodeItem<>("other", node);
|
||||
assertThat(node.getName()).as("initial root name").isEqualTo("data");
|
||||
assertThat(child.getName()).as("initial child name").isEqualTo("other");
|
||||
//when
|
||||
child.removeParent();
|
||||
//then
|
||||
assertThat(node.getName()).as("final root name").isEqualTo("data");
|
||||
assertThat(child.getName()).as("final child name").isEqualTo("other");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void removeChildRemovesTheChild() {
|
||||
//given
|
||||
node = new NodeItem<>(null);
|
||||
node = Nodes.unnamedRoot(null);
|
||||
Node<String> child = node.createChild("child");
|
||||
assertThat(node.getChildren()).containsExactly(child);
|
||||
//then
|
||||
|
@ -885,13 +802,14 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void drawTreeIsCorrect() {
|
||||
//given
|
||||
node = new NodeItem<>(null, "root");
|
||||
val bob = new NodeItem<String>(null, "bob", node);
|
||||
val alice = new NodeItem<String>(null, "alice", node);
|
||||
new NodeItem<>(null, "dave", alice);
|
||||
new NodeItem<>(null, bob); // has no name and no children so no included
|
||||
val kim = new NodeItem<String>(null, node); // nameless mother
|
||||
new NodeItem<>(null, "lucy", kim);
|
||||
node = Nodes.namedRoot(null, "root");
|
||||
val bob = Nodes.namedChild("bob data", "bob", node);
|
||||
val alice = Nodes.namedChild("alice data", "alice", node);
|
||||
Nodes.namedChild("dave data", "dave", alice);
|
||||
Nodes.unnamedChild("bob's child's data",
|
||||
bob); // has no name and no children so no included
|
||||
val kim = Nodes.unnamedChild("kim data", node); // nameless mother
|
||||
Nodes.namedChild("lucy data", "lucy", kim);
|
||||
//when
|
||||
val tree = node.drawTree(0);
|
||||
//then
|
||||
|
@ -907,7 +825,7 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void canChangeNodeData() {
|
||||
//given
|
||||
node = new NodeItem<>("initial");
|
||||
node = Nodes.unnamedRoot("initial");
|
||||
//when
|
||||
node.setData("updated");
|
||||
//then
|
||||
|
@ -918,7 +836,7 @@ public class NodeItemTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
public void canCreateNamedChild() {
|
||||
//given
|
||||
node = new NodeItem<>(null);
|
||||
node = Nodes.unnamedRoot(null);
|
||||
//when
|
||||
Node<String> child = node.createChild("child data", "child name");
|
||||
//then
|
||||
|
@ -930,10 +848,10 @@ public class NodeItemTest {
|
|||
@Test
|
||||
public void canGetChildWhenFound() {
|
||||
//given
|
||||
node = new NodeItem<>("data");
|
||||
Node<String> child = new NodeItem<>("child data", "child name", node);
|
||||
node = Nodes.unnamedRoot("data");
|
||||
val child = Nodes.namedChild("child data", "child name", node);
|
||||
//when
|
||||
Node<String> found = node.getChild("child data");
|
||||
val found = node.getChild("child data");
|
||||
//then
|
||||
assertThat(found).isSameAs(child);
|
||||
}
|
||||
|
@ -943,7 +861,7 @@ public class NodeItemTest {
|
|||
//given
|
||||
exception.expect(NodeException.class);
|
||||
exception.expectMessage("Child not found");
|
||||
node = new NodeItem<>("data");
|
||||
node = Nodes.unnamedRoot("data");
|
||||
//when
|
||||
node.getChild("child data");
|
||||
}
|
||||
|
@ -952,99 +870,19 @@ public class NodeItemTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
public void constructorWithNameSupplierAndParentBeChildOfParent() {
|
||||
//given
|
||||
node = new NodeItem<>(null);
|
||||
node = Nodes.unnamedRoot(null);
|
||||
//when
|
||||
NodeItem<String> child = new NodeItem<>(null, node);
|
||||
val child = Nodes.unnamedChild("child data", node);
|
||||
//then
|
||||
assertThat(child.getParent()).contains(node);
|
||||
assertThat(node.getChildren()).containsExactly(child);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void removeParentCopiesRootNameSupplier() {
|
||||
//given
|
||||
node = new NodeItem<>("root data", n -> "root supplier");
|
||||
val child = new NodeItem<>("child data", node);
|
||||
assertThat(child.getName()).isEqualTo("root supplier");
|
||||
//when
|
||||
child.removeParent();
|
||||
//then
|
||||
assertThat(child.getName()).isEqualTo("root supplier");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void removeParentDoesNotReplaceLocalNameSupplier() {
|
||||
//given
|
||||
node = new NodeItem<>("root data", n -> "root supplier");
|
||||
val child = new NodeItem<>("child data", n -> "local supplier", node);
|
||||
assertThat(child.getName()).isEqualTo("local supplier");
|
||||
//when
|
||||
child.removeParent();
|
||||
//then
|
||||
assertThat(child.getName()).isEqualTo("local supplier");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNameToNullRevertsToParentNameSupplier() {
|
||||
//given
|
||||
node = new NodeItem<>(null, n -> "root supplier");
|
||||
val child = new NodeItem<String>(null, "child name", node);
|
||||
assertThat(child.getName()).isEqualTo("child name");
|
||||
//when
|
||||
child.setName(null);
|
||||
//then
|
||||
assertThat(child.getName()).isEqualTo("root supplier");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNameWithNameSupplierIsRecalculatedEachCall() {
|
||||
val counter = new AtomicInteger(0);
|
||||
node = new NodeItem<>(null,
|
||||
n -> Integer.toString(counter.incrementAndGet()));
|
||||
//then
|
||||
assertThat(node.getName()).isNotEqualTo(node.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNamedWithNameSupplierIsRecalculatedEachCall() {
|
||||
val counter = new AtomicInteger(0);
|
||||
node = new NodeItem<>(null, n -> {
|
||||
// alternate between even numbers and nulls: null, 2, null, 4, null
|
||||
final int i = counter.incrementAndGet();
|
||||
if (i % 2 == 0) {
|
||||
return Integer.toString(i);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
//then
|
||||
assertThat(node.isNamed()).isFalse();
|
||||
assertThat(node.isNamed()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canUseNameSupplierToBuildFullPath() {
|
||||
//given
|
||||
final Function<Node<String>, String> pathNameSupplier = node -> {
|
||||
Optional<Node<String>> parent = node.getParent();
|
||||
if (parent.isPresent()) {
|
||||
return parent.get().getName() + "/" + node.getData().get();
|
||||
}
|
||||
return "";
|
||||
};
|
||||
node = new NodeItem<>(null, pathNameSupplier);
|
||||
val child = new NodeItem<String>("child", node);
|
||||
val grandchild = new NodeItem<String>("grandchild", child);
|
||||
//then
|
||||
assertThat(grandchild.getName()).isEqualTo("/child/grandchild");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canSafelyHandleFindChildWhenAChildHasNoData() {
|
||||
//given
|
||||
node = new NodeItem<>(null);
|
||||
new NodeItem<>(null, node);
|
||||
node = Nodes.unnamedRoot(null);
|
||||
Nodes.unnamedChild(null, node);
|
||||
//when
|
||||
node.findChild("data");
|
||||
}
|
||||
|
|
62
src/test/java/net/kemitix/node/NodesTest.java
Normal file
62
src/test/java/net/kemitix/node/NodesTest.java
Normal file
|
@ -0,0 +1,62 @@
|
|||
package net.kemitix.node;
|
||||
|
||||
import lombok.val;
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.Test;
|
||||
|
||||
import static net.trajano.commons.testing.UtilityClassTestUtil
|
||||
.assertUtilityClassWellDefined;
|
||||
|
||||
/**
|
||||
* Tests for {@link Nodes}.
|
||||
*
|
||||
* @author pcampbell
|
||||
*/
|
||||
public class NodesTest {
|
||||
|
||||
@Test
|
||||
public void shouldBeValidUtilityClass() throws Exception {
|
||||
assertUtilityClassWellDefined(Nodes.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateUnnamedRoot() throws Exception {
|
||||
val node = Nodes.unnamedRoot("data");
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
softly.assertThat(node.getData()).contains("data");
|
||||
softly.assertThat(node.getName()).isNull();
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateNamedRoot() throws Exception {
|
||||
val node = Nodes.namedRoot("data", "name");
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
softly.assertThat(node.getData()).contains("data");
|
||||
softly.assertThat(node.getName()).isEqualTo("name");
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateUnnamedChild() throws Exception {
|
||||
val parent = Nodes.unnamedRoot("root");
|
||||
val node = Nodes.unnamedChild("data", parent);
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
softly.assertThat(node.getData()).contains("data");
|
||||
softly.assertThat(node.getName()).isNull();
|
||||
softly.assertThat(node.getParent()).contains(parent);
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateNamedChild() throws Exception {
|
||||
val parent = Nodes.unnamedRoot("root");
|
||||
val node = Nodes.namedChild("data", "child", parent);
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
softly.assertThat(node.getData()).contains("data");
|
||||
softly.assertThat(node.getName()).isEqualTo("child");
|
||||
softly.assertThat(node.getParent()).contains(parent);
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue